diff --git a/build.yaml b/build.yaml index 17d5bc50..76771f22 100644 --- a/build.yaml +++ b/build.yaml @@ -4,6 +4,16 @@ targets: exclude: - bin/*.dart builders: + auto_route_generator:auto_route_generator: # this for @RoutePage + options: + enable_cached_builds: true + generate_for: + - lib/pages/**/*.dart + auto_route_generator:auto_router_generator: # this for @AutoRouterConfig + options: + enable_cached_builds: true + generate_for: + - lib/collections/routes.dart json_serializable: options: any_map: true diff --git a/lib/collections/intents.dart b/lib/collections/intents.dart index d0a0c8b6..e4e3fa07 100644 --- a/lib/collections/intents.dart +++ b/lib/collections/intents.dart @@ -3,17 +3,9 @@ import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:go_router/go_router.dart'; import 'package:spotube/collections/routes.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/modules/player/player_controls.dart'; -import 'package:spotube/pages/home/home.dart'; -import 'package:spotube/pages/library/user_albums.dart'; -import 'package:spotube/pages/library/user_artists.dart'; -import 'package:spotube/pages/library/user_downloads.dart'; -import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; -import 'package:spotube/pages/library/user_playlists.dart'; -import 'package:spotube/pages/lyrics/lyrics.dart'; -import 'package:spotube/pages/search/search.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/utils/platform.dart'; @@ -40,7 +32,7 @@ class PlayPauseAction extends Action { } class NavigationIntent extends Intent { - final GoRouter router; + final AppRouter router; final String path; const NavigationIntent(this.router, this.path); } @@ -48,7 +40,7 @@ class NavigationIntent extends Intent { class NavigationAction extends Action { @override invoke(intent) { - intent.router.go(intent.path); + intent.router.navigateNamed(intent.path); return null; } } @@ -66,39 +58,39 @@ enum HomeTabs { } class HomeTabIntent extends Intent { - final WidgetRef ref; + final AppRouter router; final HomeTabs tab; - const HomeTabIntent(this.ref, {required this.tab}); + const HomeTabIntent(this.router, {required this.tab}); } class HomeTabAction extends Action { @override invoke(intent) { - final router = intent.ref.read(routerProvider); + final router = intent.router; switch (intent.tab) { case HomeTabs.browse: - router.goNamed(HomePage.name); + router.navigate(const HomeRoute()); break; case HomeTabs.search: - router.goNamed(SearchPage.name); + router.navigate(const SearchRoute()); break; case HomeTabs.lyrics: - router.goNamed(LyricsPage.name); + router.navigate(LyricsRoute()); break; case HomeTabs.userPlaylists: - router.goNamed(UserPlaylistsPage.name); + router.navigate(const UserPlaylistsRoute()); break; case HomeTabs.userArtists: - router.goNamed(UserArtistsPage.name); + router.navigate(const UserArtistsRoute()); break; case HomeTabs.userAlbums: - router.goNamed(UserAlbumsPage.name); + router.navigate(const UserAlbumsRoute()); break; case HomeTabs.userLocalLibrary: - router.goNamed(UserLocalLibraryPage.name); + router.navigate(const UserLocalLibraryRoute()); break; case HomeTabs.userDownloads: - router.goNamed(UserDownloadsPage.name); + router.navigate(const UserDownloadsRoute()); break; } return null; diff --git a/lib/collections/routes.dart b/lib/collections/routes.dart index 4cd869cd..367e6eb8 100644 --- a/lib/collections/routes.dart +++ b/lib/collections/routes.dart @@ -1,365 +1,216 @@ -import 'package:flutter/foundation.dart' hide Category; -import 'package:flutter/widgets.dart'; -import 'package:go_router/go_router.dart'; +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotify/spotify.dart' hide Search; -import 'package:spotube/models/spotify/recommendation_seeds.dart'; -import 'package:spotube/pages/album/album.dart'; -import 'package:spotube/pages/connect/connect.dart'; -import 'package:spotube/pages/connect/control/control.dart'; -import 'package:spotube/pages/getting_started/getting_started.dart'; -import 'package:spotube/pages/home/feed/feed_section.dart'; -import 'package:spotube/pages/home/genres/genre_playlists.dart'; -import 'package:spotube/pages/home/genres/genres.dart'; -import 'package:spotube/pages/home/home.dart'; -import 'package:spotube/pages/lastfm_login/lastfm_login.dart'; -import 'package:spotube/pages/library/user_local_tracks/local_folder.dart'; -import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart'; -import 'package:spotube/pages/library/playlist_generate/playlist_generate_result.dart'; -import 'package:spotube/pages/library/user_albums.dart'; -import 'package:spotube/pages/library/user_artists.dart'; -import 'package:spotube/pages/library/user_downloads.dart'; -import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; -import 'package:spotube/pages/library/user_playlists.dart'; -import 'package:spotube/pages/lyrics/mini_lyrics.dart'; -import 'package:spotube/pages/playlist/liked_playlist.dart'; -import 'package:spotube/pages/playlist/playlist.dart'; -import 'package:spotube/pages/profile/profile.dart'; -import 'package:spotube/pages/search/search.dart'; -import 'package:spotube/pages/settings/blacklist.dart'; -import 'package:spotube/pages/settings/about.dart'; -import 'package:spotube/pages/settings/logs.dart'; -import 'package:spotube/pages/stats/albums/albums.dart'; -import 'package:spotube/pages/stats/artists/artists.dart'; -import 'package:spotube/pages/stats/fees/fees.dart'; -import 'package:spotube/pages/stats/minutes/minutes.dart'; -import 'package:spotube/pages/stats/playlists/playlists.dart'; -import 'package:spotube/pages/stats/stats.dart'; -import 'package:spotube/pages/stats/streams/streams.dart'; -import 'package:spotube/pages/track/track.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/services/kv_store/kv_store.dart'; -import 'package:spotube/components/spotube_page_route.dart'; -import 'package:spotube/pages/artist/artist.dart'; -import 'package:spotube/pages/library/library.dart'; -import 'package:spotube/pages/lyrics/lyrics.dart'; -import 'package:spotube/pages/root/root_app.dart'; -import 'package:spotube/pages/settings/settings.dart'; -import 'package:spotube/pages/mobile_login/mobile_login.dart'; final rootNavigatorKey = GlobalKey(); -final shellRouteNavigatorKey = GlobalKey(); -final routerProvider = Provider((ref) { - return GoRouter( - navigatorKey: rootNavigatorKey, - routes: [ - ShellRoute( - navigatorKey: shellRouteNavigatorKey, - builder: (context, state, child) => RootApp(child: child), - routes: [ - GoRoute( - path: "/", - name: HomePage.name, - redirect: (context, state) async { - final auth = await ref.read(authenticationProvider.future); - if (auth == null && !KVStoreService.doneGettingStarted) { - return "/getting-started"; - } +@AutoRouterConfig(replaceInRouteName: 'Screen|Page,Route') +class AppRouter extends RootStackRouter { + final WidgetRef ref; - return null; - }, - pageBuilder: (context, state) => - const SpotubePage(child: HomePage()), - routes: [ - GoRoute( - path: "genres", - name: GenrePage.name, - pageBuilder: (context, state) => - const SpotubePage(child: GenrePage()), - ), - GoRoute( - path: "genre/:categoryId", - name: GenrePlaylistsPage.name, - pageBuilder: (context, state) => SpotubePage( - child: GenrePlaylistsPage( - category: state.extra as Category, - ), - ), - ), - GoRoute( - path: "feeds/:feedId", - name: HomeFeedSectionPage.name, - pageBuilder: (context, state) => SpotubePage( - child: HomeFeedSectionPage( - sectionUri: state.pathParameters["feedId"] as String, - ), - ), - ) - ], - ), - GoRoute( - path: "/search", - name: SearchPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: SearchPage()), - ), - ShellRoute( - pageBuilder: (context, state, child) => - SpotubePage(child: LibraryPage(child: child)), - routes: [ - GoRoute( - path: "/library/playlists", - name: UserPlaylistsPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: UserPlaylistsPage()), - ), - GoRoute( - path: "/library/artists", - name: UserArtistsPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: UserArtistsPage()), - ), - GoRoute( - path: "/library/album", - name: UserAlbumsPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: UserAlbumsPage()), - ), - GoRoute( - path: "/library/local", - name: UserLocalLibraryPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: UserLocalLibraryPage()), - routes: [ - GoRoute( - path: "folder", - name: LocalLibraryPage.name, - parentNavigatorKey: shellRouteNavigatorKey, - pageBuilder: (context, state) { - assert(state.extra is String); - return SpotubePage( - child: LocalLibraryPage( - state.extra as String, - isDownloads: - state.uri.queryParameters["downloads"] != null, - isCache: state.uri.queryParameters["cache"] != null, - ), - ); - }, - ), - ]), - GoRoute( - path: "/library/downloads", - name: UserDownloadsPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: UserDownloadsPage()), - ), - ], - ), - GoRoute( - path: "/library/generate", - name: PlaylistGeneratorPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: PlaylistGeneratorPage()), - routes: [ - GoRoute( - path: "result", - name: PlaylistGenerateResultPage.name, - pageBuilder: (context, state) => SpotubePage( - child: PlaylistGenerateResultPage( - state: state.extra as GeneratePlaylistProviderInput, - ), - ), - ) - ], - ), - GoRoute( - path: "/lyrics", - name: LyricsPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: LyricsPage()), - ), - GoRoute( - path: "/settings", - name: SettingsPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: SettingsPage(), - ), - routes: [ - GoRoute( - path: "blacklist", - name: BlackListPage.name, - pageBuilder: (context, state) => SpotubeSlidePage( - child: const BlackListPage(), - ), - ), - if (!kIsWeb) - GoRoute( - path: "logs", - name: LogsPage.name, - pageBuilder: (context, state) => SpotubeSlidePage( - child: const LogsPage(), - ), - ), - GoRoute( - path: "about", - name: AboutSpotube.name, - pageBuilder: (context, state) => SpotubeSlidePage( - child: const AboutSpotube(), - ), - ), - ], - ), - GoRoute( - path: "/album/:id", - name: AlbumPage.name, - pageBuilder: (context, state) { - assert(state.extra is AlbumSimple); - return SpotubePage( - child: AlbumPage(album: state.extra as AlbumSimple), - ); - }, - ), - GoRoute( - path: "/artist/:id", - name: ArtistPage.name, - pageBuilder: (context, state) { - assert(state.pathParameters["id"] != null); - return SpotubePage( - child: ArtistPage(state.pathParameters["id"]!)); - }, - ), - GoRoute( - path: "/playlist/:id", - name: PlaylistPage.name, - pageBuilder: (context, state) { - assert(state.extra is PlaylistSimple); - return SpotubePage( - child: state.pathParameters["id"] == "user-liked-tracks" - ? LikedPlaylistPage(playlist: state.extra as PlaylistSimple) - : PlaylistPage(playlist: state.extra as PlaylistSimple), - ); - }, - ), - GoRoute( - path: "/track/:id", - name: TrackPage.name, - pageBuilder: (context, state) { - final id = state.pathParameters["id"]!; - return SpotubePage( - child: TrackPage(trackId: id), - ); - }, - ), - GoRoute( - path: "/connect", - name: ConnectPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: ConnectPage(), - ), - routes: [ - GoRoute( - path: "control", - name: ConnectControlPage.name, - pageBuilder: (context, state) { - return const SpotubePage( - child: ConnectControlPage(), - ); - }, - ) - ], - ), - GoRoute( - path: "/profile", - name: ProfilePage.name, - pageBuilder: (context, state) => - const SpotubePage(child: ProfilePage()), - ), - GoRoute( - path: "/stats", - name: StatsPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsPage(), - ), - routes: [ - GoRoute( - path: "minutes", - name: StatsMinutesPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsMinutesPage(), - ), - ), - GoRoute( - path: "streams", - name: StatsStreamsPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsStreamsPage(), - ), - ), - GoRoute( - path: "fees", - name: StatsStreamFeesPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsStreamFeesPage(), - ), - ), - GoRoute( - path: "artists", - name: StatsArtistsPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsArtistsPage(), - ), - ), - GoRoute( - path: "albums", - name: StatsAlbumsPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsAlbumsPage(), - ), - ), - GoRoute( - path: "playlists", - name: StatsPlaylistsPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsPlaylistsPage(), - ), - ), - ], - ) - ], - ), - GoRoute( - path: "/mini-player", - name: MiniLyricsPage.name, - parentNavigatorKey: rootNavigatorKey, - pageBuilder: (context, state) => SpotubePage( - child: MiniLyricsPage(prevSize: state.extra as Size), + AppRouter(this.ref) : super(navigatorKey: rootNavigatorKey); + + @override + List get guards => [ + AutoRouteGuardCallback( + (resolver, router) async { + final auth = await ref.read(authenticationProvider.future); + + if (auth == null && !KVStoreService.doneGettingStarted) { + resolver.redirect(const GettingStartedRoute()); + } else { + resolver.next(true); + } + }, ), - ), - GoRoute( - path: "/getting-started", - name: GettingStarting.name, - parentNavigatorKey: rootNavigatorKey, - pageBuilder: (context, state) => const SpotubePage( - child: GettingStarting(), + ]; + + @override + List get routes => [ + AutoRoute( + page: RootAppRoute.page, + path: "/", + initial: true, + children: [ + AutoRoute( + path: "browse", + page: HomeRoute.page, + initial: true, + ), + AutoRoute( + path: "home/genres", + page: GenreRoute.page, + ), + AutoRoute( + path: "home/genre/:categoryId", + page: GenrePlaylistsRoute.page, + ), + AutoRoute( + path: "home/feeds/:feedId", + page: HomeFeedSectionRoute.page, + ), + AutoRoute( + path: "search", + page: SearchRoute.page, + ), + AutoRoute( + path: "library", + page: LibraryRoute.page, + children: [ + AutoRoute( + path: "playlists", + page: UserPlaylistsRoute.page, + ), + AutoRoute( + path: "artists", + page: UserArtistsRoute.page, + ), + AutoRoute( + path: "album", + page: UserAlbumsRoute.page, + ), + AutoRoute( + path: "local", + page: UserLocalLibraryRoute.page, + ), + AutoRoute( + path: "local/folder", + page: LocalLibraryRoute.page, + // parentNavigatorKey: shellRouteNavigatorKey, + ), + AutoRoute( + path: "downloads", + page: UserDownloadsRoute.page, + ), + ], + ), + AutoRoute( + path: "library/generate", + page: PlaylistGeneratorRoute.page, + ), + AutoRoute( + path: "library/generate/result", + page: PlaylistGenerateResultRoute.page, + ), + AutoRoute( + path: "lyrics", + page: LyricsRoute.page, + ), + AutoRoute( + path: "settings", + page: SettingsRoute.page, + ), + AutoRoute( + path: "settings/blacklist", + page: BlackListRoute.page, + ), + if (!kIsWeb) + AutoRoute( + path: "settings/logs", + page: LogsRoute.page, + ), + AutoRoute( + path: "settings/about", + page: AboutSpotubeRoute.page, + ), + AutoRoute( + path: "album/:id", + page: AlbumRoute.page, + ), + AutoRoute( + path: "artist/:id", + page: ArtistRoute.page, + ), + AutoRoute( + path: "liked-tracks", + page: LikedPlaylistRoute.page, + ), + AutoRoute( + path: "playlist/:id", + page: PlaylistRoute.page, + guards: [ + AutoRouteGuard.redirect( + (resolver) { + final PlaylistRouteArgs(:id, :playlist) = + resolver.route.args as PlaylistRouteArgs; + if (id == "user-liked-tracks") { + return LikedPlaylistRoute(playlist: playlist); + } + + return null; + }, + ), + ], + ), + AutoRoute( + path: "track/:id", + page: TrackRoute.page, + ), + AutoRoute( + path: "connect", + page: ConnectRoute.page, + ), + AutoRoute( + path: "connect/control", + page: ConnectControlRoute.page, + ), + AutoRoute( + path: "profile", + page: ProfileRoute.page, + ), + AutoRoute( + path: "stats", + page: StatsRoute.page, + ), + AutoRoute( + path: "stats/minutes", + page: StatsMinutesRoute.page, + ), + AutoRoute( + path: "stats/streams", + page: StatsStreamsRoute.page, + ), + AutoRoute( + path: "stats/fees", + page: StatsStreamFeesRoute.page, + ), + AutoRoute( + path: "stats/artists", + page: StatsArtistsRoute.page, + ), + AutoRoute( + path: "stats/albums", + page: StatsAlbumsRoute.page, + ), + AutoRoute( + path: "stats/playlists", + page: StatsPlaylistsRoute.page, + ), + ], ), - ), - GoRoute( - path: "/login", - name: WebViewLogin.name, - parentNavigatorKey: rootNavigatorKey, - pageBuilder: (context, state) => const SpotubePage( - child: WebViewLogin(), + AutoRoute( + path: "/mini-player", + page: MiniLyricsRoute.page, + // parentNavigatorKey: rootNavigatorKey, ), - ), - GoRoute( - path: "/lastfm-login", - name: LastFMLoginPage.name, - parentNavigatorKey: rootNavigatorKey, - pageBuilder: (context, state) => - const SpotubePage(child: LastFMLoginPage()), - ), - ], - ); -}); + AutoRoute( + path: "/getting-started", + page: GettingStartedRoute.page, + // parentNavigatorKey: rootNavigatorKey, + ), + AutoRoute( + path: "/login", + page: WebViewLoginRoute.page, + // parentNavigatorKey: rootNavigatorKey, + ), + AutoRoute( + path: "/lastfm-login", + page: LastFMLoginRoute.page, + // parentNavigatorKey: rootNavigatorKey, + ), + ]; +} diff --git a/lib/collections/routes.gr.dart b/lib/collections/routes.gr.dart new file mode 100644 index 00000000..4572a23d --- /dev/null +++ b/lib/collections/routes.gr.dart @@ -0,0 +1,1143 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ************************************************************************** +// AutoRouterGenerator +// ************************************************************************** + +// ignore_for_file: type=lint +// coverage:ignore-file + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:auto_route/auto_route.dart' as _i40; +import 'package:flutter/material.dart' as _i43; +import 'package:flutter/widgets.dart' as _i44; +import 'package:shadcn_flutter/shadcn_flutter.dart' as _i41; +import 'package:spotify/spotify.dart' as _i42; +import 'package:spotube/models/spotify/recommendation_seeds.dart' as _i45; +import 'package:spotube/pages/album/album.dart' as _i2; +import 'package:spotube/pages/artist/artist.dart' as _i3; +import 'package:spotube/pages/connect/connect.dart' as _i6; +import 'package:spotube/pages/connect/control/control.dart' as _i5; +import 'package:spotube/pages/getting_started/getting_started.dart' as _i9; +import 'package:spotube/pages/home/feed/feed_section.dart' as _i10; +import 'package:spotube/pages/home/genres/genre_playlists.dart' as _i8; +import 'package:spotube/pages/home/genres/genres.dart' as _i7; +import 'package:spotube/pages/home/home.dart' as _i11; +import 'package:spotube/pages/lastfm_login/lastfm_login.dart' as _i12; +import 'package:spotube/pages/library/library.dart' as _i13; +import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart' + as _i20; +import 'package:spotube/pages/library/playlist_generate/playlist_generate_result.dart' + as _i19; +import 'package:spotube/pages/library/user_albums.dart' as _i34; +import 'package:spotube/pages/library/user_artists.dart' as _i35; +import 'package:spotube/pages/library/user_downloads.dart' as _i36; +import 'package:spotube/pages/library/user_local_tracks/local_folder.dart' + as _i15; +import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart' + as _i37; +import 'package:spotube/pages/library/user_playlists.dart' as _i38; +import 'package:spotube/pages/lyrics/lyrics.dart' as _i17; +import 'package:spotube/pages/lyrics/mini_lyrics.dart' as _i18; +import 'package:spotube/pages/mobile_login/mobile_login.dart' as _i39; +import 'package:spotube/pages/playlist/liked_playlist.dart' as _i14; +import 'package:spotube/pages/playlist/playlist.dart' as _i21; +import 'package:spotube/pages/profile/profile.dart' as _i22; +import 'package:spotube/pages/root/root_app.dart' as _i23; +import 'package:spotube/pages/search/search.dart' as _i24; +import 'package:spotube/pages/settings/about.dart' as _i1; +import 'package:spotube/pages/settings/blacklist.dart' as _i4; +import 'package:spotube/pages/settings/logs.dart' as _i16; +import 'package:spotube/pages/settings/settings.dart' as _i25; +import 'package:spotube/pages/stats/albums/albums.dart' as _i26; +import 'package:spotube/pages/stats/artists/artists.dart' as _i27; +import 'package:spotube/pages/stats/fees/fees.dart' as _i31; +import 'package:spotube/pages/stats/minutes/minutes.dart' as _i28; +import 'package:spotube/pages/stats/playlists/playlists.dart' as _i30; +import 'package:spotube/pages/stats/stats.dart' as _i29; +import 'package:spotube/pages/stats/streams/streams.dart' as _i32; +import 'package:spotube/pages/track/track.dart' as _i33; + +/// generated route for +/// [_i1.AboutSpotubePage] +class AboutSpotubeRoute extends _i40.PageRouteInfo { + const AboutSpotubeRoute({List<_i40.PageRouteInfo>? children}) + : super( + AboutSpotubeRoute.name, + initialChildren: children, + ); + + static const String name = 'AboutSpotubeRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i1.AboutSpotubePage(); + }, + ); +} + +/// generated route for +/// [_i2.AlbumPage] +class AlbumRoute extends _i40.PageRouteInfo { + AlbumRoute({ + _i41.Key? key, + required String id, + required _i42.AlbumSimple album, + List<_i40.PageRouteInfo>? children, + }) : super( + AlbumRoute.name, + args: AlbumRouteArgs( + key: key, + id: id, + album: album, + ), + rawPathParams: {'id': id}, + initialChildren: children, + ); + + static const String name = 'AlbumRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i2.AlbumPage( + key: args.key, + id: args.id, + album: args.album, + ); + }, + ); +} + +class AlbumRouteArgs { + const AlbumRouteArgs({ + this.key, + required this.id, + required this.album, + }); + + final _i41.Key? key; + + final String id; + + final _i42.AlbumSimple album; + + @override + String toString() { + return 'AlbumRouteArgs{key: $key, id: $id, album: $album}'; + } +} + +/// generated route for +/// [_i3.ArtistPage] +class ArtistRoute extends _i40.PageRouteInfo { + ArtistRoute({ + required String artistId, + _i41.Key? key, + List<_i40.PageRouteInfo>? children, + }) : super( + ArtistRoute.name, + args: ArtistRouteArgs( + artistId: artistId, + key: key, + ), + rawPathParams: {'id': artistId}, + initialChildren: children, + ); + + static const String name = 'ArtistRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + final args = data.argsAs( + orElse: () => ArtistRouteArgs(artistId: pathParams.getString('id'))); + return _i3.ArtistPage( + args.artistId, + key: args.key, + ); + }, + ); +} + +class ArtistRouteArgs { + const ArtistRouteArgs({ + required this.artistId, + this.key, + }); + + final String artistId; + + final _i41.Key? key; + + @override + String toString() { + return 'ArtistRouteArgs{artistId: $artistId, key: $key}'; + } +} + +/// generated route for +/// [_i4.BlackListPage] +class BlackListRoute extends _i40.PageRouteInfo { + const BlackListRoute({List<_i40.PageRouteInfo>? children}) + : super( + BlackListRoute.name, + initialChildren: children, + ); + + static const String name = 'BlackListRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i4.BlackListPage(); + }, + ); +} + +/// generated route for +/// [_i5.ConnectControlPage] +class ConnectControlRoute extends _i40.PageRouteInfo { + const ConnectControlRoute({List<_i40.PageRouteInfo>? children}) + : super( + ConnectControlRoute.name, + initialChildren: children, + ); + + static const String name = 'ConnectControlRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i5.ConnectControlPage(); + }, + ); +} + +/// generated route for +/// [_i6.ConnectPage] +class ConnectRoute extends _i40.PageRouteInfo { + const ConnectRoute({List<_i40.PageRouteInfo>? children}) + : super( + ConnectRoute.name, + initialChildren: children, + ); + + static const String name = 'ConnectRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i6.ConnectPage(); + }, + ); +} + +/// generated route for +/// [_i7.GenrePage] +class GenreRoute extends _i40.PageRouteInfo { + const GenreRoute({List<_i40.PageRouteInfo>? children}) + : super( + GenreRoute.name, + initialChildren: children, + ); + + static const String name = 'GenreRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i7.GenrePage(); + }, + ); +} + +/// generated route for +/// [_i8.GenrePlaylistsPage] +class GenrePlaylistsRoute extends _i40.PageRouteInfo { + GenrePlaylistsRoute({ + _i43.Key? key, + required String id, + required _i42.Category category, + List<_i40.PageRouteInfo>? children, + }) : super( + GenrePlaylistsRoute.name, + args: GenrePlaylistsRouteArgs( + key: key, + id: id, + category: category, + ), + rawPathParams: {'categoryId': id}, + initialChildren: children, + ); + + static const String name = 'GenrePlaylistsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i8.GenrePlaylistsPage( + key: args.key, + id: args.id, + category: args.category, + ); + }, + ); +} + +class GenrePlaylistsRouteArgs { + const GenrePlaylistsRouteArgs({ + this.key, + required this.id, + required this.category, + }); + + final _i43.Key? key; + + final String id; + + final _i42.Category category; + + @override + String toString() { + return 'GenrePlaylistsRouteArgs{key: $key, id: $id, category: $category}'; + } +} + +/// generated route for +/// [_i9.GettingStartedPage] +class GettingStartedRoute extends _i40.PageRouteInfo { + const GettingStartedRoute({List<_i40.PageRouteInfo>? children}) + : super( + GettingStartedRoute.name, + initialChildren: children, + ); + + static const String name = 'GettingStartedRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i9.GettingStartedPage(); + }, + ); +} + +/// generated route for +/// [_i10.HomeFeedSectionPage] +class HomeFeedSectionRoute + extends _i40.PageRouteInfo { + HomeFeedSectionRoute({ + _i41.Key? key, + required String sectionUri, + List<_i40.PageRouteInfo>? children, + }) : super( + HomeFeedSectionRoute.name, + args: HomeFeedSectionRouteArgs( + key: key, + sectionUri: sectionUri, + ), + rawPathParams: {'feedId': sectionUri}, + initialChildren: children, + ); + + static const String name = 'HomeFeedSectionRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + final args = data.argsAs( + orElse: () => HomeFeedSectionRouteArgs( + sectionUri: pathParams.getString('feedId'))); + return _i10.HomeFeedSectionPage( + key: args.key, + sectionUri: args.sectionUri, + ); + }, + ); +} + +class HomeFeedSectionRouteArgs { + const HomeFeedSectionRouteArgs({ + this.key, + required this.sectionUri, + }); + + final _i41.Key? key; + + final String sectionUri; + + @override + String toString() { + return 'HomeFeedSectionRouteArgs{key: $key, sectionUri: $sectionUri}'; + } +} + +/// generated route for +/// [_i11.HomePage] +class HomeRoute extends _i40.PageRouteInfo { + const HomeRoute({List<_i40.PageRouteInfo>? children}) + : super( + HomeRoute.name, + initialChildren: children, + ); + + static const String name = 'HomeRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i11.HomePage(); + }, + ); +} + +/// generated route for +/// [_i12.LastFMLoginPage] +class LastFMLoginRoute extends _i40.PageRouteInfo { + const LastFMLoginRoute({List<_i40.PageRouteInfo>? children}) + : super( + LastFMLoginRoute.name, + initialChildren: children, + ); + + static const String name = 'LastFMLoginRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i12.LastFMLoginPage(); + }, + ); +} + +/// generated route for +/// [_i13.LibraryPage] +class LibraryRoute extends _i40.PageRouteInfo { + const LibraryRoute({List<_i40.PageRouteInfo>? children}) + : super( + LibraryRoute.name, + initialChildren: children, + ); + + static const String name = 'LibraryRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i13.LibraryPage(); + }, + ); +} + +/// generated route for +/// [_i14.LikedPlaylistPage] +class LikedPlaylistRoute extends _i40.PageRouteInfo { + LikedPlaylistRoute({ + _i44.Key? key, + required _i42.PlaylistSimple playlist, + List<_i40.PageRouteInfo>? children, + }) : super( + LikedPlaylistRoute.name, + args: LikedPlaylistRouteArgs( + key: key, + playlist: playlist, + ), + initialChildren: children, + ); + + static const String name = 'LikedPlaylistRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i14.LikedPlaylistPage( + key: args.key, + playlist: args.playlist, + ); + }, + ); +} + +class LikedPlaylistRouteArgs { + const LikedPlaylistRouteArgs({ + this.key, + required this.playlist, + }); + + final _i44.Key? key; + + final _i42.PlaylistSimple playlist; + + @override + String toString() { + return 'LikedPlaylistRouteArgs{key: $key, playlist: $playlist}'; + } +} + +/// generated route for +/// [_i15.LocalLibraryPage] +class LocalLibraryRoute extends _i40.PageRouteInfo { + LocalLibraryRoute({ + required String location, + _i41.Key? key, + bool isDownloads = false, + bool isCache = false, + List<_i40.PageRouteInfo>? children, + }) : super( + LocalLibraryRoute.name, + args: LocalLibraryRouteArgs( + location: location, + key: key, + isDownloads: isDownloads, + isCache: isCache, + ), + initialChildren: children, + ); + + static const String name = 'LocalLibraryRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i15.LocalLibraryPage( + args.location, + key: args.key, + isDownloads: args.isDownloads, + isCache: args.isCache, + ); + }, + ); +} + +class LocalLibraryRouteArgs { + const LocalLibraryRouteArgs({ + required this.location, + this.key, + this.isDownloads = false, + this.isCache = false, + }); + + final String location; + + final _i41.Key? key; + + final bool isDownloads; + + final bool isCache; + + @override + String toString() { + return 'LocalLibraryRouteArgs{location: $location, key: $key, isDownloads: $isDownloads, isCache: $isCache}'; + } +} + +/// generated route for +/// [_i16.LogsPage] +class LogsRoute extends _i40.PageRouteInfo { + const LogsRoute({List<_i40.PageRouteInfo>? children}) + : super( + LogsRoute.name, + initialChildren: children, + ); + + static const String name = 'LogsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i16.LogsPage(); + }, + ); +} + +/// generated route for +/// [_i17.LyricsPage] +class LyricsRoute extends _i40.PageRouteInfo { + LyricsRoute({ + _i41.Key? key, + bool isModal = false, + List<_i40.PageRouteInfo>? children, + }) : super( + LyricsRoute.name, + args: LyricsRouteArgs( + key: key, + isModal: isModal, + ), + initialChildren: children, + ); + + static const String name = 'LyricsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = + data.argsAs(orElse: () => const LyricsRouteArgs()); + return _i17.LyricsPage( + key: args.key, + isModal: args.isModal, + ); + }, + ); +} + +class LyricsRouteArgs { + const LyricsRouteArgs({ + this.key, + this.isModal = false, + }); + + final _i41.Key? key; + + final bool isModal; + + @override + String toString() { + return 'LyricsRouteArgs{key: $key, isModal: $isModal}'; + } +} + +/// generated route for +/// [_i18.MiniLyricsPage] +class MiniLyricsRoute extends _i40.PageRouteInfo { + MiniLyricsRoute({ + _i41.Key? key, + required _i41.Size prevSize, + List<_i40.PageRouteInfo>? children, + }) : super( + MiniLyricsRoute.name, + args: MiniLyricsRouteArgs( + key: key, + prevSize: prevSize, + ), + initialChildren: children, + ); + + static const String name = 'MiniLyricsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i18.MiniLyricsPage( + key: args.key, + prevSize: args.prevSize, + ); + }, + ); +} + +class MiniLyricsRouteArgs { + const MiniLyricsRouteArgs({ + this.key, + required this.prevSize, + }); + + final _i41.Key? key; + + final _i41.Size prevSize; + + @override + String toString() { + return 'MiniLyricsRouteArgs{key: $key, prevSize: $prevSize}'; + } +} + +/// generated route for +/// [_i19.PlaylistGenerateResultPage] +class PlaylistGenerateResultRoute + extends _i40.PageRouteInfo { + PlaylistGenerateResultRoute({ + _i41.Key? key, + required _i45.GeneratePlaylistProviderInput state, + List<_i40.PageRouteInfo>? children, + }) : super( + PlaylistGenerateResultRoute.name, + args: PlaylistGenerateResultRouteArgs( + key: key, + state: state, + ), + initialChildren: children, + ); + + static const String name = 'PlaylistGenerateResultRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i19.PlaylistGenerateResultPage( + key: args.key, + state: args.state, + ); + }, + ); +} + +class PlaylistGenerateResultRouteArgs { + const PlaylistGenerateResultRouteArgs({ + this.key, + required this.state, + }); + + final _i41.Key? key; + + final _i45.GeneratePlaylistProviderInput state; + + @override + String toString() { + return 'PlaylistGenerateResultRouteArgs{key: $key, state: $state}'; + } +} + +/// generated route for +/// [_i20.PlaylistGeneratorPage] +class PlaylistGeneratorRoute extends _i40.PageRouteInfo { + const PlaylistGeneratorRoute({List<_i40.PageRouteInfo>? children}) + : super( + PlaylistGeneratorRoute.name, + initialChildren: children, + ); + + static const String name = 'PlaylistGeneratorRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i20.PlaylistGeneratorPage(); + }, + ); +} + +/// generated route for +/// [_i21.PlaylistPage] +class PlaylistRoute extends _i40.PageRouteInfo { + PlaylistRoute({ + _i43.Key? key, + required String id, + required _i42.PlaylistSimple playlist, + List<_i40.PageRouteInfo>? children, + }) : super( + PlaylistRoute.name, + args: PlaylistRouteArgs( + key: key, + id: id, + playlist: playlist, + ), + rawPathParams: {'id': id}, + initialChildren: children, + ); + + static const String name = 'PlaylistRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i21.PlaylistPage( + key: args.key, + id: args.id, + playlist: args.playlist, + ); + }, + ); +} + +class PlaylistRouteArgs { + const PlaylistRouteArgs({ + this.key, + required this.id, + required this.playlist, + }); + + final _i43.Key? key; + + final String id; + + final _i42.PlaylistSimple playlist; + + @override + String toString() { + return 'PlaylistRouteArgs{key: $key, id: $id, playlist: $playlist}'; + } +} + +/// generated route for +/// [_i22.ProfilePage] +class ProfileRoute extends _i40.PageRouteInfo { + const ProfileRoute({List<_i40.PageRouteInfo>? children}) + : super( + ProfileRoute.name, + initialChildren: children, + ); + + static const String name = 'ProfileRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i22.ProfilePage(); + }, + ); +} + +/// generated route for +/// [_i23.RootAppPage] +class RootAppRoute extends _i40.PageRouteInfo { + const RootAppRoute({List<_i40.PageRouteInfo>? children}) + : super( + RootAppRoute.name, + initialChildren: children, + ); + + static const String name = 'RootAppRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i23.RootAppPage(); + }, + ); +} + +/// generated route for +/// [_i24.SearchPage] +class SearchRoute extends _i40.PageRouteInfo { + const SearchRoute({List<_i40.PageRouteInfo>? children}) + : super( + SearchRoute.name, + initialChildren: children, + ); + + static const String name = 'SearchRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i24.SearchPage(); + }, + ); +} + +/// generated route for +/// [_i25.SettingsPage] +class SettingsRoute extends _i40.PageRouteInfo { + const SettingsRoute({List<_i40.PageRouteInfo>? children}) + : super( + SettingsRoute.name, + initialChildren: children, + ); + + static const String name = 'SettingsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i25.SettingsPage(); + }, + ); +} + +/// generated route for +/// [_i26.StatsAlbumsPage] +class StatsAlbumsRoute extends _i40.PageRouteInfo { + const StatsAlbumsRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsAlbumsRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsAlbumsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i26.StatsAlbumsPage(); + }, + ); +} + +/// generated route for +/// [_i27.StatsArtistsPage] +class StatsArtistsRoute extends _i40.PageRouteInfo { + const StatsArtistsRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsArtistsRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsArtistsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i27.StatsArtistsPage(); + }, + ); +} + +/// generated route for +/// [_i28.StatsMinutesPage] +class StatsMinutesRoute extends _i40.PageRouteInfo { + const StatsMinutesRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsMinutesRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsMinutesRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i28.StatsMinutesPage(); + }, + ); +} + +/// generated route for +/// [_i29.StatsPage] +class StatsRoute extends _i40.PageRouteInfo { + const StatsRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i29.StatsPage(); + }, + ); +} + +/// generated route for +/// [_i30.StatsPlaylistsPage] +class StatsPlaylistsRoute extends _i40.PageRouteInfo { + const StatsPlaylistsRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsPlaylistsRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsPlaylistsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i30.StatsPlaylistsPage(); + }, + ); +} + +/// generated route for +/// [_i31.StatsStreamFeesPage] +class StatsStreamFeesRoute extends _i40.PageRouteInfo { + const StatsStreamFeesRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsStreamFeesRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsStreamFeesRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i31.StatsStreamFeesPage(); + }, + ); +} + +/// generated route for +/// [_i32.StatsStreamsPage] +class StatsStreamsRoute extends _i40.PageRouteInfo { + const StatsStreamsRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsStreamsRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsStreamsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i32.StatsStreamsPage(); + }, + ); +} + +/// generated route for +/// [_i33.TrackPage] +class TrackRoute extends _i40.PageRouteInfo { + TrackRoute({ + _i41.Key? key, + required String trackId, + List<_i40.PageRouteInfo>? children, + }) : super( + TrackRoute.name, + args: TrackRouteArgs( + key: key, + trackId: trackId, + ), + rawPathParams: {'id': trackId}, + initialChildren: children, + ); + + static const String name = 'TrackRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + final args = data.argsAs( + orElse: () => TrackRouteArgs(trackId: pathParams.getString('id'))); + return _i33.TrackPage( + key: args.key, + trackId: args.trackId, + ); + }, + ); +} + +class TrackRouteArgs { + const TrackRouteArgs({ + this.key, + required this.trackId, + }); + + final _i41.Key? key; + + final String trackId; + + @override + String toString() { + return 'TrackRouteArgs{key: $key, trackId: $trackId}'; + } +} + +/// generated route for +/// [_i34.UserAlbumsPage] +class UserAlbumsRoute extends _i40.PageRouteInfo { + const UserAlbumsRoute({List<_i40.PageRouteInfo>? children}) + : super( + UserAlbumsRoute.name, + initialChildren: children, + ); + + static const String name = 'UserAlbumsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i34.UserAlbumsPage(); + }, + ); +} + +/// generated route for +/// [_i35.UserArtistsPage] +class UserArtistsRoute extends _i40.PageRouteInfo { + const UserArtistsRoute({List<_i40.PageRouteInfo>? children}) + : super( + UserArtistsRoute.name, + initialChildren: children, + ); + + static const String name = 'UserArtistsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i35.UserArtistsPage(); + }, + ); +} + +/// generated route for +/// [_i36.UserDownloadsPage] +class UserDownloadsRoute extends _i40.PageRouteInfo { + const UserDownloadsRoute({List<_i40.PageRouteInfo>? children}) + : super( + UserDownloadsRoute.name, + initialChildren: children, + ); + + static const String name = 'UserDownloadsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i36.UserDownloadsPage(); + }, + ); +} + +/// generated route for +/// [_i37.UserLocalLibraryPage] +class UserLocalLibraryRoute extends _i40.PageRouteInfo { + const UserLocalLibraryRoute({List<_i40.PageRouteInfo>? children}) + : super( + UserLocalLibraryRoute.name, + initialChildren: children, + ); + + static const String name = 'UserLocalLibraryRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i37.UserLocalLibraryPage(); + }, + ); +} + +/// generated route for +/// [_i38.UserPlaylistsPage] +class UserPlaylistsRoute extends _i40.PageRouteInfo { + const UserPlaylistsRoute({List<_i40.PageRouteInfo>? children}) + : super( + UserPlaylistsRoute.name, + initialChildren: children, + ); + + static const String name = 'UserPlaylistsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i38.UserPlaylistsPage(); + }, + ); +} + +/// generated route for +/// [_i39.WebViewLoginPage] +class WebViewLoginRoute extends _i40.PageRouteInfo { + const WebViewLoginRoute({List<_i40.PageRouteInfo>? children}) + : super( + WebViewLoginRoute.name, + initialChildren: children, + ); + + static const String name = 'WebViewLoginRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i39.WebViewLoginPage(); + }, + ); +} diff --git a/lib/collections/side_bar_tiles.dart b/lib/collections/side_bar_tiles.dart index f12517bb..c74d18c7 100644 --- a/lib/collections/side_bar_tiles.dart +++ b/lib/collections/side_bar_tiles.dart @@ -1,51 +1,45 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:spotube/pages/home/home.dart'; -import 'package:spotube/pages/library/user_albums.dart'; -import 'package:spotube/pages/library/user_artists.dart'; -import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; -import 'package:spotube/pages/library/user_playlists.dart'; -import 'package:spotube/pages/lyrics/lyrics.dart'; -import 'package:spotube/pages/search/search.dart'; -import 'package:spotube/pages/stats/stats.dart'; class SideBarTiles { final IconData icon; final String title; final String id; - final String name; + final PageRouteInfo route; SideBarTiles({ required this.icon, required this.title, required this.id, - required this.name, + required this.route, }); } List getSidebarTileList(AppLocalizations l10n) => [ SideBarTiles( id: "browse", - name: HomePage.name, + route: const HomeRoute(), icon: SpotubeIcons.home, title: l10n.browse, ), SideBarTiles( id: "search", - name: SearchPage.name, + route: const SearchRoute(), icon: SpotubeIcons.search, title: l10n.search, ), SideBarTiles( id: "lyrics", - name: LyricsPage.name, + route: LyricsRoute(), icon: SpotubeIcons.music, title: l10n.lyrics, ), SideBarTiles( id: "stats", - name: StatsPage.name, + route: const StatsRoute(), icon: SpotubeIcons.chart, title: l10n.stats, ), @@ -55,25 +49,25 @@ List getSidebarLibraryTileList(AppLocalizations l10n) => [ SideBarTiles( id: "playlists", title: l10n.playlists, - name: UserPlaylistsPage.name, + route: const UserPlaylistsRoute(), icon: SpotubeIcons.playlist, ), SideBarTiles( id: "artists", title: l10n.artists, - name: UserArtistsPage.name, + route: const UserArtistsRoute(), icon: SpotubeIcons.artist, ), SideBarTiles( id: "albums", title: l10n.albums, - name: UserAlbumsPage.name, + route: const UserAlbumsRoute(), icon: SpotubeIcons.album, ), SideBarTiles( id: "local_library", title: l10n.local_library, - name: UserLocalLibraryPage.name, + route: const UserLocalLibraryRoute(), icon: SpotubeIcons.device, ), ]; @@ -81,25 +75,25 @@ List getSidebarLibraryTileList(AppLocalizations l10n) => [ List getNavbarTileList(AppLocalizations l10n) => [ SideBarTiles( id: "browse", - name: HomePage.name, + route: const HomeRoute(), icon: SpotubeIcons.home, title: l10n.browse, ), SideBarTiles( id: "search", - name: SearchPage.name, + route: const SearchRoute(), icon: SpotubeIcons.search, title: l10n.search, ), SideBarTiles( id: "library", - name: UserPlaylistsPage.name, + route: const UserPlaylistsRoute(), icon: SpotubeIcons.library, title: l10n.library, ), SideBarTiles( id: "stats", - name: StatsPage.name, + route: const StatsRoute(), icon: SpotubeIcons.chart, title: l10n.stats, ), diff --git a/lib/components/dialogs/track_details_dialog.dart b/lib/components/dialogs/track_details_dialog.dart index 1296ae0e..bfb4a318 100644 --- a/lib/components/dialogs/track_details_dialog.dart +++ b/lib/components/dialogs/track_details_dialog.dart @@ -1,6 +1,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/links/artist_link.dart'; import 'package:spotube/components/links/hyper_link.dart'; @@ -32,8 +33,7 @@ class TrackDetailsDialog extends HookWidget { ), context.l10n.album: LinkText( track.album!.name!, - "/album/${track.album?.id}", - extra: track.album, + AlbumRoute(album: track.album!, id: track.album!.id!), overflow: TextOverflow.ellipsis, style: const TextStyle(color: Colors.blue), ), diff --git a/lib/components/fallbacks/anonymous_fallback.dart b/lib/components/fallbacks/anonymous_fallback.dart index 373e0454..714a0df5 100644 --- a/lib/components/fallbacks/anonymous_fallback.dart +++ b/lib/components/fallbacks/anonymous_fallback.dart @@ -1,13 +1,13 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/settings/settings.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/utils/platform.dart'; -import 'package:spotube/utils/service_utils.dart'; class AnonymousFallback extends ConsumerWidget { final Widget? child; @@ -40,7 +40,7 @@ class AnonymousFallback extends ConsumerWidget { Text(context.l10n.not_logged_in), Button.primary( child: Text(context.l10n.login_with_spotify), - onPressed: () => ServiceUtils.pushNamed(context, SettingsPage.name), + onPressed: () => context.pushRoute(const SettingsRoute()), ) ], ), diff --git a/lib/components/links/artist_link.dart b/lib/components/links/artist_link.dart index c6ea5c14..cdd7f659 100644 --- a/lib/components/links/artist_link.dart +++ b/lib/components/links/artist_link.dart @@ -1,9 +1,9 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/links/anchor_button.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/artist/artist.dart'; -import 'package:spotube/utils/service_utils.dart'; class ArtistLink extends StatelessWidget { final List artists; @@ -49,13 +49,8 @@ class ArtistLink extends StatelessWidget { if (onRouteChange != null) { onRouteChange?.call("/artist/${artist.value.id}"); } else { - ServiceUtils.pushNamed( - context, - ArtistPage.name, - pathParameters: { - "id": artist.value.id!, - }, - ); + context + .pushRoute(ArtistRoute(artistId: artist.value.id!)); } }, overflow: TextOverflow.ellipsis, diff --git a/lib/components/links/link_text.dart b/lib/components/links/link_text.dart index a54c8b9f..f21aa032 100644 --- a/lib/components/links/link_text.dart +++ b/lib/components/links/link_text.dart @@ -1,15 +1,14 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/components/links/anchor_button.dart'; -import 'package:spotube/utils/service_utils.dart'; class LinkText extends StatelessWidget { final String text; final TextStyle style; final TextAlign? textAlign; final TextOverflow? overflow; - final String route; + final PageRouteInfo route; final int? maxLines; - final T? extra; final bool push; const LinkText( @@ -17,7 +16,6 @@ class LinkText extends StatelessWidget { this.route, { super.key, this.textAlign, - this.extra, this.overflow, this.style = const TextStyle(), this.maxLines, @@ -30,9 +28,9 @@ class LinkText extends StatelessWidget { text, onTap: () { if (push) { - ServiceUtils.push(context, route, extra: extra); + context.pushRoute(route); } else { - ServiceUtils.navigate(context, route, extra: extra); + context.navigateTo(route); } }, key: key, diff --git a/lib/components/spotube_page_route.dart b/lib/components/spotube_page_route.dart index 6d152dd5..cff32975 100644 --- a/lib/components/spotube_page_route.dart +++ b/lib/components/spotube_page_route.dart @@ -1,25 +1,24 @@ import 'package:shadcn_flutter/shadcn_flutter.dart'; -import 'package:go_router/go_router.dart'; class SpotubePage extends MaterialPage { const SpotubePage({required super.child}); } -class SpotubeSlidePage extends CustomTransitionPage { - SpotubeSlidePage({ - required super.child, - super.key, - }) : super( - reverseTransitionDuration: const Duration(milliseconds: 150), - transitionDuration: const Duration(milliseconds: 150), - transitionsBuilder: (context, animation, secondaryAnimation, child) { - return SlideTransition( - position: Tween( - begin: const Offset(1, 0), - end: Offset.zero, - ).animate(animation), - child: child, - ); - }, - ); -} +// class SpotubeSlidePage extends CustomTransitionPage { +// SpotubeSlidePage({ +// required super.child, +// super.key, +// }) : super( +// reverseTransitionDuration: const Duration(milliseconds: 150), +// transitionDuration: const Duration(milliseconds: 150), +// transitionsBuilder: (context, animation, secondaryAnimation, child) { +// return SlideTransition( +// position: Tween( +// begin: const Offset(1, 0), +// end: Offset.zero, +// ).animate(animation), +// child: child, +// ); +// }, +// ); +// } diff --git a/lib/components/track_tile/track_options.dart b/lib/components/track_tile/track_options.dart index 14514cde..66cee95f 100644 --- a/lib/components/track_tile/track_options.dart +++ b/lib/components/track_tile/track_options.dart @@ -1,14 +1,16 @@ import 'dart:io'; +import 'package:auto_route/auto_route.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotify/spotify.dart' hide Offset; import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/adaptive/adaptive_pop_sheet_list.dart'; import 'package:spotube/components/dialogs/playlist_add_track_dialog.dart'; @@ -22,7 +24,6 @@ import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/local_track.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/provider/download_manager_provider.dart'; @@ -30,7 +31,6 @@ import 'package:spotube/provider/local_tracks/local_tracks_provider.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/provider/spotify_provider.dart'; -import 'package:spotube/utils/service_utils.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -166,7 +166,6 @@ class TrackOptions extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final mediaQuery = MediaQuery.of(context); - final router = GoRouter.of(context); final ThemeData(:colorScheme) = Theme.of(context); final playlist = ref.watch(audioPlayerProvider); @@ -211,9 +210,8 @@ class TrackOptions extends HookConsumerWidget { onSelected: (value) async { switch (value) { case TrackOptionValue.album: - await router.push( - '/album/${track.album!.id}', - extra: track.album!, + await context.pushRoute( + AlbumRoute(id: track.album!.id!, album: track.album!), ); break; case TrackOptionValue.delete: @@ -347,12 +345,8 @@ class TrackOptions extends HookConsumerWidget { alignment: Alignment.centerLeft, child: ArtistLink( artists: track.artists!, - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track.id!, - }, + onOverflowArtistClick: () => context.pushRoute( + TrackRoute(trackId: track.id!), ), ), ), diff --git a/lib/components/track_tile/track_tile.dart b/lib/components/track_tile/track_tile.dart index 0ca14979..71aad728 100644 --- a/lib/components/track_tile/track_tile.dart +++ b/lib/components/track_tile/track_tile.dart @@ -1,13 +1,14 @@ import 'dart:async'; +import 'package:auto_route/auto_route.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/hover_builder.dart'; import 'package:spotube/components/image/universal_image.dart'; @@ -21,12 +22,10 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/duration.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/models/local_track.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart'; import 'package:spotube/provider/audio_player/state.dart'; import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/utils/platform.dart'; -import 'package:spotube/utils/service_utils.dart'; class TrackTile extends HookConsumerWidget { /// [index] will not be shown if null @@ -234,12 +233,8 @@ class TrackTile extends HookConsumerWidget { padding: (context, states) => EdgeInsets.zero, ), onPressed: () { - context.pushNamed( - TrackPage.name, - pathParameters: { - "id": track.id!, - }, - ); + context + .pushRoute(TrackRoute(trackId: track.id!)); }, child: Text( track.name!, @@ -266,8 +261,8 @@ class TrackTile extends HookConsumerWidget { alignment: Alignment.centerLeft, child: LinkText( track.album!.name!, - "/album/${track.album?.id}", - extra: track.album, + AlbumRoute( + album: track.album!, id: track.album!.id!), push: true, overflow: TextOverflow.ellipsis, ), @@ -288,13 +283,11 @@ class TrackTile extends HookConsumerWidget { constraints: const BoxConstraints(maxHeight: 40), child: ArtistLink( artists: track.artists ?? [], - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track.id!, - }, - ), + onOverflowArtistClick: () { + context.pushRoute( + TrackRoute(trackId: track.id!), + ); + }, ), ), ), diff --git a/lib/hooks/configurators/use_deep_linking.dart b/lib/hooks/configurators/use_deep_linking.dart index ec6d8516..045fe016 100644 --- a/lib/hooks/configurators/use_deep_linking.dart +++ b/lib/hooks/configurators/use_deep_linking.dart @@ -4,6 +4,7 @@ import 'package:app_links/app_links.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/routes.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/provider/spotify_provider.dart'; import 'package:flutter_sharing_intent/flutter_sharing_intent.dart'; import 'package:flutter_sharing_intent/model/sharing_file.dart'; @@ -13,10 +14,9 @@ import 'package:spotube/utils/platform.dart'; final appLinks = AppLinks(); final linkStream = appLinks.stringLinkStream.asBroadcastStream(); -void useDeepLinking(WidgetRef ref) { +void useDeepLinking(WidgetRef ref, AppRouter router) { // single instance no worries final spotify = ref.watch(spotifyProvider); - final router = ref.watch(routerProvider); useEffect(() { void uriListener(List files) async { @@ -27,24 +27,20 @@ void useDeepLinking(WidgetRef ref) { switch (url.pathSegments.first) { case "album": + final album = await spotify.albums.get(url.pathSegments.last); router.push( - "/album/${url.pathSegments.last}", - extra: await spotify.albums.get(url.pathSegments.last), + AlbumRoute(id: album.id!, album: album), ); break; case "artist": - router.push("/artist/${url.pathSegments.last}"); + router.push(ArtistRoute(artistId: url.pathSegments.last)); break; case "playlist": - router.push( - "/playlist/${url.pathSegments.last}", - extra: await spotify.playlists.get(url.pathSegments.last), - ); + final playlist = await spotify.playlists.get(url.pathSegments.last); + router.push(PlaylistRoute(id: playlist.id!, playlist: playlist)); break; case "track": - router.push( - "/track/${url.pathSegments.last}", - ); + router.push(TrackRoute(trackId: url.pathSegments.last)); break; default: break; @@ -68,21 +64,21 @@ void useDeepLinking(WidgetRef ref) { switch (startSegment) { case "spotify:album": + final album = await spotify.albums.get(endSegment); await router.push( - "/album/$endSegment", - extra: await spotify.albums.get(endSegment), + AlbumRoute(id: album.id!, album: album), ); break; case "spotify:artist": - await router.push("/artist/$endSegment"); + await router.push(ArtistRoute(artistId: endSegment)); break; case "spotify:track": - await router.push("/track/$endSegment"); + await router.push(TrackRoute(trackId: endSegment)); break; case "spotify:playlist": + final playlist = await spotify.playlists.get(endSegment); await router.push( - "/playlist/$endSegment", - extra: await spotify.playlists.get(endSegment), + PlaylistRoute(id: playlist.id!, playlist: playlist), ); break; default: diff --git a/lib/main.dart b/lib/main.dart index 3994fd50..016c0fea 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -17,8 +17,8 @@ import 'package:metadata_god/metadata_god.dart'; import 'package:smtc_windows/smtc_windows.dart'; import 'package:spotube/collections/env.dart'; import 'package:spotube/collections/initializers.dart'; -import 'package:spotube/collections/routes.dart'; import 'package:spotube/collections/intents.dart'; +import 'package:spotube/collections/routes.dart'; import 'package:spotube/hooks/configurators/use_close_behavior.dart'; import 'package:spotube/hooks/configurators/use_deep_linking.dart'; import 'package:spotube/hooks/configurators/use_disable_battery_optimizations.dart'; @@ -133,7 +133,7 @@ class Spotube extends HookConsumerWidget { final locale = ref.watch(userPreferencesProvider.select((s) => s.locale)); final accentMaterialColor = ref.watch(userPreferencesProvider.select((s) => s.accentColorScheme)); - final router = ref.watch(routerProvider); + final router = useMemoized(() => AppRouter(ref), []); final hasTouchSupport = useHasTouch(); ref.listen(audioPlayerStreamListenersProvider, (_, __) {}); @@ -144,7 +144,7 @@ class Spotube extends HookConsumerWidget { useFixWindowStretching(); useDisableBatteryOptimizations(); - useDeepLinking(ref); + useDeepLinking(ref, router); useCloseBehavior(ref); useGetStoragePermissions(ref); @@ -171,7 +171,7 @@ class Spotube extends HookConsumerWidget { GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], - routerConfig: router, + routerConfig: router.config(), debugShowCheckedModeBanner: false, title: 'Spotube', builder: (context, child) { @@ -240,42 +240,42 @@ class Spotube extends HookConsumerWidget { LogicalKeyboardKey.digit1, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.browse), + ): HomeTabIntent(router, tab: HomeTabs.browse), LogicalKeySet( LogicalKeyboardKey.digit2, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.search), + ): HomeTabIntent(router, tab: HomeTabs.search), LogicalKeySet( LogicalKeyboardKey.digit3, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.lyrics), + ): HomeTabIntent(router, tab: HomeTabs.lyrics), LogicalKeySet( LogicalKeyboardKey.digit4, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.userPlaylists), + ): HomeTabIntent(router, tab: HomeTabs.userPlaylists), LogicalKeySet( LogicalKeyboardKey.digit5, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.userArtists), + ): HomeTabIntent(router, tab: HomeTabs.userArtists), LogicalKeySet( LogicalKeyboardKey.digit6, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.userAlbums), + ): HomeTabIntent(router, tab: HomeTabs.userAlbums), LogicalKeySet( LogicalKeyboardKey.digit7, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.userLocalLibrary), + ): HomeTabIntent(router, tab: HomeTabs.userLocalLibrary), LogicalKeySet( LogicalKeyboardKey.digit8, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.userDownloads), + ): HomeTabIntent(router, tab: HomeTabs.userDownloads), LogicalKeySet( LogicalKeyboardKey.keyW, LogicalKeyboardKey.control, diff --git a/lib/modules/album/album_card.dart b/lib/modules/album/album_card.dart index 2efacbfd..a35bd53d 100644 --- a/lib/modules/album/album_card.dart +++ b/lib/modules/album/album_card.dart @@ -1,7 +1,9 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/dialogs/select_device_dialog.dart'; import 'package:spotube/components/playbutton_view/playbutton_card.dart'; import 'package:spotube/components/playbutton_view/playbutton_tile.dart'; @@ -10,14 +12,12 @@ import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/track.dart'; import 'package:spotube/models/connect/connect.dart'; -import 'package:spotube/pages/album/album.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart'; import 'package:spotube/provider/connect/connect.dart'; import 'package:spotube/provider/history/history.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; -import 'package:spotube/utils/service_utils.dart'; extension FormattedAlbumType on AlbumType { String get formatted => name.replaceFirst(name[0], name[0].toUpperCase()); @@ -69,14 +69,7 @@ class AlbumCard extends HookConsumerWidget { "${album.albumType?.formatted} • ${album.artists?.asString() ?? ""}"; void onTap() { - ServiceUtils.pushNamed( - context, - AlbumPage.name, - pathParameters: { - "id": album.id!, - }, - extra: album, - ); + context.pushRoute(AlbumRoute(id: album.id!, album: album)); } void onPlaybuttonPressed() async { diff --git a/lib/modules/artist/artist_card.dart b/lib/modules/artist/artist_card.dart index 57c955c7..28ae6315 100644 --- a/lib/modules/artist/artist_card.dart +++ b/lib/modules/artist/artist_card.dart @@ -1,16 +1,16 @@ +import 'package:auto_route/auto_route.dart'; import 'package:auto_size_text/auto_size_text.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/artist/artist.dart'; import 'package:spotube/provider/blacklist_provider.dart'; -import 'package:spotube/utils/service_utils.dart'; class ArtistCard extends HookConsumerWidget { final Artist artist; @@ -36,13 +36,7 @@ class ArtistCard extends HookConsumerWidget { width: 180, child: Button.card( onPressed: () { - ServiceUtils.pushNamed( - context, - ArtistPage.name, - pathParameters: { - "id": artist.id!, - }, - ); + context.pushRoute(ArtistRoute(artistId: artist.id!)); }, child: Column( children: [ diff --git a/lib/modules/connect/connect_device.dart b/lib/modules/connect/connect_device.dart index a285284c..df2539a2 100644 --- a/lib/modules/connect/connect_device.dart +++ b/lib/modules/connect/connect_device.dart @@ -1,11 +1,11 @@ +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/connect/connect.dart'; import 'package:spotube/provider/connect/clients.dart'; -import 'package:spotube/utils/service_utils.dart'; class ConnectDeviceButton extends HookConsumerWidget { final bool _sidebar; @@ -26,7 +26,7 @@ class ConnectDeviceButton extends HookConsumerWidget { return IconButton.ghost( icon: const Icon(SpotubeIcons.speaker), onPressed: () { - ServiceUtils.pushNamed(context, ConnectPage.name); + context.pushRoute(const ConnectRoute()); }, ); } @@ -35,7 +35,7 @@ class ConnectDeviceButton extends HookConsumerWidget { width: double.infinity, child: Button.primary( onPressed: () { - ServiceUtils.pushNamed(context, ConnectPage.name); + context.pushRoute(const ConnectRoute()); }, trailing: const Icon(SpotubeIcons.speaker), child: Text( @@ -50,7 +50,7 @@ class ConnectDeviceButton extends HookConsumerWidget { children: [ SecondaryBadge( onPressed: () { - ServiceUtils.pushNamed(context, ConnectPage.name); + context.pushRoute(const ConnectRoute()); }, style: const ButtonStyle.secondary(size: ButtonSize(.8)), leading: connectClients.asData?.value.resolvedService != null @@ -70,7 +70,7 @@ class ConnectDeviceButton extends HookConsumerWidget { IconButton.primary( icon: const Icon(SpotubeIcons.speaker), onPressed: () { - ServiceUtils.pushNamed(context, ConnectPage.name); + context.pushRoute(const ConnectRoute()); }, ) ], diff --git a/lib/modules/home/sections/feed.dart b/lib/modules/home/sections/feed.dart index 34a9ee4b..e423b08c 100644 --- a/lib/modules/home/sections/feed.dart +++ b/lib/modules/home/sections/feed.dart @@ -1,10 +1,10 @@ +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/home/feed/feed_section.dart'; import 'package:spotube/provider/spotify/views/home.dart'; -import 'package:spotube/utils/service_utils.dart'; class HomePageFeedSection extends HookConsumerWidget { const HomePageFeedSection({super.key}); @@ -39,13 +39,9 @@ class HomePageFeedSection extends HookConsumerWidget { onFetchMore: () {}, titleTrailing: Button.text( child: Text(context.l10n.browse_all), - onPressed: () => ServiceUtils.pushNamed( - context, - HomeFeedSectionPage.name, - pathParameters: { - "feedId": section.uri, - }, - ), + onPressed: () { + context.pushRoute(HomeFeedSectionRoute(sectionUri: section.uri)); + }, ), ); }, diff --git a/lib/modules/home/sections/friends/friend_item.dart b/lib/modules/home/sections/friends/friend_item.dart index 94feb5cd..216cc607 100644 --- a/lib/modules/home/sections/friends/friend_item.dart +++ b/lib/modules/home/sections/friends/friend_item.dart @@ -1,14 +1,13 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter/gestures.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/models/spotify_friends.dart'; -import 'package:spotube/pages/album/album.dart'; -import 'package:spotube/pages/artist/artist.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/spotify_provider.dart'; class FriendItem extends HookConsumerWidget { @@ -50,9 +49,8 @@ class FriendItem extends HookConsumerWidget { text: friend.track.name, recognizer: TapGestureRecognizer() ..onTap = () { - context.pushNamed(TrackPage.name, pathParameters: { - "id": friend.track.id, - }); + context + .pushRoute(TrackRoute(trackId: friend.track.id)); }, ), const TextSpan(text: " • "), @@ -66,12 +64,8 @@ class FriendItem extends HookConsumerWidget { text: " ${friend.track.artist.name}", recognizer: TapGestureRecognizer() ..onTap = () { - context.pushNamed( - ArtistPage.name, - pathParameters: { - "id": friend.track.artist.id, - }, - extra: friend.track.artist, + context.pushRoute( + ArtistRoute(artistId: friend.track.artist.id), ); }, ), @@ -80,13 +74,13 @@ class FriendItem extends HookConsumerWidget { text: friend.track.context.name, recognizer: TapGestureRecognizer() ..onTap = () async { - context.push( + context.router.pushNamed( "/${friend.track.context.path}", - extra: - !friend.track.context.path.startsWith("album") - ? null - : await spotify.albums - .get(friend.track.context.id), + // extra: + // !friend.track.context.path.startsWith("album") + // ? null + // : await spotify.albums + // .get(friend.track.context.id), ); }, ), @@ -104,12 +98,8 @@ class FriendItem extends HookConsumerWidget { final album = await spotify.albums.get(friend.track.album.id); if (context.mounted) { - context.pushNamed( - AlbumPage.name, - pathParameters: { - "id": friend.track.album.id, - }, - extra: album, + context.pushRoute( + AlbumRoute(id: album.id!, album: album), ); } }, diff --git a/lib/modules/home/sections/genres/genre_card.dart b/lib/modules/home/sections/genres/genre_card.dart index 617d7392..8371e553 100644 --- a/lib/modules/home/sections/genres/genre_card.dart +++ b/lib/modules/home/sections/genres/genre_card.dart @@ -1,17 +1,17 @@ import 'dart:math'; import 'dart:ui'; -import 'package:go_router/go_router.dart'; +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart' hide Offset; import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/gradients.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/modules/home/sections/genres/genre_card_playlist_card.dart'; -import 'package:spotube/pages/home/genres/genre_playlists.dart'; import 'package:spotube/provider/spotify/spotify.dart'; final random = Random(); @@ -76,10 +76,11 @@ class GenreSectionCard extends HookConsumerWidget { ).h3(), Button.link( onPressed: () { - context.pushNamed( - GenrePlaylistsPage.name, - pathParameters: {'categoryId': category.id!}, - extra: category, + context.router.push( + GenrePlaylistsRoute( + id: category.id!, + category: category, + ), ); }, child: Text( diff --git a/lib/modules/home/sections/genres/genre_card_playlist_card.dart b/lib/modules/home/sections/genres/genre_card_playlist_card.dart index 0e2284b3..e5770efa 100644 --- a/lib/modules/home/sections/genres/genre_card_playlist_card.dart +++ b/lib/modules/home/sections/genres/genre_card_playlist_card.dart @@ -1,12 +1,12 @@ -import 'package:go_router/go_router.dart'; +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart' hide Image; import 'package:spotube/collections/env.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/string.dart'; -import 'package:spotube/pages/playlist/playlist.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:stroke_text/stroke_text.dart'; @@ -47,12 +47,8 @@ class GenreSectionCardPlaylistCard extends HookConsumerWidget { }, ), onPressed: () { - context.pushNamed( - PlaylistPage.name, - pathParameters: { - "id": playlist.id!, - }, - extra: playlist, + context.pushRoute( + PlaylistRoute(id: playlist.id!, playlist: playlist), ); }, child: Column( diff --git a/lib/modules/home/sections/genres/genres.dart b/lib/modules/home/sections/genres/genres.dart index 64a6be1c..507985c2 100644 --- a/lib/modules/home/sections/genres/genres.dart +++ b/lib/modules/home/sections/genres/genres.dart @@ -1,15 +1,16 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/modules/home/sections/genres/genre_card.dart'; -import 'package:spotube/pages/home/genres/genres.dart'; import 'package:spotube/provider/spotify/spotify.dart'; class HomeGenresSection extends HookConsumerWidget { @@ -47,7 +48,7 @@ class HomeGenresSection extends HookConsumerWidget { ), Button.link( onPressed: () { - context.pushNamed(GenrePage.name); + context.pushRoute(const GenreRoute()); }, child: Text( context.l10n.browse_all, diff --git a/lib/modules/library/local_folder/local_folder_item.dart b/lib/modules/library/local_folder/local_folder_item.dart index 149657cc..15355d8f 100644 --- a/lib/modules/library/local_folder/local_folder_item.dart +++ b/lib/modules/library/local_folder/local_folder_item.dart @@ -1,18 +1,18 @@ import 'dart:math'; +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:path/path.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/string.dart'; -import 'package:spotube/pages/library/user_local_tracks/local_folder.dart'; import 'package:spotube/provider/local_tracks/local_tracks_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; @@ -59,13 +59,12 @@ class LocalFolderItem extends HookConsumerWidget { return Button( onPressed: () { - context.pushNamed( - LocalLibraryPage.name, - queryParameters: { - if (isDownloadFolder) "downloads": "true", - if (isCacheFolder) "cache": "true", - }, - extra: folder, + context.pushRoute( + LocalLibraryRoute( + location: folder, + isCache: isCacheFolder, + isDownloads: isDownloadFolder, + ), ); }, style: ButtonVariance.card.copyWith( diff --git a/lib/modules/library/user_downloads/download_item.dart b/lib/modules/library/user_downloads/download_item.dart index 4b104ed1..11c86810 100644 --- a/lib/modules/library/user_downloads/download_item.dart +++ b/lib/modules/library/user_downloads/download_item.dart @@ -1,18 +1,18 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/links/artist_link.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/services/download_manager/download_status.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart'; -import 'package:spotube/utils/service_utils.dart'; class DownloadItem extends HookConsumerWidget { final Track track; @@ -66,13 +66,9 @@ class DownloadItem extends HookConsumerWidget { subtitle: ArtistLink( artists: track.artists ?? [], mainAxisAlignment: WrapAlignment.start, - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track.id!, - }, - ), + onOverflowArtistClick: () { + context.pushRoute(TrackRoute(trackId: track.id!)); + }, ), trailing: isQueryingSourceInfo ? Text(context.l10n.querying_info).small() diff --git a/lib/modules/player/player.dart b/lib/modules/player/player.dart index 16ee6c72..2f43cbee 100644 --- a/lib/modules/player/player.dart +++ b/lib/modules/player/player.dart @@ -1,13 +1,14 @@ +import 'package:auto_route/auto_route.dart'; import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart' show showModalBottomSheet; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:sliding_up_panel/sliding_up_panel.dart'; import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/framework/app_pop_scope.dart'; import 'package:spotube/modules/player/player_actions.dart'; @@ -25,13 +26,11 @@ import 'package:spotube/extensions/image.dart'; import 'package:spotube/models/local_track.dart'; import 'package:spotube/modules/root/spotube_navigation_bar.dart'; import 'package:spotube/pages/lyrics/lyrics.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/server/active_sourced_track.dart'; import 'package:spotube/provider/volume_provider.dart'; import 'package:spotube/services/sourced_track/sources/youtube.dart'; -import 'package:spotube/utils/service_utils.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -94,7 +93,7 @@ class PlayerView extends HookConsumerWidget { }, [panelController.isAttached && panelController.isPanelOpen]); return AppPopScope( - canPop: context.canPop(), + canPop: context.watchRouter.canPop(), onPopInvoked: (didPop) async { await panelController.close(); }, @@ -210,14 +209,10 @@ class PlayerView extends HookConsumerWidget { .copyWith(fontWeight: FontWeight.bold), onRouteChange: (route) { panelController.close(); - GoRouter.of(context).push(route); + context.router.pushNamed(route); }, - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": currentTrack!.id!, - }, + onOverflowArtistClick: () => context.pushRoute( + TrackRoute(trackId: currentTrack!.id!), ), ), ], diff --git a/lib/modules/player/player_track_details.dart b/lib/modules/player/player_track_details.dart index 5c13f3e8..345a19db 100644 --- a/lib/modules/player/player_track_details.dart +++ b/lib/modules/player/player_track_details.dart @@ -1,17 +1,18 @@ +import 'package:auto_route/auto_route.dart'; + import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/links/artist_link.dart'; import 'package:spotube/components/links/link_text.dart'; import 'package:spotube/extensions/artist_simple.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; -import 'package:spotube/utils/service_utils.dart'; class PlayerTrackDetails extends HookConsumerWidget { final Color? color; @@ -50,7 +51,7 @@ class PlayerTrackDetails extends HookConsumerWidget { const SizedBox(height: 4), LinkText( playback.activeTrack?.name ?? "", - "/track/${playback.activeTrack?.id}", + TrackRoute(trackId: playback.activeTrack?.id ?? ""), push: true, overflow: TextOverflow.ellipsis, style: theme.typography.normal.copyWith( @@ -72,7 +73,7 @@ class PlayerTrackDetails extends HookConsumerWidget { children: [ LinkText( playback.activeTrack?.name ?? "", - "/track/${playback.activeTrack?.id}", + TrackRoute(trackId: playback.activeTrack?.id ?? ""), push: true, overflow: TextOverflow.ellipsis, style: TextStyle(fontWeight: FontWeight.bold, color: color), @@ -80,15 +81,10 @@ class PlayerTrackDetails extends HookConsumerWidget { ArtistLink( artists: playback.activeTrack?.artists ?? [], onRouteChange: (route) { - ServiceUtils.push(context, route); + context.router.pushNamed(route); }, - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track!.id!, - }, - ), + onOverflowArtistClick: () => + context.pushRoute(TrackRoute(trackId: track!.id!)), ) ], ), diff --git a/lib/modules/playlist/playlist_card.dart b/lib/modules/playlist/playlist_card.dart index c24eb24b..1bbcf56f 100644 --- a/lib/modules/playlist/playlist_card.dart +++ b/lib/modules/playlist/playlist_card.dart @@ -1,8 +1,10 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart' hide Offset, Image; import 'package:spotube/collections/env.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/dialogs/select_device_dialog.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/playbutton_view/playbutton_card.dart'; @@ -10,14 +12,12 @@ import 'package:spotube/components/playbutton_view/playbutton_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/models/connect/connect.dart'; -import 'package:spotube/pages/playlist/playlist.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart'; import 'package:spotube/provider/connect/connect.dart'; import 'package:spotube/provider/history/history.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; -import 'package:spotube/utils/service_utils.dart'; import 'package:stroke_text/stroke_text.dart'; class PlaylistCard extends HookConsumerWidget { @@ -73,14 +73,7 @@ class PlaylistCard extends HookConsumerWidget { } void onTap() { - ServiceUtils.pushNamed( - context, - PlaylistPage.name, - pathParameters: { - "id": playlist.id!, - }, - extra: playlist, - ); + context.pushRoute(PlaylistRoute(id: playlist.id!, playlist: playlist)); } void onPlaybuttonPressed() async { diff --git a/lib/modules/playlist/playlist_create_dialog.dart b/lib/modules/playlist/playlist_create_dialog.dart index 55e7ce77..9619b2ee 100644 --- a/lib/modules/playlist/playlist_create_dialog.dart +++ b/lib/modules/playlist/playlist_create_dialog.dart @@ -1,11 +1,11 @@ import 'dart:convert'; import 'dart:io'; +import 'package:auto_route/auto_route.dart'; import 'package:collection/collection.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:image_picker/image_picker.dart'; import 'package:path/path.dart'; @@ -105,7 +105,7 @@ class PlaylistCreateDialog extends HookConsumerWidget { isSubmitting.value = false; if (context.mounted && !ref.read(playlistProvider(playlistId ?? "")).hasError) { - context.pop(); + context.router.maybePop(); } } } diff --git a/lib/modules/root/bottom_player.dart b/lib/modules/root/bottom_player.dart index fc581377..18b4c221 100644 --- a/lib/modules/root/bottom_player.dart +++ b/lib/modules/root/bottom_player.dart @@ -1,10 +1,11 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/modules/player/player_actions.dart'; @@ -96,9 +97,8 @@ class BottomPlayer extends HookConsumerWidget { const Duration(milliseconds: 100), () async { if (context.mounted) { - context.go( - '/mini-player', - extra: prevSize, + context.navigateTo( + MiniLyricsRoute(prevSize: prevSize), ); } }, diff --git a/lib/modules/root/sidebar.dart b/lib/modules/root/sidebar.dart deleted file mode 100644 index 1d5d9da0..00000000 --- a/lib/modules/root/sidebar.dart +++ /dev/null @@ -1,270 +0,0 @@ -import 'package:flutter/material.dart' show Badge; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:shadcn_flutter/shadcn_flutter.dart'; - -import 'package:spotube/collections/assets.gen.dart'; -import 'package:spotube/collections/side_bar_tiles.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/image/universal_image.dart'; -import 'package:spotube/extensions/image.dart'; -import 'package:spotube/models/database/database.dart'; -import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/extensions/context.dart'; -import 'package:spotube/modules/connect/connect_device.dart'; -import 'package:spotube/pages/library/user_downloads.dart'; -import 'package:spotube/pages/profile/profile.dart'; -import 'package:spotube/pages/settings/settings.dart'; -import 'package:spotube/provider/authentication/authentication.dart'; -import 'package:spotube/provider/download_manager_provider.dart'; -import 'package:spotube/provider/spotify/spotify.dart'; - -import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; - -import 'package:spotube/utils/service_utils.dart'; - -class Sidebar extends HookConsumerWidget { - final Widget child; - - const Sidebar({ - required this.child, - super.key, - }); - - static Widget brandLogo() { - return Container( - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(50), - ), - child: Assets.spotubeLogoPng.image(height: 50), - ); - } - - @override - Widget build(BuildContext context, WidgetRef ref) { - final routerState = GoRouterState.of(context); - final mediaQuery = MediaQuery.of(context); - - final layoutMode = - ref.watch(userPreferencesProvider.select((s) => s.layoutMode)); - - final sidebarTileList = useMemoized( - () => getSidebarTileList(context.l10n), - [context.l10n], - ); - - final sidebarLibraryTileList = useMemoized( - () => getSidebarLibraryTileList(context.l10n), - [context.l10n], - ); - - final tileList = [...sidebarTileList, ...sidebarLibraryTileList]; - - final selectedIndex = tileList.indexWhere( - (e) => routerState.namedLocation(e.name) == routerState.matchedLocation, - ); - - if (layoutMode == LayoutMode.compact || - (mediaQuery.smAndDown && layoutMode == LayoutMode.adaptive)) { - return Scaffold(child: child); - } - - final navigationButtons = [ - NavigationLabel( - child: mediaQuery.lgAndUp ? const Text("Spotube") : const Text(""), - ), - for (final tile in sidebarTileList) - NavigationButton( - label: mediaQuery.lgAndUp ? Text(tile.title) : null, - child: Tooltip( - tooltip: TooltipContainer(child: Text(tile.title)), - child: Icon(tile.icon), - ), - onChanged: (value) { - if (value) { - context.goNamed(tile.name); - } - }, - ), - const NavigationDivider(), - if (mediaQuery.lgAndUp) - NavigationLabel(child: Text(context.l10n.library)), - for (final tile in sidebarLibraryTileList) - NavigationButton( - label: mediaQuery.lgAndUp ? Text(tile.title) : null, - onChanged: (value) { - if (value) { - context.goNamed(tile.name); - } - }, - child: Tooltip( - tooltip: TooltipContainer(child: Text(tile.title)), - child: Icon(tile.icon), - ), - ), - ]; - - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - children: [ - Expanded( - child: mediaQuery.lgAndUp - ? NavigationSidebar( - index: selectedIndex, - onSelected: (index) { - final tile = tileList[index]; - context.goNamed(tile.name); - }, - children: navigationButtons, - ) - : NavigationRail( - alignment: NavigationRailAlignment.start, - index: selectedIndex, - onSelected: (index) { - final tile = tileList[index]; - context.goNamed(tile.name); - }, - children: navigationButtons, - ), - ), - const SidebarFooter(), - if (mediaQuery.lgAndUp) const Gap(130) else const Gap(65), - ], - ), - const VerticalDivider(), - Expanded(child: child), - ], - ); - } -} - -class SidebarFooter extends HookConsumerWidget implements NavigationBarItem { - const SidebarFooter({ - super.key, - }); - - @override - Widget build(BuildContext context, ref) { - final theme = Theme.of(context); - final mediaQuery = MediaQuery.of(context); - final routerState = GoRouterState.of(context); - final downloadCount = ref.watch(downloadManagerProvider).$downloadCount; - final userSnapshot = ref.watch(meProvider); - final data = userSnapshot.asData?.value; - - final avatarImg = (data?.images).asUrlString( - index: (data?.images?.length ?? 1) - 1, - placeholder: ImagePlaceholder.artist, - ); - - final auth = ref.watch(authenticationProvider); - - if (mediaQuery.mdAndDown) { - return Column( - mainAxisSize: MainAxisSize.min, - spacing: 10, - children: [ - Badge( - isLabelVisible: downloadCount > 0, - label: Text(downloadCount.toString()), - child: IconButton( - variance: routerState.topRoute?.name == UserDownloadsPage.name - ? ButtonVariance.secondary - : ButtonVariance.ghost, - icon: const Icon(SpotubeIcons.download), - onPressed: () => - ServiceUtils.navigateNamed(context, UserDownloadsPage.name), - ), - ), - const ConnectDeviceButton.sidebar(), - IconButton( - variance: ButtonVariance.ghost, - icon: const Icon(SpotubeIcons.settings), - onPressed: () => - ServiceUtils.navigateNamed(context, SettingsPage.name), - ), - ], - ); - } - - return Container( - padding: const EdgeInsets.only(left: 12), - width: 180, - child: Column( - mainAxisSize: MainAxisSize.min, - spacing: 10, - children: [ - SizedBox( - width: double.infinity, - child: Button( - style: routerState.topRoute?.name == UserDownloadsPage.name - ? ButtonVariance.secondary - : ButtonVariance.outline, - onPressed: () { - ServiceUtils.navigateNamed(context, UserDownloadsPage.name); - }, - leading: const Icon(SpotubeIcons.download), - trailing: downloadCount > 0 - ? PrimaryBadge( - child: Text(downloadCount.toString()), - ) - : null, - child: Text(context.l10n.downloads), - ), - ), - const ConnectDeviceButton.sidebar(), - Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (auth.asData?.value != null && data == null) - const CircularProgressIndicator() - else if (data != null) - Flexible( - child: GestureDetector( - onTap: () { - ServiceUtils.pushNamed(context, ProfilePage.name); - }, - child: Row( - children: [ - Avatar( - initials: - Avatar.getInitials(data.displayName ?? "User"), - provider: UniversalImage.imageProvider(avatarImg), - ), - const SizedBox(width: 10), - Flexible( - child: Text( - data.displayName ?? context.l10n.guest, - maxLines: 1, - softWrap: false, - overflow: TextOverflow.fade, - style: theme.typography.normal - .copyWith(fontWeight: FontWeight.bold), - ), - ), - ], - ), - ), - ), - IconButton( - variance: ButtonVariance.ghost, - icon: const Icon(SpotubeIcons.settings), - onPressed: () { - ServiceUtils.pushNamed(context, SettingsPage.name); - }, - ), - ], - ), - ], - ), - ); - } - - @override - bool get selectable => false; -} diff --git a/lib/modules/root/sidebar/sidebar.dart b/lib/modules/root/sidebar/sidebar.dart new file mode 100644 index 00000000..2bfb8687 --- /dev/null +++ b/lib/modules/root/sidebar/sidebar.dart @@ -0,0 +1,132 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; + +import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/side_bar_tiles.dart'; +import 'package:spotube/models/database/database.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/modules/root/sidebar/sidebar_footer.dart'; + +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; + +class Sidebar extends HookConsumerWidget { + final Widget child; + + const Sidebar({ + required this.child, + super.key, + }); + + static Widget brandLogo() { + return Container( + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(50), + ), + child: Assets.spotubeLogoPng.image(height: 50), + ); + } + + @override + Widget build(BuildContext context, WidgetRef ref) { + final mediaQuery = MediaQuery.of(context); + + final layoutMode = + ref.watch(userPreferencesProvider.select((s) => s.layoutMode)); + + final sidebarTileList = useMemoized( + () => getSidebarTileList(context.l10n), + [context.l10n], + ); + + final sidebarLibraryTileList = useMemoized( + () => getSidebarLibraryTileList(context.l10n), + [context.l10n], + ); + + final tileList = [...sidebarTileList, ...sidebarLibraryTileList]; + + final router = context.watchRouter; + + final selectedIndex = tileList.indexWhere( + (e) => router.topRoute.name == e.route.routeName, + ); + + if (layoutMode == LayoutMode.compact || + (mediaQuery.smAndDown && layoutMode == LayoutMode.adaptive)) { + return Scaffold(child: child); + } + + final navigationButtons = [ + NavigationLabel( + child: mediaQuery.lgAndUp ? const Text("Spotube") : const Text(""), + ), + for (final tile in sidebarTileList) + NavigationButton( + label: mediaQuery.lgAndUp ? Text(tile.title) : null, + child: Tooltip( + tooltip: TooltipContainer(child: Text(tile.title)), + child: Icon(tile.icon), + ), + onChanged: (value) { + if (value) { + context.navigateTo(tile.route); + } + }, + ), + const NavigationDivider(), + if (mediaQuery.lgAndUp) + NavigationLabel(child: Text(context.l10n.library)), + for (final tile in sidebarLibraryTileList) + NavigationButton( + label: mediaQuery.lgAndUp ? Text(tile.title) : null, + onChanged: (value) { + if (value) { + context.navigateTo(tile.route); + } + }, + child: Tooltip( + tooltip: TooltipContainer(child: Text(tile.title)), + child: Icon(tile.icon), + ), + ), + ]; + + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + children: [ + Expanded( + child: mediaQuery.lgAndUp + ? NavigationSidebar( + index: selectedIndex, + onSelected: (index) { + final tile = tileList[index]; + context.navigateTo(tile.route); + }, + children: navigationButtons, + ) + : NavigationRail( + alignment: NavigationRailAlignment.start, + index: selectedIndex, + onSelected: (index) { + final tile = tileList[index]; + context.navigateTo(tile.route); + }, + children: navigationButtons, + ), + ), + const SidebarFooter(), + if (mediaQuery.lgAndUp) const Gap(130) else const Gap(65), + ], + ), + const VerticalDivider(), + Expanded(child: child), + ], + ); + } +} diff --git a/lib/modules/root/sidebar/sidebar_footer.dart b/lib/modules/root/sidebar/sidebar_footer.dart new file mode 100644 index 00000000..73916f50 --- /dev/null +++ b/lib/modules/root/sidebar/sidebar_footer.dart @@ -0,0 +1,140 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart' show Badge; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; + +import 'package:spotube/collections/routes.gr.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/image/universal_image.dart'; +import 'package:spotube/extensions/image.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/modules/connect/connect_device.dart'; +import 'package:spotube/provider/authentication/authentication.dart'; +import 'package:spotube/provider/download_manager_provider.dart'; +import 'package:spotube/provider/spotify/spotify.dart'; + +class SidebarFooter extends HookConsumerWidget implements NavigationBarItem { + const SidebarFooter({ + super.key, + }); + + @override + Widget build(BuildContext context, ref) { + final theme = Theme.of(context); + final router = AutoRouter.of(context, watch: true); + final mediaQuery = MediaQuery.of(context); + final downloadCount = ref.watch(downloadManagerProvider).$downloadCount; + final userSnapshot = ref.watch(meProvider); + final data = userSnapshot.asData?.value; + + final avatarImg = (data?.images).asUrlString( + index: (data?.images?.length ?? 1) - 1, + placeholder: ImagePlaceholder.artist, + ); + + final auth = ref.watch(authenticationProvider); + + if (mediaQuery.mdAndDown) { + return Column( + mainAxisSize: MainAxisSize.min, + spacing: 10, + children: [ + Badge( + isLabelVisible: downloadCount > 0, + label: Text(downloadCount.toString()), + child: IconButton( + variance: router.topRoute.name == UserDownloadsRoute.name + ? ButtonVariance.secondary + : ButtonVariance.ghost, + icon: const Icon(SpotubeIcons.download), + onPressed: () => context.navigateTo(const UserDownloadsRoute()), + ), + ), + const ConnectDeviceButton.sidebar(), + IconButton( + variance: ButtonVariance.ghost, + icon: const Icon(SpotubeIcons.settings), + onPressed: () => context.navigateTo(const SettingsRoute()), + ), + ], + ); + } + + return Container( + padding: const EdgeInsets.only(left: 12), + width: 180, + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: 10, + children: [ + SizedBox( + width: double.infinity, + child: Button( + style: router.topRoute.name == UserDownloadsRoute.name + ? ButtonVariance.secondary + : ButtonVariance.outline, + onPressed: () { + context.navigateTo(const UserDownloadsRoute()); + }, + leading: const Icon(SpotubeIcons.download), + trailing: downloadCount > 0 + ? PrimaryBadge( + child: Text(downloadCount.toString()), + ) + : null, + child: Text(context.l10n.downloads), + ), + ), + const ConnectDeviceButton.sidebar(), + Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (auth.asData?.value != null && data == null) + const CircularProgressIndicator() + else if (data != null) + Flexible( + child: GestureDetector( + onTap: () { + context.pushRoute(const ProfileRoute()); + }, + child: Row( + children: [ + Avatar( + initials: + Avatar.getInitials(data.displayName ?? "User"), + provider: UniversalImage.imageProvider(avatarImg), + ), + const SizedBox(width: 10), + Flexible( + child: Text( + data.displayName ?? context.l10n.guest, + maxLines: 1, + softWrap: false, + overflow: TextOverflow.fade, + style: theme.typography.normal + .copyWith(fontWeight: FontWeight.bold), + ), + ), + ], + ), + ), + ), + IconButton( + variance: ButtonVariance.ghost, + icon: const Icon(SpotubeIcons.settings), + onPressed: () { + context.pushRoute(const SettingsRoute()); + }, + ), + ], + ), + ], + ), + ); + } + + @override + bool get selectable => false; +} diff --git a/lib/modules/root/spotube_navigation_bar.dart b/lib/modules/root/spotube_navigation_bar.dart index c19b3a40..cd717833 100644 --- a/lib/modules/root/spotube_navigation_bar.dart +++ b/lib/modules/root/spotube_navigation_bar.dart @@ -1,9 +1,12 @@ +import 'dart:math'; + +import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart' show Badge; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/extensions/constrains.dart'; @@ -12,8 +15,6 @@ import 'package:spotube/models/database/database.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -import 'package:spotube/utils/service_utils.dart'; - final navigationPanelHeight = StateProvider((ref) => 50); class SpotubeNavigationBar extends HookConsumerWidget { @@ -23,10 +24,9 @@ class SpotubeNavigationBar extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final routerState = GoRouterState.of(context); + final mediaQuery = MediaQuery.of(context); final downloadCount = ref.watch(downloadManagerProvider).$downloadCount; - final mediaQuery = MediaQuery.of(context); final layoutMode = ref.watch(userPreferencesProvider.select((s) => s.layoutMode)); @@ -35,15 +35,25 @@ class SpotubeNavigationBar extends HookConsumerWidget { [context.l10n], ); + final libraryTiles = useMemoized( + () => getSidebarLibraryTileList(context.l10n) + .map((e) => e.route.routeName) + .toList(), + [context.l10n], + ); + final panelHeight = ref.watch(navigationPanelHeight); - final selectedIndex = useMemoized(() { - final index = navbarTileList.indexWhere( - (e) => routerState.namedLocation(e.name) == routerState.matchedLocation, - ); - - return index == -1 ? 0 : index; - }, [navbarTileList, routerState.matchedLocation]); + final router = context.watchRouter; + final selectedIndex = max( + 0, + navbarTileList.indexWhere( + (e) => + router.topRoute.name == e.route.routeName || + (libraryTiles.contains(router.topRoute.name) && + e.route.routeName == LibraryRoute.name), + ), + ); if (layoutMode == LayoutMode.extended || (mediaQuery.mdAndUp && layoutMode == LayoutMode.adaptive) || @@ -63,7 +73,7 @@ class SpotubeNavigationBar extends HookConsumerWidget { surfaceBlur: context.theme.surfaceBlur, surfaceOpacity: context.theme.surfaceOpacity, onSelected: (i) { - ServiceUtils.navigateNamed(context, navbarTileList[i].name); + context.navigateTo(navbarTileList[i].route); }, children: [ for (final tile in navbarTileList) diff --git a/lib/modules/stats/common/album_item.dart b/lib/modules/stats/common/album_item.dart index 0920baae..3105eb17 100644 --- a/lib/modules/stats/common/album_item.dart +++ b/lib/modules/stats/common/album_item.dart @@ -1,12 +1,12 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/modules/album/album_card.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/links/artist_link.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/album/album.dart'; -import 'package:spotube/utils/service_utils.dart'; class StatsAlbumItem extends StatelessWidget { final AlbumSimple album; @@ -36,25 +36,15 @@ class StatsAlbumItem extends StatelessWidget { child: ArtistLink( artists: album.artists ?? [], mainAxisAlignment: WrapAlignment.start, - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - AlbumPage.name, - pathParameters: { - "id": album.id!, - }, - ), + onOverflowArtistClick: () => + context.pushRoute(AlbumRoute(id: album.id!, album: album)), ), ), ], ), trailing: info, onPressed: () { - ServiceUtils.pushNamed( - context, - AlbumPage.name, - pathParameters: {"id": album.id!}, - extra: album, - ); + context.pushRoute(AlbumRoute(id: album.id!, album: album)); }, ); } diff --git a/lib/modules/stats/common/artist_item.dart b/lib/modules/stats/common/artist_item.dart index 26691ba4..13e19777 100644 --- a/lib/modules/stats/common/artist_item.dart +++ b/lib/modules/stats/common/artist_item.dart @@ -1,10 +1,10 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/artist/artist.dart'; -import 'package:spotube/utils/service_utils.dart'; class StatsArtistItem extends StatelessWidget { final Artist artist; @@ -30,11 +30,7 @@ class StatsArtistItem extends StatelessWidget { ), trailing: info, onPressed: () { - ServiceUtils.pushNamed( - context, - ArtistPage.name, - pathParameters: {"id": artist.id!}, - ); + context.pushRoute(ArtistRoute(artistId: artist.id!)); }, ); } diff --git a/lib/modules/stats/common/playlist_item.dart b/lib/modules/stats/common/playlist_item.dart index 3859db6b..744fef04 100644 --- a/lib/modules/stats/common/playlist_item.dart +++ b/lib/modules/stats/common/playlist_item.dart @@ -1,11 +1,11 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/string.dart'; -import 'package:spotube/pages/playlist/playlist.dart'; -import 'package:spotube/utils/service_utils.dart'; class StatsPlaylistItem extends StatelessWidget { final PlaylistSimple playlist; @@ -35,12 +35,7 @@ class StatsPlaylistItem extends StatelessWidget { ), trailing: info, onPressed: () { - ServiceUtils.pushNamed( - context, - PlaylistPage.name, - pathParameters: {"id": playlist.id!}, - extra: playlist, - ); + context.pushRoute(PlaylistRoute(id: playlist.id!, playlist: playlist)); }, ); } diff --git a/lib/modules/stats/common/track_item.dart b/lib/modules/stats/common/track_item.dart index 8f0f5b8d..640c2b0b 100644 --- a/lib/modules/stats/common/track_item.dart +++ b/lib/modules/stats/common/track_item.dart @@ -1,11 +1,11 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/links/artist_link.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/track/track.dart'; -import 'package:spotube/utils/service_utils.dart'; class StatsTrackItem extends StatelessWidget { final Track track; @@ -34,23 +34,13 @@ class StatsTrackItem extends StatelessWidget { subtitle: ArtistLink( artists: track.artists!, mainAxisAlignment: WrapAlignment.start, - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track.id!, - }, - ), + onOverflowArtistClick: () { + context.pushRoute(TrackRoute(trackId: track.id!)); + }, ), trailing: info, onPressed: () { - ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track.id!, - }, - ); + context.pushRoute(TrackRoute(trackId: track.id!)); }, ); } diff --git a/lib/modules/stats/summary/summary.dart b/lib/modules/stats/summary/summary.dart index 351b0264..6966da97 100644 --- a/lib/modules/stats/summary/summary.dart +++ b/lib/modules/stats/summary/summary.dart @@ -1,19 +1,14 @@ +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/formatters.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/modules/stats/summary/summary_card.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/stats/albums/albums.dart'; -import 'package:spotube/pages/stats/artists/artists.dart'; -import 'package:spotube/pages/stats/fees/fees.dart'; -import 'package:spotube/pages/stats/minutes/minutes.dart'; -import 'package:spotube/pages/stats/playlists/playlists.dart'; -import 'package:spotube/pages/stats/streams/streams.dart'; import 'package:spotube/provider/history/summary.dart'; -import 'package:spotube/utils/service_utils.dart'; class StatsPageSummarySection extends HookConsumerWidget { const StatsPageSummarySection({super.key}); @@ -50,7 +45,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_listened_to_music, color: Colors.indigo, onTap: () { - ServiceUtils.pushNamed(context, StatsMinutesPage.name); + context.pushRoute(const StatsMinutesRoute()); }, ), SummaryCard( @@ -59,7 +54,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_streamed_overall, color: Colors.blue, onTap: () { - ServiceUtils.pushNamed(context, StatsStreamsPage.name); + context.pushRoute(const StatsStreamsRoute()); }, ), SummaryCard.unformatted( @@ -68,7 +63,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_owed_to_artists, color: Colors.green, onTap: () { - ServiceUtils.pushNamed(context, StatsStreamFeesPage.name); + context.pushRoute(const StatsStreamsRoute()); }, ), SummaryCard( @@ -77,7 +72,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_music_reached_you, color: Colors.yellow, onTap: () { - ServiceUtils.pushNamed(context, StatsArtistsPage.name); + context.pushRoute(const StatsArtistsRoute()); }, ), SummaryCard( @@ -86,7 +81,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_got_your_love, color: Colors.pink, onTap: () { - ServiceUtils.pushNamed(context, StatsAlbumsPage.name); + context.pushRoute(const StatsAlbumsRoute()); }, ), SummaryCard( @@ -95,7 +90,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_were_on_repeat, color: Colors.teal, onTap: () { - ServiceUtils.pushNamed(context, StatsPlaylistsPage.name); + context.pushRoute(const StatsPlaylistsRoute()); }, ), ]), diff --git a/lib/modules/stats/top/top.dart b/lib/modules/stats/top/top.dart index 8e9134c7..1df2b7e9 100644 --- a/lib/modules/stats/top/top.dart +++ b/lib/modules/stats/top/top.dart @@ -56,6 +56,7 @@ class StatsPageTopSection extends HookConsumerWidget { floating: true, elevation: 0, backgroundColor: context.theme.colorScheme.background, + automaticallyImplyLeading: false, flexibleSpace: Padding( padding: const EdgeInsets.all(8.0), child: Row( diff --git a/lib/pages/album/album.dart b/lib/pages/album/album.dart index bc013574..5d19f5ed 100644 --- a/lib/pages/album/album.dart +++ b/lib/pages/album/album.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; @@ -7,12 +8,15 @@ import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +@RoutePage() class AlbumPage extends HookConsumerWidget { static const name = "album"; final AlbumSimple album; + final String id; const AlbumPage({ super.key, + @PathParam("id") required this.id, required this.album, }); diff --git a/lib/pages/artist/artist.dart b/lib/pages/artist/artist.dart index 5565d897..67db398d 100644 --- a/lib/pages/artist/artist.dart +++ b/lib/pages/artist/artist.dart @@ -13,12 +13,17 @@ import 'package:spotube/pages/artist/section/header.dart'; import 'package:spotube/pages/artist/section/related_artists.dart'; import 'package:spotube/pages/artist/section/top_tracks.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class ArtistPage extends HookConsumerWidget { static const name = "artist"; final String artistId; - const ArtistPage(this.artistId, {super.key}); + const ArtistPage( + @PathParam("id") this.artistId, { + super.key, + }); @override Widget build(BuildContext context, ref) { diff --git a/lib/pages/connect/connect.dart b/lib/pages/connect/connect.dart index 55c72026..20b6d0da 100644 --- a/lib/pages/connect/connect.dart +++ b/lib/pages/connect/connect.dart @@ -1,14 +1,15 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/modules/connect/local_devices.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/connect/control/control.dart'; import 'package:spotube/provider/connect/clients.dart'; -import 'package:spotube/utils/service_utils.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class ConnectPage extends HookConsumerWidget { static const name = "connect"; @@ -71,10 +72,7 @@ class ConnectPage extends HookConsumerWidget { : null, onPressed: () { if (selected) { - ServiceUtils.pushNamed( - context, - ConnectControlPage.name, - ); + context.pushRoute(const ConnectControlRoute()); } else { connectClientsNotifier.resolveService(device); } diff --git a/lib/pages/connect/control/control.dart b/lib/pages/connect/control/control.dart index afe68b16..504d670c 100644 --- a/lib/pages/connect/control/control.dart +++ b/lib/pages/connect/control/control.dart @@ -1,7 +1,8 @@ -import 'package:go_router/go_router.dart'; +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/player/player_queue.dart'; import 'package:spotube/modules/player/volume_slider.dart'; @@ -13,11 +14,9 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/duration.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/connect/clients.dart'; import 'package:spotube/provider/connect/connect.dart'; import 'package:media_kit/media_kit.dart' hide Track; -import 'package:spotube/utils/service_utils.dart'; class RemotePlayerQueue extends ConsumerWidget { const RemotePlayerQueue({super.key}); @@ -46,6 +45,7 @@ class RemotePlayerQueue extends ConsumerWidget { } } +@RoutePage() class ConnectControlPage extends HookConsumerWidget { static const name = "connect_control"; @@ -65,7 +65,7 @@ class ConnectControlPage extends HookConsumerWidget { ref.listen(connectClientsProvider, (prev, next) { if (next.asData?.value.resolvedService == null) { - context.pop(); + context.back(); } }); @@ -115,12 +115,9 @@ class ConnectControlPage extends HookConsumerWidget { style: typography.h4, onTap: () { if (playlist.activeTrack == null) return; - ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": playlist.activeTrack!.id!, - }, + context.pushRoute( + TrackRoute( + trackId: playlist.activeTrack!.id!), ); }, ), @@ -130,13 +127,8 @@ class ConnectControlPage extends HookConsumerWidget { artists: playlist.activeTrack?.artists ?? [], textStyle: typography.normal, mainAxisAlignment: WrapAlignment.start, - onOverflowArtistClick: () => - ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": playlist.activeTrack!.id!, - }, + onOverflowArtistClick: () => context.pushRoute( + TrackRoute(trackId: playlist.activeTrack!.id!), ), ), ), diff --git a/lib/pages/getting_started/getting_started.dart b/lib/pages/getting_started/getting_started.dart index f710bd8f..a576ed09 100644 --- a/lib/pages/getting_started/getting_started.dart +++ b/lib/pages/getting_started/getting_started.dart @@ -8,11 +8,13 @@ import 'package:spotube/pages/getting_started/sections/greeting.dart'; import 'package:spotube/pages/getting_started/sections/playback.dart'; import 'package:spotube/pages/getting_started/sections/region.dart'; import 'package:spotube/pages/getting_started/sections/support.dart'; +import 'package:auto_route/auto_route.dart'; -class GettingStarting extends HookConsumerWidget { +@RoutePage() +class GettingStartedPage extends HookConsumerWidget { static const name = "getting_started"; - const GettingStarting({super.key}); + const GettingStartedPage({super.key}); @override Widget build(BuildContext context, ref) { diff --git a/lib/pages/getting_started/sections/support.dart b/lib/pages/getting_started/sections/support.dart index 640b0b38..9559d28d 100644 --- a/lib/pages/getting_started/sections/support.dart +++ b/lib/pages/getting_started/sections/support.dart @@ -1,11 +1,11 @@ -import 'package:go_router/go_router.dart'; +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/env.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/getting_started/blur_card.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/home/home.dart'; import 'package:spotube/pages/mobile_login/hooks/login_callback.dart'; import 'package:spotube/services/kv_store/kv_store.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -112,7 +112,7 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget { onPressed: () async { await KVStoreService.setDoneGettingStarted(true); if (context.mounted) { - context.goNamed(HomePage.name); + context.navigateTo(const HomeRoute()); } }, child: Text(context.l10n.browse_anonymously), diff --git a/lib/pages/home/feed/feed_section.dart b/lib/pages/home/feed/feed_section.dart index 38d0887c..eff70808 100644 --- a/lib/pages/home/feed/feed_section.dart +++ b/lib/pages/home/feed/feed_section.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; @@ -10,11 +11,15 @@ import 'package:spotube/modules/playlist/playlist_card.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/provider/spotify/views/home_section.dart'; +@RoutePage() class HomeFeedSectionPage extends HookConsumerWidget { static const name = "home_feed_section"; final String sectionUri; - const HomeFeedSectionPage({super.key, required this.sectionUri}); + const HomeFeedSectionPage({ + super.key, + @PathParam("feedId") required this.sectionUri, + }); @override Widget build(BuildContext context, ref) { diff --git a/lib/pages/home/genres/genre_playlists.dart b/lib/pages/home/genres/genre_playlists.dart index ebfc4450..a3e38309 100644 --- a/lib/pages/home/genres/genre_playlists.dart +++ b/lib/pages/home/genres/genre_playlists.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart' show CollapseMode, FlexibleSpaceBar; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotify/spotify.dart' hide Offset; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/components/playbutton_view/playbutton_view.dart'; import 'package:spotube/hooks/utils/use_custom_status_bar_color.dart'; @@ -16,12 +16,19 @@ import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/utils/platform.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class GenrePlaylistsPage extends HookConsumerWidget { static const name = "genre_playlists"; final Category category; - const GenrePlaylistsPage({super.key, required this.category}); + final String id; + const GenrePlaylistsPage({ + super.key, + @PathParam("categoryId") required this.id, + required this.category, + }); @override Widget build(BuildContext context, ref) { @@ -30,11 +37,10 @@ class GenrePlaylistsPage extends HookConsumerWidget { final playlistsNotifier = ref.read(categoryPlaylistsProvider(category.id!).notifier); final scrollController = useScrollController(); - final routeName = GoRouterState.of(context).name; useCustomStatusBarColor( Colors.black, - routeName == GenrePlaylistsPage.name, + context.watchRouter.topRoute.name == GenrePlaylistsRoute.name, noSetBGColor: true, automaticSystemUiAdjustment: false, ); diff --git a/lib/pages/home/genres/genres.dart b/lib/pages/home/genres/genres.dart index 062852e8..1bdb3782 100644 --- a/lib/pages/home/genres/genres.dart +++ b/lib/pages/home/genres/genres.dart @@ -3,17 +3,19 @@ import 'dart:math'; import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/gradients.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/home/genres/genre_playlists.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class GenrePage extends HookConsumerWidget { static const name = "genre"; const GenrePage({super.key}); @@ -49,12 +51,11 @@ class GenrePage extends HookConsumerWidget { final gradient = gradients[Random().nextInt(gradients.length)]; return CardImage( onPressed: () { - context.pushNamed( - GenrePlaylistsPage.name, - pathParameters: { - "categoryId": category.id!, - }, - extra: category, + context.pushRoute( + GenrePlaylistsRoute( + id: category.id!, + category: category, + ), ); }, image: Stack( diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index 1638393b..9bcba29e 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -1,9 +1,11 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/modules/connect/connect_device.dart'; @@ -16,11 +18,10 @@ import 'package:spotube/modules/home/sections/new_releases.dart'; import 'package:spotube/modules/home/sections/recent.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/pages/settings/settings.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/utils/platform.dart'; -import 'package:spotube/utils/service_utils.dart'; +@RoutePage() class HomePage extends HookConsumerWidget { static const name = "home"; const HomePage({super.key}); @@ -53,7 +54,7 @@ class HomePage extends HookConsumerWidget { IconButton.ghost( icon: const Icon(SpotubeIcons.settings, size: 20), onPressed: () { - ServiceUtils.pushNamed(context, SettingsPage.name); + context.pushRoute(const SettingsRoute()); }, ), const Gap(10), diff --git a/lib/pages/lastfm_login/lastfm_login.dart b/lib/pages/lastfm_login/lastfm_login.dart index 89b8270a..6b741f4d 100644 --- a/lib/pages/lastfm_login/lastfm_login.dart +++ b/lib/pages/lastfm_login/lastfm_login.dart @@ -1,6 +1,5 @@ import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -9,14 +8,15 @@ import 'package:spotube/components/dialogs/prompt_dialog.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/scrobbler/scrobbler.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class LastFMLoginPage extends HookConsumerWidget { static const name = "lastfm_login"; const LastFMLoginPage({super.key}); @override Widget build(BuildContext context, ref) { - final router = GoRouter.of(context); final scrobblerNotifier = ref.read(scrobblerProvider.notifier); final usernameKey = @@ -53,7 +53,9 @@ class LastFMLoginPage extends HookConsumerWidget { values[usernameKey].trim(), values[passwordKey], ); - router.pop(); + if (context.mounted) { + context.back(); + } } catch (e) { if (context.mounted) { showPromptDialog( diff --git a/lib/pages/library/library.dart b/lib/pages/library/library.dart index 6677a3b6..91353aed 100644 --- a/lib/pages/library/library.dart +++ b/lib/pages/library/library.dart @@ -1,38 +1,38 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart' show Badge; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/library/user_downloads.dart'; import 'package:spotube/provider/download_manager_provider.dart'; +@RoutePage() class LibraryPage extends HookConsumerWidget { - final Widget child; - const LibraryPage({super.key, required this.child}); + const LibraryPage({super.key}); @override Widget build(BuildContext context, ref) { final downloadingCount = ref.watch(downloadManagerProvider).$downloadCount; - final routerState = GoRouterState.of(context); + final router = context.watchRouter; final sidebarLibraryTileList = useMemoized( () => [ ...getSidebarLibraryTileList(context.l10n), SideBarTiles( id: "downloads", title: context.l10n.downloads, - name: UserDownloadsPage.name, + route: const UserDownloadsRoute(), icon: SpotubeIcons.download, ), ], [context.l10n], ); final index = sidebarLibraryTileList.indexWhere( - (e) => routerState.namedLocation(e.name) == routerState.matchedLocation, + (e) => router.topRoute.name == e.route.routeName, ); return SafeArea( @@ -56,7 +56,7 @@ class LibraryPage extends HookConsumerWidget { child: Text(tile.title), ), onPressed: () { - context.goNamed(tile.name); + context.navigateTo(tile.route); }, ), ], @@ -65,7 +65,7 @@ class LibraryPage extends HookConsumerWidget { ), const Gap(10), ], - child: child, + child: const AutoRouter(), ); }), ); diff --git a/lib/pages/library/playlist_generate/playlist_generate.dart b/lib/pages/library/playlist_generate/playlist_generate.dart index 2b1e7512..29bfb360 100644 --- a/lib/pages/library/playlist_generate/playlist_generate.dart +++ b/lib/pages/library/playlist_generate/playlist_generate.dart @@ -1,10 +1,11 @@ import 'package:collection/collection.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotify_markets.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/button/back_button.dart'; @@ -23,9 +24,11 @@ import 'package:spotube/models/spotify/recommendation_seeds.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/provider/spotify_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:auto_route/auto_route.dart'; const RecommendationAttribute zeroValues = (min: 0, target: 0, max: 0); +@RoutePage() class PlaylistGeneratorPage extends HookConsumerWidget { static const name = "playlist_generator"; @@ -660,9 +663,10 @@ class PlaylistGeneratorPage extends HookConsumerWidget { min: min.value, target: target.value, ); - GoRouter.of(context).push( - "/library/generate/result", - extra: routeState, + context.pushRoute( + PlaylistGenerateResultRoute( + state: routeState, + ), ); }, child: Text(context.l10n.generate), diff --git a/lib/pages/library/playlist_generate/playlist_generate_result.dart b/lib/pages/library/playlist_generate/playlist_generate_result.dart index 87d6fdc9..4c350366 100644 --- a/lib/pages/library/playlist_generate/playlist_generate_result.dart +++ b/lib/pages/library/playlist_generate/playlist_generate_result.dart @@ -1,8 +1,10 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/modules/library/playlist_generate/simple_track_tile.dart'; @@ -11,10 +13,10 @@ import 'package:spotube/components/dialogs/playlist_add_track_dialog.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/models/spotify/recommendation_seeds.dart'; -import 'package:spotube/pages/playlist/playlist.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +@RoutePage() class PlaylistGenerateResultPage extends HookConsumerWidget { static const name = "playlist_generate_result"; @@ -27,8 +29,6 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final router = GoRouter.of(context); - final playlistNotifier = ref.watch(audioPlayerProvider.notifier); final generatedPlaylist = ref.watch(generatePlaylistProvider(state)); @@ -134,13 +134,12 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { ), ); - if (playlist != null) { - router.goNamed( - PlaylistPage.name, - pathParameters: { - "id": playlist.id!, - }, - extra: playlist, + if (playlist != null && context.mounted) { + context.navigateTo( + PlaylistRoute( + id: playlist.id!, + playlist: playlist, + ), ); } }, diff --git a/lib/pages/library/user_albums.dart b/lib/pages/library/user_albums.dart index 861d1705..e11c6c8b 100644 --- a/lib/pages/library/user_albums.dart +++ b/lib/pages/library/user_albums.dart @@ -15,7 +15,9 @@ import 'package:spotube/components/fallbacks/anonymous_fallback.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class UserAlbumsPage extends HookConsumerWidget { static const name = 'user_albums'; const UserAlbumsPage({super.key}); diff --git a/lib/pages/library/user_artists.dart b/lib/pages/library/user_artists.dart index 6ce715ad..f55f4587 100644 --- a/lib/pages/library/user_artists.dart +++ b/lib/pages/library/user_artists.dart @@ -18,7 +18,9 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class UserArtistsPage extends HookConsumerWidget { static const name = 'user_artists'; const UserArtistsPage({super.key}); diff --git a/lib/pages/library/user_downloads.dart b/lib/pages/library/user_downloads.dart index 871e21ab..1d8f560a 100644 --- a/lib/pages/library/user_downloads.dart +++ b/lib/pages/library/user_downloads.dart @@ -5,7 +5,9 @@ import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/modules/library/user_downloads/download_item.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/download_manager_provider.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class UserDownloadsPage extends HookConsumerWidget { static const name = 'user_downloads'; const UserDownloadsPage({super.key}); diff --git a/lib/pages/library/user_local_tracks/local_folder.dart b/lib/pages/library/user_local_tracks/local_folder.dart index 5282894a..028d4e69 100644 --- a/lib/pages/library/user_local_tracks/local_folder.dart +++ b/lib/pages/library/user_local_tracks/local_folder.dart @@ -29,7 +29,9 @@ import 'package:spotube/provider/local_tracks/local_tracks_provider.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/utils/service_utils.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class LocalLibraryPage extends HookConsumerWidget { static const name = "local_library_page"; diff --git a/lib/pages/library/user_local_tracks/user_local_tracks.dart b/lib/pages/library/user_local_tracks/user_local_tracks.dart index 66c011e5..67e02b0b 100644 --- a/lib/pages/library/user_local_tracks/user_local_tracks.dart +++ b/lib/pages/library/user_local_tracks/user_local_tracks.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:file_picker/file_picker.dart'; import 'package:file_selector/file_selector.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -24,6 +25,7 @@ enum SortBy { album, } +@RoutePage() class UserLocalLibraryPage extends HookConsumerWidget { static const name = 'user_local_library'; const UserLocalLibraryPage({super.key}); diff --git a/lib/pages/library/user_playlists.dart b/lib/pages/library/user_playlists.dart index a4711e1b..76a01e18 100644 --- a/lib/pages/library/user_playlists.dart +++ b/lib/pages/library/user_playlists.dart @@ -7,6 +7,7 @@ import 'package:shadcn_flutter/shadcn_flutter.dart' hide Image; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/playbutton_view/playbutton_view.dart'; import 'package:spotube/modules/playlist/playlist_create_dialog.dart'; @@ -14,12 +15,12 @@ import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/fallbacks/anonymous_fallback.dart'; import 'package:spotube/modules/playlist/playlist_card.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/utils/platform.dart'; -import 'package:spotube/utils/service_utils.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class UserPlaylistsPage extends HookConsumerWidget { static const name = 'user_playlists'; const UserPlaylistsPage({super.key}); @@ -113,10 +114,7 @@ class UserPlaylistsPage extends HookConsumerWidget { leading: const Icon(SpotubeIcons.magic), child: Text(context.l10n.generate), onPressed: () { - ServiceUtils.pushNamed( - context, - PlaylistGeneratorPage.name, - ); + context.pushRoute(const PlaylistGeneratorRoute()); }, ), const Gap(10), diff --git a/lib/pages/lyrics/lyrics.dart b/lib/pages/lyrics/lyrics.dart index 85798eda..ab8782a8 100644 --- a/lib/pages/lyrics/lyrics.dart +++ b/lib/pages/lyrics/lyrics.dart @@ -14,7 +14,9 @@ import 'package:spotube/pages/lyrics/synced_lyrics.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/utils/platform.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class LyricsPage extends HookConsumerWidget { static const name = "lyrics"; diff --git a/lib/pages/lyrics/mini_lyrics.dart b/lib/pages/lyrics/mini_lyrics.dart index 9fd54ad6..bb879888 100644 --- a/lib/pages/lyrics/mini_lyrics.dart +++ b/lib/pages/lyrics/mini_lyrics.dart @@ -1,9 +1,10 @@ import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:palette_generator/palette_generator.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/player/player_controls.dart'; import 'package:spotube/modules/player/player_queue.dart'; @@ -14,7 +15,9 @@ import 'package:spotube/pages/lyrics/synced_lyrics.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/utils/platform.dart'; import 'package:window_manager/window_manager.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class MiniLyricsPage extends HookConsumerWidget { static const name = "mini_lyrics"; @@ -265,7 +268,7 @@ class MiniLyricsPage extends HookConsumerWidget { const Duration(milliseconds: 200)); } finally { if (context.mounted) { - GoRouter.of(context).go('/lyrics'); + context.navigateTo(LyricsRoute()); } } }, diff --git a/lib/pages/mobile_login/hooks/login_callback.dart b/lib/pages/mobile_login/hooks/login_callback.dart index 9979f4a5..af08b9f9 100644 --- a/lib/pages/mobile_login/hooks/login_callback.dart +++ b/lib/pages/mobile_login/hooks/login_callback.dart @@ -1,14 +1,15 @@ import 'dart:io'; +import 'package:auto_route/auto_route.dart'; import 'package:desktop_webview_window/desktop_webview_window.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart' hide join; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:spotube/pages/mobile_login/mobile_login.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/pages/mobile_login/no_webview_runtime_dialog.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/utils/platform.dart'; @@ -20,7 +21,7 @@ Future Function() useLoginCallback(WidgetRef ref) { return useCallback(() async { if (kIsMobile || kIsMacOS) { - context.pushNamed(WebViewLogin.name); + context.pushRoute(const WebViewLoginRoute()); return; } @@ -57,7 +58,7 @@ Future Function() useLoginCallback(WidgetRef ref) { webview.close(); if (context.mounted) { - context.go("/"); + context.navigateTo(const HomeRoute()); } }); } @@ -76,5 +77,5 @@ Future Function() useLoginCallback(WidgetRef ref) { }); } } - }, [authNotifier, theme, context.go, context.pushNamed]); + }, [authNotifier, theme, context.navigateTo]); } diff --git a/lib/pages/mobile_login/mobile_login.dart b/lib/pages/mobile_login/mobile_login.dart index e2191586..4128bfe6 100644 --- a/lib/pages/mobile_login/mobile_login.dart +++ b/lib/pages/mobile_login/mobile_login.dart @@ -1,16 +1,19 @@ import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/utils/platform.dart'; +import 'package:auto_route/auto_route.dart'; -class WebViewLogin extends HookConsumerWidget { +@RoutePage() +class WebViewLoginPage extends HookConsumerWidget { static const name = "login"; - const WebViewLogin({super.key}); + const WebViewLoginPage({super.key}); @override Widget build(BuildContext context, ref) { @@ -64,7 +67,7 @@ class WebViewLogin extends HookConsumerWidget { await authenticationNotifier.login(cookieHeader); if (context.mounted) { // ignore: use_build_context_synchronously - GoRouter.of(context).go("/"); + context.navigateTo(const HomeRoute()); } } }, diff --git a/lib/pages/playlist/liked_playlist.dart b/lib/pages/playlist/liked_playlist.dart index 95107a8c..54df2c88 100644 --- a/lib/pages/playlist/liked_playlist.dart +++ b/lib/pages/playlist/liked_playlist.dart @@ -5,7 +5,9 @@ import 'package:spotube/components/track_presentation/presentation_props.dart'; import 'package:spotube/components/track_presentation/track_presentation.dart'; import 'package:spotube/pages/playlist/playlist.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class LikedPlaylistPage extends HookConsumerWidget { static const name = PlaylistPage.name; diff --git a/lib/pages/playlist/playlist.dart b/lib/pages/playlist/playlist.dart index b610b1d4..e3992db8 100644 --- a/lib/pages/playlist/playlist.dart +++ b/lib/pages/playlist/playlist.dart @@ -9,13 +9,17 @@ import 'package:spotube/components/track_presentation/use_is_user_playlist.dart' import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class PlaylistPage extends HookConsumerWidget { static const name = "playlist"; final PlaylistSimple _playlist; + final String id; const PlaylistPage({ super.key, + @PathParam("id") required this.id, required PlaylistSimple playlist, }) : _playlist = playlist; diff --git a/lib/pages/profile/profile.dart b/lib/pages/profile/profile.dart index 004fbd1a..a82c80b5 100644 --- a/lib/pages/profile/profile.dart +++ b/lib/pages/profile/profile.dart @@ -12,7 +12,9 @@ import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:url_launcher/url_launcher_string.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class ProfilePage extends HookConsumerWidget { static const name = "profile"; diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index 2a1bf088..e5f0917b 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -1,27 +1,24 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/components/framework/app_pop_scope.dart'; import 'package:spotube/modules/root/bottom_player.dart'; -import 'package:spotube/modules/root/sidebar.dart'; +import 'package:spotube/modules/root/sidebar/sidebar.dart'; import 'package:spotube/modules/root/spotube_navigation_bar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/configurators/use_endless_playback.dart'; import 'package:spotube/modules/root/use_downloader_dialogs.dart'; import 'package:spotube/modules/root/use_global_subscriptions.dart'; -import 'package:spotube/pages/home/home.dart'; import 'package:spotube/provider/glance/glance.dart'; import 'package:spotube/utils/platform.dart'; -class RootApp extends HookConsumerWidget { - final Widget child; - const RootApp({ - required this.child, - super.key, - }); +@RoutePage() +class RootAppPage extends HookConsumerWidget { + const RootAppPage({super.key}); @override Widget build(BuildContext context, ref) { @@ -46,19 +43,19 @@ class RootApp extends HookConsumerWidget { }, [backgroundColor, brightness]); final navTileNames = useMemoized(() { - return getSidebarTileList(context.l10n).map((s) => s.name).toList(); + return getSidebarTileList(context.l10n).map((s) => s.route).toList(); }, []); final scaffold = MediaQuery.removeViewInsets( context: context, removeBottom: true, - child: Scaffold( - footers: const [ + child: const Scaffold( + footers: [ BottomPlayer(), SpotubeNavigationBar(), ], floatingFooter: true, - child: Sidebar(child: child), + child: Sidebar(child: AutoRouter()), ), ); @@ -66,18 +63,18 @@ class RootApp extends HookConsumerWidget { return scaffold; } - final topRoute = GoRouterState.of(context).topRoute; - final canPop = topRoute != null && !navTileNames.contains(topRoute.name); + final topRoute = context.router.topRoute; + final canPop = navTileNames.any((name) => name.routeName == topRoute.name); return AppPopScope( canPop: canPop, onPopInvoked: (didPop) { if (didPop) return; - if (topRoute?.name == HomePage.name) { + if (topRoute.path == const HomeRoute().fragment) { SystemNavigator.pop(); } else { - context.goNamed(HomePage.name); + context.navigateTo(const HomeRoute()); } }, child: scaffold, diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index 701c3c5c..2a69b057 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -20,7 +20,9 @@ import 'package:spotube/pages/search/sections/tracks.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/services/kv_store/kv_store.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class SearchPage extends HookConsumerWidget { static const name = "search"; diff --git a/lib/pages/settings/about.dart b/lib/pages/settings/about.dart index 79c6692b..0703d4ef 100644 --- a/lib/pages/settings/about.dart +++ b/lib/pages/settings/about.dart @@ -11,15 +11,17 @@ import 'package:spotube/hooks/controllers/use_package_info.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:auto_route/auto_route.dart'; final _licenseProvider = FutureProvider((ref) async { return await rootBundle.loadString("LICENSE"); }); -class AboutSpotube extends HookConsumerWidget { +@RoutePage() +class AboutSpotubePage extends HookConsumerWidget { static const name = "about"; - const AboutSpotube({super.key}); + const AboutSpotubePage({super.key}); @override Widget build(BuildContext context, ref) { diff --git a/lib/pages/settings/blacklist.dart b/lib/pages/settings/blacklist.dart index b525b1b5..377a6079 100644 --- a/lib/pages/settings/blacklist.dart +++ b/lib/pages/settings/blacklist.dart @@ -11,7 +11,9 @@ import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/blacklist_provider.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class BlackListPage extends HookConsumerWidget { static const name = "blacklist"; diff --git a/lib/pages/settings/logs.dart b/lib/pages/settings/logs.dart index 3a4f7715..4985b57a 100644 --- a/lib/pages/settings/logs.dart +++ b/lib/pages/settings/logs.dart @@ -11,7 +11,9 @@ import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/logs/logs_provider.dart'; import 'package:spotube/services/logger/logger.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class LogsPage extends HookConsumerWidget { static const name = "logs"; diff --git a/lib/pages/settings/sections/about.dart b/lib/pages/settings/sections/about.dart index 7f5d3977..fcdac8a7 100644 --- a/lib/pages/settings/sections/about.dart +++ b/lib/pages/settings/sections/about.dart @@ -1,9 +1,11 @@ +import 'package:auto_route/auto_route.dart'; import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart' show ListTile; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart' hide ButtonStyle; import 'package:spotube/collections/env.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/components/adaptive/adaptive_list_tile.dart'; @@ -88,7 +90,7 @@ class SettingsAboutSection extends HookConsumerWidget { title: Text(context.l10n.about_spotube), trailing: const Icon(SpotubeIcons.angleRight), onTap: () { - GoRouter.of(context).push("/settings/about"); + context.pushRoute(const AboutSpotubeRoute()); }, ) ], diff --git a/lib/pages/settings/sections/accounts.dart b/lib/pages/settings/sections/accounts.dart index 6132776c..95619d30 100644 --- a/lib/pages/settings/sections/accounts.dart +++ b/lib/pages/settings/sections/accounts.dart @@ -1,20 +1,20 @@ +import 'package:auto_route/auto_route.dart'; import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart' show ListTile; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/profile/profile.dart'; import 'package:spotube/pages/mobile_login/hooks/login_callback.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/scrobbler/scrobbler.dart'; import 'package:spotube/provider/spotify/spotify.dart'; -import 'package:spotube/utils/service_utils.dart'; class SettingsAccountSection extends HookConsumerWidget { const SettingsAccountSection({super.key}); @@ -22,7 +22,6 @@ class SettingsAccountSection extends HookConsumerWidget { @override Widget build(context, ref) { final theme = Theme.of(context); - final router = GoRouter.of(context); final auth = ref.watch(authenticationProvider); final scrobbler = ref.watch(scrobblerProvider); @@ -50,7 +49,7 @@ class SettingsAccountSection extends HookConsumerWidget { ), ), onTap: () { - ServiceUtils.pushNamed(context, ProfilePage.name); + context.pushRoute(ProfileRoute()); }, ), if (auth.asData?.value == null) @@ -99,7 +98,7 @@ class SettingsAccountSection extends HookConsumerWidget { trailing: Button.destructive( onPressed: () async { ref.read(authenticationProvider.notifier).logout(); - GoRouter.of(context).pop(); + context.maybePop(); }, child: Text(context.l10n.logout), ), @@ -113,7 +112,7 @@ class SettingsAccountSection extends HookConsumerWidget { trailing: Button.secondary( leading: const Icon(SpotubeIcons.lastFm), onPressed: () { - router.push("/lastfm-login"); + context.pushRoute(const LastFMLoginRoute()); }, child: Text(context.l10n.connect), ), diff --git a/lib/pages/settings/sections/developers.dart b/lib/pages/settings/sections/developers.dart index 4d8b8ba1..6afe01c3 100644 --- a/lib/pages/settings/sections/developers.dart +++ b/lib/pages/settings/sections/developers.dart @@ -1,7 +1,9 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart' show ListTile; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/extensions/context.dart'; @@ -19,7 +21,7 @@ class SettingsDevelopersSection extends HookWidget { title: Text(context.l10n.logs), trailing: const Icon(SpotubeIcons.angleRight), onTap: () { - GoRouter.of(context).push("/settings/logs"); + context.pushRoute(const LogsRoute()); }, ) ], diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart index be3fc15b..9e561655 100644 --- a/lib/pages/settings/sections/playback.dart +++ b/lib/pages/settings/sections/playback.dart @@ -1,12 +1,13 @@ +import 'package:auto_route/auto_route.dart'; import 'package:collection/collection.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart' show ListTile; -import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:piped_client/piped_client.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; @@ -267,7 +268,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { title: Text(context.l10n.blacklist), subtitle: Text(context.l10n.blacklist_description), onTap: () { - GoRouter.of(context).push("/settings/blacklist"); + context.pushRoute(const BlackListRoute()); }, trailing: const Icon(SpotubeIcons.angleRight), ), diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index 54c377eb..53610ae4 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -15,7 +15,9 @@ import 'package:spotube/pages/settings/sections/language_region.dart'; import 'package:spotube/pages/settings/sections/playback.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/utils/platform.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class SettingsPage extends HookConsumerWidget { static const name = "settings"; diff --git a/lib/pages/stats/albums/albums.dart b/lib/pages/stats/albums/albums.dart index eee6694b..807b8049 100644 --- a/lib/pages/stats/albums/albums.dart +++ b/lib/pages/stats/albums/albums.dart @@ -10,7 +10,9 @@ import 'package:spotube/provider/history/top.dart'; import 'package:spotube/provider/history/top/albums.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsAlbumsPage extends HookConsumerWidget { static const name = "stats_albums"; const StatsAlbumsPage({super.key}); diff --git a/lib/pages/stats/artists/artists.dart b/lib/pages/stats/artists/artists.dart index 3a719725..311faa0c 100644 --- a/lib/pages/stats/artists/artists.dart +++ b/lib/pages/stats/artists/artists.dart @@ -11,7 +11,9 @@ import 'package:spotube/provider/history/top.dart'; import 'package:spotube/provider/history/top/tracks.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsArtistsPage extends HookConsumerWidget { static const name = "stats_artists"; const StatsArtistsPage({super.key}); diff --git a/lib/pages/stats/fees/fees.dart b/lib/pages/stats/fees/fees.dart index 14f432d6..8a20758d 100644 --- a/lib/pages/stats/fees/fees.dart +++ b/lib/pages/stats/fees/fees.dart @@ -12,7 +12,9 @@ import 'package:spotube/provider/history/top.dart'; import 'package:spotube/provider/history/top/tracks.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsStreamFeesPage extends HookConsumerWidget { static const name = "stats_stream_fees"; diff --git a/lib/pages/stats/minutes/minutes.dart b/lib/pages/stats/minutes/minutes.dart index 39438b47..df7f5983 100644 --- a/lib/pages/stats/minutes/minutes.dart +++ b/lib/pages/stats/minutes/minutes.dart @@ -10,7 +10,9 @@ import 'package:spotube/provider/history/top.dart'; import 'package:spotube/provider/history/top/tracks.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsMinutesPage extends HookConsumerWidget { static const name = "stats_minutes"; diff --git a/lib/pages/stats/playlists/playlists.dart b/lib/pages/stats/playlists/playlists.dart index f5d7a285..78c3cd24 100644 --- a/lib/pages/stats/playlists/playlists.dart +++ b/lib/pages/stats/playlists/playlists.dart @@ -10,7 +10,9 @@ import 'package:spotube/provider/history/top.dart'; import 'package:spotube/provider/history/top/playlists.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsPlaylistsPage extends HookConsumerWidget { static const name = "stats_playlists"; const StatsPlaylistsPage({super.key}); diff --git a/lib/pages/stats/stats.dart b/lib/pages/stats/stats.dart index e543900c..4f0cf95b 100644 --- a/lib/pages/stats/stats.dart +++ b/lib/pages/stats/stats.dart @@ -4,7 +4,9 @@ import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/modules/stats/summary/summary.dart'; import 'package:spotube/modules/stats/top/top.dart'; import 'package:spotube/utils/platform.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsPage extends HookConsumerWidget { static const name = "stats"; diff --git a/lib/pages/stats/streams/streams.dart b/lib/pages/stats/streams/streams.dart index 2c2e0c9b..05e53d7c 100644 --- a/lib/pages/stats/streams/streams.dart +++ b/lib/pages/stats/streams/streams.dart @@ -10,7 +10,9 @@ import 'package:spotube/provider/history/top.dart'; import 'package:spotube/provider/history/top/tracks.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsStreamsPage extends HookConsumerWidget { static const name = "stats_streams"; diff --git a/lib/pages/track/track.dart b/lib/pages/track/track.dart index 54563bfe..765969be 100644 --- a/lib/pages/track/track.dart +++ b/lib/pages/track/track.dart @@ -1,10 +1,10 @@ import 'dart:ui'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/heart_button/heart_button.dart'; import 'package:spotube/components/image/universal_image.dart'; @@ -20,14 +20,16 @@ import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/extensions/constrains.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class TrackPage extends HookConsumerWidget { static const name = "track"; final String trackId; const TrackPage({ super.key, - required this.trackId, + @PathParam("id") required this.trackId, }); @override @@ -138,9 +140,11 @@ class TrackPage extends HookConsumerWidget { Flexible( child: LinkText( track.album!.name!, - '/album/${track.album!.id}', + AlbumRoute( + id: track.album!.id!, + album: track.album!, + ), push: true, - extra: track.album, ), ), ], diff --git a/lib/utils/service_utils.dart b/lib/utils/service_utils.dart index c89866b4..b55af9e9 100644 --- a/lib/utils/service_utils.dart +++ b/lib/utils/service_utils.dart @@ -1,8 +1,9 @@ import 'dart:typed_data'; +import 'package:auto_route/auto_route.dart'; import 'package:dio/dio.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; -import 'package:go_router/go_router.dart'; + import 'package:html/dom.dart' hide Text; import 'package:shadcn_flutter/shadcn_flutter.dart' hide Element; import 'package:spotify/spotify.dart'; @@ -276,70 +277,6 @@ abstract class ServiceUtils { return subtitle; } - static void navigate(BuildContext context, String location, {Object? extra}) { - if (GoRouterState.of(context).matchedLocation == location) return; - GoRouter.of(context).go(location, extra: extra); - } - - static void navigateNamed( - BuildContext context, - String name, { - Object? extra, - Map? pathParameters, - Map? queryParameters, - }) { - if (GoRouterState.of(context).matchedLocation == name) return; - GoRouter.of(context).goNamed( - name, - pathParameters: pathParameters ?? const {}, - queryParameters: queryParameters ?? const {}, - extra: extra, - ); - } - - static void push(BuildContext context, String location, {Object? extra}) { - final router = GoRouter.of(context); - final routerState = GoRouterState.of(context); - final routerStack = router.routerDelegate.currentConfiguration.matches - .map((e) => e.matchedLocation); - - if (routerState.matchedLocation == location || - routerStack.contains(location)) { - return; - } - router.push(location, extra: extra); - } - - static void pushNamed( - BuildContext context, - String name, { - Object? extra, - Map pathParameters = const {}, - Map queryParameters = const {}, - }) { - final router = GoRouter.of(context); - final routerState = GoRouterState.of(context); - final routerStack = router.routerDelegate.currentConfiguration.matches - .map((e) => e.matchedLocation); - - final nameLocation = routerState.namedLocation( - name, - pathParameters: pathParameters, - queryParameters: queryParameters, - ); - - if (routerState.matchedLocation == nameLocation || - routerStack.contains(nameLocation)) { - return; - } - router.pushNamed( - name, - pathParameters: pathParameters, - queryParameters: queryParameters, - extra: extra, - ); - } - static DateTime parseSpotifyAlbumDate(AlbumSimple? album) { if (album == null || album.releaseDate == null) { return DateTime.parse("1975-01-01"); diff --git a/pubspec.lock b/pubspec.lock index 1e9d9265..8c1bb00d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -142,6 +142,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.21" + auto_route: + dependency: "direct main" + description: + name: auto_route + sha256: "1d1bd908a1fec327719326d5d0791edd37f16caff6493c01003689fb03315ad7" + url: "https://pub.dev" + source: hosted + version: "9.3.0+1" + auto_route_generator: + dependency: "direct dev" + description: + name: auto_route_generator + sha256: c9086eb07271e51b44071ad5cff34e889f3156710b964a308c2ab590769e79e6 + url: "https://pub.dev" + source: hosted + version: "9.0.0" auto_size_text: dependency: "direct main" description: @@ -1073,14 +1089,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" - go_router: - dependency: "direct main" - description: - name: go_router - sha256: "2fd11229f59e23e967b0775df8d5948a519cd7e1e8b6e849729e010587b46539" - url: "https://pub.dev" - source: hosted - version: "14.6.2" google_fonts: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index ed0d7ce5..8b3c3e7b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,6 +19,7 @@ dependencies: audio_service: ^0.18.13 audio_service_mpris: ^0.2.0 audio_session: ^0.1.19 + auto_route: ^9.3.0+1 auto_size_text: ^3.0.0 bonsoir: ^5.1.10 cached_network_image: ^3.3.1 @@ -70,7 +71,6 @@ dependencies: freezed_annotation: ^2.4.1 fuzzywuzzy: ^1.1.6 gap: ^3.0.1 - go_router: ^14.2.7 google_fonts: ^6.2.1 hive: ^2.2.3 hive_flutter: ^1.1.0 @@ -161,6 +161,7 @@ dev_dependencies: xml: ^6.5.0 io: ^1.0.4 drift_dev: ^2.21.0 + auto_route_generator: ^9.0.0 dependency_overrides: bonsoir_android: