feat(ui_kit): allow to cascade styles in ThemeHelper

This commit is contained in:
Malo Léon 2023-02-22 19:28:09 +01:00
parent 4a3fde3a1e
commit 2dfbd59773
7 changed files with 39 additions and 33 deletions

View File

@ -77,7 +77,7 @@ class Bars extends DemoPage {
),
],
navigationItems: [
'ACCEUIL'.wrap(),
'ACCEUIL'.wrap(style: const TextStyle(color: Colors.red)),
'VOTRE PROGRAMME'.wrap(),
'LE STUDIO'.wrap(),
'SAVOIR FAIRE'.wrap()

View File

@ -25,6 +25,7 @@ class TopAppBarTheme extends TopBarThemeExtension {
subTitleStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w400,
color: const Color.fromRGBO(36, 38, 42, 1),
fontStyle: FontStyle.italic,
fontSize: 18,
),
iconTheme: const IconThemeData(color: Color.fromRGBO(36, 38, 42, 1)),
@ -43,6 +44,7 @@ class TopAppBarTheme extends TopBarThemeExtension {
),
subTitleStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w400,
fontStyle: FontStyle.italic,
fontSize: 18,
),
iconTheme: const IconThemeData(color: Colors.white),

View File

@ -58,16 +58,15 @@ class TopAppBar extends TopAppBarComponent with $TopAppBarCWMixin {
valueValidator: (value) => value?.isGradient,
transform: (value) =>
LinearGradientHelper.fromNullableColors(value?.colors),
defaultValue: null,
),
color: ThemeHelper.getThemeElement<MultiColor, Color>(
[
backgroundColor,
context.themeExtension<TopBarThemeExtension>()?.backgroundColors,
MultiColor.single(Theme.of(context).appBarTheme.backgroundColor),
],
valueValidator: (value) => value?.isColor,
transform: (value) => value?.color,
defaultValue: Theme.of(context).appBarTheme.backgroundColor,
),
),
child: Column(
@ -88,10 +87,10 @@ class TopAppBar extends TopAppBarComponent with $TopAppBarCWMixin {
[
iconTheme,
context.themeExtension<TopBarThemeExtension>()?.iconTheme,
Theme.of(context).iconTheme,
],
valueValidator: (value) => value != null,
transform: (value) => value,
defaultValue: Theme.of(context).iconTheme,
),
primary: primary ?? true,
excludeHeaderSemantics: excludeHeaderSemantics ?? false,
@ -100,12 +99,13 @@ class TopAppBar extends TopAppBarComponent with $TopAppBarCWMixin {
title?.data ?? '',
style: ThemeHelper.getThemeElement<TextStyle, TextStyle>(
[
context.textTheme.titleLarge,
context.themeExtension<TopBarThemeExtension>()?.titleStyle,
title?.style,
context.themeExtension<TopBarThemeExtension>()?.titleStyle
],
valueValidator: (value) => value != null,
combine: (p0, p1) => p0?.merge(p1),
transform: (value) => value,
defaultValue: context.textTheme.titleLarge,
),
).toGradient(gradientColors: title?.gradientColors),
leading: leading,
@ -120,10 +120,10 @@ class TopAppBar extends TopAppBarComponent with $TopAppBarCWMixin {
.themeExtension<TopBarThemeExtension>()
?.secondaryColor
?.withOpacity(0.1),
Theme.of(context).dividerColor,
],
valueValidator: (value) => value != null,
transform: (value) => value,
defaultValue: Theme.of(context).dividerColor,
),
context: context,
tiles: expandedWidget!,

View File

@ -62,16 +62,15 @@ class TopNavigationBar extends TopNavigationBarComponent
valueValidator: (value) => value?.isGradient,
transform: (value) =>
LinearGradientHelper.fromNullableColors(value?.colors),
defaultValue: null,
),
color: ThemeHelper.getThemeElement<MultiColor, Color>(
[
backgroundColor,
context.themeExtension<TopBarThemeExtension>()?.backgroundColors,
MultiColor.single(Theme.of(context).appBarTheme.backgroundColor),
],
valueValidator: (value) => value?.isColor,
transform: (value) => value?.color,
defaultValue: Theme.of(context).appBarTheme.backgroundColor,
),
),
child: AppBar(
@ -90,10 +89,10 @@ class TopNavigationBar extends TopNavigationBarComponent
[
iconTheme,
context.themeExtension<TopBarThemeExtension>()?.iconTheme,
Theme.of(context).iconTheme,
],
valueValidator: (value) => value != null,
transform: (value) => value,
defaultValue: Theme.of(context).iconTheme,
),
primary: primary ?? true,
excludeHeaderSemantics: excludeHeaderSemantics ?? false,

