diff --git a/packages/neon/neon/lib/src/app.dart b/packages/neon/neon/lib/src/app.dart index 83563284..cdd467f6 100644 --- a/packages/neon/neon/lib/src/app.dart +++ b/packages/neon/neon/lib/src/app.dart @@ -28,24 +28,10 @@ class _NeonAppState extends State with WidgetsBindingObserver, tray.Tra late final _routerDelegate = AppRouter( navigatorKey: _navigatorKey, accountsBloc: _accountsBloc, - onThemeChanged: (final nextcloudTheme) { - setState(() { - _nextcloudTheme = nextcloudTheme; - }); - }, ); - NextcloudCoreServerCapabilities_Ocs_Data_Capabilities_Theming? _nextcloudTheme; - final _platformBrightness = BehaviorSubject.seeded(WidgetsBinding.instance.window.platformBrightness); Rect? _lastBounds; - @override - void didChangePlatformBrightness() { - _platformBrightness.add(WidgetsBinding.instance.window.platformBrightness); - - super.didChangePlatformBrightness(); - } - @override void initState() { super.initState(); @@ -260,42 +246,46 @@ class _NeonAppState extends State with WidgetsBindingObserver, tray.Tra if (_platform.canUseWindowManager) { windowManager.removeListener(this); } - unawaited(_platformBrightness.close()); super.dispose(); } @override - Widget build(final BuildContext context) => StreamBuilder( - stream: _platformBrightness, - builder: (final context, final platformBrightnessSnapshot) => OptionBuilder( - option: widget.globalOptions.themeMode, - builder: (final context, final themeMode) => OptionBuilder( - option: widget.globalOptions.themeOLEDAsDark, - builder: (final context, final themeOLEDAsDark) => OptionBuilder( - option: widget.globalOptions.themeKeepOriginalAccentColor, - builder: (final context, final themeKeepOriginalAccentColor) => StreamBuilder( - stream: widget.accountsBloc.activeAccount, - builder: (final context, final activeAccountSnapshot) { - if (themeMode == null || !platformBrightnessSnapshot.hasData || themeOLEDAsDark == null) { - return Container(); - } - - FlutterNativeSplash.remove(); - return MaterialApp.router( + Widget build(final BuildContext context) => OptionBuilder( + option: widget.globalOptions.themeMode, + builder: (final context, final themeMode) => OptionBuilder( + option: widget.globalOptions.themeOLEDAsDark, + builder: (final context, final themeOLEDAsDark) => OptionBuilder( + option: widget.globalOptions.themeKeepOriginalAccentColor, + builder: (final context, final themeKeepOriginalAccentColor) => StreamBuilder( + stream: widget.accountsBloc.activeAccount, + builder: (final context, final activeAccountSnapshot) { + if (themeMode == null || themeOLEDAsDark == null) { + return Container(); + } + + FlutterNativeSplash.remove(); + return ValueListenableBuilder( + valueListenable: themeNotifier, + builder: (final context, final nextcloudTheme, final child) => MaterialApp.router( localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, + themeMode: themeMode, theme: getThemeFromNextcloudTheme( - _nextcloudTheme, - themeMode, - platformBrightnessSnapshot.data!, + nextcloudTheme, + Brightness.light, + keepOriginalAccentColor: nextcloudTheme == null || (themeKeepOriginalAccentColor ?? false), + ), + darkTheme: getThemeFromNextcloudTheme( + nextcloudTheme, + Brightness.dark, + keepOriginalAccentColor: nextcloudTheme == null || (themeKeepOriginalAccentColor ?? false), oledAsDark: themeOLEDAsDark, - keepOriginalAccentColor: _nextcloudTheme == null || (themeKeepOriginalAccentColor ?? false), ), routerDelegate: _routerDelegate, - ); - }, - ), + ), + ); + }, ), ), ), diff --git a/packages/neon/neon/lib/src/blocs/capabilities.dart b/packages/neon/neon/lib/src/blocs/capabilities.dart index 04c7fcd1..de91d45c 100644 --- a/packages/neon/neon/lib/src/blocs/capabilities.dart +++ b/packages/neon/neon/lib/src/blocs/capabilities.dart @@ -14,6 +14,10 @@ class CapabilitiesBloc extends InteractiveBloc implements CapabilitiesBlocEvents this._requestManager, this._client, ) { + capabilities.listen((final value) { + themeNotifier.value = value.data!.capabilities.theming; + }); + unawaited(refresh()); } diff --git a/packages/neon/neon/lib/src/pages/home.dart b/packages/neon/neon/lib/src/pages/home.dart index f3591072..d807df3a 100644 --- a/packages/neon/neon/lib/src/pages/home.dart +++ b/packages/neon/neon/lib/src/pages/home.dart @@ -5,12 +5,10 @@ const kQuickBarWidth = kAvatarSize + 20; class HomePage extends StatefulWidget { const HomePage({ required this.account, - required this.onThemeChanged, super.key, }); final Account account; - final Function(NextcloudTheme? theme) onThemeChanged; @override State createState() => _HomePageState(); @@ -48,8 +46,6 @@ class _HomePageState extends State { _capabilitiesBloc.capabilities.listen((final result) async { if (result.data != null) { - widget.onThemeChanged(result.data!.capabilities.theming); - // ignore cached version and prevent duplicate dialogs if (result.cached) { return; diff --git a/packages/neon/neon/lib/src/router.dart b/packages/neon/neon/lib/src/router.dart index 4e7ac622..e482c58f 100644 --- a/packages/neon/neon/lib/src/router.dart +++ b/packages/neon/neon/lib/src/router.dart @@ -5,11 +5,9 @@ class AppRouter extends RouterDelegate with ChangeNotifier, PopNavigato AppRouter({ required this.navigatorKey, required this.accountsBloc, - required this.onThemeChanged, }); final AccountsBloc accountsBloc; - final Function(NextcloudTheme? theme) onThemeChanged; final _globalPopups = const GlobalPopups(); @override @@ -41,7 +39,6 @@ class AppRouter extends RouterDelegate with ChangeNotifier, PopNavigato HomePage( key: Key(currentConfiguration!.id), account: currentConfiguration!, - onThemeChanged: onThemeChanged, ), ], ), diff --git a/packages/neon/neon/lib/src/utils/theme.dart b/packages/neon/neon/lib/src/utils/theme.dart index 4c498042..0b0f174f 100644 --- a/packages/neon/neon/lib/src/utils/theme.dart +++ b/packages/neon/neon/lib/src/utils/theme.dart @@ -1,34 +1,26 @@ part of '../../neon.dart'; +final themeNotifier = ValueNotifier(null); + const themePrimaryColor = Color(0xFFF37736); ThemeData getThemeFromNextcloudTheme( final NextcloudCoreServerCapabilities_Ocs_Data_Capabilities_Theming? nextcloudTheme, - final ThemeMode themeMode, - final Brightness platformBrightness, { - required final bool oledAsDark, + final Brightness brightness, { required final bool keepOriginalAccentColor, + final bool oledAsDark = false, }) { - final primaryColor = nextcloudTheme?.color != null ? HexColor(nextcloudTheme!.color!) : themePrimaryColor; - - late final Brightness selectBrightness; - switch (themeMode) { - case ThemeMode.system: - selectBrightness = platformBrightness; - break; - case ThemeMode.light: - selectBrightness = Brightness.light; - break; - case ThemeMode.dark: - selectBrightness = Brightness.dark; - break; + if (oledAsDark) { + assert(brightness == Brightness.dark, 'Brightness.dark is required for oledAsDark.'); } - final oledBackgroundOverride = selectBrightness == Brightness.dark && oledAsDark ? Colors.black : null; + final primaryColor = nextcloudTheme?.color != null ? HexColor(nextcloudTheme!.color!) : themePrimaryColor; + + final oledBackgroundOverride = oledAsDark ? Colors.black : null; final keepOriginalAccentColorOverride = keepOriginalAccentColor ? primaryColor : null; final colorScheme = ColorScheme.fromSeed( seedColor: primaryColor, - brightness: selectBrightness, + brightness: brightness, ).copyWith( background: oledBackgroundOverride, primary: keepOriginalAccentColorOverride, @@ -37,7 +29,7 @@ ThemeData getThemeFromNextcloudTheme( final fillColor = MaterialStateProperty.resolveWith((final states) { if (states.contains(MaterialState.disabled)) { - return selectBrightness == Brightness.dark ? Colors.white38 : Colors.black38; + return brightness == Brightness.dark ? Colors.white38 : Colors.black38; } return colorScheme.primary; @@ -62,7 +54,7 @@ ThemeData getThemeFromNextcloudTheme( ), popupMenuTheme: PopupMenuThemeData( // TODO: Only needed until M3 popup menus are implemented - color: selectBrightness == Brightness.dark + color: brightness == Brightness.dark ? oledAsDark ? const Color(0xFF202020) : const Color(0xFF404040)