mirror of
https://github.com/hanskokx/arcane_framework.git
synced 2026-05-14 02:19:08 +02:00
Fixed theme
- fixed: currentMode, dark, light now actually emit new values when changed - added: getters for lightTheme, darkTheme, and systemTheme - breaking: currentMode -> systemTheme - added: currentTheme - breaking: currentMode => currentTheme - change: Arcane.theme.followSystemTheme(context) required to follow system theme - change: After following the system theme, calling Arcane.theme.switchTheme() cancels following the system theme - added: ArcaneReactiveTheme is now registered in ArcaneServiceProvider when using ArcaneApp Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -61,7 +61,7 @@ class _MainAppState extends State<MainApp> {
|
|||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
theme: Arcane.theme.light,
|
theme: Arcane.theme.light,
|
||||||
darkTheme: Arcane.theme.dark,
|
darkTheme: Arcane.theme.dark,
|
||||||
themeMode: Arcane.theme.currentMode,
|
themeMode: Arcane.theme.currentTheme,
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text("Arcane Framework Example"),
|
title: const Text("Arcane Framework Example"),
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ class ArcaneApp extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ArcaneEnvironmentProvider(
|
return ArcaneEnvironmentProvider(
|
||||||
child: ArcaneServiceProvider(
|
child: ArcaneServiceProvider(
|
||||||
serviceInstances: services,
|
serviceInstances: [
|
||||||
|
ArcaneReactiveTheme.I,
|
||||||
|
...services,
|
||||||
|
],
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import "package:arcane_framework/arcane_framework.dart";
|
import "package:arcane_framework/arcane_framework.dart";
|
||||||
import "package:flutter/foundation.dart";
|
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
|
|
||||||
part "reactive_theme_extensions.dart";
|
part "reactive_theme_extensions.dart";
|
||||||
@@ -21,10 +20,13 @@ class ArcaneReactiveTheme extends ArcaneService {
|
|||||||
final ValueNotifier<ThemeMode> _systemThemeNotifier =
|
final ValueNotifier<ThemeMode> _systemThemeNotifier =
|
||||||
ValueNotifier(ThemeMode.light);
|
ValueNotifier(ThemeMode.light);
|
||||||
|
|
||||||
/// Returns the current theme mode based on `_isDark`.
|
final ValueNotifier<ThemeMode> _currentThemeNotifier =
|
||||||
///
|
ValueNotifier(ThemeMode.light);
|
||||||
/// If `_isDark` is true, it returns `ThemeMode.dark`, otherwise it returns `ThemeMode.light`.
|
|
||||||
ThemeMode get currentMode => I._systemThemeNotifier.value;
|
ThemeMode get currentTheme => I._currentThemeNotifier.value;
|
||||||
|
|
||||||
|
/// A listenable that notifies listeners when the system theme mode changes.
|
||||||
|
ThemeMode get systemTheme => I._systemThemeNotifier.value;
|
||||||
|
|
||||||
/// The `ThemeData` for the dark theme.
|
/// The `ThemeData` for the dark theme.
|
||||||
final ValueNotifier<ThemeData> _darkTheme = ValueNotifier(ThemeData.dark());
|
final ValueNotifier<ThemeData> _darkTheme = ValueNotifier(ThemeData.dark());
|
||||||
@@ -40,9 +42,6 @@ class ArcaneReactiveTheme extends ArcaneService {
|
|||||||
ThemeData get light => _lightTheme.value;
|
ThemeData get light => _lightTheme.value;
|
||||||
ValueNotifier<ThemeData> get lightTheme => I._lightTheme;
|
ValueNotifier<ThemeData> get lightTheme => I._lightTheme;
|
||||||
|
|
||||||
/// A listenable that notifies listeners when the syste theme mode changes.
|
|
||||||
ValueListenable<ThemeMode> get systemTheme => I._systemThemeNotifier;
|
|
||||||
|
|
||||||
/// Switches the current theme between light and dark modes.
|
/// Switches the current theme between light and dark modes.
|
||||||
///
|
///
|
||||||
/// If the theme is currently light, it switches to dark, and vice versa. It also
|
/// If the theme is currently light, it switches to dark, and vice versa. It also
|
||||||
@@ -53,10 +52,15 @@ class ArcaneReactiveTheme extends ArcaneService {
|
|||||||
/// ArcaneReactiveTheme.I.switchTheme();
|
/// ArcaneReactiveTheme.I.switchTheme();
|
||||||
/// ```
|
/// ```
|
||||||
ArcaneReactiveTheme switchTheme({ThemeMode? themeMode}) {
|
ArcaneReactiveTheme switchTheme({ThemeMode? themeMode}) {
|
||||||
|
if (I._systemThemeNotifier.hasListeners) {
|
||||||
|
_systemThemeNotifier.removeListener(_systemThemeListener);
|
||||||
|
}
|
||||||
|
|
||||||
if (themeMode != null) {
|
if (themeMode != null) {
|
||||||
_systemThemeNotifier.value = themeMode;
|
_currentThemeNotifier.value = themeMode;
|
||||||
} else {
|
} else {
|
||||||
_systemThemeNotifier.value = _systemThemeNotifier.value == ThemeMode.light
|
_currentThemeNotifier.value =
|
||||||
|
_currentThemeNotifier.value == ThemeMode.light
|
||||||
? ThemeMode.dark
|
? ThemeMode.dark
|
||||||
: ThemeMode.light;
|
: ThemeMode.light;
|
||||||
}
|
}
|
||||||
@@ -78,8 +82,13 @@ class ArcaneReactiveTheme extends ArcaneService {
|
|||||||
final ThemeMode systemMode =
|
final ThemeMode systemMode =
|
||||||
context.isDarkMode ? ThemeMode.dark : ThemeMode.light;
|
context.isDarkMode ? ThemeMode.dark : ThemeMode.light;
|
||||||
|
|
||||||
if (currentMode != systemMode) {
|
if (!I._systemThemeNotifier.hasListeners) {
|
||||||
switchTheme();
|
I._systemThemeNotifier.addListener(_systemThemeListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (systemMode != currentTheme) {
|
||||||
|
_systemThemeNotifier.value = systemMode;
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
return I;
|
return I;
|
||||||
@@ -120,6 +129,14 @@ class ArcaneReactiveTheme extends ArcaneService {
|
|||||||
_darkTheme.value = ThemeData.dark();
|
_darkTheme.value = ThemeData.dark();
|
||||||
_lightTheme.value = ThemeData.light();
|
_lightTheme.value = ThemeData.light();
|
||||||
_systemThemeNotifier.value = ThemeMode.light;
|
_systemThemeNotifier.value = ThemeMode.light;
|
||||||
|
_currentThemeNotifier.value = ThemeMode.light;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _systemThemeListener() {
|
||||||
|
if (currentTheme != _systemThemeNotifier.value) {
|
||||||
|
_currentThemeNotifier.value = _systemThemeNotifier.value;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,15 +16,15 @@ void main() {
|
|||||||
|
|
||||||
group("theme mode", () {
|
group("theme mode", () {
|
||||||
test("initial mode is light", () {
|
test("initial mode is light", () {
|
||||||
expect(theme.currentMode, equals(ThemeMode.light));
|
expect(theme.currentTheme, equals(ThemeMode.light));
|
||||||
});
|
});
|
||||||
|
|
||||||
test("switchTheme toggles between light and dark", () {
|
test("switchTheme toggles between light and dark", () {
|
||||||
expect(theme.currentMode, equals(ThemeMode.light));
|
expect(theme.currentTheme, equals(ThemeMode.light));
|
||||||
theme.switchTheme();
|
theme.switchTheme();
|
||||||
expect(theme.currentMode, equals(ThemeMode.dark));
|
expect(theme.currentTheme, equals(ThemeMode.dark));
|
||||||
theme.switchTheme();
|
theme.switchTheme();
|
||||||
expect(theme.currentMode, equals(ThemeMode.light));
|
expect(theme.currentTheme, equals(ThemeMode.light));
|
||||||
});
|
});
|
||||||
|
|
||||||
test("switching theme notifies listeners", () {
|
test("switching theme notifies listeners", () {
|
||||||
@@ -66,7 +66,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
theme.addListener(() {
|
theme.addListener(() {
|
||||||
currentTheme = theme.currentMode;
|
currentTheme = theme.currentTheme;
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(currentTheme, ThemeMode.system);
|
expect(currentTheme, ThemeMode.system);
|
||||||
@@ -103,7 +103,7 @@ void main() {
|
|||||||
final BuildContext lightContext = tester.element(find.byType(SizedBox));
|
final BuildContext lightContext = tester.element(find.byType(SizedBox));
|
||||||
theme.followSystemTheme(lightContext);
|
theme.followSystemTheme(lightContext);
|
||||||
|
|
||||||
expect(theme.currentMode, equals(ThemeMode.light));
|
expect(theme.currentTheme, equals(ThemeMode.light));
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
const MediaQuery(
|
const MediaQuery(
|
||||||
@@ -113,9 +113,8 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final BuildContext darkContext = tester.element(find.byType(SizedBox));
|
final BuildContext darkContext = tester.element(find.byType(SizedBox));
|
||||||
|
|
||||||
theme.followSystemTheme(darkContext);
|
theme.followSystemTheme(darkContext);
|
||||||
expect(theme.currentMode, equals(ThemeMode.dark));
|
expect(theme.currentTheme, equals(ThemeMode.dark));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets("followSystemTheme only switches when needed",
|
testWidgets("followSystemTheme only switches when needed",
|
||||||
|
|||||||
Reference in New Issue
Block a user