Browse Source

neon: allow apps to define custom themes

pull/449/head
Nikolas Rimikis 1 year ago
parent
commit
1bca03c4d5
No known key found for this signature in database
GPG Key ID: 85ED1DE9786A4FF2
  1. 22
      packages/neon/neon/lib/src/app.dart
  2. 5
      packages/neon/neon/lib/src/models/app_implementation.dart
  3. 101
      packages/neon/neon/lib/src/utils/theme.dart

22
packages/neon/neon/lib/src/app.dart

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:neon/l10n/localizations.dart'; import 'package:neon/l10n/localizations.dart';
@ -285,7 +286,13 @@ class _NeonAppState extends State<NeonApp> with WidgetsBindingObserver, tray.Tra
? _accountsBloc.getCapabilitiesBlocFor(activeAccountSnapshot.data!).capabilities ? _accountsBloc.getCapabilitiesBlocFor(activeAccountSnapshot.data!).capabilities
: null, : null,
builder: (final context, final capabilitiesSnapshot) { builder: (final context, final capabilitiesSnapshot) {
final nextcloudTheme = capabilitiesSnapshot.data?.capabilities.theming; final appTheme = AppTheme(
capabilitiesSnapshot.data?.capabilities.theming,
keepOriginalAccentColor: themeKeepOriginalAccentColor,
oledAsDark: themeOLEDAsDark,
appThemes: _appImplementations.map((final a) => a.theme).whereNotNull(),
);
return MaterialApp.router( return MaterialApp.router(
localizationsDelegates: [ localizationsDelegates: [
..._appImplementations.map((final app) => app.localizationsDelegate), ..._appImplementations.map((final app) => app.localizationsDelegate),
@ -298,17 +305,8 @@ class _NeonAppState extends State<NeonApp> with WidgetsBindingObserver, tray.Tra
...AppLocalizations.supportedLocales, ...AppLocalizations.supportedLocales,
}, },
themeMode: themeMode, themeMode: themeMode,
theme: getThemeFromNextcloudTheme( theme: appTheme.lightTheme,
nextcloudTheme, darkTheme: appTheme.darkTheme,
Brightness.light,
keepOriginalAccentColor: nextcloudTheme == null || themeKeepOriginalAccentColor,
),
darkTheme: getThemeFromNextcloudTheme(
nextcloudTheme,
Brightness.dark,
keepOriginalAccentColor: nextcloudTheme == null || themeKeepOriginalAccentColor,
oledAsDark: themeOLEDAsDark,
),
routerConfig: _routerDelegate, routerConfig: _routerDelegate,
); );
}, },

5
packages/neon/neon/lib/src/models/app_implementation.dart

@ -86,6 +86,11 @@ abstract class AppImplementation<T extends Bloc, R extends NextcloudAppOptions>
void dispose() { void dispose() {
options.dispose(); options.dispose();
} }
/// A custom theme that will be injected into the widget tree.
///
/// You can later acess it through `Theme.of(context).extension<ThemeName>()`.
ThemeExtension? theme;
} }
extension AppImplementationFind on Iterable<AppImplementation> { extension AppImplementationFind on Iterable<AppImplementation> {

101
packages/neon/neon/lib/src/utils/theme.dart

@ -7,40 +7,79 @@ import 'package:nextcloud/nextcloud.dart';
const themePrimaryColor = Color(0xFFF37736); const themePrimaryColor = Color(0xFFF37736);
@internal @internal
ThemeData getThemeFromNextcloudTheme( @immutable
final CoreServerCapabilities_Ocs_Data_Capabilities_Theming? nextcloudTheme, class AppTheme {
final Brightness brightness, { AppTheme(
required final bool keepOriginalAccentColor, this.nextcloudTheme, {
final bool oledAsDark = false, final bool keepOriginalAccentColor = false,
}) { this.oledAsDark = false,
if (oledAsDark) { this.appThemes,
assert(brightness == Brightness.dark, 'Brightness.dark is required for oledAsDark.'); }) : keepOriginalAccentColor = nextcloudTheme == null || keepOriginalAccentColor;
final CoreServerCapabilities_Ocs_Data_Capabilities_Theming? nextcloudTheme;
final bool keepOriginalAccentColor;
final bool oledAsDark;
final Iterable<ThemeExtension>? appThemes;
late final _primaryColor = nextcloudTheme?.color != null ? HexColor(nextcloudTheme!.color!) : themePrimaryColor;
late final _keepOriginalAccentColorOverride = keepOriginalAccentColor ? _primaryColor : null;
ColorScheme _buildColorScheme(final Brightness brightness) {
final oledBackgroundOverride = oledAsDark && brightness == Brightness.dark ? Colors.black : null;
return ColorScheme.fromSeed(
seedColor: _primaryColor,
brightness: brightness,
).copyWith(
background: oledBackgroundOverride,
primary: _keepOriginalAccentColorOverride,
secondary: _keepOriginalAccentColorOverride,
);
}
ThemeData _getTheme(final Brightness brightness) {
final colorScheme = _buildColorScheme(brightness);
return ThemeData(
useMaterial3: true,
colorScheme: colorScheme,
scaffoldBackgroundColor: colorScheme.background,
cardColor: colorScheme.background, // For LicensePage
snackBarTheme: _snackBarTheme,
dividerTheme: _dividerTheme,
extensions: [
const NeonTheme(),
...?appThemes,
],
);
} }
final primaryColor = nextcloudTheme?.color != null ? HexColor(nextcloudTheme!.color!) : themePrimaryColor; ThemeData get lightTheme => _getTheme(Brightness.light);
ThemeData get darkTheme => _getTheme(Brightness.dark);
final oledBackgroundOverride = oledAsDark ? Colors.black : null;
final keepOriginalAccentColorOverride = keepOriginalAccentColor ? primaryColor : null; static const _snackBarTheme = SnackBarThemeData(
final colorScheme = ColorScheme.fromSeed( behavior: SnackBarBehavior.floating,
seedColor: primaryColor,
brightness: brightness,
).copyWith(
background: oledBackgroundOverride,
primary: keepOriginalAccentColorOverride,
secondary: keepOriginalAccentColorOverride,
); );
return ThemeData( static const _dividerTheme = DividerThemeData(
useMaterial3: true, thickness: 1.5,
colorScheme: colorScheme, space: 30,
scaffoldBackgroundColor: colorScheme.background,
cardColor: colorScheme.background, // For LicensePage
snackBarTheme: const SnackBarThemeData(
behavior: SnackBarBehavior.floating,
),
dividerTheme: const DividerThemeData(
thickness: 1.5,
space: 30,
),
); );
} }
@internal
@immutable
class NeonTheme extends ThemeExtension<NeonTheme> {
const NeonTheme();
@override
NeonTheme copyWith() => const NeonTheme();
@override
NeonTheme lerp(final NeonTheme? other, final double t) {
if (other is! NeonTheme) {
return this;
}
return const NeonTheme();
}
}

Loading…
Cancel
Save