diff --git a/packages/wyatt_ui_components/lib/src/core/utils/theme_resolver.dart b/packages/wyatt_ui_components/lib/src/core/utils/theme_resolver.dart index cc14f747..45834ca5 100644 --- a/packages/wyatt_ui_components/lib/src/core/utils/theme_resolver.dart +++ b/packages/wyatt_ui_components/lib/src/core/utils/theme_resolver.dart @@ -15,6 +15,7 @@ // along with this program. If not, see . import 'package:flutter/material.dart'; +import 'package:wyatt_ui_components/src/domain/entities/theme_style.dart'; /// {@template theme_resolver} /// In charge of theme negotiation and merge. @@ -30,7 +31,7 @@ import 'package:flutter/material.dart'; /// - If the value is mandatory: a hardcoded value in "wyatt_ui_kit" is chosen. /// - If not, the style is simply not applied. /// {@endtemplate} -abstract class ThemeResolver { +abstract class ThemeResolver, T, E> { /// {@macro theme_resolver} const ThemeResolver(); @@ -81,8 +82,13 @@ abstract class ThemeResolver { /// Choose most suitable style for a given context. S negotiate(BuildContext context, {E? extra}) { S style = computeDefaultValue(context, extra: extra); - style = computeExtensionValue(context, style, extra: extra) ?? style; - style = computeCustomValue(context, style, extra: extra) ?? style; - return style; + final S? extensionStyle = + computeExtensionValue(context, style, extra: extra); + + style = style.mergeWith(extensionStyle); + + final S? customStyle = computeCustomValue(context, style, extra: extra); + + return style.mergeWith(customStyle); } } diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/button_component.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/button_component.dart index a5c285d5..57b543c2 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/button_component.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/button_component.dart @@ -26,7 +26,7 @@ abstract class ButtonComponent extends Component { this.selectedStyle, this.invalidStyle, this.onPressed, - this.themeResolver, + super.themeResolver, super.key, }); @@ -53,7 +53,4 @@ abstract class ButtonComponent extends Component { /// Callback on button press final void Function(ControlState state)? onPressed; - - /// Theme Resolver for this component - final ThemeResolver? themeResolver; } diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/button_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/button_style.dart index de126460..9d3fddf9 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/button_style.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/button_style.dart @@ -16,8 +16,9 @@ import 'package:flutter/widgets.dart'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart'; +import 'package:wyatt_ui_components/src/domain/entities/theme_style.dart'; -abstract class ButtonStyle { +abstract class ButtonStyle extends ThemeStyle { const ButtonStyle({ this.radius, this.padding, diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_style.dart index e543229b..4bf83810 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_style.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_style.dart @@ -37,6 +37,31 @@ class FileSelectionButtonStyle extends ButtonStyle { super.shadow, }); + /// Merges non-null `b` attributes in `a` + static FileSelectionButtonStyle? merge( + FileSelectionButtonStyle? a, + FileSelectionButtonStyle? b, + ) { + if (b == null) { + return a?.copyWith(); + } + if (a == null) { + return b.copyWith(); + } + + return a.copyWith( + title: b.title, + subTitle: b.subTitle, + radius: b.radius, + padding: b.padding, + foregroundColors: b.foregroundColors, + backgroundColors: b.backgroundColors, + borderColors: b.borderColors, + stroke: b.stroke, + shadow: b.shadow, + ); + } + /// Used for interpolation. static FileSelectionButtonStyle? lerp( FileSelectionButtonStyle? a, @@ -81,4 +106,15 @@ class FileSelectionButtonStyle extends ButtonStyle { /// /// Default to `TextTheme.labelSmall` final TextStyle? subTitle; + + @override + FileSelectionButtonStyle mergeWith(FileSelectionButtonStyle? other) => + FileSelectionButtonStyle.merge(this, other)!; + + @override + FileSelectionButtonStyle? lerpWith( + FileSelectionButtonStyle? other, + double t, + ) => + FileSelectionButtonStyle.lerp(this, other, t); } diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_style.dart index cc57472b..980b83d7 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_style.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_style.dart @@ -36,6 +36,30 @@ class FlatButtonStyle extends ButtonStyle { super.shadow, }); + /// Merges non-null `b` attributes in `a` + static FlatButtonStyle? merge( + FlatButtonStyle? a, + FlatButtonStyle? b, + ) { + if (b == null) { + return a?.copyWith(); + } + if (a == null) { + return b.copyWith(); + } + + return a.copyWith( + label: b.label, + radius: b.radius, + padding: b.padding, + foregroundColors: b.foregroundColors, + backgroundColors: b.backgroundColors, + borderColors: b.borderColors, + stroke: b.stroke, + shadow: b.shadow, + ); + } + /// Used for interpolation. static FlatButtonStyle? lerp( FlatButtonStyle? a, @@ -76,6 +100,10 @@ class FlatButtonStyle extends ButtonStyle { final TextStyle? label; @override - String toString() => - 'FlatButtonStyle(label: $label), inherited: ${super.toString()}'; + FlatButtonStyle mergeWith(FlatButtonStyle? other) => + FlatButtonStyle.merge(this, other)!; + + @override + FlatButtonStyle? lerpWith(FlatButtonStyle? other, double t) => + FlatButtonStyle.lerp(this, other, t); } diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_style.dart index 3d468e63..70be77bc 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_style.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_style.dart @@ -36,6 +36,30 @@ class SimpleIconButtonStyle extends ButtonStyle { super.shadow, }); + /// Merges non-null `b` attributes in `a` + static SimpleIconButtonStyle? merge( + SimpleIconButtonStyle? a, + SimpleIconButtonStyle? b, + ) { + if (b == null) { + return a?.copyWith(); + } + if (a == null) { + return b.copyWith(); + } + + return a.copyWith( + dimension: b.dimension, + radius: b.radius, + padding: b.padding, + foregroundColors: b.foregroundColors, + backgroundColors: b.backgroundColors, + borderColors: b.borderColors, + stroke: b.stroke, + shadow: b.shadow, + ); + } + /// Used for interpolation. static SimpleIconButtonStyle? lerp( SimpleIconButtonStyle? a, @@ -74,4 +98,12 @@ class SimpleIconButtonStyle extends ButtonStyle { /// /// Default to `context.buttonTheme.height` final double? dimension; + + @override + SimpleIconButtonStyle mergeWith(SimpleIconButtonStyle? other) => + SimpleIconButtonStyle.merge(this, other)!; + + @override + SimpleIconButtonStyle? lerpWith(SimpleIconButtonStyle? other, double t) => + SimpleIconButtonStyle.lerp(this, other, t); } diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_style.dart index ab5c44b8..7f8e7b6d 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_style.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_style.dart @@ -37,6 +37,31 @@ class SymbolButtonStyle extends ButtonStyle { super.shadow, }); + /// Merges non-null `b` attributes in `a` + static SymbolButtonStyle? merge( + SymbolButtonStyle? a, + SymbolButtonStyle? b, + ) { + if (b == null) { + return a?.copyWith(); + } + if (a == null) { + return b.copyWith(); + } + + return a.copyWith( + label: b.label, + dimension: b.dimension, + radius: b.radius, + padding: b.padding, + foregroundColors: b.foregroundColors, + backgroundColors: b.backgroundColors, + borderColors: b.borderColors, + stroke: b.stroke, + shadow: b.shadow, + ); + } + /// Used for interpolation. static SymbolButtonStyle? lerp( SymbolButtonStyle? a, @@ -81,4 +106,12 @@ class SymbolButtonStyle extends ButtonStyle { /// /// Default to `context.buttonTheme.height` final double? dimension; + + @override + SymbolButtonStyle mergeWith(SymbolButtonStyle? other) => + SymbolButtonStyle.merge(this, other)!; + + @override + SymbolButtonStyle? lerpWith(SymbolButtonStyle? other, double t) => + SymbolButtonStyle.lerp(this, other, t); } diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/component.dart b/packages/wyatt_ui_components/lib/src/domain/entities/component.dart index 33f05fbd..e7f984f1 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/component.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/component.dart @@ -15,7 +15,11 @@ // along with this program. If not, see . import 'package:flutter/material.dart'; +import 'package:wyatt_ui_components/src/core/utils/theme_resolver.dart'; abstract class Component extends StatelessWidget { - const Component({super.key}); + const Component({this.themeResolver, super.key}); + + /// Theme Resolver for this component + final ThemeResolver? themeResolver; } diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/entities.dart b/packages/wyatt_ui_components/lib/src/domain/entities/entities.dart index 5a07411a..39ae2f65 100644 --- a/packages/wyatt_ui_components/lib/src/domain/entities/entities.dart +++ b/packages/wyatt_ui_components/lib/src/domain/entities/entities.dart @@ -21,3 +21,4 @@ export './cards/cards.dart'; export './component.dart'; export './error_widget_component.dart'; export './loading_widget_component.dart'; +export './theme_style.dart'; diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/theme_style.dart b/packages/wyatt_ui_components/lib/src/domain/entities/theme_style.dart new file mode 100644 index 00000000..7c923ac0 --- /dev/null +++ b/packages/wyatt_ui_components/lib/src/domain/entities/theme_style.dart @@ -0,0 +1,25 @@ +// Copyright (C) 2023 WYATT GROUP +// Please see the AUTHORS file for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +abstract class ThemeStyle { + const ThemeStyle(); + + /// Merges non-null `other` attributes in `this` and returns a copy. + T mergeWith(T? other); + + /// Used for interpolation. + T? lerpWith(T? other, double t); +}