From 902f5589f588ec79021a3b2b5634ef6eb13a6253 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 20 Dec 2025 14:10:49 +0800 Subject: [PATCH] :sparkles: Rebuilt router with go router --- lib/main.dart | 7 ++-- lib/router.dart | 59 +++++++++++++++++++++++++++++ lib/ui/screens/player_screen.dart | 16 ++++++-- lib/ui/screens/settings_screen.dart | 3 ++ lib/ui/shell.dart | 31 ++++++--------- pubspec.lock | 8 ++++ pubspec.yaml | 1 + 7 files changed, 99 insertions(+), 26 deletions(-) create mode 100644 lib/router.dart diff --git a/lib/main.dart b/lib/main.dart index 95641c8..c099ce7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,7 +3,7 @@ import 'package:groovybox/logic/audio_handler.dart'; import 'package:groovybox/logic/window_helpers.dart'; import 'package:groovybox/providers/audio_provider.dart'; import 'package:groovybox/providers/theme_provider.dart'; -import 'package:groovybox/ui/shell.dart'; +import 'package:groovybox/router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:media_kit/media_kit.dart'; import 'package:audio_service/audio_service.dart' as audio_service; @@ -52,14 +52,15 @@ class GroovyApp extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final themeMode = ref.watch(themeProvider); + final router = ref.watch(routerProvider); - return MaterialApp( + return MaterialApp.router( title: 'GroovyBox', debugShowCheckedModeBanner: false, theme: ref.watch(lightThemeProvider), darkTheme: ref.watch(darkThemeProvider), themeMode: themeMode, - home: const Shell(), + routerConfig: router, ); } } diff --git a/lib/router.dart b/lib/router.dart new file mode 100644 index 0000000..8a0015f --- /dev/null +++ b/lib/router.dart @@ -0,0 +1,59 @@ +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:groovybox/data/db.dart'; +import 'package:groovybox/data/playlist_repository.dart'; +import 'package:groovybox/ui/screens/album_detail_screen.dart'; +import 'package:groovybox/ui/screens/library_screen.dart'; +import 'package:groovybox/ui/screens/player_screen.dart'; +import 'package:groovybox/ui/screens/playlist_detail_screen.dart'; +import 'package:groovybox/ui/screens/settings_screen.dart'; +import 'package:groovybox/ui/shell.dart'; + +// Route names +class AppRoutes { + static const String library = '/'; + static const String player = '/player'; + static const String settings = '/settings'; + static const String albumDetail = '/album'; + static const String playlistDetail = '/playlist'; +} + +// Router provider that can be accessed from anywhere in the app +final routerProvider = Provider((ref) { + return GoRouter( + initialLocation: AppRoutes.library, + routes: [ + ShellRoute( + builder: (context, state, child) => Shell(child: child), + routes: [ + GoRoute( + path: AppRoutes.library, + builder: (context, state) => const LibraryScreen(), + ), + GoRoute( + path: AppRoutes.player, + builder: (context, state) => const PlayerScreen(), + ), + GoRoute( + path: AppRoutes.settings, + builder: (context, state) => const SettingsScreen(), + ), + GoRoute( + path: AppRoutes.albumDetail, + builder: (context, state) { + final album = state.extra as AlbumData; + return AlbumDetailScreen(album: album); + }, + ), + GoRoute( + path: AppRoutes.playlistDetail, + builder: (context, state) { + final playlist = state.extra as Playlist; + return PlaylistDetailScreen(playlist: playlist); + }, + ), + ], + ), + ], + ); +}); diff --git a/lib/ui/screens/player_screen.dart b/lib/ui/screens/player_screen.dart index eb1ab66..0fa84d8 100644 --- a/lib/ui/screens/player_screen.dart +++ b/lib/ui/screens/player_screen.dart @@ -14,6 +14,7 @@ import 'package:groovybox/data/track_repository.dart'; import 'package:groovybox/logic/lrc_providers.dart'; import 'package:groovybox/logic/lyrics_parser.dart'; import 'package:groovybox/logic/metadata_service.dart'; +import 'package:groovybox/logic/window_helpers.dart'; import 'package:groovybox/providers/audio_provider.dart'; import 'package:groovybox/providers/db_provider.dart'; import 'package:groovybox/providers/lrc_fetcher_provider.dart'; @@ -151,7 +152,12 @@ class PlayerScreen extends HookConsumerWidget { builder: (context) { if (isMobile) { return Padding( - padding: EdgeInsets.only(top: devicePadding.top + 40), + padding: EdgeInsets.only( + top: + devicePadding.top + + 40 + + (isDesktopPlatform() ? 28 : 0), + ), child: _MobileLayout( player: player, viewMode: viewMode, @@ -171,7 +177,8 @@ class PlayerScreen extends HookConsumerWidget { ), // IconButton Positioned( - top: MediaQuery.of(context).padding.top + 16, + top: + devicePadding.top + 16 + (isDesktopPlatform() ? 28 : 0), left: 16, child: IconButton( icon: const Icon(Symbols.keyboard_arrow_down), @@ -1149,7 +1156,10 @@ class _ViewToggleButton extends StatelessWidget { } return Positioned( - top: MediaQuery.of(context).padding.top + 16, + top: + MediaQuery.of(context).padding.top + + 16 + + (isDesktopPlatform() ? 28 : 0), right: 16, child: IconButton( icon: Icon(getIcon()), diff --git a/lib/ui/screens/settings_screen.dart b/lib/ui/screens/settings_screen.dart index 37fd805..142ace7 100644 --- a/lib/ui/screens/settings_screen.dart +++ b/lib/ui/screens/settings_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; import 'package:groovybox/data/track_repository.dart'; import 'package:groovybox/providers/settings_provider.dart'; import 'package:groovybox/providers/watch_folder_provider.dart'; @@ -434,6 +435,8 @@ class SettingsScreen extends ConsumerWidget { ], ), ), + // Gap for mini player + const Gap(80), ], ), ), diff --git a/lib/ui/shell.dart b/lib/ui/shell.dart index d2907a0..e14857c 100644 --- a/lib/ui/shell.dart +++ b/lib/ui/shell.dart @@ -4,11 +4,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; +import 'package:go_router/go_router.dart'; import 'package:groovybox/data/track_repository.dart'; import 'package:groovybox/logic/lyrics_parser.dart'; import 'package:groovybox/logic/window_helpers.dart'; import 'package:groovybox/providers/settings_provider.dart'; -import 'package:groovybox/ui/screens/settings_screen.dart'; +import 'package:groovybox/router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:path/path.dart' as p; @@ -68,7 +69,9 @@ class _WindowMaximizeListener extends WindowListener { } class Shell extends HookConsumerWidget { - const Shell({super.key}); + final Widget child; + + const Shell({super.key, required this.child}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -106,11 +109,7 @@ class Shell extends HookConsumerWidget { final pageActionsButton = [ IconButton( - onPressed: () { - Navigator.of( - context, - ).push(MaterialPageRoute(builder: (context) => SettingsScreen())); - }, + onPressed: () => context.push(AppRoutes.settings), icon: const Icon(Symbols.settings), padding: EdgeInsets.all(8), constraints: BoxConstraints(), @@ -169,10 +168,7 @@ class Shell extends HookConsumerWidget { ), IconButton( icon: Icon(Symbols.home), - onPressed: () => Navigator.of(context).pushAndRemoveUntil( - MaterialPageRoute(builder: (context) => const LibraryScreen()), - (route) => false, - ), + onPressed: () => context.go(AppRoutes.library), iconSize: 16, padding: EdgeInsets.all(8), constraints: BoxConstraints(), @@ -246,13 +242,8 @@ class Shell extends HookConsumerWidget { // Settings button IconButton( icon: Icon(Symbols.settings), - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => SettingsScreen(), - ), - ); - }, + onPressed: () => + context.go(AppRoutes.settings), iconSize: 16, padding: EdgeInsets.all(8), constraints: BoxConstraints(), @@ -391,7 +382,7 @@ class Shell extends HookConsumerWidget { child: Stack( children: [ // Main Content - Positioned.fill(child: LibraryScreen()), + Positioned.fill(child: child), // Mini Player Positioned( left: 0, @@ -420,7 +411,7 @@ class Shell extends HookConsumerWidget { child: Stack( fit: StackFit.expand, children: [ - Positioned.fill(child: LibraryScreen()), + Positioned.fill(child: child), Positioned(left: 0, right: 0, bottom: 0, child: MiniPlayer()), ], ), diff --git a/pubspec.lock b/pubspec.lock index 2f12ac4..0ec2690 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -544,6 +544,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" + go_router: + dependency: "direct main" + description: + name: go_router + sha256: f02fd7d2a4dc512fec615529824fdd217fecb3a3d3de68360293a551f21634b3 + url: "https://pub.dev" + source: hosted + version: "14.8.1" graphs: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b5dc902..9530a69 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -61,6 +61,7 @@ dependencies: flutter_cache_manager: ^3.4.1 material_symbols_icons: ^4.2892.0 window_manager: ^0.5.1 + go_router: ^14.2.0 dev_dependencies: flutter_test: