refactor(ui): replace ThemeResolver by ThemeHelper in Loader / RichTextBuilder (closes #148)

This commit is contained in:
Hugo Pointcheval 2023-02-23 18:27:17 +01:00
parent 6c54689393
commit 1a48b606a4
Signed by: hugo
GPG Key ID: 3AAC487E131E00BC
15 changed files with 68 additions and 330 deletions

View File

@ -19,8 +19,7 @@ export './buttons/buttons.dart';
export './cards/cards.dart';
export './component.dart';
export './error_widget_component.dart';
export './loader_component.dart';
export './loader_style.dart';
export './loader/loader.dart';
export './loading_widget_component.dart';
export './rich_text_builder/rich_text_builder.dart';
export './text_inputs/text_inputs.dart';

View File

@ -0,0 +1,17 @@
// 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 <https://www.gnu.org/licenses/>.
export './loader_component.dart';

View File

@ -1,82 +0,0 @@
// 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 <https://www.gnu.org/licenses/>.
import 'dart:ui';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
class LoaderStyle extends ThemeStyle<LoaderStyle> {
const LoaderStyle({
this.colors,
this.stroke,
});
/// Merges non-null `b` attributes in `a`
static LoaderStyle? merge(
LoaderStyle? a,
LoaderStyle? b,
) {
if (b == null) {
return a?.copyWith();
}
if (a == null) {
return b.copyWith();
}
return a.copyWith(
colors: b.colors,
stroke: b.stroke,
);
}
/// Used for interpolation.
static LoaderStyle? lerp(
LoaderStyle? a,
LoaderStyle? b,
double t,
) {
if (a == null || b == null) {
return null;
}
// b.copyWith to return b attributes even if they are not lerped
return b.copyWith(
colors: MultiColor.lerp(a.colors, b.colors, t),
stroke: lerpDouble(a.stroke, b.stroke, t),
);
}
/// Gradient colors from start to end.
final MultiColor? colors;
/// Loader stroke width
final double? stroke;
@override
LoaderStyle? mergeWith(LoaderStyle? other) => LoaderStyle.merge(this, other);
@override
LoaderStyle copyWith({
MultiColor? colors,
double? stroke,
}) =>
LoaderStyle(
colors: colors ?? this.colors,
stroke: stroke ?? this.stroke,
);
@override
String toString() => 'LoaderStyle($colors, $stroke)';
}

View File

@ -16,4 +16,3 @@
export 'parser.dart';
export 'rich_text_builder_component.dart';
export 'rich_text_builder_style.dart';

View File

@ -28,7 +28,6 @@ abstract class RichTextBuilderComponent extends Component
this.parser,
this.defaultStyle,
this.styles,
super.themeResolver,
super.key,
});

View File

@ -11,15 +11,12 @@ abstract class $RichTextBuilderComponentCWProxy {
RichTextBuilderComponent parser(RichTextParser? parser);
RichTextBuilderComponent defaultStyle(TextStyle? defaultStyle);
RichTextBuilderComponent styles(Map<String, TextStyle>? styles);
RichTextBuilderComponent themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
RichTextBuilderComponent key(Key? key);
RichTextBuilderComponent call({
String? text,
RichTextParser? parser,
TextStyle? defaultStyle,
Map<String, TextStyle>? styles,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key,
});
}

View File

@ -1,79 +0,0 @@
// 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 <https://www.gnu.org/licenses/>.
import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
class RichTextBuilderStyle extends ThemeStyle<RichTextBuilderStyle> {
const RichTextBuilderStyle({
this.defaultStyle,
this.styles,
});
/// Merges non-null `b` attributes in `a`
static RichTextBuilderStyle? merge(
RichTextBuilderStyle? a,
RichTextBuilderStyle? b,
) {
if (b == null) {
return a?.copyWith();
}
if (a == null) {
return b.copyWith();
}
return a.copyWith(
defaultStyle: b.defaultStyle,
styles: b.styles,
);
}
/// Used for interpolation.
static RichTextBuilderStyle? lerp(
RichTextBuilderStyle? a,
RichTextBuilderStyle? b,
double t,
) {
if (a == null || b == null) {
return null;
}
// b.copyWith to return b attributes even if they are not lerped
return b.copyWith(
defaultStyle: TextStyle.lerp(a.defaultStyle, b.defaultStyle, t),
styles: b.styles, // TODO(wyatt): compute lerp value of each styles
);
}
/// Default TextStyle used in this rich text component.
final TextStyle? defaultStyle;
/// Used styles in this rich text component.
final Map<String, TextStyle>? styles;
@override
RichTextBuilderStyle? mergeWith(RichTextBuilderStyle? other) =>
RichTextBuilderStyle.merge(this, other);
@override
RichTextBuilderStyle? copyWith({
TextStyle? defaultStyle,
Map<String, TextStyle>? styles,
}) =>
RichTextBuilderStyle(
defaultStyle: defaultStyle ?? this.defaultStyle,
styles: styles ?? this.styles,
);
}

View File

