mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 15:35:17 +00:00
feat: initial platform_ui integration
What's changed: - Sidebar - Settings - UserLibrary (root) - Search (search field)
This commit is contained in:
parent
4b21cc8299
commit
9eee573ce9
@ -84,17 +84,13 @@ class Shell extends HookConsumerWidget {
|
||||
)
|
||||
: null,
|
||||
extendBodyBehindAppBar: true,
|
||||
body: Row(
|
||||
children: [
|
||||
Sidebar(
|
||||
selectedIndex: index.value,
|
||||
onSelectedIndexChanged: (selectedIndex) {
|
||||
index.value = selectedIndex;
|
||||
GoRouter.of(context).go(_path[selectedIndex]!);
|
||||
},
|
||||
),
|
||||
Expanded(child: child),
|
||||
],
|
||||
body: Sidebar(
|
||||
selectedIndex: index.value,
|
||||
onSelectedIndexChanged: (i) {
|
||||
index.value = i;
|
||||
GoRouter.of(context).go(_path[index.value]!);
|
||||
},
|
||||
child: child,
|
||||
),
|
||||
extendBody: true,
|
||||
bottomNavigationBar: Column(
|
||||
|
@ -5,6 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotube/components/Shared/UniversalImage.dart';
|
||||
import 'package:spotube/hooks/useBreakpoints.dart';
|
||||
import 'package:spotube/models/sideBarTiles.dart';
|
||||
@ -15,16 +16,19 @@ import 'package:spotube/provider/SpotifyRequests.dart';
|
||||
import 'package:spotube/provider/UserPreferences.dart';
|
||||
import 'package:spotube/utils/platform.dart';
|
||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||
import 'package:fluent_ui/fluent_ui.dart' as FluentUI;
|
||||
|
||||
final sidebarExtendedStateProvider = StateProvider<bool?>((ref) => null);
|
||||
|
||||
class Sidebar extends HookConsumerWidget {
|
||||
final int selectedIndex;
|
||||
final void Function(int) onSelectedIndexChanged;
|
||||
final Widget child;
|
||||
|
||||
const Sidebar({
|
||||
required this.selectedIndex,
|
||||
required this.onSelectedIndexChanged,
|
||||
required this.child,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@ -45,7 +49,6 @@ class Sidebar extends HookConsumerWidget {
|
||||
final breakpoints = useBreakpoints();
|
||||
final extended = useState(false);
|
||||
|
||||
final auth = ref.watch(authProvider);
|
||||
final downloadCount = ref.watch(
|
||||
downloaderProvider.select((s) => s.currentlyRunning),
|
||||
);
|
||||
@ -81,10 +84,31 @@ class Sidebar extends HookConsumerWidget {
|
||||
|
||||
return SafeArea(
|
||||
top: false,
|
||||
child: Material(
|
||||
color: Theme.of(context).navigationRailTheme.backgroundColor,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
child: PlatformSidebar(
|
||||
currentIndex: selectedIndex,
|
||||
onIndexChanged: onSelectedIndexChanged,
|
||||
body: Map.fromEntries(
|
||||
sidebarTileList.map(
|
||||
(e) {
|
||||
final icon = Icon(e.icon);
|
||||
return MapEntry(
|
||||
PlatformSidebarItem(
|
||||
icon: icon,
|
||||
title: Text(
|
||||
e.title,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
child,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
expanded: extended.value,
|
||||
header: Column(
|
||||
children: [
|
||||
if (kIsDesktop)
|
||||
SizedBox(
|
||||
@ -126,138 +150,120 @@ class Sidebar extends HookConsumerWidget {
|
||||
],
|
||||
)
|
||||
: _buildSmallLogo(),
|
||||
Expanded(
|
||||
child: NavigationRail(
|
||||
destinations: sidebarTileList.map(
|
||||
(e) {
|
||||
final icon = Icon(e.icon);
|
||||
return NavigationRailDestination(
|
||||
icon: e.title == "Library" && downloadCount > 0
|
||||
? Badge(
|
||||
badgeColor: Colors.red[100]!,
|
||||
badgeContent: Text(
|
||||
downloadCount.toString(),
|
||||
style: const TextStyle(
|
||||
color: Colors.red,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
animationType: BadgeAnimationType.fade,
|
||||
child: icon,
|
||||
)
|
||||
: icon,
|
||||
label: Text(
|
||||
e.title,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
selectedIndex: selectedIndex,
|
||||
onDestinationSelected: onSelectedIndexChanged,
|
||||
extended: extended.value,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: extended.value ? 256 : 80,
|
||||
child: HookBuilder(
|
||||
builder: (context) {
|
||||
final me = useQuery(
|
||||
job: currentUserQueryJob,
|
||||
externalData: ref.watch(spotifyProvider),
|
||||
);
|
||||
final data = me.data;
|
||||
|
||||
final avatarImg = TypeConversionUtils.image_X_UrlString(
|
||||
data?.images,
|
||||
index: (data?.images?.length ?? 1) - 1,
|
||||
placeholder: ImagePlaceholder.artist,
|
||||
);
|
||||
|
||||
useEffect(() {
|
||||
if (auth.isLoggedIn && !me.hasData) {
|
||||
me.setExternalData(ref.read(spotifyProvider));
|
||||
me.refetch();
|
||||
}
|
||||
return;
|
||||
}, [auth.isLoggedIn, me.hasData]);
|
||||
|
||||
if (extended.value) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16).copyWith(left: 0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
if (auth.isLoggedIn && data == null)
|
||||
const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
else if (data != null)
|
||||
Flexible(
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
backgroundImage:
|
||||
UniversalImage.imageProvider(
|
||||
avatarImg),
|
||||
onBackgroundImageError:
|
||||
(exception, stackTrace) =>
|
||||
Image.asset(
|
||||
"assets/user-placeholder.png",
|
||||
height: 16,
|
||||
width: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Flexible(
|
||||
child: Text(
|
||||
data.displayName ?? "Guest",
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.settings_outlined),
|
||||
onPressed: () => goToSettings(context)),
|
||||
],
|
||||
));
|
||||
} else {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: InkWell(
|
||||
onTap: () => goToSettings(context),
|
||||
child: CircleAvatar(
|
||||
backgroundImage:
|
||||
UniversalImage.imageProvider(avatarImg),
|
||||
onBackgroundImageError: (exception, stackTrace) =>
|
||||
Image.asset(
|
||||
"assets/user-placeholder.png",
|
||||
height: 16,
|
||||
width: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
windowsFooterItems: [
|
||||
FluentUI.PaneItemAction(
|
||||
icon: const FluentUI.Icon(FluentUI.FluentIcons.settings),
|
||||
onTap: () => goToSettings(context),
|
||||
),
|
||||
],
|
||||
footer: SidebarFooter(extended: extended.value),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SidebarFooter extends HookConsumerWidget {
|
||||
final bool extended;
|
||||
const SidebarFooter({
|
||||
Key? key,
|
||||
required this.extended,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
final auth = ref.watch(authProvider);
|
||||
|
||||
return SizedBox(
|
||||
width: extended ? 256 : 80,
|
||||
child: HookBuilder(
|
||||
builder: (context) {
|
||||
final me = useQuery(
|
||||
job: currentUserQueryJob,
|
||||
externalData: ref.watch(spotifyProvider),
|
||||
);
|
||||
final data = me.data;
|
||||
|
||||
final avatarImg = TypeConversionUtils.image_X_UrlString(
|
||||
data?.images,
|
||||
index: (data?.images?.length ?? 1) - 1,
|
||||
placeholder: ImagePlaceholder.artist,
|
||||
);
|
||||
|
||||
useEffect(() {
|
||||
if (auth.isLoggedIn && !me.hasData) {
|
||||
me.setExternalData(ref.read(spotifyProvider));
|
||||
me.refetch();
|
||||
}
|
||||
return;
|
||||
}, [auth.isLoggedIn, me.hasData]);
|
||||
|
||||
if (extended) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16).copyWith(left: 0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
if (auth.isLoggedIn && data == null)
|
||||
const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
else if (data != null)
|
||||
Flexible(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
backgroundImage:
|
||||
UniversalImage.imageProvider(avatarImg),
|
||||
onBackgroundImageError: (exception, stackTrace) =>
|
||||
Image.asset(
|
||||
"assets/user-placeholder.png",
|
||||
height: 16,
|
||||
width: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Flexible(
|
||||
child: Text(
|
||||
data.displayName ?? "Guest",
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.settings_outlined),
|
||||
onPressed: () => Sidebar.goToSettings(context)),
|
||||
],
|
||||
));
|
||||
} else {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: InkWell(
|
||||
onTap: () => Sidebar.goToSettings(context),
|
||||
child: CircleAvatar(
|
||||
backgroundImage: UniversalImage.imageProvider(avatarImg),
|
||||
onBackgroundImageError: (exception, stackTrace) =>
|
||||
Image.asset(
|
||||
"assets/user-placeholder.png",
|
||||
height: 16,
|
||||
width: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/components/Shared/UniversalImage.dart';
|
||||
import 'package:spotube/provider/Downloader.dart';
|
||||
@ -47,7 +48,7 @@ class UserDownloads extends HookConsumerWidget {
|
||||
itemCount: downloader.inQueue.length,
|
||||
itemBuilder: (context, index) {
|
||||
final track = downloader.inQueue.elementAt(index);
|
||||
return ListTile(
|
||||
return PlatformListTile(
|
||||
title: Text(track.name!),
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5),
|
||||
@ -68,7 +69,6 @@ class UserDownloads extends HookConsumerWidget {
|
||||
height: 30,
|
||||
child: CircularProgressIndicator.adaptive(),
|
||||
),
|
||||
horizontalTitleGap: 5,
|
||||
subtitle: Text(
|
||||
TypeConversionUtils.artists_X_String(
|
||||
track.artists ?? <Artist>[],
|
||||
|
@ -1,12 +1,12 @@
|
||||
import 'package:flutter/material.dart' hide Image;
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotube/components/Library/UserAlbums.dart';
|
||||
import 'package:spotube/components/Library/UserArtists.dart';
|
||||
import 'package:spotube/components/Library/UserDownloads.dart';
|
||||
import 'package:spotube/components/Library/UserLocalTracks.dart';
|
||||
import 'package:spotube/components/Library/UserPlaylists.dart';
|
||||
import 'package:spotube/components/Shared/AnonymousFallback.dart';
|
||||
import 'package:spotube/components/Shared/ColoredTabBar.dart';
|
||||
|
||||
class UserLibrary extends ConsumerWidget {
|
||||
const UserLibrary({Key? key}) : super(key: key);
|
||||
@ -15,27 +15,30 @@ class UserLibrary extends ConsumerWidget {
|
||||
return DefaultTabController(
|
||||
length: 5,
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
appBar: ColoredTabBar(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: const TabBar(
|
||||
isScrollable: true,
|
||||
tabs: [
|
||||
Tab(text: "Playlist"),
|
||||
Tab(text: "Downloads"),
|
||||
Tab(text: "Local"),
|
||||
Tab(text: "Artists"),
|
||||
Tab(text: "Album"),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: const TabBarView(children: [
|
||||
AnonymousFallback(child: UserPlaylists()),
|
||||
UserDownloads(),
|
||||
UserLocalTracks(),
|
||||
AnonymousFallback(child: UserArtists()),
|
||||
AnonymousFallback(child: UserAlbums()),
|
||||
]),
|
||||
child: PlatformTabView(
|
||||
placement: PlatformProperty.all(PlatformTabbarPlacement.top),
|
||||
body: {
|
||||
PlatformTab(
|
||||
label: "Playlist",
|
||||
icon: Container(),
|
||||
): const AnonymousFallback(child: UserPlaylists()),
|
||||
PlatformTab(
|
||||
label: "Downloads",
|
||||
icon: Container(),
|
||||
): const UserDownloads(),
|
||||
PlatformTab(
|
||||
label: "Local",
|
||||
icon: Container(),
|
||||
): const UserLocalTracks(),
|
||||
PlatformTab(
|
||||
label: "Artists",
|
||||
icon: Container(),
|
||||
): const AnonymousFallback(child: UserArtists()),
|
||||
PlatformTab(
|
||||
label: "Album",
|
||||
icon: Container(),
|
||||
): const AnonymousFallback(child: UserAlbums()),
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -9,6 +9,7 @@ import 'package:mime/mime.dart';
|
||||
import 'package:path/path.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/components/LoaderShimmers/ShimmerTrackTile.dart';
|
||||
import 'package:spotube/components/Shared/SortTracksDropdown.dart';
|
||||
@ -169,13 +170,7 @@ class UserLocalTracks extends HookConsumerWidget {
|
||||
child: Row(
|
||||
children: [
|
||||
const SizedBox(width: 10),
|
||||
ElevatedButton.icon(
|
||||
label: const Text("Play"),
|
||||
icon: Icon(
|
||||
isPlaylistPlaying
|
||||
? Icons.stop_rounded
|
||||
: Icons.play_arrow_rounded,
|
||||
),
|
||||
PlatformFilledButton(
|
||||
onPressed: trackSnapshot.value != null
|
||||
? () {
|
||||
if (trackSnapshot.value?.isNotEmpty == true) {
|
||||
@ -187,6 +182,16 @@ class UserLocalTracks extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: Row(
|
||||
children: [
|
||||
const Text("Play"),
|
||||
Icon(
|
||||
isPlaylistPlaying
|
||||
? Icons.stop_rounded
|
||||
: Icons.play_arrow_rounded,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
SortTracksDropdown(
|
||||
@ -196,7 +201,7 @@ class UserLocalTracks extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
ElevatedButton(
|
||||
PlatformFilledButton(
|
||||
child: const Icon(Icons.refresh_rounded),
|
||||
onPressed: () {
|
||||
ref.refresh(localTracksProvider);
|
||||
|
@ -11,10 +11,11 @@ class ShimmerArtistProfile extends HookWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final shimmerColor =
|
||||
Theme.of(context).extension<ShimmerColorTheme>()!.shimmerColor!;
|
||||
Theme.of(context).extension<ShimmerColorTheme>()?.shimmerColor ??
|
||||
Colors.white;
|
||||
final shimmerBackgroundColor = Theme.of(context)
|
||||
.extension<ShimmerColorTheme>()!
|
||||
.shimmerBackgroundColor!;
|
||||
.extension<ShimmerColorTheme>()
|
||||
?.shimmerBackgroundColor;
|
||||
|
||||
final avatarWidth = useBreakpointValue(
|
||||
sm: MediaQuery.of(context).size.width * 0.80,
|
||||
|
@ -9,10 +9,12 @@ class ShimmerCategories extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final shimmerColor =
|
||||
Theme.of(context).extension<ShimmerColorTheme>()!.shimmerColor!;
|
||||
Theme.of(context).extension<ShimmerColorTheme>()?.shimmerColor ??
|
||||
Colors.white;
|
||||
final shimmerBackgroundColor = Theme.of(context)
|
||||
.extension<ShimmerColorTheme>()!
|
||||
.shimmerBackgroundColor!;
|
||||
.extension<ShimmerColorTheme>()
|
||||
?.shimmerBackgroundColor ??
|
||||
Colors.grey;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
|
@ -12,10 +12,12 @@ class ShimmerLyrics extends HookWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final shimmerColor =
|
||||
Theme.of(context).extension<ShimmerColorTheme>()!.shimmerColor!;
|
||||
Theme.of(context).extension<ShimmerColorTheme>()?.shimmerColor ??
|
||||
Colors.white;
|
||||
final shimmerBackgroundColor = Theme.of(context)
|
||||
.extension<ShimmerColorTheme>()!
|
||||
.shimmerBackgroundColor!;
|
||||
.extension<ShimmerColorTheme>()
|
||||
?.shimmerBackgroundColor ??
|
||||
Colors.grey;
|
||||
|
||||
final breakpoint = useBreakpoints();
|
||||
|
||||
|
@ -9,10 +9,12 @@ class ShimmerPlaybuttonCard extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final shimmerColor =
|
||||
Theme.of(context).extension<ShimmerColorTheme>()!.shimmerColor!;
|
||||
Theme.of(context).extension<ShimmerColorTheme>()?.shimmerColor ??
|
||||
Colors.white;
|
||||
final shimmerBackgroundColor = Theme.of(context)
|
||||
.extension<ShimmerColorTheme>()!
|
||||
.shimmerBackgroundColor!;
|
||||
.extension<ShimmerColorTheme>()
|
||||
?.shimmerBackgroundColor ??
|
||||
Colors.grey;
|
||||
|
||||
final card = Stack(
|
||||
children: [
|
||||
|
@ -13,10 +13,12 @@ class ShimmerTrackTile extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final shimmerColor =
|
||||
Theme.of(context).extension<ShimmerColorTheme>()!.shimmerColor!;
|
||||
Theme.of(context).extension<ShimmerColorTheme>()?.shimmerColor ??
|
||||
Colors.white;
|
||||
final shimmerBackgroundColor = Theme.of(context)
|
||||
.extension<ShimmerColorTheme>()!
|
||||
.shimmerBackgroundColor!;
|
||||
.extension<ShimmerColorTheme>()
|
||||
?.shimmerBackgroundColor ??
|
||||
Colors.grey;
|
||||
|
||||
final single = Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 20),
|
||||
|
@ -3,6 +3,8 @@ import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:palette_generator/palette_generator.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotube/components/Lyrics/GeniusLyrics.dart';
|
||||
import 'package:spotube/components/Lyrics/SyncedLyrics.dart';
|
||||
import 'package:spotube/components/Shared/UniversalImage.dart';
|
||||
@ -14,6 +16,25 @@ import 'package:spotube/utils/type_conversion_utils.dart';
|
||||
class Lyrics extends HookConsumerWidget {
|
||||
const Lyrics({Key? key}) : super(key: key);
|
||||
|
||||
Widget buildContainer(Widget child, String albumArt, PaletteColor palette) {
|
||||
return Container(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: UniversalImage.imageProvider(albumArt),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
|
||||
child: Container(
|
||||
color: palette.color.withOpacity(.7),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
Playback playback = ref.watch(playbackProvider);
|
||||
@ -33,8 +54,22 @@ class Lyrics extends HookConsumerWidget {
|
||||
noSetBGColor: true,
|
||||
);
|
||||
|
||||
return DefaultTabController(
|
||||
length: 2,
|
||||
return SafeArea(
|
||||
child: PlatformTabView(
|
||||
body: {
|
||||
PlatformTab(
|
||||
label: "Synced Lyrics",
|
||||
icon: Container(),
|
||||
): buildContainer(SyncedLyrics(palette: palette), albumArt, palette),
|
||||
PlatformTab(
|
||||
label: "Lyrics (genius.com)",
|
||||
icon: Container(),
|
||||
): buildContainer(GeniusLyrics(palette: palette), albumArt, palette),
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
return SafeArea(
|
||||
child: Scaffold(
|
||||
extendBodyBehindAppBar: true,
|
||||
appBar: const TabBar(
|
||||
|
@ -2,6 +2,7 @@ import 'package:fl_query/fl_query.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotube/provider/SpotifyDI.dart';
|
||||
import 'package:spotube/provider/SpotifyRequests.dart';
|
||||
|
||||
@ -12,7 +13,7 @@ class PlaylistCreateDialog extends HookConsumerWidget {
|
||||
Widget build(BuildContext context, ref) {
|
||||
final spotify = ref.watch(spotifyProvider);
|
||||
|
||||
return TextButton(
|
||||
return PlatformTextButton(
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
@ -26,11 +27,11 @@ class PlaylistCreateDialog extends HookConsumerWidget {
|
||||
return AlertDialog(
|
||||
title: const Text("Create a Playlist"),
|
||||
actions: [
|
||||
TextButton(
|
||||
PlatformTextButton(
|
||||
child: const Text("Cancel"),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
ElevatedButton(
|
||||
PlatformFilledButton(
|
||||
child: const Text("Create"),
|
||||
onPressed: () async {
|
||||
if (playlistName.text.isEmpty) return;
|
||||
@ -58,19 +59,15 @@ class PlaylistCreateDialog extends HookConsumerWidget {
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
TextField(
|
||||
PlatformTextField(
|
||||
controller: playlistName,
|
||||
decoration: const InputDecoration(
|
||||
hintText: "Name of the playlist",
|
||||
label: Text("Playlist Name"),
|
||||
),
|
||||
placeholder: "Name of the playlist",
|
||||
label: "Playlist Name",
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
TextField(
|
||||
PlatformTextField(
|
||||
controller: description,
|
||||
decoration: const InputDecoration(
|
||||
hintText: "Description...",
|
||||
),
|
||||
placeholder: "Description...",
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: 5,
|
||||
),
|
||||
|
@ -3,6 +3,7 @@ import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart' hide Page;
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/components/Album/AlbumCard.dart';
|
||||
import 'package:spotube/components/Artist/ArtistCard.dart';
|
||||
@ -85,23 +86,15 @@ class Search extends HookConsumerWidget {
|
||||
vertical: 10,
|
||||
),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: TextField(
|
||||
child: PlatformTextField(
|
||||
onChanged: (value) {
|
||||
ref.read(searchTermStateProvider.notifier).state = value;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
suffix: ElevatedButton(
|
||||
onPressed: onSearch,
|
||||
child: const Icon(Icons.search_rounded),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 7,
|
||||
),
|
||||
hintStyle: const TextStyle(height: 2),
|
||||
hintText: "Search...",
|
||||
suffix: PlatformFilledButton(
|
||||
onPressed: onSearch,
|
||||
child: const Icon(Icons.search_rounded),
|
||||
),
|
||||
placeholder: "Search...",
|
||||
onSubmitted: (value) {
|
||||
onSearch();
|
||||
},
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotube/components/Shared/Hyperlink.dart';
|
||||
import 'package:spotube/hooks/usePackageInfo.dart';
|
||||
|
||||
@ -29,7 +30,7 @@ class About extends HookWidget {
|
||||
version: "2.5.0",
|
||||
);
|
||||
|
||||
return ListTile(
|
||||
return PlatformListTile(
|
||||
leading: const Icon(Icons.info_outline_rounded),
|
||||
title: const Text("About Spotube"),
|
||||
onTap: () {
|
||||
|
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotube/components/Settings/About.dart';
|
||||
import 'package:spotube/components/Settings/ColorSchemePickerDialog.dart';
|
||||
import 'package:spotube/components/Shared/AdaptiveListTile.dart';
|
||||
@ -88,7 +89,7 @@ class Settings extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
trailing: (context, update) => ElevatedButton(
|
||||
trailing: (context, update) => PlatformFilledButton(
|
||||
onPressed: () {
|
||||
GoRouter.of(context).push("/login");
|
||||
},
|
||||
@ -105,7 +106,7 @@ class Settings extends HookConsumerWidget {
|
||||
if (auth.isLoggedIn)
|
||||
Builder(builder: (context) {
|
||||
Auth auth = ref.watch(authProvider);
|
||||
return ListTile(
|
||||
return PlatformListTile(
|
||||
leading: const Icon(Icons.logout_rounded),
|
||||
title: const SizedBox(
|
||||
height: 50,
|
||||
@ -118,7 +119,7 @@ class Settings extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
trailing: ElevatedButton(
|
||||
trailing: PlatformFilledButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
MaterialStateProperty.all(Colors.red),
|
||||
@ -144,24 +145,25 @@ class Settings extends HookConsumerWidget {
|
||||
subtitle: const Text(
|
||||
"Override responsive layout mode settings",
|
||||
),
|
||||
trailing: (context, update) => DropdownButton<LayoutMode>(
|
||||
trailing: (context, update) =>
|
||||
PlatformDropDownMenu<LayoutMode>(
|
||||
value: preferences.layoutMode,
|
||||
items: const [
|
||||
DropdownMenuItem(
|
||||
items: [
|
||||
PlatformDropDownMenuItem(
|
||||
value: LayoutMode.adaptive,
|
||||
child: Text(
|
||||
child: const Text(
|
||||
"Adaptive",
|
||||
),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
PlatformDropDownMenuItem(
|
||||
value: LayoutMode.compact,
|
||||
child: Text(
|
||||
child: const Text(
|
||||
"Compact",
|
||||
),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
PlatformDropDownMenuItem(
|
||||
value: LayoutMode.extended,
|
||||
child: Text("Extended"),
|
||||
child: const Text("Extended"),
|
||||
),
|
||||
],
|
||||
onChanged: (value) {
|
||||
@ -175,24 +177,25 @@ class Settings extends HookConsumerWidget {
|
||||
AdaptiveListTile(
|
||||
leading: const Icon(Icons.dark_mode_outlined),
|
||||
title: const Text("Theme"),
|
||||
trailing: (context, update) => DropdownButton<ThemeMode>(
|
||||
trailing: (context, update) =>
|
||||
PlatformDropDownMenu<ThemeMode>(
|
||||
value: preferences.themeMode,
|
||||
items: const [
|
||||
DropdownMenuItem(
|
||||
items: [
|
||||
PlatformDropDownMenuItem(
|
||||
value: ThemeMode.dark,
|
||||
child: Text(
|
||||
child: const Text(
|
||||
"Dark",
|
||||
),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
PlatformDropDownMenuItem(
|
||||
value: ThemeMode.light,
|
||||
child: Text(
|
||||
child: const Text(
|
||||
"Light",
|
||||
),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
PlatformDropDownMenuItem(
|
||||
value: ThemeMode.system,
|
||||
child: Text("System"),
|
||||
child: const Text("System"),
|
||||
),
|
||||
],
|
||||
onChanged: (value) {
|
||||
@ -203,7 +206,7 @@ class Settings extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
PlatformListTile(
|
||||
leading: const Icon(Icons.palette_outlined),
|
||||
title: const Text("Accent Color Scheme"),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
@ -217,7 +220,7 @@ class Settings extends HookConsumerWidget {
|
||||
),
|
||||
onTap: pickColorScheme(ColorSchemeType.accent),
|
||||
),
|
||||
ListTile(
|
||||
PlatformListTile(
|
||||
leading: const Icon(Icons.format_color_fill_rounded),
|
||||
title: const Text("Background Color Scheme"),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
@ -231,11 +234,10 @@ class Settings extends HookConsumerWidget {
|
||||
),
|
||||
onTap: pickColorScheme(ColorSchemeType.background),
|
||||
),
|
||||
ListTile(
|
||||
PlatformListTile(
|
||||
leading: const Icon(Icons.album_rounded),
|
||||
title: const Text("Rotating Album Art"),
|
||||
trailing: Switch.adaptive(
|
||||
activeColor: Theme.of(context).primaryColor,
|
||||
trailing: PlatformSwitch(
|
||||
value: preferences.rotatingAlbumArt,
|
||||
onChanged: (state) {
|
||||
preferences.setRotatingAlbumArt(state);
|
||||
@ -251,18 +253,18 @@ class Settings extends HookConsumerWidget {
|
||||
leading: const Icon(Icons.multitrack_audio_rounded),
|
||||
title: const Text("Audio Quality"),
|
||||
trailing: (context, update) =>
|
||||
DropdownButton<AudioQuality>(
|
||||
PlatformDropDownMenu<AudioQuality>(
|
||||
value: preferences.audioQuality,
|
||||
items: const [
|
||||
DropdownMenuItem(
|
||||
items: [
|
||||
PlatformDropDownMenuItem(
|
||||
value: AudioQuality.high,
|
||||
child: Text(
|
||||
child: const Text(
|
||||
"High",
|
||||
),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
PlatformDropDownMenuItem(
|
||||
value: AudioQuality.low,
|
||||
child: Text("Low"),
|
||||
child: const Text("Low"),
|
||||
),
|
||||
],
|
||||
onChanged: (value) {
|
||||
@ -274,7 +276,7 @@ class Settings extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
if (kIsMobile)
|
||||
ListTile(
|
||||
PlatformListTile(
|
||||
leading: const Icon(Icons.download_for_offline_rounded),
|
||||
title: const Text(
|
||||
"Pre download and play",
|
||||
@ -282,21 +284,19 @@ class Settings extends HookConsumerWidget {
|
||||
subtitle: const Text(
|
||||
"Instead of streaming audio, download bytes and play instead (Recommended for higher bandwidth users)",
|
||||
),
|
||||
trailing: Switch.adaptive(
|
||||
activeColor: Theme.of(context).primaryColor,
|
||||
trailing: PlatformSwitch(
|
||||
value: preferences.androidBytesPlay,
|
||||
onChanged: (state) {
|
||||
preferences.setAndroidBytesPlay(state);
|
||||
},
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
PlatformListTile(
|
||||
leading: const Icon(Icons.fast_forward_rounded),
|
||||
title: const Text(
|
||||
"Skip non-music segments (SponsorBlock)",
|
||||
),
|
||||
trailing: Switch.adaptive(
|
||||
activeColor: Theme.of(context).primaryColor,
|
||||
trailing: PlatformSwitch(
|
||||
value: preferences.skipSponsorSegments,
|
||||
onChanged: (state) {
|
||||
preferences.setSkipSponsorSegments(state);
|
||||
@ -320,12 +320,11 @@ class Settings extends HookConsumerWidget {
|
||||
),
|
||||
trailing: (context, update) => ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 250),
|
||||
child: DropdownButton(
|
||||
isExpanded: true,
|
||||
child: PlatformDropDownMenu(
|
||||
value: preferences.recommendationMarket,
|
||||
items: spotifyMarkets
|
||||
.map(
|
||||
(country) => (DropdownMenuItem(
|
||||
(country) => (PlatformDropDownMenuItem(
|
||||
value: country.first,
|
||||
child: Text(country.last),
|
||||
)),
|
||||
@ -358,18 +357,15 @@ class Settings extends HookConsumerWidget {
|
||||
breakOn: Breakpoints.lg,
|
||||
trailing: (context, update) => ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 450),
|
||||
child: TextField(
|
||||
child: PlatformTextField(
|
||||
controller: ytSearchFormatController,
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
suffix: ElevatedButton(
|
||||
child: const Icon(Icons.save_rounded),
|
||||
onPressed: () {
|
||||
preferences.setYtSearchFormat(
|
||||
ytSearchFormatController.value.text,
|
||||
);
|
||||
},
|
||||
),
|
||||
suffix: PlatformFilledButton(
|
||||
child: const Icon(Icons.save_rounded),
|
||||
onPressed: () {
|
||||
preferences.setYtSearchFormat(
|
||||
ytSearchFormatController.value.text,
|
||||
);
|
||||
},
|
||||
),
|
||||
onSubmitted: (value) {
|
||||
preferences.setYtSearchFormat(value);
|
||||
@ -392,24 +388,24 @@ class Settings extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
trailing: (context, update) =>
|
||||
DropdownButton<SpotubeTrackMatchAlgorithm>(
|
||||
PlatformDropDownMenu<SpotubeTrackMatchAlgorithm>(
|
||||
value: preferences.trackMatchAlgorithm,
|
||||
items: const [
|
||||
DropdownMenuItem(
|
||||
items: [
|
||||
PlatformDropDownMenuItem(
|
||||
value: SpotubeTrackMatchAlgorithm.authenticPopular,
|
||||
child: Text(
|
||||
child: const Text(
|
||||
"Popular from Author",
|
||||
),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
PlatformDropDownMenuItem(
|
||||
value: SpotubeTrackMatchAlgorithm.popular,
|
||||
child: Text(
|
||||
child: const Text(
|
||||
"Accurately Popular",
|
||||
),
|
||||
),
|
||||
DropdownMenuItem(
|
||||
PlatformDropDownMenuItem(
|
||||
value: SpotubeTrackMatchAlgorithm.youtube,
|
||||
child: Text("YouTube's Top choice"),
|
||||
child: const Text("YouTube's Top choice"),
|
||||
),
|
||||
],
|
||||
onChanged: (value) {
|
||||
@ -425,21 +421,20 @@ class Settings extends HookConsumerWidget {
|
||||
style:
|
||||
TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
|
||||
),
|
||||
ListTile(
|
||||
PlatformListTile(
|
||||
leading: const Icon(Icons.file_download_outlined),
|
||||
title: const Text("Download Location"),
|
||||
subtitle: Text(preferences.downloadLocation),
|
||||
trailing: ElevatedButton(
|
||||
trailing: PlatformFilledButton(
|
||||
onPressed: pickDownloadLocation,
|
||||
child: const Icon(Icons.folder_rounded),
|
||||
),
|
||||
onTap: pickDownloadLocation,
|
||||
),
|
||||
ListTile(
|
||||
PlatformListTile(
|
||||
leading: const Icon(Icons.lyrics_rounded),
|
||||
title: const Text("Download lyrics along with the Track"),
|
||||
trailing: Switch.adaptive(
|
||||
activeColor: Theme.of(context).primaryColor,
|
||||
trailing: PlatformSwitch(
|
||||
value: preferences.saveTrackLyrics,
|
||||
onChanged: (state) {
|
||||
preferences.setSaveTrackLyrics(state);
|
||||
@ -487,11 +482,10 @@ class Settings extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
PlatformListTile(
|
||||
leading: const Icon(Icons.update_rounded),
|
||||
title: const Text("Check for Update"),
|
||||
trailing: Switch.adaptive(
|
||||
activeColor: Theme.of(context).primaryColor,
|
||||
trailing: PlatformSwitch(
|
||||
value: preferences.checkUpdate,
|
||||
onChanged: (checked) =>
|
||||
preferences.setCheckUpdate(checked),
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotube/hooks/useBreakpoints.dart';
|
||||
|
||||
class AdaptiveListTile extends HookWidget {
|
||||
@ -24,7 +25,7 @@ class AdaptiveListTile extends HookWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final breakpoint = useBreakpoints();
|
||||
|
||||
return ListTile(
|
||||
return PlatformListTile(
|
||||
title: title,
|
||||
subtitle: subtitle,
|
||||
trailing:
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotube/components/Shared/HoverBuilder.dart';
|
||||
import 'package:spotube/components/Shared/SpotubeMarqueeText.dart';
|
||||
import 'package:spotube/components/Shared/UniversalImage.dart';
|
||||
@ -67,7 +68,7 @@ class PlaybuttonCard extends StatelessWidget {
|
||||
bottom: 10,
|
||||
end: 5,
|
||||
child: Builder(builder: (context) {
|
||||
return ElevatedButton(
|
||||
return PlatformFilledButton(
|
||||
onPressed: onPlaybuttonPressed,
|
||||
style: ButtonStyle(
|
||||
shape: MaterialStateProperty.all(
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:spotube/components/Library/UserLocalTracks.dart';
|
||||
|
||||
class SortTracksDropdown extends StatelessWidget {
|
||||
@ -12,43 +13,41 @@ class SortTracksDropdown extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PopupMenuButton<SortBy>(
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem(
|
||||
value: SortBy.none,
|
||||
enabled: value != SortBy.none,
|
||||
child: const Text("None"),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: SortBy.ascending,
|
||||
enabled: value != SortBy.ascending,
|
||||
child: const Text("Sort by A-Z"),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: SortBy.descending,
|
||||
enabled: value != SortBy.descending,
|
||||
child: const Text("Sort by Z-A"),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: SortBy.dateAdded,
|
||||
enabled: value != SortBy.dateAdded,
|
||||
child: const Text("Sort by Date"),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: SortBy.artist,
|
||||
enabled: value != SortBy.artist,
|
||||
child: const Text("Sort by Artist"),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: SortBy.album,
|
||||
enabled: value != SortBy.album,
|
||||
child: const Text("Sort by Album"),
|
||||
),
|
||||
];
|
||||
},
|
||||
return PlatformPopupMenuButton<SortBy>(
|
||||
items: [
|
||||
PlatformPopupMenuItem(
|
||||
value: SortBy.none,
|
||||
enabled: value != SortBy.none,
|
||||
child: const Text("None"),
|
||||
),
|
||||
PlatformPopupMenuItem(
|
||||
value: SortBy.ascending,
|
||||
enabled: value != SortBy.ascending,
|
||||
child: const Text("Sort by A-Z"),
|
||||
),
|
||||
PlatformPopupMenuItem(
|
||||
value: SortBy.descending,
|
||||
enabled: value != SortBy.descending,
|
||||
child: const Text("Sort by Z-A"),
|
||||
),
|
||||
PlatformPopupMenuItem(
|
||||
value: SortBy.dateAdded,
|
||||
enabled: value != SortBy.dateAdded,
|
||||
child: const Text("Sort by Date"),
|
||||
),
|
||||
PlatformPopupMenuItem(
|
||||
value: SortBy.artist,
|
||||
enabled: value != SortBy.artist,
|
||||
child: const Text("Sort by Artist"),
|
||||
),
|
||||
PlatformPopupMenuItem(
|
||||
value: SortBy.album,
|
||||
enabled: value != SortBy.album,
|
||||
child: const Text("Sort by Album"),
|
||||
),
|
||||
],
|
||||
onSelected: onChanged,
|
||||
icon: const Icon(Icons.sort_rounded),
|
||||
child: const Icon(Icons.sort_rounded),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:platform_ui/platform_ui.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:spotube/components/Shared/ReplaceDownloadedFileDialog.dart';
|
||||
import 'package:spotube/entities/CacheTrack.dart';
|
||||
@ -198,57 +199,66 @@ class SpotubeState extends ConsumerState<Spotube> with WidgetsBindingObserver {
|
||||
};
|
||||
}, []);
|
||||
|
||||
return MaterialApp.router(
|
||||
routerConfig: router,
|
||||
platform = TargetPlatform.macOS;
|
||||
|
||||
return PlatformApp.router(
|
||||
routeInformationParser: router.routeInformationParser,
|
||||
routerDelegate: router.routerDelegate,
|
||||
routeInformationProvider: router.routeInformationProvider,
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'Spotube',
|
||||
theme: lightTheme(
|
||||
androidTheme: lightTheme(
|
||||
accentMaterialColor: accentMaterialColor,
|
||||
backgroundMaterialColor: backgroundMaterialColor,
|
||||
),
|
||||
darkTheme: darkTheme(
|
||||
androidDarkTheme: darkTheme(
|
||||
accentMaterialColor: accentMaterialColor,
|
||||
backgroundMaterialColor: backgroundMaterialColor,
|
||||
),
|
||||
themeMode: themeMode,
|
||||
shortcuts: {
|
||||
...WidgetsApp.defaultShortcuts,
|
||||
const SingleActivator(LogicalKeyboardKey.space): PlayPauseIntent(ref),
|
||||
const SingleActivator(LogicalKeyboardKey.comma, control: true):
|
||||
shortcuts: PlatformProperty.all({
|
||||
...WidgetsApp.defaultShortcuts.map((key, value) {
|
||||
return MapEntry(
|
||||
LogicalKeySet.fromSet(key.triggers?.toSet() ?? {}),
|
||||
value,
|
||||
);
|
||||
}),
|
||||
LogicalKeySet(LogicalKeyboardKey.space): PlayPauseIntent(ref),
|
||||
LogicalKeySet(LogicalKeyboardKey.comma, LogicalKeyboardKey.control):
|
||||
NavigationIntent(router, "/settings"),
|
||||
const SingleActivator(
|
||||
LogicalKeySet(
|
||||
LogicalKeyboardKey.keyB,
|
||||
control: true,
|
||||
shift: true,
|
||||
LogicalKeyboardKey.control,
|
||||
LogicalKeyboardKey.shift,
|
||||
): HomeTabIntent(ref, tab: HomeTabs.browse),
|
||||
const SingleActivator(
|
||||
LogicalKeySet(
|
||||
LogicalKeyboardKey.keyS,
|
||||
control: true,
|
||||
shift: true,
|
||||
LogicalKeyboardKey.control,
|
||||
LogicalKeyboardKey.shift,
|
||||
): HomeTabIntent(ref, tab: HomeTabs.search),
|
||||
const SingleActivator(
|
||||
LogicalKeySet(
|
||||
LogicalKeyboardKey.keyL,
|
||||
control: true,
|
||||
shift: true,
|
||||
LogicalKeyboardKey.control,
|
||||
LogicalKeyboardKey.shift,
|
||||
): HomeTabIntent(ref, tab: HomeTabs.library),
|
||||
const SingleActivator(
|
||||
LogicalKeySet(
|
||||
LogicalKeyboardKey.keyY,
|
||||
control: true,
|
||||
shift: true,
|
||||
LogicalKeyboardKey.control,
|
||||
LogicalKeyboardKey.shift,
|
||||
): HomeTabIntent(ref, tab: HomeTabs.lyrics),
|
||||
const SingleActivator(
|
||||
LogicalKeySet(
|
||||
LogicalKeyboardKey.keyW,
|
||||
control: true,
|
||||
shift: true,
|
||||
LogicalKeyboardKey.control,
|
||||
LogicalKeyboardKey.shift,
|
||||
): CloseAppIntent(),
|
||||
},
|
||||
actions: {
|
||||
}),
|
||||
actions: PlatformProperty.all({
|
||||
...WidgetsApp.defaultActions,
|
||||
PlayPauseIntent: PlayPauseAction(),
|
||||
NavigationIntent: NavigationAction(),
|
||||
HomeTabIntent: HomeTabAction(),
|
||||
CloseAppIntent: CloseAppAction(),
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import audio_session
|
||||
import audioplayers_darwin
|
||||
import bitsdojo_window_macos
|
||||
import connectivity_plus_macos
|
||||
import macos_ui
|
||||
import metadata_god
|
||||
import package_info_plus_macos
|
||||
import path_provider_macos
|
||||
@ -23,6 +24,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
|
||||
BitsdojoWindowPlugin.register(with: registry.registrar(forPlugin: "BitsdojoWindowPlugin"))
|
||||
ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
|
||||
MacOSUiPlugin.register(with: registry.registrar(forPlugin: "MacOSUiPlugin"))
|
||||
MetadataGodPlugin.register(with: registry.registrar(forPlugin: "MetadataGodPlugin"))
|
||||
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
|
47
pubspec.lock
47
pubspec.lock
@ -493,6 +493,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.1"
|
||||
fluent_ui:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fluent_ui
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.3"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@ -561,6 +568,11 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
flutter_localizations:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -690,6 +702,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
intl:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: intl
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.17.0"
|
||||
introduction_screen:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -739,6 +758,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
macos_ui:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: macos_ui
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.5"
|
||||
marquee:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -972,6 +998,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
platform_ui:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "../platform_ui"
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.0.1"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1021,6 +1054,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0+1"
|
||||
recase:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: recase
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
riverpod:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1035,6 +1075,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.27.3"
|
||||
scroll_pos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: scroll_pos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
scroll_to_index:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -62,6 +62,8 @@ dependencies:
|
||||
flutter_inappwebview: ^5.4.3+7
|
||||
tuple: ^2.0.1
|
||||
uuid: ^3.0.6
|
||||
platform_ui:
|
||||
path: ../platform_ui
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
Reference in New Issue
Block a user