diff --git a/packages/app/linux/flutter/generated_plugin_registrant.cc b/packages/app/linux/flutter/generated_plugin_registrant.cc index c05f1fa5..9db402be 100644 --- a/packages/app/linux/flutter/generated_plugin_registrant.cc +++ b/packages/app/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,7 @@ #include "generated_plugin_registrant.h" +#include #include #include #include @@ -13,6 +14,9 @@ #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) file_selector_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); file_selector_plugin_register_with_registrar(file_selector_linux_registrar); diff --git a/packages/app/linux/flutter/generated_plugins.cmake b/packages/app/linux/flutter/generated_plugins.cmake index 7180e5e3..eb1257c1 100644 --- a/packages/app/linux/flutter/generated_plugins.cmake +++ b/packages/app/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + dynamic_color file_selector_linux screen_retriever tray_manager diff --git a/packages/app/pubspec.lock b/packages/app/pubspec.lock index 9ffd8868..9cc847a8 100644 --- a/packages/app/pubspec.lock +++ b/packages/app/pubspec.lock @@ -201,6 +201,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.3" + dynamic_color: + dependency: transitive + description: + name: dynamic_color + sha256: "8b8bd1d798bd393e11eddeaa8ae95b12ff028bf7d5998fc5d003488cd5f4ce2f" + url: "https://pub.dev" + source: hosted + version: "1.6.8" dynamite_runtime: dependency: "direct overridden" description: diff --git a/packages/neon/neon/lib/src/app.dart b/packages/neon/neon/lib/src/app.dart index 149f0f96..856eb204 100644 --- a/packages/neon/neon/lib/src/app.dart +++ b/packages/neon/neon/lib/src/app.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:collection/collection.dart'; +import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:meta/meta.dart'; @@ -284,42 +285,48 @@ class _NeonAppState extends State with WidgetsBindingObserver, tray.Tra } @override - Widget build(final BuildContext context) => OptionsCollectionBuilder( - valueListenable: _globalOptions, - builder: (final context, final options, final _) => StreamBuilder( - stream: _accountsBloc.activeAccount, - builder: (final context, final activeAccountSnapshot) { - FlutterNativeSplash.remove(); - return ResultBuilder.behaviorSubject( - subject: activeAccountSnapshot.hasData - ? _accountsBloc.getCapabilitiesBlocFor(activeAccountSnapshot.data!).capabilities - : null, - builder: (final context, final capabilitiesSnapshot) { - final appTheme = AppTheme( - capabilitiesSnapshot.data?.capabilities.themingPublicCapabilities?.theming, - useNextcloudTheme: options.themeUseNextcloudTheme.value, - oledAsDark: options.themeOLEDAsDark.value, - appThemes: _appImplementations.map((final a) => a.theme).whereNotNull(), - neonTheme: widget.neonTheme, - ); - - return MaterialApp.router( - localizationsDelegates: [ - ..._appImplementations.map((final app) => app.localizationsDelegate), - ...NeonLocalizations.localizationsDelegates, - ], - supportedLocales: { - ..._appImplementations.map((final app) => app.supportedLocales).expand((final element) => element), - ...NeonLocalizations.supportedLocales, - }, - themeMode: options.themeMode.value, - theme: appTheme.lightTheme, - darkTheme: appTheme.darkTheme, - routerConfig: _routerDelegate, - ); - }, - ); - }, + Widget build(final BuildContext context) => DynamicColorBuilder( + builder: (final deviceThemeLight, final deviceThemeDark) => OptionsCollectionBuilder( + valueListenable: _globalOptions, + builder: (final context, final options, final _) => StreamBuilder( + stream: _accountsBloc.activeAccount, + builder: (final context, final activeAccountSnapshot) { + FlutterNativeSplash.remove(); + return ResultBuilder.behaviorSubject( + subject: activeAccountSnapshot.hasData + ? _accountsBloc.getCapabilitiesBlocFor(activeAccountSnapshot.data!).capabilities + : null, + builder: (final context, final capabilitiesSnapshot) { + final appTheme = AppTheme( + nextcloudTheme: capabilitiesSnapshot.data?.capabilities.themingPublicCapabilities?.theming, + useNextcloudTheme: options.themeUseNextcloudTheme.value, + deviceThemeLight: deviceThemeLight, + deviceThemeDark: deviceThemeDark, + oledAsDark: options.themeOLEDAsDark.value, + appThemes: _appImplementations.map((final a) => a.theme).whereNotNull(), + neonTheme: widget.neonTheme, + ); + + return MaterialApp.router( + localizationsDelegates: [ + ..._appImplementations.map((final app) => app.localizationsDelegate), + ...NeonLocalizations.localizationsDelegates, + ], + supportedLocales: { + ..._appImplementations + .map((final app) => app.supportedLocales) + .expand((final element) => element), + ...NeonLocalizations.supportedLocales, + }, + themeMode: options.themeMode.value, + theme: appTheme.lightTheme, + darkTheme: appTheme.darkTheme, + routerConfig: _routerDelegate, + ); + }, + ); + }, + ), ), ); } diff --git a/packages/neon/neon/lib/src/theme/theme.dart b/packages/neon/neon/lib/src/theme/theme.dart index 4fbc761d..5c7cee8e 100644 --- a/packages/neon/neon/lib/src/theme/theme.dart +++ b/packages/neon/neon/lib/src/theme/theme.dart @@ -10,8 +10,10 @@ import 'package:nextcloud/core.dart' as core; @immutable class AppTheme { /// Creates a new Neon app theme. - const AppTheme( - this.nextcloudTheme, { + const AppTheme({ + required this.nextcloudTheme, + required this.deviceThemeLight, + required this.deviceThemeDark, required this.neonTheme, final bool useNextcloudTheme = false, this.oledAsDark = false, @@ -24,6 +26,12 @@ class AppTheme { /// Whether to use of the Nextcloud theme. final bool useNextcloudTheme; + /// The light theme provided by the device. + final ColorScheme? deviceThemeLight; + + /// The dark theme provided by the device. + final ColorScheme? deviceThemeDark; + /// Whether to use [NcColors.oledBackground] in the dark theme. final bool oledAsDark; @@ -34,19 +42,39 @@ class AppTheme { final NeonTheme neonTheme; ColorScheme _buildColorScheme(final Brightness brightness) { - final primaryColor = - nextcloudTheme?.color != null ? HexColor(nextcloudTheme!.color) : neonTheme.colorScheme.primary; - final primaryColorOverride = useNextcloudTheme ? primaryColor : null; - final oledBackgroundOverride = oledAsDark && brightness == Brightness.dark ? NcColors.oledBackground : null; - - return ColorScheme.fromSeed( - seedColor: primaryColor, + ColorScheme? colorScheme; + + if (nextcloudTheme != null && useNextcloudTheme) { + final primaryColor = HexColor(nextcloudTheme!.color); + final onPrimaryColor = HexColor(nextcloudTheme!.colorText); + + colorScheme = ColorScheme.fromSeed( + seedColor: primaryColor, + brightness: brightness, + ).copyWith( + primary: primaryColor, + onPrimary: onPrimaryColor, + secondary: primaryColor, + onSecondary: onPrimaryColor, + tertiary: primaryColor, + onTertiary: onPrimaryColor, + ); + } else { + colorScheme = brightness == Brightness.dark ? deviceThemeDark : deviceThemeLight; + } + + colorScheme ??= ColorScheme.fromSeed( + seedColor: NcColors.primary, brightness: brightness, - ).copyWith( - background: oledBackgroundOverride, - primary: primaryColorOverride, - secondary: primaryColorOverride, ); + + if (oledAsDark && brightness == Brightness.dark) { + colorScheme = colorScheme.copyWith( + background: NcColors.oledBackground, + ); + } + + return colorScheme; } ThemeData _getTheme(final Brightness brightness) { @@ -56,7 +84,8 @@ class AppTheme { useMaterial3: true, colorScheme: colorScheme, scaffoldBackgroundColor: colorScheme.background, - cardColor: colorScheme.background, // For LicensePage + cardColor: colorScheme.background, + // For LicensePage snackBarTheme: _snackBarTheme, dividerTheme: _dividerTheme, scrollbarTheme: _scrollbarTheme, diff --git a/packages/neon/neon/pubspec.yaml b/packages/neon/neon/pubspec.yaml index 1d5fc229..784339b7 100644 --- a/packages/neon/neon/pubspec.yaml +++ b/packages/neon/neon/pubspec.yaml @@ -9,6 +9,7 @@ environment: dependencies: collection: ^1.0.0 crypto: ^3.0.0 + dynamic_color: ^1.0.0 file_picker: ^6.0.0 filesize: ^2.0.0 flutter: @@ -66,7 +67,7 @@ dev_dependencies: git: url: https://github.com/nextcloud/neon path: packages/neon_lints - test: ^1.24.9 + test: ^1.24.3 vector_graphics_compiler: ^1.1.9 flutter: