feat: add theme settings route and update theme management in app settings

This commit is contained in:
Dr-Blank 2024-10-05 06:52:27 -04:00
parent 0437ca110c
commit 9441a2cdd3
No known key found for this signature in database
GPG key ID: 7452CC63F210A266
10 changed files with 301 additions and 131 deletions

View file

@ -66,12 +66,14 @@ class MyApp extends ConsumerWidget {
lightColorScheme = lightDynamic.harmonized(); lightColorScheme = lightDynamic.harmonized();
darkColorScheme = darkDynamic.harmonized(); darkColorScheme = darkDynamic.harmonized();
} else { } else {
lightColorScheme = brandLightColorScheme; lightColorScheme = brandLightColorScheme.harmonized();
darkColorScheme = brandDarkColorScheme; darkColorScheme = brandDarkColorScheme.harmonized();
} }
// set the background and surface colors to pure black in the amoled theme // set the background and surface colors to pure black in the amoled theme
if (themeSettings.highContrast) { if (themeSettings.highContrast) {
lightColorScheme =
lightColorScheme.copyWith(surface: Colors.white).harmonized();
darkColorScheme = darkColorScheme =
darkColorScheme.copyWith(surface: Colors.black).harmonized(); darkColorScheme.copyWith(surface: Colors.black).harmonized();
} }
@ -85,15 +87,25 @@ class MyApp extends ConsumerWidget {
colorScheme: darkColorScheme, colorScheme: darkColorScheme,
brightness: Brightness.dark, brightness: Brightness.dark,
); );
final themeLightHighContrast = themeLight.copyWith(
colorScheme:
lightColorScheme.copyWith(surface: Colors.white).harmonized(),
);
final themeDarkHighContrast = themeDark.copyWith(
colorScheme:
darkColorScheme.copyWith(surface: Colors.black).harmonized(),
);
try { try {
return MaterialApp.router( return MaterialApp.router(
// debugShowCheckedModeBanner: false, // debugShowCheckedModeBanner: false,
theme: themeLight, theme: themeLight,
darkTheme: themeDark, darkTheme: themeDark,
themeMode: themeMode: themeSettings.themeMode,
themeSettings.isDarkMode ? ThemeMode.dark : ThemeMode.light, highContrastTheme: themeLightHighContrast,
highContrastDarkTheme: themeDarkHighContrast,
routerConfig: routerConfig, routerConfig: routerConfig,
themeAnimationCurve: Curves.easeInOut,
); );
} catch (e) { } catch (e) {
debugPrintStack(stackTrace: StackTrace.current, label: e.toString()); debugPrintStack(stackTrace: StackTrace.current, label: e.toString());

View file

@ -27,6 +27,11 @@ class Routes {
pathName: 'config', pathName: 'config',
name: 'settings', name: 'settings',
); );
static const themeSettings = _SimpleRoute(
pathName: 'theme',
name: 'themeSettings',
parentRoute: settings,
);
static const autoSleepTimerSettings = _SimpleRoute( static const autoSleepTimerSettings = _SimpleRoute(
pathName: 'autoSleepTimer', pathName: 'autoSleepTimer',
name: 'autoSleepTimerSettings', name: 'autoSleepTimerSettings',

View file

@ -17,6 +17,7 @@ import 'package:vaani/settings/view/auto_sleep_timer_settings_page.dart';
import 'package:vaani/settings/view/notification_settings_page.dart'; import 'package:vaani/settings/view/notification_settings_page.dart';
import 'package:vaani/settings/view/player_settings_page.dart'; import 'package:vaani/settings/view/player_settings_page.dart';
import 'package:vaani/settings/view/shake_detector_settings_page.dart'; import 'package:vaani/settings/view/shake_detector_settings_page.dart';
import 'package:vaani/settings/view/theme_settings_page.dart';
import 'scaffold_with_nav_bar.dart'; import 'scaffold_with_nav_bar.dart';
import 'transitions/slide.dart'; import 'transitions/slide.dart';
@ -178,6 +179,13 @@ class MyAppRouter {
// builder: (context, state) => const AppSettingsPage(), // builder: (context, state) => const AppSettingsPage(),
pageBuilder: defaultPageBuilder(const AppSettingsPage()), pageBuilder: defaultPageBuilder(const AppSettingsPage()),
routes: [ routes: [
GoRoute(
path: Routes.themeSettings.pathName,
name: Routes.themeSettings.name,
pageBuilder: defaultPageBuilder(
const ThemeSettingsPage(),
),
),
GoRoute( GoRoute(
path: Routes.autoSleepTimerSettings.pathName, path: Routes.autoSleepTimerSettings.pathName,
name: Routes.autoSleepTimerSettings.name, name: Routes.autoSleepTimerSettings.name,

View file

@ -47,11 +47,6 @@ class AppSettings extends _$AppSettings {
_logger.fine('wrote settings to box: $state'); _logger.fine('wrote settings to box: $state');
} }
void toggleDarkMode() {
state = state.copyWith
.themeSettings(isDarkMode: !state.themeSettings.isDarkMode);
}
void update(model.AppSettings newSettings) { void update(model.AppSettings newSettings) {
state = newSettings; state = newSettings;
} }

View file

@ -6,7 +6,7 @@ part of 'app_settings_provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$appSettingsHash() => r'f51d55f117692d4fb9f4b4febf02906c0953d334'; String _$appSettingsHash() => r'314d7936f54550f57d308056a99230402342a6d0';
/// See also [AppSettings]. /// See also [AppSettings].
@ProviderFor(AppSettings) @ProviderFor(AppSettings)

View file

@ -25,19 +25,15 @@ class AppSettings with _$AppSettings {
_$AppSettingsFromJson(json); _$AppSettingsFromJson(json);
} }
enum ThemeType { light, dark, system }
@freezed @freezed
class ThemeSettings with _$ThemeSettings { class ThemeSettings with _$ThemeSettings {
const factory ThemeSettings({ const factory ThemeSettings({
@Default(true) bool isDarkMode, @Default(ThemeMode.system) ThemeMode themeMode,
@Default(ThemeType.system) ThemeType themeType,
@Default(false) bool highContrast, @Default(false) bool highContrast,
@Default(true) bool useMaterialThemeFromSystem, @Default(true) bool useMaterialThemeFromSystem,
@Default('#FF311B92') String customThemeColor, @Default('#FF311B92') String customThemeColor,
@Default(true) bool useMaterialThemeOfPlayingItem, @Default(true) bool useMaterialThemeOfPlayingItem,
@Default(true) bool useMaterialThemeOnItemPage, @Default(true) bool useMaterialThemeOnItemPage,
@Default(true) bool useCurrentPlayerThemeThroughoutApp,
}) = _ThemeSettings; }) = _ThemeSettings;
factory ThemeSettings.fromJson(Map<String, dynamic> json) => factory ThemeSettings.fromJson(Map<String, dynamic> json) =>

View file

@ -378,15 +378,12 @@ ThemeSettings _$ThemeSettingsFromJson(Map<String, dynamic> json) {
/// @nodoc /// @nodoc
mixin _$ThemeSettings { mixin _$ThemeSettings {
bool get isDarkMode => throw _privateConstructorUsedError; ThemeMode get themeMode => throw _privateConstructorUsedError;
ThemeType get themeType => throw _privateConstructorUsedError;
bool get highContrast => throw _privateConstructorUsedError; bool get highContrast => throw _privateConstructorUsedError;
bool get useMaterialThemeFromSystem => throw _privateConstructorUsedError; bool get useMaterialThemeFromSystem => throw _privateConstructorUsedError;
String get customThemeColor => throw _privateConstructorUsedError; String get customThemeColor => throw _privateConstructorUsedError;
bool get useMaterialThemeOfPlayingItem => throw _privateConstructorUsedError; bool get useMaterialThemeOfPlayingItem => throw _privateConstructorUsedError;
bool get useMaterialThemeOnItemPage => throw _privateConstructorUsedError; bool get useMaterialThemeOnItemPage => throw _privateConstructorUsedError;
bool get useCurrentPlayerThemeThroughoutApp =>
throw _privateConstructorUsedError;
/// Serializes this ThemeSettings to a JSON map. /// Serializes this ThemeSettings to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError; Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@ -405,14 +402,12 @@ abstract class $ThemeSettingsCopyWith<$Res> {
_$ThemeSettingsCopyWithImpl<$Res, ThemeSettings>; _$ThemeSettingsCopyWithImpl<$Res, ThemeSettings>;
@useResult @useResult
$Res call( $Res call(
{bool isDarkMode, {ThemeMode themeMode,
ThemeType themeType,
bool highContrast, bool highContrast,
bool useMaterialThemeFromSystem, bool useMaterialThemeFromSystem,
String customThemeColor, String customThemeColor,
bool useMaterialThemeOfPlayingItem, bool useMaterialThemeOfPlayingItem,
bool useMaterialThemeOnItemPage, bool useMaterialThemeOnItemPage});
bool useCurrentPlayerThemeThroughoutApp});
} }
/// @nodoc /// @nodoc
@ -430,24 +425,18 @@ class _$ThemeSettingsCopyWithImpl<$Res, $Val extends ThemeSettings>
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@override @override
$Res call({ $Res call({
Object? isDarkMode = null, Object? themeMode = null,
Object? themeType = null,
Object? highContrast = null, Object? highContrast = null,
Object? useMaterialThemeFromSystem = null, Object? useMaterialThemeFromSystem = null,
Object? customThemeColor = null, Object? customThemeColor = null,
Object? useMaterialThemeOfPlayingItem = null, Object? useMaterialThemeOfPlayingItem = null,
Object? useMaterialThemeOnItemPage = null, Object? useMaterialThemeOnItemPage = null,
Object? useCurrentPlayerThemeThroughoutApp = null,
}) { }) {
return _then(_value.copyWith( return _then(_value.copyWith(
isDarkMode: null == isDarkMode themeMode: null == themeMode
? _value.isDarkMode ? _value.themeMode
: isDarkMode // ignore: cast_nullable_to_non_nullable : themeMode // ignore: cast_nullable_to_non_nullable
as bool, as ThemeMode,
themeType: null == themeType
? _value.themeType
: themeType // ignore: cast_nullable_to_non_nullable
as ThemeType,
highContrast: null == highContrast highContrast: null == highContrast
? _value.highContrast ? _value.highContrast
: highContrast // ignore: cast_nullable_to_non_nullable : highContrast // ignore: cast_nullable_to_non_nullable
@ -468,11 +457,6 @@ class _$ThemeSettingsCopyWithImpl<$Res, $Val extends ThemeSettings>
? _value.useMaterialThemeOnItemPage ? _value.useMaterialThemeOnItemPage
: useMaterialThemeOnItemPage // ignore: cast_nullable_to_non_nullable : useMaterialThemeOnItemPage // ignore: cast_nullable_to_non_nullable
as bool, as bool,
useCurrentPlayerThemeThroughoutApp: null ==
useCurrentPlayerThemeThroughoutApp
? _value.useCurrentPlayerThemeThroughoutApp
: useCurrentPlayerThemeThroughoutApp // ignore: cast_nullable_to_non_nullable
as bool,
) as $Val); ) as $Val);
} }
} }
@ -486,14 +470,12 @@ abstract class _$$ThemeSettingsImplCopyWith<$Res>
@override @override
@useResult @useResult
$Res call( $Res call(
{bool isDarkMode, {ThemeMode themeMode,
ThemeType themeType,
bool highContrast, bool highContrast,
bool useMaterialThemeFromSystem, bool useMaterialThemeFromSystem,
String customThemeColor, String customThemeColor,
bool useMaterialThemeOfPlayingItem, bool useMaterialThemeOfPlayingItem,
bool useMaterialThemeOnItemPage, bool useMaterialThemeOnItemPage});
bool useCurrentPlayerThemeThroughoutApp});
} }
/// @nodoc /// @nodoc
@ -509,24 +491,18 @@ class __$$ThemeSettingsImplCopyWithImpl<$Res>
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@override @override
$Res call({ $Res call({
Object? isDarkMode = null, Object? themeMode = null,
Object? themeType = null,
Object? highContrast = null, Object? highContrast = null,
Object? useMaterialThemeFromSystem = null, Object? useMaterialThemeFromSystem = null,
Object? customThemeColor = null, Object? customThemeColor = null,
Object? useMaterialThemeOfPlayingItem = null, Object? useMaterialThemeOfPlayingItem = null,
Object? useMaterialThemeOnItemPage = null, Object? useMaterialThemeOnItemPage = null,
Object? useCurrentPlayerThemeThroughoutApp = null,
}) { }) {
return _then(_$ThemeSettingsImpl( return _then(_$ThemeSettingsImpl(
isDarkMode: null == isDarkMode themeMode: null == themeMode
? _value.isDarkMode ? _value.themeMode
: isDarkMode // ignore: cast_nullable_to_non_nullable : themeMode // ignore: cast_nullable_to_non_nullable
as bool, as ThemeMode,
themeType: null == themeType
? _value.themeType
: themeType // ignore: cast_nullable_to_non_nullable
as ThemeType,
highContrast: null == highContrast highContrast: null == highContrast
? _value.highContrast ? _value.highContrast
: highContrast // ignore: cast_nullable_to_non_nullable : highContrast // ignore: cast_nullable_to_non_nullable
@ -547,11 +523,6 @@ class __$$ThemeSettingsImplCopyWithImpl<$Res>
? _value.useMaterialThemeOnItemPage ? _value.useMaterialThemeOnItemPage
: useMaterialThemeOnItemPage // ignore: cast_nullable_to_non_nullable : useMaterialThemeOnItemPage // ignore: cast_nullable_to_non_nullable
as bool, as bool,
useCurrentPlayerThemeThroughoutApp: null ==
useCurrentPlayerThemeThroughoutApp
? _value.useCurrentPlayerThemeThroughoutApp
: useCurrentPlayerThemeThroughoutApp // ignore: cast_nullable_to_non_nullable
as bool,
)); ));
} }
} }
@ -560,24 +531,19 @@ class __$$ThemeSettingsImplCopyWithImpl<$Res>
@JsonSerializable() @JsonSerializable()
class _$ThemeSettingsImpl implements _ThemeSettings { class _$ThemeSettingsImpl implements _ThemeSettings {
const _$ThemeSettingsImpl( const _$ThemeSettingsImpl(
{this.isDarkMode = true, {this.themeMode = ThemeMode.system,
this.themeType = ThemeType.system,
this.highContrast = false, this.highContrast = false,
this.useMaterialThemeFromSystem = true, this.useMaterialThemeFromSystem = true,
this.customThemeColor = '#FF311B92', this.customThemeColor = '#FF311B92',
this.useMaterialThemeOfPlayingItem = true, this.useMaterialThemeOfPlayingItem = true,
this.useMaterialThemeOnItemPage = true, this.useMaterialThemeOnItemPage = true});
this.useCurrentPlayerThemeThroughoutApp = true});
factory _$ThemeSettingsImpl.fromJson(Map<String, dynamic> json) => factory _$ThemeSettingsImpl.fromJson(Map<String, dynamic> json) =>
_$$ThemeSettingsImplFromJson(json); _$$ThemeSettingsImplFromJson(json);
@override @override
@JsonKey() @JsonKey()
final bool isDarkMode; final ThemeMode themeMode;
@override
@JsonKey()
final ThemeType themeType;
@override @override
@JsonKey() @JsonKey()
final bool highContrast; final bool highContrast;
@ -593,13 +559,10 @@ class _$ThemeSettingsImpl implements _ThemeSettings {
@override @override
@JsonKey() @JsonKey()
final bool useMaterialThemeOnItemPage; final bool useMaterialThemeOnItemPage;
@override
@JsonKey()
final bool useCurrentPlayerThemeThroughoutApp;
@override @override
String toString() { String toString() {
return 'ThemeSettings(isDarkMode: $isDarkMode, themeType: $themeType, highContrast: $highContrast, useMaterialThemeFromSystem: $useMaterialThemeFromSystem, customThemeColor: $customThemeColor, useMaterialThemeOfPlayingItem: $useMaterialThemeOfPlayingItem, useMaterialThemeOnItemPage: $useMaterialThemeOnItemPage, useCurrentPlayerThemeThroughoutApp: $useCurrentPlayerThemeThroughoutApp)'; return 'ThemeSettings(themeMode: $themeMode, highContrast: $highContrast, useMaterialThemeFromSystem: $useMaterialThemeFromSystem, customThemeColor: $customThemeColor, useMaterialThemeOfPlayingItem: $useMaterialThemeOfPlayingItem, useMaterialThemeOnItemPage: $useMaterialThemeOnItemPage)';
} }
@override @override
@ -607,10 +570,8 @@ class _$ThemeSettingsImpl implements _ThemeSettings {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$ThemeSettingsImpl && other is _$ThemeSettingsImpl &&
(identical(other.isDarkMode, isDarkMode) || (identical(other.themeMode, themeMode) ||
other.isDarkMode == isDarkMode) && other.themeMode == themeMode) &&
(identical(other.themeType, themeType) ||
other.themeType == themeType) &&
(identical(other.highContrast, highContrast) || (identical(other.highContrast, highContrast) ||
other.highContrast == highContrast) && other.highContrast == highContrast) &&
(identical(other.useMaterialThemeFromSystem, (identical(other.useMaterialThemeFromSystem,
@ -626,25 +587,19 @@ class _$ThemeSettingsImpl implements _ThemeSettings {
(identical(other.useMaterialThemeOnItemPage, (identical(other.useMaterialThemeOnItemPage,
useMaterialThemeOnItemPage) || useMaterialThemeOnItemPage) ||
other.useMaterialThemeOnItemPage == other.useMaterialThemeOnItemPage ==
useMaterialThemeOnItemPage) && useMaterialThemeOnItemPage));
(identical(other.useCurrentPlayerThemeThroughoutApp,
useCurrentPlayerThemeThroughoutApp) ||
other.useCurrentPlayerThemeThroughoutApp ==
useCurrentPlayerThemeThroughoutApp));
} }
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash( int get hashCode => Object.hash(
runtimeType, runtimeType,
isDarkMode, themeMode,
themeType,
highContrast, highContrast,
useMaterialThemeFromSystem, useMaterialThemeFromSystem,
customThemeColor, customThemeColor,
useMaterialThemeOfPlayingItem, useMaterialThemeOfPlayingItem,
useMaterialThemeOnItemPage, useMaterialThemeOnItemPage);
useCurrentPlayerThemeThroughoutApp);
/// Create a copy of ThemeSettings /// Create a copy of ThemeSettings
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@ -664,22 +619,18 @@ class _$ThemeSettingsImpl implements _ThemeSettings {
abstract class _ThemeSettings implements ThemeSettings { abstract class _ThemeSettings implements ThemeSettings {
const factory _ThemeSettings( const factory _ThemeSettings(
{final bool isDarkMode, {final ThemeMode themeMode,
final ThemeType themeType,
final bool highContrast, final bool highContrast,
final bool useMaterialThemeFromSystem, final bool useMaterialThemeFromSystem,
final String customThemeColor, final String customThemeColor,
final bool useMaterialThemeOfPlayingItem, final bool useMaterialThemeOfPlayingItem,
final bool useMaterialThemeOnItemPage, final bool useMaterialThemeOnItemPage}) = _$ThemeSettingsImpl;
final bool useCurrentPlayerThemeThroughoutApp}) = _$ThemeSettingsImpl;
factory _ThemeSettings.fromJson(Map<String, dynamic> json) = factory _ThemeSettings.fromJson(Map<String, dynamic> json) =
_$ThemeSettingsImpl.fromJson; _$ThemeSettingsImpl.fromJson;
@override @override
bool get isDarkMode; ThemeMode get themeMode;
@override
ThemeType get themeType;
@override @override
bool get highContrast; bool get highContrast;
@override @override
@ -690,8 +641,6 @@ abstract class _ThemeSettings implements ThemeSettings {
bool get useMaterialThemeOfPlayingItem; bool get useMaterialThemeOfPlayingItem;
@override @override
bool get useMaterialThemeOnItemPage; bool get useMaterialThemeOnItemPage;
@override
bool get useCurrentPlayerThemeThroughoutApp;
/// Create a copy of ThemeSettings /// Create a copy of ThemeSettings
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.

View file

@ -46,9 +46,8 @@ Map<String, dynamic> _$$AppSettingsImplToJson(_$AppSettingsImpl instance) =>
_$ThemeSettingsImpl _$$ThemeSettingsImplFromJson(Map<String, dynamic> json) => _$ThemeSettingsImpl _$$ThemeSettingsImplFromJson(Map<String, dynamic> json) =>
_$ThemeSettingsImpl( _$ThemeSettingsImpl(
isDarkMode: json['isDarkMode'] as bool? ?? true, themeMode: $enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode']) ??
themeType: $enumDecodeNullable(_$ThemeTypeEnumMap, json['themeType']) ?? ThemeMode.system,
ThemeType.system,
highContrast: json['highContrast'] as bool? ?? false, highContrast: json['highContrast'] as bool? ?? false,
useMaterialThemeFromSystem: useMaterialThemeFromSystem:
json['useMaterialThemeFromSystem'] as bool? ?? true, json['useMaterialThemeFromSystem'] as bool? ?? true,
@ -57,27 +56,22 @@ _$ThemeSettingsImpl _$$ThemeSettingsImplFromJson(Map<String, dynamic> json) =>
json['useMaterialThemeOfPlayingItem'] as bool? ?? true, json['useMaterialThemeOfPlayingItem'] as bool? ?? true,
useMaterialThemeOnItemPage: useMaterialThemeOnItemPage:
json['useMaterialThemeOnItemPage'] as bool? ?? true, json['useMaterialThemeOnItemPage'] as bool? ?? true,
useCurrentPlayerThemeThroughoutApp:
json['useCurrentPlayerThemeThroughoutApp'] as bool? ?? true,
); );
Map<String, dynamic> _$$ThemeSettingsImplToJson(_$ThemeSettingsImpl instance) => Map<String, dynamic> _$$ThemeSettingsImplToJson(_$ThemeSettingsImpl instance) =>
<String, dynamic>{ <String, dynamic>{
'isDarkMode': instance.isDarkMode, 'themeMode': _$ThemeModeEnumMap[instance.themeMode]!,
'themeType': _$ThemeTypeEnumMap[instance.themeType]!,
'highContrast': instance.highContrast, 'highContrast': instance.highContrast,
'useMaterialThemeFromSystem': instance.useMaterialThemeFromSystem, 'useMaterialThemeFromSystem': instance.useMaterialThemeFromSystem,
'customThemeColor': instance.customThemeColor, 'customThemeColor': instance.customThemeColor,
'useMaterialThemeOfPlayingItem': instance.useMaterialThemeOfPlayingItem, 'useMaterialThemeOfPlayingItem': instance.useMaterialThemeOfPlayingItem,
'useMaterialThemeOnItemPage': instance.useMaterialThemeOnItemPage, 'useMaterialThemeOnItemPage': instance.useMaterialThemeOnItemPage,
'useCurrentPlayerThemeThroughoutApp':
instance.useCurrentPlayerThemeThroughoutApp,
}; };
const _$ThemeTypeEnumMap = { const _$ThemeModeEnumMap = {
ThemeType.light: 'light', ThemeMode.system: 'system',
ThemeType.dark: 'dark', ThemeMode.light: 'light',
ThemeType.system: 'system', ThemeMode.dark: 'dark',
}; };
_$PlayerSettingsImpl _$$PlayerSettingsImplFromJson(Map<String, dynamic> json) => _$PlayerSettingsImpl _$$PlayerSettingsImplFromJson(Map<String, dynamic> json) =>

View file

@ -43,33 +43,14 @@ class AppSettingsPage extends HookConsumerWidget {
style: Theme.of(context).textTheme.titleLarge, style: Theme.of(context).textTheme.titleLarge,
), ),
tiles: [ tiles: [
SettingsTile.switchTile( SettingsTile.navigation(
initialValue: appSettings.themeSettings.isDarkMode, leading: const Icon(Icons.color_lens),
title: const Text('Dark Mode'), title: const Text('Theme Settings'),
description: const Text('we all know dark mode is better'),
leading: appSettings.themeSettings.isDarkMode
? const Icon(Icons.dark_mode)
: const Icon(Icons.light_mode),
onToggle: (value) {
ref.read(appSettingsProvider.notifier).toggleDarkMode();
},
),
SettingsTile.switchTile(
initialValue:
appSettings.themeSettings.useMaterialThemeOnItemPage,
title: const Text('Adaptive Theme on Item Page'),
description: const Text( description: const Text(
'get fancy with the colors on the item page at the cost of some performance', 'Customize the app theme',
), ),
leading: appSettings.themeSettings.useMaterialThemeOnItemPage onPressed: (context) {
? const Icon(Icons.auto_fix_high) context.pushNamed(Routes.themeSettings.name);
: const Icon(Icons.auto_fix_off),
onToggle: (value) {
ref.read(appSettingsProvider.notifier).update(
appSettings.copyWith.themeSettings(
useMaterialThemeOnItemPage: value,
),
);
}, },
), ),
], ],

View file

@ -0,0 +1,230 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_settings_ui/flutter_settings_ui.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:vaani/settings/app_settings_provider.dart';
import 'package:vaani/settings/view/simple_settings_page.dart';
import 'package:vaani/shared/extensions/enum.dart';
class ThemeSettingsPage extends HookConsumerWidget {
const ThemeSettingsPage({
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final appSettings = ref.watch(appSettingsProvider);
final themeSettings = appSettings.themeSettings;
final primaryColor = Theme.of(context).colorScheme.primary;
return SimpleSettingsPage(
title: const Text('Theme Settings'),
sections: [
SettingsSection(
margin: const EdgeInsetsDirectional.symmetric(
horizontal: 16.0,
vertical: 8.0,
),
tiles: [
// choose system , light or dark theme
SettingsTile.navigation(
title: const Text('Theme Mode'),
description: Text.rich(
TextSpan(
text: themeSettings.themeMode == ThemeMode.system
? 'Using mode from '
: 'Using ',
children: [
TextSpan(
text: themeSettings.themeMode.pascalCase,
style: TextStyle(
color: primaryColor,
),
),
if (themeSettings.themeMode != ThemeMode.system)
const TextSpan(text: ' mode'),
],
),
),
leading: const Icon(Icons.color_lens),
trailing: themeSettings.themeMode == ThemeMode.system
? const Icon(Icons.auto_awesome)
: themeSettings.themeMode == ThemeMode.light
? const Icon(Icons.light_mode)
: const Icon(Icons.dark_mode),
onPressed: (context) async {
final themeMode = await showDialog<ThemeMode>(
context: context,
builder: (context) {
return SimpleDialog(
title: const Text('Select Theme Mode'),
children: [
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, ThemeMode.system);
},
child: const Text('System'),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, ThemeMode.light);
},
child: const Text('Light'),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, ThemeMode.dark);
},
child: const Text('Dark'),
),
],
);
},
);
if (themeMode != null) {
ref.read(appSettingsProvider.notifier).update(
appSettings.copyWith.themeSettings(
themeMode: themeMode,
),
);
}
},
),
// high contrast mode
SettingsTile.switchTile(
leading: themeSettings.highContrast
? const Icon(Icons.accessibility)
: const Icon(Icons.accessibility_new_outlined),
initialValue: themeSettings.highContrast,
title: const Text('High Contrast Mode'),
description: const Text(
'Increase the contrast between the background and the text',
),
onToggle: (value) {
ref.read(appSettingsProvider.notifier).update(
appSettings.copyWith.themeSettings(
highContrast: value,
),
);
},
),
// use material theme from system
SettingsTile.switchTile(
initialValue: themeSettings.useMaterialThemeFromSystem,
title: Platform.isAndroid
? const Text('Use Material You')
: const Text('Material Theme from System'),
description: const Text(
'Use the system theme colors for the app',
),
leading: themeSettings.useMaterialThemeFromSystem
? const Icon(Icons.auto_awesome)
: const Icon(Icons.auto_fix_off),
onToggle: (value) {
ref.read(appSettingsProvider.notifier).update(
appSettings.copyWith.themeSettings(
useMaterialThemeFromSystem: value,
),
);
},
),
// TODO choose the primary color
// SettingsTile.navigation(
// title: const Text('Primary Color'),
// description: const Text(
// 'Choose the primary color for the app',
// ),
// leading: const Icon(Icons.colorize),
// trailing: Icon(
// Icons.circle,
// color: themeSettings.customThemeColor.toColor(),
// ),
// onPressed: (context) async {
// final selectedColor = await showDialog<Color>(
// context: context,
// builder: (context) {
// return SimpleDialog(
// title: const Text('Select Primary Color'),
// children: [
// for (final color in Colors.primaries)
// SimpleDialogOption(
// onPressed: () {
// Navigator.pop(context, color);
// },
// child: Container(
// color: color,
// height: 48,
// ),
// ),
// ],
// );
// },
// );
// if (selectedColor != null) {
// ref.read(appSettingsProvider.notifier).update(
// appSettings.copyWith.themeSettings(
// customThemeColor: selectedColor.toHexString(),
// ),
// );
// }
// },
// ),
// use theme throughout the app when playing item
SettingsTile.switchTile(
initialValue: themeSettings.useMaterialThemeOfPlayingItem,
title: const Text('Adapt theme from currently playing item'),
description: const Text(
'Use the theme colors from the currently playing item for the app',
),
leading: themeSettings.useMaterialThemeOfPlayingItem
? const Icon(Icons.auto_fix_high)
: const Icon(Icons.auto_fix_off),
onToggle: (value) {
ref.read(appSettingsProvider.notifier).update(
appSettings.copyWith.themeSettings(
useMaterialThemeOfPlayingItem: value,
),
);
},
),
SettingsTile.switchTile(
initialValue: themeSettings.useMaterialThemeOnItemPage,
title: const Text('Adaptive Theme on Item Page'),
description: const Text(
'get fancy with the colors on the item page at the cost of some performance',
),
leading: themeSettings.useMaterialThemeOnItemPage
? const Icon(Icons.auto_fix_high)
: const Icon(Icons.auto_fix_off),
onToggle: (value) {
ref.read(appSettingsProvider.notifier).update(
appSettings.copyWith.themeSettings(
useMaterialThemeOnItemPage: value,
),
);
},
),
],
),
],
);
}
}
extension ColorExtension on Color {
String toHexString() {
return '#${value.toRadixString(16).substring(2)}';
}
}
extension StringExtension on String {
Color toColor() {
return Color(int.parse('0xff$substring(1)'));
}
}