refactor: migrate to auto_route from go_router

This commit is contained in:
Kingkor Roy Tirtho 2025-01-31 21:07:51 +06:00
parent 2b0b5eae1d
commit 0037677383
87 changed files with 2086 additions and 1173 deletions

View File

@ -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

View File

@ -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<PlayPauseIntent> {
}
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<NavigationIntent> {
@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<HomeTabIntent> {
@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;

View File

@ -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<NavigatorState>();
final shellRouteNavigatorKey = GlobalKey<NavigatorState>();
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 {
@AutoRouterConfig(replaceInRouteName: 'Screen|Page,Route')
class AppRouter extends RootStackRouter {
final WidgetRef ref;
AppRouter(this.ref) : super(navigatorKey: rootNavigatorKey);
@override
List<AutoRouteGuard> get guards => [
AutoRouteGuardCallback(
(resolver, router) async {
final auth = await ref.read(authenticationProvider.future);
if (auth == null && !KVStoreService.doneGettingStarted) {
return "/getting-started";
resolver.redirect(const GettingStartedRoute());
} else {
resolver.next(true);
}
},
),
];
@override
List<AutoRoute> 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;
},
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,
AutoRoute(
path: "track/:id",
page: TrackRoute.page,
),
AutoRoute(
path: "connect",
page: ConnectRoute.page,
),
)
],
AutoRoute(
path: "connect/control",
page: ConnectControlRoute.page,
),
GoRoute(
path: "/lyrics",
name: LyricsPage.name,
pageBuilder: (context, state) =>
const SpotubePage(child: LyricsPage()),
AutoRoute(
path: "profile",
page: ProfileRoute.page,
),
GoRoute(
path: "/settings",
name: SettingsPage.name,
pageBuilder: (context, state) => const SpotubePage(
child: SettingsPage(),
AutoRoute(
path: "stats",
page: StatsRoute.page,
),
routes: [
GoRoute(
path: "blacklist",
name: BlackListPage.name,
pageBuilder: (context, state) => SpotubeSlidePage(
child: const BlackListPage(),
AutoRoute(
path: "stats/minutes",
page: StatsMinutesRoute.page,
),
AutoRoute(
path: "stats/streams",
page: StatsStreamsRoute.page,
),
if (!kIsWeb)
GoRoute(
path: "logs",
name: LogsPage.name,
pageBuilder: (context, state) => SpotubeSlidePage(
child: const LogsPage(),
AutoRoute(
path: "stats/fees",
page: StatsStreamFeesRoute.page,
),
AutoRoute(
path: "stats/artists",
page: StatsArtistsRoute.page,
),
GoRoute(
path: "about",
name: AboutSpotube.name,
pageBuilder: (context, state) => SpotubeSlidePage(
child: const AboutSpotube(),
AutoRoute(
path: "stats/albums",
page: StatsAlbumsRoute.page,
),
AutoRoute(
path: "stats/playlists",
page: StatsPlaylistsRoute.page,
),
],
),
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(
AutoRoute(
path: "/mini-player",
name: MiniLyricsPage.name,
parentNavigatorKey: rootNavigatorKey,
pageBuilder: (context, state) => SpotubePage(
child: MiniLyricsPage(prevSize: state.extra as Size),
page: MiniLyricsRoute.page,
// parentNavigatorKey: rootNavigatorKey,
),
),
GoRoute(
AutoRoute(
path: "/getting-started",
name: GettingStarting.name,
parentNavigatorKey: rootNavigatorKey,
pageBuilder: (context, state) => const SpotubePage(
child: GettingStarting(),
page: GettingStartedRoute.page,
// parentNavigatorKey: rootNavigatorKey,
),
),
GoRoute(
AutoRoute(
path: "/login",
name: WebViewLogin.name,
parentNavigatorKey: rootNavigatorKey,
pageBuilder: (context, state) => const SpotubePage(
child: WebViewLogin(),
page: WebViewLoginRoute.page,
// parentNavigatorKey: rootNavigatorKey,
),
),
GoRoute(
AutoRoute(
path: "/lastfm-login",
name: LastFMLoginPage.name,
parentNavigatorKey: rootNavigatorKey,
pageBuilder: (context, state) =>
const SpotubePage(child: LastFMLoginPage()),
page: LastFMLoginRoute.page,
// parentNavigatorKey: rootNavigatorKey,
),
],
);
});
];
}

File diff suppressed because it is too large Load Diff

View File

@ -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<SideBarTiles> 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<SideBarTiles> 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<SideBarTiles> getSidebarLibraryTileList(AppLocalizations l10n) => [
List<SideBarTiles> 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,
),

View File

@ -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),
),

View File

@ -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()),
)
],
),

View File

@ -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<ArtistSimple> 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,

View File

@ -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<T> 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<T> extends StatelessWidget {
this.route, {
super.key,
this.textAlign,
this.extra,
this.overflow,
this.style = const TextStyle(),
this.maxLines,
@ -30,9 +28,9 @@ class LinkText<T> 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,

View File

@ -1,25 +1,24 @@
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:go_router/go_router.dart';
class SpotubePage<T> extends MaterialPage<T> {
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<Offset>(
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<Offset>(
// begin: const Offset(1, 0),
// end: Offset.zero,
// ).animate(animation),
// child: child,
// );
// },
// );
// }

View File

@ -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!),
),
),
),

View File

@ -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,17 +283,15 @@ 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!),
);
},
),
),
),
),
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [

View File

@ -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<SharedFile> 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:

View File

@ -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,

View File

@ -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 {

View File

@ -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: [

View File

@ -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());
},
)
],

