mirror of
https://github.com/hanskokx/arcane_framework.git
synced 2026-05-14 10:29:06 +02:00
Fixes tests and updates reactive theme
Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -10,7 +10,10 @@ part "reactive_theme_extensions.dart";
|
||||
/// `ArcaneReactiveTheme` allows switching between light and dark themes and provides
|
||||
/// methods to customize the themes. The current theme mode can be accessed, and the
|
||||
/// theme can be switched at runtime.
|
||||
class ArcaneReactiveTheme extends ArcaneService with WidgetsBindingObserver {
|
||||
///
|
||||
/// System theme changes are detected by the `ArcaneApp` widget, which ensures
|
||||
/// theme updates happen automatically when the device theme changes.
|
||||
class ArcaneReactiveTheme extends ArcaneService {
|
||||
/// The singleton instance of `ArcaneReactiveTheme`.
|
||||
static final ArcaneReactiveTheme _instance = ArcaneReactiveTheme._internal();
|
||||
|
||||
@@ -22,6 +25,12 @@ class ArcaneReactiveTheme extends ArcaneService with WidgetsBindingObserver {
|
||||
// Whether to follow system theme
|
||||
bool _followingSystemTheme = false;
|
||||
|
||||
/// Whether the theme service is currently following the system theme.
|
||||
///
|
||||
/// When true, the theme will automatically switch between light and dark
|
||||
/// based on the system's brightness setting.
|
||||
bool get isFollowingSystemTheme => _followingSystemTheme;
|
||||
|
||||
final ValueNotifier<ThemeMode> _systemThemeNotifier =
|
||||
ValueNotifier(ThemeMode.system);
|
||||
|
||||
@@ -32,10 +41,12 @@ class ArcaneReactiveTheme extends ArcaneService with WidgetsBindingObserver {
|
||||
},
|
||||
);
|
||||
|
||||
/// Stream of theme mode changes that can be listened to for reactive UI updates.
|
||||
Stream<ThemeMode> get currentThemeStream => I._themeStreamController.stream;
|
||||
|
||||
ThemeMode _currentTheme = ThemeMode.light;
|
||||
|
||||
/// The currently active theme mode (light or dark).
|
||||
ThemeMode get currentTheme => _currentTheme;
|
||||
|
||||
/// A listenable that notifies listeners when the system theme mode changes.
|
||||
@@ -49,10 +60,14 @@ class ArcaneReactiveTheme extends ArcaneService with WidgetsBindingObserver {
|
||||
|
||||
/// Returns the current dark theme `ThemeData`.
|
||||
ThemeData get dark => _darkTheme.value;
|
||||
|
||||
/// ValueNotifier for the dark theme that can be observed for changes.
|
||||
ValueNotifier<ThemeData> get darkTheme => I._darkTheme;
|
||||
|
||||
/// Returns the current light theme `ThemeData`.
|
||||
ThemeData get light => _lightTheme.value;
|
||||
|
||||
/// ValueNotifier for the light theme that can be observed for changes.
|
||||
ValueNotifier<ThemeData> get lightTheme => I._lightTheme;
|
||||
|
||||
/// Switches the current theme between light and dark modes.
|
||||
@@ -82,24 +97,26 @@ class ArcaneReactiveTheme extends ArcaneService with WidgetsBindingObserver {
|
||||
/// Switches the current theme between light and dark modes automatically
|
||||
/// based upon the system's current mode.
|
||||
///
|
||||
/// This will also register for system theme changes, so the theme will
|
||||
/// automatically update when the system theme changes.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// ArcaneReactiveTheme.I.followSystemTheme(context);
|
||||
/// final ThemeMode mode = Arcane.theme.systemTheme.value;
|
||||
/// ```
|
||||
ArcaneReactiveTheme followSystemTheme(BuildContext context) {
|
||||
if (!_followingSystemTheme) {
|
||||
_followingSystemTheme = true;
|
||||
_followingSystemTheme = true;
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
checkSystemTheme(context);
|
||||
});
|
||||
}
|
||||
// Always check the system theme when this method is called
|
||||
checkSystemTheme(context);
|
||||
|
||||
return I;
|
||||
}
|
||||
|
||||
/// Check and apply the system theme if we're following it
|
||||
///
|
||||
/// This is called automatically when the system brightness changes if
|
||||
/// [followSystemTheme] has been enabled.
|
||||
void checkSystemTheme(BuildContext context) {
|
||||
if (!_followingSystemTheme) return;
|
||||
|
||||
@@ -109,6 +126,7 @@ class ArcaneReactiveTheme extends ArcaneService with WidgetsBindingObserver {
|
||||
final ThemeMode systemMode =
|
||||
systemBrightness == Brightness.dark ? ThemeMode.dark : ThemeMode.light;
|
||||
|
||||
// Only update and notify if the theme actually changed
|
||||
if (systemMode != _currentTheme) {
|
||||
_updateTheme(systemMode);
|
||||
notifyListeners();
|
||||
@@ -145,6 +163,10 @@ class ArcaneReactiveTheme extends ArcaneService with WidgetsBindingObserver {
|
||||
return I;
|
||||
}
|
||||
|
||||
/// Resets the theme service to its default state.
|
||||
///
|
||||
/// This resets both light and dark themes to their default values and
|
||||
/// disables system theme following.
|
||||
@visibleForTesting
|
||||
void reset() {
|
||||
_darkTheme.value = ThemeData.dark();
|
||||
@@ -154,6 +176,7 @@ class ArcaneReactiveTheme extends ArcaneService with WidgetsBindingObserver {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Updates the current theme mode and broadcasts the change.
|
||||
void _updateTheme(ThemeMode themeMode) {
|
||||
_currentTheme = themeMode;
|
||||
_themeStreamController.add(themeMode);
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import "package:arcane_framework/src/services/reactive_theme/reactive_theme_service.dart";
|
||||
import "package:flutter/material.dart";
|
||||
|
||||
class ArcaneTheme extends InheritedWidget {
|
||||
final ThemeMode themeMode;
|
||||
|
||||
const ArcaneTheme({
|
||||
required this.themeMode,
|
||||
required super.child,
|
||||
super.key,
|
||||
});
|
||||
|
||||
static ArcaneTheme? of(BuildContext context) {
|
||||
return context.dependOnInheritedWidgetOfExactType<ArcaneTheme>();
|
||||
}
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(ArcaneTheme oldWidget) {
|
||||
return oldWidget.themeMode != themeMode;
|
||||
}
|
||||
|
||||
static ArcaneReactiveTheme get service => ArcaneReactiveTheme.I;
|
||||
static bool get isFollowingSystemTheme => service.isFollowingSystemTheme;
|
||||
static Stream<ThemeMode> get currentThemeStream => service.currentThemeStream;
|
||||
static ThemeMode get currentTheme => service.currentTheme;
|
||||
static ThemeMode get systemTheme => service.systemTheme;
|
||||
static ThemeData get dark => service.dark;
|
||||
static ValueNotifier<ThemeData> get darkTheme => service.darkTheme;
|
||||
static ThemeData get light => service.light;
|
||||
static ValueNotifier<ThemeData> get lightTheme => service.lightTheme;
|
||||
|
||||
static ArcaneReactiveTheme Function({ThemeMode? themeMode}) get switchTheme =>
|
||||
service.switchTheme;
|
||||
static ArcaneReactiveTheme Function(BuildContext context)
|
||||
get followSystemTheme => service.followSystemTheme;
|
||||
static void get checkSystemTheme => service.checkSystemTheme;
|
||||
static ArcaneReactiveTheme Function(ThemeData theme) get setDarkTheme =>
|
||||
service.setDarkTheme;
|
||||
static ArcaneReactiveTheme Function(ThemeData theme) get setLightTheme =>
|
||||
service.setLightTheme;
|
||||
}
|
||||
Reference in New Issue
Block a user