#260 optional dynamic accent color

This commit is contained in:
Thibault Deckers 2022-05-29 23:08:33 +09:00
parent cbc958289c
commit 21f3df8003
22 changed files with 297 additions and 183 deletions

View file

@ -32,6 +32,7 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
"canPinShortcut" to ShortcutManagerCompat.isRequestPinShortcutSupported(context),
"canPrint" to (sdkInt >= Build.VERSION_CODES.KITKAT),
"canRenderFlagEmojis" to (sdkInt >= Build.VERSION_CODES.LOLLIPOP),
"isDynamicColorAvailable" to (sdkInt >= Build.VERSION_CODES.S),
"showPinShortcutFeedback" to (sdkInt >= Build.VERSION_CODES.O),
"supportEdgeToEdgeUIMode" to (sdkInt >= Build.VERSION_CODES.Q),
)

View file

@ -723,6 +723,7 @@
"settingsSectionDisplay": "Display",
"settingsThemeBrightness": "Theme",
"settingsThemeColorHighlights": "Color highlights",
"settingsThemeEnableDynamicColor": "Dynamic color",
"settingsDisplayRefreshRateModeTile": "Display refresh rate",
"settingsDisplayRefreshRateModeTitle": "Refresh Rate",

View file

@ -6,7 +6,7 @@ final Device device = Device._private();
class Device {
late final String _userAgent;
late final bool _canGrantDirectoryAccess, _canPinShortcut, _canPrint, _canRenderFlagEmojis;
late final bool _showPinShortcutFeedback, _supportEdgeToEdgeUIMode;
late final bool _isDynamicColorAvailable, _showPinShortcutFeedback, _supportEdgeToEdgeUIMode;
String get userAgent => _userAgent;
@ -18,6 +18,8 @@ class Device {
bool get canRenderFlagEmojis => _canRenderFlagEmojis;
bool get isDynamicColorAvailable => _isDynamicColorAvailable;
bool get showPinShortcutFeedback => _showPinShortcutFeedback;
bool get supportEdgeToEdgeUIMode => _supportEdgeToEdgeUIMode;
@ -33,6 +35,7 @@ class Device {
_canPinShortcut = capabilities['canPinShortcut'] ?? false;
_canPrint = capabilities['canPrint'] ?? false;
_canRenderFlagEmojis = capabilities['canRenderFlagEmojis'] ?? false;
_isDynamicColorAvailable = capabilities['isDynamicColorAvailable'] ?? false;
_showPinShortcutFeedback = capabilities['showPinShortcutFeedback'] ?? false;
_supportEdgeToEdgeUIMode = capabilities['supportEdgeToEdgeUIMode'] ?? false;
}

View file

@ -17,11 +17,15 @@ class SettingsDefaults {
static const canUseAnalysisService = true;
static const isInstalledAppAccessAllowed = false;
static const isErrorReportingAllowed = false;
static const tileLayout = TileLayout.grid;
static const entryRenamingPattern = '<${DateNamingProcessor.key}, yyyyMMdd-HHmmss> <${NameNamingProcessor.key}>';
// display
static const displayRefreshRateMode = DisplayRefreshRateMode.auto;
static const themeBrightness = AvesThemeBrightness.system;
static const themeColorMode = AvesThemeColorMode.polychrome;
static const tileLayout = TileLayout.grid;
static const entryRenamingPattern = '<${DateNamingProcessor.key}, yyyyMMdd-HHmmss> <${NameNamingProcessor.key}>';
static const enableDynamicColor = false;
static const enableBlurEffect = true; // `enableBlurEffect` has a contextual default value
// navigation
static const mustBackTwiceToExit = true;
@ -79,7 +83,6 @@ class SettingsDefaults {
static const showOverlayInfo = true;
static const showOverlayShootingDetails = false;
static const showOverlayThumbnailPreview = false;
static const enableOverlayBlurEffect = true; // `enableOverlayBlurEffect` has a contextual default value
static const viewerUseCutout = true;
static const viewerMaxBrightness = false;
static const enableMotionPhotoAutoPlay = false;

View file

@ -42,15 +42,19 @@ class Settings extends ChangeNotifier {
static const isInstalledAppAccessAllowedKey = 'is_installed_app_access_allowed';
static const isErrorReportingAllowedKey = 'is_crashlytics_enabled';
static const localeKey = 'locale';
static const displayRefreshRateModeKey = 'display_refresh_rate_mode';
static const themeBrightnessKey = 'theme_brightness';
static const themeColorModeKey = 'theme_color_mode';
static const catalogTimeZoneKey = 'catalog_time_zone';
static const tileExtentPrefixKey = 'tile_extent_';
static const tileLayoutPrefixKey = 'tile_layout_';
static const entryRenamingPatternKey = 'entry_renaming_pattern';
static const topEntryIdsKey = 'top_entry_ids';
// display
static const displayRefreshRateModeKey = 'display_refresh_rate_mode';
static const themeBrightnessKey = 'theme_brightness';
static const themeColorModeKey = 'theme_color_mode';
static const enableDynamicColorKey = 'dynamic_color';
static const enableBlurEffectKey = 'enable_overlay_blur_effect';
// navigation
static const mustBackTwiceToExitKey = 'must_back_twice_to_exit';
static const keepScreenOnKey = 'keep_screen_on';
@ -92,7 +96,6 @@ class Settings extends ChangeNotifier {
static const showOverlayInfoKey = 'show_overlay_info';
static const showOverlayShootingDetailsKey = 'show_overlay_shooting_details';
static const showOverlayThumbnailPreviewKey = 'show_overlay_thumbnail_preview';
static const enableOverlayBlurEffectKey = 'enable_overlay_blur_effect';
static const viewerUseCutoutKey = 'viewer_use_cutout';
static const viewerMaxBrightnessKey = 'viewer_max_brightness';
static const enableMotionPhotoAutoPlayKey = 'motion_photo_auto_play';
@ -161,7 +164,7 @@ class Settings extends ChangeNotifier {
Future<void> setContextualDefaults() async {
// performance
final performanceClass = await deviceService.getPerformanceClass();
enableOverlayBlurEffect = performanceClass >= 29;
enableBlurEffect = performanceClass >= 29;
// availability
final defaultMapStyle = mobileServices.defaultMapStyle;
@ -249,18 +252,6 @@ class Settings extends ChangeNotifier {
return _appliedLocale!;
}
DisplayRefreshRateMode get displayRefreshRateMode => getEnumOrDefault(displayRefreshRateModeKey, SettingsDefaults.displayRefreshRateMode, DisplayRefreshRateMode.values);
set displayRefreshRateMode(DisplayRefreshRateMode newValue) => setAndNotify(displayRefreshRateModeKey, newValue.toString());
AvesThemeBrightness get themeBrightness => getEnumOrDefault(themeBrightnessKey, SettingsDefaults.themeBrightness, AvesThemeBrightness.values);
set themeBrightness(AvesThemeBrightness newValue) => setAndNotify(themeBrightnessKey, newValue.toString());
AvesThemeColorMode get themeColorMode => getEnumOrDefault(themeColorModeKey, SettingsDefaults.themeColorMode, AvesThemeColorMode.values);
set themeColorMode(AvesThemeColorMode newValue) => setAndNotify(themeColorModeKey, newValue.toString());
String get catalogTimeZone => getString(catalogTimeZoneKey) ?? '';
set catalogTimeZone(String newValue) => setAndNotify(catalogTimeZoneKey, newValue);
@ -281,6 +272,28 @@ class Settings extends ChangeNotifier {
set topEntryIds(List<int>? newValue) => setAndNotify(topEntryIdsKey, newValue?.map((id) => id.toString()).whereNotNull().toList());
// display
DisplayRefreshRateMode get displayRefreshRateMode => getEnumOrDefault(displayRefreshRateModeKey, SettingsDefaults.displayRefreshRateMode, DisplayRefreshRateMode.values);
set displayRefreshRateMode(DisplayRefreshRateMode newValue) => setAndNotify(displayRefreshRateModeKey, newValue.toString());
AvesThemeBrightness get themeBrightness => getEnumOrDefault(themeBrightnessKey, SettingsDefaults.themeBrightness, AvesThemeBrightness.values);
set themeBrightness(AvesThemeBrightness newValue) => setAndNotify(themeBrightnessKey, newValue.toString());
AvesThemeColorMode get themeColorMode => getEnumOrDefault(themeColorModeKey, SettingsDefaults.themeColorMode, AvesThemeColorMode.values);
set themeColorMode(AvesThemeColorMode newValue) => setAndNotify(themeColorModeKey, newValue.toString());
bool get enableDynamicColor => getBoolOrDefault(enableDynamicColorKey, SettingsDefaults.enableDynamicColor);
set enableDynamicColor(bool newValue) => setAndNotify(enableDynamicColorKey, newValue);
bool get enableBlurEffect => getBoolOrDefault(enableBlurEffectKey, SettingsDefaults.enableBlurEffect);
set enableBlurEffect(bool newValue) => setAndNotify(enableBlurEffectKey, newValue);
// navigation
bool get mustBackTwiceToExit => getBoolOrDefault(mustBackTwiceToExitKey, SettingsDefaults.mustBackTwiceToExit);
@ -441,10 +454,6 @@ class Settings extends ChangeNotifier {
set showOverlayThumbnailPreview(bool newValue) => setAndNotify(showOverlayThumbnailPreviewKey, newValue);
bool get enableOverlayBlurEffect => getBoolOrDefault(enableOverlayBlurEffectKey, SettingsDefaults.enableOverlayBlurEffect);
set enableOverlayBlurEffect(bool newValue) => setAndNotify(enableOverlayBlurEffectKey, newValue);
bool get viewerUseCutout => getBoolOrDefault(viewerUseCutoutKey, SettingsDefaults.viewerUseCutout);
set viewerUseCutout(bool newValue) => setAndNotify(viewerUseCutoutKey, newValue);
@ -695,6 +704,8 @@ class Settings extends ChangeNotifier {
break;
case isInstalledAppAccessAllowedKey:
case isErrorReportingAllowedKey:
case enableDynamicColorKey:
case enableBlurEffectKey:
case showBottomNavigationBarKey:
case mustBackTwiceToExitKey:
case confirmDeleteForeverKey:
@ -713,7 +724,6 @@ class Settings extends ChangeNotifier {
case showOverlayInfoKey:
case showOverlayShootingDetailsKey:
case showOverlayThumbnailPreviewKey:
case enableOverlayBlurEffectKey:
case viewerUseCutoutKey:
case viewerMaxBrightnessKey:
case enableMotionPhotoAutoPlayKey:

View file

@ -7,7 +7,7 @@ import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
class Themes {
static const _accentColor = Colors.indigoAccent;
static const defaultAccent = Colors.indigoAccent;
static const _tooltipTheme = TooltipThemeData(
verticalOffset: 32,
@ -19,10 +19,10 @@ class Themes {
fontFeatures: [FontFeature.enable('smcp')],
);
static const _snackBarTheme = SnackBarThemeData(
actionTextColor: _accentColor,
behavior: SnackBarBehavior.floating,
);
static SnackBarThemeData _snackBarTheme(Color accentColor) => SnackBarThemeData(
actionTextColor: accentColor,
behavior: SnackBarBehavior.floating,
);
static final _typography = Typography.material2018(platform: TargetPlatform.android);
@ -35,49 +35,49 @@ class Themes {
static const _lightSecondLayer = Color(0xFFF5F5F5); // aka `Colors.grey[100]`
static const _lightThirdLayer = Color(0xFFEEEEEE); // aka `Colors.grey[200]`
static final lightTheme = ThemeData(
colorScheme: ColorScheme.light(
primary: _accentColor,
secondary: _accentColor,
onPrimary: _lightBodyColor,
onSecondary: _lightBodyColor,
),
brightness: Brightness.light,
// `canvasColor` is used by `Drawer`, `DropdownButton` and `ExpansionTileCard`
canvasColor: _lightSecondLayer,
scaffoldBackgroundColor: _lightFirstLayer,
// `cardColor` is used by `ExpansionPanel`
cardColor: _lightSecondLayer,
dialogBackgroundColor: _lightSecondLayer,
indicatorColor: _accentColor,
toggleableActiveColor: _accentColor,
typography: _typography,
appBarTheme: AppBarTheme(
backgroundColor: _lightFirstLayer,
// `foregroundColor` is used by icons
foregroundColor: _lightActionIconColor,
// `titleTextStyle.color` is used by text
titleTextStyle: _appBarTitleTextStyle.copyWith(color: _lightTitleColor),
systemOverlayStyle: SystemUiOverlayStyle.dark,
),
listTileTheme: const ListTileThemeData(
iconColor: _lightActionIconColor,
),
popupMenuTheme: const PopupMenuThemeData(
color: _lightSecondLayer,
),
snackBarTheme: _snackBarTheme,
tabBarTheme: TabBarTheme(
labelColor: _lightTitleColor,
unselectedLabelColor: Colors.black54,
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
primary: _lightLabelColor,
),
),
tooltipTheme: _tooltipTheme,
);
static ThemeData lightTheme(Color accentColor) => ThemeData(
colorScheme: ColorScheme.light(
primary: accentColor,
secondary: accentColor,
onPrimary: _lightBodyColor,
onSecondary: _lightBodyColor,
),
brightness: Brightness.light,
// `canvasColor` is used by `Drawer`, `DropdownButton` and `ExpansionTileCard`
canvasColor: _lightSecondLayer,
scaffoldBackgroundColor: _lightFirstLayer,
// `cardColor` is used by `ExpansionPanel`
cardColor: _lightSecondLayer,
dialogBackgroundColor: _lightSecondLayer,
indicatorColor: accentColor,
toggleableActiveColor: accentColor,
typography: _typography,
appBarTheme: AppBarTheme(
backgroundColor: _lightFirstLayer,
// `foregroundColor` is used by icons
foregroundColor: _lightActionIconColor,
// `titleTextStyle.color` is used by text
titleTextStyle: _appBarTitleTextStyle.copyWith(color: _lightTitleColor),
systemOverlayStyle: SystemUiOverlayStyle.dark,
),
listTileTheme: const ListTileThemeData(
iconColor: _lightActionIconColor,
),
popupMenuTheme: const PopupMenuThemeData(
color: _lightSecondLayer,
),
snackBarTheme: _snackBarTheme(accentColor),
tabBarTheme: TabBarTheme(
labelColor: _lightTitleColor,
unselectedLabelColor: Colors.black54,
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
primary: _lightLabelColor,
),
),
tooltipTheme: _tooltipTheme,
);
static final _darkThemeTypo = _typography.white;
static final _darkTitleColor = _darkThemeTypo.titleMedium!.color!;
@ -87,71 +87,74 @@ class Themes {
static const _darkSecondLayer = Color(0xFF363636);
static const _darkThirdLayer = Color(0xFF424242); // aka `Colors.grey[800]`
static final darkTheme = ThemeData(
colorScheme: ColorScheme.dark(
primary: _accentColor,
secondary: _accentColor,
// surface color is used by the date/time pickers
surface: Colors.grey.shade800,
onPrimary: _darkBodyColor,
onSecondary: _darkBodyColor,
),
brightness: Brightness.dark,
// `canvasColor` is used by `Drawer`, `DropdownButton` and `ExpansionTileCard`
canvasColor: _darkSecondLayer,
scaffoldBackgroundColor: _darkFirstLayer,
// `cardColor` is used by `ExpansionPanel`
cardColor: _darkSecondLayer,
dialogBackgroundColor: _darkSecondLayer,
indicatorColor: _accentColor,
toggleableActiveColor: _accentColor,
typography: _typography,
appBarTheme: AppBarTheme(
backgroundColor: _darkFirstLayer,
// `foregroundColor` is used by icons
foregroundColor: _darkTitleColor,
// `titleTextStyle.color` is used by text
titleTextStyle: _appBarTitleTextStyle.copyWith(color: _darkTitleColor),
systemOverlayStyle: SystemUiOverlayStyle.light,
),
popupMenuTheme: const PopupMenuThemeData(
color: _darkSecondLayer,
),
snackBarTheme: _snackBarTheme.copyWith(
backgroundColor: Colors.grey.shade800,
contentTextStyle: TextStyle(
color: _darkBodyColor,
),
),
tabBarTheme: TabBarTheme(
labelColor: _darkTitleColor,
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
primary: _darkLabelColor,
),
),
tooltipTheme: _tooltipTheme,
);
static ThemeData darkTheme(Color accentColor) => ThemeData(
colorScheme: ColorScheme.dark(
primary: accentColor,
secondary: accentColor,
// surface color is used by the date/time pickers
surface: Colors.grey.shade800,
onPrimary: _darkBodyColor,
onSecondary: _darkBodyColor,
),
brightness: Brightness.dark,
// `canvasColor` is used by `Drawer`, `DropdownButton` and `ExpansionTileCard`
canvasColor: _darkSecondLayer,
scaffoldBackgroundColor: _darkFirstLayer,
// `cardColor` is used by `ExpansionPanel`
cardColor: _darkSecondLayer,
dialogBackgroundColor: _darkSecondLayer,
indicatorColor: accentColor,
toggleableActiveColor: accentColor,
typography: _typography,
appBarTheme: AppBarTheme(
backgroundColor: _darkFirstLayer,
// `foregroundColor` is used by icons
foregroundColor: _darkTitleColor,
// `titleTextStyle.color` is used by text
titleTextStyle: _appBarTitleTextStyle.copyWith(color: _darkTitleColor),
systemOverlayStyle: SystemUiOverlayStyle.light,
),
popupMenuTheme: const PopupMenuThemeData(
color: _darkSecondLayer,
),
snackBarTheme: _snackBarTheme(accentColor).copyWith(
backgroundColor: Colors.grey.shade800,
contentTextStyle: TextStyle(
color: _darkBodyColor,
),
),
tabBarTheme: TabBarTheme(
labelColor: _darkTitleColor,
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
primary: _darkLabelColor,
),
),
tooltipTheme: _tooltipTheme,
);
static const _blackFirstLayer = Colors.black;
static const _blackSecondLayer = Color(0xFF212121); // aka `Colors.grey[900]`
static const _blackThirdLayer = Color(0xFF303030); // aka `Colors.grey[850]`
static final blackTheme = darkTheme.copyWith(
// `canvasColor` is used by `Drawer`, `DropdownButton` and `ExpansionTileCard`
canvasColor: _blackSecondLayer,
scaffoldBackgroundColor: _blackFirstLayer,
// `cardColor` is used by `ExpansionPanel`
cardColor: _blackSecondLayer,
dialogBackgroundColor: _blackSecondLayer,
appBarTheme: darkTheme.appBarTheme.copyWith(
backgroundColor: _blackFirstLayer,
),
popupMenuTheme: darkTheme.popupMenuTheme.copyWith(
color: _blackSecondLayer,
),
);
static ThemeData blackTheme(Color accentColor) {
final baseTheme = darkTheme(accentColor);
return baseTheme.copyWith(
// `canvasColor` is used by `Drawer`, `DropdownButton` and `ExpansionTileCard`
canvasColor: _blackSecondLayer,
scaffoldBackgroundColor: _blackFirstLayer,
// `cardColor` is used by `ExpansionPanel`
cardColor: _blackSecondLayer,
dialogBackgroundColor: _blackSecondLayer,
appBarTheme: baseTheme.appBarTheme.copyWith(
backgroundColor: _blackFirstLayer,
),
popupMenuTheme: baseTheme.popupMenuTheme.copyWith(
color: _blackSecondLayer,
),
);
}
static Color overlayBackgroundColor({
required Brightness brightness,

View file

@ -108,6 +108,11 @@ class Constants {
licenseUrl: 'https://github.com/fluttercommunity/plus_plugins/blob/main/packages/device_info_plus/device_info_plus/LICENSE',
sourceUrl: 'https://github.com/fluttercommunity/plus_plugins/tree/main/packages/device_info_plus',
),
Dependency(
name: 'Dynamic Color',
license: 'BSD 3-Clause',
sourceUrl: 'https://github.com/material-foundation/material-dynamic-color-flutter',
),
Dependency(
name: 'fijkplayer (Aves fork)',
license: 'MIT',
@ -337,6 +342,12 @@ class Constants {
license: 'Apache 2.0',
sourceUrl: 'https://github.com/jifalops/dart-latlong',
),
Dependency(
name: 'Material Color Utilities',
license: 'Apache 2.0',
licenseUrl: 'https://github.com/material-foundation/material-color-utilities/tree/main/dart/LICENSE',
sourceUrl: 'https://github.com/material-foundation/material-color-utilities/tree/main/dart',
),
Dependency(
name: 'Path',
license: 'BSD 3-Clause',

View file

@ -5,6 +5,7 @@ import 'package:aves/app_flavor.dart';
import 'package:aves/app_mode.dart';
import 'package:aves/l10n/l10n.dart';
import 'package:aves/model/device.dart';
import 'package:aves/model/settings/defaults.dart';
import 'package:aves/model/settings/enums/accessibility_animations.dart';
import 'package:aves/model/settings/enums/display_refresh_rate_mode.dart';
import 'package:aves/model/settings/enums/enums.dart';
@ -30,11 +31,13 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/providers/highlight_info_provider.dart';
import 'package:aves/widgets/home_page.dart';
import 'package:aves/widgets/welcome_page.dart';
import 'package:dynamic_color/dynamic_color.dart';
import 'package:equatable/equatable.dart';
import 'package:fijkplayer/fijkplayer.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:material_color_utilities/material_color_utilities.dart';
import 'package:overlay_support/overlay_support.dart';
import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
@ -70,6 +73,7 @@ class AvesApp extends StatefulWidget {
class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
final ValueNotifier<AppMode> appModeNotifier = ValueNotifier(AppMode.main);
late Future<void> _appSetup;
late Future<CorePalette?> _dynamicColorPaletteLoader;
final _mediaStoreSource = MediaStoreSource();
final Debouncer _mediaStoreChangeDebouncer = Debouncer(delay: Durations.mediaContentChangeDebounceDelay);
final Set<String> changedUris = {};
@ -89,6 +93,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
super.initState();
EquatableConfig.stringify = true;
_appSetup = _setup();
_dynamicColorPaletteLoader = DynamicColorPlugin.getCorePalette();
_mediaStoreChangeChannel.receiveBroadcastStream().listen((event) => _onMediaStoreChange(event as String?));
_newIntentChannel.receiveBroadcastStream().listen((event) => _onNewIntent(event as Map?));
_analysisCompletionChannel.receiveBroadcastStream().listen((event) => _onAnalysisCompletion());
@ -120,16 +125,18 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
: Scaffold(
body: snapshot.hasError ? _buildError(snapshot.error!) : const SizedBox(),
);
return Selector<Settings, Tuple3<Locale?, bool, AvesThemeBrightness>>(
selector: (context, s) => Tuple3(
return Selector<Settings, Tuple4<Locale?, bool, AvesThemeBrightness, bool>>(
selector: (context, s) => Tuple4(
s.locale,
s.initialized ? s.accessibilityAnimations.animate : true,
s.initialized ? s.themeBrightness : AvesThemeBrightness.system,
s.initialized ? s.themeBrightness : SettingsDefaults.themeBrightness,
s.initialized ? s.enableDynamicColor : SettingsDefaults.enableDynamicColor,
),
builder: (context, s, child) {
final settingsLocale = s.item1;
final areAnimationsEnabled = s.item2;
final themeBrightness = s.item3;
final enableDynamicColor = s.item4;
final pageTransitionsTheme = areAnimationsEnabled
// Flutter has various page transition implementations for Android:
@ -144,27 +151,42 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
// strip page transitions used by `MaterialPageRoute`
: const DirectPageTransitionsTheme();
return MaterialApp(
navigatorKey: AvesApp.navigatorKey,
home: home,
navigatorObservers: _navigatorObservers,
builder: (context, child) => AvesColorsProvider(
child: Theme(
data: Theme.of(context).copyWith(
pageTransitionsTheme: pageTransitionsTheme,
return FutureBuilder<CorePalette?>(
future: _dynamicColorPaletteLoader,
builder: (context, snapshot) {
const defaultAccent = Themes.defaultAccent;
Color lightAccent = defaultAccent, darkAccent = defaultAccent;
if (enableDynamicColor) {
// `DynamicColorBuilder` from package `dynamic_color` provides light/dark
// palettes with a primary color from tones too dark/light (40/80),
// so we derive the color with adjusted tones (60/70)
final tonalPalette = snapshot.data?.primary;
lightAccent = Color(tonalPalette?.get(60) ?? defaultAccent.value);
darkAccent = Color(tonalPalette?.get(70) ?? defaultAccent.value);
}
return MaterialApp(
navigatorKey: AvesApp.navigatorKey,
home: home,
navigatorObservers: _navigatorObservers,
builder: (context, child) => AvesColorsProvider(
child: Theme(
data: Theme.of(context).copyWith(
pageTransitionsTheme: pageTransitionsTheme,
),
child: child!,
),
),
child: child!,
),
),
onGenerateTitle: (context) => context.l10n.appName,
theme: Themes.lightTheme,
darkTheme: themeBrightness == AvesThemeBrightness.black ? Themes.blackTheme : Themes.darkTheme,
themeMode: themeBrightness.appThemeMode,
locale: settingsLocale,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
// TODO TLAD remove custom scroll behavior when this is fixed: https://github.com/flutter/flutter/issues/82906
scrollBehavior: StretchMaterialScrollBehavior(),
onGenerateTitle: (context) => context.l10n.appName,
theme: Themes.lightTheme(lightAccent),
darkTheme: themeBrightness == AvesThemeBrightness.black ? Themes.blackTheme(darkAccent) : Themes.darkTheme(darkAccent),
themeMode: themeBrightness.appThemeMode,
locale: settingsLocale,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
// TODO TLAD remove custom scroll behavior when this is fixed: https://github.com/flutter/flutter/issues/82906
scrollBehavior: StretchMaterialScrollBehavior(),
);
},
);
},
);

View file

@ -206,7 +206,7 @@ class _AvesFloatingBarState extends State<AvesFloatingBar> with RouteAware {
return ValueListenableBuilder<bool>(
valueListenable: _isBlurAllowedNotifier,
builder: (context, isBlurAllowed, child) {
final blurred = isBlurAllowed && context.select<Settings, bool>((s) => s.enableOverlayBlurEffect);
final blurred = isBlurAllowed && context.select<Settings, bool>((s) => s.enableBlurEffect);
return Container(
foregroundDecoration: BoxDecoration(
border: Border.all(

View file

@ -20,7 +20,7 @@ class EmptyContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
const color = Colors.blueGrey;
final color = Theme.of(context).colorScheme.secondary.withOpacity(.5);
return Padding(
padding: safeBottom
? EdgeInsets.only(

View file

@ -20,7 +20,7 @@ class MapOverlayButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final blurred = settings.enableOverlayBlurEffect;
final blurred = settings.enableBlurEffect;
return Selector<MapThemeData, Animation<double>>(
selector: (context, v) => v.scale,
builder: (context, scale, child) => ScaleTransition(

View file

@ -57,7 +57,7 @@ class _OverlayCoordinateFilterChipState extends State<OverlayCoordinateFilterChi
@override
Widget build(BuildContext context) {
final blurred = settings.enableOverlayBlurEffect;
final blurred = settings.enableBlurEffect;
final theme = Theme.of(context);
return Theme(
data: theme.copyWith(

View file

@ -129,7 +129,7 @@ class _AppDrawerState extends State<AppDrawer> {
spacing: 16,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
const AvesLogo(size: 64),
const AvesLogo(size: 56),
Text(
context.l10n.appName,
style: const TextStyle(

View file

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:aves/model/device.dart';
import 'package:aves/model/settings/enums/display_refresh_rate_mode.dart';
import 'package:aves/model/settings/enums/enums.dart';
import 'package:aves/model/settings/enums/theme_brightness.dart';
@ -30,8 +31,9 @@ class DisplaySection extends SettingsSection {
FutureOr<List<SettingsTile>> tiles(BuildContext context) => [
SettingsTileDisplayThemeBrightness(),
SettingsTileDisplayThemeColorMode(),
SettingsTileDisplayDisplayRefreshRateMode(),
if (device.isDynamicColorAvailable) SettingsTileDisplayEnableDynamicColor(),
SettingsTileDisplayEnableBlurEffect(),
SettingsTileDisplayDisplayRefreshRateMode(),
];
}
@ -62,6 +64,30 @@ class SettingsTileDisplayThemeColorMode extends SettingsTile {
);
}
class SettingsTileDisplayEnableDynamicColor extends SettingsTile {
@override
String title(BuildContext context) => context.l10n.settingsThemeEnableDynamicColor;
@override
Widget build(BuildContext context) => SettingsSwitchListTile(
selector: (context, s) => s.enableDynamicColor,
onChanged: (v) => settings.enableDynamicColor = v,
title: title(context),
);
}
class SettingsTileDisplayEnableBlurEffect extends SettingsTile {
@override
String title(BuildContext context) => context.l10n.settingsViewerEnableOverlayBlurEffect;
@override
Widget build(BuildContext context) => SettingsSwitchListTile(
selector: (context, s) => s.enableBlurEffect,
onChanged: (v) => settings.enableBlurEffect = v,
title: title(context),
);
}
class SettingsTileDisplayDisplayRefreshRateMode extends SettingsTile {
@override
String title(BuildContext context) => context.l10n.settingsDisplayRefreshRateModeTile;
@ -76,15 +102,3 @@ class SettingsTileDisplayDisplayRefreshRateMode extends SettingsTile {
dialogTitle: context.l10n.settingsDisplayRefreshRateModeTitle,
);
}
class SettingsTileDisplayEnableBlurEffect extends SettingsTile {
@override
String title(BuildContext context) => context.l10n.settingsViewerEnableOverlayBlurEffect;
@override
Widget build(BuildContext context) => SettingsSwitchListTile(
selector: (context, s) => s.enableOverlayBlurEffect,
onChanged: (v) => settings.enableOverlayBlurEffect = v,
title: title(context),
);
}

View file

@ -19,7 +19,7 @@ class OverlayButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final brightness = Theme.of(context).brightness;
final blurred = settings.enableOverlayBlurEffect;
final blurred = settings.enableBlurEffect;
return ScaleTransition(
scale: scale,
child: borderRadius != null
@ -77,7 +77,7 @@ class OverlayTextButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final blurred = settings.enableOverlayBlurEffect;
final blurred = settings.enableBlurEffect;
final theme = Theme.of(context);
return SizeTransition(
sizeFactor: scale,

View file

@ -42,7 +42,7 @@ class ViewerTopOverlay extends StatelessWidget {
final viewStateConductor = context.read<ViewStateConductor>();
final viewStateNotifier = viewStateConductor.getOrCreateController(pageEntry);
final blurred = settings.enableOverlayBlurEffect;
final blurred = settings.enableBlurEffect;
final viewInsetsPadding = (viewInsets ?? EdgeInsets.zero) + (viewPadding ?? EdgeInsets.zero);
return Column(
mainAxisSize: MainAxisSize.min,

View file

@ -39,7 +39,7 @@ class _VideoProgressBarState extends State<VideoProgressBar> {
@override
Widget build(BuildContext context) {
final blurred = settings.enableOverlayBlurEffect;
final blurred = settings.enableBlurEffect;
final brightness = Theme.of(context).brightness;
final textStyle = TextStyle(
shadows: brightness == Brightness.dark ? Constants.embossShadows : null,

View file

@ -260,6 +260,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
dynamic_color:
dependency: "direct main"
description:
name: dynamic_color
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
equatable:
dependency: "direct main"
description:
@ -589,7 +596,7 @@ packages:
source: hosted
version: "0.12.11"
material_color_utilities:
dependency: transitive
dependency: "direct main"
description:
name: material_color_utilities
url: "https://pub.dartlang.org"

View file

@ -37,6 +37,7 @@ dependencies:
country_code:
decorated_icon:
device_info_plus:
dynamic_color:
equatable:
event_bus:
expansion_tile_card:
@ -56,6 +57,7 @@ dependencies:
get_it:
intl:
latlong2:
material_color_utilities:
material_design_icons_flutter:
overlay_support:
package_info_plus:

View file

@ -41,7 +41,7 @@ Future<void> configureAndLaunch() async {
..showOverlayInfo = true
..showOverlayShootingDetails = false
..showOverlayThumbnailPreview = false
..enableOverlayBlurEffect = true
..enableBlurEffect = true
..viewerUseCutout = true
// info
..infoMapStyle = EntryMapStyle.stamenWatercolor

View file

@ -29,7 +29,7 @@ Future<void> configureAndLaunch() async {
..showOverlayInfo = true
..showOverlayShootingDetails = true
..showOverlayThumbnailPreview = true
..enableOverlayBlurEffect = true
..enableBlurEffect = true
..imageBackground = EntryBackground.checkered
// info
..infoMapStyle = EntryMapStyle.googleNormal;

View file

@ -1,6 +1,43 @@
{
"de": [
"settingsThemeEnableDynamicColor"
],
"es": [
"settingsShowBottomNavigationBar",
"settingsThumbnailShowTagIcon"
"settingsThumbnailShowTagIcon",
"settingsThemeEnableDynamicColor"
],
"fr": [
"settingsThemeEnableDynamicColor"
],
"id": [
"settingsThemeEnableDynamicColor"
],
"it": [
"settingsThemeEnableDynamicColor"
],
"ja": [
"settingsThemeEnableDynamicColor"
],
"ko": [
"settingsThemeEnableDynamicColor"
],
"pt": [
"settingsThemeEnableDynamicColor"
],
"ru": [
"settingsThemeEnableDynamicColor"
],
"zh": [
"settingsThemeEnableDynamicColor"
]
}