mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 16:05:18 +00:00
feat: album art dominant color as accent color (#447)
This commit is contained in:
parent
cac8ea6388
commit
31b9249cc8
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -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
|
||||||
|
4
lib/provider/palette_provider.dart
Normal file
4
lib/provider/palette_provider.dart
Normal 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);
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user