mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
refactor: use expanded sidebar tiles for library
This commit is contained in:
parent
2411f46877
commit
6e357230ac
11
.vscode/launch.json
vendored
11
.vscode/launch.json
vendored
@ -30,6 +30,17 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "lib/main.dart",
|
"program": "lib/main.dart",
|
||||||
"flutterMode": "release"
|
"flutterMode": "release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spotube (mobile) (release)",
|
||||||
|
"type": "dart",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "lib/main.dart",
|
||||||
|
"flutterMode": "release",
|
||||||
|
"args": [
|
||||||
|
"--flavor",
|
||||||
|
"dev"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"compounds": []
|
"compounds": []
|
||||||
|
@ -7,7 +7,11 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:spotube/collections/routes.dart';
|
import 'package:spotube/collections/routes.dart';
|
||||||
import 'package:spotube/modules/player/player_controls.dart';
|
import 'package:spotube/modules/player/player_controls.dart';
|
||||||
import 'package:spotube/pages/home/home.dart';
|
import 'package:spotube/pages/home/home.dart';
|
||||||
import 'package:spotube/pages/library/library.dart';
|
import 'package:spotube/pages/library/user_albums.dart';
|
||||||
|
import 'package:spotube/pages/library/user_artists.dart';
|
||||||
|
import 'package:spotube/pages/library/user_downloads.dart';
|
||||||
|
import 'package:spotube/pages/library/user_local_tracks.dart';
|
||||||
|
import 'package:spotube/pages/library/user_playlists.dart';
|
||||||
import 'package:spotube/pages/lyrics/lyrics.dart';
|
import 'package:spotube/pages/lyrics/lyrics.dart';
|
||||||
import 'package:spotube/pages/search/search.dart';
|
import 'package:spotube/pages/search/search.dart';
|
||||||
import 'package:spotube/provider/audio_player/querying_track_info.dart';
|
import 'package:spotube/provider/audio_player/querying_track_info.dart';
|
||||||
@ -52,8 +56,13 @@ class NavigationAction extends Action<NavigationIntent> {
|
|||||||
enum HomeTabs {
|
enum HomeTabs {
|
||||||
browse,
|
browse,
|
||||||
search,
|
search,
|
||||||
library,
|
|
||||||
lyrics,
|
lyrics,
|
||||||
|
userPlaylists,
|
||||||
|
userArtists,
|
||||||
|
userAlbums,
|
||||||
|
userLocalLibrary,
|
||||||
|
userDownloads,
|
||||||
}
|
}
|
||||||
|
|
||||||
class HomeTabIntent extends Intent {
|
class HomeTabIntent extends Intent {
|
||||||
@ -73,12 +82,24 @@ class HomeTabAction extends Action<HomeTabIntent> {
|
|||||||
case HomeTabs.search:
|
case HomeTabs.search:
|
||||||
router.goNamed(SearchPage.name);
|
router.goNamed(SearchPage.name);
|
||||||
break;
|
break;
|
||||||
case HomeTabs.library:
|
|
||||||
router.goNamed(LibraryPage.name);
|
|
||||||
break;
|
|
||||||
case HomeTabs.lyrics:
|
case HomeTabs.lyrics:
|
||||||
router.goNamed(LyricsPage.name);
|
router.goNamed(LyricsPage.name);
|
||||||
break;
|
break;
|
||||||
|
case HomeTabs.userPlaylists:
|
||||||
|
router.goNamed(UserPlaylistsPage.name);
|
||||||
|
break;
|
||||||
|
case HomeTabs.userArtists:
|
||||||
|
router.goNamed(UserArtistsPage.name);
|
||||||
|
break;
|
||||||
|
case HomeTabs.userAlbums:
|
||||||
|
router.goNamed(UserAlbumsPage.name);
|
||||||
|
break;
|
||||||
|
case HomeTabs.userLocalLibrary:
|
||||||
|
router.goNamed(UserLocalLibraryPage.name);
|
||||||
|
break;
|
||||||
|
case HomeTabs.userDownloads:
|
||||||
|
router.goNamed(UserDownloadsPage.name);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,11 @@ import 'package:spotube/pages/lastfm_login/lastfm_login.dart';
|
|||||||
import 'package:spotube/pages/library/local_folder.dart';
|
import 'package:spotube/pages/library/local_folder.dart';
|
||||||
import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart';
|
import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart';
|
||||||
import 'package:spotube/pages/library/playlist_generate/playlist_generate_result.dart';
|
import 'package:spotube/pages/library/playlist_generate/playlist_generate_result.dart';
|
||||||
|
import 'package:spotube/pages/library/user_albums.dart';
|
||||||
|
import 'package:spotube/pages/library/user_artists.dart';
|
||||||
|
import 'package:spotube/pages/library/user_downloads.dart';
|
||||||
|
import 'package:spotube/pages/library/user_local_tracks.dart';
|
||||||
|
import 'package:spotube/pages/library/user_playlists.dart';
|
||||||
import 'package:spotube/pages/lyrics/mini_lyrics.dart';
|
import 'package:spotube/pages/lyrics/mini_lyrics.dart';
|
||||||
import 'package:spotube/pages/playlist/liked_playlist.dart';
|
import 'package:spotube/pages/playlist/liked_playlist.dart';
|
||||||
import 'package:spotube/pages/playlist/playlist.dart';
|
import 'package:spotube/pages/playlist/playlist.dart';
|
||||||
@ -99,45 +104,73 @@ final routerProvider = Provider((ref) {
|
|||||||
pageBuilder: (context, state) =>
|
pageBuilder: (context, state) =>
|
||||||
const SpotubePage(child: SearchPage()),
|
const SpotubePage(child: SearchPage()),
|
||||||
),
|
),
|
||||||
|
ShellRoute(
|
||||||
|
pageBuilder: (context, state, child) =>
|
||||||
|
SpotubePage(child: LibraryPage(child: child)),
|
||||||
|
routes: [
|
||||||
|
GoRoute(
|
||||||
|
path: "/library/playlists",
|
||||||
|
name: UserPlaylistsPage.name,
|
||||||
|
pageBuilder: (context, state) =>
|
||||||
|
const SpotubePage(child: UserPlaylistsPage()),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: "/library/artists",
|
||||||
|
name: UserArtistsPage.name,
|
||||||
|
pageBuilder: (context, state) =>
|
||||||
|
const SpotubePage(child: UserArtistsPage()),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: "/library/album",
|
||||||
|
name: UserAlbumsPage.name,
|
||||||
|
pageBuilder: (context, state) =>
|
||||||
|
const SpotubePage(child: UserAlbumsPage()),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: "/library/local",
|
||||||
|
name: UserLocalLibraryPage.name,
|
||||||
|
pageBuilder: (context, state) =>
|
||||||
|
const SpotubePage(child: UserLocalLibraryPage()),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: "/library/downloads",
|
||||||
|
name: UserDownloadsPage.name,
|
||||||
|
pageBuilder: (context, state) =>
|
||||||
|
const SpotubePage(child: UserDownloadsPage()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/library",
|
path: "/library/generate",
|
||||||
name: LibraryPage.name,
|
name: PlaylistGeneratorPage.name,
|
||||||
pageBuilder: (context, state) =>
|
pageBuilder: (context, state) =>
|
||||||
const SpotubePage(child: LibraryPage()),
|
const SpotubePage(child: PlaylistGeneratorPage()),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "generate",
|
path: "result",
|
||||||
name: PlaylistGeneratorPage.name,
|
name: PlaylistGenerateResultPage.name,
|
||||||
pageBuilder: (context, state) =>
|
pageBuilder: (context, state) => SpotubePage(
|
||||||
const SpotubePage(child: PlaylistGeneratorPage()),
|
child: PlaylistGenerateResultPage(
|
||||||
routes: [
|
state: state.extra as GeneratePlaylistProviderInput,
|
||||||
GoRoute(
|
),
|
||||||
path: "result",
|
|
||||||
name: PlaylistGenerateResultPage.name,
|
|
||||||
pageBuilder: (context, state) => SpotubePage(
|
|
||||||
child: PlaylistGenerateResultPage(
|
|
||||||
state: state.extra as GeneratePlaylistProviderInput,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
GoRoute(
|
)
|
||||||
path: "local",
|
],
|
||||||
name: LocalLibraryPage.name,
|
),
|
||||||
pageBuilder: (context, state) {
|
GoRoute(
|
||||||
assert(state.extra is String);
|
path: "/library/local",
|
||||||
return SpotubePage(
|
name: LocalLibraryPage.name,
|
||||||
child: LocalLibraryPage(
|
pageBuilder: (context, state) {
|
||||||
state.extra as String,
|
assert(state.extra is String);
|
||||||
isDownloads:
|
return SpotubePage(
|
||||||
state.uri.queryParameters["downloads"] != null,
|
child: LocalLibraryPage(
|
||||||
isCache: state.uri.queryParameters["cache"] != null,
|
state.extra as String,
|
||||||
),
|
isDownloads: state.uri.queryParameters["downloads"] != null,
|
||||||
);
|
isCache: state.uri.queryParameters["cache"] != null,
|
||||||
},
|
|
||||||
),
|
),
|
||||||
]),
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: "/lyrics",
|
path: "/lyrics",
|
||||||
name: LyricsPage.name,
|
name: LyricsPage.name,
|
||||||
|
@ -2,7 +2,10 @@ 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/home/home.dart';
|
||||||
import 'package:spotube/pages/library/library.dart';
|
import 'package:spotube/pages/library/user_albums.dart';
|
||||||
|
import 'package:spotube/pages/library/user_artists.dart';
|
||||||
|
import 'package:spotube/pages/library/user_local_tracks.dart';
|
||||||
|
import 'package:spotube/pages/library/user_playlists.dart';
|
||||||
import 'package:spotube/pages/lyrics/lyrics.dart';
|
import 'package:spotube/pages/lyrics/lyrics.dart';
|
||||||
import 'package:spotube/pages/search/search.dart';
|
import 'package:spotube/pages/search/search.dart';
|
||||||
import 'package:spotube/pages/stats/stats.dart';
|
import 'package:spotube/pages/stats/stats.dart';
|
||||||
@ -34,12 +37,6 @@ List<SideBarTiles> getSidebarTileList(AppLocalizations l10n) => [
|
|||||||
icon: SpotubeIcons.search,
|
icon: SpotubeIcons.search,
|
||||||
title: l10n.search,
|
title: l10n.search,
|
||||||
),
|
),
|
||||||
SideBarTiles(
|
|
||||||
id: "library",
|
|
||||||
name: LibraryPage.name,
|
|
||||||
icon: SpotubeIcons.library,
|
|
||||||
title: l10n.library,
|
|
||||||
),
|
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "lyrics",
|
id: "lyrics",
|
||||||
name: LyricsPage.name,
|
name: LyricsPage.name,
|
||||||
@ -54,6 +51,33 @@ List<SideBarTiles> getSidebarTileList(AppLocalizations l10n) => [
|
|||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
List<SideBarTiles> getSidebarLibraryTileList(AppLocalizations l10n) => [
|
||||||
|
SideBarTiles(
|
||||||
|
id: "playlists",
|
||||||
|
title: l10n.playlists,
|
||||||
|
name: UserPlaylistsPage.name,
|
||||||
|
icon: SpotubeIcons.playlist,
|
||||||
|
),
|
||||||
|
SideBarTiles(
|
||||||
|
id: "artists",
|
||||||
|
title: l10n.artists,
|
||||||
|
name: UserArtistsPage.name,
|
||||||
|
icon: SpotubeIcons.artist,
|
||||||
|
),
|
||||||
|
SideBarTiles(
|
||||||
|
id: "albums",
|
||||||
|
title: l10n.albums,
|
||||||
|
name: UserAlbumsPage.name,
|
||||||
|
icon: SpotubeIcons.album,
|
||||||
|
),
|
||||||
|
SideBarTiles(
|
||||||
|
id: "local_library",
|
||||||
|
title: l10n.local_library,
|
||||||
|
name: UserLocalLibraryPage.name,
|
||||||
|
icon: SpotubeIcons.device,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
List<SideBarTiles> getNavbarTileList(AppLocalizations l10n) => [
|
List<SideBarTiles> getNavbarTileList(AppLocalizations l10n) => [
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "browse",
|
id: "browse",
|
||||||
@ -69,7 +93,7 @@ List<SideBarTiles> getNavbarTileList(AppLocalizations l10n) => [
|
|||||||
),
|
),
|
||||||
SideBarTiles(
|
SideBarTiles(
|
||||||
id: "library",
|
id: "library",
|
||||||
name: LibraryPage.name,
|
name: UserPlaylistsPage.name,
|
||||||
icon: SpotubeIcons.library,
|
icon: SpotubeIcons.library,
|
||||||
title: l10n.library,
|
title: l10n.library,
|
||||||
),
|
),
|
||||||
|
@ -37,6 +37,7 @@ abstract class SpotubeIcons {
|
|||||||
static const share = FeatherIcons.share2;
|
static const share = FeatherIcons.share2;
|
||||||
static const playlistAdd = Icons.playlist_add_rounded;
|
static const playlistAdd = Icons.playlist_add_rounded;
|
||||||
static const playlistRemove = Icons.playlist_remove_rounded;
|
static const playlistRemove = Icons.playlist_remove_rounded;
|
||||||
|
static const playlist = Icons.playlist_play_rounded;
|
||||||
static const trash = FeatherIcons.trash2;
|
static const trash = FeatherIcons.trash2;
|
||||||
static const clock = FeatherIcons.clock;
|
static const clock = FeatherIcons.clock;
|
||||||
static const lyrics = Icons.lyrics_rounded;
|
static const lyrics = Icons.lyrics_rounded;
|
||||||
@ -132,4 +133,5 @@ abstract class SpotubeIcons {
|
|||||||
static const radioUnchecked = Icons.radio_button_off_rounded;
|
static const radioUnchecked = Icons.radio_button_off_rounded;
|
||||||
static const grid = FeatherIcons.grid;
|
static const grid = FeatherIcons.grid;
|
||||||
static const list = FeatherIcons.list;
|
static const list = FeatherIcons.list;
|
||||||
|
static const device = FeatherIcons.smartphone;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import 'package:collection/collection.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:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/modules/library/user_local_tracks.dart';
|
import 'package:spotube/pages/library/user_local_tracks.dart';
|
||||||
import 'package:spotube/provider/spotify/spotify.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
import 'package:spotube/utils/service_utils.dart';
|
import 'package:spotube/utils/service_utils.dart';
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
import 'package:spotube/collections/spotube_icons.dart';
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
import 'package:spotube/modules/library/user_local_tracks.dart';
|
import 'package:spotube/pages/library/user_local_tracks.dart';
|
||||||
import 'package:spotube/components/adaptive/adaptive_pop_sheet_list.dart';
|
import 'package:spotube/components/adaptive/adaptive_pop_sheet_list.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
|
|
||||||
|
@ -264,12 +264,32 @@ class Spotube extends HookConsumerWidget {
|
|||||||
LogicalKeyboardKey.digit3,
|
LogicalKeyboardKey.digit3,
|
||||||
LogicalKeyboardKey.control,
|
LogicalKeyboardKey.control,
|
||||||
LogicalKeyboardKey.shift,
|
LogicalKeyboardKey.shift,
|
||||||
): HomeTabIntent(ref, tab: HomeTabs.library),
|
): HomeTabIntent(ref, tab: HomeTabs.lyrics),
|
||||||
LogicalKeySet(
|
LogicalKeySet(
|
||||||
LogicalKeyboardKey.digit4,
|
LogicalKeyboardKey.digit4,
|
||||||
LogicalKeyboardKey.control,
|
LogicalKeyboardKey.control,
|
||||||
LogicalKeyboardKey.shift,
|
LogicalKeyboardKey.shift,
|
||||||
): HomeTabIntent(ref, tab: HomeTabs.lyrics),
|
): HomeTabIntent(ref, tab: HomeTabs.userPlaylists),
|
||||||
|
LogicalKeySet(
|
||||||
|
LogicalKeyboardKey.digit5,
|
||||||
|
LogicalKeyboardKey.control,
|
||||||
|
LogicalKeyboardKey.shift,
|
||||||
|
): HomeTabIntent(ref, tab: HomeTabs.userArtists),
|
||||||
|
LogicalKeySet(
|
||||||
|
LogicalKeyboardKey.digit6,
|
||||||
|
LogicalKeyboardKey.control,
|
||||||
|
LogicalKeyboardKey.shift,
|
||||||
|
): HomeTabIntent(ref, tab: HomeTabs.userAlbums),
|
||||||
|
LogicalKeySet(
|
||||||
|
LogicalKeyboardKey.digit7,
|
||||||
|
LogicalKeyboardKey.control,
|
||||||
|
LogicalKeyboardKey.shift,
|
||||||
|
): HomeTabIntent(ref, tab: HomeTabs.userLocalLibrary),
|
||||||
|
LogicalKeySet(
|
||||||
|
LogicalKeyboardKey.digit8,
|
||||||
|
LogicalKeyboardKey.control,
|
||||||
|
LogicalKeyboardKey.shift,
|
||||||
|
): HomeTabIntent(ref, tab: HomeTabs.userDownloads),
|
||||||
LogicalKeySet(
|
LogicalKeySet(
|
||||||
LogicalKeyboardKey.keyW,
|
LogicalKeyboardKey.keyW,
|
||||||
LogicalKeyboardKey.control,
|
LogicalKeyboardKey.control,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
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/spotube_icons.dart';
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/pages/connect/connect.dart';
|
import 'package:spotube/pages/connect/connect.dart';
|
||||||
import 'package:spotube/provider/connect/clients.dart';
|
import 'package:spotube/provider/connect/clients.dart';
|
||||||
@ -19,6 +20,17 @@ class ConnectDeviceButton extends HookConsumerWidget {
|
|||||||
connectClients.asData?.value.services.isNotEmpty == true;
|
connectClients.asData?.value.services.isNotEmpty == true;
|
||||||
|
|
||||||
if (_sidebar) {
|
if (_sidebar) {
|
||||||
|
final mediaQuery = MediaQuery.sizeOf(context);
|
||||||
|
|
||||||
|
if (mediaQuery.mdAndDown) {
|
||||||
|
return IconButton.ghost(
|
||||||
|
icon: const Icon(SpotubeIcons.speaker),
|
||||||
|
onPressed: () {
|
||||||
|
ServiceUtils.pushNamed(context, ConnectPage.name);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: Button.primary(
|
child: Button.primary(
|
||||||
|
@ -3,7 +3,6 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.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:spotube/collections/assets.gen.dart';
|
import 'package:spotube/collections/assets.gen.dart';
|
||||||
import 'package:spotube/collections/side_bar_tiles.dart';
|
import 'package:spotube/collections/side_bar_tiles.dart';
|
||||||
@ -14,6 +13,7 @@ import 'package:spotube/models/database/database.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/modules/connect/connect_device.dart';
|
import 'package:spotube/modules/connect/connect_device.dart';
|
||||||
|
import 'package:spotube/pages/library/user_downloads.dart';
|
||||||
import 'package:spotube/pages/profile/profile.dart';
|
import 'package:spotube/pages/profile/profile.dart';
|
||||||
import 'package:spotube/pages/settings/settings.dart';
|
import 'package:spotube/pages/settings/settings.dart';
|
||||||
import 'package:spotube/provider/authentication/authentication.dart';
|
import 'package:spotube/provider/authentication/authentication.dart';
|
||||||
@ -47,8 +47,6 @@ class Sidebar extends HookConsumerWidget {
|
|||||||
final routerState = GoRouterState.of(context);
|
final routerState = GoRouterState.of(context);
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
|
|
||||||
final downloadCount = ref.watch(downloadManagerProvider).$downloadCount;
|
|
||||||
|
|
||||||
final layoutMode =
|
final layoutMode =
|
||||||
ref.watch(userPreferencesProvider.select((s) => s.layoutMode));
|
ref.watch(userPreferencesProvider.select((s) => s.layoutMode));
|
||||||
|
|
||||||
@ -57,7 +55,14 @@ class Sidebar extends HookConsumerWidget {
|
|||||||
[context.l10n],
|
[context.l10n],
|
||||||
);
|
);
|
||||||
|
|
||||||
final selectedIndex = sidebarTileList.indexWhere(
|
final sidebarLibraryTileList = useMemoized(
|
||||||
|
() => getSidebarLibraryTileList(context.l10n),
|
||||||
|
[context.l10n],
|
||||||
|
);
|
||||||
|
|
||||||
|
final tileList = [...sidebarTileList, ...sidebarLibraryTileList];
|
||||||
|
|
||||||
|
final selectedIndex = tileList.indexWhere(
|
||||||
(e) => routerState.namedLocation(e.name) == routerState.matchedLocation,
|
(e) => routerState.namedLocation(e.name) == routerState.matchedLocation,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -73,16 +78,8 @@ class Sidebar extends HookConsumerWidget {
|
|||||||
for (final tile in sidebarTileList)
|
for (final tile in sidebarTileList)
|
||||||
NavigationButton(
|
NavigationButton(
|
||||||
label: mediaQuery.lgAndUp ? Text(tile.title) : null,
|
label: mediaQuery.lgAndUp ? Text(tile.title) : null,
|
||||||
child: Badge(
|
child: Tooltip(
|
||||||
backgroundColor: context.theme.colorScheme.primary,
|
tooltip: TooltipContainer(child: Text(tile.title)),
|
||||||
isLabelVisible: tile.title == "Library" && downloadCount > 0,
|
|
||||||
label: Text(
|
|
||||||
downloadCount.toString(),
|
|
||||||
style: TextStyle(
|
|
||||||
color: context.theme.colorScheme.primaryForeground,
|
|
||||||
fontSize: 10,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Icon(tile.icon),
|
child: Icon(tile.icon),
|
||||||
),
|
),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
@ -91,6 +88,22 @@ class Sidebar extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
const NavigationDivider(),
|
||||||
|
if (mediaQuery.lgAndUp)
|
||||||
|
NavigationLabel(child: Text(context.l10n.library)),
|
||||||
|
for (final tile in sidebarLibraryTileList)
|
||||||
|
NavigationButton(
|
||||||
|
label: mediaQuery.lgAndUp ? Text(tile.title) : null,
|
||||||
|
onChanged: (value) {
|
||||||
|
if (value) {
|
||||||
|
context.goNamed(tile.name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Tooltip(
|
||||||
|
tooltip: TooltipContainer(child: Text(tile.title)),
|
||||||
|
child: Icon(tile.icon),
|
||||||
|
),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
@ -103,7 +116,7 @@ class Sidebar extends HookConsumerWidget {
|
|||||||
? NavigationSidebar(
|
? NavigationSidebar(
|
||||||
index: selectedIndex,
|
index: selectedIndex,
|
||||||
onSelected: (index) {
|
onSelected: (index) {
|
||||||
final tile = sidebarTileList[index];
|
final tile = tileList[index];
|
||||||
context.goNamed(tile.name);
|
context.goNamed(tile.name);
|
||||||
},
|
},
|
||||||
children: navigationButtons,
|
children: navigationButtons,
|
||||||
@ -112,7 +125,7 @@ class Sidebar extends HookConsumerWidget {
|
|||||||
alignment: NavigationRailAlignment.start,
|
alignment: NavigationRailAlignment.start,
|
||||||
index: selectedIndex,
|
index: selectedIndex,
|
||||||
onSelected: (index) {
|
onSelected: (index) {
|
||||||
final tile = sidebarTileList[index];
|
final tile = tileList[index];
|
||||||
context.goNamed(tile.name);
|
context.goNamed(tile.name);
|
||||||
},
|
},
|
||||||
children: navigationButtons,
|
children: navigationButtons,
|
||||||
@ -138,8 +151,10 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem {
|
|||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
final me = ref.watch(meProvider);
|
final routerState = GoRouterState.of(context);
|
||||||
final data = me.asData?.value;
|
final downloadCount = ref.watch(downloadManagerProvider).$downloadCount;
|
||||||
|
final userSnapshot = ref.watch(meProvider);
|
||||||
|
final data = userSnapshot.asData?.value;
|
||||||
|
|
||||||
final avatarImg = (data?.images).asUrlString(
|
final avatarImg = (data?.images).asUrlString(
|
||||||
index: (data?.images?.length ?? 1) - 1,
|
index: (data?.images?.length ?? 1) - 1,
|
||||||
@ -149,10 +164,30 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem {
|
|||||||
final auth = ref.watch(authenticationProvider);
|
final auth = ref.watch(authenticationProvider);
|
||||||
|
|
||||||
if (mediaQuery.mdAndDown) {
|
if (mediaQuery.mdAndDown) {
|
||||||
return IconButton(
|
return Column(
|
||||||
variance: ButtonVariance.ghost,
|
mainAxisSize: MainAxisSize.min,
|
||||||
icon: const Icon(SpotubeIcons.settings),
|
spacing: 10,
|
||||||
onPressed: () => ServiceUtils.navigateNamed(context, SettingsPage.name),
|
children: [
|
||||||
|
Badge(
|
||||||
|
isLabelVisible: downloadCount > 0,
|
||||||
|
label: Text(downloadCount.toString()),
|
||||||
|
child: IconButton(
|
||||||
|
variance: routerState.topRoute?.name == UserDownloadsPage.name
|
||||||
|
? ButtonVariance.secondary
|
||||||
|
: ButtonVariance.ghost,
|
||||||
|
icon: const Icon(SpotubeIcons.download),
|
||||||
|
onPressed: () =>
|
||||||
|
ServiceUtils.navigateNamed(context, UserDownloadsPage.name),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const ConnectDeviceButton.sidebar(),
|
||||||
|
IconButton(
|
||||||
|
variance: ButtonVariance.ghost,
|
||||||
|
icon: const Icon(SpotubeIcons.settings),
|
||||||
|
onPressed: () =>
|
||||||
|
ServiceUtils.navigateNamed(context, SettingsPage.name),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,9 +196,27 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem {
|
|||||||
width: 180,
|
width: 180,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
spacing: 10,
|
||||||
children: [
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Button(
|
||||||
|
style: routerState.topRoute?.name == UserDownloadsPage.name
|
||||||
|
? ButtonVariance.secondary
|
||||||
|
: ButtonVariance.outline,
|
||||||
|
onPressed: () {
|
||||||
|
ServiceUtils.navigateNamed(context, UserDownloadsPage.name);
|
||||||
|
},
|
||||||
|
leading: const Icon(SpotubeIcons.download),
|
||||||
|
trailing: downloadCount > 0
|
||||||
|
? PrimaryBadge(
|
||||||
|
child: Text(downloadCount.toString()),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
child: Text(context.l10n.downloads),
|
||||||
|
),
|
||||||
|
),
|
||||||
const ConnectDeviceButton.sidebar(),
|
const ConnectDeviceButton.sidebar(),
|
||||||
const Gap(10),
|
|
||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
@ -34,32 +34,35 @@ class GettingStarting extends HookConsumerWidget {
|
|||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
headers: [
|
headers: [
|
||||||
TitleBar(
|
SafeArea(
|
||||||
backgroundColor: Colors.transparent,
|
child: TitleBar(
|
||||||
surfaceBlur: 0,
|
backgroundColor: Colors.transparent,
|
||||||
trailing: [
|
surfaceBlur: 0,
|
||||||
ListenableBuilder(
|
trailing: [
|
||||||
listenable: pageController,
|
ListenableBuilder(
|
||||||
builder: (context, _) {
|
listenable: pageController,
|
||||||
return AnimatedSwitcher(
|
builder: (context, _) {
|
||||||
duration: const Duration(milliseconds: 300),
|
return AnimatedSwitcher(
|
||||||
child: pageController.hasClients &&
|
duration: const Duration(milliseconds: 300),
|
||||||
(pageController.page == 0 || pageController.page == 3)
|
child: pageController.hasClients &&
|
||||||
? const SizedBox()
|
(pageController.page == 0 ||
|
||||||
: Button.secondary(
|
pageController.page == 3)
|
||||||
onPressed: () {
|
? const SizedBox()
|
||||||
pageController.animateToPage(
|
: Button.secondary(
|
||||||
3,
|
onPressed: () {
|
||||||
duration: const Duration(milliseconds: 300),
|
pageController.animateToPage(
|
||||||
curve: Curves.easeInOut,
|
3,
|
||||||
);
|
duration: const Duration(milliseconds: 300),
|
||||||
},
|
curve: Curves.easeInOut,
|
||||||
child: Text(context.l10n.skip_this_nonsense),
|
);
|
||||||
),
|
},
|
||||||
);
|
child: Text(context.l10n.skip_this_nonsense),
|
||||||
},
|
),
|
||||||
),
|
);
|
||||||
],
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
floatingHeader: true,
|
floatingHeader: true,
|
||||||
|
@ -1,71 +1,63 @@
|
|||||||
import 'package:flutter/material.dart' show Badge;
|
import 'package:flutter/material.dart' show Badge;
|
||||||
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:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
import 'package:spotube/modules/library/user_local_tracks.dart';
|
import 'package:spotube/collections/side_bar_tiles.dart';
|
||||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||||
import 'package:spotube/modules/library/user_albums.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/modules/library/user_artists.dart';
|
|
||||||
import 'package:spotube/modules/library/user_downloads.dart';
|
|
||||||
import 'package:spotube/modules/library/user_playlists.dart';
|
|
||||||
import 'package:spotube/extensions/context.dart';
|
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";
|
final Widget child;
|
||||||
|
const LibraryPage({super.key, required this.child});
|
||||||
|
|
||||||
const LibraryPage({super.key});
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
||||||
final downloadingCount = ref.watch(downloadManagerProvider).$downloadCount;
|
final downloadingCount = ref.watch(downloadManagerProvider).$downloadCount;
|
||||||
final index = useState(0);
|
final routerState = GoRouterState.of(context);
|
||||||
|
final sidebarLibraryTileList = useMemoized(
|
||||||
final children = [
|
() => getSidebarLibraryTileList(context.l10n),
|
||||||
Text(context.l10n.playlists),
|
[context.l10n],
|
||||||
Text(context.l10n.local_tab),
|
);
|
||||||
Badge(
|
final index = sidebarLibraryTileList.indexWhere(
|
||||||
isLabelVisible: downloadingCount > 0,
|
(e) => routerState.namedLocation(e.name) == routerState.matchedLocation,
|
||||||
label: Text(downloadingCount.toString()),
|
);
|
||||||
child: Text(context.l10n.downloads),
|
|
||||||
),
|
|
||||||
Text(context.l10n.artists),
|
|
||||||
Text(context.l10n.albums),
|
|
||||||
];
|
|
||||||
|
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: Scaffold(
|
child: LayoutBuilder(builder: (context, constraints) {
|
||||||
headers: [
|
return Scaffold(
|
||||||
TitleBar(
|
headers: [
|
||||||
child: SingleChildScrollView(
|
if (constraints.smAndDown)
|
||||||
scrollDirection: Axis.horizontal,
|
TitleBar(
|
||||||
child: TabList(
|
child: SingleChildScrollView(
|
||||||
index: index.value,
|
scrollDirection: Axis.horizontal,
|
||||||
children: [
|
child: TabList(
|
||||||
for (final child in children)
|
index: index,
|
||||||
TabButton(
|
children: [
|
||||||
child: child,
|
for (final tile in sidebarLibraryTileList)
|
||||||
onPressed: () {
|
TabButton(
|
||||||
index.value = children.indexOf(child);
|
child: Badge(
|
||||||
},
|
isLabelVisible:
|
||||||
),
|
tile.id == 'downloads' && downloadingCount > 0,
|
||||||
],
|
label: Text(downloadingCount.toString()),
|
||||||
|
child: Text(tile.title),
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
context.goNamed(tile.name);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
const Gap(10),
|
||||||
),
|
|
||||||
const Gap(10),
|
|
||||||
],
|
|
||||||
child: IndexedStack(
|
|
||||||
index: index.value,
|
|
||||||
children: const [
|
|
||||||
UserPlaylists(),
|
|
||||||
UserLocalTracks(),
|
|
||||||
UserDownloads(),
|
|
||||||
UserArtists(),
|
|
||||||
UserAlbums(),
|
|
||||||
],
|
],
|
||||||
),
|
child: child,
|
||||||
),
|
);
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,8 @@ import 'package:spotube/components/button/back_button.dart';
|
|||||||
import 'package:spotube/extensions/constrains.dart';
|
import 'package:spotube/extensions/constrains.dart';
|
||||||
import 'package:spotube/extensions/string.dart';
|
import 'package:spotube/extensions/string.dart';
|
||||||
import 'package:spotube/modules/library/local_folder/cache_export_dialog.dart';
|
import 'package:spotube/modules/library/local_folder/cache_export_dialog.dart';
|
||||||
import 'package:spotube/modules/library/user_local_tracks.dart';
|
import 'package:spotube/pages/library/user_local_tracks.dart';
|
||||||
import 'package:spotube/components/expandable_search/expandable_search.dart';
|
import 'package:spotube/components/expandable_search/expandable_search.dart';
|
||||||
import 'package:spotube/components/fallbacks/not_found.dart';
|
|
||||||
import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart';
|
import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart';
|
||||||
import 'package:spotube/components/titlebar/titlebar.dart';
|
import 'package:spotube/components/titlebar/titlebar.dart';
|
||||||
import 'package:spotube/components/track_presentation/sort_tracks_dropdown.dart';
|
import 'package:spotube/components/track_presentation/sort_tracks_dropdown.dart';
|
||||||
|
@ -16,8 +16,9 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/provider/authentication/authentication.dart';
|
import 'package:spotube/provider/authentication/authentication.dart';
|
||||||
import 'package:spotube/provider/spotify/spotify.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class UserAlbums extends HookConsumerWidget {
|
class UserAlbumsPage extends HookConsumerWidget {
|
||||||
const UserAlbums({super.key});
|
static const name = 'user_albums';
|
||||||
|
const UserAlbumsPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
@ -19,8 +19,9 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/provider/authentication/authentication.dart';
|
import 'package:spotube/provider/authentication/authentication.dart';
|
||||||
import 'package:spotube/provider/spotify/spotify.dart';
|
import 'package:spotube/provider/spotify/spotify.dart';
|
||||||
|
|
||||||
class UserArtists extends HookConsumerWidget {
|
class UserArtistsPage extends HookConsumerWidget {
|
||||||
const UserArtists({super.key});
|
static const name = 'user_artists';
|
||||||
|
const UserArtistsPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
@ -6,8 +6,9 @@ import 'package:spotube/modules/library/user_downloads/download_item.dart';
|
|||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/provider/download_manager_provider.dart';
|
import 'package:spotube/provider/download_manager_provider.dart';
|
||||||
|
|
||||||
class UserDownloads extends HookConsumerWidget {
|
class UserDownloadsPage extends HookConsumerWidget {
|
||||||
const UserDownloads({super.key});
|
static const name = 'user_downloads';
|
||||||
|
const UserDownloadsPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
@ -24,8 +24,9 @@ enum SortBy {
|
|||||||
album,
|
album,
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserLocalTracks extends HookConsumerWidget {
|
class UserLocalLibraryPage extends HookConsumerWidget {
|
||||||
const UserLocalTracks({super.key});
|
static const name = 'user_local_library';
|
||||||
|
const UserLocalLibraryPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
@ -20,8 +20,9 @@ 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 UserPlaylists extends HookConsumerWidget {
|
class UserPlaylistsPage extends HookConsumerWidget {
|
||||||
const UserPlaylists({super.key});
|
static const name = 'user_playlists';
|
||||||
|
const UserPlaylistsPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ref) {
|
Widget build(BuildContext context, ref) {
|
@ -8,7 +8,6 @@ import 'package:spotube/components/titlebar/titlebar.dart';
|
|||||||
import 'package:spotube/components/image/universal_image.dart';
|
import 'package:spotube/components/image/universal_image.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
import 'package:spotube/extensions/context.dart';
|
||||||
import 'package:spotube/extensions/image.dart';
|
import 'package:spotube/extensions/image.dart';
|
||||||
import 'package:spotube/hooks/utils/use_custom_status_bar_color.dart';
|
|
||||||
import 'package:spotube/hooks/utils/use_palette_color.dart';
|
import 'package:spotube/hooks/utils/use_palette_color.dart';
|
||||||
import 'package:spotube/pages/lyrics/plain_lyrics.dart';
|
import 'package:spotube/pages/lyrics/plain_lyrics.dart';
|
||||||
import 'package:spotube/pages/lyrics/synced_lyrics.dart';
|
import 'package:spotube/pages/lyrics/synced_lyrics.dart';
|
||||||
@ -33,15 +32,8 @@ class LyricsPage extends HookConsumerWidget {
|
|||||||
[playlist.activeTrack?.album?.images],
|
[playlist.activeTrack?.album?.images],
|
||||||
);
|
);
|
||||||
final palette = usePaletteColor(albumArt, ref);
|
final palette = usePaletteColor(albumArt, ref);
|
||||||
final route = ModalRoute.of(context);
|
|
||||||
final selectedIndex = useState(0);
|
final selectedIndex = useState(0);
|
||||||
|
|
||||||
final resetStatusBar = useCustomStatusBarColor(
|
|
||||||
palette.color,
|
|
||||||
route?.isCurrent ?? false,
|
|
||||||
noSetBGColor: true,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget tabbar = Padding(
|
Widget tabbar = Padding(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: isModal
|
child: isModal
|
||||||
@ -93,51 +85,47 @@ class LyricsPage extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (isModal) {
|
if (isModal) {
|
||||||
return PopScope(
|
return SafeArea(
|
||||||
canPop: true,
|
bottom: false,
|
||||||
onPopInvokedWithResult: (_, __) => resetStatusBar(),
|
child: SurfaceCard(
|
||||||
child: SafeArea(
|
surfaceBlur: context.theme.surfaceBlur,
|
||||||
bottom: false,
|
surfaceOpacity: context.theme.surfaceOpacity,
|
||||||
child: SurfaceCard(
|
padding: EdgeInsets.zero,
|
||||||
surfaceBlur: context.theme.surfaceBlur,
|
borderRadius: BorderRadius.zero,
|
||||||
surfaceOpacity: context.theme.surfaceOpacity,
|
borderWidth: 0,
|
||||||
padding: EdgeInsets.zero,
|
child: Column(
|
||||||
borderRadius: BorderRadius.zero,
|
children: [
|
||||||
borderWidth: 0,
|
const SizedBox(height: 20),
|
||||||
child: Column(
|
Container(
|
||||||
children: [
|
height: 7,
|
||||||
const SizedBox(height: 5),
|
width: 150,
|
||||||
Container(
|
decoration: BoxDecoration(
|
||||||
height: 7,
|
color: palette.titleTextColor,
|
||||||
width: 150,
|
borderRadius: BorderRadius.circular(10),
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: palette.titleTextColor,
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Row(
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: tabbar,
|
||||||
|
),
|
||||||
|
IconButton.ghost(
|
||||||
|
icon: const Icon(SpotubeIcons.minimize),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 5),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: IndexedStack(
|
||||||
|
index: selectedIndex.value,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
SyncedLyrics(palette: palette, isModal: isModal),
|
||||||
child: tabbar,
|
PlainLyrics(palette: palette, isModal: isModal),
|
||||||
),
|
|
||||||
IconButton.ghost(
|
|
||||||
icon: const Icon(SpotubeIcons.minimize),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 5),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Expanded(
|
),
|
||||||
child: IndexedStack(
|
],
|
||||||
index: selectedIndex.value,
|
|
||||||
children: [
|
|
||||||
SyncedLyrics(palette: palette, isModal: isModal),
|
|
||||||
PlainLyrics(palette: palette, isModal: isModal),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -6,7 +6,7 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:html/dom.dart' hide Text;
|
import 'package:html/dom.dart' hide Text;
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.dart' hide Element;
|
import 'package:shadcn_flutter/shadcn_flutter.dart' hide Element;
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/modules/library/user_local_tracks.dart';
|
import 'package:spotube/pages/library/user_local_tracks.dart';
|
||||||
import 'package:spotube/modules/root/update_dialog.dart';
|
import 'package:spotube/modules/root/update_dialog.dart';
|
||||||
|
|
||||||
import 'package:spotube/models/lyrics.dart';
|
import 'package:spotube/models/lyrics.dart';
|
||||||
|
@ -168,35 +168,35 @@ EXTERNAL SOURCES:
|
|||||||
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a
|
app_links: 9028728e32c83a0831d9db8cf91c526d16cc5468
|
||||||
audio_service: b88ff778e0e3915efd4cd1a5ad6f0beef0c950a9
|
audio_service: 0d9e4e25347bb3efb768f3b9f005911a81e587a7
|
||||||
audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72
|
audio_session: 48ab6500f7a5e7c64363e206565a5dfe5a0c1441
|
||||||
bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842
|
bonsoir_darwin: 29c7ccf356646118844721f36e1de4b61f6cbd0e
|
||||||
connectivity_plus: 18382e7311ba19efcaee94442b23b32507b20695
|
connectivity_plus: 2256d3e20624a7749ed21653aafe291a46446fee
|
||||||
desktop_webview_window: 89bb3d691f4c80314a10be312f4cd35db93a9d5a
|
desktop_webview_window: 2f0cdefecc06e21208a51589bd3d1580a87a703c
|
||||||
device_info_plus: 1b14eed9bf95428983aed283a8d51cce3d8c4215
|
device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76
|
||||||
file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d
|
file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31
|
||||||
flutter_discord_rpc: 67a7c10ea24d9d3bf35d01af643f48fbcfa7c24f
|
flutter_discord_rpc: 90614fcca26f3cebfd33263557ea7875936d184b
|
||||||
flutter_inappwebview_macos: bdf207b8f4ebd58e86ae06cd96b147de99a67c9b
|
flutter_inappwebview_macos: c2d68649f9f8f1831bfcd98d73fd6256366d9d1d
|
||||||
flutter_secure_storage_macos: 59459653abe1adb92abbc8ea747d79f8d19866c9
|
flutter_secure_storage_macos: b2d62a774c23b060f0b99d0173b0b36abb4a8632
|
||||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||||
local_notifier: e9506bc66fc70311e8bc7291fb70f743c081e4ff
|
local_notifier: ebf072651e35ae5e47280ad52e2707375cb2ae4e
|
||||||
media_kit_libs_macos_audio: 3871782a4f3f84c77f04d7666c87800a781c24da
|
media_kit_libs_macos_audio: 06f3cf88d6d89c7c3c87eae57689d1c6adb335b2
|
||||||
media_kit_native_event_loop: 7321675377cb9ae8596a29bddf3a3d2b5e8792c5
|
media_kit_native_event_loop: a5833d1e4d5bedb6f691e9909fa57f15f436f2c8
|
||||||
metadata_god: 829f61208b44ac1173e7cd32ab740d8776be5435
|
metadata_god: 8029e6ff4b1400ae4f13c38d2c478e8633f0e58b
|
||||||
open_file_mac: 0e554648e2a87ce59e9438e3e5ca3e552e90d89a
|
open_file_mac: 01874b6d6a2c1485ac9b126d7105b99102dea2cf
|
||||||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||||
package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c
|
package_info_plus: a8a591e70e87ce97ce5d21b2594f69cea9e0312f
|
||||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||||
screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161
|
screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f
|
||||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
||||||
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
|
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||||
sqlite3: 7559e33dae4c78538df563795af3a86fc887ee71
|
sqlite3: 7559e33dae4c78538df563795af3a86fc887ee71
|
||||||
sqlite3_flutter_libs: 1b4e98da20ebd4e9b1240269b78cdcf492dbe9f3
|
sqlite3_flutter_libs: f0b59f6bb2a18597d0796558725007e5a7428397
|
||||||
system_theme: c7b9f6659a5caa26c9bc2284da096781e9a6fcbc
|
system_theme: ed74293ad07d3a05e3e2d0059ff342360346f1a0
|
||||||
tray_manager: 9064e219c56d75c476e46b9a21182087930baf90
|
tray_manager: a104b5c81b578d83f3c3d0f40a997c8b10810166
|
||||||
url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404
|
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
|
||||||
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
|
window_manager: 1d01fa7ac65a6e6f83b965471b1a7fdd3f06166c
|
||||||
|
|
||||||
PODFILE CHECKSUM: 0d3963a09fc94f580682bd88480486da345dc3f0
|
PODFILE CHECKSUM: 0d3963a09fc94f580682bd88480486da345dc3f0
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user