From 07780ada4eae73ce6b53237ecd8395e03b98d328 Mon Sep 17 00:00:00 2001 From: Dr-Blank <64108942+Dr-Blank@users.noreply.github.com> Date: Sat, 5 Oct 2024 07:22:00 -0400 Subject: [PATCH] feat: enhance theme management by integrating high contrast support in various components --- .../view/library_item_hero_section.dart | 9 +++-- .../player/view/audiobook_player.dart | 2 + lib/main.dart | 6 ++- lib/theme/theme_from_cover_provider.dart | 21 ++++++++-- lib/theme/theme_from_cover_provider.g.dart | 40 +++++++++++++++++-- 5 files changed, 66 insertions(+), 12 deletions(-) diff --git a/lib/features/item_viewer/view/library_item_hero_section.dart b/lib/features/item_viewer/view/library_item_hero_section.dart index 83b5555..fb6a51c 100644 --- a/lib/features/item_viewer/view/library_item_hero_section.dart +++ b/lib/features/item_viewer/view/library_item_hero_section.dart @@ -353,16 +353,17 @@ class _BookCover extends HookConsumerWidget { final coverImage = ref.watch(coverImageProvider(itemId)); final themeData = Theme.of(context); // final item = ref.watch(libraryItemProvider(itemId)); - final useMaterialThemeOnItemPage = - ref.watch(appSettingsProvider).themeSettings.useMaterialThemeOnItemPage; + final themeSettings = ref.watch(appSettingsProvider).themeSettings; ColorScheme? coverColorScheme; - if (useMaterialThemeOnItemPage) { + if (themeSettings.useMaterialThemeOnItemPage) { coverColorScheme = ref .watch( themeOfLibraryItemProvider( itemId, brightness: Theme.of(context).brightness, + highContrast: MediaQuery.of(context).highContrast || + themeSettings.highContrast, ), ) .valueOrNull; @@ -371,7 +372,7 @@ class _BookCover extends HookConsumerWidget { return ThemeSwitcher( builder: (context) { // change theme after 2 seconds - if (useMaterialThemeOnItemPage) { + if (themeSettings.useMaterialThemeOnItemPage) { Future.delayed(150.ms, () { try { ThemeSwitcher.of(context).changeTheme( diff --git a/lib/features/player/view/audiobook_player.dart b/lib/features/player/view/audiobook_player.dart index 46ed7aa..b659650 100644 --- a/lib/features/player/view/audiobook_player.dart +++ b/lib/features/player/view/audiobook_player.dart @@ -65,6 +65,8 @@ class AudiobookPlayer extends HookConsumerWidget { themeOfLibraryItemProvider( itemBeingPlayed.valueOrNull?.id, brightness: Theme.of(context).brightness, + highContrast: MediaQuery.of(context).highContrast || + appSettings.themeSettings.highContrast, ), ); diff --git a/lib/main.dart b/lib/main.dart index 5469747..dda1925 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -71,7 +71,7 @@ class MyApp extends ConsumerWidget { } // set the background and surface colors to pure black in the amoled theme - if (themeSettings.highContrast) { + if (MediaQuery.of(context).highContrast || themeSettings.highContrast) { lightColorScheme = lightColorScheme.copyWith(surface: Colors.white).harmonized(); darkColorScheme = @@ -86,6 +86,10 @@ class MyApp extends ConsumerWidget { useMaterial3: true, colorScheme: darkColorScheme, brightness: Brightness.dark, + // TODO bottom sheet theme is not working + bottomSheetTheme: BottomSheetThemeData( + backgroundColor: darkColorScheme.surface, + ), ); final themeLightHighContrast = themeLight.copyWith( colorScheme: diff --git a/lib/theme/theme_from_cover_provider.dart b/lib/theme/theme_from_cover_provider.dart index a535f2f..a61a381 100644 --- a/lib/theme/theme_from_cover_provider.dart +++ b/lib/theme/theme_from_cover_provider.dart @@ -1,3 +1,4 @@ +import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:logging/logging.dart'; @@ -13,15 +14,25 @@ Future> themeFromCover( ThemeFromCoverRef ref, ImageProvider img, { Brightness brightness = Brightness.dark, + bool highContrast = false, }) async { // ! add deliberate delay to simulate a long running task as it interferes with other animations await Future.delayed(500.ms); _logger.fine('Generating color scheme from cover image'); - return ColorScheme.fromImageProvider( + var theme = await ColorScheme.fromImageProvider( provider: img, brightness: brightness, ); + // set high contrast theme + if (highContrast) { + theme = theme + .copyWith( + surface: brightness == Brightness.light ? Colors.white : Colors.black, + ) + .harmonized(); + } + return theme; // TODO isolate is not working // see https://github.com/flutter/flutter/issues/119207 // use isolate to generate the color scheme @@ -50,14 +61,18 @@ FutureOr themeOfLibraryItem( ThemeOfLibraryItemRef ref, String? itemId, { Brightness brightness = Brightness.dark, + bool highContrast = false, }) async { if (itemId == null) { return null; } final coverImage = await ref.watch(coverImageProvider(itemId).future); final val = await ref.watch( - themeFromCoverProvider(MemoryImage(coverImage), brightness: brightness) - .future, + themeFromCoverProvider( + MemoryImage(coverImage), + brightness: brightness, + highContrast: highContrast, + ).future, ); return val; // coverImage.when( diff --git a/lib/theme/theme_from_cover_provider.g.dart b/lib/theme/theme_from_cover_provider.g.dart index 61a86a9..07b5790 100644 --- a/lib/theme/theme_from_cover_provider.g.dart +++ b/lib/theme/theme_from_cover_provider.g.dart @@ -6,7 +6,7 @@ part of 'theme_from_cover_provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$themeFromCoverHash() => r'a549513a0dcdff76be94488baf38a8b886ce63eb'; +String _$themeFromCoverHash() => r'f656614e2d4851acdfa16d249b3198ae0e1d6d6f'; /// Copied from Dart SDK class _SystemHash { @@ -42,10 +42,12 @@ class ThemeFromCoverFamily extends Family>> { ThemeFromCoverProvider call( ImageProvider img, { Brightness brightness = Brightness.dark, + bool highContrast = false, }) { return ThemeFromCoverProvider( img, brightness: brightness, + highContrast: highContrast, ); } @@ -56,6 +58,7 @@ class ThemeFromCoverFamily extends Family>> { return call( provider.img, brightness: provider.brightness, + highContrast: provider.highContrast, ); } @@ -80,11 +83,13 @@ class ThemeFromCoverProvider extends FutureProvider> { ThemeFromCoverProvider( ImageProvider img, { Brightness brightness = Brightness.dark, + bool highContrast = false, }) : this._internal( (ref) => themeFromCover( ref as ThemeFromCoverRef, img, brightness: brightness, + highContrast: highContrast, ), from: themeFromCoverProvider, name: r'themeFromCoverProvider', @@ -97,6 +102,7 @@ class ThemeFromCoverProvider extends FutureProvider> { ThemeFromCoverFamily._allTransitiveDependencies, img: img, brightness: brightness, + highContrast: highContrast, ); ThemeFromCoverProvider._internal( @@ -108,10 +114,12 @@ class ThemeFromCoverProvider extends FutureProvider> { required super.from, required this.img, required this.brightness, + required this.highContrast, }) : super.internal(); final ImageProvider img; final Brightness brightness; + final bool highContrast; @override Override overrideWith( @@ -129,6 +137,7 @@ class ThemeFromCoverProvider extends FutureProvider> { debugGetCreateSourceHash: null, img: img, brightness: brightness, + highContrast: highContrast, ), ); } @@ -142,7 +151,8 @@ class ThemeFromCoverProvider extends FutureProvider> { bool operator ==(Object other) { return other is ThemeFromCoverProvider && other.img == img && - other.brightness == brightness; + other.brightness == brightness && + other.highContrast == highContrast; } @override @@ -150,6 +160,7 @@ class ThemeFromCoverProvider extends FutureProvider> { var hash = _SystemHash.combine(0, runtimeType.hashCode); hash = _SystemHash.combine(hash, img.hashCode); hash = _SystemHash.combine(hash, brightness.hashCode); + hash = _SystemHash.combine(hash, highContrast.hashCode); return _SystemHash.finish(hash); } @@ -161,6 +172,9 @@ mixin ThemeFromCoverRef on FutureProviderRef> { /// The parameter `brightness` of this provider. Brightness get brightness; + + /// The parameter `highContrast` of this provider. + bool get highContrast; } class _ThemeFromCoverProviderElement @@ -172,10 +186,12 @@ class _ThemeFromCoverProviderElement ImageProvider get img => (origin as ThemeFromCoverProvider).img; @override Brightness get brightness => (origin as ThemeFromCoverProvider).brightness; + @override + bool get highContrast => (origin as ThemeFromCoverProvider).highContrast; } String _$themeOfLibraryItemHash() => - r'a1d0e5d81f4debe88d5a6ce46c3af28623ad4273'; + r'b2677daf31a6a53f3f237e5204c62dff5ec43171'; /// See also [themeOfLibraryItem]. @ProviderFor(themeOfLibraryItem) @@ -190,10 +206,12 @@ class ThemeOfLibraryItemFamily extends Family> { ThemeOfLibraryItemProvider call( String? itemId, { Brightness brightness = Brightness.dark, + bool highContrast = false, }) { return ThemeOfLibraryItemProvider( itemId, brightness: brightness, + highContrast: highContrast, ); } @@ -204,6 +222,7 @@ class ThemeOfLibraryItemFamily extends Family> { return call( provider.itemId, brightness: provider.brightness, + highContrast: provider.highContrast, ); } @@ -228,11 +247,13 @@ class ThemeOfLibraryItemProvider extends FutureProvider { ThemeOfLibraryItemProvider( String? itemId, { Brightness brightness = Brightness.dark, + bool highContrast = false, }) : this._internal( (ref) => themeOfLibraryItem( ref as ThemeOfLibraryItemRef, itemId, brightness: brightness, + highContrast: highContrast, ), from: themeOfLibraryItemProvider, name: r'themeOfLibraryItemProvider', @@ -245,6 +266,7 @@ class ThemeOfLibraryItemProvider extends FutureProvider { ThemeOfLibraryItemFamily._allTransitiveDependencies, itemId: itemId, brightness: brightness, + highContrast: highContrast, ); ThemeOfLibraryItemProvider._internal( @@ -256,10 +278,12 @@ class ThemeOfLibraryItemProvider extends FutureProvider { required super.from, required this.itemId, required this.brightness, + required this.highContrast, }) : super.internal(); final String? itemId; final Brightness brightness; + final bool highContrast; @override Override overrideWith( @@ -276,6 +300,7 @@ class ThemeOfLibraryItemProvider extends FutureProvider { debugGetCreateSourceHash: null, itemId: itemId, brightness: brightness, + highContrast: highContrast, ), ); } @@ -289,7 +314,8 @@ class ThemeOfLibraryItemProvider extends FutureProvider { bool operator ==(Object other) { return other is ThemeOfLibraryItemProvider && other.itemId == itemId && - other.brightness == brightness; + other.brightness == brightness && + other.highContrast == highContrast; } @override @@ -297,6 +323,7 @@ class ThemeOfLibraryItemProvider extends FutureProvider { var hash = _SystemHash.combine(0, runtimeType.hashCode); hash = _SystemHash.combine(hash, itemId.hashCode); hash = _SystemHash.combine(hash, brightness.hashCode); + hash = _SystemHash.combine(hash, highContrast.hashCode); return _SystemHash.finish(hash); } @@ -308,6 +335,9 @@ mixin ThemeOfLibraryItemRef on FutureProviderRef { /// The parameter `brightness` of this provider. Brightness get brightness; + + /// The parameter `highContrast` of this provider. + bool get highContrast; } class _ThemeOfLibraryItemProviderElement @@ -319,6 +349,8 @@ class _ThemeOfLibraryItemProviderElement @override Brightness get brightness => (origin as ThemeOfLibraryItemProvider).brightness; + @override + bool get highContrast => (origin as ThemeOfLibraryItemProvider).highContrast; } // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member