mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-12-10 09:07:29 +00:00
refactor: use route names
This commit is contained in:
parent
ddadb0edc5
commit
5f442a1ff7
@ -7,6 +7,10 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:spotube/collections/routes.dart';
|
import 'package:spotube/collections/routes.dart';
|
||||||
import 'package:spotube/components/player/player_controls.dart';
|
import 'package:spotube/components/player/player_controls.dart';
|
||||||
import 'package:spotube/models/logger.dart';
|
import 'package:spotube/models/logger.dart';
|
||||||
|
import 'package:spotube/pages/home/home.dart';
|
||||||
|
import 'package:spotube/pages/library/library.dart';
|
||||||
|
import 'package:spotube/pages/lyrics/lyrics.dart';
|
||||||
|
import 'package:spotube/pages/search/search.dart';
|
||||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||||
import 'package:spotube/services/audio_player/audio_player.dart';
|
import 'package:spotube/services/audio_player/audio_player.dart';
|
||||||
import 'package:spotube/utils/platform.dart';
|
import 'package:spotube/utils/platform.dart';
|
||||||
@ -67,16 +71,16 @@ class HomeTabAction extends Action<HomeTabIntent> {
|
|||||||
final router = intent.ref.read(routerProvider);
|
final router = intent.ref.read(routerProvider);
|
||||||
switch (intent.tab) {
|
switch (intent.tab) {
|
||||||
case HomeTabs.browse:
|
case HomeTabs.browse:
|
||||||
router.go("/");
|
router.goNamed(HomePage.name);
|
||||||
break;
|
break;
|
||||||
case HomeTabs.search:
|
case HomeTabs.search:
|
||||||
router.go("/search");
|
router.goNamed(SearchPage.name);
|
||||||
break;
|
break;
|
||||||
case HomeTabs.library:
|
case HomeTabs.library:
|
||||||
router.go("/library");
|
router.goNamed(LibraryPage.name);
|
||||||
break;
|
break;
|
||||||
case HomeTabs.lyrics:
|
case HomeTabs.lyrics:
|
||||||
router.go("/lyrics");
|
router.goNamed(LyricsPage.name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import 'package:spotube/pages/search/search.dart';
|
|||||||
import 'package:spotube/pages/settings/blacklist.dart';
|
import 'package:spotube/pages/settings/blacklist.dart';
|
||||||
import 'package:spotube/pages/settings/about.dart';
|
import 'package:spotube/pages/settings/about.dart';
|
||||||
import 'package:spotube/pages/settings/logs.dart';
|
import 'package:spotube/pages/settings/logs.dart';
|
||||||
|
import 'package:spotube/pages/stats/stats.dart';
|
||||||
import 'package:spotube/pages/track/track.dart';
|
import 'package:spotube/pages/track/track.dart';
|
||||||
import 'package:spotube/provider/authentication_provider.dart';
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
import 'package:spotube/services/kv_store/kv_store.dart';
|
import 'package:spotube/services/kv_store/kv_store.dart';
|
||||||
@ -50,6 +51,7 @@ final routerProvider = Provider((ref) {
|
|||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/",
|
path: "/",
|
||||||
|
name: HomePage.name,
|
||||||
redirect: (context, state) async {
|
redirect: (context, state) async {
|
||||||
final authNotifier = ref.read(authenticationProvider.notifier);
|
final authNotifier = ref.read(authenticationProvider.notifier);
|
||||||
final json = await authNotifier.box.get(authNotifier.cacheKey);
|
final json = await authNotifier.box.get(authNotifier.cacheKey);
|
||||||
@ -66,11 +68,13 @@ final routerProvider = Provider((ref) {
|
|||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "genres",
|
path: "genres",
|
||||||
|
name: GenrePage.name,
|
||||||
pageBuilder: (context, state) =>
|
pageBuilder: (context, state) =>
|
||||||
const SpotubePage(child: GenrePage()),
|
const SpotubePage(child: GenrePage()),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "genre/:categoryId",
|
path: "genre/:categoryId",
|
||||||
|
name: GenrePlaylistsPage.name,
|
||||||
pageBuilder: (context, state) => SpotubePage(
|
pageBuilder: (context, state) => SpotubePage(
|
||||||
child: GenrePlaylistsPage(
|
child: GenrePlaylistsPage(
|
||||||
category: state.extra as Category,
|
category: state.extra as Category,
|
||||||
@ -79,6 +83,7 @@ final routerProvider = Provider((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "feeds/:feedId",
|
path: "feeds/:feedId",
|
||||||
|
name: HomeFeedSectionPage.name,
|
||||||
pageBuilder: (context, state) => SpotubePage(
|
pageBuilder: (context, state) => SpotubePage(
|
||||||
child: HomeFeedSectionPage(
|
child: HomeFeedSectionPage(
|
||||||
sectionUri: state.pathParameters["feedId"] as String,
|
sectionUri: state.pathParameters["feedId"] as String,
|
||||||
@ -89,45 +94,50 @@ final routerProvider = Provider((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/search",
|
path: "/search",
|
||||||
name: "Search",
|
name: SearchPage.name,
|
||||||
pageBuilder: (context, state) =>
|
pageBuilder: (context, state) =>
|
||||||
const SpotubePage(child: SearchPage()),
|
const SpotubePage(child: SearchPage()),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/library",
|
path: "/library",
|
||||||
name: "Library",
|
name: LibraryPage.name,
|
||||||
pageBuilder: (context, state) =>
|
pageBuilder: (context, state) =>
|
||||||
const SpotubePage(child: LibraryPage()),
|
const SpotubePage(child: LibraryPage()),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "generate",
|
path: "generate",
|
||||||
pageBuilder: (context, state) =>
|
name: PlaylistGeneratorPage.name,
|
||||||
const SpotubePage(child: PlaylistGeneratorPage()),
|
pageBuilder: (context, state) =>
|
||||||
routes: [
|
const SpotubePage(child: PlaylistGeneratorPage()),
|
||||||
GoRoute(
|
routes: [
|
||||||
path: "result",
|
GoRoute(
|
||||||
pageBuilder: (context, state) => SpotubePage(
|
path: "result",
|
||||||
child: PlaylistGenerateResultPage(
|
name: PlaylistGenerateResultPage.name,
|
||||||
state: state.extra as GeneratePlaylistProviderInput,
|
pageBuilder: (context, state) => SpotubePage(
|
||||||
),
|
child: PlaylistGenerateResultPage(
|
||||||
|
state: state.extra as GeneratePlaylistProviderInput,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]),
|
),
|
||||||
]),
|
]),
|
||||||
|
],
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/lyrics",
|
path: "/lyrics",
|
||||||
name: "Lyrics",
|
name: LyricsPage.name,
|
||||||
pageBuilder: (context, state) =>
|
pageBuilder: (context, state) =>
|
||||||
const SpotubePage(child: LyricsPage()),
|
const SpotubePage(child: LyricsPage()),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/settings",
|
path: "/settings",
|
||||||
|
name: SettingsPage.name,
|
||||||
pageBuilder: (context, state) => const SpotubePage(
|
pageBuilder: (context, state) => const SpotubePage(
|
||||||
child: SettingsPage(),
|
child: SettingsPage(),
|
||||||
),
|
),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "blacklist",
|
path: "blacklist",
|
||||||
|
name: BlackListPage.name,
|
||||||
pageBuilder: (context, state) => SpotubeSlidePage(
|
pageBuilder: (context, state) => SpotubeSlidePage(
|
||||||
child: const BlackListPage(),
|
child: const BlackListPage(),
|
||||||
),
|
),
|
||||||
@ -135,12 +145,14 @@ final routerProvider = Provider((ref) {
|
|||||||
if (!kIsWeb)
|
if (!kIsWeb)
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "logs",
|
path: "logs",
|
||||||
|
name: LogsPage.name,
|
||||||
pageBuilder: (context, state) => SpotubeSlidePage(
|
pageBuilder: (context, state) => SpotubeSlidePage(
|
||||||
child: const LogsPage(),
|
child: const LogsPage(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "about",
|
path: "about",
|
||||||
|
name: AboutSpotube.name,
|
||||||
pageBuilder: (context, state) => SpotubeSlidePage(
|
pageBuilder: (context, state) => SpotubeSlidePage(
|
||||||
child: const AboutSpotube(),
|
child: const AboutSpotube(),
|
||||||
),
|
),
|
||||||
@ -149,6 +161,7 @@ final routerProvider = Provider((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/album/:id",
|
path: "/album/:id",
|
||||||
|
name: AlbumPage.name,
|
||||||
pageBuilder: (context, state) {
|
pageBuilder: (context, state) {
|
||||||
assert(state.extra is AlbumSimple);
|
assert(state.extra is AlbumSimple);
|
||||||
return SpotubePage(
|
return SpotubePage(
|
||||||
@ -158,6 +171,7 @@ final routerProvider = Provider((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/artist/:id",
|
path: "/artist/:id",
|
||||||
|
name: ArtistPage.name,
|
||||||
pageBuilder: (context, state) {
|
pageBuilder: (context, state) {
|
||||||
assert(state.pathParameters["id"] != null);
|
assert(state.pathParameters["id"] != null);
|
||||||
return SpotubePage(
|
return SpotubePage(
|
||||||
@ -166,6 +180,7 @@ final routerProvider = Provider((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/playlist/:id",
|
path: "/playlist/:id",
|
||||||
|
name: PlaylistPage.name,
|
||||||
pageBuilder: (context, state) {
|
pageBuilder: (context, state) {
|
||||||
assert(state.extra is PlaylistSimple);
|
assert(state.extra is PlaylistSimple);
|
||||||
return SpotubePage(
|
return SpotubePage(
|
||||||
@ -177,6 +192,7 @@ final routerProvider = Provider((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/track/:id",
|
path: "/track/:id",
|
||||||
|
name: TrackPage.name,
|
||||||
pageBuilder: (context, state) {
|
pageBuilder: (context, state) {
|
||||||
final id = state.pathParameters["id"]!;
|
final id = state.pathParameters["id"]!;
|
||||||
return SpotubePage(
|
return SpotubePage(
|
||||||
@ -186,12 +202,14 @@ final routerProvider = Provider((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/connect",
|
path: "/connect",
|
||||||
|
name: ConnectPage.name,
|
||||||
pageBuilder: (context, state) => const SpotubePage(
|
pageBuilder: (context, state) => const SpotubePage(
|
||||||
child: ConnectPage(),
|
child: ConnectPage(),
|
||||||
),
|
),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "control",
|
path: "control",
|
||||||
|
name: ConnectControlPage.name,
|
||||||
pageBuilder: (context, state) {
|
pageBuilder: (context, state) {
|
||||||
return const SpotubePage(
|
return const SpotubePage(
|
||||||
child: ConnectControlPage(),
|
child: ConnectControlPage(),
|
||||||
@ -202,13 +220,22 @@ final routerProvider = Provider((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/profile",
|
path: "/profile",
|
||||||
|
name: ProfilePage.name,
|
||||||
pageBuilder: (context, state) =>
|
pageBuilder: (context, state) =>
|
||||||
const SpotubePage(child: ProfilePage()),
|
const SpotubePage(child: ProfilePage()),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: "/stats",
|
||||||
|
name: StatsPage.name,
|
||||||
|
pageBuilder: (context, state) => const SpotubePage(
|
||||||
|
child: StatsPage(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/mini-player",
|
path: "/mini-player",
|
||||||
|
name: MiniLyricsPage.name,
|
||||||
parentNavigatorKey: rootNavigatorKey,
|
parentNavigatorKey: rootNavigatorKey,
|
||||||
pageBuilder: (context, state) => SpotubePage(
|
pageBuilder: (context, state) => SpotubePage(
|
||||||
child: MiniLyricsPage(prevSize: state.extra as Size),
|
child: MiniLyricsPage(prevSize: state.extra as Size),
|
||||||
@ -216,6 +243,7 @@ final routerProvider = Provider((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/getting-started",
|
path: "/getting-started",
|
||||||
|
name: GettingStarting.name,
|
||||||
parentNavigatorKey: rootNavigatorKey,
|
parentNavigatorKey: rootNavigatorKey,
|
||||||
pageBuilder: (context, state) => const SpotubePage(
|
pageBuilder: (context, state) => const SpotubePage(
|
||||||
child: GettingStarting(),
|
child: GettingStarting(),
|
||||||
@ -223,6 +251,7 @@ final routerProvider = Provider((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/login",
|
path: "/login",
|
||||||
|
name: WebViewLogin.name,
|
||||||
parentNavigatorKey: rootNavigatorKey,
|
parentNavigatorKey: rootNavigatorKey,
|
||||||
pageBuilder: (context, state) => SpotubePage(
|
pageBuilder: (context, state) => SpotubePage(
|
||||||
child: kIsMobile ? const WebViewLogin() : const DesktopLoginPage(),
|
child: kIsMobile ? const WebViewLogin() : const DesktopLoginPage(),
|
||||||
@ -230,6 +259,7 @@ final routerProvider = Provider((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/login-tutorial",
|
path: "/login-tutorial",
|
||||||
|
name: LoginTutorial.name,
|
||||||
parentNavigatorKey: rootNavigatorKey,
|
parentNavigatorKey: rootNavigatorKey,
|
||||||
pageBuilder: (context, state) => const SpotubePage(
|
pageBuilder: (context, state) => const SpotubePage(
|
||||||
child: LoginTutorial(),
|
child: LoginTutorial(),
|
||||||
@ -237,6 +267,7 @@ final routerProvider = Provider((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/lastfm-login",
|
path: "/lastfm-login",
|
||||||
|
name: LastFMLoginPage.name,
|
||||||
parentNavigatorKey: rootNavigatorKey,
|
parentNavigatorKey: rootNavigatorKey,
|
||||||
pageBuilder: (context, state) =>
|
pageBuilder: (context, state) =>
|
||||||
const SpotubePage(child: LastFMLoginPage()),
|
const SpotubePage(child: LastFMLoginPage()),
|
||||||
|
|||||||
@ -1,32 +1,82 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:spotube/collections/spotube_icons.dart';
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
import 'package:spotube/pages/home/home.dart';
|
||||||
|
import 'package:spotube/pages/library/library.dart';
|
||||||
|
import 'package:spotube/pages/lyrics/lyrics.dart';
|
||||||
|
import 'package:spotube/pages/search/search.dart';
|
||||||
|
import 'package:spotube/pages/settings/settings.dart';
|
||||||
|
import 'package:spotube/pages/stats/stats.dart';
|
||||||
|
|
||||||
class SideBarTiles {
|
class SideBarTiles {
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
final String title;
|
final String title;
|
||||||
final String id;
|
final String id;
|
||||||
SideBarTiles({required this.icon, required this.title, required this.id});
|
final String name;
|
||||||
|
|
||||||
|
SideBarTiles({
|
||||||
|
required this.icon,
|
||||||
|
required this.title,
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SideBarTiles> getSidebarTileList(AppLocalizations l10n) => [
|
List<SideBarTiles> getSidebarTileList(AppLocalizations l10n) => [
|
||||||
SideBarTiles(id: "browse", icon: SpotubeIcons.home, title: l10n.browse),
|
|
||||||
SideBarTiles(id: "search", icon: SpotubeIcons.search, title: l10n.search),
|
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "library", icon: SpotubeIcons.library, title: l10n.library),
|
id: "browse",
|
||||||
SideBarTiles(id: "lyrics", icon: SpotubeIcons.music, title: l10n.lyrics),
|
name: HomePage.name,
|
||||||
];
|
icon: SpotubeIcons.home,
|
||||||
|
title: l10n.browse,
|
||||||
List<SideBarTiles> getNavbarTileList(AppLocalizations l10n) => [
|
),
|
||||||
SideBarTiles(id: "browse", icon: SpotubeIcons.home, title: l10n.browse),
|
SideBarTiles(
|
||||||
SideBarTiles(id: "search", icon: SpotubeIcons.search, title: l10n.search),
|
id: "search",
|
||||||
|
name: SearchPage.name,
|
||||||
|
icon: SpotubeIcons.search,
|
||||||
|
title: l10n.search,
|
||||||
|
),
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "library",
|
id: "library",
|
||||||
|
name: LibraryPage.name,
|
||||||
icon: SpotubeIcons.library,
|
icon: SpotubeIcons.library,
|
||||||
title: l10n.library,
|
title: l10n.library,
|
||||||
),
|
),
|
||||||
|
SideBarTiles(
|
||||||
|
id: "lyrics",
|
||||||
|
name: LyricsPage.name,
|
||||||
|
icon: SpotubeIcons.music,
|
||||||
|
title: l10n.lyrics,
|
||||||
|
),
|
||||||
|
SideBarTiles(
|
||||||
|
id: "stats",
|
||||||
|
name: StatsPage.name,
|
||||||
|
icon: SpotubeIcons.chart,
|
||||||
|
title: l10n.stats,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
List<SideBarTiles> getNavbarTileList(AppLocalizations l10n) => [
|
||||||
|
SideBarTiles(
|
||||||
|
id: "browse",
|
||||||
|
name: HomePage.name,
|
||||||
|
icon: SpotubeIcons.home,
|
||||||
|
title: l10n.browse,
|
||||||
|
),
|
||||||
|
SideBarTiles(
|
||||||
|
id: "library",
|
||||||
|
name: LibraryPage.name,
|
||||||
|
icon: SpotubeIcons.library,
|
||||||
|
title: l10n.library,
|
||||||
|
),
|
||||||
|
SideBarTiles(
|
||||||
|
id: "stats",
|
||||||
|
name: StatsPage.name,
|
||||||
|
icon: SpotubeIcons.chart,
|
||||||
|
title: l10n.stats,
|
||||||
|
),
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "settings",
|
id: "settings",
|
||||||
|
name: SettingsPage.name,
|
||||||
icon: SpotubeIcons.settings,
|
icon: SpotubeIcons.settings,
|
||||||
title: l10n.settings,
|
title: l10n.settings,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -121,4 +121,5 @@ abstract class SpotubeIcons {
|
|||||||
static const monitor = FeatherIcons.monitor;
|
static const monitor = FeatherIcons.monitor;
|
||||||
static const power = FeatherIcons.power;
|
static const power = FeatherIcons.power;
|
||||||
static const bluetooth = FeatherIcons.bluetooth;
|
static const bluetooth = FeatherIcons.bluetooth;
|
||||||
|
static const chart = FeatherIcons.barChart2;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/extensions/image.dart';
|
import 'package:spotube/extensions/image.dart';
|
||||||
import 'package:spotube/extensions/track.dart';
|
import 'package:spotube/extensions/track.dart';
|
||||||
import 'package:spotube/models/connect/connect.dart';
|
import 'package:spotube/models/connect/connect.dart';
|
||||||
|
import 'package:spotube/pages/album/album.dart';
|
||||||
import 'package:spotube/provider/connect/connect.dart';
|
import 'package:spotube/provider/connect/connect.dart';
|
||||||
import 'package:spotube/provider/history/history.dart';
|
import 'package:spotube/provider/history/history.dart';
|
||||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||||
@ -64,7 +65,14 @@ class AlbumCard extends HookConsumerWidget {
|
|||||||
description:
|
description:
|
||||||
"${album.albumType?.formatted} • ${album.artists?.asString() ?? ""}",
|
"${album.albumType?.formatted} • ${album.artists?.asString() ?? ""}",
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ServiceUtils.push(context, "/album/${album.id}", extra: album);
|
ServiceUtils.pushNamed(
|
||||||
|
context,
|
||||||
|
AlbumPage.name,
|
||||||
|
pathParameters: {
|
||||||
|
"id": album.id!,
|
||||||
|
},
|
||||||
|
extra: album,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
onPlaybuttonPressed: () async {
|
onPlaybuttonPressed: () async {
|
||||||
updating.value = true;
|
updating.value = true;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/extensions/image.dart';
|
import 'package:spotube/extensions/image.dart';
|
||||||
import 'package:spotube/hooks/utils/use_breakpoint_value.dart';
|
import 'package:spotube/hooks/utils/use_breakpoint_value.dart';
|
||||||
import 'package:spotube/hooks/utils/use_brightness_value.dart';
|
import 'package:spotube/hooks/utils/use_brightness_value.dart';
|
||||||
|
import 'package:spotube/pages/artist/artist.dart';
|
||||||
import 'package:spotube/provider/blacklist_provider.dart';
|
import 'package:spotube/provider/blacklist_provider.dart';
|
||||||
import 'package:spotube/utils/service_utils.dart';
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
@ -63,7 +64,13 @@ class ArtistCard extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ServiceUtils.push(context, "/artist/${artist.id}");
|
ServiceUtils.pushNamed(
|
||||||
|
context,
|
||||||
|
ArtistPage.name,
|
||||||
|
pathParameters: {
|
||||||
|
"id": artist.id!,
|
||||||
|
},
|
||||||
|
);
|
||||||
},
|
},
|
||||||
borderRadius: radius,
|
borderRadius: radius,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:gap/gap.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:spotube/collections/spotube_icons.dart';
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
|
import 'package:spotube/pages/connect/connect.dart';
|
||||||
import 'package:spotube/provider/connect/clients.dart';
|
import 'package:spotube/provider/connect/clients.dart';
|
||||||
import 'package:spotube/utils/service_utils.dart';
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ class ConnectDeviceButton extends HookConsumerWidget {
|
|||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ServiceUtils.push(context, "/connect");
|
ServiceUtils.pushNamed(context, ConnectPage.name);
|
||||||
},
|
},
|
||||||
style: FilledButton.styleFrom(
|
style: FilledButton.styleFrom(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
@ -59,7 +60,7 @@ class ConnectDeviceButton extends HookConsumerWidget {
|
|||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ServiceUtils.push(context, "/connect");
|
ServiceUtils.pushNamed(context, ConnectPage.name);
|
||||||
},
|
},
|
||||||
borderRadius: BorderRadius.circular(50),
|
borderRadius: BorderRadius.circular(50),
|
||||||
child: Ink(
|
child: Ink(
|
||||||
@ -111,7 +112,7 @@ class ConnectDeviceButton extends HookConsumerWidget {
|
|||||||
foregroundColor: colorScheme.onPrimary,
|
foregroundColor: colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ServiceUtils.push(context, "/connect");
|
ServiceUtils.pushNamed(context, ConnectPage.name);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:spotube/collections/spotube_icons.dart';
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart';
|
import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart';
|
||||||
|
import 'package:spotube/pages/home/feed/feed_section.dart';
|
||||||
import 'package:spotube/provider/spotify/views/home.dart';
|
import 'package:spotube/provider/spotify/views/home.dart';
|
||||||
import 'package:spotube/utils/service_utils.dart';
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
@ -41,8 +42,13 @@ class HomePageFeedSection extends HookConsumerWidget {
|
|||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
label: const Text("Browse More"),
|
label: const Text("Browse More"),
|
||||||
icon: const Icon(SpotubeIcons.angleRight),
|
icon: const Icon(SpotubeIcons.angleRight),
|
||||||
onPressed: () =>
|
onPressed: () => ServiceUtils.pushNamed(
|
||||||
ServiceUtils.push(context, "/feeds/${section.uri}"),
|
context,
|
||||||
|
HomeFeedSectionPage.name,
|
||||||
|
pathParameters: {
|
||||||
|
"feedId": section.uri,
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -6,6 +6,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:spotube/collections/spotube_icons.dart';
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||||
import 'package:spotube/models/spotify_friends.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';
|
import 'package:spotube/provider/spotify_provider.dart';
|
||||||
|
|
||||||
class FriendItem extends HookConsumerWidget {
|
class FriendItem extends HookConsumerWidget {
|
||||||
@ -57,7 +60,9 @@ class FriendItem extends HookConsumerWidget {
|
|||||||
text: friend.track.name,
|
text: friend.track.name,
|
||||||
recognizer: TapGestureRecognizer()
|
recognizer: TapGestureRecognizer()
|
||||||
..onTap = () {
|
..onTap = () {
|
||||||
context.push("/track/${friend.track.id}");
|
context.pushNamed(TrackPage.name, pathParameters: {
|
||||||
|
"id": friend.track.id,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const TextSpan(text: " • "),
|
const TextSpan(text: " • "),
|
||||||
@ -71,8 +76,12 @@ class FriendItem extends HookConsumerWidget {
|
|||||||
text: " ${friend.track.artist.name}",
|
text: " ${friend.track.artist.name}",
|
||||||
recognizer: TapGestureRecognizer()
|
recognizer: TapGestureRecognizer()
|
||||||
..onTap = () {
|
..onTap = () {
|
||||||
context.push(
|
context.pushNamed(
|
||||||
"/artist/${friend.track.artist.id}",
|
ArtistPage.name,
|
||||||
|
pathParameters: {
|
||||||
|
"id": friend.track.artist.id,
|
||||||
|
},
|
||||||
|
extra: friend.track.artist,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -105,8 +114,11 @@ 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.push(
|
context.pushNamed(
|
||||||
"/album/${friend.track.album.id}",
|
AlbumPage.name,
|
||||||
|
pathParameters: {
|
||||||
|
"id": friend.track.album.id,
|
||||||
|
},
|
||||||
extra: album,
|
extra: album,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,8 @@ import 'package:spotube/collections/spotube_icons.dart';
|
|||||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||||
import 'package:spotube/extensions/constrains.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
|
import 'package:spotube/pages/home/genres/genre_playlists.dart';
|
||||||
|
import 'package:spotube/pages/home/genres/genres.dart';
|
||||||
import 'package:spotube/provider/spotify/spotify.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class HomeGenresSection extends HookConsumerWidget {
|
class HomeGenresSection extends HookConsumerWidget {
|
||||||
@ -50,7 +52,7 @@ class HomeGenresSection extends HookConsumerWidget {
|
|||||||
textDirection: TextDirection.rtl,
|
textDirection: TextDirection.rtl,
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.push('/genres');
|
context.pushNamed(GenrePage.name);
|
||||||
},
|
},
|
||||||
icon: const Icon(SpotubeIcons.angleRight),
|
icon: const Icon(SpotubeIcons.angleRight),
|
||||||
label: Text(
|
label: Text(
|
||||||
@ -110,7 +112,13 @@ class HomeGenresSection extends HookConsumerWidget {
|
|||||||
|
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.push('/genre/${category.id}', extra: category);
|
context.pushNamed(
|
||||||
|
GenrePlaylistsPage.name,
|
||||||
|
pathParameters: {
|
||||||
|
"categoryId": category.id!,
|
||||||
|
},
|
||||||
|
extra: category,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: Ink(
|
child: Ink(
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:spotube/components/shared/dialogs/select_device_dialog.dart';
|
|||||||
import 'package:spotube/components/shared/playbutton_card.dart';
|
import 'package:spotube/components/shared/playbutton_card.dart';
|
||||||
import 'package:spotube/extensions/image.dart';
|
import 'package:spotube/extensions/image.dart';
|
||||||
import 'package:spotube/models/connect/connect.dart';
|
import 'package:spotube/models/connect/connect.dart';
|
||||||
|
import 'package:spotube/pages/playlist/playlist.dart';
|
||||||
import 'package:spotube/provider/connect/connect.dart';
|
import 'package:spotube/provider/connect/connect.dart';
|
||||||
import 'package:spotube/provider/history/history.dart';
|
import 'package:spotube/provider/history/history.dart';
|
||||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||||
@ -58,9 +59,12 @@ class PlaylistCard extends HookConsumerWidget {
|
|||||||
isOwner: playlist.owner?.id == me.asData?.value.id &&
|
isOwner: playlist.owner?.id == me.asData?.value.id &&
|
||||||
me.asData?.value.id != null,
|
me.asData?.value.id != null,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ServiceUtils.push(
|
ServiceUtils.pushNamed(
|
||||||
context,
|
context,
|
||||||
"/playlist/${playlist.id}",
|
PlaylistPage.name,
|
||||||
|
pathParameters: {
|
||||||
|
"id": playlist.id!,
|
||||||
|
},
|
||||||
extra: playlist,
|
extra: playlist,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -16,6 +16,8 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/extensions/image.dart';
|
import 'package:spotube/extensions/image.dart';
|
||||||
import 'package:spotube/hooks/utils/use_brightness_value.dart';
|
import 'package:spotube/hooks/utils/use_brightness_value.dart';
|
||||||
import 'package:spotube/hooks/controllers/use_sidebarx_controller.dart';
|
import 'package:spotube/hooks/controllers/use_sidebarx_controller.dart';
|
||||||
|
import 'package:spotube/pages/profile/profile.dart';
|
||||||
|
import 'package:spotube/pages/settings/settings.dart';
|
||||||
import 'package:spotube/provider/download_manager_provider.dart';
|
import 'package:spotube/provider/download_manager_provider.dart';
|
||||||
import 'package:spotube/provider/authentication_provider.dart';
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
import 'package:spotube/provider/spotify/spotify.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
@ -26,13 +28,9 @@ import 'package:spotube/utils/platform.dart';
|
|||||||
import 'package:spotube/utils/service_utils.dart';
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
class Sidebar extends HookConsumerWidget {
|
class Sidebar extends HookConsumerWidget {
|
||||||
final int? selectedIndex;
|
|
||||||
final void Function(int) onSelectedIndexChanged;
|
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
const Sidebar({
|
const Sidebar({
|
||||||
required this.selectedIndex,
|
|
||||||
required this.onSelectedIndexChanged,
|
|
||||||
required this.child,
|
required this.child,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
@ -47,12 +45,9 @@ class Sidebar extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void goToSettings(BuildContext context) {
|
|
||||||
GoRouter.of(context).go("/settings");
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final routerState = GoRouterState.of(context);
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
|
|
||||||
final downloadCount = ref.watch(downloadManagerProvider).$downloadCount;
|
final downloadCount = ref.watch(downloadManagerProvider).$downloadCount;
|
||||||
@ -60,8 +55,17 @@ class Sidebar extends HookConsumerWidget {
|
|||||||
final layoutMode =
|
final layoutMode =
|
||||||
ref.watch(userPreferencesProvider.select((s) => s.layoutMode));
|
ref.watch(userPreferencesProvider.select((s) => s.layoutMode));
|
||||||
|
|
||||||
|
final sidebarTileList = useMemoized(
|
||||||
|
() => getSidebarTileList(context.l10n),
|
||||||
|
[context.l10n],
|
||||||
|
);
|
||||||
|
|
||||||
|
final selectedIndex = sidebarTileList.indexWhere(
|
||||||
|
(e) => routerState.namedLocation(e.name) == routerState.matchedLocation,
|
||||||
|
);
|
||||||
|
|
||||||
final controller = useSidebarXController(
|
final controller = useSidebarXController(
|
||||||
selectedIndex: selectedIndex ?? 0,
|
selectedIndex: selectedIndex,
|
||||||
extended: mediaQuery.lgAndUp,
|
extended: mediaQuery.lgAndUp,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -73,29 +77,6 @@ class Sidebar extends HookConsumerWidget {
|
|||||||
Color.lerp(bg, Colors.black, 0.45)!,
|
Color.lerp(bg, Colors.black, 0.45)!,
|
||||||
);
|
);
|
||||||
|
|
||||||
final sidebarTileList = useMemoized(
|
|
||||||
() => getSidebarTileList(context.l10n),
|
|
||||||
[context.l10n],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() {
|
|
||||||
if (controller.selectedIndex != selectedIndex && selectedIndex != null) {
|
|
||||||
controller.selectIndex(selectedIndex!);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}, [selectedIndex]);
|
|
||||||
|
|
||||||
useEffect(() {
|
|
||||||
void listener() {
|
|
||||||
onSelectedIndexChanged(controller.selectedIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller.addListener(listener);
|
|
||||||
return () {
|
|
||||||
controller.removeListener(listener);
|
|
||||||
};
|
|
||||||
}, [controller]);
|
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
if (mediaQuery.lgAndUp && !controller.extended) {
|
if (mediaQuery.lgAndUp && !controller.extended) {
|
||||||
@ -106,6 +87,13 @@ class Sidebar extends HookConsumerWidget {
|
|||||||
return null;
|
return null;
|
||||||
}, [mediaQuery, controller]);
|
}, [mediaQuery, controller]);
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
if (controller.selectedIndex != selectedIndex) {
|
||||||
|
controller.selectIndex(selectedIndex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}, [selectedIndex]);
|
||||||
|
|
||||||
if (layoutMode == LayoutMode.compact ||
|
if (layoutMode == LayoutMode.compact ||
|
||||||
(mediaQuery.smAndDown && layoutMode == LayoutMode.adaptive)) {
|
(mediaQuery.smAndDown && layoutMode == LayoutMode.adaptive)) {
|
||||||
return Scaffold(body: child);
|
return Scaffold(body: child);
|
||||||
@ -119,23 +107,28 @@ class Sidebar extends HookConsumerWidget {
|
|||||||
items: sidebarTileList.mapIndexed(
|
items: sidebarTileList.mapIndexed(
|
||||||
(index, e) {
|
(index, e) {
|
||||||
return SidebarXItem(
|
return SidebarXItem(
|
||||||
iconWidget: Badge(
|
onTap: () {
|
||||||
backgroundColor: theme.colorScheme.primary,
|
context.goNamed(e.name);
|
||||||
isLabelVisible: e.title == "Library" && downloadCount > 0,
|
},
|
||||||
label: Text(
|
iconBuilder: (selected, hovered) {
|
||||||
downloadCount.toString(),
|
return Badge(
|
||||||
style: const TextStyle(
|
backgroundColor: theme.colorScheme.primary,
|
||||||
color: Colors.white,
|
isLabelVisible: e.title == "Library" && downloadCount > 0,
|
||||||
fontSize: 10,
|
label: Text(
|
||||||
|
downloadCount.toString(),
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 10,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
child: Icon(
|
||||||
child: Icon(
|
e.icon,
|
||||||
e.icon,
|
color: selected || hovered
|
||||||
color: selectedIndex == index
|
? theme.colorScheme.primary
|
||||||
? theme.colorScheme.primary
|
: null,
|
||||||
: null,
|
),
|
||||||
),
|
);
|
||||||
),
|
},
|
||||||
label: e.title,
|
label: e.title,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -257,7 +250,7 @@ class SidebarFooter extends HookConsumerWidget {
|
|||||||
if (mediaQuery.mdAndDown) {
|
if (mediaQuery.mdAndDown) {
|
||||||
return IconButton(
|
return IconButton(
|
||||||
icon: const Icon(SpotubeIcons.settings),
|
icon: const Icon(SpotubeIcons.settings),
|
||||||
onPressed: () => Sidebar.goToSettings(context),
|
onPressed: () => ServiceUtils.navigateNamed(context, SettingsPage.name),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +271,7 @@ class SidebarFooter extends HookConsumerWidget {
|
|||||||
Flexible(
|
Flexible(
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ServiceUtils.push(context, "/profile");
|
ServiceUtils.pushNamed(context, ProfilePage.name);
|
||||||
},
|
},
|
||||||
borderRadius: BorderRadius.circular(30),
|
borderRadius: BorderRadius.circular(30),
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -310,7 +303,7 @@ class SidebarFooter extends HookConsumerWidget {
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(SpotubeIcons.settings),
|
icon: const Icon(SpotubeIcons.settings),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Sidebar.goToSettings(context);
|
ServiceUtils.navigateNamed(context, SettingsPage.name);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -3,39 +3,35 @@ import 'dart:ui';
|
|||||||
import 'package:curved_navigation_bar/curved_navigation_bar.dart';
|
import 'package:curved_navigation_bar/curved_navigation_bar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
import 'package:spotube/collections/side_bar_tiles.dart';
|
import 'package:spotube/collections/side_bar_tiles.dart';
|
||||||
import 'package:spotube/components/root/sidebar.dart';
|
|
||||||
import 'package:spotube/extensions/constrains.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/hooks/utils/use_brightness_value.dart';
|
import 'package:spotube/hooks/utils/use_brightness_value.dart';
|
||||||
import 'package:spotube/provider/download_manager_provider.dart';
|
import 'package:spotube/provider/download_manager_provider.dart';
|
||||||
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
||||||
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
|
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
|
||||||
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
final navigationPanelHeight = StateProvider<double>((ref) => 50);
|
final navigationPanelHeight = StateProvider<double>((ref) => 50);
|
||||||
|
|
||||||
class SpotubeNavigationBar extends HookConsumerWidget {
|
class SpotubeNavigationBar extends HookConsumerWidget {
|
||||||
final int? selectedIndex;
|
|
||||||
final void Function(int) onSelectedIndexChanged;
|
|
||||||
|
|
||||||
const SpotubeNavigationBar({
|
const SpotubeNavigationBar({
|
||||||
required this.selectedIndex,
|
|
||||||
required this.onSelectedIndexChanged,
|
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
final routerState = GoRouterState.of(context);
|
||||||
|
|
||||||
final downloadCount = ref.watch(downloadManagerProvider).$downloadCount;
|
final downloadCount = ref.watch(downloadManagerProvider).$downloadCount;
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
final layoutMode =
|
final layoutMode =
|
||||||
ref.watch(userPreferencesProvider.select((s) => s.layoutMode));
|
ref.watch(userPreferencesProvider.select((s) => s.layoutMode));
|
||||||
|
|
||||||
final insideSelectedIndex = useState<int>(selectedIndex ?? 0);
|
|
||||||
|
|
||||||
final buttonColor = useBrightnessValue(
|
final buttonColor = useBrightnessValue(
|
||||||
theme.colorScheme.inversePrimary,
|
theme.colorScheme.inversePrimary,
|
||||||
theme.colorScheme.primary.withOpacity(0.2),
|
theme.colorScheme.primary.withOpacity(0.2),
|
||||||
@ -46,12 +42,9 @@ class SpotubeNavigationBar extends HookConsumerWidget {
|
|||||||
|
|
||||||
final panelHeight = ref.watch(navigationPanelHeight);
|
final panelHeight = ref.watch(navigationPanelHeight);
|
||||||
|
|
||||||
useEffect(() {
|
final selectedIndex = navbarTileList.indexWhere(
|
||||||
if (selectedIndex != null) {
|
(e) => routerState.namedLocation(e.name) == routerState.matchedLocation,
|
||||||
insideSelectedIndex.value = selectedIndex!;
|
);
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}, [selectedIndex]);
|
|
||||||
|
|
||||||
if (layoutMode == LayoutMode.extended ||
|
if (layoutMode == LayoutMode.extended ||
|
||||||
(mediaQuery.mdAndUp && layoutMode == LayoutMode.adaptive) ||
|
(mediaQuery.mdAndUp && layoutMode == LayoutMode.adaptive) ||
|
||||||
@ -91,14 +84,9 @@ class SpotubeNavigationBar extends HookConsumerWidget {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
).toList(),
|
).toList(),
|
||||||
index: insideSelectedIndex.value,
|
index: selectedIndex,
|
||||||
onTap: (i) {
|
onTap: (i) {
|
||||||
insideSelectedIndex.value = i;
|
ServiceUtils.navigateNamed(context, navbarTileList[i].name);
|
||||||
if (navbarTileList[i].id == "settings") {
|
|
||||||
Sidebar.goToSettings(context);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
onSelectedIndexChanged(i);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
|
import 'package:spotube/pages/settings/settings.dart';
|
||||||
|
|
||||||
import 'package:spotube/provider/authentication_provider.dart';
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
import 'package:spotube/utils/service_utils.dart';
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
@ -25,7 +26,7 @@ class AnonymousFallback extends ConsumerWidget {
|
|||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
FilledButton(
|
FilledButton(
|
||||||
child: Text(context.l10n.login_with_spotify),
|
child: Text(context.l10n.login_with_spotify),
|
||||||
onPressed: () => ServiceUtils.push(context, "/settings"),
|
onPressed: () => ServiceUtils.pushNamed(context, SettingsPage.name),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/shared/links/anchor_button.dart';
|
import 'package:spotube/components/shared/links/anchor_button.dart';
|
||||||
|
import 'package:spotube/pages/artist/artist.dart';
|
||||||
import 'package:spotube/utils/service_utils.dart';
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
class ArtistLink extends StatelessWidget {
|
class ArtistLink extends StatelessWidget {
|
||||||
@ -40,9 +41,12 @@ class ArtistLink extends StatelessWidget {
|
|||||||
if (onRouteChange != null) {
|
if (onRouteChange != null) {
|
||||||
onRouteChange?.call("/artist/${artist.value.id}");
|
onRouteChange?.call("/artist/${artist.value.id}");
|
||||||
} else {
|
} else {
|
||||||
ServiceUtils.push(
|
ServiceUtils.pushNamed(
|
||||||
context,
|
context,
|
||||||
"/artist/${artist.value.id}",
|
ArtistPage.name,
|
||||||
|
pathParameters: {
|
||||||
|
"id": artist.value.id!,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -320,5 +320,6 @@
|
|||||||
"select": "Select",
|
"select": "Select",
|
||||||
"connect_client_alert": "You're being controlled by {client}",
|
"connect_client_alert": "You're being controlled by {client}",
|
||||||
"this_device": "This Device",
|
"this_device": "This Device",
|
||||||
"remote": "Remote"
|
"remote": "Remote",
|
||||||
|
"stats": "Stats"
|
||||||
}
|
}
|
||||||
@ -8,6 +8,8 @@ import 'package:spotube/extensions/image.dart';
|
|||||||
import 'package:spotube/provider/spotify/spotify.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class AlbumPage extends HookConsumerWidget {
|
class AlbumPage extends HookConsumerWidget {
|
||||||
|
static const name = "album";
|
||||||
|
|
||||||
final AlbumSimple album;
|
final AlbumSimple album;
|
||||||
const AlbumPage({
|
const AlbumPage({
|
||||||
super.key,
|
super.key,
|
||||||
|
|||||||
@ -15,6 +15,8 @@ import 'package:spotube/pages/artist/section/top_tracks.dart';
|
|||||||
import 'package:spotube/provider/spotify/spotify.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class ArtistPage extends HookConsumerWidget {
|
class ArtistPage extends HookConsumerWidget {
|
||||||
|
static const name = "artist";
|
||||||
|
|
||||||
final String artistId;
|
final String artistId;
|
||||||
final logger = getLogger(ArtistPage);
|
final logger = getLogger(ArtistPage);
|
||||||
ArtistPage(this.artistId, {super.key});
|
ArtistPage(this.artistId, {super.key});
|
||||||
|
|||||||
@ -5,10 +5,13 @@ import 'package:spotube/collections/spotube_icons.dart';
|
|||||||
import 'package:spotube/components/connect/local_devices.dart';
|
import 'package:spotube/components/connect/local_devices.dart';
|
||||||
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
||||||
import 'package:spotube/extensions/context.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/provider/connect/clients.dart';
|
||||||
import 'package:spotube/utils/service_utils.dart';
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
class ConnectPage extends HookConsumerWidget {
|
class ConnectPage extends HookConsumerWidget {
|
||||||
|
static const name = "connect";
|
||||||
|
|
||||||
const ConnectPage({super.key});
|
const ConnectPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -65,9 +68,9 @@ class ConnectPage extends HookConsumerWidget {
|
|||||||
selected: selected,
|
selected: selected,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
ServiceUtils.push(
|
ServiceUtils.pushNamed(
|
||||||
context,
|
context,
|
||||||
"/connect/control",
|
ConnectControlPage.name,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
connectClientsNotifier.resolveService(device);
|
connectClientsNotifier.resolveService(device);
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import 'package:spotube/extensions/constrains.dart';
|
|||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/extensions/duration.dart';
|
import 'package:spotube/extensions/duration.dart';
|
||||||
import 'package:spotube/extensions/image.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/clients.dart';
|
||||||
import 'package:spotube/provider/connect/connect.dart';
|
import 'package:spotube/provider/connect/connect.dart';
|
||||||
import 'package:spotube/services/audio_player/loop_mode.dart';
|
import 'package:spotube/services/audio_player/loop_mode.dart';
|
||||||
@ -46,6 +47,8 @@ class RemotePlayerQueue extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ConnectControlPage extends HookConsumerWidget {
|
class ConnectControlPage extends HookConsumerWidget {
|
||||||
|
static const name = "connect_control";
|
||||||
|
|
||||||
const ConnectControlPage({super.key});
|
const ConnectControlPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -125,9 +128,13 @@ class ConnectControlPage extends HookConsumerWidget {
|
|||||||
playlist.activeTrack?.name ?? "",
|
playlist.activeTrack?.name ?? "",
|
||||||
style: textTheme.titleLarge!,
|
style: textTheme.titleLarge!,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ServiceUtils.push(
|
if (playlist.activeTrack == null) return;
|
||||||
|
ServiceUtils.pushNamed(
|
||||||
context,
|
context,
|
||||||
"/track/${playlist.activeTrack?.id}",
|
TrackPage.name,
|
||||||
|
pathParameters: {
|
||||||
|
"id": playlist.activeTrack!.id!,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@ -7,8 +7,10 @@ import 'package:spotube/components/desktop_login/login_form.dart';
|
|||||||
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
||||||
import 'package:spotube/extensions/constrains.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
|
import 'package:spotube/pages/mobile_login/mobile_login.dart';
|
||||||
|
|
||||||
class DesktopLoginPage extends HookConsumerWidget {
|
class DesktopLoginPage extends HookConsumerWidget {
|
||||||
|
static const name = WebViewLogin.name;
|
||||||
const DesktopLoginPage({super.key});
|
const DesktopLoginPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -8,10 +8,12 @@ import 'package:spotube/components/desktop_login/login_form.dart';
|
|||||||
import 'package:spotube/components/shared/links/hyper_link.dart';
|
import 'package:spotube/components/shared/links/hyper_link.dart';
|
||||||
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
|
import 'package:spotube/pages/home/home.dart';
|
||||||
import 'package:spotube/provider/authentication_provider.dart';
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
import 'package:spotube/utils/service_utils.dart';
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
class LoginTutorial extends ConsumerWidget {
|
class LoginTutorial extends ConsumerWidget {
|
||||||
|
static const name = "login_tutorial";
|
||||||
const LoginTutorial({super.key});
|
const LoginTutorial({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -53,7 +55,7 @@ class LoginTutorial extends ConsumerWidget {
|
|||||||
overrideDone: FilledButton(
|
overrideDone: FilledButton(
|
||||||
onPressed: authenticationNotifier.isLoggedIn
|
onPressed: authenticationNotifier.isLoggedIn
|
||||||
? () {
|
? () {
|
||||||
ServiceUtils.push(context, "/");
|
ServiceUtils.pushNamed(context, HomePage.name);
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
child: Center(child: Text(context.l10n.done)),
|
child: Center(child: Text(context.l10n.done)),
|
||||||
|
|||||||
@ -12,6 +12,8 @@ import 'package:spotube/provider/user_preferences/user_preferences_provider.dart
|
|||||||
import 'package:spotube/themes/theme.dart';
|
import 'package:spotube/themes/theme.dart';
|
||||||
|
|
||||||
class GettingStarting extends HookConsumerWidget {
|
class GettingStarting extends HookConsumerWidget {
|
||||||
|
static const name = "getting_started";
|
||||||
|
|
||||||
const GettingStarting({super.key});
|
const GettingStarting({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:spotube/collections/spotube_icons.dart';
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
import 'package:spotube/components/getting_started/blur_card.dart';
|
import 'package:spotube/components/getting_started/blur_card.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
|
import 'package:spotube/pages/mobile_login/mobile_login.dart';
|
||||||
import 'package:spotube/services/kv_store/kv_store.dart';
|
import 'package:spotube/services/kv_store/kv_store.dart';
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
@ -120,7 +121,7 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget {
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await KVStoreService.setDoneGettingStarted(true);
|
await KVStoreService.setDoneGettingStarted(true);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.push("/login");
|
context.pushNamed(WebViewLogin.name);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import 'package:spotube/extensions/constrains.dart';
|
|||||||
import 'package:spotube/provider/spotify/views/home_section.dart';
|
import 'package:spotube/provider/spotify/views/home_section.dart';
|
||||||
|
|
||||||
class HomeFeedSectionPage extends HookConsumerWidget {
|
class HomeFeedSectionPage extends HookConsumerWidget {
|
||||||
|
static const name = "home_feed_section";
|
||||||
|
|
||||||
final String sectionUri;
|
final String sectionUri;
|
||||||
const HomeFeedSectionPage({super.key, required this.sectionUri});
|
const HomeFeedSectionPage({super.key, required this.sectionUri});
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,8 @@ import 'package:collection/collection.dart';
|
|||||||
import 'package:spotube/utils/platform.dart';
|
import 'package:spotube/utils/platform.dart';
|
||||||
|
|
||||||
class GenrePlaylistsPage extends HookConsumerWidget {
|
class GenrePlaylistsPage extends HookConsumerWidget {
|
||||||
|
static const name = "genre_playlists";
|
||||||
|
|
||||||
final Category category;
|
final Category category;
|
||||||
const GenrePlaylistsPage({super.key, required this.category});
|
const GenrePlaylistsPage({super.key, required this.category});
|
||||||
|
|
||||||
|
|||||||
@ -9,9 +9,11 @@ import 'package:spotube/collections/gradients.dart';
|
|||||||
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
||||||
import 'package:spotube/extensions/constrains.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/extensions/context.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:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class GenrePage extends HookConsumerWidget {
|
class GenrePage extends HookConsumerWidget {
|
||||||
|
static const name = "genre";
|
||||||
const GenrePage({super.key});
|
const GenrePage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -47,7 +49,13 @@ class GenrePage extends HookConsumerWidget {
|
|||||||
return InkWell(
|
return InkWell(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.push("/genre/${category.id}", extra: category);
|
context.pushNamed(
|
||||||
|
GenrePlaylistsPage.name,
|
||||||
|
pathParameters: {
|
||||||
|
"categoryId": category.id!,
|
||||||
|
},
|
||||||
|
extra: category,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
child: Ink(
|
child: Ink(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:spotube/collections/assets.gen.dart';
|
import 'package:spotube/collections/assets.gen.dart';
|
||||||
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
import 'package:spotube/components/connect/connect_device.dart';
|
import 'package:spotube/components/connect/connect_device.dart';
|
||||||
import 'package:spotube/components/home/sections/featured.dart';
|
import 'package:spotube/components/home/sections/featured.dart';
|
||||||
import 'package:spotube/components/home/sections/feed.dart';
|
import 'package:spotube/components/home/sections/feed.dart';
|
||||||
@ -15,12 +16,15 @@ import 'package:spotube/components/shared/image/universal_image.dart';
|
|||||||
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
||||||
import 'package:spotube/extensions/constrains.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/extensions/image.dart';
|
import 'package:spotube/extensions/image.dart';
|
||||||
|
import 'package:spotube/pages/profile/profile.dart';
|
||||||
|
import 'package:spotube/pages/search/search.dart';
|
||||||
import 'package:spotube/provider/authentication_provider.dart';
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
import 'package:spotube/provider/spotify/spotify.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
import 'package:spotube/utils/platform.dart';
|
import 'package:spotube/utils/platform.dart';
|
||||||
import 'package:spotube/utils/service_utils.dart';
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
class HomePage extends HookConsumerWidget {
|
class HomePage extends HookConsumerWidget {
|
||||||
|
static const name = "home";
|
||||||
const HomePage({super.key});
|
const HomePage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -63,11 +67,18 @@ class HomePage extends HookConsumerWidget {
|
|||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ServiceUtils.push(context, "/profile");
|
ServiceUtils.pushNamed(context, ProfilePage.name);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
const Gap(10),
|
const Gap(10),
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(SpotubeIcons.search),
|
||||||
|
onPressed: () {
|
||||||
|
ServiceUtils.pushNamed(context, SearchPage.name);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const Gap(10),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
else if (kIsMacOS)
|
else if (kIsMacOS)
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/provider/scrobbler_provider.dart';
|
import 'package:spotube/provider/scrobbler_provider.dart';
|
||||||
|
|
||||||
class LastFMLoginPage extends HookConsumerWidget {
|
class LastFMLoginPage extends HookConsumerWidget {
|
||||||
|
static const name = "lastfm_login";
|
||||||
const LastFMLoginPage({super.key});
|
const LastFMLoginPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -12,6 +12,8 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/provider/download_manager_provider.dart';
|
import 'package:spotube/provider/download_manager_provider.dart';
|
||||||
|
|
||||||
class LibraryPage extends HookConsumerWidget {
|
class LibraryPage extends HookConsumerWidget {
|
||||||
|
static const name = "library";
|
||||||
|
|
||||||
const LibraryPage({super.key});
|
const LibraryPage({super.key});
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
|
|||||||
@ -24,6 +24,8 @@ import 'package:spotube/provider/user_preferences/user_preferences_provider.dart
|
|||||||
const RecommendationAttribute zeroValues = (min: 0, target: 0, max: 0);
|
const RecommendationAttribute zeroValues = (min: 0, target: 0, max: 0);
|
||||||
|
|
||||||
class PlaylistGeneratorPage extends HookConsumerWidget {
|
class PlaylistGeneratorPage extends HookConsumerWidget {
|
||||||
|
static const name = "playlist_generator";
|
||||||
|
|
||||||
const PlaylistGeneratorPage({super.key});
|
const PlaylistGeneratorPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -10,10 +10,13 @@ import 'package:spotube/components/shared/dialogs/playlist_add_track_dialog.dart
|
|||||||
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/models/spotify/recommendation_seeds.dart';
|
import 'package:spotube/models/spotify/recommendation_seeds.dart';
|
||||||
|
import 'package:spotube/pages/playlist/playlist.dart';
|
||||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||||
import 'package:spotube/provider/spotify/spotify.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class PlaylistGenerateResultPage extends HookConsumerWidget {
|
class PlaylistGenerateResultPage extends HookConsumerWidget {
|
||||||
|
static const name = "playlist_generate_result";
|
||||||
|
|
||||||
final GeneratePlaylistProviderInput state;
|
final GeneratePlaylistProviderInput state;
|
||||||
|
|
||||||
const PlaylistGenerateResultPage({
|
const PlaylistGenerateResultPage({
|
||||||
@ -123,8 +126,11 @@ class PlaylistGenerateResultPage extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (playlist != null) {
|
if (playlist != null) {
|
||||||
router.go(
|
router.goNamed(
|
||||||
'/playlist/${playlist.id}',
|
PlaylistPage.name,
|
||||||
|
pathParameters: {
|
||||||
|
"id": playlist.id!,
|
||||||
|
},
|
||||||
extra: playlist,
|
extra: playlist,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,8 @@ import 'package:spotube/utils/platform.dart';
|
|||||||
import 'package:spotube/provider/spotify/spotify.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class LyricsPage extends HookConsumerWidget {
|
class LyricsPage extends HookConsumerWidget {
|
||||||
|
static const name = "lyrics";
|
||||||
|
|
||||||
final bool isModal;
|
final bool isModal;
|
||||||
const LyricsPage({super.key, this.isModal = false});
|
const LyricsPage({super.key, this.isModal = false});
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,8 @@ import 'package:spotube/utils/platform.dart';
|
|||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
class MiniLyricsPage extends HookConsumerWidget {
|
class MiniLyricsPage extends HookConsumerWidget {
|
||||||
|
static const name = "mini_lyrics";
|
||||||
|
|
||||||
final Size prevSize;
|
final Size prevSize;
|
||||||
const MiniLyricsPage({super.key, required this.prevSize});
|
const MiniLyricsPage({super.key, required this.prevSize});
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import 'package:spotube/provider/authentication_provider.dart';
|
|||||||
import 'package:spotube/utils/platform.dart';
|
import 'package:spotube/utils/platform.dart';
|
||||||
|
|
||||||
class WebViewLogin extends HookConsumerWidget {
|
class WebViewLogin extends HookConsumerWidget {
|
||||||
|
static const name = "login";
|
||||||
const WebViewLogin({super.key});
|
const WebViewLogin({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -3,9 +3,12 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/components/shared/tracks_view/track_view.dart';
|
import 'package:spotube/components/shared/tracks_view/track_view.dart';
|
||||||
import 'package:spotube/components/shared/tracks_view/track_view_props.dart';
|
import 'package:spotube/components/shared/tracks_view/track_view_props.dart';
|
||||||
|
import 'package:spotube/pages/playlist/playlist.dart';
|
||||||
import 'package:spotube/provider/spotify/spotify.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class LikedPlaylistPage extends HookConsumerWidget {
|
class LikedPlaylistPage extends HookConsumerWidget {
|
||||||
|
static const name = PlaylistPage.name;
|
||||||
|
|
||||||
final PlaylistSimple playlist;
|
final PlaylistSimple playlist;
|
||||||
const LikedPlaylistPage({
|
const LikedPlaylistPage({
|
||||||
super.key,
|
super.key,
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import 'package:spotube/extensions/image.dart';
|
|||||||
import 'package:spotube/provider/spotify/spotify.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class PlaylistPage extends HookConsumerWidget {
|
class PlaylistPage extends HookConsumerWidget {
|
||||||
|
static const name = "playlist";
|
||||||
|
|
||||||
final PlaylistSimple playlist;
|
final PlaylistSimple playlist;
|
||||||
const PlaylistPage({
|
const PlaylistPage({
|
||||||
super.key,
|
super.key,
|
||||||
|
|||||||
@ -14,6 +14,8 @@ import 'package:spotube/provider/spotify/spotify.dart';
|
|||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
class ProfilePage extends HookConsumerWidget {
|
class ProfilePage extends HookConsumerWidget {
|
||||||
|
static const name = "profile";
|
||||||
|
|
||||||
const ProfilePage({super.key});
|
const ProfilePage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -22,13 +22,6 @@ import 'package:spotube/services/connectivity_adapter.dart';
|
|||||||
import 'package:spotube/utils/persisted_state_notifier.dart';
|
import 'package:spotube/utils/persisted_state_notifier.dart';
|
||||||
import 'package:spotube/utils/platform.dart';
|
import 'package:spotube/utils/platform.dart';
|
||||||
|
|
||||||
const rootPaths = {
|
|
||||||
"/": 0,
|
|
||||||
"/search": 1,
|
|
||||||
"/library": 2,
|
|
||||||
"/lyrics": 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
class RootApp extends HookConsumerWidget {
|
class RootApp extends HookConsumerWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
const RootApp({
|
const RootApp({
|
||||||
@ -42,7 +35,6 @@ class RootApp extends HookConsumerWidget {
|
|||||||
final downloader = ref.watch(downloadManagerProvider);
|
final downloader = ref.watch(downloadManagerProvider);
|
||||||
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final location = GoRouterState.of(context).matchedLocation;
|
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
@ -178,32 +170,17 @@ class RootApp extends HookConsumerWidget {
|
|||||||
return null;
|
return null;
|
||||||
}, [backgroundColor]);
|
}, [backgroundColor]);
|
||||||
|
|
||||||
void onSelectIndexChanged(int d) {
|
|
||||||
final invertedRouteMap =
|
|
||||||
rootPaths.map((key, value) => MapEntry(value, key));
|
|
||||||
|
|
||||||
if (context.mounted) {
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
GoRouter.of(context).go(invertedRouteMap[d]!);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignore: deprecated_member_use
|
// ignore: deprecated_member_use
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
onWillPop: () async {
|
onWillPop: () async {
|
||||||
if (rootPaths[location] != 0) {
|
// if (rootPaths[location] != 0) {
|
||||||
onSelectIndexChanged(0);
|
// onSelectIndexChanged(0);
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
body: Sidebar(
|
body: Sidebar(child: child),
|
||||||
selectedIndex: rootPaths[location],
|
|
||||||
onSelectedIndexChanged: onSelectIndexChanged,
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
extendBody: true,
|
extendBody: true,
|
||||||
drawerScrimColor: Colors.transparent,
|
drawerScrimColor: Colors.transparent,
|
||||||
endDrawer: kIsDesktop
|
endDrawer: kIsDesktop
|
||||||
@ -237,10 +214,7 @@ class RootApp extends HookConsumerWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
BottomPlayer(),
|
BottomPlayer(),
|
||||||
SpotubeNavigationBar(
|
const SpotubeNavigationBar(),
|
||||||
selectedIndex: rootPaths[location],
|
|
||||||
onSelectedIndexChanged: onSelectIndexChanged,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:flutter/material.dart' hide Page;
|
|||||||
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:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
@ -26,6 +27,8 @@ import 'package:spotube/services/kv_store/kv_store.dart';
|
|||||||
import 'package:spotube/utils/platform.dart';
|
import 'package:spotube/utils/platform.dart';
|
||||||
|
|
||||||
class SearchPage extends HookConsumerWidget {
|
class SearchPage extends HookConsumerWidget {
|
||||||
|
static const name = "search";
|
||||||
|
|
||||||
const SearchPage({super.key});
|
const SearchPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -85,99 +88,117 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
return SafeArea(
|
return SafeArea(
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: kIsDesktop && !kIsMacOS ? const PageWindowTitleBar() : null,
|
appBar: kIsDesktop && !kIsMacOS
|
||||||
|
? const PageWindowTitleBar(automaticallyImplyLeading: true)
|
||||||
|
: null,
|
||||||
body: !authenticationNotifier.isLoggedIn
|
body: !authenticationNotifier.isLoggedIn
|
||||||
? const AnonymousFallback()
|
? const AnonymousFallback()
|
||||||
: Column(
|
: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Row(
|
||||||
padding: const EdgeInsets.symmetric(
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
horizontal: 20,
|
children: [
|
||||||
vertical: 10,
|
if ((kIsMobile || kIsMacOS) && context.canPop())
|
||||||
),
|
const BackButton()
|
||||||
color: theme.scaffoldBackgroundColor,
|
else
|
||||||
child: SearchAnchor(
|
const Gap(20),
|
||||||
searchController: controller,
|
Expanded(
|
||||||
viewBuilder: (_) => HookBuilder(builder: (context) {
|
child: Padding(
|
||||||
final searchController = useListenable(controller);
|
padding: const EdgeInsets.only(
|
||||||
final update = useForceUpdate();
|
right: 20,
|
||||||
final suggestions = searchController.text.isEmpty
|
top: 20,
|
||||||
? KVStoreService.recentSearches
|
bottom: 20,
|
||||||
: KVStoreService.recentSearches
|
),
|
||||||
.where(
|
child: SearchAnchor(
|
||||||
(s) =>
|
searchController: controller,
|
||||||
weightedRatio(
|
viewBuilder: (_) => HookBuilder(builder: (context) {
|
||||||
s.toLowerCase(),
|
final searchController =
|
||||||
searchController.text.toLowerCase(),
|
useListenable(controller);
|
||||||
) >
|
final update = useForceUpdate();
|
||||||
50,
|
final suggestions = searchController.text.isEmpty
|
||||||
)
|
? KVStoreService.recentSearches
|
||||||
.toList();
|
: KVStoreService.recentSearches
|
||||||
|
.where(
|
||||||
|
(s) =>
|
||||||
|
weightedRatio(
|
||||||
|
s.toLowerCase(),
|
||||||
|
searchController.text
|
||||||
|
.toLowerCase(),
|
||||||
|
) >
|
||||||
|
50,
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
itemCount: suggestions.length,
|
itemCount: suggestions.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final suggestion = suggestions[index];
|
final suggestion = suggestions[index];
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: const Icon(SpotubeIcons.history),
|
leading: const Icon(SpotubeIcons.history),
|
||||||
title: Text(suggestion),
|
title: Text(suggestion),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
icon: const Icon(SpotubeIcons.trash),
|
icon: const Icon(SpotubeIcons.trash),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
KVStoreService.setRecentSearches(
|
KVStoreService.setRecentSearches(
|
||||||
KVStoreService.recentSearches
|
KVStoreService.recentSearches
|
||||||
.where((s) => s != suggestion)
|
.where((s) => s != suggestion)
|
||||||
.toList(),
|
.toList(),
|
||||||
|
);
|
||||||
|
update();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
controller.closeView(suggestion);
|
||||||
|
ref
|
||||||
|
.read(
|
||||||
|
searchTermStateProvider.notifier)
|
||||||
|
.state = suggestion;
|
||||||
|
},
|
||||||
);
|
);
|
||||||
update();
|
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
onTap: () {
|
}),
|
||||||
controller.closeView(suggestion);
|
suggestionsBuilder: (context, controller) {
|
||||||
ref
|
return [];
|
||||||
.read(searchTermStateProvider.notifier)
|
},
|
||||||
.state = suggestion;
|
viewOnSubmitted: (value) async {
|
||||||
},
|
controller.closeView(value);
|
||||||
);
|
Timer(
|
||||||
},
|
const Duration(milliseconds: 50),
|
||||||
);
|
() {
|
||||||
}),
|
ref
|
||||||
suggestionsBuilder: (context, controller) {
|
.read(searchTermStateProvider.notifier)
|
||||||
return [];
|
.state = value;
|
||||||
},
|
if (value.trim().isEmpty) {
|
||||||
viewOnSubmitted: (value) async {
|
return;
|
||||||
controller.closeView(value);
|
}
|
||||||
Timer(
|
KVStoreService.setRecentSearches(
|
||||||
const Duration(milliseconds: 50),
|
{
|
||||||
() {
|
value,
|
||||||
ref.read(searchTermStateProvider.notifier).state =
|
...KVStoreService.recentSearches,
|
||||||
value;
|
}.toList(),
|
||||||
if (value.trim().isEmpty) {
|
);
|
||||||
return;
|
},
|
||||||
}
|
);
|
||||||
KVStoreService.setRecentSearches(
|
},
|
||||||
{
|
builder: (context, controller) {
|
||||||
value,
|
return SearchBar(
|
||||||
...KVStoreService.recentSearches,
|
autoFocus: queries.none((s) =>
|
||||||
}.toList(),
|
s.asData?.value != null &&
|
||||||
);
|
!s.hasError) &&
|
||||||
},
|
!kIsMobile,
|
||||||
);
|
controller: controller,
|
||||||
},
|
leading: const Icon(SpotubeIcons.search),
|
||||||
builder: (context, controller) {
|
hintText: "${context.l10n.search}...",
|
||||||
return SearchBar(
|
onTap: controller.openView,
|
||||||
autoFocus: queries.none((s) =>
|
onChanged: (_) => controller.openView(),
|
||||||
s.asData?.value != null && !s.hasError) &&
|
);
|
||||||
!kIsMobile,
|
},
|
||||||
controller: controller,
|
),
|
||||||
leading: const Icon(SpotubeIcons.search),
|
),
|
||||||
hintText: "${context.l10n.search}...",
|
),
|
||||||
onTap: controller.openView,
|
],
|
||||||
onChanged: (_) => controller.openView(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: AnimatedSwitcher(
|
child: AnimatedSwitcher(
|
||||||
|
|||||||
@ -16,6 +16,8 @@ final _licenseProvider = FutureProvider<String>((ref) async {
|
|||||||
});
|
});
|
||||||
|
|
||||||
class AboutSpotube extends HookConsumerWidget {
|
class AboutSpotube extends HookConsumerWidget {
|
||||||
|
static const name = "about";
|
||||||
|
|
||||||
const AboutSpotube({super.key});
|
const AboutSpotube({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -11,6 +11,8 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/provider/blacklist_provider.dart';
|
import 'package:spotube/provider/blacklist_provider.dart';
|
||||||
|
|
||||||
class BlackListPage extends HookConsumerWidget {
|
class BlackListPage extends HookConsumerWidget {
|
||||||
|
static const name = "blacklist";
|
||||||
|
|
||||||
const BlackListPage({super.key});
|
const BlackListPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -11,6 +11,8 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/models/logger.dart';
|
import 'package:spotube/models/logger.dart';
|
||||||
|
|
||||||
class LogsPage extends HookWidget {
|
class LogsPage extends HookWidget {
|
||||||
|
static const name = "logs";
|
||||||
|
|
||||||
const LogsPage({super.key});
|
const LogsPage({super.key});
|
||||||
|
|
||||||
List<({DateTime? date, String body})> parseLogs(String raw) {
|
List<({DateTime? date, String body})> parseLogs(String raw) {
|
||||||
|
|||||||
@ -16,6 +16,8 @@ import 'package:spotube/provider/user_preferences/user_preferences_provider.dart
|
|||||||
import 'package:spotube/utils/platform.dart';
|
import 'package:spotube/utils/platform.dart';
|
||||||
|
|
||||||
class SettingsPage extends HookConsumerWidget {
|
class SettingsPage extends HookConsumerWidget {
|
||||||
|
static const name = "settings";
|
||||||
|
|
||||||
const SettingsPage({super.key});
|
const SettingsPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
13
lib/pages/stats/stats.dart
Normal file
13
lib/pages/stats/stats.dart
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
|
class StatsPage extends HookConsumerWidget {
|
||||||
|
static const name = "stats";
|
||||||
|
|
||||||
|
const StatsPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, ref) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -21,6 +21,8 @@ import 'package:spotube/services/audio_player/audio_player.dart';
|
|||||||
import 'package:spotube/extensions/constrains.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
|
|
||||||
class TrackPage extends HookConsumerWidget {
|
class TrackPage extends HookConsumerWidget {
|
||||||
|
static const name = "track";
|
||||||
|
|
||||||
final String trackId;
|
final String trackId;
|
||||||
const TrackPage({
|
const TrackPage({
|
||||||
super.key,
|
super.key,
|
||||||
|
|||||||
@ -262,6 +262,22 @@ abstract class ServiceUtils {
|
|||||||
GoRouter.of(context).go(location, extra: extra);
|
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}) {
|
static void push(BuildContext context, String location, {Object? extra}) {
|
||||||
final router = GoRouter.of(context);
|
final router = GoRouter.of(context);
|
||||||
final routerState = GoRouterState.of(context);
|
final routerState = GoRouterState.of(context);
|
||||||
@ -273,6 +289,36 @@ abstract class ServiceUtils {
|
|||||||
router.push(location, extra: extra);
|
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) {
|
static DateTime parseSpotifyAlbumDate(AlbumSimple? album) {
|
||||||
if (album == null || album.releaseDate == null) {
|
if (album == null || album.releaseDate == null) {
|
||||||
return DateTime.parse("1975-01-01");
|
return DateTime.parse("1975-01-01");
|
||||||
|
|||||||
@ -1 +1,89 @@
|
|||||||
{}
|
{
|
||||||
|
"ar": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"bn": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ca": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"cs": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"de": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"es": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"fa": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"fr": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"hi": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"it": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ja": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ko": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ne": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"nl": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"pl": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"pt": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ru": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"th": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"tr": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"uk": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"vi": [
|
||||||
|
"stats"
|
||||||
|
],
|
||||||
|
|
||||||
|
"zh": [
|
||||||
|
"stats"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user