mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 16:05:18 +00:00
feat(player): replace bg blur with gradient, proper fg color and align title and artist name
This commit is contained in:
parent
36396b7583
commit
159f03e7ca
@ -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,23 +109,26 @@ class PlayerControls extends HookConsumerWidget {
|
||||
),
|
||||
);
|
||||
},
|
||||
activeColor: iconColor,
|
||||
activeColor: color,
|
||||
inactiveColor: color?.withOpacity(0.15),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
),
|
||||
child: DefaultTextStyle(
|
||||
style:
|
||||
theme.textTheme.bodySmall!.copyWith(color: color),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"$currentMinutes:$currentSeconds",
|
||||
),
|
||||
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<PlayPauseIntent>(
|
||||
context,
|
||||
@ -182,7 +185,7 @@ class PlayerControls extends HookConsumerWidget {
|
||||
tooltip: "Next track",
|
||||
icon: Icon(
|
||||
SpotubeIcons.skipForward,
|
||||
color: iconColor,
|
||||
color: color,
|
||||
),
|
||||
onPressed: playlistNotifier.next,
|
||||
),
|
||||
|
@ -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();
|
||||
|
@ -68,7 +68,7 @@ class _PageWindowTitleBarState extends State<PageWindowTitleBar> {
|
||||
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<PageWindowTitleBar> {
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -66,10 +66,7 @@ class TrackCollectionView<T> 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<Widget> buttons = [
|
||||
if (showShare)
|
||||
|
@ -12,6 +12,7 @@ final _paletteColorState = StateProvider<PaletteColor>(
|
||||
|
||||
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();
|
||||
|
||||
|
@ -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,40 +54,64 @@ 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(
|
||||
return IconTheme(
|
||||
data: theme.iconTheme.copyWith(color: bodyTextColor),
|
||||
child: Scaffold(
|
||||
appBar: PageWindowTitleBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: paletteColor.titleTextColor,
|
||||
foregroundColor: titleTextColor,
|
||||
toolbarOpacity: 1,
|
||||
leading: BackButton(color: paletteColor.titleTextColor),
|
||||
leading: const BackButton(),
|
||||
),
|
||||
extendBodyBehindAppBar: true,
|
||||
body: DecoratedBox(
|
||||
body: Container(
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: UniversalImage.imageProvider(albumArt),
|
||||
fit: BoxFit.cover,
|
||||
color: palette.dominantColor?.color,
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
palette.dominantColor?.color ?? theme.colorScheme.primary,
|
||||
palette.mutedColor?.color ?? theme.colorScheme.secondary,
|
||||
],
|
||||
transform: const GradientRotation(0.5),
|
||||
),
|
||||
),
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15),
|
||||
alignment: Alignment.center,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 580),
|
||||
child: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
ClipRRect(
|
||||
DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Colors.black26,
|
||||
spreadRadius: 2,
|
||||
blurRadius: 10,
|
||||
offset: Offset(0, 0),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: UniversalImage(
|
||||
path: albumArt,
|
||||
placeholder: Assets.albumPlaceholder.path,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
@ -103,7 +125,7 @@ class PlayerView extends HookConsumerWidget {
|
||||
currentTrack?.name ?? "Not playing",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: paletteColor.titleTextColor,
|
||||
color: titleTextColor,
|
||||
),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.start,
|
||||
@ -115,7 +137,7 @@ class PlayerView extends HookConsumerWidget {
|
||||
),
|
||||
style: theme.textTheme.bodyMedium!.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: paletteColor.bodyTextColor,
|
||||
color: bodyTextColor,
|
||||
),
|
||||
)
|
||||
else
|
||||
@ -123,7 +145,7 @@ class PlayerView extends HookConsumerWidget {
|
||||
currentTrack?.artists ?? [],
|
||||
textStyle: theme.textTheme.bodyMedium!.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: paletteColor.bodyTextColor,
|
||||
color: bodyTextColor,
|
||||
),
|
||||
onRouteChange: (route) {
|
||||
GoRouter.of(context).pop();
|
||||
@ -134,7 +156,7 @@ class PlayerView extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 40),
|
||||
PlayerControls(iconColor: paletteColor.bodyTextColor),
|
||||
PlayerControls(color: bodyTextColor),
|
||||
const Spacer(),
|
||||
PlayerActions(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
@ -175,6 +197,7 @@ class PlayerView extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user