@ -20,7 +20,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/loader/loader_theme_resolver.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
part 'loader.g.dart';
@ -33,30 +32,11 @@ class Loader extends LoaderComponent with $LoaderCWMixin {
super.stroke,
super.duration,
super.flip,
super.themeResolver,
super.key,
});
@override
LoaderThemeResolver? get themeResolver =>
super.themeResolver as LoaderThemeResolver?;
/// Negotiate the theme to get a complete style.
LoaderStyle _resolve(BuildContext context) {
final LoaderThemeResolver resolver = themeResolver ??
LoaderThemeResolver(
customStyleFn: (context, {extra}) => LoaderStyle(
colors: colors,
stroke: stroke,
),
);
return resolver.negotiate(context);
}
@override
Widget build(BuildContext context) {
final style = _resolve(context);
final dimension =
(radius != null) ? radius! * 2 : context.buttonTheme.height;
return SizedBox.square(
@ -64,9 +44,34 @@ class Loader extends LoaderComponent with $LoaderCWMixin {
child: RepaintBoundary(
child: CustomPaint(
painter: _LoaderPainter(
style.colors ?? const MultiColor([]),
ThemeHelper.getThemeElement<MultiColor, MultiColor>(
[
colors,
Theme.of(context).extension<LoaderThemeExtension>()?.colors,
MultiColor([
Theme.of(context).progressIndicatorTheme.color ??
context.colorScheme.primary,
context.colorScheme.onPrimary,
]),
/// This is the default value. So the final
/// value cannot be null.
const MultiColor([])
],
valueValidator: (multiColor) =>
multiColor != null && multiColor.isColor,
transform: (multiColor) => multiColor,
)!,
dimension / 2,
style.stroke ?? 4,
ThemeHelper.getThemeElement<double, double>(
[
stroke,
Theme.of(context).extension<LoaderThemeExtension>()?.stroke,
4,
],
valueValidator: (stroke) => stroke != null,
transform: (stroke) => stroke,
)!,
flip: flip ?? false,
),
)

View File

@ -41,7 +41,6 @@ class $LoaderCWProxyImpl implements $LoaderComponentCWProxy {
stroke: stroke ?? _value.stroke,
duration: duration ?? _value.duration,
flip: flip ?? _value.flip,
themeResolver: themeResolver ?? _value.themeResolver,
key: key ?? _value.key,
);
}

View File

@ -1,58 +0,0 @@
// 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 <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class LoaderThemeResolver
extends ThemeResolver<LoaderStyle, LoaderThemeExtension, void> {
const LoaderThemeResolver({
required this.customStyleFn,
});
@override
final LoaderStyle? Function(
BuildContext context, {
void extra,
}) customStyleFn;
/// Values taken from <https://api.flutter.dev/flutter/material/ElevatedButton/defaultStyleOf.html>
@override
LoaderStyle computeDefaultValue(
BuildContext context, {
void extra,
}) =>
LoaderStyle(
colors: MultiColor([
Theme.of(context).progressIndicatorTheme.color ??
context.colorScheme.primary,
context.colorScheme.onPrimary,
]),
stroke: 4,
);
@override
LoaderStyle? computeExtensionValueFn(
BuildContext context,
LoaderThemeExtension? themeExtension, {
void extra,
}) =>
LoaderStyle(
colors: themeExtension?.colors,
stroke: themeExtension?.stroke,
);
}

View File

@ -17,7 +17,6 @@
import 'package:flutter/material.dart';
import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/rich_text_builder/rich_text_builder_theme_resolver.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
part 'rich_text_builder.g.dart';
@ -30,37 +29,39 @@ class RichTextBuilder extends RichTextBuilderComponent
super.parser,
super.defaultStyle,
super.styles,
super.themeResolver,
super.key,
});
@override
RichTextBuilderThemeResolver? get themeResolver =>
super.themeResolver as RichTextBuilderThemeResolver?;
/// Negotiate the theme to get a complete style.
RichTextBuilderStyle _resolve(BuildContext context) {
final RichTextBuilderThemeResolver resolver = themeResolver ??
RichTextBuilderThemeResolver(
customStyleFn: (context, {extra}) => RichTextBuilderStyle(
defaultStyle: defaultStyle,
styles: styles,
),
);
return resolver.negotiate(context);
}
@override
Widget build(BuildContext context) {
final style = _resolve(context);
final RegExp regex = RegExp(r'<(.*?)>(.*?)<\/\1>');
final root = RichTextNode.from(
text ?? '',
regex,
RichTextStyleParameter(
style.defaultStyle,
style.styles ?? {},
ThemeHelper.getThemeElement<TextStyle, TextStyle>(
[
defaultStyle,
Theme.of(context)
.extension<RichTextBuilderThemeExtension>()
?.defaultStyle,
context.textTheme.bodyMedium,
],
valueValidator: (style) => style != null,
transform: (style) => style,
),
ThemeHelper.getThemeElement<Map<String, TextStyle>,
Map<String, TextStyle>>(
[
styles,
Theme.of(context)
.extension<RichTextBuilderThemeExtension>()
?.styles,
const <String, TextStyle>{},
],
valueValidator: (styles) => styles != null,
transform: (styles) => styles,
)!,
null,
),
);

View File

@ -20,10 +20,6 @@ class $RichTextBuilderCWProxyImpl implements $RichTextBuilderComponentCWProxy {
RichTextBuilder styles(Map<String, TextStyle>? styles) =>
this(styles: styles);
@override
RichTextBuilder themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) =>
this(themeResolver: themeResolver);
@override
RichTextBuilder key(Key? key) => this(key: key);
@override
RichTextBuilder call({
@ -31,7 +27,6 @@ class $RichTextBuilderCWProxyImpl implements $RichTextBuilderComponentCWProxy {
RichTextParser? parser,
TextStyle? defaultStyle,
Map<String, TextStyle>? styles,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key,
}) =>
RichTextBuilder(
@ -39,7 +34,6 @@ class $RichTextBuilderCWProxyImpl implements $RichTextBuilderComponentCWProxy {
parser: parser ?? _value.parser,
defaultStyle: defaultStyle ?? _value.defaultStyle,
styles: styles ?? _value.styles,
themeResolver: themeResolver ?? _value.themeResolver,
key: key ?? _value.key,
);
}

View File

@ -1,53 +0,0 @@
// 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 <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class RichTextBuilderThemeResolver extends ThemeResolver<RichTextBuilderStyle,
RichTextBuilderThemeExtension, void> {
const RichTextBuilderThemeResolver({
required this.customStyleFn,
});
/// Values taken from <https://api.flutter.dev/flutter/material/ElevatedButton/defaultStyleOf.html>
@override
RichTextBuilderStyle computeDefaultValue(
BuildContext context, {
void extra,
}) =>
RichTextBuilderStyle(
defaultStyle: context.textTheme.bodyMedium,
);
@override
final RichTextBuilderStyle? Function(
BuildContext context, {
void extra,
}) customStyleFn;
@override
RichTextBuilderStyle? computeExtensionValueFn(
BuildContext context,
RichTextBuilderThemeExtension? themeExtension, {
void extra,
}) =>
RichTextBuilderStyle(
defaultStyle: themeExtension?.defaultStyle,
styles: themeExtension?.styles,
);
}