Skip to content

Commit

Permalink
Merge pull request #205 from jpnurmi/theme-data-overrides
Browse files Browse the repository at this point in the history
Introduce theme data overrides
  • Loading branch information
kenvandine committed Sep 15, 2022
2 parents 6f7fb5d + 0ceaac0 commit 7fd68bc
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 6 deletions.
99 changes: 93 additions & 6 deletions lib/src/widgets/inherited_theme.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:async';

import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:platform/platform.dart';
Expand Down Expand Up @@ -56,8 +57,8 @@ YaruVariant? _detectYaruVariant(Platform platform) {
/// YaruTheme(
/// builder: (context, yaru, child) {
/// return MaterialApp(
/// theme: yaru.variant?.theme,
/// darkTheme: yaru.variant?.darkTheme,
/// theme: yaru.theme,
/// darkTheme: yaru.darkTheme,
/// home: ...
/// );
/// },
Expand All @@ -70,6 +71,28 @@ YaruVariant? _detectYaruVariant(Platform platform) {
/// that any widget created by [MaterialApp], such as the built-in [Navigator],
/// gains Yaru-theme as well.
///
/// ### Theme data overrides
///
/// The [data] property can be used to override parts of the default theme data.
/// For example, the following code overrides the default page transitions and
/// visual density:
///
/// ```dart
/// YaruTheme(
/// data: YaruThemeData(
/// pageTransitionsTheme: PageTransitionsTheme(/*...*/),
/// visualDensity: VisualDensity(horizontal: -4, vertical: -4),
/// ),
/// builder: (context, yaru, child) {
/// return MaterialApp(
/// theme: yaru.theme,
/// darkTheme: yaru.darkTheme,
/// home: ...
/// );
/// },
/// )
/// ```
///
/// See also:
/// * [YaruThemeData]
class YaruTheme extends StatefulWidget {
Expand Down Expand Up @@ -177,7 +200,7 @@ class _YaruThemeState extends State<YaruTheme> {
}

YaruThemeData resolveData() {
return YaruThemeData(
return widget.data.copyWith(
variant: widget.data.variant ?? _variant,
highContrast:
widget.data.highContrast ?? MediaQuery.highContrastOf(context),
Expand All @@ -193,7 +216,7 @@ class _YaruThemeState extends State<YaruTheme> {
}

final variant = data.variant ?? YaruVariant.orange;
return dark ? variant.darkTheme : variant.theme;
return (dark ? variant.darkTheme : variant.theme).overrideWith(data);
}

@override
Expand All @@ -216,6 +239,10 @@ class YaruThemeData with Diagnosticable {
this.variant,
this.highContrast,
this.themeMode,
this.extensions,
this.pageTransitionsTheme,
this.useMaterial3,
this.visualDensity,
});

/// Specifies the theme variant.
Expand All @@ -227,16 +254,45 @@ class YaruThemeData with Diagnosticable {
/// Whether a light or dark theme is used.
final ThemeMode? themeMode;

/// Overrides [ThemeData.extensions].
final Iterable<ThemeExtension<dynamic>>? extensions;

/// Overrides [ThemeData.pageTransitionsTheme].
final PageTransitionsTheme? pageTransitionsTheme;

/// Overrides [ThemeData.useMaterial3].
final bool? useMaterial3;

/// Overrides [ThemeData.visualDensity].
final VisualDensity? visualDensity;

/// The light theme of [variant] (or [yaruLight] if not available) merged with
/// the `YaruThemeData` overrides.
ThemeData? get theme => (variant?.theme ?? yaruLight).overrideWith(this);

/// The dark theme of [variant] (or [yaruDark] if not available) merged with
/// the `YaruThemeData` overrides.
ThemeData? get darkTheme =>
(variant?.darkTheme ?? yaruDark).overrideWith(this);

/// Creates a copy of this [YaruThemeData] with the provided values.
YaruThemeData copyWith({
YaruVariant? variant,
bool? highContrast,
ThemeMode? themeMode,
Iterable<ThemeExtension<dynamic>>? extensions,
PageTransitionsTheme? pageTransitionsTheme,
bool? useMaterial3,
VisualDensity? visualDensity,
}) {
return YaruThemeData(
variant: variant ?? this.variant,
highContrast: highContrast ?? this.highContrast,
themeMode: themeMode ?? this.themeMode,
extensions: extensions ?? this.extensions,
pageTransitionsTheme: pageTransitionsTheme ?? this.pageTransitionsTheme,
useMaterial3: useMaterial3 ?? this.useMaterial3,
visualDensity: visualDensity ?? this.visualDensity,
);
}

Expand All @@ -246,19 +302,39 @@ class YaruThemeData with Diagnosticable {
properties.add(DiagnosticsProperty<YaruVariant>('variant', variant));
properties.add(DiagnosticsProperty<bool>('highContrast', highContrast));
properties.add(DiagnosticsProperty<ThemeMode>('themeMode', themeMode));
properties.add(IterableProperty('extensions', extensions));
properties
.add(DiagnosticsProperty('pageTransitionsTheme', pageTransitionsTheme));
properties.add(DiagnosticsProperty('useMaterial3', useMaterial3));
properties.add(DiagnosticsProperty('visualDensity', visualDensity));
}

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
final iterableEquals = const IterableEquality().equals;
return other is YaruThemeData &&
other.variant == variant &&
other.highContrast == highContrast &&
other.themeMode == themeMode;
other.themeMode == themeMode &&
iterableEquals(other.extensions, extensions) &&
other.pageTransitionsTheme == pageTransitionsTheme &&
other.useMaterial3 == useMaterial3 &&
other.visualDensity == visualDensity;
}

@override
int get hashCode => Object.hash(variant, highContrast, themeMode);
int get hashCode {
return Object.hash(
variant,
highContrast,
themeMode,
extensions,
pageTransitionsTheme,
useMaterial3,
visualDensity,
);
}
}

class _YaruInheritedTheme extends InheritedTheme {
Expand All @@ -279,3 +355,14 @@ class _YaruInheritedTheme extends InheritedTheme {
return _YaruInheritedTheme(data: data, child: child);
}
}

extension _YaruThemeDataX on ThemeData {
ThemeData overrideWith(YaruThemeData data) {
return copyWith(
extensions: data.extensions,
pageTransitionsTheme: data.pageTransitionsTheme,
useMaterial3: data.useMaterial3,
visualDensity: data.visualDensity,
);
}
}
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ environment:
flutter: ">=3.3.0"

dependencies:
collection: ^1.16.0
flutter:
sdk: flutter
platform: ^3.1.0
Expand Down
26 changes: 26 additions & 0 deletions test/widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,24 @@ void main() {
expect(YaruTheme.of(context).themeMode, ThemeMode.dark);
});
});

