From d4c52224306fd29d41d7c67f62322821145ec518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Apitzsch?= Date: Thu, 25 Jun 2026 10:38:03 +0200 Subject: [PATCH] Fix high contrast themes All contrast ratios should be in line with WCAG AAA. Meaning a contrast ratio of at least 7:1 for normal text and 4.5:1 for large text. Currently only applicable on iOS. --- lib/commons/themes.dart | 47 ++++++++++++++++--- .../completed_area_layer.dart | 4 +- .../osm_element_layer/osm_element_marker.dart | 5 +- lib/widgets/question_inputs/bool_input.dart | 5 +- 4 files changed, 49 insertions(+), 12 deletions(-) diff --git a/lib/commons/themes.dart b/lib/commons/themes.dart index ce2a4ceb..2ef61797 100644 --- a/lib/commons/themes.dart +++ b/lib/commons/themes.dart @@ -8,11 +8,11 @@ class Default { // (FloatingAction)Button Foreground Selected / Account Background, Border, Text static Color onPrimary = Colors.grey.shade100; - // FloatingActionButton Background Unselected + // FloatingActionButton Background Unselected / Marker Background static Color primaryContainerLight = Colors.grey.shade100; static const Color primaryContainerDark = Color(0xFF002020); - // (FloatingAction)Button Foreground Unselected + // (FloatingAction)Button Foreground Unselected / Marker Foreground static Color onPrimaryContainerLight = Colors.grey.shade900; static Color onPrimaryContainerDark = Colors.grey.shade50; @@ -164,18 +164,51 @@ final ThemeData darkTheme = ThemeData( scaffoldBackgroundColor: Default.surfaceDark, ); -final ThemeData highContrastDarkTheme = ThemeData.dark().copyWith( - colorScheme: const ColorScheme.highContrastDark(), +final ThemeData highContrastDarkTheme = ThemeData( + colorScheme: ThemeData.dark().colorScheme.copyWith( + primary: Default.primary, + onPrimary: Colors.black, + primaryContainer: Colors.white, + onPrimaryContainer: Colors.black, + surface: Colors.black, + tertiary: Colors.black, + onTertiary: Colors.white, + error: Colors.orange, + ), + appBarTheme: defaultTheme.appBarTheme.copyWith( + foregroundColor: Colors.black, + ), floatingActionButtonTheme: defaultTheme.floatingActionButtonTheme, outlinedButtonTheme: defaultTheme.outlinedButtonTheme, iconButtonTheme: defaultTheme.iconButtonTheme, inputDecorationTheme: defaultTheme.inputDecorationTheme, ); -final ThemeData highContrastLightTheme = ThemeData.light().copyWith( - colorScheme: const ColorScheme.highContrastLight(), +final ThemeData highContrastLightTheme = ThemeData( + colorScheme: ThemeData.light().colorScheme.copyWith( + primary: Default.primary, + onPrimary: Colors.black, + primaryContainer: Colors.black, + onPrimaryContainer: Colors.white, + surface: Colors.white, + tertiary: Colors.white, + onTertiary: Colors.black, + error: Colors.purple.shade600, + ), + appBarTheme: defaultTheme.appBarTheme.copyWith( + foregroundColor: Colors.black, + ), floatingActionButtonTheme: defaultTheme.floatingActionButtonTheme, - outlinedButtonTheme: defaultTheme.outlinedButtonTheme, + outlinedButtonTheme: OutlinedButtonThemeData( + style: defaultTheme.outlinedButtonTheme.style?.copyWith( + foregroundColor: WidgetStateProperty.all(Colors.black), + ), + ), + textButtonTheme: TextButtonThemeData( + style: ButtonStyle( + foregroundColor: WidgetStateProperty.all(Colors.black), + ), + ), iconButtonTheme: defaultTheme.iconButtonTheme, inputDecorationTheme: defaultTheme.inputDecorationTheme, ); diff --git a/lib/widgets/completed_area_layer/completed_area_layer.dart b/lib/widgets/completed_area_layer/completed_area_layer.dart index 59e40a33..3efb20bf 100644 --- a/lib/widgets/completed_area_layer/completed_area_layer.dart +++ b/lib/widgets/completed_area_layer/completed_area_layer.dart @@ -71,7 +71,7 @@ class _CheckMarkState extends State with SingleTickerProviderStateMix color: const Color(0xFF8ccf73), shape: BoxShape.circle, border: Border.all( - color: Colors.white, + color: Theme.of(context).colorScheme.primaryContainer, width: 3.0, ), ), @@ -80,7 +80,7 @@ class _CheckMarkState extends State with SingleTickerProviderStateMix child: AnimatedPath( animation: _animation, strokeWidth: 5, - color: Colors.white, + color: Theme.of(context).colorScheme.onPrimary, pathBuilder: (size) { return Path() ..moveTo(0.270 * size.width, 0.541 * size.height) diff --git a/lib/widgets/osm_element_layer/osm_element_marker.dart b/lib/widgets/osm_element_layer/osm_element_marker.dart index 2305a65c..2250bd12 100644 --- a/lib/widgets/osm_element_layer/osm_element_marker.dart +++ b/lib/widgets/osm_element_layer/osm_element_marker.dart @@ -73,6 +73,7 @@ class _OsmElementMarkerState extends State with SingleTickerPr child: AnimatedBuilder( animation: _animation, builder: (_, _) => MarkerBubble( + color: Theme.of(context).colorScheme.primaryContainer, shadowColor: Theme.of(context).colorScheme.shadow.withValues(alpha: 0.4), elevation: _animation.value * 2, child: Padding( @@ -90,7 +91,7 @@ class _OsmElementMarkerState extends State with SingleTickerPr padding: const EdgeInsets.all(7), child: Icon( widget.icon, - color: Colors.white, + color: Theme.of(context).colorScheme.onPrimary, shadows: const [ Shadow( color: Colors.black12, @@ -119,7 +120,7 @@ class _OsmElementMarkerState extends State with SingleTickerPr softWrap: true, maxLines: 2, style: TextStyle( - color: Colors.grey.shade900, + color: Theme.of(context).colorScheme.onPrimaryContainer, fontSize: 16, overflow: TextOverflow.ellipsis, ), diff --git a/lib/widgets/question_inputs/bool_input.dart b/lib/widgets/question_inputs/bool_input.dart index f22930a4..8296536a 100644 --- a/lib/widgets/question_inputs/bool_input.dart +++ b/lib/widgets/question_inputs/bool_input.dart @@ -19,6 +19,7 @@ class BoolInput extends QuestionInputWidget { Widget build(BuildContext context) { final theme = Theme.of(context); final appLocale = AppLocalizations.of(context)!; + final isHighContrast = MediaQuery.highContrastOf(context); return SizedBox( width: double.infinity, @@ -39,7 +40,9 @@ class BoolInput extends QuestionInputWidget { active: controller.answer?.value == state, backgroundColor: theme.colorScheme.primary.withValues(alpha: 0.0), activeBackgroundColor: theme.colorScheme.primary, - foregroundColor: theme.colorScheme.primary, + foregroundColor: isHighContrast && theme.brightness == Brightness.light + ? Colors.black + : theme.colorScheme.primary, activeForegroundColor: theme.colorScheme.onPrimary, ), );