mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-23 16:00:41 +00:00
made dynamic colors enabled/disabled
This commit is contained in:
parent
d30295048b
commit
3ad2343456
8 changed files with 151 additions and 64 deletions
1
lib/data/models/dynamic_colors_state.dart
Normal file
1
lib/data/models/dynamic_colors_state.dart
Normal file
|
@ -0,0 +1 @@
|
|||
enum DynamicColorsState { unavailable, enabled, disabled }
|
|
@ -10,6 +10,7 @@ class UserPreferencesService {
|
|||
|
||||
static const _hapticsKey = "haptics";
|
||||
static const _themeTypeKey = "themeType";
|
||||
static const _dynamicColorsKey = "dynamicColors";
|
||||
|
||||
final SharedPreferences _sharedPreferences;
|
||||
|
||||
|
@ -26,4 +27,7 @@ class UserPreferencesService {
|
|||
|
||||
ThemeType get themeType => ThemeType.values[_sharedPreferences.getInt(_themeTypeKey) ?? 0];
|
||||
set themeType(ThemeType value) => _sharedPreferences.setInt(_themeTypeKey, value.index);
|
||||
|
||||
bool get dynamicColors => _sharedPreferences.getBool(_dynamicColorsKey) ?? false;
|
||||
set dynamicColors(bool value) => _sharedPreferences.setBool(_dynamicColorsKey, value);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"haptics": "Haptics",
|
||||
"theme": "Theme",
|
||||
"chooseTheme": "Choose theme",
|
||||
"dynamicColors": "Dynamic colors",
|
||||
"themeLight": "Light",
|
||||
"themeDark": "Dark",
|
||||
"themeSystemDefault": "System default",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:dynamic_color/dynamic_color.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:lightmeter/data/models/dynamic_colors_state.dart';
|
||||
import 'package:lightmeter/data/models/theme_type.dart';
|
||||
import 'package:lightmeter/data/shared_prefs_service.dart';
|
||||
import 'package:material_color_utilities/material_color_utilities.dart';
|
||||
|
@ -8,11 +9,9 @@ import 'package:material_color_utilities/material_color_utilities.dart';
|
|||
import 'package:provider/provider.dart';
|
||||
|
||||
class ThemeProvider extends StatefulWidget {
|
||||
final Widget? child;
|
||||
final TransitionBuilder? builder;
|
||||
|
||||
const ThemeProvider({
|
||||
this.child,
|
||||
this.builder,
|
||||
super.key,
|
||||
});
|
||||
|
@ -26,59 +25,50 @@ class ThemeProvider extends StatefulWidget {
|
|||
}
|
||||
|
||||
class ThemeProviderState extends State<ThemeProvider> {
|
||||
late ThemeType _themeType;
|
||||
Color _primaryColor = const Color(0xFF2196f3);
|
||||
bool _allowDynamicColors = false;
|
||||
|
||||
bool get allowDynamicColors => _allowDynamicColors;
|
||||
late final _themeTypeNotifier = ValueNotifier<ThemeType>(context.read<UserPreferencesService>().themeType);
|
||||
late final _dynamicColorsNotifier = ValueNotifier<bool>(context.read<UserPreferencesService>().dynamicColors);
|
||||
late final _primaryColorNotifier = ValueNotifier<Color>(const Color(0xFF2196f3));
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_themeType = context.read<UserPreferencesService>().themeType;
|
||||
void dispose() {
|
||||
_themeTypeNotifier.dispose();
|
||||
_dynamicColorsNotifier.dispose();
|
||||
_primaryColorNotifier.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DynamicColorBuilder(
|
||||
builder: (lightDynamic, darkDynamic) {
|
||||
_allowDynamicColors = lightDynamic != null && darkDynamic != null;
|
||||
if (_allowDynamicColors) {
|
||||
final dynamicColorScheme = _themeBrightness == Brightness.light ? lightDynamic : darkDynamic;
|
||||
if (dynamicColorScheme != null) {
|
||||
_primaryColor = dynamicColorScheme.primary;
|
||||
}
|
||||
}
|
||||
return Provider.value(
|
||||
value: _themeType,
|
||||
child: Provider.value(
|
||||
value: _themeFromColorScheme(
|
||||
_colorSchemeFromColor(
|
||||
_primaryColor,
|
||||
_themeBrightness,
|
||||
),
|
||||
),
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: _themeTypeNotifier,
|
||||
builder: (_, themeType, __) => Provider.value(
|
||||
value: themeType,
|
||||
child: ValueListenableBuilder(
|
||||
valueListenable: _dynamicColorsNotifier,
|
||||
builder: (_, useDynamicColors, __) => _DynamicColorsProvider(
|
||||
useDynamicColors: useDynamicColors,
|
||||
themeBrightness: _themeBrightness,
|
||||
builder: (_, dynamicPrimaryColor) => ValueListenableBuilder(
|
||||
valueListenable: _primaryColorNotifier,
|
||||
builder: (_, primaryColor, __) => _ThemeDataProvider(
|
||||
primaryColor: dynamicPrimaryColor ?? primaryColor,
|
||||
brightness: _themeBrightness,
|
||||
builder: widget.builder,
|
||||
child: widget.child,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void setThemeType(ThemeType themeType) {
|
||||
if (themeType == _themeType) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_themeType = themeType;
|
||||
});
|
||||
_themeTypeNotifier.value = themeType;
|
||||
context.read<UserPreferencesService>().themeType = themeType;
|
||||
}
|
||||
|
||||
Brightness get _themeBrightness {
|
||||
switch (_themeType) {
|
||||
switch (_themeTypeNotifier.value) {
|
||||
case ThemeType.light:
|
||||
return Brightness.light;
|
||||
case ThemeType.dark:
|
||||
|
@ -88,18 +78,84 @@ class ThemeProviderState extends State<ThemeProvider> {
|
|||
}
|
||||
}
|
||||
|
||||
void setPrimaryColor(Color color) {
|
||||
if (color == _primaryColor) {
|
||||
return;
|
||||
void enableDynamicColors(bool enable) {
|
||||
_dynamicColorsNotifier.value = enable;
|
||||
context.read<UserPreferencesService>().dynamicColors = enable;
|
||||
}
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_primaryColor = color;
|
||||
class _DynamicColorsProvider extends StatelessWidget {
|
||||
final bool useDynamicColors;
|
||||
final Brightness themeBrightness;
|
||||
final Widget Function(BuildContext context, Color? primaryColor) builder;
|
||||
|
||||
const _DynamicColorsProvider({
|
||||
required this.useDynamicColors,
|
||||
required this.themeBrightness,
|
||||
required this.builder,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DynamicColorBuilder(
|
||||
builder: (lightDynamic, darkDynamic) {
|
||||
late final DynamicColorsState state;
|
||||
late final Color? dynamicPrimaryColor;
|
||||
if (lightDynamic != null && darkDynamic != null) {
|
||||
if (useDynamicColors) {
|
||||
dynamicPrimaryColor = (themeBrightness == Brightness.light ? lightDynamic : darkDynamic).primary;
|
||||
state = DynamicColorsState.enabled;
|
||||
} else {
|
||||
dynamicPrimaryColor = null;
|
||||
state = DynamicColorsState.disabled;
|
||||
}
|
||||
} else {
|
||||
dynamicPrimaryColor = null;
|
||||
state = DynamicColorsState.unavailable;
|
||||
}
|
||||
return Provider.value(
|
||||
value: state,
|
||||
child: builder(context, dynamicPrimaryColor),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ThemeDataProvider extends StatelessWidget {
|
||||
final Color primaryColor;
|
||||
final Brightness brightness;
|
||||
final TransitionBuilder? builder;
|
||||
|
||||
const _ThemeDataProvider({
|
||||
required this.primaryColor,
|
||||
required this.brightness,
|
||||
required this.builder,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Provider.value(
|
||||
value: _themeFromColorScheme(_colorSchemeFromColor()),
|
||||
builder: builder,
|
||||
);
|
||||
}
|
||||
|
||||
ColorScheme _colorSchemeFromColor(Color color, Brightness brightness) {
|
||||
final scheme = brightness == Brightness.light ? Scheme.light(color.value) : Scheme.dark(color.value);
|
||||
ThemeData _themeFromColorScheme(ColorScheme scheme) {
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
bottomAppBarColor: scheme.surface,
|
||||
brightness: scheme.brightness,
|
||||
colorScheme: scheme,
|
||||
dialogBackgroundColor: scheme.surface,
|
||||
dialogTheme: DialogTheme(backgroundColor: scheme.surface),
|
||||
scaffoldBackgroundColor: scheme.surface,
|
||||
toggleableActiveColor: scheme.primary,
|
||||
);
|
||||
}
|
||||
|
||||
ColorScheme _colorSchemeFromColor() {
|
||||
final scheme = brightness == Brightness.light ? Scheme.light(primaryColor.value) : Scheme.dark(primaryColor.value);
|
||||
return ColorScheme(
|
||||
brightness: brightness,
|
||||
primary: Color(scheme.primary),
|
||||
|
@ -118,17 +174,4 @@ class ThemeProviderState extends State<ThemeProvider> {
|
|||
onSurfaceVariant: Color(scheme.onSurfaceVariant),
|
||||
);
|
||||
}
|
||||
|
||||
ThemeData _themeFromColorScheme(ColorScheme scheme) {
|
||||
return ThemeData(
|
||||
useMaterial3: true,
|
||||
bottomAppBarColor: scheme.surface,
|
||||
brightness: scheme.brightness,
|
||||
colorScheme: scheme,
|
||||
dialogBackgroundColor: scheme.surface,
|
||||
dialogTheme: DialogTheme(backgroundColor: scheme.surface),
|
||||
scaffoldBackgroundColor: scheme.surface,
|
||||
toggleableActiveColor: scheme.primary,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:lightmeter/data/models/dynamic_colors_state.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/res/theme.dart';
|
||||
|
||||
class DynamicColorsListTile extends StatelessWidget {
|
||||
const DynamicColorsListTile({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SwitchListTile(
|
||||
secondary: const Icon(Icons.colorize),
|
||||
title: Text(S.of(context).dynamicColors),
|
||||
value: context.watch<DynamicColorsState>() == DynamicColorsState.enabled,
|
||||
onChanged: ThemeProvider.of(context).enableDynamicColors,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,10 +2,9 @@ import 'package:flutter/material.dart';
|
|||
import 'package:lightmeter/data/models/theme_type.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/res/theme.dart';
|
||||
import 'package:lightmeter/screens/settings/components/shared/widget_dialog_picker.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'shared/widget_dialog_picker.dart';
|
||||
|
||||
class ThemeTypeListTile extends StatelessWidget {
|
||||
const ThemeTypeListTile({super.key});
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/data/models/dynamic_colors_state.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'components/widget_list_tile_dynamic_colors.dart';
|
||||
import 'components/widget_list_tile_theme_type.dart';
|
||||
|
||||
class ThemeSettings extends StatelessWidget {
|
||||
const ThemeSettings({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
const ThemeTypeListTile(),
|
||||
if (context.read<DynamicColorsState>() != DynamicColorsState.unavailable) const DynamicColorsListTile(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ import 'package:lightmeter/res/dimens.dart';
|
|||
|
||||
import 'components/haptics/provider_list_tile_haptics.dart';
|
||||
import 'components/widget_list_tile_fractional_stops.dart';
|
||||
import 'components/widget_list_tile_theme_type.dart';
|
||||
import 'components/theme/widget_settings_theme.dart';
|
||||
import 'components/widget_label_version.dart';
|
||||
|
||||
class SettingsScreen extends StatelessWidget {
|
||||
|
@ -41,7 +41,7 @@ class SettingsScreen extends StatelessWidget {
|
|||
[
|
||||
const StopTypeListTile(),
|
||||
const HapticsListTileProvider(),
|
||||
const ThemeTypeListTile(),
|
||||
const ThemeSettings(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
Loading…
Reference in a new issue