diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 87d5fc6..84e11fb 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -55,6 +55,8 @@ PODS:
- sqlite3/fts5
- sqlite3/perf-threadsafe
- sqlite3/rtree
+ - url_launcher_ios (0.0.1):
+ - Flutter
DEPENDENCIES:
- audio_service (from `.symlinks/plugins/audio_service/ios`)
@@ -73,6 +75,7 @@ DEPENDENCIES:
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
+ - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
SPEC REPOS:
trunk:
@@ -112,6 +115,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/sqflite/darwin"
sqlite3_flutter_libs:
:path: ".symlinks/plugins/sqlite3_flutter_libs/ios"
+ url_launcher_ios:
+ :path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
audio_service: f509d65da41b9521a61f1c404dd58651f265a567
@@ -132,6 +137,7 @@ SPEC CHECKSUMS:
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
sqlite3: 0bb0e6389d824e40296f531b858a2a0b71c0d2fb
sqlite3_flutter_libs: c00457ebd31e59fa6bb830380ddba24d44fbcd3b
+ url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 684734b..8b626b8 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -473,7 +473,8 @@
DEVELOPMENT_TEAM = W7HPZ53V6B;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
- INFOPLIST_KEY_CFBundleDisplayName = RhythmBox;
+ INFOPLIST_KEY_CFBundleDisplayName = GroovyBox;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -657,7 +658,8 @@
DEVELOPMENT_TEAM = W7HPZ53V6B;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
- INFOPLIST_KEY_CFBundleDisplayName = RhythmBox;
+ INFOPLIST_KEY_CFBundleDisplayName = GroovyBox;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -681,7 +683,8 @@
DEVELOPMENT_TEAM = W7HPZ53V6B;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
- INFOPLIST_KEY_CFBundleDisplayName = RhythmBox;
+ INFOPLIST_KEY_CFBundleDisplayName = GroovyBox;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 005933c..fbc43c9 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -13,7 +13,7 @@
CFBundleInfoDictionaryVersion
6.0
CFBundleName
- rhythm_box
+ Groovy Box
CFBundlePackageType
APPL
CFBundleShortVersionString
diff --git a/lib/router.dart b/lib/router.dart
index bc1f145..30d7e2f 100644
--- a/lib/router.dart
+++ b/lib/router.dart
@@ -1,6 +1,7 @@
import 'package:animations/animations.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
+import 'package:rhythm_box/screens/about.dart';
import 'package:rhythm_box/screens/album/view.dart';
import 'package:rhythm_box/screens/auth/mobile_login.dart';
import 'package:rhythm_box/screens/explore.dart';
@@ -51,6 +52,11 @@ final router = GoRouter(routes: [
name: 'settings',
builder: (context, state) => const SettingsScreen(),
),
+ GoRoute(
+ path: '/about',
+ name: 'about',
+ builder: (context, state) => const AboutScreen(),
+ ),
],
),
ShellRoute(
diff --git a/lib/screens/about.dart b/lib/screens/about.dart
new file mode 100644
index 0000000..a90b41c
--- /dev/null
+++ b/lib/screens/about.dart
@@ -0,0 +1,90 @@
+import 'package:flutter/material.dart';
+import 'package:package_info_plus/package_info_plus.dart';
+import 'package:rhythm_box/platform.dart';
+import 'package:url_launcher/url_launcher_string.dart';
+
+class AboutScreen extends StatelessWidget {
+ const AboutScreen({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ const denseButtonStyle =
+ ButtonStyle(visualDensity: VisualDensity(vertical: -4));
+
+ return Material(
+ color: Theme.of(context).colorScheme.surface,
+ child: SizedBox(
+ width: double.infinity,
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ ClipRRect(
+ borderRadius: const BorderRadius.all(Radius.circular(16)),
+ child: Image.asset('assets/icon.png', width: 120, height: 120),
+ ),
+ const SizedBox(height: 8),
+ Text(
+ PlatformInfo.isIOS || PlatformInfo.isMacOS
+ ? 'GroovyBox'
+ : 'RhythmBox',
+ style: Theme.of(context).textTheme.headlineMedium,
+ ),
+ const Text(
+ 'Yet another Spotify third-party app',
+ style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
+ ),
+ const SizedBox(height: 8),
+ FutureBuilder(
+ future: PackageInfo.fromPlatform(),
+ builder: (context, snapshot) {
+ if (!snapshot.hasData) {
+ return const SizedBox();
+ }
+
+ return Text(
+ 'v${snapshot.data!.version} · ${snapshot.data!.buildNumber}',
+ style: const TextStyle(fontFamily: 'monospace'),
+ );
+ },
+ ),
+ Text('Copyright © ${DateTime.now().year} Solsynth LLC'),
+ const SizedBox(height: 16),
+ TextButton(
+ style: denseButtonStyle,
+ child: const Text('App Details'),
+ onPressed: () async {
+ final info = await PackageInfo.fromPlatform();
+
+ showAboutDialog(
+ context: context,
+ applicationVersion: '${info.version} (${info.buildNumber})',
+ applicationLegalese: 'Yet another Spotify third-party app.',
+ applicationIcon: ClipRRect(
+ borderRadius: const BorderRadius.all(Radius.circular(16)),
+ child:
+ Image.asset('assets/icon.png', width: 60, height: 60),
+ ),
+ );
+ },
+ ),
+ TextButton(
+ style: denseButtonStyle,
+ child: const Text('Project Website'),
+ onPressed: () {
+ launchUrlString('https://solsynth.dev/products/rhythm-box');
+ },
+ ),
+ const SizedBox(height: 16),
+ const Text(
+ 'Open-sourced under AGPLv3',
+ style: TextStyle(
+ fontWeight: FontWeight.w300,
+ fontSize: 12,
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart
index 12d4c89..9a5dc75 100644
--- a/lib/screens/settings.dart
+++ b/lib/screens/settings.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
+import 'package:go_router/go_router.dart';
import 'package:rhythm_box/providers/auth.dart';
import 'package:rhythm_box/providers/spotify.dart';
import 'package:rhythm_box/providers/user_preferences.dart';
@@ -122,6 +123,17 @@ class _SettingsScreenState extends State {
onChanged: _preferences.setNormalizeAudio,
),
),
+ const Divider(thickness: 0.3, height: 1),
+ ListTile(
+ contentPadding: const EdgeInsets.symmetric(horizontal: 24),
+ leading: const Icon(Icons.info),
+ title: const Text('About'),
+ subtitle: const Text('More information about this app'),
+ trailing: const Icon(Icons.chevron_right),
+ onTap: () async {
+ GoRouter.of(context).pushNamed('about');
+ },
+ ),
],
),
),
diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt
index 40271c0..506adc6 100644
--- a/linux/CMakeLists.txt
+++ b/linux/CMakeLists.txt
@@ -4,7 +4,7 @@ project(runner LANGUAGES CXX)
# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
-set(BINARY_NAME "rhythm_box")
+set(BINARY_NAME "RhythmBox")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "dev.solsynth.rhythmBox")
diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc
index 3501420..8211dc5 100644
--- a/linux/flutter/generated_plugin_registrant.cc
+++ b/linux/flutter/generated_plugin_registrant.cc
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include
void fl_register_plugins(FlPluginRegistry* registry) {
@@ -29,6 +30,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar);
+ g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
+ fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
+ url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
g_autoptr(FlPluginRegistrar) window_manager_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin");
window_manager_plugin_register_with_registrar(window_manager_registrar);
diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake
index 701f5cf..abe8e61 100644
--- a/linux/flutter/generated_plugins.cmake
+++ b/linux/flutter/generated_plugins.cmake
@@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
media_kit_libs_linux
screen_retriever
sqlite3_flutter_libs
+ url_launcher_linux
window_manager
)
diff --git a/linux/my_application.cc b/linux/my_application.cc
index fc1f0b5..8a034e5 100644
--- a/linux/my_application.cc
+++ b/linux/my_application.cc
@@ -40,11 +40,11 @@ static void my_application_activate(GApplication* application) {
if (use_header_bar) {
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar));
- gtk_header_bar_set_title(header_bar, "rhythm_box");
+ gtk_header_bar_set_title(header_bar, "RhythmBox");
gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
} else {
- gtk_window_set_title(window, "rhythm_box");
+ gtk_window_set_title(window, "RhythmBox");
}
gtk_window_set_default_size(window, 1280, 720);
diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift
index dff91bc..302ade2 100644
--- a/macos/Flutter/GeneratedPluginRegistrant.swift
+++ b/macos/Flutter/GeneratedPluginRegistrant.swift
@@ -18,6 +18,7 @@ import screen_retriever
import shared_preferences_foundation
import sqflite
import sqlite3_flutter_libs
+import url_launcher_macos
import window_manager
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
@@ -34,5 +35,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
+ UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
}
diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj
index e7854e7..5be36b4 100644
--- a/macos/Runner.xcodeproj/project.pbxproj
+++ b/macos/Runner.xcodeproj/project.pbxproj
@@ -574,7 +574,8 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
- INFOPLIST_KEY_CFBundleDisplayName = RhythmBox;
+ INFOPLIST_KEY_CFBundleDisplayName = GroovyBox;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
@@ -707,7 +708,8 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
- INFOPLIST_KEY_CFBundleDisplayName = RhythmBox;
+ INFOPLIST_KEY_CFBundleDisplayName = GroovyBox;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
@@ -728,7 +730,8 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
- INFOPLIST_KEY_CFBundleDisplayName = RhythmBox;
+ INFOPLIST_KEY_CFBundleDisplayName = GroovyBox;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist
index 4789daa..3368dbc 100644
--- a/macos/Runner/Info.plist
+++ b/macos/Runner/Info.plist
@@ -13,7 +13,7 @@
CFBundleInfoDictionaryVersion
6.0
CFBundleName
- $(PRODUCT_NAME)
+ Groovy Box
CFBundlePackageType
APPL
CFBundleShortVersionString
diff --git a/pubspec.lock b/pubspec.lock
index ac22e32..77c64c9 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1438,6 +1438,70 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.2"
+ url_launcher:
+ dependency: "direct main"
+ description:
+ name: url_launcher
+ sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.3.0"
+ url_launcher_android:
+ dependency: transitive
+ description:
+ name: url_launcher_android
+ sha256: e35a698ac302dd68e41f73250bd9517fe3ab5fa4f18fe4647a0872db61bacbab
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.3.10"
+ url_launcher_ios:
+ dependency: transitive
+ description:
+ name: url_launcher_ios
+ sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.3.1"
+ url_launcher_linux:
+ dependency: transitive
+ description:
+ name: url_launcher_linux
+ sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.2.0"
+ url_launcher_macos:
+ dependency: transitive
+ description:
+ name: url_launcher_macos
+ sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.2.0"
+ url_launcher_platform_interface:
+ dependency: transitive
+ description:
+ name: url_launcher_platform_interface
+ sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.2"
+ url_launcher_web:
+ dependency: transitive
+ description:
+ name: url_launcher_web
+ sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.3"
+ url_launcher_windows:
+ dependency: transitive
+ description:
+ name: url_launcher_windows
+ sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.2"
uuid:
dependency: "direct main"
description:
@@ -1544,4 +1608,4 @@ packages:
version: "2.2.1"
sdks:
dart: ">=3.5.0 <4.0.0"
- flutter: ">=3.22.0"
+ flutter: ">=3.24.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index 457cef3..62b217a 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -100,6 +100,7 @@ dependencies:
path: packages/desktop_webview_window
flutter_inappwebview: ^6.0.0
timezone: ^0.9.4
+ url_launcher: ^6.3.0
dev_dependencies:
flutter_test:
@@ -130,9 +131,8 @@ flutter:
uses-material-design: true
# To add assets to your application, add an assets section, like this:
- # assets:
- # - images/a_dot_burr.jpeg
- # - images/a_dot_ham.jpeg
+ assets:
+ - assets/icon.png
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images
diff --git a/web/index.html b/web/index.html
index f986a9c..34e5cf0 100644
--- a/web/index.html
+++ b/web/index.html
@@ -21,13 +21,13 @@
-
+
- rhythm_box
+ RhythmBox