feat: album art dominant color as accent color (#447)

This commit is contained in:
Kingkor Roy Tirtho 2023-04-28 12:58:03 +06:00
parent cac8ea6388
commit 31b9249cc8
6 changed files with 65 additions and 5 deletions

View File

@ -76,4 +76,5 @@ abstract class SpotubeIcons {
static const hoverOff = Icons.back_hand_outlined; static const hoverOff = Icons.back_hand_outlined;
static const dragHandle = Icons.drag_indicator; static const dragHandle = Icons.drag_indicator;
static const lightning = Icons.flash_on_rounded; static const lightning = Icons.flash_on_rounded;
static const colorSync = FeatherIcons.activity;
} }

View File

@ -19,6 +19,7 @@ import 'package:spotube/collections/routes.dart';
import 'package:spotube/collections/intents.dart'; import 'package:spotube/collections/intents.dart';
import 'package:spotube/models/logger.dart'; import 'package:spotube/models/logger.dart';
import 'package:spotube/provider/downloader_provider.dart'; import 'package:spotube/provider/downloader_provider.dart';
import 'package:spotube/provider/palette_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/services/audio_player.dart'; import 'package:spotube/services/audio_player.dart';
import 'package:spotube/services/pocketbase.dart'; import 'package:spotube/services/pocketbase.dart';
@ -188,6 +189,8 @@ class SpotubeState extends ConsumerState<Spotube> {
ref.watch(userPreferencesProvider.select((s) => s.themeMode)); ref.watch(userPreferencesProvider.select((s) => s.themeMode));
final accentMaterialColor = final accentMaterialColor =
ref.watch(userPreferencesProvider.select((s) => s.accentColorScheme)); ref.watch(userPreferencesProvider.select((s) => s.accentColorScheme));
final paletteColor =
ref.watch(paletteProvider.select((s) => s?.dominantColor?.color));
useInitSysTray(ref); useInitSysTray(ref);
@ -209,8 +212,8 @@ class SpotubeState extends ConsumerState<Spotube> {
return DragToResizeArea(child: child!); return DragToResizeArea(child: child!);
}, },
themeMode: themeMode, themeMode: themeMode,
theme: theme(accentMaterialColor, Brightness.light), theme: theme(paletteColor ?? accentMaterialColor, Brightness.light),
darkTheme: theme(accentMaterialColor, Brightness.dark), darkTheme: theme(paletteColor ?? accentMaterialColor, Brightness.dark),
shortcuts: { shortcuts: {
...WidgetsApp.defaultShortcuts.map((key, value) { ...WidgetsApp.defaultShortcuts.map((key, value) {
return MapEntry( return MapEntry(

View File

@ -203,6 +203,15 @@ class SettingsPage extends HookConsumerWidget {
), ),
onTap: pickColorScheme(), onTap: pickColorScheme(),
), ),
SwitchListTile(
secondary: const Icon(SpotubeIcons.colorSync),
title: const Text("Sync Album Color"),
subtitle: const Text(
"Uses the dominant color of the album art as the accent color",
),
value: preferences.albumColorSync,
onChanged: preferences.setAlbumColorSync,
),
Text( Text(
" Playback", " Playback",
style: theme.textTheme.headlineSmall style: theme.textTheme.headlineSmall

View File

@ -0,0 +1,4 @@
import 'package:palette_generator/palette_generator.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final paletteProvider = StateProvider<PaletteGenerator?>((ref) => null);

View File

@ -2,11 +2,14 @@ import 'package:audio_service/audio_service.dart';
import 'package:audioplayers/audioplayers.dart'; import 'package:audioplayers/audioplayers.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:palette_generator/palette_generator.dart';
import 'package:spotify/spotify.dart'; import 'package:spotify/spotify.dart';
import 'package:spotube/components/shared/image/universal_image.dart';
import 'package:spotube/models/local_track.dart'; import 'package:spotube/models/local_track.dart';
import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/models/spotube_track.dart';
import 'package:spotube/extensions/track.dart'; import 'package:spotube/extensions/track.dart';
import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/provider/blacklist_provider.dart';
import 'package:spotube/provider/palette_provider.dart';
import 'package:spotube/provider/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences_provider.dart';
import 'package:spotube/services/audio_player.dart'; import 'package:spotube/services/audio_player.dart';
import 'package:spotube/services/linux_audio_service.dart'; import 'package:spotube/services/linux_audio_service.dart';
@ -532,6 +535,30 @@ class PlaylistQueueNotifier extends PersistedStateNotifier<PlaylistQueue?> {
state = state!.copyWith(tracks: Set.from(tracks), active: active); state = state!.copyWith(tracks: Set.from(tracks), active: active);
} }
Future<void> updatePalette() async {
final palette = await PaletteGenerator.fromImageProvider(
UniversalImage.imageProvider(
TypeConversionUtils.image_X_UrlString(
state?.activeTrack.album?.images,
placeholder: ImagePlaceholder.albumArt,
),
height: 50,
width: 50,
),
);
ref.read(paletteProvider.notifier).state = palette;
}
@override
set state(state) {
if (preferences.albumColorSync &&
state != null &&
state.active != this.state?.active) {
updatePalette();
}
super.state = state;
}
@override @override
Future<PlaylistQueue>? fromJson(Map<String, dynamic> json) { Future<PlaylistQueue>? fromJson(Map<String, dynamic> json) {
if (json.isEmpty) return null; if (json.isEmpty) return null;

View File

@ -4,6 +4,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:spotube/components/settings/color_scheme_picker_dialog.dart'; import 'package:spotube/components/settings/color_scheme_picker_dialog.dart';
import 'package:spotube/provider/palette_provider.dart';
import 'package:spotube/provider/playlist_queue_provider.dart';
import 'package:spotube/utils/persisted_change_notifier.dart'; import 'package:spotube/utils/persisted_change_notifier.dart';
import 'package:spotube/utils/platform.dart'; import 'package:spotube/utils/platform.dart';
@ -33,6 +35,7 @@ class UserPreferences extends PersistedChangeNotifier {
AudioQuality audioQuality; AudioQuality audioQuality;
SpotubeColor accentColorScheme; SpotubeColor accentColorScheme;
bool albumColorSync;
bool skipSponsorSegments; bool skipSponsorSegments;
String downloadLocation; String downloadLocation;
@ -45,12 +48,16 @@ class UserPreferences extends PersistedChangeNotifier {
bool showSystemTrayIcon; bool showSystemTrayIcon;
UserPreferences({ final Ref ref;
UserPreferences(
this.ref, {
required this.recommendationMarket, required this.recommendationMarket,
required this.themeMode, required this.themeMode,
required this.layoutMode, required this.layoutMode,
required this.predownload, required this.predownload,
required this.accentColorScheme, required this.accentColorScheme,
this.albumColorSync = true,
this.saveTrackLyrics = false, this.saveTrackLyrics = false,
this.checkUpdate = true, this.checkUpdate = true,
this.audioQuality = AudioQuality.high, this.audioQuality = AudioQuality.high,
@ -98,7 +105,13 @@ class UserPreferences extends PersistedChangeNotifier {
updatePersistence(); updatePersistence();
} }
void setBackgroundColorScheme(MaterialColor color) { void setAlbumColorSync(bool sync) {
albumColorSync = sync;
if (!sync) {
ref.read(paletteProvider.notifier).state = null;
} else {
ref.read(PlaylistQueueNotifier.notifier).updatePalette();
}
notifyListeners(); notifyListeners();
updatePersistence(); updatePersistence();
} }
@ -168,6 +181,7 @@ class UserPreferences extends PersistedChangeNotifier {
accentColorScheme = map["accentColorScheme"] != null accentColorScheme = map["accentColorScheme"] != null
? SpotubeColor.fromString(map["accentColorScheme"]) ? SpotubeColor.fromString(map["accentColorScheme"])
: accentColorScheme; : accentColorScheme;
albumColorSync = map["albumColorSync"] ?? albumColorSync;
audioQuality = map["audioQuality"] != null audioQuality = map["audioQuality"] != null
? AudioQuality.values[map["audioQuality"]] ? AudioQuality.values[map["audioQuality"]]
: audioQuality; : audioQuality;
@ -196,6 +210,7 @@ class UserPreferences extends PersistedChangeNotifier {
"recommendationMarket": recommendationMarket, "recommendationMarket": recommendationMarket,
"themeMode": themeMode.index, "themeMode": themeMode.index,
"accentColorScheme": accentColorScheme.toString(), "accentColorScheme": accentColorScheme.toString(),
"albumColorSync": albumColorSync,
"checkUpdate": checkUpdate, "checkUpdate": checkUpdate,
"audioQuality": audioQuality.index, "audioQuality": audioQuality.index,
"skipSponsorSegments": skipSponsorSegments, "skipSponsorSegments": skipSponsorSegments,
@ -209,7 +224,8 @@ class UserPreferences extends PersistedChangeNotifier {
} }
final userPreferencesProvider = ChangeNotifierProvider( final userPreferencesProvider = ChangeNotifierProvider(
(_) => UserPreferences( (ref) => UserPreferences(
ref,
accentColorScheme: SpotubeColor(Colors.blue.value, name: "Blue"), accentColorScheme: SpotubeColor(Colors.blue.value, name: "Blue"),
recommendationMarket: 'US', recommendationMarket: 'US',
themeMode: ThemeMode.system, themeMode: ThemeMode.system,