View File

@ -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,14 +39,10 @@ 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));
},
),
),
);
},
);

View File

@ -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),
);
}
},

View File

@ -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(

View File

@ -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(

View File

@ -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,

View File

@ -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(

View File

@ -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,14 +66,10 @@ class DownloadItem extends HookConsumerWidget {
subtitle: ArtistLink(
artists: track.artists ?? <Artist>[],
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()
: switch (taskStatus.value!) {

View File

@ -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);
},
onOverflowArtistClick: () => ServiceUtils.pushNamed(
context,
TrackPage.name,
pathParameters: {
"id": currentTrack!.id!,
context.router.pushNamed(route);
},
onOverflowArtistClick: () => context.pushRoute(
TrackRoute(trackId: currentTrack!.id!),
),
),
],

View File

@ -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!)),
)
],
),

View File

@ -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 {

View File

@ -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();
}
}
}

View File

@ -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),
);
}
},

View File

@ -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;
}

View File

@ -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),
],
);
}
}

View File

@ -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;
}

View File

@ -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<double>((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 panelHeight = ref.watch(navigationPanelHeight);
final selectedIndex = useMemoized(() {
final index = navbarTileList.indexWhere(
(e) => routerState.namedLocation(e.name) == routerState.matchedLocation,
final libraryTiles = useMemoized(
() => getSidebarLibraryTileList(context.l10n)
.map((e) => e.route.routeName)
.toList(),
[context.l10n],
);
return index == -1 ? 0 : index;
}, [navbarTileList, routerState.matchedLocation]);
final panelHeight = ref.watch(navigationPanelHeight);
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)

View File

@ -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));
},
);
}

View File

@ -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!));
},
);
}

View File

@ -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));
},
);
}

View File

@ -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!));
},
);
}

View File

@ -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());
},
),
]),

View File

@ -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(

View File

@ -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,
});

View File

@ -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) {

View File

@ -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);
}

View File

@ -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!),
),
),
),

View File

@ -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) {

View File

@ -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),

View File

@ -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) {

View File

@ -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,
);

View File

@ -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(

View File

@ -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),

View File

@ -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(

View File

@ -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(),
);
}),
);

View File

@ -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),

View File

@ -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,
),
);
}
},

View File

@ -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});

View File

@ -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});

View File

@ -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});

View File

@ -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";

View File

@ -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});

View File

@ -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),

View File

@ -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";

View File

@ -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());
}
}
},

View File

@ -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<void> Function() useLoginCallback(WidgetRef ref) {
return useCallback(() async {
if (kIsMobile || kIsMacOS) {
context.pushNamed(WebViewLogin.name);
context.pushRoute(const WebViewLoginRoute());
return;
}
@ -57,7 +58,7 @@ Future<void> Function() useLoginCallback(WidgetRef ref) {
webview.close();
if (context.mounted) {
context.go("/");
context.navigateTo(const HomeRoute());
}
});
}
@ -76,5 +77,5 @@ Future<void> Function() useLoginCallback(WidgetRef ref) {
});
}
}
}, [authNotifier, theme, context.go, context.pushNamed]);
}, [authNotifier, theme, context.navigateTo]);
}

View File

@ -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());
}
}
},

View File

@ -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;

View File

@ -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;

View File

@ -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";

View File

@ -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,

View File

@ -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";

View File

@ -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<String>((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) {

View File

@ -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";

View File

@ -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";

View File

@ -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());
},
)
],

View File

@ -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),
),

View File

@ -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());
},
)
],

View File

@ -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),
),

View File

@ -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";

View File

@ -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});

View File

@ -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});

View File

@ -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";

View File

@ -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";

View File

@ -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});

View File

@ -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";

View File

@ -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";

View File

@ -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,
),
),
],

View File

@ -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<String, String>? pathParameters,
Map<String, dynamic>? 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<String, String> pathParameters = const {},
Map<String, String> 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");

View File

@ -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:

View File

@ -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: