Compare commits

...

3 Commits

Author SHA1 Message Date
0d5109fc77
feat(ui): make gradient as component
Some checks failed
continuous-integration/drone/pr Build is failing
2023-04-26 18:15:47 +02:00
3fb4020594
feat(ui): fix, rename, rewrite some helpers 2023-04-26 18:14:00 +02:00
cef73aa62d
fix(gen): rename builder correctly 2023-04-26 18:12:10 +02:00
27 changed files with 715 additions and 138 deletions

View File

@ -15,7 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
/// Extension for component copy with feature /// Extension for component copy with feature
library component_copy_with_extension; library wyatt_component_copy_with_extension;
export './src/domain/domain.dart'; export './src/domain/domain.dart';
export 'src/component_copy_with_extension.dart'; export 'src/component_copy_with_extension.dart';

View File

@ -1,7 +1,7 @@
targets: targets:
$default: $default:
builders: builders:
component_copy_with_gen: wyatt_component_copy_with_gen:
enabled: true enabled: true
generate_for: generate_for:
exclude: exclude:
@ -11,9 +11,9 @@ targets:
- test/gen_* - test/gen_*
builders: builders:
component_copy_with_gen: wyatt_component_copy_with_gen:
target: ":component_copy_with_gen" target: ":wyatt_component_copy_with_gen"
import: "package:wyatt_component_copy_with_gen/component_copy_with_gen.dart" import: "package:wyatt_component_copy_with_gen/wyatt_component_copy_with_gen.dart"
builder_factories: ["componentCopyWithReporter"] builder_factories: ["componentCopyWithReporter"]
build_extensions: { ".dart": ["copy_with_extension_gen.g.part"] } build_extensions: { ".dart": ["copy_with_extension_gen.g.part"] }
auto_apply: dependents auto_apply: dependents

View File

@ -15,7 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
/// Generator for copywith method for components /// Generator for copywith method for components
library component_copy_with_gen; library wyatt_component_copy_with_gen;
export 'src/builder.dart'; export 'src/builder.dart';
export 'src/generators/component_copy_with_generator.dart'; export 'src/generators/component_copy_with_generator.dart';

View File

@ -2,8 +2,8 @@ targets:
$default: $default:
builders: builders:
# Typically the builder key is just the package name, run `pub run build_runner doctor` to check your config. # Typically the builder key is just the package name, run `pub run build_runner doctor` to check your config.
wyatt_component_copy_with_gen:component_copy_with_gen: wyatt_component_copy_with_gen:wyatt_component_copy_with_gen:
generate_for: generate_for:
# Example glob for only the Dart files under `lib/models` # Example glob for only the Dart files under `lib/models`
- lib/**/*.dart - lib/**/*.dart
- example/lib/**/*.dart - example/lib/**/*.dart

View File

@ -49,14 +49,14 @@ class Home extends StatelessWidget {
appBar: PreferredSize( appBar: PreferredSize(
preferredSize: const Size.fromHeight(60), preferredSize: const Size.fromHeight(60),
child: context.components.appBar?.copyWith child: context.components.appBar?.copyWith
.title('Example title'.wrap()) ?? .title(const TextWrapper('Example title')) ??
const SizedBox.shrink(), const SizedBox.shrink(),
), ),
body: Column( body: Column(
children: [ children: [
Expanded( Expanded(
child: context.components.errorWidget child: context.components.errorWidget
?.copyWith(error: 'Example erreur'.wrap()) ?? ?.copyWith(error: const TextWrapper('Example erreur')) ??
const SizedBox.shrink(), const SizedBox.shrink(),
), ),
const SizedBox( const SizedBox(

View File

@ -16,6 +16,5 @@
export 'enums/enums.dart'; export 'enums/enums.dart';
export 'extensions/build_context_extensions.dart'; export 'extensions/build_context_extensions.dart';
export 'extensions/string_extension.dart';
export 'mixins/copy_with_mixin.dart'; export 'mixins/copy_with_mixin.dart';
export 'utils/utils.dart'; export 'utils/utils.dart';

View File

@ -0,0 +1,38 @@
// 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_ui_components.dart';
abstract class GradientHelper {
static LinearGradient? linearFromNullableColors(List<Color>? colors) =>
colors != null ? LinearGradient(colors: colors) : null;
static LinearGradient? linearFromMultiColor(MultiColor multiColor) =>
multiColor.isGradient ? LinearGradient(colors: multiColor.colors) : null;
static RadialGradient? radialFromNullableColors(List<Color>? colors) =>
colors != null ? RadialGradient(colors: colors) : null;
static RadialGradient? radialFromMultiColor(MultiColor multiColor) =>
multiColor.isGradient ? RadialGradient(colors: multiColor.colors) : null;
static SweepGradient? sweepFromNullableColors(List<Color>? colors) =>
colors != null ? SweepGradient(colors: colors) : null;
static SweepGradient? sweepFromMultiColor(MultiColor multiColor) =>
multiColor.isGradient ? SweepGradient(colors: multiColor.colors) : null;
}

View File

@ -36,15 +36,28 @@ class TextWrapper {
}); });
/// Creates a [TextWrapper] from a [Text] widget. /// Creates a [TextWrapper] from a [Text] widget.
const TextWrapper.text(this.data) TextWrapper.text(Text text)
: style = null, : data = text.data!,
style = text.style,
gradientColors = null, gradientColors = null,
textAlign = null, textAlign = text.textAlign,
textDirection = null, textDirection = text.textDirection,
softWrap = null, softWrap = text.softWrap,
overflow = null, overflow = text.overflow,
maxLines = null, maxLines = text.maxLines,
selectionColor = null; selectionColor = text.selectionColor;
/// Creates a [TextWrapper] from a [RichText] widget.
TextWrapper.rich(RichText richText)
: data = richText.text.toPlainText(),
style = richText.text.style,
gradientColors = null,
textAlign = richText.textAlign,
textDirection = richText.textDirection,
softWrap = richText.softWrap,
overflow = richText.overflow,
maxLines = richText.maxLines,
selectionColor = richText.selectionColor;
/// Text to be displayed /// Text to be displayed
final String data; final String data;

View File

@ -16,33 +16,76 @@
/// A helper class for getting theme elements. /// A helper class for getting theme elements.
abstract class ThemeHelper { abstract class ThemeHelper {
/// Gets a theme element from a list of styles. /// Gets a nullable theme element from a list of styles.
/// {@template getElement}
/// Styles are checked in order, and the first one that passes the /// Styles are checked in order, and the first one that passes the
/// [valueValidator] is returned. /// [valueValidator] is returned.
/// Style elements are transformed using the [transform] function. /// Style elements are transformed using the [transform] function.
/// ///
/// [styles]: A list of styles that need to be checked. /// - [styles] : A list of styles that need to be checked.
/// [transform]: A function that transforms each style element ///
/// to a [T] type. /// - [transform] : An optional function that transforms each style element
/// [valueValidator]: An optional validation function that /// to a [T] type after it passes the [valueValidator]. *(default: returns
/// determines if a style element is valid. /// element as is)*
/// [combine]: A function that combines two [P] type objects to create ///
/// a new object. /// - [valueValidator] : An optional validation function that
static T? getThemeElement<P, T>( /// determines if a style element is valid. *(default: checks if element
/// is not null)*
///
/// - [combine] : A function that combines two [P] type objects to create
/// a new object. *(default: returns the first element)*
///
/// So, if you only pass a [styles] list, the first valid style element
/// will be returned as is.
/// If you pass a [transform] function, the first valid style element
/// will be transformed to a [T] type.
/// {@endtemplate}
static T? maybeGetElement<P, T>(
List<P?>? styles, { List<P?>? styles, {
required T? Function(P?)? transform, T? Function(P?)? transform,
bool? Function(P?)? valueValidator, bool? Function(P?)? valueValidator,
P? Function(P?, P?)? combine, P? Function(P?, P?)? combine,
}) { }) {
// List of valid styles
final Iterable<P?>? validStyles = styles?.where( final Iterable<P?>? validStyles = styles?.where(
(element) => valueValidator?.call(element) ?? (element != null), (element) => valueValidator?.call(element) ?? (element != null),
); );
// tranformation function
final transformation = transform ?? (element) => element as T?;
return (validStyles?.isNotEmpty ?? false) return (validStyles?.isNotEmpty ?? false)
? transform?.call( ? transformation.call(
validStyles?.reduce( validStyles?.reduce(
(value, element) => combine?.call(value, element) ?? value, (value, element) => combine?.call(value, element) ?? value,
), ),
) )
: null; : null;
} }
/// Gets a theme element from a list of styles. Throws an exception if no
/// valid style is found.
///
/// See [maybeGetElement] for more details.
///
/// {@macro getElement}
static T getElement<P, T>(
List<P?>? styles, {
T? Function(P?)? transform,
bool? Function(P?)? valueValidator,
P? Function(P?, P?)? combine,
}) {
final result = maybeGetElement<P, T>(
styles,
transform: transform,
valueValidator: valueValidator,
combine: combine,
);
if (result == null) {
throw Exception('No valid style found');
}
return result;
}
} }

View File

@ -14,12 +14,26 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/widgets.dart'; import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
extension StringExtension on String? { abstract class ThemeImporter {
TextWrapper? wrap({TextStyle? style, MultiColor? gradientColors}) => /// Imports a [ThemeData] from either a [BuildContext] or a [ThemeData].
this != null ///
? TextWrapper(this!, style: style, gradientColors: gradientColors) /// Throws an [ArgumentError] if the type of [from] is not a [BuildContext]
: null; /// or a [ThemeData].
static ThemeData importFrom<T>(T from) {
ThemeData theme;
if (from is BuildContext) {
theme = Theme.of(from);
} else if (from is ThemeData) {
theme = from;
} else {
throw ArgumentError(
'from must be either a BuildContext or a ThemeData',
);
}
return theme;
}
} }

View File

@ -26,47 +26,52 @@ import 'package:wyatt_ui_components/src/domain/entities/theme_style.dart';
/// 1) Pass the "radius" into the constructor, `Component(radius: 12)`. /// 1) Pass the "radius" into the constructor, `Component(radius: 12)`.
/// 2) Set up a theme extension `ComponentThemeExtension(radius: 15)`. /// 2) Set up a theme extension `ComponentThemeExtension(radius: 15)`.
/// 3) Let `wyatt_ui_kit` "negotiate" and try to find a suitable style in the /// 3) Let `wyatt_ui_kit` "negotiate" and try to find a suitable style in the
/// flutter theme. /// flutter theme, or use a hardcoded value.
/// ///
/// If this negotiation phase fails, then: /// If a negotiation phase fails, it will fallback to the next one.
/// - If the value is mandatory: a hardcoded value in "wyatt_ui_kit" is chosen. ///
/// - If not, the style is simply not applied. /// This resolver uses [ThemeHelper] to negotiate and merge styles.
/// {@endtemplate} /// {@endtemplate}
abstract class ThemeResolver<S extends ThemeStyle<S>, T, E> { abstract class ThemeResolver<Style extends ThemeStyle<Style>, Extension,
Extra> {
/// {@macro theme_resolver} /// {@macro theme_resolver}
const ThemeResolver(); const ThemeResolver();
S? Function(BuildContext context, {E? extra}) get customStyleFn;
/// Compute default value from Flutter Theme or with hardcoded values. /// Compute default value from Flutter Theme or with hardcoded values.
S computeDefaultValue( Style computeDefaultValue(
BuildContext context, { BuildContext context, {
E? extra, Extra? extra,
}); });
/// Compute custom style from context.
Style? Function(BuildContext context, {Extra? extra}) get customStyleFn;
/// Compute extension value from custom component extension. /// Compute extension value from custom component extension.
S? computeExtensionValueFn( Style? computeExtensionValueFn(
BuildContext context, BuildContext context,
T? themeExtension, { Extension? themeExtension, {
E? extra, Extra? extra,
}); });
/// Choose most suitable style for a given context. /// Choose most suitable style for a given context.
S negotiate(BuildContext context, {E? extra}) { Style negotiate(BuildContext context, {Extra? extra}) {
// 1) Custom style passed in constructor (cannot be null)
final style = computeDefaultValue(context, extra: extra); final style = computeDefaultValue(context, extra: extra);
return ThemeHelper.getThemeElement<S, S>( return ThemeHelper.getElement<Style, Style>(
[ [
style, // 1) Custom style passed in constructor
computeExtensionValueFn( customStyleFn(context, extra: extra),
context, // 2) Theme extension
Theme.of(context).extension<T>(), computeExtensionValueFn(
extra: extra, context,
), Theme.of(context).extension<Extension>(),
customStyleFn(context, extra: extra) extra: extra,
], ),
transform: (value) => value, // 3) Default
combine: (value, element) => value?.mergeWith(element), style,
) ?? ],
style; transform: (value) => value,
combine: (value, element) => value?.mergeWith(element),
);
} }
} }

View File

@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
export 'gradient_helper.dart';
export 'multi_color.dart'; export 'multi_color.dart';
export 'text_wrapper.dart'; export 'text_wrapper.dart';
export 'theme_helper.dart'; export 'theme_helper.dart';

View File

@ -21,6 +21,7 @@ import 'package:wyatt_ui_components/src/core/utils/theme_resolver.dart';
/// Base class for all components. /// Base class for all components.
/// {@endtemplate} /// {@endtemplate}
abstract class Component extends StatelessWidget { abstract class Component extends StatelessWidget {
/// {@macro component}
const Component({this.themeResolver, super.key}); const Component({this.themeResolver, super.key});
/// Theme Resolver for this component /// Theme Resolver for this component

View File

@ -19,6 +19,7 @@ export './buttons/buttons.dart';
export './cards/cards.dart'; export './cards/cards.dart';
export './component.dart'; export './component.dart';
export './error_widget_component.dart'; export './error_widget_component.dart';
export './gradients/gradients.dart';
export './loader/loader.dart'; export './loader/loader.dart';
export './loading_widget_component.dart'; export './loading_widget_component.dart';
export './rich_text_builder/rich_text_builder.dart'; export './rich_text_builder/rich_text_builder.dart';

View File

@ -14,13 +14,18 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart'; import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/src/domain/entities/component.dart';
class LinearGradientHelper { /// {@template gradient_component}
static LinearGradient? fromNullableColors(List<Color>? colors) => /// Base class for all gradient components.
colors != null ? LinearGradient(colors: colors) : null; ///
/// For example, text, icons, and box borders.
/// {@endtemplate}
abstract class GradientComponent extends Component {
/// {@macro gradient_component}
const GradientComponent({super.key});
static LinearGradient? fromMultiColor(MultiColor multiColor) => /// Returns colors for the gradient.
multiColor.isGradient ? LinearGradient(colors: multiColor.colors) : null; MultiColor get gradientColors;
} }

View File

@ -0,0 +1,47 @@
// 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_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'gradient_icon_component.g.dart';
@ComponentProxyExtension()
abstract class GradientIconComponent extends Icon
with CopyWithMixin<$GradientIconComponentCWProxy>
implements GradientComponent {
GradientIconComponent({
required IconData? icon,
required this.gradientColors,
super.key,
super.size,
super.fill,
super.weight,
super.grade,
super.opticalSize,
super.color,
super.shadows,
super.semanticLabel,
super.textDirection,
}) : super(icon);
@override
final MultiColor gradientColors;
@override
ThemeResolver<dynamic, dynamic, dynamic>? get themeResolver => null;
}

View File

@ -0,0 +1,36 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'gradient_icon_component.dart';
// **************************************************************************
// ComponentProxyGenerator
// **************************************************************************
abstract class $GradientIconComponentCWProxy {
GradientIconComponent icon(IconData? icon);
GradientIconComponent gradientColors(MultiColor? gradientColors);
GradientIconComponent key(Key? key);
GradientIconComponent size(double? size);
GradientIconComponent fill(double? fill);
GradientIconComponent weight(double? weight);
GradientIconComponent grade(double? grade);
GradientIconComponent opticalSize(double? opticalSize);
GradientIconComponent color(Color? color);
GradientIconComponent shadows(List<Shadow>? shadows);
GradientIconComponent semanticLabel(String? semanticLabel);
GradientIconComponent textDirection(TextDirection? textDirection);
GradientIconComponent call({
IconData? icon,
MultiColor? gradientColors,
Key? key,
double? size,
double? fill,
double? weight,
double? grade,
double? opticalSize,
Color? color,
List<Shadow>? shadows,
String? semanticLabel,
TextDirection? textDirection,
});
}

View File

@ -0,0 +1,54 @@
// 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_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/src/core/mixins/copy_with_mixin.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/core/utils/theme_resolver.dart';
import 'package:wyatt_ui_components/src/domain/entities/gradients/gradients.dart';
part 'gradient_text_component.g.dart';
@ComponentProxyExtension()
abstract class GradientTextComponent extends Text
with CopyWithMixin<$GradientTextComponentCWProxy>
implements GradientComponent {
const GradientTextComponent({
required String? data,
required this.gradientColors,
super.style,
super.key,
super.strutStyle,
super.textAlign,
super.textDirection,
super.locale,
super.softWrap,
super.overflow,
super.textScaleFactor,
super.maxLines,
super.semanticsLabel,
super.textWidthBasis,
super.textHeightBehavior,
super.selectionColor,
}) : super(data ?? '');
@override
final MultiColor gradientColors;
@override
ThemeResolver<dynamic, dynamic, dynamic>? get themeResolver => null;
}

View File

@ -0,0 +1,45 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'gradient_text_component.dart';
// **************************************************************************
// ComponentProxyGenerator
// **************************************************************************
abstract class $GradientTextComponentCWProxy {
GradientTextComponent data(String? data);
GradientTextComponent gradientColors(MultiColor? gradientColors);
GradientTextComponent style(TextStyle? style);
GradientTextComponent key(Key? key);
GradientTextComponent strutStyle(StrutStyle? strutStyle);
GradientTextComponent textAlign(TextAlign? textAlign);
GradientTextComponent textDirection(TextDirection? textDirection);
GradientTextComponent locale(Locale? locale);
GradientTextComponent softWrap(bool? softWrap);
GradientTextComponent overflow(TextOverflow? overflow);
GradientTextComponent textScaleFactor(double? textScaleFactor);
GradientTextComponent maxLines(int? maxLines);
GradientTextComponent semanticsLabel(String? semanticsLabel);
GradientTextComponent textWidthBasis(TextWidthBasis? textWidthBasis);
GradientTextComponent textHeightBehavior(
TextHeightBehavior? textHeightBehavior);
GradientTextComponent selectionColor(Color? selectionColor);
GradientTextComponent call({
String? data,
MultiColor? gradientColors,
TextStyle? style,
Key? key,
StrutStyle? strutStyle,
TextAlign? textAlign,
TextDirection? textDirection,
Locale? locale,
bool? softWrap,
TextOverflow? overflow,
double? textScaleFactor,
int? maxLines,
String? semanticsLabel,
TextWidthBasis? textWidthBasis,
TextHeightBehavior? textHeightBehavior,
Color? selectionColor,
});
}

View File

@ -14,4 +14,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
export './linear_gradient_helper.dart'; export 'gradient_component.dart';
export 'gradient_icon_component.dart';
export 'gradient_text_component.dart';

View File

@ -2,7 +2,7 @@ targets:
$default: $default:
builders: builders:
# Typically the builder key is just the package name, run `pub run build_runner doctor` to check your config. # Typically the builder key is just the package name, run `pub run build_runner doctor` to check your config.
wyatt_component_copy_with_gen:component_copy_with_gen: wyatt_component_copy_with_gen:wyatt_component_copy_with_gen:
generate_for: generate_for:
# Example glob for only the Dart files under `lib/models` # Example glob for only the Dart files under `lib/models`
- lib/**/*.dart - lib/**/*.dart

View File

@ -14,17 +14,18 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/widgets.dart'; import 'package:flutter/material.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
extension GradientIconExtension on Icon { part 'gradient_icon.g.dart';
GradientIcon toGradient(Gradient? gradient) =>
GradientIcon.from(this, gradient);
}
class GradientIcon extends Icon { @ComponentCopyWithExtension()
const GradientIcon( class GradientIcon extends GradientIconComponent with $GradientIconCWMixin {
super.icon, { GradientIcon(
this.gradient, {
required super.icon,
required super.gradientColors,
super.key, super.key,
super.size, super.size,
super.fill, super.fill,
@ -35,11 +36,34 @@ class GradientIcon extends Icon {
super.shadows, super.shadows,
super.semanticLabel, super.semanticLabel,
super.textDirection, super.textDirection,
}); }) : widgetIcon = null;
factory GradientIcon.from(Icon icon, Gradient? gradient) => GradientIcon( GradientIcon.fromWidget(
icon.icon, Widget icon, {
gradient: gradient, MultiColor? gradientColors,
super.key,
super.size,
super.fill,
super.weight,
super.grade,
super.opticalSize,
super.color,
super.shadows,
super.semanticLabel,
super.textDirection,
}) : widgetIcon = icon,
super(
icon: null,
gradientColors: gradientColors ?? const MultiColor([]),
);
factory GradientIcon.fromIcon(
Icon icon, {
MultiColor? gradientColors,
}) =>
GradientIcon(
icon: icon.icon,
gradientColors: gradientColors ?? const MultiColor([]),
key: icon.key, key: icon.key,
size: icon.size, size: icon.size,
fill: icon.fill, fill: icon.fill,
@ -52,20 +76,76 @@ class GradientIcon extends Icon {
textDirection: icon.textDirection, textDirection: icon.textDirection,
); );
final Gradient? gradient; /// Creates a [GradientIcon] from a [Widget].
///
/// Use [GradientIcon.fromWidget] to set this widget as the icon.
final Widget? widgetIcon;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (gradient != null) { if (widgetIcon != null) {
// Return the widget icon colorized with the super.color.
if (super.color != null) {
return ColorFiltered(
colorFilter: ColorFilter.mode(
super.color!,
BlendMode.srcIn,
),
child: widgetIcon,
);
}
// else, return the widget icon with the gradient.
final Gradient? linearGradient =
GradientHelper.linearFromMultiColor(gradientColors);
if (linearGradient != null) {
return ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (bounds) => linearGradient.createShader(
Rect.fromLTWH(0, 0, bounds.width, bounds.height),
),
child: widgetIcon,
);
}
if (gradientColors.colors.isNotEmpty) {
// if multicolor has only one color, return the widget icon with the
// color.
return ColorFiltered(
colorFilter: ColorFilter.mode(
gradientColors.color,
BlendMode.srcIn,
),
child: widgetIcon,
);
}
// If there is no gradient and no color, just build the widget icon.
return widgetIcon!;
}
// if no widgetIcon, work with the icon.
if (super.color != null) {
return super.copyWith.call(color: super.color).build(context);
}
final Gradient? linearGradient =
GradientHelper.linearFromMultiColor(gradientColors);
if (linearGradient != null) {
return ShaderMask( return ShaderMask(
blendMode: BlendMode.srcIn, blendMode: BlendMode.srcIn,
shaderCallback: (bounds) => gradient!.createShader( shaderCallback: (bounds) => linearGradient.createShader(
Rect.fromLTWH(0, 0, bounds.width, bounds.height), Rect.fromLTWH(0, 0, bounds.width, bounds.height),
), ),
child: super.build(context), child: super.build(context),
); );
} else {
return super.build(context);
} }
if (gradientColors.colors.isNotEmpty) {
return super.copyWith.call(color: gradientColors.color).build(context);
}
// If there is no gradient and no color, just build the icon.
return super.build(context);
} }
} }

View File

@ -0,0 +1,74 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'gradient_icon.dart';
// **************************************************************************
// ComponentCopyWithGenerator
// **************************************************************************
class $GradientIconCWProxyImpl implements $GradientIconComponentCWProxy {
const $GradientIconCWProxyImpl(this._value);
final GradientIcon _value;
@override
GradientIcon icon(IconData? icon) => this(icon: icon);
@override
GradientIcon gradientColors(MultiColor? gradientColors) =>
this(gradientColors: gradientColors);
@override
GradientIcon key(Key? key) => this(key: key);
@override
GradientIcon size(double? size) => this(size: size);
@override
GradientIcon fill(double? fill) => this(fill: fill);
@override
GradientIcon weight(double? weight) => this(weight: weight);
@override
GradientIcon grade(double? grade) => this(grade: grade);
@override
GradientIcon opticalSize(double? opticalSize) =>
this(opticalSize: opticalSize);
@override
GradientIcon color(Color? color) => this(color: color);
@override
GradientIcon shadows(List<Shadow>? shadows) => this(shadows: shadows);
@override
GradientIcon semanticLabel(String? semanticLabel) =>
this(semanticLabel: semanticLabel);
@override
GradientIcon textDirection(TextDirection? textDirection) =>
this(textDirection: textDirection);
@override
GradientIcon call({
IconData? icon,
MultiColor? gradientColors,
Key? key,
double? size,
double? fill,
double? weight,
double? grade,
double? opticalSize,
Color? color,
List<Shadow>? shadows,
String? semanticLabel,
TextDirection? textDirection,
}) =>
GradientIcon(
icon: icon ?? _value.icon,
gradientColors: gradientColors ?? _value.gradientColors,
key: key ?? _value.key,
size: size ?? _value.size,
fill: fill ?? _value.fill,
weight: weight ?? _value.weight,
grade: grade ?? _value.grade,
opticalSize: opticalSize ?? _value.opticalSize,
color: color ?? _value.color,
shadows: shadows ?? _value.shadows,
semanticLabel: semanticLabel ?? _value.semanticLabel,
textDirection: textDirection ?? _value.textDirection,
);
}
mixin $GradientIconCWMixin on Component {
$GradientIconComponentCWProxy get copyWith =>
$GradientIconCWProxyImpl(this as GradientIcon);
}

View File

@ -17,30 +17,19 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; import 'package:wyatt_ui_kit/src/components/gradients/gradient_text_style.dart';
extension GradientTextExtension on Text { part 'gradient_text.g.dart';
/// If this text contains a [GradientTextStyle] it simply transforms it in
/// [GradientText], if not it needs a [MultiColor].
GradientText toGradient({MultiColor? gradientColors}) {
if (style is GradientTextStyle?) {
// Gradient
final gradientStyle = (style as GradientTextStyle?)?.gradientColors;
return GradientText.from(this, gradientStyle ?? gradientColors);
}
return GradientText.from(this, gradientColors); @ComponentCopyWithExtension()
} class GradientText extends GradientTextComponent with $GradientTextCWMixin {
const GradientText({
GradientText toFlutterGradient(Gradient? gradient) => required super.data,
GradientText.from(this, MultiColor(gradient?.colors)); required super.gradientColors,
}
class GradientText extends Text {
const GradientText(
super.data, {
super.style, super.style,
super.key,
super.strutStyle, super.strutStyle,
super.textAlign, super.textAlign,
super.textDirection, super.textDirection,
@ -53,46 +42,79 @@ class GradientText extends Text {
super.textWidthBasis, super.textWidthBasis,
super.textHeightBehavior, super.textHeightBehavior,
super.selectionColor, super.selectionColor,
super.key,
}); });
factory GradientText.from(Text text, MultiColor? gradientColors) => /// Creates a [GradientText] from a [TextWrapper].
///
/// You can pass a gradient in case the [TextWrapper] doesn't have one.
/// You can also pass a style in case the [TextWrapper] doesn't have one.
factory GradientText.fromWrapper(
TextWrapper wrapper, {
MultiColor? gradientColors,
TextStyle? style,
}) =>
GradientText( GradientText(
text.data ?? '', data: wrapper.data,
style: GradientTextStyle.from(text.style, gradientColors), gradientColors:
strutStyle: text.strutStyle, wrapper.gradientColors ?? gradientColors ?? const MultiColor([]),
textAlign: text.textAlign, style: wrapper.style ?? style,
textDirection: text.textDirection, textAlign: wrapper.textAlign,
locale: text.locale, textDirection: wrapper.textDirection,
softWrap: text.softWrap, softWrap: wrapper.softWrap,
overflow: text.overflow, overflow: wrapper.overflow,
textScaleFactor: text.textScaleFactor, maxLines: wrapper.maxLines,
maxLines: text.maxLines, selectionColor: wrapper.selectionColor,
semanticsLabel: text.semanticsLabel, );
textWidthBasis: text.textWidthBasis,
textHeightBehavior: text.textHeightBehavior, factory GradientText.fromGradientStyle(
selectionColor: text.selectionColor, String data, {
key: text.key, required GradientTextStyle style,
}) =>
GradientText(
data: data,
gradientColors: style.gradientColors ?? const MultiColor([]),
style: style,
); );
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (style is GradientTextStyle?) { if (super.style is GradientTextStyle) {
// Gradient // If the style is a gradient style, create a gradient text from it.
final gradientStyle = (style as GradientTextStyle?)?.gradientColors; final Gradient? linearGradient = GradientHelper.linearFromMultiColor(
final gradient = (gradientStyle?.isGradient ?? false) (super.style as GradientTextStyle?)?.gradientColors ??
? LinearGradientHelper.fromMultiColor(gradientStyle!) const MultiColor([]),
: null; );
if (gradient != null) { if (linearGradient != null) {
return ShaderMask( return ShaderMask(
blendMode: BlendMode.srcIn, blendMode: BlendMode.srcIn,
shaderCallback: (bounds) => gradient.createShader( shaderCallback: (bounds) => linearGradient.createShader(
Rect.fromLTWH(0, 0, bounds.width, bounds.height), Rect.fromLTWH(0, 0, bounds.width, bounds.height),
), ),
child: super.build(context), child: super.build(context),
); );
} }
} }
final Gradient? linearGradient =
GradientHelper.linearFromMultiColor(gradientColors);
if (linearGradient != null) {
return ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (bounds) => linearGradient.createShader(
Rect.fromLTWH(0, 0, bounds.width, bounds.height),
),
child: super.build(context),
);
}
if (gradientColors.colors.isNotEmpty) {
return super
.copyWith
.call(style: style?.copyWith(color: gradientColors.color))
.build(context);
}
// If there is no gradient and no color, just build the text.
return super.build(context); return super.build(context);
} }
} }

View File

@ -0,0 +1,94 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'gradient_text.dart';
// **************************************************************************
// ComponentCopyWithGenerator
// **************************************************************************
class $GradientTextCWProxyImpl implements $GradientTextComponentCWProxy {
const $GradientTextCWProxyImpl(this._value);
final GradientText _value;
@override
GradientText data(String? data) => this(data: data);
@override
GradientText gradientColors(MultiColor? gradientColors) =>
this(gradientColors: gradientColors);
@override
GradientText style(TextStyle? style) => this(style: style);
@override
GradientText key(Key? key) => this(key: key);
@override
GradientText strutStyle(StrutStyle? strutStyle) =>
this(strutStyle: strutStyle);
@override
GradientText textAlign(TextAlign? textAlign) => this(textAlign: textAlign);
@override
GradientText textDirection(TextDirection? textDirection) =>
this(textDirection: textDirection);
@override
GradientText locale(Locale? locale) => this(locale: locale);
@override
GradientText softWrap(bool? softWrap) => this(softWrap: softWrap);
@override
GradientText overflow(TextOverflow? overflow) => this(overflow: overflow);
@override
GradientText textScaleFactor(double? textScaleFactor) =>
this(textScaleFactor: textScaleFactor);
@override
GradientText maxLines(int? maxLines) => this(maxLines: maxLines);
@override
GradientText semanticsLabel(String? semanticsLabel) =>
this(semanticsLabel: semanticsLabel);
@override
GradientText textWidthBasis(TextWidthBasis? textWidthBasis) =>
this(textWidthBasis: textWidthBasis);
@override
GradientText textHeightBehavior(TextHeightBehavior? textHeightBehavior) =>
this(textHeightBehavior: textHeightBehavior);
@override
GradientText selectionColor(Color? selectionColor) =>
this(selectionColor: selectionColor);
@override
GradientText call({
String? data,
MultiColor? gradientColors,
TextStyle? style,
Key? key,
StrutStyle? strutStyle,
TextAlign? textAlign,
TextDirection? textDirection,
Locale? locale,
bool? softWrap,
TextOverflow? overflow,
double? textScaleFactor,
int? maxLines,
String? semanticsLabel,
TextWidthBasis? textWidthBasis,
TextHeightBehavior? textHeightBehavior,
Color? selectionColor,
}) =>
GradientText(
data: data ?? _value.data,
gradientColors: gradientColors ?? _value.gradientColors,
style: style ?? _value.style,
key: key ?? _value.key,
strutStyle: strutStyle ?? _value.strutStyle,
textAlign: textAlign ?? _value.textAlign,
textDirection: textDirection ?? _value.textDirection,
locale: locale ?? _value.locale,
softWrap: softWrap ?? _value.softWrap,
overflow: overflow ?? _value.overflow,
textScaleFactor: textScaleFactor ?? _value.textScaleFactor,
maxLines: maxLines ?? _value.maxLines,
semanticsLabel: semanticsLabel ?? _value.semanticsLabel,
textWidthBasis: textWidthBasis ?? _value.textWidthBasis,
textHeightBehavior: textHeightBehavior ?? _value.textHeightBehavior,
selectionColor: selectionColor ?? _value.selectionColor,
);
}
mixin $GradientTextCWMixin on Component {
$GradientTextComponentCWProxy get copyWith =>
$GradientTextCWProxyImpl(this as GradientText);
}

View File

@ -15,4 +15,3 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
export './extensions/extensions.dart'; export './extensions/extensions.dart';
export './helpers/helpers.dart';

View File

@ -17,7 +17,11 @@
import 'package:wyatt_ui_components/wyatt_ui_components.dart'; import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
/// {@template wyatt_component_theme_data}
/// A class that holds the theme data for the Wyatt UI Kit.
/// {@endtemplate}
class WyattComponentThemeData { class WyattComponentThemeData {
/// {@macro wyatt_component_theme_data}
static ComponentThemeData get wyattComponentThemeData => ComponentThemeData( static ComponentThemeData get wyattComponentThemeData => ComponentThemeData(
appBar: const TopAppBar(), appBar: const TopAppBar(),
topNavigationBarComponent: const TopNavigationBar(), topNavigationBarComponent: const TopNavigationBar(),