From 066baa3745abd6973d3e101366982b5d569591d1 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Thu, 26 May 2022 23:17:57 +0600 Subject: [PATCH] Custom Color scheme complete support added --- .../Settings/ColorSchemePickerDialog.dart | 136 ++++++++++++++++++ lib/components/{ => Settings}/Login.dart | 0 lib/components/{ => Settings}/Settings.dart | 32 +++++ lib/main.dart | 12 +- lib/models/GoRouteDeclarations.dart | 5 +- lib/provider/UserPreferences.dart | 18 ++- lib/themes/dark-theme.dart | 4 +- lib/themes/light-theme.dart | 5 +- 8 files changed, 196 insertions(+), 16 deletions(-) create mode 100644 lib/components/Settings/ColorSchemePickerDialog.dart rename lib/components/{ => Settings}/Login.dart (100%) rename lib/components/{ => Settings}/Settings.dart (90%) diff --git a/lib/components/Settings/ColorSchemePickerDialog.dart b/lib/components/Settings/ColorSchemePickerDialog.dart new file mode 100644 index 00000000..89d2984b --- /dev/null +++ b/lib/components/Settings/ColorSchemePickerDialog.dart @@ -0,0 +1,136 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/provider/UserPreferences.dart'; + +final colorsMap = { + "Red": Colors.red, + "Pink": Colors.pink, + "Purple": Colors.purple, + "DeepPurple": Colors.deepPurple, + "Indigo": Colors.indigo, + "Blue": Colors.blue, + "LightBlue": Colors.lightBlue, + "Cyan": Colors.cyan, + "Teal": Colors.teal, + "Green": Colors.green, + "LightGreen": Colors.lightGreen, + "Lime": Colors.lime, + "Yellow": Colors.yellow, + "Amber": Colors.amber, + "Orange": Colors.orange, + "DeepOrange": Colors.deepOrange, + "Brown": Colors.brown, + "BlueGrey": Colors.blueGrey, + "Grey": Colors.grey, +}; + +enum ColorSchemeType { + accent, + background, +} + +class ColorSchemePickerDialog extends HookConsumerWidget { + final ColorSchemeType schemeType; + const ColorSchemePickerDialog({required this.schemeType, Key? key}) + : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final preferences = ref.watch(userPreferencesProvider); + final scheme = schemeType == ColorSchemeType.accent + ? preferences.accentColorScheme + : preferences.backgroundColorScheme; + final active = useState(colorsMap.entries.firstWhere( + (element) { + return scheme.value == element.value.value; + }, + ).key); + + return AlertDialog( + title: Text("Pick ${schemeType.name} color scheme"), + actions: [ + TextButton( + child: const Text("Cancel"), + onPressed: () { + Navigator.pop(context); + }, + ), + ElevatedButton( + child: const Text("Save"), + onPressed: () { + switch (schemeType) { + case ColorSchemeType.accent: + preferences.setAccentColorScheme(colorsMap[active.value]!); + break; + default: + preferences.setBackgroundColorScheme( + colorsMap[active.value]!, + ); + } + Navigator.pop(context); + }, + ) + ], + content: SizedBox( + height: 200, + width: 400, + child: Center( + child: Wrap( + spacing: 10, + runSpacing: 10, + children: colorsMap.entries + .map( + (e) => ColorTile( + color: e.value, + isActive: active.value == e.key, + tooltip: e.key, + onPressed: () { + active.value = e.key; + }, + ), + ) + .toList(), + ), + ), + ), + ); + } +} + +class ColorTile extends StatelessWidget { + final MaterialColor color; + final bool isActive; + final void Function()? onPressed; + final String? tooltip; + const ColorTile({ + required this.color, + this.isActive = false, + this.onPressed, + this.tooltip = "", + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Tooltip( + message: tooltip, + child: GestureDetector( + onTap: onPressed, + child: Container( + height: 50, + width: 50, + decoration: BoxDecoration( + border: isActive + ? const Border.fromBorderSide( + BorderSide(color: Colors.black, width: 5), + ) + : null, + shape: BoxShape.circle, + color: color, + ), + ), + ), + ); + } +} diff --git a/lib/components/Login.dart b/lib/components/Settings/Login.dart similarity index 100% rename from lib/components/Login.dart rename to lib/components/Settings/Login.dart diff --git a/lib/components/Settings.dart b/lib/components/Settings/Settings.dart similarity index 90% rename from lib/components/Settings.dart rename to lib/components/Settings/Settings.dart index d09739bd..9747eb92 100644 --- a/lib/components/Settings.dart +++ b/lib/components/Settings/Settings.dart @@ -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:shared_preferences/shared_preferences.dart'; +import 'package:spotube/components/Settings/ColorSchemePickerDialog.dart'; import 'package:spotube/components/Settings/SettingsHotkeyTile.dart'; import 'package:spotube/components/Shared/Hyperlink.dart'; import 'package:spotube/components/Shared/PageWindowTitleBar.dart'; @@ -39,6 +40,16 @@ class Settings extends HookConsumerWidget { packageName: 'spotube', ); + final pickColorScheme = useCallback((ColorSchemeType schemeType) { + return () => showDialog( + context: context, + builder: (context) { + return ColorSchemePickerDialog( + schemeType: schemeType, + ); + }); + }, []); + return SafeArea( child: Scaffold( appBar: PageWindowTitleBar( @@ -159,6 +170,27 @@ class Settings extends HookConsumerWidget { ], ), const SizedBox(height: 10), + ListTile( + title: const Text("Accent Color Scheme"), + trailing: ColorTile( + color: preferences.accentColorScheme, + onPressed: pickColorScheme(ColorSchemeType.accent), + isActive: true, + ), + onTap: pickColorScheme(ColorSchemeType.accent), + ), + const SizedBox(height: 10), + ListTile( + title: const Text("Background Color Scheme"), + trailing: ColorTile( + color: preferences.backgroundColorScheme, + onPressed: + pickColorScheme(ColorSchemeType.background), + isActive: true, + ), + onTap: pickColorScheme(ColorSchemeType.background), + ), + const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ diff --git a/lib/main.dart b/lib/main.dart index defec1cb..747ec653 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -47,6 +47,10 @@ class MyApp extends HookConsumerWidget { Widget build(BuildContext context, ref) { final themeMode = ref.watch(userPreferencesProvider.select((s) => s.themeMode)); + final accentMaterialColor = + ref.watch(userPreferencesProvider.select((s) => s.accentColorScheme)); + final backgroundMaterialColor = ref + .watch(userPreferencesProvider.select((s) => s.backgroundColorScheme)); final player = ref.watch(audioPlayerProvider); final youtube = ref.watch(youtubeProvider); useEffect(() { @@ -62,12 +66,12 @@ class MyApp extends HookConsumerWidget { debugShowCheckedModeBanner: false, title: 'Spotube', theme: lightTheme( - accentMaterialColor: Colors.deepPurple, - backgroundMaterialColor: Colors.grey, + accentMaterialColor: accentMaterialColor, + backgroundMaterialColor: backgroundMaterialColor, ), darkTheme: darkTheme( - accentMaterialColor: Colors.purple, - backgroundMaterialColor: Colors.grey, + accentMaterialColor: accentMaterialColor, + backgroundMaterialColor: backgroundMaterialColor, ), themeMode: themeMode, ); diff --git a/lib/models/GoRouteDeclarations.dart b/lib/models/GoRouteDeclarations.dart index e734b7bd..3d91cc0b 100644 --- a/lib/models/GoRouteDeclarations.dart +++ b/lib/models/GoRouteDeclarations.dart @@ -1,14 +1,13 @@ import 'package:go_router/go_router.dart'; -import 'package:palette_generator/palette_generator.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/Album/AlbumView.dart'; import 'package:spotube/components/Artist/ArtistAlbumView.dart'; import 'package:spotube/components/Artist/ArtistProfile.dart'; import 'package:spotube/components/Home/Home.dart'; -import 'package:spotube/components/Login.dart'; +import 'package:spotube/components/Settings/Login.dart'; import 'package:spotube/components/Player/PlayerView.dart'; import 'package:spotube/components/Playlist/PlaylistView.dart'; -import 'package:spotube/components/Settings.dart'; +import 'package:spotube/components/Settings/Settings.dart'; import 'package:spotube/components/Shared/SpotubePageRoute.dart'; GoRouter createGoRouter() => GoRouter( diff --git a/lib/provider/UserPreferences.dart b/lib/provider/UserPreferences.dart index 04ae66af..6ffd7c83 100644 --- a/lib/provider/UserPreferences.dart +++ b/lib/provider/UserPreferences.dart @@ -4,9 +4,11 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:hotkey_manager/hotkey_manager.dart'; +import 'package:spotube/components/Settings/ColorSchemePickerDialog.dart'; import 'package:spotube/helpers/get-random-element.dart'; import 'package:spotube/models/generated_secrets.dart'; import 'package:spotube/utils/PersistedChangeNotifier.dart'; +import 'package:collection/collection.dart'; class UserPreferences extends PersistedChangeNotifier { ThemeMode themeMode; @@ -18,19 +20,19 @@ class UserPreferences extends PersistedChangeNotifier { HotKey? prevTrackHotKey; HotKey? playPauseHotKey; - MaterialColor? accentColorScheme; - MaterialColor? backgroundColorScheme; + MaterialColor accentColorScheme; + MaterialColor backgroundColorScheme; UserPreferences({ required this.geniusAccessToken, required this.recommendationMarket, required this.themeMode, required this.ytSearchFormat, this.saveTrackLyrics = false, + this.accentColorScheme = Colors.green, + this.backgroundColorScheme = Colors.grey, this.nextTrackHotKey, this.prevTrackHotKey, this.playPauseHotKey, - this.accentColorScheme, - this.backgroundColorScheme, }) : super(); void setThemeMode(ThemeMode mode) { @@ -110,6 +112,12 @@ class UserPreferences extends PersistedChangeNotifier { : null; ytSearchFormat = map["ytSearchFormat"] ?? ytSearchFormat; themeMode = ThemeMode.values[map["themeMode"] ?? 0]; + backgroundColorScheme = colorsMap.values + .firstWhereOrNull((e) => e.value == map["backgroundColorScheme"]) ?? + backgroundColorScheme; + accentColorScheme = colorsMap.values + .firstWhereOrNull((e) => e.value == map["accentColorScheme"]) ?? + accentColorScheme; } @override @@ -123,6 +131,8 @@ class UserPreferences extends PersistedChangeNotifier { "playPauseHotKey": jsonEncode(playPauseHotKey?.toJson() ?? {}), "ytSearchFormat": ytSearchFormat, "themeMode": themeMode.index, + "backgroundColorScheme": backgroundColorScheme.value, + "accentColorScheme": accentColorScheme.value, }; } } diff --git a/lib/themes/dark-theme.dart b/lib/themes/dark-theme.dart index 12180168..968a147f 100644 --- a/lib/themes/dark-theme.dart +++ b/lib/themes/dark-theme.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; ThemeData darkTheme({ - MaterialColor accentMaterialColor = Colors.green, - MaterialColor backgroundMaterialColor = Colors.blueGrey, + required MaterialColor accentMaterialColor, + required MaterialColor backgroundMaterialColor, }) { return ThemeData( useMaterial3: true, diff --git a/lib/themes/light-theme.dart b/lib/themes/light-theme.dart index 1e00f01f..540def04 100644 --- a/lib/themes/light-theme.dart +++ b/lib/themes/light-theme.dart @@ -14,10 +14,9 @@ final materialWhite = MaterialColor(Colors.white.value, { }); ThemeData lightTheme({ - MaterialColor accentMaterialColor = Colors.green, - MaterialColor? backgroundMaterialColor, + required MaterialColor accentMaterialColor, + required MaterialColor backgroundMaterialColor, }) { - backgroundMaterialColor ??= materialWhite; return ThemeData( useMaterial3: true, primaryColor: accentMaterialColor,