diff --git a/lib/blocs/theme/theme_bloc.dart b/lib/blocs/theme/theme_bloc.dart index 7e34a32..56cbdfe 100644 --- a/lib/blocs/theme/theme_bloc.dart +++ b/lib/blocs/theme/theme_bloc.dart @@ -14,10 +14,8 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; import 'package:timecop/data_providers/settings/settings_provider.dart'; import 'package:timecop/models/theme_type.dart'; -import 'package:timecop/themes.dart'; part 'theme_event.dart'; part 'theme_state.dart'; diff --git a/lib/blocs/theme/theme_state.dart b/lib/blocs/theme/theme_state.dart index ca232d3..014c2e4 100644 --- a/lib/blocs/theme/theme_state.dart +++ b/lib/blocs/theme/theme_state.dart @@ -19,19 +19,4 @@ class ThemeState extends Equatable { const ThemeState(this.theme); @override List get props => [theme]; - - ThemeData? get themeData { - switch (theme) { - case ThemeType.auto: - return null; - case ThemeType.light: - return ThemeUtil.lightTheme; - case ThemeType.dark: - return ThemeUtil.darkTheme; - case ThemeType.black: - return ThemeUtil.blackTheme; - default: - return null; - } - } } diff --git a/lib/main.dart b/lib/main.dart index c9104ac..6f8c886 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,6 +15,7 @@ import 'dart:async'; import 'dart:io'; +import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; @@ -33,6 +34,7 @@ import 'package:timecop/data_providers/notifications/notifications_provider.dart import 'package:timecop/data_providers/settings/settings_provider.dart'; import 'package:timecop/fontlicenses.dart'; import 'package:timecop/l10n.dart'; +import 'package:timecop/models/theme_type.dart'; import 'package:timecop/screens/dashboard/DashboardScreen.dart'; import 'package:timecop/themes.dart'; import 'package:flutter_app_badger/flutter_app_badger.dart'; @@ -195,6 +197,46 @@ class _TimeCopAppState extends State with WidgetsBindingObserver { () => brightness = WidgetsBinding.instance.window.platformBrightness); } + ThemeData getTheme( + ThemeType? type, ColorScheme? lightDynamic, ColorScheme? darkDynamic) { + if (type == ThemeType.autoMaterialYou) { + if (brightness == Brightness.dark) { + type = ThemeType.darkMaterialYou; + } else { + type = ThemeType.lightMaterialYou; + } + } + switch (type) { + case ThemeType.light: + return ThemeUtil.lightTheme; + case ThemeType.dark: + return ThemeUtil.darkTheme; + case ThemeType.black: + return ThemeUtil.blackTheme; + case ThemeType.lightMaterialYou: + return ThemeUtil.getThemeFromColors( + brightness: Brightness.light, + colors: lightDynamic ?? ThemeUtil.lightColors, + appBarBackground: + lightDynamic?.background ?? ThemeUtil.lightColors.background, + appBarForeground: lightDynamic?.onBackground ?? + ThemeUtil.lightColors.onBackground); + case ThemeType.darkMaterialYou: + return ThemeUtil.getThemeFromColors( + brightness: Brightness.dark, + colors: darkDynamic ?? ThemeUtil.darkColors, + appBarBackground: + darkDynamic?.background ?? ThemeUtil.darkColors.background, + appBarForeground: + darkDynamic?.onBackground ?? ThemeUtil.darkColors.onBackground); + case ThemeType.auto: + default: + return brightness == Brightness.dark + ? ThemeUtil.darkTheme + : ThemeUtil.lightTheme; + } + } + @override Widget build(BuildContext context) { return MultiRepositoryProvider( @@ -204,42 +246,43 @@ class _TimeCopAppState extends State with WidgetsBindingObserver { child: BlocBuilder( builder: (BuildContext context, ThemeState themeState) => BlocBuilder( - builder: (BuildContext context, LocaleState localeState) => - MaterialApp( - title: 'Time Cop', - home: const DashboardScreen(), - theme: themeState.themeData ?? - (brightness == Brightness.dark - ? ThemeUtil.darkTheme - : ThemeUtil.lightTheme), - localizationsDelegates: const [ - L10N.delegate, - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - locale: localeState.locale, - supportedLocales: const [ - Locale('en'), - Locale('ar'), - Locale('cs'), - Locale('da'), - Locale('de'), - Locale('es'), - Locale('fr'), - Locale('hi'), - Locale('id'), - Locale('it'), - Locale('ja'), - Locale('ko'), - Locale('nb', 'NO'), - Locale('pt'), - Locale('ru'), - Locale('tr'), - Locale('zh', 'CN'), - Locale('zh', 'TW'), - ], - ), - ))); + builder: (BuildContext context, LocaleState localeState) => + DynamicColorBuilder( + builder: (ColorScheme? lightDynamic, + ColorScheme? darkDynamic) => + MaterialApp( + title: 'Time Cop', + home: const DashboardScreen(), + theme: getTheme( + themeState.theme, lightDynamic, darkDynamic), + localizationsDelegates: const [ + L10N.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + locale: localeState.locale, + supportedLocales: const [ + Locale('en'), + Locale('ar'), + Locale('cs'), + Locale('da'), + Locale('de'), + Locale('es'), + Locale('fr'), + Locale('hi'), + Locale('id'), + Locale('it'), + Locale('ja'), + Locale('ko'), + Locale('nb', 'NO'), + Locale('pt'), + Locale('ru'), + Locale('tr'), + Locale('zh', 'CN'), + Locale('zh', 'TW'), + ], + ), + )))); } } diff --git a/lib/models/theme_type.dart b/lib/models/theme_type.dart index d592a75..829b008 100644 --- a/lib/models/theme_type.dart +++ b/lib/models/theme_type.dart @@ -15,7 +15,15 @@ import 'package:flutter/cupertino.dart'; import 'package:timecop/l10n.dart'; -enum ThemeType { auto, light, dark, black } +enum ThemeType { + auto, + light, + dark, + black, + autoMaterialYou, + lightMaterialYou, + darkMaterialYou +} ThemeType themeFromString(String? type) { if (type == null) return ThemeType.auto; @@ -28,12 +36,18 @@ ThemeType themeFromString(String? type) { return ThemeType.dark; case "black": return ThemeType.black; + case "autoMaterialYou": + return ThemeType.autoMaterialYou; + case "lightMaterialYou": + return ThemeType.lightMaterialYou; + case "darkMaterialYou": + return ThemeType.darkMaterialYou; default: return ThemeType.auto; } } -extension ThemeTypeStr on ThemeType? { +extension ThemeTypeStr on ThemeType { String? get stringify { switch (this) { case ThemeType.auto: @@ -44,8 +58,12 @@ extension ThemeTypeStr on ThemeType? { return "dark"; case ThemeType.black: return "black"; - default: - return null; + case ThemeType.autoMaterialYou: + return "autoMaterialYou"; + case ThemeType.lightMaterialYou: + return "lightMaterialYou"; + case ThemeType.darkMaterialYou: + return "darkMaterialYou"; } } @@ -59,6 +77,12 @@ extension ThemeTypeStr on ThemeType? { return L10N.of(context).tr.dark; case ThemeType.black: return L10N.of(context).tr.black; + case ThemeType.autoMaterialYou: + return L10N.of(context).tr.autoMaterialYou; + case ThemeType.lightMaterialYou: + return L10N.of(context).tr.lightMaterialYou; + case ThemeType.darkMaterialYou: + return L10N.of(context).tr.darkMaterialYou; default: return null; } diff --git a/lib/screens/settings/components/theme_options.dart b/lib/screens/settings/components/theme_options.dart index 8d7a053..80fc577 100644 --- a/lib/screens/settings/components/theme_options.dart +++ b/lib/screens/settings/components/theme_options.dart @@ -31,7 +31,7 @@ class ThemeOptions extends StatelessWidget { return ListTile( key: const Key("themeOption"), title: Text(L10N.of(context).tr.theme), - subtitle: Text(state.theme.display(context)!), + subtitle: Text(state.theme?.display(context) ?? ""), trailing: Icon(L10N.of(context).rtl ? FontAwesomeIcons.chevronLeft : FontAwesomeIcons.chevronRight), @@ -75,6 +75,30 @@ class ThemeOptions extends StatelessWidget { onChanged: (ThemeType? type) => Navigator.pop(context, type), ), + RadioListTile( + key: const Key("themeAutoMaterialYou"), + title: Text(L10N.of(context).tr.autoMaterialYou), + value: ThemeType.autoMaterialYou, + groupValue: state.theme, + onChanged: (ThemeType? type) => + Navigator.pop(context, type), + ), + RadioListTile( + key: const Key("themeLightMaterialYou"), + title: Text(L10N.of(context).tr.lightMaterialYou), + value: ThemeType.lightMaterialYou, + groupValue: state.theme, + onChanged: (ThemeType? type) => + Navigator.pop(context, type), + ), + RadioListTile( + key: const Key("themeDarkMaterialYou"), + title: Text(L10N.of(context).tr.darkMaterialYou), + value: ThemeType.darkMaterialYou, + groupValue: state.theme, + onChanged: (ThemeType? type) => + Navigator.pop(context, type), + ), ], )); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index f6f23bf..fe56f8d 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,9 +6,13 @@ #include "generated_plugin_registrant.h" +#include #include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) dynamic_color_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin"); + dynamic_color_plugin_register_with_registrar(dynamic_color_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index f16b4c3..1836621 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + dynamic_color url_launcher_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index a291b11..ad9eb8e 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import dynamic_color import flutter_app_badger import flutter_local_notifications import package_info_plus @@ -15,6 +16,7 @@ import sqflite import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) FlutterAppBadgerPlugin.register(with: registry.registrar(forPlugin: "FlutterAppBadgerPlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 5907897..535fb3e 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -1,4 +1,6 @@ PODS: + - dynamic_color (0.0.2): + - FlutterMacOS - flutter_app_badger (1.3.0): - FlutterMacOS - flutter_local_notifications (0.0.1): @@ -24,6 +26,7 @@ PODS: - FlutterMacOS DEPENDENCIES: + - dynamic_color (from `Flutter/ephemeral/.symlinks/plugins/dynamic_color/macos`) - flutter_app_badger (from `Flutter/ephemeral/.symlinks/plugins/flutter_app_badger/macos`) - flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`) - FlutterMacOS (from `Flutter/ephemeral`) @@ -39,6 +42,8 @@ SPEC REPOS: - FMDB EXTERNAL SOURCES: + dynamic_color: + :path: Flutter/ephemeral/.symlinks/plugins/dynamic_color/macos flutter_app_badger: :path: Flutter/ephemeral/.symlinks/plugins/flutter_app_badger/macos flutter_local_notifications: @@ -59,6 +64,7 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos SPEC CHECKSUMS: + dynamic_color: 2eaa27267de1ca20d879fbd6e01259773fb1670f flutter_app_badger: 55a64b179f8438e89d574320c77b306e327a1730 flutter_local_notifications: 3805ca215b2fb7f397d78b66db91f6a747af52e4 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 diff --git a/pubspec.lock b/pubspec.lock index ca2888f..1f896f6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -161,6 +161,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.8" + dynamic_color: + dependency: "direct main" + description: + name: dynamic_color + sha256: de4798a7069121aee12d5895315680258415de9b00e717723a1bd73d58f0126d + url: "https://pub.dev" + source: hosted + version: "1.6.6" effective_dart: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index a859679..267ab21 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -44,6 +44,7 @@ dependencies: xdg_directories: ^1.0.0 fluent: ^2.0.1 permission_handler: ^10.2.0 + dynamic_color: ^1.6.6 dependency_overrides: intl: 0.18.1