testWidgets('theme data overrides', (tester) async {
const extensions = <ThemeExtension>[];
const pageTransitionsTheme = PageTransitionsTheme();
const visualDensity = VisualDensity(horizontal: -4, vertical: -4);
await tester.pumpTheme(
extensions: extensions,
pageTransitionsTheme: pageTransitionsTheme,
useMaterial3: false,
visualDensity: visualDensity,
);
final context = tester.element(find.byType(Container));
final theme = YaruTheme.of(context);
expect(theme.extensions, same(extensions));
expect(theme.pageTransitionsTheme, same(pageTransitionsTheme));
expect(theme.useMaterial3, isFalse);
expect(theme.visualDensity, visualDensity);
});
}

MockYaruSettings createMockSettings({String theme = ''}) {
Expand All @@ -163,13 +181,21 @@ extension ThemeTester on WidgetTester {
YaruVariant? variant,
bool? highContrast,
ThemeMode? themeMode,
Iterable<ThemeExtension<dynamic>>? extensions,
PageTransitionsTheme? pageTransitionsTheme,
bool? useMaterial3,
VisualDensity? visualDensity,
String desktop = '',
YaruSettings? settings,
}) async {
final data = YaruThemeData(
variant: variant,
highContrast: highContrast,
themeMode: themeMode,
extensions: extensions,
pageTransitionsTheme: pageTransitionsTheme,
useMaterial3: useMaterial3,
visualDensity: visualDensity,
);
await pumpWidget(
MaterialApp(
Expand Down

0 comments on commit 7fd68bc

Please sign in to comment.