mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
chore: use navigateTo instead of pushRoute
This commit is contained in:
parent
0037677383
commit
4b2d259add
@ -37,7 +37,7 @@ class AppRouter extends RootStackRouter {
|
|||||||
initial: true,
|
initial: true,
|
||||||
children: [
|
children: [
|
||||||
AutoRoute(
|
AutoRoute(
|
||||||
path: "browse",
|
path: "home",
|
||||||
page: HomeRoute.page,
|
page: HomeRoute.page,
|
||||||
initial: true,
|
initial: true,
|
||||||
),
|
),
|
||||||
@ -70,7 +70,7 @@ class AppRouter extends RootStackRouter {
|
|||||||
page: UserArtistsRoute.page,
|
page: UserArtistsRoute.page,
|
||||||
),
|
),
|
||||||
AutoRoute(
|
AutoRoute(
|
||||||
path: "album",
|
path: "albums",
|
||||||
page: UserAlbumsRoute.page,
|
page: UserAlbumsRoute.page,
|
||||||
),
|
),
|
||||||
AutoRoute(
|
AutoRoute(
|
||||||
|
@ -8,6 +8,7 @@ class SideBarTiles {
|
|||||||
final IconData icon;
|
final IconData icon;
|
||||||
final String title;
|
final String title;
|
||||||
final String id;
|
final String id;
|
||||||
|
final String pathPrefix;
|
||||||
final PageRouteInfo route;
|
final PageRouteInfo route;
|
||||||
|
|
||||||
SideBarTiles({
|
SideBarTiles({
|
||||||
@ -15,30 +16,35 @@ class SideBarTiles {
|
|||||||
required this.title,
|
required this.title,
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.route,
|
required this.route,
|
||||||
|
required this.pathPrefix,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SideBarTiles> getSidebarTileList(AppLocalizations l10n) => [
|
List<SideBarTiles> getSidebarTileList(AppLocalizations l10n) => [
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "browse",
|
id: "home",
|
||||||
|
pathPrefix: "/home",
|
||||||
route: const HomeRoute(),
|
route: const HomeRoute(),
|
||||||
icon: SpotubeIcons.home,
|
icon: SpotubeIcons.home,
|
||||||
title: l10n.browse,
|
title: l10n.browse,
|
||||||
),
|
),
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "search",
|
id: "search",
|
||||||
|
pathPrefix: "/search",
|
||||||
route: const SearchRoute(),
|
route: const SearchRoute(),
|
||||||
icon: SpotubeIcons.search,
|
icon: SpotubeIcons.search,
|
||||||
title: l10n.search,
|
title: l10n.search,
|
||||||
),
|
),
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "lyrics",
|
id: "lyrics",
|
||||||
|
pathPrefix: "/lyrics",
|
||||||
route: LyricsRoute(),
|
route: LyricsRoute(),
|
||||||
icon: SpotubeIcons.music,
|
icon: SpotubeIcons.music,
|
||||||
title: l10n.lyrics,
|
title: l10n.lyrics,
|
||||||
),
|
),
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "stats",
|
id: "stats",
|
||||||
|
pathPrefix: "/stats",
|
||||||
route: const StatsRoute(),
|
route: const StatsRoute(),
|
||||||
icon: SpotubeIcons.chart,
|
icon: SpotubeIcons.chart,
|
||||||
title: l10n.stats,
|
title: l10n.stats,
|
||||||
@ -48,24 +54,28 @@ List<SideBarTiles> getSidebarTileList(AppLocalizations l10n) => [
|
|||||||
List<SideBarTiles> getSidebarLibraryTileList(AppLocalizations l10n) => [
|
List<SideBarTiles> getSidebarLibraryTileList(AppLocalizations l10n) => [
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "playlists",
|
id: "playlists",
|
||||||
|
pathPrefix: "/library/playlists",
|
||||||
title: l10n.playlists,
|
title: l10n.playlists,
|
||||||
route: const UserPlaylistsRoute(),
|
route: const UserPlaylistsRoute(),
|
||||||
icon: SpotubeIcons.playlist,
|
icon: SpotubeIcons.playlist,
|
||||||
),
|
),
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "artists",
|
id: "artists",
|
||||||
|
pathPrefix: "/library/artists",
|
||||||
title: l10n.artists,
|
title: l10n.artists,
|
||||||
route: const UserArtistsRoute(),
|
route: const UserArtistsRoute(),
|
||||||
icon: SpotubeIcons.artist,
|
icon: SpotubeIcons.artist,
|
||||||
),
|
),
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "albums",
|
id: "albums",
|
||||||
|
pathPrefix: "/library/albums",
|
||||||
title: l10n.albums,
|
title: l10n.albums,
|
||||||
route: const UserAlbumsRoute(),
|
route: const UserAlbumsRoute(),
|
||||||
icon: SpotubeIcons.album,
|
icon: SpotubeIcons.album,
|
||||||
),
|
),
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "local_library",
|
id: "local_library",
|
||||||
|
pathPrefix: "/library/local",
|
||||||
title: l10n.local_library,
|
title: l10n.local_library,
|
||||||
route: const UserLocalLibraryRoute(),
|
route: const UserLocalLibraryRoute(),
|
||||||
icon: SpotubeIcons.device,
|
icon: SpotubeIcons.device,
|
||||||
@ -74,25 +84,29 @@ List<SideBarTiles> getSidebarLibraryTileList(AppLocalizations l10n) => [
|
|||||||
|
|
||||||
List<SideBarTiles> getNavbarTileList(AppLocalizations l10n) => [
|
List<SideBarTiles> getNavbarTileList(AppLocalizations l10n) => [
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "browse",
|
id: "home",
|
||||||
|
pathPrefix: "/home",
|
||||||
route: const HomeRoute(),
|
route: const HomeRoute(),
|
||||||
icon: SpotubeIcons.home,
|
icon: SpotubeIcons.home,
|
||||||
title: l10n.browse,
|
title: l10n.browse,
|
||||||
),
|
),
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "search",
|
id: "search",
|
||||||
|
pathPrefix: "/search",
|
||||||
route: const SearchRoute(),
|
route: const SearchRoute(),
|
||||||
icon: SpotubeIcons.search,
|
icon: SpotubeIcons.search,
|
||||||
title: l10n.search,
|
title: l10n.search,
|
||||||
),
|
),
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "library",
|
id: "library",
|
||||||
|
pathPrefix: "/library",
|
||||||
route: const UserPlaylistsRoute(),
|
route: const UserPlaylistsRoute(),
|
||||||
icon: SpotubeIcons.library,
|
icon: SpotubeIcons.library,
|
||||||
title: l10n.library,
|
title: l10n.library,
|
||||||
),
|
),
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "stats",
|
id: "stats",
|
||||||
|
pathPrefix: "/stats",
|
||||||
route: const StatsRoute(),
|
route: const StatsRoute(),
|
||||||
icon: SpotubeIcons.chart,
|
icon: SpotubeIcons.chart,
|
||||||
title: l10n.stats,
|
title: l10n.stats,
|
||||||
|
@ -40,7 +40,7 @@ class AnonymousFallback extends ConsumerWidget {
|
|||||||
Text(context.l10n.not_logged_in),
|
Text(context.l10n.not_logged_in),
|
||||||
Button.primary(
|
Button.primary(
|
||||||
child: Text(context.l10n.login_with_spotify),
|
child: Text(context.l10n.login_with_spotify),
|
||||||
onPressed: () => context.pushRoute(const SettingsRoute()),
|
onPressed: () => context.navigateTo(const SettingsRoute()),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -50,7 +50,7 @@ class ArtistLink extends StatelessWidget {
|
|||||||
onRouteChange?.call("/artist/${artist.value.id}");
|
onRouteChange?.call("/artist/${artist.value.id}");
|
||||||
} else {
|
} else {
|
||||||
context
|
context
|
||||||
.pushRoute(ArtistRoute(artistId: artist.value.id!));
|
.navigateTo(ArtistRoute(artistId: artist.value.id!));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
@ -28,7 +28,7 @@ class LinkText<T> extends StatelessWidget {
|
|||||||
text,
|
text,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (push) {
|
if (push) {
|
||||||
context.pushRoute(route);
|
context.navigateTo(route);
|
||||||
} else {
|
} else {
|
||||||
context.navigateTo(route);
|
context.navigateTo(route);
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ class TrackOptions extends HookConsumerWidget {
|
|||||||
onSelected: (value) async {
|
onSelected: (value) async {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case TrackOptionValue.album:
|
case TrackOptionValue.album:
|
||||||
await context.pushRoute(
|
await context.navigateTo(
|
||||||
AlbumRoute(id: track.album!.id!, album: track.album!),
|
AlbumRoute(id: track.album!.id!, album: track.album!),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@ -345,7 +345,7 @@ class TrackOptions extends HookConsumerWidget {
|
|||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: ArtistLink(
|
child: ArtistLink(
|
||||||
artists: track.artists!,
|
artists: track.artists!,
|
||||||
onOverflowArtistClick: () => context.pushRoute(
|
onOverflowArtistClick: () => context.navigateTo(
|
||||||
TrackRoute(trackId: track.id!),
|
TrackRoute(trackId: track.id!),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -234,7 +234,7 @@ class TrackTile extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context
|
context
|
||||||
.pushRoute(TrackRoute(trackId: track.id!));
|
.navigateTo(TrackRoute(trackId: track.id!));
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
track.name!,
|
track.name!,
|
||||||
@ -284,7 +284,7 @@ class TrackTile extends HookConsumerWidget {
|
|||||||
child: ArtistLink(
|
child: ArtistLink(
|
||||||
artists: track.artists ?? [],
|
artists: track.artists ?? [],
|
||||||
onOverflowArtistClick: () {
|
onOverflowArtistClick: () {
|
||||||
context.pushRoute(
|
context.navigateTo(
|
||||||
TrackRoute(trackId: track.id!),
|
TrackRoute(trackId: track.id!),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -28,19 +28,20 @@ void useDeepLinking(WidgetRef ref, AppRouter router) {
|
|||||||
switch (url.pathSegments.first) {
|
switch (url.pathSegments.first) {
|
||||||
case "album":
|
case "album":
|
||||||
final album = await spotify.albums.get(url.pathSegments.last);
|
final album = await spotify.albums.get(url.pathSegments.last);
|
||||||
router.push(
|
router.navigate(
|
||||||
AlbumRoute(id: album.id!, album: album),
|
AlbumRoute(id: album.id!, album: album),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "artist":
|
case "artist":
|
||||||
router.push(ArtistRoute(artistId: url.pathSegments.last));
|
router.navigate(ArtistRoute(artistId: url.pathSegments.last));
|
||||||
break;
|
break;
|
||||||
case "playlist":
|
case "playlist":
|
||||||
final playlist = await spotify.playlists.get(url.pathSegments.last);
|
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;
|
break;
|
||||||
case "track":
|
case "track":
|
||||||
router.push(TrackRoute(trackId: url.pathSegments.last));
|
router.navigate(TrackRoute(trackId: url.pathSegments.last));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -65,19 +66,19 @@ void useDeepLinking(WidgetRef ref, AppRouter router) {
|
|||||||
switch (startSegment) {
|
switch (startSegment) {
|
||||||
case "spotify:album":
|
case "spotify:album":
|
||||||
final album = await spotify.albums.get(endSegment);
|
final album = await spotify.albums.get(endSegment);
|
||||||
await router.push(
|
await router.navigate(
|
||||||
AlbumRoute(id: album.id!, album: album),
|
AlbumRoute(id: album.id!, album: album),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "spotify:artist":
|
case "spotify:artist":
|
||||||
await router.push(ArtistRoute(artistId: endSegment));
|
await router.navigate(ArtistRoute(artistId: endSegment));
|
||||||
break;
|
break;
|
||||||
case "spotify:track":
|
case "spotify:track":
|
||||||
await router.push(TrackRoute(trackId: endSegment));
|
await router.navigate(TrackRoute(trackId: endSegment));
|
||||||
break;
|
break;
|
||||||
case "spotify:playlist":
|
case "spotify:playlist":
|
||||||
final playlist = await spotify.playlists.get(endSegment);
|
final playlist = await spotify.playlists.get(endSegment);
|
||||||
await router.push(
|
await router.navigate(
|
||||||
PlaylistRoute(id: playlist.id!, playlist: playlist),
|
PlaylistRoute(id: playlist.id!, playlist: playlist),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
@ -69,7 +69,7 @@ class AlbumCard extends HookConsumerWidget {
|
|||||||
"${album.albumType?.formatted} • ${album.artists?.asString() ?? ""}";
|
"${album.albumType?.formatted} • ${album.artists?.asString() ?? ""}";
|
||||||
|
|
||||||
void onTap() {
|
void onTap() {
|
||||||
context.pushRoute(AlbumRoute(id: album.id!, album: album));
|
context.navigateTo(AlbumRoute(id: album.id!, album: album));
|
||||||
}
|
}
|
||||||
|
|
||||||
void onPlaybuttonPressed() async {
|
void onPlaybuttonPressed() async {
|
||||||
|
@ -36,7 +36,7 @@ class ArtistCard extends HookConsumerWidget {
|
|||||||
width: 180,
|
width: 180,
|
||||||
child: Button.card(
|
child: Button.card(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(ArtistRoute(artistId: artist.id!));
|
context.navigateTo(ArtistRoute(artistId: artist.id!));
|
||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
@ -26,7 +26,7 @@ class ConnectDeviceButton extends HookConsumerWidget {
|
|||||||
return IconButton.ghost(
|
return IconButton.ghost(
|
||||||
icon: const Icon(SpotubeIcons.speaker),
|
icon: const Icon(SpotubeIcons.speaker),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(const ConnectRoute());
|
context.navigateTo(const ConnectRoute());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -35,7 +35,7 @@ class ConnectDeviceButton extends HookConsumerWidget {
|
|||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: Button.primary(
|
child: Button.primary(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(const ConnectRoute());
|
context.navigateTo(const ConnectRoute());
|
||||||
},
|
},
|
||||||
trailing: const Icon(SpotubeIcons.speaker),
|
trailing: const Icon(SpotubeIcons.speaker),
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -50,7 +50,7 @@ class ConnectDeviceButton extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
SecondaryBadge(
|
SecondaryBadge(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(const ConnectRoute());
|
context.navigateTo(const ConnectRoute());
|
||||||
},
|
},
|
||||||
style: const ButtonStyle.secondary(size: ButtonSize(.8)),
|
style: const ButtonStyle.secondary(size: ButtonSize(.8)),
|
||||||
leading: connectClients.asData?.value.resolvedService != null
|
leading: connectClients.asData?.value.resolvedService != null
|
||||||
@ -70,7 +70,7 @@ class ConnectDeviceButton extends HookConsumerWidget {
|
|||||||
IconButton.primary(
|
IconButton.primary(
|
||||||
icon: const Icon(SpotubeIcons.speaker),
|
icon: const Icon(SpotubeIcons.speaker),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(const ConnectRoute());
|
context.navigateTo(const ConnectRoute());
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -40,7 +40,7 @@ class HomePageFeedSection extends HookConsumerWidget {
|
|||||||
titleTrailing: Button.text(
|
titleTrailing: Button.text(
|
||||||
child: Text(context.l10n.browse_all),
|
child: Text(context.l10n.browse_all),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(HomeFeedSectionRoute(sectionUri: section.uri));
|
context.navigateTo(HomeFeedSectionRoute(sectionUri: section.uri));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -50,7 +50,7 @@ class FriendItem extends HookConsumerWidget {
|
|||||||
recognizer: TapGestureRecognizer()
|
recognizer: TapGestureRecognizer()
|
||||||
..onTap = () {
|
..onTap = () {
|
||||||
context
|
context
|
||||||
.pushRoute(TrackRoute(trackId: friend.track.id));
|
.navigateTo(TrackRoute(trackId: friend.track.id));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const TextSpan(text: " • "),
|
const TextSpan(text: " • "),
|
||||||
@ -64,7 +64,7 @@ class FriendItem extends HookConsumerWidget {
|
|||||||
text: " ${friend.track.artist.name}",
|
text: " ${friend.track.artist.name}",
|
||||||
recognizer: TapGestureRecognizer()
|
recognizer: TapGestureRecognizer()
|
||||||
..onTap = () {
|
..onTap = () {
|
||||||
context.pushRoute(
|
context.navigateTo(
|
||||||
ArtistRoute(artistId: friend.track.artist.id),
|
ArtistRoute(artistId: friend.track.artist.id),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -74,7 +74,7 @@ class FriendItem extends HookConsumerWidget {
|
|||||||
text: friend.track.context.name,
|
text: friend.track.context.name,
|
||||||
recognizer: TapGestureRecognizer()
|
recognizer: TapGestureRecognizer()
|
||||||
..onTap = () async {
|
..onTap = () async {
|
||||||
context.router.pushNamed(
|
context.router.navigateNamed(
|
||||||
"/${friend.track.context.path}",
|
"/${friend.track.context.path}",
|
||||||
// extra:
|
// extra:
|
||||||
// !friend.track.context.path.startsWith("album")
|
// !friend.track.context.path.startsWith("album")
|
||||||
@ -98,7 +98,7 @@ class FriendItem extends HookConsumerWidget {
|
|||||||
final album =
|
final album =
|
||||||
await spotify.albums.get(friend.track.album.id);
|
await spotify.albums.get(friend.track.album.id);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.pushRoute(
|
context.navigateTo(
|
||||||
AlbumRoute(id: album.id!, album: album),
|
AlbumRoute(id: album.id!, album: album),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ class GenreSectionCard extends HookConsumerWidget {
|
|||||||
).h3(),
|
).h3(),
|
||||||
Button.link(
|
Button.link(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.router.push(
|
context.navigateTo(
|
||||||
GenrePlaylistsRoute(
|
GenrePlaylistsRoute(
|
||||||
id: category.id!,
|
id: category.id!,
|
||||||
category: category,
|
category: category,
|
||||||
|
@ -47,7 +47,7 @@ class GenreSectionCardPlaylistCard extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(
|
context.navigateTo(
|
||||||
PlaylistRoute(id: playlist.id!, playlist: playlist),
|
PlaylistRoute(id: playlist.id!, playlist: playlist),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -48,7 +48,7 @@ class HomeGenresSection extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
Button.link(
|
Button.link(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(const GenreRoute());
|
context.navigateTo(const GenreRoute());
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
context.l10n.browse_all,
|
context.l10n.browse_all,
|
||||||
|
@ -59,7 +59,7 @@ class LocalFolderItem extends HookConsumerWidget {
|
|||||||
|
|
||||||
return Button(
|
return Button(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(
|
context.navigateTo(
|
||||||
LocalLibraryRoute(
|
LocalLibraryRoute(
|
||||||
location: folder,
|
location: folder,
|
||||||
isCache: isCacheFolder,
|
isCache: isCacheFolder,
|
||||||
|
@ -67,7 +67,7 @@ class DownloadItem extends HookConsumerWidget {
|
|||||||
artists: track.artists ?? <Artist>[],
|
artists: track.artists ?? <Artist>[],
|
||||||
mainAxisAlignment: WrapAlignment.start,
|
mainAxisAlignment: WrapAlignment.start,
|
||||||
onOverflowArtistClick: () {
|
onOverflowArtistClick: () {
|
||||||
context.pushRoute(TrackRoute(trackId: track.id!));
|
context.navigateTo(TrackRoute(trackId: track.id!));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
trailing: isQueryingSourceInfo
|
trailing: isQueryingSourceInfo
|
||||||
|
@ -93,7 +93,7 @@ class PlayerView extends HookConsumerWidget {
|
|||||||
}, [panelController.isAttached && panelController.isPanelOpen]);
|
}, [panelController.isAttached && panelController.isPanelOpen]);
|
||||||
|
|
||||||
return AppPopScope(
|
return AppPopScope(
|
||||||
canPop: context.watchRouter.canPop(),
|
canPop: false,
|
||||||
onPopInvoked: (didPop) async {
|
onPopInvoked: (didPop) async {
|
||||||
await panelController.close();
|
await panelController.close();
|
||||||
},
|
},
|
||||||
@ -209,9 +209,9 @@ class PlayerView extends HookConsumerWidget {
|
|||||||
.copyWith(fontWeight: FontWeight.bold),
|
.copyWith(fontWeight: FontWeight.bold),
|
||||||
onRouteChange: (route) {
|
onRouteChange: (route) {
|
||||||
panelController.close();
|
panelController.close();
|
||||||
context.router.pushNamed(route);
|
context.router.navigateNamed(route);
|
||||||
},
|
},
|
||||||
onOverflowArtistClick: () => context.pushRoute(
|
onOverflowArtistClick: () => context.navigateTo(
|
||||||
TrackRoute(trackId: currentTrack!.id!),
|
TrackRoute(trackId: currentTrack!.id!),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
import 'package:sliding_up_panel/sliding_up_panel.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/modules/player/player.dart';
|
||||||
import 'package:spotube/provider/audio_player/audio_player.dart';
|
import 'package:spotube/provider/audio_player/audio_player.dart';
|
||||||
|
|
||||||
|
final playerOverlayControllerProvider = StateProvider<PanelController>((ref) {
|
||||||
|
return PanelController();
|
||||||
|
});
|
||||||
|
|
||||||
class PlayerOverlay extends HookConsumerWidget {
|
class PlayerOverlay extends HookConsumerWidget {
|
||||||
final String albumArt;
|
final String albumArt;
|
||||||
|
|
||||||
@ -23,7 +26,7 @@ class PlayerOverlay extends HookConsumerWidget {
|
|||||||
|
|
||||||
final screenSize = MediaQuery.sizeOf(context);
|
final screenSize = MediaQuery.sizeOf(context);
|
||||||
|
|
||||||
final panelController = useMemoized(() => PanelController(), []);
|
final panelController = ref.watch(playerOverlayControllerProvider);
|
||||||
|
|
||||||
return SlidingUpPanel(
|
return SlidingUpPanel(
|
||||||
maxHeight: screenSize.height,
|
maxHeight: screenSize.height,
|
||||||
|
@ -81,10 +81,10 @@ class PlayerTrackDetails extends HookConsumerWidget {
|
|||||||
ArtistLink(
|
ArtistLink(
|
||||||
artists: playback.activeTrack?.artists ?? [],
|
artists: playback.activeTrack?.artists ?? [],
|
||||||
onRouteChange: (route) {
|
onRouteChange: (route) {
|
||||||
context.router.pushNamed(route);
|
context.router.navigateNamed(route);
|
||||||
},
|
},
|
||||||
onOverflowArtistClick: () =>
|
onOverflowArtistClick: () =>
|
||||||
context.pushRoute(TrackRoute(trackId: track!.id!)),
|
context.navigateTo(TrackRoute(trackId: track!.id!)),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -73,7 +73,7 @@ class PlaylistCard extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onTap() {
|
void onTap() {
|
||||||
context.pushRoute(PlaylistRoute(id: playlist.id!, playlist: playlist));
|
context.navigateTo(PlaylistRoute(id: playlist.id!, playlist: playlist));
|
||||||
}
|
}
|
||||||
|
|
||||||
void onPlaybuttonPressed() async {
|
void onPlaybuttonPressed() async {
|
||||||
|
@ -52,12 +52,12 @@ class Sidebar extends HookConsumerWidget {
|
|||||||
final router = context.watchRouter;
|
final router = context.watchRouter;
|
||||||
|
|
||||||
final selectedIndex = tileList.indexWhere(
|
final selectedIndex = tileList.indexWhere(
|
||||||
(e) => router.topRoute.name == e.route.routeName,
|
(e) => router.currentPath.startsWith(e.pathPrefix),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (layoutMode == LayoutMode.compact ||
|
if (layoutMode == LayoutMode.compact ||
|
||||||
(mediaQuery.smAndDown && layoutMode == LayoutMode.adaptive)) {
|
(mediaQuery.smAndDown && layoutMode == LayoutMode.adaptive)) {
|
||||||
return Scaffold(child: child);
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
final navigationButtons = [
|
final navigationButtons = [
|
||||||
|
@ -97,7 +97,7 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem {
|
|||||||
Flexible(
|
Flexible(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.pushRoute(const ProfileRoute());
|
context.navigateTo(const ProfileRoute());
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
@ -125,7 +125,7 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem {
|
|||||||
variance: ButtonVariance.ghost,
|
variance: ButtonVariance.ghost,
|
||||||
icon: const Icon(SpotubeIcons.settings),
|
icon: const Icon(SpotubeIcons.settings),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(const SettingsRoute());
|
context.navigateTo(const SettingsRoute());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -6,7 +6,6 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter_extension.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/collections/side_bar_tiles.dart';
|
||||||
import 'package:spotube/extensions/constrains.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
@ -35,23 +34,13 @@ class SpotubeNavigationBar extends HookConsumerWidget {
|
|||||||
[context.l10n],
|
[context.l10n],
|
||||||
);
|
);
|
||||||
|
|
||||||
final libraryTiles = useMemoized(
|
|
||||||
() => getSidebarLibraryTileList(context.l10n)
|
|
||||||
.map((e) => e.route.routeName)
|
|
||||||
.toList(),
|
|
||||||
[context.l10n],
|
|
||||||
);
|
|
||||||
|
|
||||||
final panelHeight = ref.watch(navigationPanelHeight);
|
final panelHeight = ref.watch(navigationPanelHeight);
|
||||||
|
|
||||||
final router = context.watchRouter;
|
final router = context.watchRouter;
|
||||||
final selectedIndex = max(
|
final selectedIndex = max(
|
||||||
0,
|
0,
|
||||||
navbarTileList.indexWhere(
|
navbarTileList.indexWhere(
|
||||||
(e) =>
|
(e) => router.currentPath.startsWith(e.pathPrefix),
|
||||||
router.topRoute.name == e.route.routeName ||
|
|
||||||
(libraryTiles.contains(router.topRoute.name) &&
|
|
||||||
e.route.routeName == LibraryRoute.name),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -37,14 +37,14 @@ class StatsAlbumItem extends StatelessWidget {
|
|||||||
artists: album.artists ?? [],
|
artists: album.artists ?? [],
|
||||||
mainAxisAlignment: WrapAlignment.start,
|
mainAxisAlignment: WrapAlignment.start,
|
||||||
onOverflowArtistClick: () =>
|
onOverflowArtistClick: () =>
|
||||||
context.pushRoute(AlbumRoute(id: album.id!, album: album)),
|
context.navigateTo(AlbumRoute(id: album.id!, album: album)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
trailing: info,
|
trailing: info,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(AlbumRoute(id: album.id!, album: album));
|
context.navigateTo(AlbumRoute(id: album.id!, album: album));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ class StatsArtistItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
trailing: info,
|
trailing: info,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(ArtistRoute(artistId: artist.id!));
|
context.navigateTo(ArtistRoute(artistId: artist.id!));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ class StatsPlaylistItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
trailing: info,
|
trailing: info,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(PlaylistRoute(id: playlist.id!, playlist: playlist));
|
context.navigateTo(PlaylistRoute(id: playlist.id!, playlist: playlist));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -35,12 +35,12 @@ class StatsTrackItem extends StatelessWidget {
|
|||||||
artists: track.artists!,
|
artists: track.artists!,
|
||||||
mainAxisAlignment: WrapAlignment.start,
|
mainAxisAlignment: WrapAlignment.start,
|
||||||
onOverflowArtistClick: () {
|
onOverflowArtistClick: () {
|
||||||
context.pushRoute(TrackRoute(trackId: track.id!));
|
context.navigateTo(TrackRoute(trackId: track.id!));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
trailing: info,
|
trailing: info,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(TrackRoute(trackId: track.id!));
|
context.navigateTo(TrackRoute(trackId: track.id!));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
|
|||||||
description: context.l10n.summary_listened_to_music,
|
description: context.l10n.summary_listened_to_music,
|
||||||
color: Colors.indigo,
|
color: Colors.indigo,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.pushRoute(const StatsMinutesRoute());
|
context.navigateTo(const StatsMinutesRoute());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SummaryCard(
|
SummaryCard(
|
||||||
@ -54,7 +54,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
|
|||||||
description: context.l10n.summary_streamed_overall,
|
description: context.l10n.summary_streamed_overall,
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.pushRoute(const StatsStreamsRoute());
|
context.navigateTo(const StatsStreamsRoute());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SummaryCard.unformatted(
|
SummaryCard.unformatted(
|
||||||
@ -63,7 +63,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
|
|||||||
description: context.l10n.summary_owed_to_artists,
|
description: context.l10n.summary_owed_to_artists,
|
||||||
color: Colors.green,
|
color: Colors.green,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.pushRoute(const StatsStreamsRoute());
|
context.navigateTo(const StatsStreamsRoute());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SummaryCard(
|
SummaryCard(
|
||||||
@ -72,7 +72,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
|
|||||||
description: context.l10n.summary_music_reached_you,
|
description: context.l10n.summary_music_reached_you,
|
||||||
color: Colors.yellow,
|
color: Colors.yellow,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.pushRoute(const StatsArtistsRoute());
|
context.navigateTo(const StatsArtistsRoute());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SummaryCard(
|
SummaryCard(
|
||||||
@ -81,7 +81,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
|
|||||||
description: context.l10n.summary_got_your_love,
|
description: context.l10n.summary_got_your_love,
|
||||||
color: Colors.pink,
|
color: Colors.pink,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.pushRoute(const StatsAlbumsRoute());
|
context.navigateTo(const StatsAlbumsRoute());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SummaryCard(
|
SummaryCard(
|
||||||
@ -90,7 +90,7 @@ class StatsPageSummarySection extends HookConsumerWidget {
|
|||||||
description: context.l10n.summary_were_on_repeat,
|
description: context.l10n.summary_were_on_repeat,
|
||||||
color: Colors.teal,
|
color: Colors.teal,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.pushRoute(const StatsPlaylistsRoute());
|
context.navigateTo(const StatsPlaylistsRoute());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
|
@ -72,7 +72,7 @@ class ConnectPage extends HookConsumerWidget {
|
|||||||
: null,
|
: null,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
context.pushRoute(const ConnectControlRoute());
|
context.navigateTo(const ConnectControlRoute());
|
||||||
} else {
|
} else {
|
||||||
connectClientsNotifier.resolveService(device);
|
connectClientsNotifier.resolveService(device);
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ class ConnectControlPage extends HookConsumerWidget {
|
|||||||
style: typography.h4,
|
style: typography.h4,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (playlist.activeTrack == null) return;
|
if (playlist.activeTrack == null) return;
|
||||||
context.pushRoute(
|
context.navigateTo(
|
||||||
TrackRoute(
|
TrackRoute(
|
||||||
trackId: playlist.activeTrack!.id!),
|
trackId: playlist.activeTrack!.id!),
|
||||||
);
|
);
|
||||||
@ -127,7 +127,7 @@ class ConnectControlPage extends HookConsumerWidget {
|
|||||||
artists: playlist.activeTrack?.artists ?? [],
|
artists: playlist.activeTrack?.artists ?? [],
|
||||||
textStyle: typography.normal,
|
textStyle: typography.normal,
|
||||||
mainAxisAlignment: WrapAlignment.start,
|
mainAxisAlignment: WrapAlignment.start,
|
||||||
onOverflowArtistClick: () => context.pushRoute(
|
onOverflowArtistClick: () => context.navigateTo(
|
||||||
TrackRoute(trackId: playlist.activeTrack!.id!),
|
TrackRoute(trackId: playlist.activeTrack!.id!),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -51,7 +51,7 @@ class GenrePage extends HookConsumerWidget {
|
|||||||
final gradient = gradients[Random().nextInt(gradients.length)];
|
final gradient = gradients[Random().nextInt(gradients.length)];
|
||||||
return CardImage(
|
return CardImage(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(
|
context.navigateTo(
|
||||||
GenrePlaylistsRoute(
|
GenrePlaylistsRoute(
|
||||||
id: category.id!,
|
id: category.id!,
|
||||||
category: category,
|
category: category,
|
||||||
|
@ -54,7 +54,7 @@ class HomePage extends HookConsumerWidget {
|
|||||||
IconButton.ghost(
|
IconButton.ghost(
|
||||||
icon: const Icon(SpotubeIcons.settings, size: 20),
|
icon: const Icon(SpotubeIcons.settings, size: 20),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(const SettingsRoute());
|
context.navigateTo(const SettingsRoute());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Gap(10),
|
const Gap(10),
|
||||||
|
@ -24,6 +24,7 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
...getSidebarLibraryTileList(context.l10n),
|
...getSidebarLibraryTileList(context.l10n),
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "downloads",
|
id: "downloads",
|
||||||
|
pathPrefix: "library/downloads",
|
||||||
title: context.l10n.downloads,
|
title: context.l10n.downloads,
|
||||||
route: const UserDownloadsRoute(),
|
route: const UserDownloadsRoute(),
|
||||||
icon: SpotubeIcons.download,
|
icon: SpotubeIcons.download,
|
||||||
@ -32,42 +33,48 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
[context.l10n],
|
[context.l10n],
|
||||||
);
|
);
|
||||||
final index = sidebarLibraryTileList.indexWhere(
|
final index = sidebarLibraryTileList.indexWhere(
|
||||||
(e) => router.topRoute.name == e.route.routeName,
|
(e) => router.currentPath.startsWith(e.pathPrefix),
|
||||||
);
|
);
|
||||||
|
|
||||||
return SafeArea(
|
return PopScope(
|
||||||
bottom: false,
|
canPop: false,
|
||||||
child: LayoutBuilder(builder: (context, constraints) {
|
onPopInvokedWithResult: (didPop, result) {
|
||||||
return Scaffold(
|
context.navigateTo(const HomeRoute());
|
||||||
headers: [
|
},
|
||||||
if (constraints.smAndDown)
|
child: SafeArea(
|
||||||
TitleBar(
|
bottom: false,
|
||||||
child: SingleChildScrollView(
|
child: LayoutBuilder(builder: (context, constraints) {
|
||||||
scrollDirection: Axis.horizontal,
|
return Scaffold(
|
||||||
child: TabList(
|
headers: [
|
||||||
index: index,
|
if (constraints.smAndDown)
|
||||||
children: [
|
TitleBar(
|
||||||
for (final tile in sidebarLibraryTileList)
|
child: SingleChildScrollView(
|
||||||
TabButton(
|
scrollDirection: Axis.horizontal,
|
||||||
child: Badge(
|
child: TabList(
|
||||||
isLabelVisible:
|
index: index,
|
||||||
tile.id == 'downloads' && downloadingCount > 0,
|
children: [
|
||||||
label: Text(downloadingCount.toString()),
|
for (final tile in sidebarLibraryTileList)
|
||||||
child: Text(tile.title),
|
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),
|
||||||
const Gap(10),
|
],
|
||||||
],
|
child: const AutoRouter(),
|
||||||
child: const AutoRouter(),
|
);
|
||||||
);
|
}),
|
||||||
}),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -663,7 +663,7 @@ class PlaylistGeneratorPage extends HookConsumerWidget {
|
|||||||
min: min.value,
|
min: min.value,
|
||||||
target: target.value,
|
target: target.value,
|
||||||
);
|
);
|
||||||
context.pushRoute(
|
context.navigateTo(
|
||||||
PlaylistGenerateResultRoute(
|
PlaylistGenerateResultRoute(
|
||||||
state: routeState,
|
state: routeState,
|
||||||
),
|
),
|
||||||
|
@ -114,7 +114,7 @@ class UserPlaylistsPage extends HookConsumerWidget {
|
|||||||
leading: const Icon(SpotubeIcons.magic),
|
leading: const Icon(SpotubeIcons.magic),
|
||||||
child: Text(context.l10n.generate),
|
child: Text(context.l10n.generate),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(const PlaylistGeneratorRoute());
|
context.navigateTo(const PlaylistGeneratorRoute());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Gap(10),
|
const Gap(10),
|
||||||
|
@ -21,7 +21,7 @@ Future<void> Function() useLoginCallback(WidgetRef ref) {
|
|||||||
|
|
||||||
return useCallback(() async {
|
return useCallback(() async {
|
||||||
if (kIsMobile || kIsMacOS) {
|
if (kIsMobile || kIsMacOS) {
|
||||||
context.pushRoute(const WebViewLoginRoute());
|
context.navigateTo(const WebViewLoginRoute());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,18 +3,13 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.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/bottom_player.dart';
|
||||||
import 'package:spotube/modules/root/sidebar/sidebar.dart';
|
import 'package:spotube/modules/root/sidebar/sidebar.dart';
|
||||||
import 'package:spotube/modules/root/spotube_navigation_bar.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/hooks/configurators/use_endless_playback.dart';
|
||||||
import 'package:spotube/modules/root/use_downloader_dialogs.dart';
|
import 'package:spotube/modules/root/use_downloader_dialogs.dart';
|
||||||
import 'package:spotube/modules/root/use_global_subscriptions.dart';
|
import 'package:spotube/modules/root/use_global_subscriptions.dart';
|
||||||
import 'package:spotube/provider/glance/glance.dart';
|
import 'package:spotube/provider/glance/glance.dart';
|
||||||
import 'package:spotube/utils/platform.dart';
|
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
class RootAppPage extends HookConsumerWidget {
|
class RootAppPage extends HookConsumerWidget {
|
||||||
@ -42,10 +37,6 @@ class RootAppPage extends HookConsumerWidget {
|
|||||||
return null;
|
return null;
|
||||||
}, [backgroundColor, brightness]);
|
}, [backgroundColor, brightness]);
|
||||||
|
|
||||||
final navTileNames = useMemoized(() {
|
|
||||||
return getSidebarTileList(context.l10n).map((s) => s.route).toList();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
final scaffold = MediaQuery.removeViewInsets(
|
final scaffold = MediaQuery.removeViewInsets(
|
||||||
context: context,
|
context: context,
|
||||||
removeBottom: true,
|
removeBottom: true,
|
||||||
@ -59,25 +50,6 @@ class RootAppPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!kIsAndroid) {
|
return scaffold;
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import 'package:spotify/spotify.dart';
|
|||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:fuzzywuzzy/fuzzywuzzy.dart';
|
import 'package:fuzzywuzzy/fuzzywuzzy.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.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/collections/spotube_icons.dart';
|
||||||
import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart';
|
import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart';
|
||||||
@ -68,165 +69,174 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SafeArea(
|
return PopScope(
|
||||||
bottom: false,
|
canPop: false,
|
||||||
child: Scaffold(
|
onPopInvokedWithResult: (didPop, result) {
|
||||||
headers: [
|
context.navigateTo(const HomeRoute());
|
||||||
if (kTitlebarVisible)
|
},
|
||||||
const TitleBar(automaticallyImplyLeading: true, height: 30)
|
child: SafeArea(
|
||||||
],
|
bottom: false,
|
||||||
child: auth.asData?.value == null
|
child: Scaffold(
|
||||||
? const AnonymousFallback()
|
headers: [
|
||||||
: Column(
|
if (kTitlebarVisible)
|
||||||
children: [
|
const TitleBar(automaticallyImplyLeading: true, height: 30)
|
||||||
Row(
|
],
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
child: auth.asData?.value == null
|
||||||
children: [
|
? const AnonymousFallback()
|
||||||
Expanded(
|
: Column(
|
||||||
child: Padding(
|
children: [
|
||||||
padding: const EdgeInsets.all(20),
|
Row(
|
||||||
child: ListenableBuilder(
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
listenable: controller,
|
children: [
|
||||||
builder: (context, _) {
|
Expanded(
|
||||||
final suggestions = controller.text.isEmpty
|
child: Padding(
|
||||||
? KVStoreService.recentSearches
|
padding: const EdgeInsets.all(20),
|
||||||
: KVStoreService.recentSearches
|
child: ListenableBuilder(
|
||||||
.where(
|
listenable: controller,
|
||||||
(s) =>
|
builder: (context, _) {
|
||||||
weightedRatio(
|
final suggestions = controller.text.isEmpty
|
||||||
s.toLowerCase(),
|
? KVStoreService.recentSearches
|
||||||
controller.text.toLowerCase(),
|
: KVStoreService.recentSearches
|
||||||
) >
|
.where(
|
||||||
50,
|
(s) =>
|
||||||
)
|
weightedRatio(
|
||||||
.toList();
|
s.toLowerCase(),
|
||||||
|
controller.text.toLowerCase(),
|
||||||
|
) >
|
||||||
|
50,
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
return KeyboardListener(
|
return KeyboardListener(
|
||||||
focusNode: focusNode,
|
focusNode: focusNode,
|
||||||
autofocus: true,
|
|
||||||
onKeyEvent: (value) {
|
|
||||||
final isEnter = value.logicalKey ==
|
|
||||||
LogicalKeyboardKey.enter;
|
|
||||||
|
|
||||||
if (isEnter) {
|
|
||||||
onSubmitted(controller.text);
|
|
||||||
focusNode.unfocus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: AutoComplete(
|
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
controller: controller,
|
onKeyEvent: (value) {
|
||||||
suggestions: suggestions,
|
final isEnter = value.logicalKey ==
|
||||||
leading: const Icon(SpotubeIcons.search),
|
LogicalKeyboardKey.enter;
|
||||||
textInputAction: TextInputAction.search,
|
|
||||||
placeholder: Text(context.l10n.search),
|
if (isEnter) {
|
||||||
trailing: AnimatedCrossFade(
|
onSubmitted(controller.text);
|
||||||
duration:
|
focusNode.unfocus();
|
||||||
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) {},
|
child: AutoComplete(
|
||||||
onSubmitted: onSubmitted,
|
autofocus: true,
|
||||||
),
|
controller: controller,
|
||||||
);
|
suggestions: suggestions,
|
||||||
}),
|
leading: const Icon(SpotubeIcons.search),
|
||||||
),
|
textInputAction: TextInputAction.search,
|
||||||
),
|
placeholder: Text(context.l10n.search),
|
||||||
],
|
trailing: AnimatedCrossFade(
|
||||||
),
|
duration:
|
||||||
Expanded(
|
const Duration(milliseconds: 300),
|
||||||
child: AnimatedSwitcher(
|
crossFadeState:
|
||||||
duration: const Duration(milliseconds: 300),
|
controller.text.isNotEmpty
|
||||||
child: switch ((searchTerm.isEmpty, isFetching)) {
|
? CrossFadeState.showFirst
|
||||||
(true, false) => Column(
|
: CrossFadeState.showSecond,
|
||||||
children: [
|
firstChild: IconButton.ghost(
|
||||||
SizedBox(
|
size: ButtonSize.small,
|
||||||
height: mediaQuery.height * 0.2,
|
icon: const Icon(SpotubeIcons.close),
|
||||||
),
|
onPressed: () {
|
||||||
Undraw(
|
controller.clear();
|
||||||
illustration: UndrawIllustration.explore,
|
},
|
||||||
color: theme.colorScheme.primary,
|
),
|
||||||
height: 200 * theme.scaling,
|
secondChild: const SizedBox.square(
|
||||||
),
|
dimension: 28),
|
||||||
const SizedBox(height: 20),
|
),
|
||||||
Text(context.l10n.search_to_get_results).large(),
|
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
|
Expanded(
|
||||||
: mediaQuery.width,
|
child: AnimatedSwitcher(
|
||||||
),
|
duration: const Duration(milliseconds: 300),
|
||||||
padding: const EdgeInsets.symmetric(
|
child: switch ((searchTerm.isEmpty, isFetching)) {
|
||||||
horizontal: 20,
|
(true, false) => Column(
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
Text(
|
SizedBox(
|
||||||
context.l10n.crunching_results,
|
height: mediaQuery.height * 0.2,
|
||||||
style: TextStyle(
|
),
|
||||||
fontSize: 20,
|
Undraw(
|
||||||
fontWeight: FontWeight.w900,
|
illustration: UndrawIllustration.explore,
|
||||||
color: theme.colorScheme.foreground
|
color: theme.colorScheme.primary,
|
||||||
.withOpacity(0.7),
|
height: 200 * theme.scaling,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const LinearProgressIndicator(),
|
Text(context.l10n.search_to_get_results)
|
||||||
|
.large(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
(false, true) => Container(
|
||||||
_ => InterScrollbar(
|
constraints: BoxConstraints(
|
||||||
controller: scrollController,
|
maxWidth: mediaQuery.lgAndUp
|
||||||
child: SingleChildScrollView(
|
? 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,
|
controller: scrollController,
|
||||||
child: const Padding(
|
child: SingleChildScrollView(
|
||||||
padding: EdgeInsets.symmetric(vertical: 8),
|
controller: scrollController,
|
||||||
child: SafeArea(
|
child: const Padding(
|
||||||
child: Column(
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
crossAxisAlignment:
|
child: SafeArea(
|
||||||
CrossAxisAlignment.start,
|
child: Column(
|
||||||
children: [
|
crossAxisAlignment:
|
||||||
SearchTracksSection(),
|
CrossAxisAlignment.start,
|
||||||
SearchPlaylistsSection(),
|
children: [
|
||||||
Gap(20),
|
SearchTracksSection(),
|
||||||
SearchArtistsSection(),
|
SearchPlaylistsSection(),
|
||||||
Gap(20),
|
Gap(20),
|
||||||
SearchAlbumsSection(),
|
SearchArtistsSection(),
|
||||||
],
|
Gap(20),
|
||||||
|
SearchAlbumsSection(),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
},
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ class SettingsAboutSection extends HookConsumerWidget {
|
|||||||
title: Text(context.l10n.about_spotube),
|
title: Text(context.l10n.about_spotube),
|
||||||
trailing: const Icon(SpotubeIcons.angleRight),
|
trailing: const Icon(SpotubeIcons.angleRight),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.pushRoute(const AboutSpotubeRoute());
|
context.navigateTo(const AboutSpotubeRoute());
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -49,7 +49,7 @@ class SettingsAccountSection extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.pushRoute(ProfileRoute());
|
context.navigateTo(ProfileRoute());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (auth.asData?.value == null)
|
if (auth.asData?.value == null)
|
||||||
@ -112,7 +112,7 @@ class SettingsAccountSection extends HookConsumerWidget {
|
|||||||
trailing: Button.secondary(
|
trailing: Button.secondary(
|
||||||
leading: const Icon(SpotubeIcons.lastFm),
|
leading: const Icon(SpotubeIcons.lastFm),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushRoute(const LastFMLoginRoute());
|
context.navigateTo(const LastFMLoginRoute());
|
||||||
},
|
},
|
||||||
child: Text(context.l10n.connect),
|
child: Text(context.l10n.connect),
|
||||||
),
|
),
|
||||||
|
@ -21,7 +21,7 @@ class SettingsDevelopersSection extends HookWidget {
|
|||||||
title: Text(context.l10n.logs),
|
title: Text(context.l10n.logs),
|
||||||
trailing: const Icon(SpotubeIcons.angleRight),
|
trailing: const Icon(SpotubeIcons.angleRight),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.pushRoute(const LogsRoute());
|
context.navigateTo(const LogsRoute());
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -268,7 +268,7 @@ class SettingsPlaybackSection extends HookConsumerWidget {
|
|||||||
title: Text(context.l10n.blacklist),
|
title: Text(context.l10n.blacklist),
|
||||||
subtitle: Text(context.l10n.blacklist_description),
|
subtitle: Text(context.l10n.blacklist_description),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.pushRoute(const BlackListRoute());
|
context.navigateTo(const BlackListRoute());
|
||||||
},
|
},
|
||||||
trailing: const Icon(SpotubeIcons.angleRight),
|
trailing: const Icon(SpotubeIcons.angleRight),
|
||||||
),
|
),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.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/components/titlebar/titlebar.dart';
|
||||||
import 'package:spotube/modules/stats/summary/summary.dart';
|
import 'package:spotube/modules/stats/summary/summary.dart';
|
||||||
import 'package:spotube/modules/stats/top/top.dart';
|
import 'package:spotube/modules/stats/top/top.dart';
|
||||||
@ -14,23 +15,29 @@ class StatsPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
return SafeArea(
|
return PopScope(
|
||||||
bottom: false,
|
canPop: false,
|
||||||
child: Scaffold(
|
onPopInvokedWithResult: (didPop, result) {
|
||||||
headers: [
|
context.navigateTo(const HomeRoute());
|
||||||
if (kTitlebarVisible) const TitleBar(),
|
},
|
||||||
],
|
child: SafeArea(
|
||||||
child: CustomScrollView(
|
bottom: false,
|
||||||
slivers: [
|
child: Scaffold(
|
||||||
if (kIsMacOS) const SliverGap(20),
|
headers: [
|
||||||
const StatsPageSummarySection(),
|
if (kTitlebarVisible) const TitleBar(),
|
||||||
const StatsPageTopSection(),
|
|
||||||
const SliverToBoxAdapter(
|
|
||||||
child: SafeArea(
|
|
||||||
child: SizedBox(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
|
child: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
if (kIsMacOS) const SliverGap(20),
|
||||||
|
const StatsPageSummarySection(),
|
||||||
|
const StatsPageTopSection(),
|
||||||
|
const SliverToBoxAdapter(
|
||||||
|
child: SafeArea(
|
||||||
|
child: SizedBox(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user