From 159f03e7ca62e6b3b86389e2795da84de61fba78 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Thu, 6 Apr 2023 11:13:14 +0600 Subject: [PATCH] feat(player): replace bg blur with gradient, proper fg color and align title and artist name --- lib/components/player/player_controls.dart | 31 +-- lib/components/shared/heart_button.dart | 5 +- .../shared/page_window_title_bar.dart | 12 +- .../track_table/track_collection_view.dart | 5 +- lib/hooks/use_palette_color.dart | 8 +- lib/pages/player/player.dart | 229 ++++++++++-------- pubspec.lock | 2 +- 7 files changed, 157 insertions(+), 135 deletions(-) diff --git a/lib/components/player/player_controls.dart b/lib/components/player/player_controls.dart index 5a0b0bcbd..d1ea19575 100644 --- a/lib/components/player/player_controls.dart +++ b/lib/components/player/player_controls.dart @@ -11,10 +11,10 @@ import 'package:spotube/provider/playlist_queue_provider.dart'; import 'package:spotube/utils/primitive_utils.dart'; class PlayerControls extends HookConsumerWidget { - final Color? iconColor; + final Color? color; PlayerControls({ - this.iconColor, + this.color, Key? key, }) : super(key: key); @@ -109,21 +109,24 @@ class PlayerControls extends HookConsumerWidget { ), ); }, - activeColor: iconColor, + activeColor: color, + inactiveColor: color?.withOpacity(0.15), ), ), Padding( padding: const EdgeInsets.symmetric( horizontal: 8.0, ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "$currentMinutes:$currentSeconds", - ), - Text("$totalMinutes:$totalSeconds"), - ], + child: DefaultTextStyle( + style: + theme.textTheme.bodySmall!.copyWith(color: color), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text("$currentMinutes:$currentSeconds"), + Text("$totalMinutes:$totalSeconds"), + ], + ), ), ), ], @@ -157,7 +160,7 @@ class PlayerControls extends HookConsumerWidget { tooltip: "Previous track", icon: Icon( SpotubeIcons.skipBack, - color: iconColor, + color: color, ), onPressed: playlistNotifier.previous, ), @@ -171,7 +174,7 @@ class PlayerControls extends HookConsumerWidget { ) : Icon( playing ? SpotubeIcons.pause : SpotubeIcons.play, - color: iconColor, + color: color, ), onPressed: Actions.handler( context, @@ -182,7 +185,7 @@ class PlayerControls extends HookConsumerWidget { tooltip: "Next track", icon: Icon( SpotubeIcons.skipForward, - color: iconColor, + color: color, ), onPressed: playlistNotifier.next, ), diff --git a/lib/components/shared/heart_button.dart b/lib/components/shared/heart_button.dart index 363fecc52..d0ab9de4d 100644 --- a/lib/components/shared/heart_button.dart +++ b/lib/components/shared/heart_button.dart @@ -144,10 +144,7 @@ class PlaylistHeartButton extends HookConsumerWidget { ), [playlist.images]); - final color = usePaletteGenerator( - context, - titleImage, - ).dominantColor; + final color = usePaletteGenerator(titleImage).dominantColor; if (me.isLoading || !me.hasData) { return const CircularProgressIndicator(); diff --git a/lib/components/shared/page_window_title_bar.dart b/lib/components/shared/page_window_title_bar.dart index 067a2d1fc..652497849 100644 --- a/lib/components/shared/page_window_title_bar.dart +++ b/lib/components/shared/page_window_title_bar.dart @@ -68,7 +68,7 @@ class _PageWindowTitleBarState extends State { automaticallyImplyLeading: widget.automaticallyImplyLeading, actions: [ ...?widget.actions, - const WindowTitleBarButtons(), + WindowTitleBarButtons(foregroundColor: widget.foregroundColor), ], backgroundColor: widget.backgroundColor, foregroundColor: widget.foregroundColor, @@ -86,7 +86,11 @@ class _PageWindowTitleBarState extends State { } class WindowTitleBarButtons extends HookWidget { - const WindowTitleBarButtons({Key? key}) : super(key: key); + final Color? foregroundColor; + const WindowTitleBarButtons({ + Key? key, + this.foregroundColor, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -110,7 +114,7 @@ class WindowTitleBarButtons extends HookWidget { final theme = Theme.of(context); final colors = WindowButtonColors( normal: Colors.transparent, - iconNormal: theme.colorScheme.onBackground, + iconNormal: foregroundColor ?? theme.colorScheme.onBackground, mouseOver: theme.colorScheme.onBackground.withOpacity(0.1), mouseDown: theme.colorScheme.onBackground.withOpacity(0.2), iconMouseOver: theme.colorScheme.onBackground, @@ -119,7 +123,7 @@ class WindowTitleBarButtons extends HookWidget { final closeColors = WindowButtonColors( normal: Colors.transparent, - iconNormal: theme.colorScheme.onBackground, + iconNormal: foregroundColor ?? theme.colorScheme.onBackground, mouseOver: Colors.red, mouseDown: Colors.red[800]!, iconMouseOver: Colors.white, diff --git a/lib/components/shared/track_table/track_collection_view.dart b/lib/components/shared/track_table/track_collection_view.dart index 73fe5b7e8..28db7444b 100644 --- a/lib/components/shared/track_table/track_collection_view.dart +++ b/lib/components/shared/track_table/track_collection_view.dart @@ -66,10 +66,7 @@ class TrackCollectionView extends HookConsumerWidget { Widget build(BuildContext context, ref) { final theme = Theme.of(context); final auth = ref.watch(AuthenticationNotifier.provider); - final color = usePaletteGenerator( - context, - titleImage, - ).dominantColor; + final color = usePaletteGenerator(titleImage).dominantColor; final List buttons = [ if (showShare) diff --git a/lib/hooks/use_palette_color.dart b/lib/hooks/use_palette_color.dart index 300eff149..9269edd79 100644 --- a/lib/hooks/use_palette_color.dart +++ b/lib/hooks/use_palette_color.dart @@ -12,6 +12,7 @@ final _paletteColorState = StateProvider( PaletteColor usePaletteColor(String imageUrl, WidgetRef ref) { final context = useContext(); + final theme = Theme.of(context); final paletteColor = ref.watch(_paletteColorState); final mounted = useIsMounted(); @@ -25,7 +26,7 @@ PaletteColor usePaletteColor(String imageUrl, WidgetRef ref) { ), ); if (!mounted()) return; - final color = Theme.of(context).brightness == Brightness.light + final color = theme.brightness == Brightness.light ? palette.lightMutedColor ?? palette.lightVibrantColor : palette.darkMutedColor ?? palette.darkVibrantColor; if (color != null) { @@ -38,10 +39,7 @@ PaletteColor usePaletteColor(String imageUrl, WidgetRef ref) { return paletteColor; } -PaletteGenerator usePaletteGenerator( - BuildContext context, - String imageUrl, -) { +PaletteGenerator usePaletteGenerator(String imageUrl) { final palette = useState(PaletteGenerator.fromColors([])); final mounted = useIsMounted(); diff --git a/lib/pages/player/player.dart b/lib/pages/player/player.dart index 42a4d0051..a74848ea9 100644 --- a/lib/pages/player/player.dart +++ b/lib/pages/player/player.dart @@ -1,13 +1,11 @@ -import 'dart:ui'; - import 'package:auto_size_text/auto_size_text.dart'; 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:palette_generator/palette_generator.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/player/player_actions.dart'; import 'package:spotube/components/player/player_controls.dart'; @@ -56,120 +54,145 @@ class PlayerView extends HookConsumerWidget { [currentTrack?.album?.images], ); - final PaletteColor paletteColor = usePaletteColor(albumArt, ref); + final palette = usePaletteGenerator(albumArt); + final bgColor = palette.dominantColor?.color ?? theme.colorScheme.primary; + final titleTextColor = palette.dominantColor?.titleTextColor; + final bodyTextColor = palette.dominantColor?.bodyTextColor; useCustomStatusBarColor( - paletteColor.color, + bgColor, GoRouter.of(context).location == "/player", noSetBGColor: true, ); - return Scaffold( - appBar: PageWindowTitleBar( - backgroundColor: Colors.transparent, - foregroundColor: paletteColor.titleTextColor, - toolbarOpacity: 1, - leading: BackButton(color: paletteColor.titleTextColor), - ), - extendBodyBehindAppBar: true, - body: DecoratedBox( - decoration: BoxDecoration( - image: DecorationImage( - image: UniversalImage.imageProvider(albumArt), - fit: BoxFit.cover, - ), + return IconTheme( + data: theme.iconTheme.copyWith(color: bodyTextColor), + child: Scaffold( + appBar: PageWindowTitleBar( + backgroundColor: Colors.transparent, + foregroundColor: titleTextColor, + toolbarOpacity: 1, + leading: const BackButton(), ), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15), - child: SafeArea( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(20), - child: UniversalImage( - path: albumArt, - ), - ), - const SizedBox(height: 10), - Container( - padding: const EdgeInsets.symmetric(horizontal: 16), - alignment: Alignment.centerLeft, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AutoSizeText( - currentTrack?.name ?? "Not playing", - style: TextStyle( - fontSize: 20, - color: paletteColor.titleTextColor, + extendBodyBehindAppBar: true, + body: Container( + decoration: BoxDecoration( + color: palette.dominantColor?.color, + gradient: LinearGradient( + colors: [ + palette.dominantColor?.color ?? theme.colorScheme.primary, + palette.mutedColor?.color ?? theme.colorScheme.secondary, + ], + transform: const GradientRotation(0.5), + ), + ), + alignment: Alignment.center, + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 580), + child: SafeArea( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + DecoratedBox( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + boxShadow: const [ + BoxShadow( + color: Colors.black26, + spreadRadius: 2, + blurRadius: 10, + offset: Offset(0, 0), ), - maxLines: 1, - textAlign: TextAlign.start, + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(20), + child: UniversalImage( + path: albumArt, + placeholder: Assets.albumPlaceholder.path, ), - if (isLocalTrack) - Text( - TypeConversionUtils.artists_X_String( - currentTrack?.artists ?? [], - ), - style: theme.textTheme.bodyMedium!.copyWith( - fontWeight: FontWeight.bold, - color: paletteColor.bodyTextColor, + ), + ), + const SizedBox(height: 10), + Container( + padding: const EdgeInsets.symmetric(horizontal: 16), + alignment: Alignment.centerLeft, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AutoSizeText( + currentTrack?.name ?? "Not playing", + style: TextStyle( + fontSize: 20, + color: titleTextColor, ), - ) - else - TypeConversionUtils.artists_X_ClickableArtists( - currentTrack?.artists ?? [], - textStyle: theme.textTheme.bodyMedium!.copyWith( - fontWeight: FontWeight.bold, - color: paletteColor.bodyTextColor, + maxLines: 1, + textAlign: TextAlign.start, + ), + if (isLocalTrack) + Text( + TypeConversionUtils.artists_X_String( + currentTrack?.artists ?? [], + ), + style: theme.textTheme.bodyMedium!.copyWith( + fontWeight: FontWeight.bold, + color: bodyTextColor, + ), + ) + else + TypeConversionUtils.artists_X_ClickableArtists( + currentTrack?.artists ?? [], + textStyle: theme.textTheme.bodyMedium!.copyWith( + fontWeight: FontWeight.bold, + color: bodyTextColor, + ), + onRouteChange: (route) { + GoRouter.of(context).pop(); + GoRouter.of(context).push(route); + }, ), - onRouteChange: (route) { - GoRouter.of(context).pop(); - GoRouter.of(context).push(route); + ], + ), + ), + const SizedBox(height: 40), + PlayerControls(color: bodyTextColor), + const Spacer(), + PlayerActions( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + floatingQueue: false, + extraActions: [ + if (auth != null) + IconButton( + tooltip: "Open Lyrics", + icon: const Icon(SpotubeIcons.music), + onPressed: () { + showModalBottomSheet( + context: context, + isDismissible: true, + enableDrag: true, + isScrollControlled: true, + backgroundColor: Colors.black38, + barrierColor: Colors.black12, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + ), + ), + constraints: BoxConstraints( + maxHeight: + MediaQuery.of(context).size.height * 0.8, + ), + builder: (context) => + const LyricsPage(isModal: true), + ); }, - ), + ) ], ), - ), - const SizedBox(height: 40), - PlayerControls(iconColor: paletteColor.bodyTextColor), - const Spacer(), - PlayerActions( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - floatingQueue: false, - extraActions: [ - if (auth != null) - IconButton( - tooltip: "Open Lyrics", - icon: const Icon(SpotubeIcons.music), - onPressed: () { - showModalBottomSheet( - context: context, - isDismissible: true, - enableDrag: true, - isScrollControlled: true, - backgroundColor: Colors.black38, - barrierColor: Colors.black12, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20), - topRight: Radius.circular(20), - ), - ), - constraints: BoxConstraints( - maxHeight: - MediaQuery.of(context).size.height * 0.8, - ), - builder: (context) => - const LyricsPage(isModal: true), - ); - }, - ) - ], - ), - ], + ], + ), ), ), ), diff --git a/pubspec.lock b/pubspec.lock index 8f06a2b43..86e874cc3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1778,4 +1778,4 @@ packages: version: "1.12.3" sdks: dart: ">=2.19.2 <3.0.0" - flutter: ">=3.7.0" + flutter: ">=3.3.0"