mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-02 06:46:22 +01:00
Support system theme color (aka Material You)
This commit is contained in:
parent
2c50e06991
commit
cadf9c7410
13 changed files with 216 additions and 109 deletions
|
@ -251,8 +251,14 @@ extension PrefExtension on Pref {
|
||||||
|
|
||||||
int? getSeedColor() => provider.getInt(PrefKey.seedColor);
|
int? getSeedColor() => provider.getInt(PrefKey.seedColor);
|
||||||
int getSeedColorOr(int def) => getSeedColor() ?? def;
|
int getSeedColorOr(int def) => getSeedColor() ?? def;
|
||||||
Future<bool> setSeedColor(int value) => _set<int>(
|
Future<bool> setSeedColor(int? value) {
|
||||||
PrefKey.seedColor, value, (key, value) => provider.setInt(key, value));
|
if (value == null) {
|
||||||
|
return _remove(PrefKey.seedColor);
|
||||||
|
} else {
|
||||||
|
return _set<int>(PrefKey.seedColor, value,
|
||||||
|
(key, value) => provider.setInt(key, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool? isVideoPlayerMute() => provider.getBool(PrefKey.isVideoPlayerMute);
|
bool? isVideoPlayerMute() => provider.getBool(PrefKey.isVideoPlayerMute);
|
||||||
bool isVideoPlayerMuteOr([bool def = false]) => isVideoPlayerMute() ?? def;
|
bool isVideoPlayerMuteOr([bool def = false]) => isVideoPlayerMute() ?? def;
|
||||||
|
|
|
@ -383,10 +383,18 @@
|
||||||
"@settingsSeedColorDescription": {
|
"@settingsSeedColorDescription": {
|
||||||
"description": "Customize the colors used in app"
|
"description": "Customize the colors used in app"
|
||||||
},
|
},
|
||||||
|
"settingsSeedColorSystemColorDescription": "Use system color",
|
||||||
|
"@settingsSeedColorSystemColorDescription": {
|
||||||
|
"description": "Use color provided by the OS, i.e., Material You"
|
||||||
|
},
|
||||||
"settingsSeedColorPickerTitle": "Pick a color",
|
"settingsSeedColorPickerTitle": "Pick a color",
|
||||||
"@settingsSeedColorPickerTitle": {
|
"@settingsSeedColorPickerTitle": {
|
||||||
"description": "Dialog to customize the colors used in app"
|
"description": "Dialog to customize the colors used in app"
|
||||||
},
|
},
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel": "USE SYSTEM COLOR",
|
||||||
|
"@settingsSeedColorPickerSystemColorButtonLabel": {
|
||||||
|
"description": "Use color provided by the OS, i.e., Material You"
|
||||||
|
},
|
||||||
"settingsUseBlackInDarkThemeTitle": "Darker theme",
|
"settingsUseBlackInDarkThemeTitle": "Darker theme",
|
||||||
"@settingsUseBlackInDarkThemeTitle": {
|
"@settingsUseBlackInDarkThemeTitle": {
|
||||||
"description": "Make the dark theme darker"
|
"description": "Make the dark theme darker"
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
"cs": [
|
"cs": [
|
||||||
"nameInputInvalidEmpty",
|
"nameInputInvalidEmpty",
|
||||||
"settingsPersonProviderTitle",
|
"settingsPersonProviderTitle",
|
||||||
|
"settingsSeedColorSystemColorDescription",
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel",
|
||||||
"settingsServerVersionTitle",
|
"settingsServerVersionTitle",
|
||||||
"searchLandingPeopleListEmptyText2",
|
"searchLandingPeopleListEmptyText2",
|
||||||
"createCollectionFailureNotification",
|
"createCollectionFailureNotification",
|
||||||
|
@ -49,7 +51,9 @@
|
||||||
"settingsImageEditSaveResultsToServerFalseDescription",
|
"settingsImageEditSaveResultsToServerFalseDescription",
|
||||||
"settingsSeedColorTitle",
|
"settingsSeedColorTitle",
|
||||||
"settingsSeedColorDescription",
|
"settingsSeedColorDescription",
|
||||||
|
"settingsSeedColorSystemColorDescription",
|
||||||
"settingsSeedColorPickerTitle",
|
"settingsSeedColorPickerTitle",
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel",
|
||||||
"settingsMiscellaneousTitle",
|
"settingsMiscellaneousTitle",
|
||||||
"settingsDoubleTapExitTitle",
|
"settingsDoubleTapExitTitle",
|
||||||
"settingsPhotosTabSortByNameTitle",
|
"settingsPhotosTabSortByNameTitle",
|
||||||
|
@ -242,7 +246,9 @@
|
||||||
"settingsImageEditSaveResultsToServerFalseDescription",
|
"settingsImageEditSaveResultsToServerFalseDescription",
|
||||||
"settingsSeedColorTitle",
|
"settingsSeedColorTitle",
|
||||||
"settingsSeedColorDescription",
|
"settingsSeedColorDescription",
|
||||||
|
"settingsSeedColorSystemColorDescription",
|
||||||
"settingsSeedColorPickerTitle",
|
"settingsSeedColorPickerTitle",
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel",
|
||||||
"settingsDoubleTapExitTitle",
|
"settingsDoubleTapExitTitle",
|
||||||
"settingsExpertTitle",
|
"settingsExpertTitle",
|
||||||
"settingsExpertWarningText",
|
"settingsExpertWarningText",
|
||||||
|
@ -328,12 +334,16 @@
|
||||||
|
|
||||||
"es": [
|
"es": [
|
||||||
"settingsPersonProviderTitle",
|
"settingsPersonProviderTitle",
|
||||||
|
"settingsSeedColorSystemColorDescription",
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel",
|
||||||
"searchLandingPeopleListEmptyText2",
|
"searchLandingPeopleListEmptyText2",
|
||||||
"accountSettingsTooltip"
|
"accountSettingsTooltip"
|
||||||
],
|
],
|
||||||
|
|
||||||
"fi": [
|
"fi": [
|
||||||
"settingsPersonProviderTitle",
|
"settingsPersonProviderTitle",
|
||||||
|
"settingsSeedColorSystemColorDescription",
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel",
|
||||||
"searchLandingPeopleListEmptyText2",
|
"searchLandingPeopleListEmptyText2",
|
||||||
"accountSettingsTooltip"
|
"accountSettingsTooltip"
|
||||||
],
|
],
|
||||||
|
@ -362,7 +372,9 @@
|
||||||
"settingsImageEditSaveResultsToServerFalseDescription",
|
"settingsImageEditSaveResultsToServerFalseDescription",
|
||||||
"settingsSeedColorTitle",
|
"settingsSeedColorTitle",
|
||||||
"settingsSeedColorDescription",
|
"settingsSeedColorDescription",
|
||||||
|
"settingsSeedColorSystemColorDescription",
|
||||||
"settingsSeedColorPickerTitle",
|
"settingsSeedColorPickerTitle",
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel",
|
||||||
"settingsMiscellaneousTitle",
|
"settingsMiscellaneousTitle",
|
||||||
"settingsDoubleTapExitTitle",
|
"settingsDoubleTapExitTitle",
|
||||||
"settingsPhotosTabSortByNameTitle",
|
"settingsPhotosTabSortByNameTitle",
|
||||||
|
@ -495,7 +507,9 @@
|
||||||
"settingsFollowSystemThemeTitle",
|
"settingsFollowSystemThemeTitle",
|
||||||
"settingsSeedColorTitle",
|
"settingsSeedColorTitle",
|
||||||
"settingsSeedColorDescription",
|
"settingsSeedColorDescription",
|
||||||
|
"settingsSeedColorSystemColorDescription",
|
||||||
"settingsSeedColorPickerTitle",
|
"settingsSeedColorPickerTitle",
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel",
|
||||||
"settingsUseBlackInDarkThemeTitle",
|
"settingsUseBlackInDarkThemeTitle",
|
||||||
"settingsUseBlackInDarkThemeTrueDescription",
|
"settingsUseBlackInDarkThemeTrueDescription",
|
||||||
"settingsUseBlackInDarkThemeFalseDescription",
|
"settingsUseBlackInDarkThemeFalseDescription",
|
||||||
|
@ -843,7 +857,9 @@
|
||||||
"settingsFollowSystemThemeTitle",
|
"settingsFollowSystemThemeTitle",
|
||||||
"settingsSeedColorTitle",
|
"settingsSeedColorTitle",
|
||||||
"settingsSeedColorDescription",
|
"settingsSeedColorDescription",
|
||||||
|
"settingsSeedColorSystemColorDescription",
|
||||||
"settingsSeedColorPickerTitle",
|
"settingsSeedColorPickerTitle",
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel",
|
||||||
"settingsUseBlackInDarkThemeTitle",
|
"settingsUseBlackInDarkThemeTitle",
|
||||||
"settingsUseBlackInDarkThemeTrueDescription",
|
"settingsUseBlackInDarkThemeTrueDescription",
|
||||||
"settingsUseBlackInDarkThemeFalseDescription",
|
"settingsUseBlackInDarkThemeFalseDescription",
|
||||||
|
@ -1145,7 +1161,9 @@
|
||||||
"settingsImageEditSaveResultsToServerFalseDescription",
|
"settingsImageEditSaveResultsToServerFalseDescription",
|
||||||
"settingsSeedColorTitle",
|
"settingsSeedColorTitle",
|
||||||
"settingsSeedColorDescription",
|
"settingsSeedColorDescription",
|
||||||
|
"settingsSeedColorSystemColorDescription",
|
||||||
"settingsSeedColorPickerTitle",
|
"settingsSeedColorPickerTitle",
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel",
|
||||||
"settingsMiscellaneousTitle",
|
"settingsMiscellaneousTitle",
|
||||||
"settingsDoubleTapExitTitle",
|
"settingsDoubleTapExitTitle",
|
||||||
"settingsPhotosTabSortByNameTitle",
|
"settingsPhotosTabSortByNameTitle",
|
||||||
|
@ -1265,6 +1283,8 @@
|
||||||
"pt": [
|
"pt": [
|
||||||
"nameInputInvalidEmpty",
|
"nameInputInvalidEmpty",
|
||||||
"settingsPersonProviderTitle",
|
"settingsPersonProviderTitle",
|
||||||
|
"settingsSeedColorSystemColorDescription",
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel",
|
||||||
"settingsServerVersionTitle",
|
"settingsServerVersionTitle",
|
||||||
"searchLandingPeopleListEmptyText2",
|
"searchLandingPeopleListEmptyText2",
|
||||||
"createCollectionFailureNotification",
|
"createCollectionFailureNotification",
|
||||||
|
@ -1302,7 +1322,9 @@
|
||||||
"settingsImageEditSaveResultsToServerFalseDescription",
|
"settingsImageEditSaveResultsToServerFalseDescription",
|
||||||
"settingsSeedColorTitle",
|
"settingsSeedColorTitle",
|
||||||
"settingsSeedColorDescription",
|
"settingsSeedColorDescription",
|
||||||
|
"settingsSeedColorSystemColorDescription",
|
||||||
"settingsSeedColorPickerTitle",
|
"settingsSeedColorPickerTitle",
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel",
|
||||||
"settingsMiscellaneousTitle",
|
"settingsMiscellaneousTitle",
|
||||||
"settingsDoubleTapExitTitle",
|
"settingsDoubleTapExitTitle",
|
||||||
"settingsPhotosTabSortByNameTitle",
|
"settingsPhotosTabSortByNameTitle",
|
||||||
|
@ -1424,7 +1446,9 @@
|
||||||
"settingsImageEditSaveResultsToServerFalseDescription",
|
"settingsImageEditSaveResultsToServerFalseDescription",
|
||||||
"settingsSeedColorTitle",
|
"settingsSeedColorTitle",
|
||||||
"settingsSeedColorDescription",
|
"settingsSeedColorDescription",
|
||||||
|
"settingsSeedColorSystemColorDescription",
|
||||||
"settingsSeedColorPickerTitle",
|
"settingsSeedColorPickerTitle",
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel",
|
||||||
"settingsMiscellaneousTitle",
|
"settingsMiscellaneousTitle",
|
||||||
"settingsDoubleTapExitTitle",
|
"settingsDoubleTapExitTitle",
|
||||||
"settingsPhotosTabSortByNameTitle",
|
"settingsPhotosTabSortByNameTitle",
|
||||||
|
@ -1546,7 +1570,9 @@
|
||||||
"settingsImageEditSaveResultsToServerFalseDescription",
|
"settingsImageEditSaveResultsToServerFalseDescription",
|
||||||
"settingsSeedColorTitle",
|
"settingsSeedColorTitle",
|
||||||
"settingsSeedColorDescription",
|
"settingsSeedColorDescription",
|
||||||
|
"settingsSeedColorSystemColorDescription",
|
||||||
"settingsSeedColorPickerTitle",
|
"settingsSeedColorPickerTitle",
|
||||||
|
"settingsSeedColorPickerSystemColorButtonLabel",
|
||||||
"settingsMiscellaneousTitle",
|
"settingsMiscellaneousTitle",
|
||||||
"settingsDoubleTapExitTitle",
|
"settingsDoubleTapExitTitle",
|
||||||
"settingsPhotosTabSortByNameTitle",
|
"settingsPhotosTabSortByNameTitle",
|
||||||
|
|
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class M3 extends ThemeExtension<M3> {
|
class M3 extends ThemeExtension<M3> {
|
||||||
const M3({
|
const M3({
|
||||||
required this.seed,
|
|
||||||
required this.checkbox,
|
required this.checkbox,
|
||||||
required this.filterChip,
|
required this.filterChip,
|
||||||
required this.listTile,
|
required this.listTile,
|
||||||
|
@ -12,13 +11,11 @@ class M3 extends ThemeExtension<M3> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
M3 copyWith({
|
M3 copyWith({
|
||||||
Color? seed,
|
|
||||||
M3Checkbox? checkbox,
|
M3Checkbox? checkbox,
|
||||||
M3FilterChip? filterChip,
|
M3FilterChip? filterChip,
|
||||||
M3ListTile? listTile,
|
M3ListTile? listTile,
|
||||||
}) =>
|
}) =>
|
||||||
M3(
|
M3(
|
||||||
seed: seed ?? this.seed,
|
|
||||||
checkbox: checkbox ?? this.checkbox,
|
checkbox: checkbox ?? this.checkbox,
|
||||||
filterChip: filterChip ?? this.filterChip,
|
filterChip: filterChip ?? this.filterChip,
|
||||||
listTile: listTile ?? this.listTile,
|
listTile: listTile ?? this.listTile,
|
||||||
|
@ -30,14 +27,12 @@ class M3 extends ThemeExtension<M3> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
return M3(
|
return M3(
|
||||||
seed: Color.lerp(seed, other.seed, t)!,
|
|
||||||
checkbox: checkbox.lerp(other.checkbox, t),
|
checkbox: checkbox.lerp(other.checkbox, t),
|
||||||
filterChip: filterChip.lerp(other.filterChip, t),
|
filterChip: filterChip.lerp(other.filterChip, t),
|
||||||
listTile: listTile.lerp(other.listTile, t),
|
listTile: listTile.lerp(other.listTile, t),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Color seed;
|
|
||||||
final M3Checkbox checkbox;
|
final M3Checkbox checkbox;
|
||||||
final M3FilterChip filterChip;
|
final M3FilterChip filterChip;
|
||||||
final M3ListTile listTile;
|
final M3ListTile listTile;
|
||||||
|
|
|
@ -12,5 +12,8 @@ class SessionStorage {
|
||||||
/// Whether the drag to rearrange notification has been shown
|
/// Whether the drag to rearrange notification has been shown
|
||||||
bool hasShowDragRearrangeNotification = false;
|
bool hasShowDragRearrangeNotification = false;
|
||||||
|
|
||||||
|
/// Whether the dynamic_color library is supported in this platform
|
||||||
|
bool isSupportDynamicColor = false;
|
||||||
|
|
||||||
static final _inst = SessionStorage._();
|
static final _inst = SessionStorage._();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@ import 'dart:ui';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:nc_photos/entity/pref.dart';
|
import 'package:nc_photos/entity/pref.dart';
|
||||||
import 'package:nc_photos/material3.dart';
|
import 'package:nc_photos/material3.dart';
|
||||||
|
import 'package:nc_photos/object_extension.dart';
|
||||||
|
|
||||||
|
const defaultSeedColor = 0xFF2196F3;
|
||||||
|
|
||||||
extension ThemeExtension on ThemeData {
|
extension ThemeExtension on ThemeData {
|
||||||
double get widthLimitedContentMaxWidth => 550.0;
|
double get widthLimitedContentMaxWidth => 550.0;
|
||||||
|
@ -90,38 +93,43 @@ ThemeData buildTheme(Brightness brightness) {
|
||||||
: buildDarkTheme();
|
: buildDarkTheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeData buildLightTheme() {
|
ThemeData buildLightTheme([ColorScheme? dynamicScheme]) {
|
||||||
final seedColor = getSeedColor();
|
final colorScheme = _getColorScheme(dynamicScheme, Brightness.light);
|
||||||
final colorScheme = ColorScheme.fromSeed(
|
return _applyColorScheme(colorScheme);
|
||||||
seedColor: seedColor,
|
|
||||||
);
|
|
||||||
return _applyColorScheme(colorScheme, seedColor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeData buildDarkTheme() {
|
ThemeData buildDarkTheme([ColorScheme? dynamicScheme]) {
|
||||||
final seedColor = getSeedColor();
|
final colorScheme = _getColorScheme(dynamicScheme, Brightness.dark);
|
||||||
final colorScheme = ColorScheme.fromSeed(
|
|
||||||
seedColor: seedColor,
|
|
||||||
brightness: Brightness.dark,
|
|
||||||
);
|
|
||||||
if (Pref().isUseBlackInDarkThemeOr(false)) {
|
if (Pref().isUseBlackInDarkThemeOr(false)) {
|
||||||
return _applyColorScheme(
|
return _applyColorScheme(colorScheme.copyWith(
|
||||||
colorScheme.copyWith(
|
|
||||||
background: Colors.black,
|
background: Colors.black,
|
||||||
surface: Colors.grey[900],
|
surface: Colors.grey[900],
|
||||||
),
|
));
|
||||||
seedColor,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
return _applyColorScheme(colorScheme, seedColor);
|
return _applyColorScheme(colorScheme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Color getSeedColor() {
|
Color? getSeedColor() {
|
||||||
return Color(Pref().getSeedColor() ?? 0xFF2196F3).withAlpha(0xFF);
|
return Pref().getSeedColor()?.run((c) => Color(c).withAlpha(0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeData _applyColorScheme(ColorScheme colorScheme, Color seedColor) {
|
ColorScheme _getColorScheme(ColorScheme? dynamicScheme, Brightness brightness) {
|
||||||
|
var seedColor = Pref().getSeedColor();
|
||||||
|
if (seedColor == null) {
|
||||||
|
if (dynamicScheme != null) {
|
||||||
|
return dynamicScheme;
|
||||||
|
} else {
|
||||||
|
seedColor = defaultSeedColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ColorScheme.fromSeed(
|
||||||
|
seedColor: Color(seedColor),
|
||||||
|
brightness: brightness,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ThemeData _applyColorScheme(ColorScheme colorScheme) {
|
||||||
return ThemeData(
|
return ThemeData(
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
brightness: colorScheme.brightness,
|
brightness: colorScheme.brightness,
|
||||||
|
@ -212,7 +220,6 @@ ThemeData _applyColorScheme(ColorScheme colorScheme, Color seedColor) {
|
||||||
),
|
),
|
||||||
extensions: [
|
extensions: [
|
||||||
M3(
|
M3(
|
||||||
seed: seedColor,
|
|
||||||
checkbox: M3Checkbox(
|
checkbox: M3Checkbox(
|
||||||
disabled: M3CheckboxDisabled(
|
disabled: M3CheckboxDisabled(
|
||||||
container: colorScheme.onSurface.withOpacity(.38),
|
container: colorScheme.onSurface.withOpacity(.38),
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:dynamic_color/dynamic_color.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
@ -13,6 +14,7 @@ import 'package:nc_photos/language_util.dart' as language_util;
|
||||||
import 'package:nc_photos/legacy/connect.dart' as legacy;
|
import 'package:nc_photos/legacy/connect.dart' as legacy;
|
||||||
import 'package:nc_photos/legacy/sign_in.dart' as legacy;
|
import 'package:nc_photos/legacy/sign_in.dart' as legacy;
|
||||||
import 'package:nc_photos/navigation_manager.dart';
|
import 'package:nc_photos/navigation_manager.dart';
|
||||||
|
import 'package:nc_photos/session_storage.dart';
|
||||||
import 'package:nc_photos/snack_bar_manager.dart';
|
import 'package:nc_photos/snack_bar_manager.dart';
|
||||||
import 'package:nc_photos/stream_util.dart';
|
import 'package:nc_photos/stream_util.dart';
|
||||||
import 'package:nc_photos/theme.dart';
|
import 'package:nc_photos/theme.dart';
|
||||||
|
@ -97,7 +99,7 @@ class _WrappedAppState extends State<_WrappedApp>
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ThemeMode themeMode;
|
final ThemeMode themeMode;
|
||||||
if (Pref().isFollowSystemThemeOr(false)) {
|
if (Pref().isFollowSystemThemeOr(false)) {
|
||||||
themeMode = ThemeMode.system;
|
themeMode = ThemeMode.system;
|
||||||
|
@ -108,10 +110,16 @@ class _WrappedAppState extends State<_WrappedApp>
|
||||||
final prefController = context.read<PrefController>();
|
final prefController = context.read<PrefController>();
|
||||||
return ValueStreamBuilder<language_util.AppLanguage>(
|
return ValueStreamBuilder<language_util.AppLanguage>(
|
||||||
stream: prefController.language,
|
stream: prefController.language,
|
||||||
builder: (context, snapshot) => MaterialApp(
|
builder: (context, snapshot) => DynamicColorBuilder(
|
||||||
onGenerateTitle: (context) => AppLocalizations.of(context)!.appTitle,
|
builder: (lightDynamic, darkDynamic) {
|
||||||
theme: buildLightTheme(),
|
if (lightDynamic != null) {
|
||||||
darkTheme: buildDarkTheme(),
|
SessionStorage().isSupportDynamicColor = true;
|
||||||
|
}
|
||||||
|
return MaterialApp(
|
||||||
|
onGenerateTitle: (context) =>
|
||||||
|
AppLocalizations.of(context)!.appTitle,
|
||||||
|
theme: buildLightTheme(lightDynamic),
|
||||||
|
darkTheme: buildDarkTheme(darkDynamic),
|
||||||
themeMode: themeMode,
|
themeMode: themeMode,
|
||||||
initialRoute: Splash.routeName,
|
initialRoute: Splash.routeName,
|
||||||
onGenerateRoute: _onGenerateRoute,
|
onGenerateRoute: _onGenerateRoute,
|
||||||
|
@ -144,6 +152,8 @@ class _WrappedAppState extends State<_WrappedApp>
|
||||||
},
|
},
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
scrollBehavior: const _MyScrollBehavior(),
|
scrollBehavior: const _MyScrollBehavior(),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ class _Bloc extends Bloc<_Event, _State> {
|
||||||
super(_State(
|
super(_State(
|
||||||
isFollowSystemTheme: c.pref.isFollowSystemThemeOr(false),
|
isFollowSystemTheme: c.pref.isFollowSystemThemeOr(false),
|
||||||
isUseBlackInDarkTheme: c.pref.isUseBlackInDarkThemeOr(false),
|
isUseBlackInDarkTheme: c.pref.isUseBlackInDarkThemeOr(false),
|
||||||
seedColor: getSeedColor(),
|
seedColor: getSeedColor()?.value,
|
||||||
)) {
|
)) {
|
||||||
on<_SetFollowSystemTheme>(_onSetFollowSystemTheme);
|
on<_SetFollowSystemTheme>(_onSetFollowSystemTheme);
|
||||||
on<_SetUseBlackInDarkTheme>(_onSetUseBlackInDarkTheme);
|
on<_SetUseBlackInDarkTheme>(_onSetUseBlackInDarkTheme);
|
||||||
|
@ -27,6 +27,7 @@ class _Bloc extends Bloc<_Event, _State> {
|
||||||
|
|
||||||
Future<void> _onSetFollowSystemTheme(
|
Future<void> _onSetFollowSystemTheme(
|
||||||
_SetFollowSystemTheme ev, Emitter<_State> emit) async {
|
_SetFollowSystemTheme ev, Emitter<_State> emit) async {
|
||||||
|
_log.info(ev);
|
||||||
final oldValue = state.isFollowSystemTheme;
|
final oldValue = state.isFollowSystemTheme;
|
||||||
emit(state.copyWith(isFollowSystemTheme: ev.value));
|
emit(state.copyWith(isFollowSystemTheme: ev.value));
|
||||||
if (await _c.pref.setFollowSystemTheme(ev.value)) {
|
if (await _c.pref.setFollowSystemTheme(ev.value)) {
|
||||||
|
@ -40,6 +41,7 @@ class _Bloc extends Bloc<_Event, _State> {
|
||||||
|
|
||||||
Future<void> _onSetUseBlackInDarkTheme(
|
Future<void> _onSetUseBlackInDarkTheme(
|
||||||
_SetUseBlackInDarkTheme ev, Emitter<_State> emit) async {
|
_SetUseBlackInDarkTheme ev, Emitter<_State> emit) async {
|
||||||
|
_log.info(ev);
|
||||||
final oldValue = state.isUseBlackInDarkTheme;
|
final oldValue = state.isUseBlackInDarkTheme;
|
||||||
emit(state.copyWith(isUseBlackInDarkTheme: ev.value));
|
emit(state.copyWith(isUseBlackInDarkTheme: ev.value));
|
||||||
if (await _c.pref.setUseBlackInDarkTheme(ev.value)) {
|
if (await _c.pref.setUseBlackInDarkTheme(ev.value)) {
|
||||||
|
@ -54,9 +56,10 @@ class _Bloc extends Bloc<_Event, _State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onSetSeedColor(_SetSeedColor ev, Emitter<_State> emit) async {
|
Future<void> _onSetSeedColor(_SetSeedColor ev, Emitter<_State> emit) async {
|
||||||
|
_log.info(ev);
|
||||||
final oldValue = state.seedColor;
|
final oldValue = state.seedColor;
|
||||||
emit(state.copyWith(seedColor: ev.value));
|
emit(state.copyWith(seedColor: ev.value?.value));
|
||||||
if (await _c.pref.setSeedColor(ev.value.withAlpha(0xFF).value)) {
|
if (await _c.pref.setSeedColor(ev.value?.withAlpha(0xFF).value)) {
|
||||||
KiwiContainer().resolve<EventBus>().fire(ThemeChangedEvent());
|
KiwiContainer().resolve<EventBus>().fire(ThemeChangedEvent());
|
||||||
} else {
|
} else {
|
||||||
_log.severe("[_onSetSeedColor] Failed writing pref");
|
_log.severe("[_onSetSeedColor] Failed writing pref");
|
||||||
|
|
|
@ -14,7 +14,8 @@ class _State {
|
||||||
|
|
||||||
final bool isFollowSystemTheme;
|
final bool isFollowSystemTheme;
|
||||||
final bool isUseBlackInDarkTheme;
|
final bool isUseBlackInDarkTheme;
|
||||||
final Color seedColor;
|
// workaround analyzer bug where Color type can't be recognized
|
||||||
|
final int? seedColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class _Event {
|
abstract class _Event {
|
||||||
|
@ -49,5 +50,5 @@ class _SetSeedColor extends _Event {
|
||||||
@override
|
@override
|
||||||
String toString() => _$toString();
|
String toString() => _$toString();
|
||||||
|
|
||||||
final Color value;
|
final Color? value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import 'package:nc_photos/event/event.dart';
|
||||||
import 'package:nc_photos/k.dart' as k;
|
import 'package:nc_photos/k.dart' as k;
|
||||||
import 'package:nc_photos/mobile/android/android_info.dart';
|
import 'package:nc_photos/mobile/android/android_info.dart';
|
||||||
import 'package:nc_photos/platform/k.dart' as platform_k;
|
import 'package:nc_photos/platform/k.dart' as platform_k;
|
||||||
|
import 'package:nc_photos/session_storage.dart';
|
||||||
import 'package:nc_photos/snack_bar_manager.dart';
|
import 'package:nc_photos/snack_bar_manager.dart';
|
||||||
import 'package:nc_photos/theme.dart';
|
import 'package:nc_photos/theme.dart';
|
||||||
import 'package:np_codegen/np_codegen.dart';
|
import 'package:np_codegen/np_codegen.dart';
|
||||||
|
@ -23,6 +24,8 @@ part 'theme/bloc.dart';
|
||||||
part 'theme/state_event.dart';
|
part 'theme/state_event.dart';
|
||||||
part 'theme_settings.g.dart';
|
part 'theme_settings.g.dart';
|
||||||
|
|
||||||
|
typedef _BlocBuilder = BlocBuilder<_Bloc, _State>;
|
||||||
|
|
||||||
class ThemeSettings extends StatelessWidget {
|
class ThemeSettings extends StatelessWidget {
|
||||||
const ThemeSettings({super.key});
|
const ThemeSettings({super.key});
|
||||||
|
|
||||||
|
@ -47,7 +50,7 @@ class _WrappedThemeSettingsState extends State<_WrappedThemeSettings> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_errorSubscription = context.read<_Bloc>().errorStream().listen((_) {
|
_errorSubscription = _bloc.errorStream().listen((_) {
|
||||||
SnackBarManager().showSnackBar(SnackBar(
|
SnackBarManager().showSnackBar(SnackBar(
|
||||||
content: Text(L10n.global().writePreferenceFailureNotification),
|
content: Text(L10n.global().writePreferenceFailureNotification),
|
||||||
duration: k.snackBarDurationNormal,
|
duration: k.snackBarDurationNormal,
|
||||||
|
@ -80,25 +83,10 @@ class _WrappedThemeSettingsState extends State<_WrappedThemeSettings> {
|
||||||
SliverList(
|
SliverList(
|
||||||
delegate: SliverChildListDelegate(
|
delegate: SliverChildListDelegate(
|
||||||
[
|
[
|
||||||
BlocBuilder<_Bloc, _State>(
|
const _SeedColorOption(),
|
||||||
buildWhen: (previous, current) =>
|
|
||||||
previous.seedColor != current.seedColor,
|
|
||||||
builder: (context, state) {
|
|
||||||
return ListTile(
|
|
||||||
title: Text(L10n.global().settingsSeedColorTitle),
|
|
||||||
subtitle: Text(L10n.global().settingsSeedColorDescription),
|
|
||||||
trailing: Icon(
|
|
||||||
Icons.circle,
|
|
||||||
size: 32,
|
|
||||||
color: state.seedColor,
|
|
||||||
),
|
|
||||||
onTap: () => _onSeedColorPressed(context),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (platform_k.isAndroid &&
|
if (platform_k.isAndroid &&
|
||||||
AndroidInfo().sdkInt >= AndroidVersion.Q)
|
AndroidInfo().sdkInt >= AndroidVersion.Q)
|
||||||
BlocBuilder<_Bloc, _State>(
|
_BlocBuilder(
|
||||||
buildWhen: (previous, current) =>
|
buildWhen: (previous, current) =>
|
||||||
previous.isFollowSystemTheme !=
|
previous.isFollowSystemTheme !=
|
||||||
current.isFollowSystemTheme,
|
current.isFollowSystemTheme,
|
||||||
|
@ -107,12 +95,12 @@ class _WrappedThemeSettingsState extends State<_WrappedThemeSettings> {
|
||||||
title: Text(L10n.global().settingsFollowSystemThemeTitle),
|
title: Text(L10n.global().settingsFollowSystemThemeTitle),
|
||||||
value: state.isFollowSystemTheme,
|
value: state.isFollowSystemTheme,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
context.read<_Bloc>().add(_SetFollowSystemTheme(value));
|
_bloc.add(_SetFollowSystemTheme(value));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
BlocBuilder<_Bloc, _State>(
|
_BlocBuilder(
|
||||||
buildWhen: (previous, current) =>
|
buildWhen: (previous, current) =>
|
||||||
previous.isUseBlackInDarkTheme !=
|
previous.isUseBlackInDarkTheme !=
|
||||||
current.isUseBlackInDarkTheme,
|
current.isUseBlackInDarkTheme,
|
||||||
|
@ -126,7 +114,7 @@ class _WrappedThemeSettingsState extends State<_WrappedThemeSettings> {
|
||||||
.settingsUseBlackInDarkThemeFalseDescription),
|
.settingsUseBlackInDarkThemeFalseDescription),
|
||||||
value: state.isUseBlackInDarkTheme,
|
value: state.isUseBlackInDarkTheme,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
context.read<_Bloc>().add(
|
_bloc.add(
|
||||||
_SetUseBlackInDarkTheme(value, Theme.of(context)));
|
_SetUseBlackInDarkTheme(value, Theme.of(context)));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -139,20 +127,63 @@ class _WrappedThemeSettingsState extends State<_WrappedThemeSettings> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
late final _bloc = context.read<_Bloc>();
|
||||||
|
late final StreamSubscription _errorSubscription;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SeedColorOption extends StatelessWidget {
|
||||||
|
const _SeedColorOption();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return _BlocBuilder(
|
||||||
|
buildWhen: (previous, current) => previous.seedColor != current.seedColor,
|
||||||
|
builder: (context, state) {
|
||||||
|
if (SessionStorage().isSupportDynamicColor) {
|
||||||
|
return ListTile(
|
||||||
|
title: Text(L10n.global().settingsSeedColorTitle),
|
||||||
|
subtitle: Text(state.seedColor == null
|
||||||
|
? L10n.global().settingsSeedColorSystemColorDescription
|
||||||
|
: L10n.global().settingsSeedColorDescription),
|
||||||
|
trailing: state.seedColor == null
|
||||||
|
? null
|
||||||
|
: Icon(
|
||||||
|
Icons.circle,
|
||||||
|
size: 32,
|
||||||
|
color: Color(state.seedColor!),
|
||||||
|
),
|
||||||
|
onTap: () => _onSeedColorPressed(context),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return ListTile(
|
||||||
|
title: Text(L10n.global().settingsSeedColorTitle),
|
||||||
|
subtitle: Text(L10n.global().settingsSeedColorDescription),
|
||||||
|
trailing: Icon(
|
||||||
|
Icons.circle,
|
||||||
|
size: 32,
|
||||||
|
color: Color(state.seedColor ?? defaultSeedColor),
|
||||||
|
),
|
||||||
|
onTap: () => _onSeedColorPressed(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _onSeedColorPressed(BuildContext context) async {
|
Future<void> _onSeedColorPressed(BuildContext context) async {
|
||||||
final result = await showDialog<Color>(
|
final result = await showDialog<int>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => const _SeedColorPicker(),
|
builder: (context) => const _SeedColorPicker(),
|
||||||
);
|
);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mounted) {
|
if (context.mounted) {
|
||||||
context.read<_Bloc>().add(_SetSeedColor(result));
|
context
|
||||||
|
.read<_Bloc>()
|
||||||
|
.add(_SetSeedColor(result == -1 ? null : Color(result)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
late final StreamSubscription _errorSubscription;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SeedColorPicker extends StatefulWidget {
|
class _SeedColorPicker extends StatefulWidget {
|
||||||
|
@ -180,15 +211,24 @@ class _SeedColorPickerState extends State<_SeedColorPicker> {
|
||||||
]
|
]
|
||||||
.map((c) => _SeedColorPickerItem(
|
.map((c) => _SeedColorPickerItem(
|
||||||
seedColor: c,
|
seedColor: c,
|
||||||
onSelected: () => _onItemSelected(context, c),
|
onSelected: () => _onItemSelected(context, c?.value),
|
||||||
))
|
))
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
|
actions: SessionStorage().isSupportDynamicColor
|
||||||
|
? [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => _onItemSelected(context, -1),
|
||||||
|
child: Text(L10n.global()
|
||||||
|
.settingsSeedColorPickerSystemColorButtonLabel),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onItemSelected(BuildContext context, Color? seedColor) async {
|
Future<void> _onItemSelected(BuildContext context, int? seedColor) async {
|
||||||
if (seedColor != null) {
|
if (seedColor != null) {
|
||||||
Navigator.of(context).pop(seedColor);
|
Navigator.of(context).pop(seedColor);
|
||||||
return;
|
return;
|
||||||
|
@ -198,10 +238,10 @@ class _SeedColorPickerState extends State<_SeedColorPicker> {
|
||||||
});
|
});
|
||||||
final color = await showDialog<Color>(
|
final color = await showDialog<Color>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => const _SeedColorCustomPicker(),
|
builder: (_) => const _SeedColorCustomPicker(),
|
||||||
barrierColor: Colors.transparent,
|
barrierColor: Colors.transparent,
|
||||||
);
|
);
|
||||||
Navigator.of(context).pop(color);
|
Navigator.of(context).pop(color?.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
var _isVisible = true;
|
var _isVisible = true;
|
||||||
|
@ -240,7 +280,7 @@ class _SeedColorCustomPickerState extends State<_SeedColorCustomPicker> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
late Color _customColor = getSeedColor();
|
late Color _customColor = getSeedColor() ?? const Color(defaultSeedColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SeedColorPickerItem extends StatelessWidget {
|
class _SeedColorPickerItem extends StatelessWidget {
|
||||||
|
|
|
@ -14,9 +14,7 @@ part of 'theme_settings.dart';
|
||||||
|
|
||||||
abstract class $_StateCopyWithWorker {
|
abstract class $_StateCopyWithWorker {
|
||||||
_State call(
|
_State call(
|
||||||
{bool? isFollowSystemTheme,
|
{bool? isFollowSystemTheme, bool? isUseBlackInDarkTheme, int? seedColor});
|
||||||
bool? isUseBlackInDarkTheme,
|
|
||||||
Color? seedColor});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
|
class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
|
||||||
|
@ -26,13 +24,14 @@ class _$_StateCopyWithWorkerImpl implements $_StateCopyWithWorker {
|
||||||
_State call(
|
_State call(
|
||||||
{dynamic isFollowSystemTheme,
|
{dynamic isFollowSystemTheme,
|
||||||
dynamic isUseBlackInDarkTheme,
|
dynamic isUseBlackInDarkTheme,
|
||||||
dynamic seedColor}) {
|
dynamic seedColor = copyWithNull}) {
|
||||||
return _State(
|
return _State(
|
||||||
isFollowSystemTheme:
|
isFollowSystemTheme:
|
||||||
isFollowSystemTheme as bool? ?? that.isFollowSystemTheme,
|
isFollowSystemTheme as bool? ?? that.isFollowSystemTheme,
|
||||||
isUseBlackInDarkTheme:
|
isUseBlackInDarkTheme:
|
||||||
isUseBlackInDarkTheme as bool? ?? that.isUseBlackInDarkTheme,
|
isUseBlackInDarkTheme as bool? ?? that.isUseBlackInDarkTheme,
|
||||||
seedColor: seedColor as Color? ?? that.seedColor);
|
seedColor:
|
||||||
|
seedColor == copyWithNull ? that.seedColor : seedColor as int?);
|
||||||
}
|
}
|
||||||
|
|
||||||
final _State that;
|
final _State that;
|
||||||
|
|
|
@ -413,6 +413,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.8.0"
|
version: "2.8.0"
|
||||||
|
dynamic_color:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: dynamic_color
|
||||||
|
sha256: de4798a7069121aee12d5895315680258415de9b00e717723a1bd73d58f0126d
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.6.6"
|
||||||
equatable:
|
equatable:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -1779,4 +1787,4 @@ packages:
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.19.0 <3.0.0"
|
dart: ">=2.19.0 <3.0.0"
|
||||||
flutter: ">=3.3.0"
|
flutter: ">=3.4.0-17.0.pre"
|
||||||
|
|
|
@ -53,6 +53,7 @@ dependencies:
|
||||||
url: https://gitlab.com/nc-photos/flutter-draggable-scrollbar
|
url: https://gitlab.com/nc-photos/flutter-draggable-scrollbar
|
||||||
ref: v0.1.0-nc-photos-6
|
ref: v0.1.0-nc-photos-6
|
||||||
drift: 2.8.0
|
drift: 2.8.0
|
||||||
|
dynamic_color: ^1.6.6
|
||||||
equatable: ^2.0.5
|
equatable: ^2.0.5
|
||||||
event_bus: ^2.0.0
|
event_bus: ^2.0.0
|
||||||
exifdart:
|
exifdart:
|
||||||
|
|
Loading…
Reference in a new issue