chore: use navigateTo instead of pushRoute

This commit is contained in:
Kingkor Roy Tirtho 2025-01-31 22:10:40 +06:00
parent 0037677383
commit 4b2d259add
45 changed files with 307 additions and 304 deletions

View File

@ -37,7 +37,7 @@ class AppRouter extends RootStackRouter {
initial: true,
children: [
AutoRoute(
path: "browse",
path: "home",
page: HomeRoute.page,
initial: true,
),
@ -70,7 +70,7 @@ class AppRouter extends RootStackRouter {
page: UserArtistsRoute.page,
),
AutoRoute(
path: "album",
path: "albums",
page: UserAlbumsRoute.page,
),
AutoRoute(

View File

@ -8,6 +8,7 @@ class SideBarTiles {
final IconData icon;
final String title;
final String id;
final String pathPrefix;
final PageRouteInfo route;
SideBarTiles({
@ -15,30 +16,35 @@ class SideBarTiles {
required this.title,
required this.id,
required this.route,
required this.pathPrefix,
});
}
List<SideBarTiles> getSidebarTileList(AppLocalizations l10n) => [
SideBarTiles(
id: "browse",
id: "home",
pathPrefix: "/home",
route: const HomeRoute(),
icon: SpotubeIcons.home,
title: l10n.browse,
),
SideBarTiles(
id: "search",
pathPrefix: "/search",
route: const SearchRoute(),
icon: SpotubeIcons.search,
title: l10n.search,
),
SideBarTiles(
id: "lyrics",
pathPrefix: "/lyrics",
route: LyricsRoute(),
icon: SpotubeIcons.music,
title: l10n.lyrics,
),
SideBarTiles(
id: "stats",
pathPrefix: "/stats",
route: const StatsRoute(),
icon: SpotubeIcons.chart,
title: l10n.stats,
@ -48,24 +54,28 @@ List<SideBarTiles> getSidebarTileList(AppLocalizations l10n) => [
List<SideBarTiles> getSidebarLibraryTileList(AppLocalizations l10n) => [
SideBarTiles(
id: "playlists",
pathPrefix: "/library/playlists",
title: l10n.playlists,
route: const UserPlaylistsRoute(),
icon: SpotubeIcons.playlist,
),
SideBarTiles(
id: "artists",
pathPrefix: "/library/artists",
title: l10n.artists,
route: const UserArtistsRoute(),
icon: SpotubeIcons.artist,
),
SideBarTiles(
id: "albums",
pathPrefix: "/library/albums",
title: l10n.albums,
route: const UserAlbumsRoute(),
icon: SpotubeIcons.album,
),
SideBarTiles(
id: "local_library",
pathPrefix: "/library/local",
title: l10n.local_library,
route: const UserLocalLibraryRoute(),
icon: SpotubeIcons.device,
@ -74,25 +84,29 @@ List<SideBarTiles> getSidebarLibraryTileList(AppLocalizations l10n) => [
List<SideBarTiles> getNavbarTileList(AppLocalizations l10n) => [
SideBarTiles(
id: "browse",
id: "home",
pathPrefix: "/home",
route: const HomeRoute(),
icon: SpotubeIcons.home,
title: l10n.browse,
),
SideBarTiles(
id: "search",
pathPrefix: "/search",
route: const SearchRoute(),
icon: SpotubeIcons.search,
title: l10n.search,
),
SideBarTiles(
id: "library",
pathPrefix: "/library",
route: const UserPlaylistsRoute(),
icon: SpotubeIcons.library,
title: l10n.library,
),
SideBarTiles(
id: "stats",
pathPrefix: "/stats",
route: const StatsRoute(),
icon: SpotubeIcons.chart,
title: l10n.stats,

View File

@ -40,7 +40,7 @@ class AnonymousFallback extends ConsumerWidget {
Text(context.l10n.not_logged_in),
Button.primary(
child: Text(context.l10n.login_with_spotify),
onPressed: () => context.pushRoute(const SettingsRoute()),
onPressed: () => context.navigateTo(const SettingsRoute()),
)
],
),

View File

@ -50,7 +50,7 @@ class ArtistLink extends StatelessWidget {
onRouteChange?.call("/artist/${artist.value.id}");
} else {
context
.pushRoute(ArtistRoute(artistId: artist.value.id!));
.navigateTo(ArtistRoute(artistId: artist.value.id!));
}
},
overflow: TextOverflow.ellipsis,

View File

@ -28,7 +28,7 @@ class LinkText<T> extends StatelessWidget {
text,
onTap: () {
if (push) {
context.pushRoute(route);
context.navigateTo(route);
} else {
context.navigateTo(route);
}

View File

@ -210,7 +210,7 @@ class TrackOptions extends HookConsumerWidget {
onSelected: (value) async {
switch (value) {
case TrackOptionValue.album:
await context.pushRoute(
await context.navigateTo(
AlbumRoute(id: track.album!.id!, album: track.album!),
);
break;
@ -345,7 +345,7 @@ class TrackOptions extends HookConsumerWidget {
alignment: Alignment.centerLeft,
child: ArtistLink(
artists: track.artists!,
onOverflowArtistClick: () => context.pushRoute(
onOverflowArtistClick: () => context.navigateTo(
TrackRoute(trackId: track.id!),
),
),

View File

@ -234,7 +234,7 @@ class TrackTile extends HookConsumerWidget {
),
onPressed: () {
context
.pushRoute(TrackRoute(trackId: track.id!));
.navigateTo(TrackRoute(trackId: track.id!));
},
child: Text(
track.name!,
@ -284,7 +284,7 @@ class TrackTile extends HookConsumerWidget {
child: ArtistLink(
artists: track.artists ?? [],
onOverflowArtistClick: () {
context.pushRoute(
context.navigateTo(
TrackRoute(trackId: track.id!),
);
},

View File

@ -28,19 +28,20 @@ void useDeepLinking(WidgetRef ref, AppRouter router) {
switch (url.pathSegments.first) {
case "album":
final album = await spotify.albums.get(url.pathSegments.last);
router.push(
router.navigate(
AlbumRoute(id: album.id!, album: album),
);
break;
case "artist":
router.push(ArtistRoute(artistId: url.pathSegments.last));
router.navigate(ArtistRoute(artistId: url.pathSegments.last));
break;
case "playlist":
final playlist = await spotify.playlists.get(url.pathSegments.last);
router.push(PlaylistRoute(id: playlist.id!, playlist: playlist));
router
.navigate(PlaylistRoute(id: playlist.id!, playlist: playlist));
break;
case "track":
router.push(TrackRoute(trackId: url.pathSegments.last));
router.navigate(TrackRoute(trackId: url.pathSegments.last));
break;
default:
break;
@ -65,19 +66,19 @@ void useDeepLinking(WidgetRef ref, AppRouter router) {
switch (startSegment) {
case "spotify:album":
final album = await spotify.albums.get(endSegment);
await router.push(
await router.navigate(
AlbumRoute(id: album.id!, album: album),
);
break;
case "spotify:artist":
await router.push(ArtistRoute(artistId: endSegment));
await router.navigate(ArtistRoute(artistId: endSegment));
break;
case "spotify:track":
await router.push(TrackRoute(trackId: endSegment));
await router.navigate(TrackRoute(trackId: endSegment));
break;
case "spotify:playlist":
final playlist = await spotify.playlists.get(endSegment);
await router.push(
await router.navigate(
PlaylistRoute(id: playlist.id!, playlist: playlist),
);
break;

View File

@ -69,7 +69,7 @@ class AlbumCard extends HookConsumerWidget {
"${album.albumType?.formatted}${album.artists?.asString() ?? ""}";
void onTap() {
context.pushRoute(AlbumRoute(id: album.id!, album: album));
context.navigateTo(AlbumRoute(id: album.id!, album: album));
}
void onPlaybuttonPressed() async {

View File

@ -36,7 +36,7 @@ class ArtistCard extends HookConsumerWidget {
width: 180,
child: Button.card(
onPressed: () {
context.pushRoute(ArtistRoute(artistId: artist.id!));
context.navigateTo(ArtistRoute(artistId: artist.id!));
},
child: Column(
children: [

View File

@ -26,7 +26,7 @@ class ConnectDeviceButton extends HookConsumerWidget {
return IconButton.ghost(
icon: const Icon(SpotubeIcons.speaker),
onPressed: () {
context.pushRoute(const ConnectRoute());
context.navigateTo(const ConnectRoute());
},
);
}
@ -35,7 +35,7 @@ class ConnectDeviceButton extends HookConsumerWidget {
width: double.infinity,
child: Button.primary(
onPressed: () {
context.pushRoute(const ConnectRoute());
context.navigateTo(const ConnectRoute());
},
trailing: const Icon(SpotubeIcons.speaker),
child: Text(
@ -50,7 +50,7 @@ class ConnectDeviceButton extends HookConsumerWidget {
children: [
SecondaryBadge(
onPressed: () {
context.pushRoute(const ConnectRoute());
context.navigateTo(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: () {
context.pushRoute(const ConnectRoute());
context.navigateTo(const ConnectRoute());
},
)
],

View File

@ -40,7 +40,7 @@ class HomePageFeedSection extends HookConsumerWidget {
titleTrailing: Button.text(
child: Text(context.l10n.browse_all),
onPressed: () {
context.pushRoute(HomeFeedSectionRoute(sectionUri: section.uri));
context.navigateTo(HomeFeedSectionRoute(sectionUri: section.uri));
},
),
);

View File

@ -50,7 +50,7 @@ class FriendItem extends HookConsumerWidget {
recognizer: TapGestureRecognizer()
..onTap = () {
context
.pushRoute(TrackRoute(trackId: friend.track.id));
.navigateTo(TrackRoute(trackId: friend.track.id));
},
),
const TextSpan(text: ""),
@ -64,7 +64,7 @@ class FriendItem extends HookConsumerWidget {
text: " ${friend.track.artist.name}",
recognizer: TapGestureRecognizer()
..onTap = () {
context.pushRoute(
context.navigateTo(
ArtistRoute(artistId: friend.track.artist.id),
);
},
@ -74,7 +74,7 @@ class FriendItem extends HookConsumerWidget {
text: friend.track.context.name,
recognizer: TapGestureRecognizer()
..onTap = () async {
context.router.pushNamed(
context.router.navigateNamed(
"/${friend.track.context.path}",
// extra:
// !friend.track.context.path.startsWith("album")
@ -98,7 +98,7 @@ class FriendItem extends HookConsumerWidget {
final album =
await spotify.albums.get(friend.track.album.id);
if (context.mounted) {
context.pushRoute(
context.navigateTo(
AlbumRoute(id: album.id!, album: album),
);
}

View File

@ -76,7 +76,7 @@ class GenreSectionCard extends HookConsumerWidget {
).h3(),
Button.link(
onPressed: () {
context.router.push(
context.navigateTo(
GenrePlaylistsRoute(
id: category.id!,
category: category,

View File

@ -47,7 +47,7 @@ class GenreSectionCardPlaylistCard extends HookConsumerWidget {
},
),
onPressed: () {
context.pushRoute(
context.navigateTo(
PlaylistRoute(id: playlist.id!, playlist: playlist),
);
},

View File

@ -48,7 +48,7 @@ class HomeGenresSection extends HookConsumerWidget {
),
Button.link(
onPressed: () {
context.pushRoute(const GenreRoute());
context.navigateTo(const GenreRoute());
},
child: Text(
context.l10n.browse_all,

View File

@ -59,7 +59,7 @@ class LocalFolderItem extends HookConsumerWidget {
return Button(
onPressed: () {
context.pushRoute(
context.navigateTo(
LocalLibraryRoute(
location: folder,
isCache: isCacheFolder,

View File

@ -67,7 +67,7 @@ class DownloadItem extends HookConsumerWidget {
artists: track.artists ?? <Artist>[],
mainAxisAlignment: WrapAlignment.start,
onOverflowArtistClick: () {
context.pushRoute(TrackRoute(trackId: track.id!));
context.navigateTo(TrackRoute(trackId: track.id!));
},
),
trailing: isQueryingSourceInfo

View File

@ -93,7 +93,7 @@ class PlayerView extends HookConsumerWidget {
}, [panelController.isAttached && panelController.isPanelOpen]);
return AppPopScope(
canPop: context.watchRouter.canPop(),
canPop: false,
onPopInvoked: (didPop) async {
await panelController.close();
},
@ -209,9 +209,9 @@ class PlayerView extends HookConsumerWidget {
.copyWith(fontWeight: FontWeight.bold),
onRouteChange: (route) {
panelController.close();
context.router.pushNamed(route);
context.router.navigateNamed(route);
},
onOverflowArtistClick: () => context.pushRoute(
onOverflowArtistClick: () => context.navigateTo(
TrackRoute(trackId: currentTrack!.id!),
),
),

View File

@ -1,4 +1,3 @@
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:sliding_up_panel/sliding_up_panel.dart';
@ -8,6 +7,10 @@ import 'package:spotube/modules/root/spotube_navigation_bar.dart';
import 'package:spotube/modules/player/player.dart';
import 'package:spotube/provider/audio_player/audio_player.dart';
final playerOverlayControllerProvider = StateProvider<PanelController>((ref) {
return PanelController();
});
class PlayerOverlay extends HookConsumerWidget {
final String albumArt;
@ -23,7 +26,7 @@ class PlayerOverlay extends HookConsumerWidget {
final screenSize = MediaQuery.sizeOf(context);
final panelController = useMemoized(() => PanelController(), []);
final panelController = ref.watch(playerOverlayControllerProvider);
return SlidingUpPanel(
maxHeight: screenSize.height,

View File

@ -81,10 +81,10 @@ class PlayerTrackDetails extends HookConsumerWidget {
ArtistLink(
artists: playback.activeTrack?.artists ?? [],
onRouteChange: (route) {
context.router.pushNamed(route);
context.router.navigateNamed(route);
},
onOverflowArtistClick: () =>
context.pushRoute(TrackRoute(trackId: track!.id!)),
context.navigateTo(TrackRoute(trackId: track!.id!)),
)
],
),

View File

@ -73,7 +73,7 @@ class PlaylistCard extends HookConsumerWidget {
}
void onTap() {
context.pushRoute(PlaylistRoute(id: playlist.id!, playlist: playlist));
context.navigateTo(PlaylistRoute(id: playlist.id!, playlist: playlist));
}
void onPlaybuttonPressed() async {

View File

@ -52,12 +52,12 @@ class Sidebar extends HookConsumerWidget {
final router = context.watchRouter;
final selectedIndex = tileList.indexWhere(
(e) => router.topRoute.name == e.route.routeName,
(e) => router.currentPath.startsWith(e.pathPrefix),
);
if (layoutMode == LayoutMode.compact ||
(mediaQuery.smAndDown && layoutMode == LayoutMode.adaptive)) {
return Scaffold(child: child);
return child;
}
final navigationButtons = [

View File

@ -97,7 +97,7 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem {
Flexible(
child: GestureDetector(
onTap: () {
context.pushRoute(const ProfileRoute());
context.navigateTo(const ProfileRoute());
},
child: Row(
children: [
@ -125,7 +125,7 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem {
variance: ButtonVariance.ghost,
icon: const Icon(SpotubeIcons.settings),
onPressed: () {
context.pushRoute(const SettingsRoute());
context.navigateTo(const SettingsRoute());
},
),
],

View File

@ -6,7 +6,6 @@ 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/routes.gr.dart';
import 'package:spotube/collections/side_bar_tiles.dart';
import 'package:spotube/extensions/constrains.dart';
@ -35,23 +34,13 @@ class SpotubeNavigationBar extends HookConsumerWidget {
[context.l10n],
);
final libraryTiles = useMemoized(
() => getSidebarLibraryTileList(context.l10n)
.map((e) => e.route.routeName)
.toList(),
[context.l10n],
);
final panelHeight = ref.watch(navigationPanelHeight);
final 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),
(e) => router.currentPath.startsWith(e.pathPrefix),
),
);

View File

@ -37,14 +37,14 @@ class StatsAlbumItem extends StatelessWidget {
artists: album.artists ?? [],
mainAxisAlignment: WrapAlignment.start,
onOverflowArtistClick: () =>
context.pushRoute(AlbumRoute(id: album.id!, album: album)),
context.navigateTo(AlbumRoute(id: album.id!, album: album)),
),
),
],
),
trailing: info,
onPressed: () {
context.pushRoute(AlbumRoute(id: album.id!, album: album));
context.navigateTo(AlbumRoute(id: album.id!, album: album));
},
);
}

View File

@ -30,7 +30,7 @@ class StatsArtistItem extends StatelessWidget {
),
trailing: info,
onPressed: () {
context.pushRoute(ArtistRoute(artistId: artist.id!));
context.navigateTo(ArtistRoute(artistId: artist.id!));
},
);
}

View File

@ -35,7 +35,7 @@ class StatsPlaylistItem extends StatelessWidget {
),
trailing: info,
onPressed: () {
context.pushRoute(PlaylistRoute(id: playlist.id!, playlist: playlist));
context.navigateTo(PlaylistRoute(id: playlist.id!, playlist: playlist));
},
);
}

View File

@ -35,12 +35,12 @@ class StatsTrackItem extends StatelessWidget {
artists: track.artists!,
mainAxisAlignment: WrapAlignment.start,
onOverflowArtistClick: () {
context.pushRoute(TrackRoute(trackId: track.id!));
context.navigateTo(TrackRoute(trackId: track.id!));
},
),
trailing: info,
onPressed: () {
context.pushRoute(TrackRoute(trackId: track.id!));
context.navigateTo(TrackRoute(trackId: track.id!));
},
);
}

View File

@ -45,7 +45,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
description: context.l10n.summary_listened_to_music,
color: Colors.indigo,
onTap: () {
context.pushRoute(const StatsMinutesRoute());
context.navigateTo(const StatsMinutesRoute());
},
),
SummaryCard(
@ -54,7 +54,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
description: context.l10n.summary_streamed_overall,
color: Colors.blue,
onTap: () {
context.pushRoute(const StatsStreamsRoute());
context.navigateTo(const StatsStreamsRoute());
},
),
SummaryCard.unformatted(
@ -63,7 +63,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
description: context.l10n.summary_owed_to_artists,
color: Colors.green,
onTap: () {
context.pushRoute(const StatsStreamsRoute());
context.navigateTo(const StatsStreamsRoute());
},
),
SummaryCard(
@ -72,7 +72,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
description: context.l10n.summary_music_reached_you,
color: Colors.yellow,
onTap: () {
context.pushRoute(const StatsArtistsRoute());
context.navigateTo(const StatsArtistsRoute());
},
),
SummaryCard(
@ -81,7 +81,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
description: context.l10n.summary_got_your_love,
color: Colors.pink,
onTap: () {
context.pushRoute(const StatsAlbumsRoute());
context.navigateTo(const StatsAlbumsRoute());
},
),
SummaryCard(
@ -90,7 +90,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
description: context.l10n.summary_were_on_repeat,
color: Colors.teal,
onTap: () {
context.pushRoute(const StatsPlaylistsRoute());
context.navigateTo(const StatsPlaylistsRoute());
},
),
]),

View File

@ -72,7 +72,7 @@ class ConnectPage extends HookConsumerWidget {
: null,
onPressed: () {
if (selected) {
context.pushRoute(const ConnectControlRoute());
context.navigateTo(const ConnectControlRoute());
} else {
connectClientsNotifier.resolveService(device);
}

View File

@ -115,7 +115,7 @@ class ConnectControlPage extends HookConsumerWidget {
style: typography.h4,
onTap: () {
if (playlist.activeTrack == null) return;
context.pushRoute(
context.navigateTo(
TrackRoute(
trackId: playlist.activeTrack!.id!),
);
@ -127,7 +127,7 @@ class ConnectControlPage extends HookConsumerWidget {
artists: playlist.activeTrack?.artists ?? [],
textStyle: typography.normal,
mainAxisAlignment: WrapAlignment.start,
onOverflowArtistClick: () => context.pushRoute(
onOverflowArtistClick: () => context.navigateTo(
TrackRoute(trackId: playlist.activeTrack!.id!),
),
),

View File

@ -51,7 +51,7 @@ class GenrePage extends HookConsumerWidget {
final gradient = gradients[Random().nextInt(gradients.length)];
return CardImage(
onPressed: () {
context.pushRoute(
context.navigateTo(
GenrePlaylistsRoute(
id: category.id!,
category: category,

View File

@ -54,7 +54,7 @@ class HomePage extends HookConsumerWidget {
IconButton.ghost(
icon: const Icon(SpotubeIcons.settings, size: 20),
onPressed: () {
context.pushRoute(const SettingsRoute());
context.navigateTo(const SettingsRoute());
},
),
const Gap(10),

View File

@ -24,6 +24,7 @@ class LibraryPage extends HookConsumerWidget {
...getSidebarLibraryTileList(context.l10n),
SideBarTiles(
id: "downloads",
pathPrefix: "library/downloads",
title: context.l10n.downloads,
route: const UserDownloadsRoute(),
icon: SpotubeIcons.download,
@ -32,42 +33,48 @@ class LibraryPage extends HookConsumerWidget {
[context.l10n],
);
final index = sidebarLibraryTileList.indexWhere(
(e) => router.topRoute.name == e.route.routeName,
(e) => router.currentPath.startsWith(e.pathPrefix),
);
return SafeArea(
bottom: false,
child: LayoutBuilder(builder: (context, constraints) {
return Scaffold(
headers: [
if (constraints.smAndDown)
TitleBar(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: TabList(
index: index,
children: [
for (final tile in sidebarLibraryTileList)
TabButton(
child: Badge(
isLabelVisible:
tile.id == 'downloads' && downloadingCount > 0,
label: Text(downloadingCount.toString()),
child: Text(tile.title),
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) {
context.navigateTo(const HomeRoute());
},
child: SafeArea(
bottom: false,
child: LayoutBuilder(builder: (context, constraints) {
return Scaffold(
headers: [
if (constraints.smAndDown)
TitleBar(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: TabList(
index: index,
children: [
for (final tile in sidebarLibraryTileList)
TabButton(
child: Badge(
isLabelVisible: tile.id == 'downloads' &&
downloadingCount > 0,
label: Text(downloadingCount.toString()),
child: Text(tile.title),
),
onPressed: () {
context.navigateTo(tile.route);
},
),
onPressed: () {
context.navigateTo(tile.route);
},
),
],
],
),
),
),
),
const Gap(10),
],
child: const AutoRouter(),
);
}),
const Gap(10),
],
child: const AutoRouter(),
);
}),
),
);
}
}

View File

@ -663,7 +663,7 @@ class PlaylistGeneratorPage extends HookConsumerWidget {
min: min.value,
target: target.value,
);
context.pushRoute(
context.navigateTo(
PlaylistGenerateResultRoute(
state: routeState,
),

View File

@ -114,7 +114,7 @@ class UserPlaylistsPage extends HookConsumerWidget {
leading: const Icon(SpotubeIcons.magic),
child: Text(context.l10n.generate),
onPressed: () {
context.pushRoute(const PlaylistGeneratorRoute());
context.navigateTo(const PlaylistGeneratorRoute());
},
),
const Gap(10),

View File

@ -21,7 +21,7 @@ Future<void> Function() useLoginCallback(WidgetRef ref) {
return useCallback(() async {
if (kIsMobile || kIsMacOS) {
context.pushRoute(const WebViewLoginRoute());
context.navigateTo(const WebViewLoginRoute());
return;
}

View File

@ -3,18 +3,13 @@ import 'package:flutter/services.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/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/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/provider/glance/glance.dart';
import 'package:spotube/utils/platform.dart';
@RoutePage()
class RootAppPage extends HookConsumerWidget {
@ -42,10 +37,6 @@ class RootAppPage extends HookConsumerWidget {
return null;
}, [backgroundColor, brightness]);
final navTileNames = useMemoized(() {
return getSidebarTileList(context.l10n).map((s) => s.route).toList();
}, []);
final scaffold = MediaQuery.removeViewInsets(
context: context,
removeBottom: true,
@ -59,25 +50,6 @@ class RootAppPage extends HookConsumerWidget {
),
);
if (!kIsAndroid) {
return scaffold;
}
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.path == const HomeRoute().fragment) {
SystemNavigator.pop();
} else {
context.navigateTo(const HomeRoute());
}
},
child: scaffold,
);
return scaffold;
}
}

View File

@ -6,6 +6,7 @@ import 'package:spotify/spotify.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:fuzzywuzzy/fuzzywuzzy.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/collections/routes.gr.dart';
import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart';
@ -68,165 +69,174 @@ class SearchPage extends HookConsumerWidget {
);
}
return SafeArea(
bottom: false,
child: Scaffold(
headers: [
if (kTitlebarVisible)
const TitleBar(automaticallyImplyLeading: true, height: 30)
],
child: auth.asData?.value == null
? const AnonymousFallback()
: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(20),
child: ListenableBuilder(
listenable: controller,
builder: (context, _) {
final suggestions = controller.text.isEmpty
? KVStoreService.recentSearches
: KVStoreService.recentSearches
.where(
(s) =>
weightedRatio(
s.toLowerCase(),
controller.text.toLowerCase(),
) >
50,
)
.toList();
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) {
context.navigateTo(const HomeRoute());
},
child: SafeArea(
bottom: false,
child: Scaffold(
headers: [
if (kTitlebarVisible)
const TitleBar(automaticallyImplyLeading: true, height: 30)
],
child: auth.asData?.value == null
? const AnonymousFallback()
: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(20),
child: ListenableBuilder(
listenable: controller,
builder: (context, _) {
final suggestions = controller.text.isEmpty
? KVStoreService.recentSearches
: KVStoreService.recentSearches
.where(
(s) =>
weightedRatio(
s.toLowerCase(),
controller.text.toLowerCase(),
) >
50,
)
.toList();
return KeyboardListener(
focusNode: focusNode,
autofocus: true,
onKeyEvent: (value) {
final isEnter = value.logicalKey ==
LogicalKeyboardKey.enter;
if (isEnter) {
onSubmitted(controller.text);
focusNode.unfocus();
}
},
child: AutoComplete(
return KeyboardListener(
focusNode: focusNode,
autofocus: true,
controller: controller,
suggestions: suggestions,
leading: const Icon(SpotubeIcons.search),
textInputAction: TextInputAction.search,
placeholder: Text(context.l10n.search),
trailing: AnimatedCrossFade(
duration:
const Duration(milliseconds: 300),
crossFadeState: controller.text.isNotEmpty
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
firstChild: IconButton.ghost(
size: ButtonSize.small,
icon: const Icon(SpotubeIcons.close),
onPressed: () {
controller.clear();
},
),
secondChild:
const SizedBox.square(dimension: 28),
),
onAcceptSuggestion: (index) {
controller.text =
KVStoreService.recentSearches[index];
ref
.read(searchTermStateProvider
.notifier)
.state =
KVStoreService.recentSearches[index];
onKeyEvent: (value) {
final isEnter = value.logicalKey ==
LogicalKeyboardKey.enter;
if (isEnter) {
onSubmitted(controller.text);
focusNode.unfocus();
}
},
onChanged: (value) {},
onSubmitted: onSubmitted,
),
);
}),
),
),
],
),
Expanded(
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: switch ((searchTerm.isEmpty, isFetching)) {
(true, false) => Column(
children: [
SizedBox(
height: mediaQuery.height * 0.2,
),
Undraw(
illustration: UndrawIllustration.explore,
color: theme.colorScheme.primary,
height: 200 * theme.scaling,
),
const SizedBox(height: 20),
Text(context.l10n.search_to_get_results).large(),
],
child: AutoComplete(
autofocus: true,
controller: controller,
suggestions: suggestions,
leading: const Icon(SpotubeIcons.search),
textInputAction: TextInputAction.search,
placeholder: Text(context.l10n.search),
trailing: AnimatedCrossFade(
duration:
const Duration(milliseconds: 300),
crossFadeState:
controller.text.isNotEmpty
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
firstChild: IconButton.ghost(
size: ButtonSize.small,
icon: const Icon(SpotubeIcons.close),
onPressed: () {
controller.clear();
},
),
secondChild: const SizedBox.square(
dimension: 28),
),
onAcceptSuggestion: (index) {
controller.text = KVStoreService
.recentSearches[index];
ref
.read(searchTermStateProvider
.notifier)
.state =
KVStoreService
.recentSearches[index];
},
onChanged: (value) {},
onSubmitted: onSubmitted,
),
);
}),
),
(false, true) => Container(
constraints: BoxConstraints(
maxWidth: mediaQuery.lgAndUp
? mediaQuery.width * 0.5
: mediaQuery.width,
),
padding: const EdgeInsets.symmetric(
horizontal: 20,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
),
],
),
Expanded(
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: switch ((searchTerm.isEmpty, isFetching)) {
(true, false) => Column(
children: [
Text(
context.l10n.crunching_results,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w900,
color: theme.colorScheme.foreground
.withOpacity(0.7),
),
SizedBox(
height: mediaQuery.height * 0.2,
),
Undraw(
illustration: UndrawIllustration.explore,
color: theme.colorScheme.primary,
height: 200 * theme.scaling,
),
const SizedBox(height: 20),
const LinearProgressIndicator(),
Text(context.l10n.search_to_get_results)
.large(),
],
),
),
_ => InterScrollbar(
controller: scrollController,
child: SingleChildScrollView(
(false, true) => Container(
constraints: BoxConstraints(
maxWidth: mediaQuery.lgAndUp
? mediaQuery.width * 0.5
: mediaQuery.width,
),
padding: const EdgeInsets.symmetric(
horizontal: 20,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
context.l10n.crunching_results,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w900,
color: theme.colorScheme.foreground
.withOpacity(0.7),
),
),
const SizedBox(height: 20),
const LinearProgressIndicator(),
],
),
),
_ => InterScrollbar(
controller: scrollController,
child: const Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: SafeArea(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
SearchTracksSection(),
SearchPlaylistsSection(),
Gap(20),
SearchArtistsSection(),
Gap(20),
SearchAlbumsSection(),
],
child: SingleChildScrollView(
controller: scrollController,
child: const Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: SafeArea(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
SearchTracksSection(),
SearchPlaylistsSection(),
Gap(20),
SearchArtistsSection(),
Gap(20),
SearchAlbumsSection(),
],
),
),
),
),
),
),
},
},
),
),
),
],
),
],
),
),
),
);
}

View File

@ -90,7 +90,7 @@ class SettingsAboutSection extends HookConsumerWidget {
title: Text(context.l10n.about_spotube),
trailing: const Icon(SpotubeIcons.angleRight),
onTap: () {
context.pushRoute(const AboutSpotubeRoute());
context.navigateTo(const AboutSpotubeRoute());
},
)
],

View File

@ -49,7 +49,7 @@ class SettingsAccountSection extends HookConsumerWidget {
),
),
onTap: () {
context.pushRoute(ProfileRoute());
context.navigateTo(ProfileRoute());
},
),
if (auth.asData?.value == null)
@ -112,7 +112,7 @@ class SettingsAccountSection extends HookConsumerWidget {
trailing: Button.secondary(
leading: const Icon(SpotubeIcons.lastFm),
onPressed: () {
context.pushRoute(const LastFMLoginRoute());
context.navigateTo(const LastFMLoginRoute());
},
child: Text(context.l10n.connect),
),

View File

@ -21,7 +21,7 @@ class SettingsDevelopersSection extends HookWidget {
title: Text(context.l10n.logs),
trailing: const Icon(SpotubeIcons.angleRight),
onTap: () {
context.pushRoute(const LogsRoute());
context.navigateTo(const LogsRoute());
},
)
],

View File

@ -268,7 +268,7 @@ class SettingsPlaybackSection extends HookConsumerWidget {
title: Text(context.l10n.blacklist),
subtitle: Text(context.l10n.blacklist_description),
onTap: () {
context.pushRoute(const BlackListRoute());
context.navigateTo(const BlackListRoute());
},
trailing: const Icon(SpotubeIcons.angleRight),
),

View File

@ -1,5 +1,6 @@
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/titlebar/titlebar.dart';
import 'package:spotube/modules/stats/summary/summary.dart';
import 'package:spotube/modules/stats/top/top.dart';
@ -14,23 +15,29 @@ class StatsPage extends HookConsumerWidget {
@override
Widget build(BuildContext context, ref) {
return SafeArea(
bottom: false,
child: Scaffold(
headers: [
if (kTitlebarVisible) const TitleBar(),
],
child: CustomScrollView(
slivers: [
if (kIsMacOS) const SliverGap(20),
const StatsPageSummarySection(),
const StatsPageTopSection(),
const SliverToBoxAdapter(
child: SafeArea(
child: SizedBox(),
),
)
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, result) {
context.navigateTo(const HomeRoute());
},
child: SafeArea(
bottom: false,
child: Scaffold(
headers: [
if (kTitlebarVisible) const TitleBar(),
],
child: CustomScrollView(
slivers: [
if (kIsMacOS) const SliverGap(20),
const StatsPageSummarySection(),
const StatsPageTopSection(),
const SliverToBoxAdapter(
child: SafeArea(
child: SizedBox(),
),
)
],
),
),
),
);