View File

@ -41,11 +41,11 @@ class NavigationItem extends StatelessWidget {
[
context
.themeExtension<TopBarThemeExtension>()
?.secondaryColor
?.secondaryColor,
Theme.of(context).primaryColor,
],
valueValidator: (value) => value != null,
transform: (value) => value,
defaultValue: Theme.of(context).primaryColor,
),
),
),
@ -56,14 +56,15 @@ class NavigationItem extends StatelessWidget {
item.data,
style: ThemeHelper.getThemeElement<TextStyle, TextStyle>(
[
item.style,
context.textTheme.titleMedium,
context
.themeExtension<TopBarThemeExtension>()
?.subTitleStyle
?.subTitleStyle,
item.style,
],
combine: (value, element) => value?.merge(element),
valueValidator: (value) => value != null,
transform: (value) => value,
defaultValue: context.textTheme.titleMedium,
),
),
),

View File

@ -74,7 +74,6 @@ class CardWrapper extends StatelessWidget {
],
valueValidator: (shadow) => shadow != null,
transform: (shadow) => shadow,
defaultValue: null,
);
return (themeShadow != null) ? [themeShadow] : [];
}
@ -92,11 +91,9 @@ class CardWrapper extends StatelessWidget {
.extension<CardThemeExtension>()
?.backgroundColors,
],
valueValidator: (multiColor) =>
multiColor != null && multiColor.isGradient,
valueValidator: (multiColor) => multiColor?.isGradient,
transform: (multiColor) =>
LinearGradientHelper.fromMultiColor(multiColor!),
defaultValue: null,
),
color: ThemeHelper.getThemeElement<MultiColor, Color>(
[
@ -104,11 +101,11 @@ class CardWrapper extends StatelessWidget {
Theme.of(context)
.extension<CardThemeExtension>()
?.backgroundColors,
MultiColor.single(Theme.of(context).cardColor),
],
valueValidator: (multiColor) =>
multiColor != null && multiColor.isColor,
transform: (multiColor) => multiColor?.color,
defaultValue: Theme.of(context).cardColor,
),
border: ThemeHelper.getThemeElement<MultiColor, BoxBorder>(
[
@ -130,7 +127,6 @@ class CardWrapper extends StatelessWidget {
color: multiColor.color,
);
},
defaultValue: null,
),
boxShadow: _shadow(context),
),

View File

@ -16,26 +16,34 @@
/// A helper class for getting theme elements.
abstract class ThemeHelper {
/// Gets a theme element from a list of styles.
/// Styles are checked in order, and the first one that passes the
/// [valueValidator] is returned.
/// If no style passes the [valueValidator], the [defaultValue] is returned.
/// If [styles] is null or empty, the [defaultValue] is returned.
/// Style elements are transformed using the [transform] function.
///
/// [styles]: A list of styles that need to be checked.
/// [transform]: A function that transforms each style element
/// to a [T] type.
/// [valueValidator]: An optional validation function that
/// determines if a style element is valid.
/// [combine]: A function that combines two [P] type objects to create
/// a new object.
static T? getThemeElement<P, T>(
List<P?>? styles, {
required T? Function(P?)? transform,
required T? defaultValue,
bool? Function(P?)? valueValidator,
P? Function(P?, P?)? combine,
}) {
if (styles?.isNotEmpty ?? false) {
for (final element in styles!) {
if (valueValidator?.call(element) ?? false) {
return transform?.call(element);
}
}
}
return defaultValue;
final Iterable<P?>? validStyles = styles?.where(
(element) => valueValidator?.call(element) ?? (element != null),
);
return (validStyles?.isNotEmpty ?? false)
? transform?.call(
validStyles?.reduce(
(value, element) => combine?.call(value, element) ?? value,
),
)
: null;
}
}