Compare commits

...

27 Commits

Author SHA1 Message Date
4030511f4a fix(ui_components-ui_kit): fix, clean and unify logic and code after rebase 2023-02-21 09:54:19 +01:00
8ed8a71c7c fix(ui_kit): fix conflicts in card component after rebase 2023-02-21 08:53:38 +01:00
b6d22002ee fix(ui_kit): fix export theme file 2023-02-21 08:52:18 +01:00
9b9339cb56 chore(ui_components): add copywith deps 2023-02-21 08:49:52 +01:00
b57500b854 feat(ui_kit): update example (#138) 2023-02-21 08:46:14 +01:00
1edb1f7324 feat(ui_kit): implemement text inputs (#138) 2023-02-21 08:37:36 +01:00
edf72cf4c2 feat(ui_components):add text input components, theme extension and worked on utils (#138) 2023-02-21 08:36:58 +01:00
f6c16c5dc4 feat(ui_components): add isColor getter in multicolor helper 2023-02-21 08:35:12 +01:00
c6beae597b refactor(ui_components): update colors using Multicolor class (#138) 2023-02-21 08:35:12 +01:00
c2b60f2d79 feat(ui_kit): add text input theme extension (#138) 2023-02-21 08:35:12 +01:00
1e8d5d088e chore(ui_components): export text inputs (#138) 2023-02-21 08:35:04 +01:00
419c99c103 feat(ui_components): add text input abstract class (#138) 2023-02-21 08:32:38 +01:00
5387dd6eed
build(ui_kit): use hosted version of bloc_helper
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-17 17:26:23 +01:00
f67e4aa112
ci: use latest dart version in ci container
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-17 16:28:22 +01:00
2769d45e20
fix(ui_kit): fix text align, add selection and update example for rich text builder
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-17 15:57:54 +01:00
66719732f7
feat(ui_kit): implement rich text builder (closes #141) 2023-02-17 14:49:41 +01:00
25018dc78a
feat(ui_component): add rich text builder / parser 2023-02-17 14:48:49 +01:00
efeb3acff3
build(ui): optimize build runner 2023-02-17 14:48:23 +01:00
ef52015372
refactor(ui): rework text gradient and text wrapper 2023-02-17 14:47:56 +01:00
c5f8b69184
style(ui_kit): add example demo-page auto-generation
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-16 15:13:55 +01:00
33984b1733
feat(ui_kit): add loader implementation 2023-02-16 15:13:21 +01:00
a47c28a4d6
feat(ui_component): add loader component and style 2023-02-16 15:12:40 +01:00
63bbde8213
refactor(ui_component): remove CopyWith extension 2023-02-16 15:12:18 +01:00
8070623e88
fix(ui_component): add generated component with theme resolver 2023-02-16 15:11:34 +01:00
4c08a692d2
refactor(ui_kit): move exportable bloc from mixin to widget
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-16 11:55:11 +01:00
8044d07413
fix(ui_component): add style merge in Theme Resolver 2023-02-16 11:54:42 +01:00
1af9b0b1f1
refactor(ui_kit): make resolve private and dotter child a widget 2023-02-16 10:23:48 +01:00
109 changed files with 4685 additions and 537 deletions

View File

@ -20,12 +20,12 @@ name: default
steps:
- name: quality-check
image: git.wyatt-studio.fr/wyatt-foss/flutter-melos:2.9.0
image: git.wyatt-studio.fr/wyatt-foss/flutter-melos:2.9.0-1
commands:
- melos run quality-check
- melos run publish:validate
- name: publish
image: git.wyatt-studio.fr/wyatt-foss/flutter-melos:2.9.0
image: git.wyatt-studio.fr/wyatt-foss/flutter-melos:2.9.0-1
commands:
- melos run publish:validate

View File

@ -0,0 +1,9 @@
targets:
$default:
builders:
# 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:
generate_for:
# Example glob for only the Dart files under `lib/models`
- lib/**/*.dart
- example/lib/**/*.dart

View File

@ -14,7 +14,7 @@
// 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 'enums/control_state.dart';
export 'enums/enums.dart';
export 'extensions/build_context_extensions.dart';
export 'extensions/string_extension.dart';
export 'mixins/copy_with_mixin.dart';

View File

@ -0,0 +1,18 @@
// 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 './control_state.dart';
export './status_state.dart';

View File

@ -0,0 +1,22 @@
// 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/>.
enum StatusState {
initial,
success,
loading,
error;
}

View File

@ -15,10 +15,11 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/text_wrapper.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
extension StringExtension on String? {
TextWrapper? wrap({TextStyle? style, List<Color>? gradient}) => this != null
? TextWrapper(this!, style: style, gradient: gradient)
: null;
TextWrapper? wrap({TextStyle? style, MultiColor? gradientColors}) =>
this != null
? TextWrapper(this!, style: style, gradientColors: gradientColors)
: null;
}

View File

@ -23,32 +23,54 @@ class MultiColor {
final List<Color>? _colors;
final Color? _color;
Color get color {
if (_color != null) {
return _color!;
}
if (_colors?.isNotEmpty ?? false) {
return _colors!.first;
}
throw IndexError.withLength(
0,
_colors?.length ?? 0,
message: '_color is not defined or _colors is empty.',
);
}
Color get color => _color != null
? _color!
: _colors?.isNotEmpty ?? false
? _colors!.first
: throw IndexError.withLength(
0,
_colors?.length ?? 0,
message: '_color is not defined or _colors is empty.',
);
List<Color> get colors => _colors ?? [];
bool get isGradient =>
(_colors?.isNotEmpty ?? false) && (_colors?.length ?? 0) > 1;
bool get isGradient => (_colors?.length ?? 0) > 1;
bool get isColor => _color != null || isGradient;
static MultiColor? lerp(MultiColor? a, MultiColor? b, double t) {
if (a == null && b == null) {
return null;
}
if (b == null) {
} else if (a == null) {
return b;
} else if (b == null) {
return a;
}
if (a.isColor && b.isColor) {
return MultiColor.single(Color.lerp(a.color, b.color, t));
} else if (a.isColor && b.isGradient) {
return MultiColor(
b.colors
.map((e) => Color.lerp(a.color, e, t))
.whereType<Color>()
.toList(),
);
} else if (a.isGradient && b.isColor) {
return MultiColor(
a.colors
.map((e) => Color.lerp(b.color, e, t))
.whereType<Color>()
.toList(),
);
} else if (a.isGradient && b.isGradient) {
final colors = List<Color>.empty(growable: true);
for (int i = 0; i < a.colors.length; i++) {
final lerpColor = Color.lerp(a.colors[i], b.colors[i], t);
if (lerpColor != null) {
colors.add(lerpColor);
}
}
}
return b;
}

View File

@ -15,17 +15,22 @@
// 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';
/// Wraps [String] and [TextStyle] into one object that can be
/// a [Text] or a [RichText].
class TextWrapper {
const TextWrapper(
this.text, {
this.style,
this.gradient,
this.gradientColors,
});
factory TextWrapper.text(String text) => TextWrapper(text);
const TextWrapper.text(this.text)
: style = null,
gradientColors = null;
final String text;
final TextStyle? style;
final List<Color>? gradient;
final MultiColor? gradientColors;
}

View File

@ -15,6 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
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,59 +31,59 @@ 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<S, T, E> {
abstract class ThemeResolver<S extends ThemeStyle<S>, T, E> {
/// {@macro theme_resolver}
const ThemeResolver();
S? Function(
BuildContext context,
S defaultValue,
T themeExtension, {
E? extra,
}) get computeExtensionValueFn;
S? Function(BuildContext context, {E? extra}) get customStyleFn;
/// Compute default value from Flutter Theme or with hardcoded values.
S computeDefaultValue(BuildContext context, {E? extra});
/// Compute values from the extension if found
S? computeExtensionValue(
S? computeExtensionValueFn(
BuildContext context,
S defaultValue, {
T themeExtension, {
E? extra,
});
/// Compute values from the extension if found
S? _computeExtensionValue(
BuildContext context, {
E? extra,
}) {
final themeExtension = findExtension(context);
final themeExtension = Theme.of(context).extension<T>();
if (themeExtension != null) {
return computeExtensionValueFn(
context,
defaultValue,
themeExtension,
extra: extra,
);
}
return defaultValue;
return null;
}
/// Compute custom value
S? computeCustomValue(
BuildContext context,
S previousPhaseValue, {
S? _computeCustomValue(
BuildContext context, {
E? extra,
}) {
final customStyle = customStyleFn(context, extra: extra);
final customStyle = customStyleFn(
context,
extra: extra,
);
if (customStyle != null) {
return customStyle;
}
return previousPhaseValue;
return null;
}
T? findExtension(BuildContext context) => Theme.of(context).extension<T>();
/// 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;
style =
style.mergeWith(_computeExtensionValue(context, extra: extra)) ?? style;
style =
style.mergeWith(_computeCustomValue(context, extra: extra)) ?? style;
return style;
}
}

View File

@ -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<dynamic, dynamic, dynamic>? themeResolver;
}

View File

@ -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<T> {
abstract class ButtonStyle<T> extends ThemeStyle<T> {
const ButtonStyle({
this.radius,
this.padding,

View File

@ -22,6 +22,8 @@ abstract class $FileSelectionButtonComponentCWProxy {
FileSelectionButtonComponent invalidStyle(ButtonStyle<dynamic>? invalidStyle);
FileSelectionButtonComponent onPressed(
void Function(ControlState)? onPressed);
FileSelectionButtonComponent themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
FileSelectionButtonComponent key(Key? key);
FileSelectionButtonComponent call({
MainAxisSize? mainAxisSize,
@ -36,6 +38,7 @@ abstract class $FileSelectionButtonComponentCWProxy {
ButtonStyle<dynamic>? selectedStyle,
ButtonStyle<dynamic>? invalidStyle,
void Function(ControlState)? onPressed,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key,
});
}

View File

@ -20,7 +20,6 @@ import 'package:copy_with_extension/copy_with_extension.dart';
import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
part 'file_selection_button_style.g.dart';
@CopyWith()
@ -37,6 +36,31 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
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 +105,8 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
///
/// Default to `TextTheme.labelSmall`
final TextStyle? subTitle;
@override
FileSelectionButtonStyle mergeWith(FileSelectionButtonStyle? other) =>
FileSelectionButtonStyle.merge(this, other)!;
}

View File

@ -17,6 +17,8 @@ abstract class $FlatButtonComponentCWProxy {
FlatButtonComponent focusedStyle(ButtonStyle<dynamic>? focusedStyle);
FlatButtonComponent tappedStyle(ButtonStyle<dynamic>? tappedStyle);
FlatButtonComponent onPressed(void Function(ControlState)? onPressed);
FlatButtonComponent themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
FlatButtonComponent key(Key? key);
FlatButtonComponent call({
MainAxisSize? mainAxisSize,
@ -29,6 +31,7 @@ abstract class $FlatButtonComponentCWProxy {
ButtonStyle<dynamic>? focusedStyle,
ButtonStyle<dynamic>? tappedStyle,
void Function(ControlState)? onPressed,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key,
});
}

View File

@ -20,7 +20,6 @@ import 'package:copy_with_extension/copy_with_extension.dart';
import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
part 'flat_button_style.g.dart';
@CopyWith()
@ -36,6 +35,30 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
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 +99,6 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
final TextStyle? label;
@override
String toString() =>
'FlatButtonStyle(label: $label), inherited: ${super.toString()}';
FlatButtonStyle mergeWith(FlatButtonStyle? other) =>
FlatButtonStyle.merge(this, other)!;
}

View File

@ -14,6 +14,8 @@ abstract class $SimpleIconButtonComponentCWProxy {
SimpleIconButtonComponent focusedStyle(ButtonStyle<dynamic>? focusedStyle);
SimpleIconButtonComponent tappedStyle(ButtonStyle<dynamic>? tappedStyle);
SimpleIconButtonComponent onPressed(void Function(ControlState)? onPressed);
SimpleIconButtonComponent themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
SimpleIconButtonComponent key(Key? key);
SimpleIconButtonComponent call({
Icon? icon,
@ -23,6 +25,7 @@ abstract class $SimpleIconButtonComponentCWProxy {
ButtonStyle<dynamic>? focusedStyle,
ButtonStyle<dynamic>? tappedStyle,
void Function(ControlState)? onPressed,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key,
});
}

View File

@ -20,7 +20,6 @@ import 'package:copy_with_extension/copy_with_extension.dart';
import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
part 'simple_icon_button_style.g.dart';
@CopyWith()
@ -36,6 +35,30 @@ class SimpleIconButtonStyle extends ButtonStyle<SimpleIconButtonStyle> {
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 +97,8 @@ class SimpleIconButtonStyle extends ButtonStyle<SimpleIconButtonStyle> {
///
/// Default to `context.buttonTheme.height`
final double? dimension;
@override
SimpleIconButtonStyle mergeWith(SimpleIconButtonStyle? other) =>
SimpleIconButtonStyle.merge(this, other)!;
}

View File

@ -17,6 +17,8 @@ abstract class $SymbolButtonComponentCWProxy {
SymbolButtonComponent tappedStyle(ButtonStyle<dynamic>? tappedStyle);
SymbolButtonComponent selectedStyle(ButtonStyle<dynamic>? selectedStyle);
SymbolButtonComponent onPressed(void Function(ControlState)? onPressed);
SymbolButtonComponent themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
SymbolButtonComponent key(Key? key);
SymbolButtonComponent call({
MainAxisSize? mainAxisSize,
@ -29,6 +31,7 @@ abstract class $SymbolButtonComponentCWProxy {
ButtonStyle<dynamic>? tappedStyle,
ButtonStyle<dynamic>? selectedStyle,
void Function(ControlState)? onPressed,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key,
});
}

View File

@ -20,7 +20,6 @@ import 'package:copy_with_extension/copy_with_extension.dart';
import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
part 'symbol_button_style.g.dart';
@CopyWith()
@ -37,6 +36,31 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
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 +105,8 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
///
/// Default to `context.buttonTheme.height`
final double? dimension;
@override
SymbolButtonStyle mergeWith(SymbolButtonStyle? other) =>
SymbolButtonStyle.merge(this, other)!;
}

View File

@ -15,7 +15,11 @@
// 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/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<dynamic, dynamic, dynamic>? themeResolver;
}

View File

@ -20,4 +20,9 @@ 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 './loading_widget_component.dart';
export './rich_text_builder/rich_text_builder.dart';
export './text_inputs/text_inputs.dart';
export './theme_style.dart';

View File

@ -0,0 +1,50 @@
// 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/component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
part 'loader_component.g.dart';
@ComponentProxyExtension()
abstract class LoaderComponent extends Component
with CopyWithMixin<$LoaderComponentCWProxy> {
const LoaderComponent({
this.colors,
this.radius,
this.stroke,
this.duration,
this.flip,
super.themeResolver,
super.key,
});
/// Gradient colors from start to end.
final MultiColor? colors;
/// Loader radius
final double? radius;
/// Loader stroke width
final double? stroke;
/// Animation duration
final Duration? duration;
/// Flip the animation
final bool? flip;
}

View File

@ -0,0 +1,27 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'loader_component.dart';
// **************************************************************************
// ComponentProxyGenerator
// **************************************************************************
abstract class $LoaderComponentCWProxy {
LoaderComponent colors(MultiColor? colors);
LoaderComponent radius(double? radius);
LoaderComponent stroke(double? stroke);
LoaderComponent duration(Duration? duration);
LoaderComponent flip(bool? flip);
LoaderComponent themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
LoaderComponent key(Key? key);
LoaderComponent call({
MultiColor? colors,
double? radius,
double? stroke,
Duration? duration,
bool? flip,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key,
});
}

View File

@ -0,0 +1,75 @@
// 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:copy_with_extension/copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
part 'loader_style.g.dart';
@CopyWith()
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
String toString() => 'LoaderStyle($colors, $stroke)';
}

View File

@ -0,0 +1,67 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'loader_style.dart';
// **************************************************************************
// CopyWithGenerator
// **************************************************************************
abstract class _$LoaderStyleCWProxy {
LoaderStyle colors(MultiColor? colors);
LoaderStyle stroke(double? stroke);
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `LoaderStyle(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
///
/// Usage
/// ```dart
/// LoaderStyle(...).copyWith(id: 12, name: "My name")
/// ````
LoaderStyle call({
MultiColor? colors,
double? stroke,
});
}
/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfLoaderStyle.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfLoaderStyle.copyWith.fieldName(...)`
class _$LoaderStyleCWProxyImpl implements _$LoaderStyleCWProxy {
const _$LoaderStyleCWProxyImpl(this._value);
final LoaderStyle _value;
@override
LoaderStyle colors(MultiColor? colors) => this(colors: colors);
@override
LoaderStyle stroke(double? stroke) => this(stroke: stroke);
@override
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `LoaderStyle(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
///
/// Usage
/// ```dart
/// LoaderStyle(...).copyWith(id: 12, name: "My name")
/// ````
LoaderStyle call({
Object? colors = const $CopyWithPlaceholder(),
Object? stroke = const $CopyWithPlaceholder(),
}) {
return LoaderStyle(
colors: colors == const $CopyWithPlaceholder()
? _value.colors
// ignore: cast_nullable_to_non_nullable
: colors as MultiColor?,
stroke: stroke == const $CopyWithPlaceholder()
? _value.stroke
// ignore: cast_nullable_to_non_nullable
: stroke as double?,
);
}
}
extension $LoaderStyleCopyWith on LoaderStyle {
/// Returns a callable class that can be used as follows: `instanceOfLoaderStyle.copyWith(...)` or like so:`instanceOfLoaderStyle.copyWith.fieldName(...)`.
// ignore: library_private_types_in_public_api
_$LoaderStyleCWProxy get copyWith => _$LoaderStyleCWProxyImpl(this);
}

View File

@ -0,0 +1,120 @@
// 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';
class RichTextStyleParameter {
const RichTextStyleParameter(
this.defaultStyle,
this.definedStyle,
this.styleName,
);
final TextStyle defaultStyle;
final Map<String, TextStyle> definedStyle;
final String? styleName;
TextStyle get style {
if (definedStyle.containsKey(styleName)) {
return definedStyle[styleName]!;
}
return defaultStyle;
}
RichTextStyleParameter copyWith({
TextStyle? defaultStyle,
Map<String, TextStyle>? definedStyle,
String? styleName,
}) =>
RichTextStyleParameter(
defaultStyle ?? this.defaultStyle,
definedStyle ?? this.definedStyle,
styleName ?? this.styleName,
);
}
class RichTextNode {
RichTextNode(this.nodes);
final List<RichTextNode> nodes;
static RichTextNode from(
String content,
RegExp regex,
RichTextStyleParameter styleParameter,
) {
final matches = regex.allMatches(content);
if (matches.isNotEmpty) {
// match found -> construct node with leaf/nodes
final List<RichTextNode> nodes = [];
for (var i = 0; i < matches.length; i++) {
final previousMatch = i > 0 ? matches.elementAt(i - 1) : null;
final currentMatch = matches.elementAt(i);
// non match before
final nonMatchBefore = (previousMatch != null)
? content.substring(previousMatch.end, currentMatch.start)
: content.substring(0, currentMatch.start);
nodes
..add(RichTextNode.from(nonMatchBefore, regex, styleParameter))
// match
..add(
RichTextNode.from(
currentMatch.group(2)!,
regex,
styleParameter.copyWith(styleName: currentMatch.group(1)),
),
);
}
// non match after
final nonMatchAfter = content.substring(matches.last.end);
nodes.add(RichTextNode.from(nonMatchAfter, regex, styleParameter));
return RichTextNode(nodes);
} else {
// match not found -> construct leaf
return RichTextLeaf(styleParameter.style, content);
}
}
InlineSpan toInlineSpan(RichTextParser parser) {
final children = <InlineSpan>[];
for (final node in nodes) {
children.add(node.toInlineSpan(parser));
}
return TextSpan(children: children);
}
}
class RichTextLeaf extends RichTextNode {
RichTextLeaf(this.style, this.content) : super([]);
final TextStyle style;
final String content;
@override
InlineSpan toInlineSpan(RichTextParser parser) =>
parser.nodeBuilder.call(content, style);
}
class RichTextParser {
const RichTextParser({required this.nodeBuilder});
factory RichTextParser.defaultBuilder() => RichTextParser(
nodeBuilder: (content, style) => TextSpan(
text: content,
style: style,
),
);
final InlineSpan Function(String content, TextStyle style) nodeBuilder;
}

View File

@ -0,0 +1,19 @@
// 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 'parser.dart';
export 'rich_text_builder_component.dart';
export 'rich_text_builder_style.dart';

View File

@ -0,0 +1,56 @@
// 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/component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
part 'rich_text_builder_component.g.dart';
@ComponentProxyExtension()
abstract class RichTextBuilderComponent extends Component
with CopyWithMixin<$RichTextBuilderComponentCWProxy> {
const RichTextBuilderComponent({
this.text,
this.parser,
this.defaultStyle,
this.styles,
super.themeResolver,
super.key,
});
/// Full text
final String? text;
/// How to build InlineSpans
final RichTextParser? parser;
/// Default TextStyle used in this rich text component.
final TextStyle? defaultStyle;
/// Used styles in this rich text component.
///
/// e.g.
/// ```dart
/// styles = {'red': TextStyle(color: Colors.red)};
/// ```
/// will transform:
/// ```text
/// This text <red>is red</red.
/// ```
/// in "This text `is red`."
final Map<String, TextStyle>? styles;
}

View File

@ -0,0 +1,25 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'rich_text_builder_component.dart';
// **************************************************************************
// ComponentProxyGenerator
// **************************************************************************
abstract class $RichTextBuilderComponentCWProxy {
RichTextBuilderComponent text(String? text);
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

@ -0,0 +1,72 @@
// 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:copy_with_extension/copy_with_extension.dart';
import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
part 'rich_text_builder_style.g.dart';
@CopyWith()
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)!;
}

View File

@ -0,0 +1,71 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'rich_text_builder_style.dart';
// **************************************************************************
// CopyWithGenerator
// **************************************************************************
abstract class _$RichTextBuilderStyleCWProxy {
RichTextBuilderStyle defaultStyle(TextStyle? defaultStyle);
RichTextBuilderStyle styles(Map<String, TextStyle>? styles);
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `RichTextBuilderStyle(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
///
/// Usage
/// ```dart
/// RichTextBuilderStyle(...).copyWith(id: 12, name: "My name")
/// ````
RichTextBuilderStyle call({
TextStyle? defaultStyle,
Map<String, TextStyle>? styles,
});
}
/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfRichTextBuilderStyle.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfRichTextBuilderStyle.copyWith.fieldName(...)`
class _$RichTextBuilderStyleCWProxyImpl
implements _$RichTextBuilderStyleCWProxy {
const _$RichTextBuilderStyleCWProxyImpl(this._value);
final RichTextBuilderStyle _value;
@override
RichTextBuilderStyle defaultStyle(TextStyle? defaultStyle) =>
this(defaultStyle: defaultStyle);
@override
RichTextBuilderStyle styles(Map<String, TextStyle>? styles) =>
this(styles: styles);
@override
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `RichTextBuilderStyle(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
///
/// Usage
/// ```dart
/// RichTextBuilderStyle(...).copyWith(id: 12, name: "My name")
/// ````
RichTextBuilderStyle call({
Object? defaultStyle = const $CopyWithPlaceholder(),
Object? styles = const $CopyWithPlaceholder(),
}) {
return RichTextBuilderStyle(
defaultStyle: defaultStyle == const $CopyWithPlaceholder()
? _value.defaultStyle
// ignore: cast_nullable_to_non_nullable
: defaultStyle as TextStyle?,
styles: styles == const $CopyWithPlaceholder()
? _value.styles
// ignore: cast_nullable_to_non_nullable
: styles as Map<String, TextStyle>?,
);
}
}
extension $RichTextBuilderStyleCopyWith on RichTextBuilderStyle {
/// Returns a callable class that can be used as follows: `instanceOfRichTextBuilderStyle.copyWith(...)` or like so:`instanceOfRichTextBuilderStyle.copyWith.fieldName(...)`.
// ignore: library_private_types_in_public_api
_$RichTextBuilderStyleCWProxy get copyWith =>
_$RichTextBuilderStyleCWProxyImpl(this);
}

View File

@ -0,0 +1,173 @@
// 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:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
part 'text_input_component.g.dart';
@ComponentProxyExtension()
abstract class TextInputComponent extends Component
with CopyWithMixin<$TextInputComponentCWProxy> {
const TextInputComponent({
this.expand,
this.onError,
this.validator,
this.suffixText,
this.prefixText,
this.prefixIcon,
this.suffixIcon,
this.label,
this.hint,
this.normalStyle,
this.focusedStyle,
this.errorStyle,
this.disableStyle,
this.controller,
this.focusNode,
this.keyboardType,
this.smartDashesType,
this.smartQuotesType,
this.enableInteractiveSelection,
this.textInputAction,
this.textCapitalization,
this.style,
this.strutStyle,
this.textAlign,
this.textAlignVertical,
this.textDirection,
this.readOnly,
this.showCursor,
this.autofocus,
this.obscuringCharacter,
this.obscureText,
this.autocorrect,
this.enableSuggestions,
this.maxLines,
this.minLines,
this.expands,
this.maxLength,
this.maxLengthEnforcement,
this.onChanged,
this.onEditingComplete,
this.onSubmitted,
this.onAppPrivateCommand,
this.inputFormatters,
this.enabled,
this.cursorWidth,
this.cursorHeight,
this.cursorRadius,
this.cursorColor,
this.selectionHeightStyle,
this.selectionWidthStyle,
this.keyboardAppearance,
this.scrollPadding,
this.dragStartBehavior,
this.selectionControls,
this.onTap,
this.onTapOutside,
this.mouseCursor,
this.scrollController,
this.scrollPhysics,
this.autofillHints,
this.clipBehavior,
this.restorationId,
this.scribbleEnabled,
this.enableIMEPersonalizedLearning,
this.contextMenuBuilder,
this.spellCheckConfiguration,
this.magnifierConfiguration,
super.key,
});
final TextMagnifierConfiguration? magnifierConfiguration;
final TextEditingController? controller;
final FocusNode? focusNode;
final TextInputType? keyboardType;
final TextInputAction? textInputAction;
final TextCapitalization? textCapitalization;
final TextStyle? style;
final StrutStyle? strutStyle;
final TextAlign? textAlign;
final TextAlignVertical? textAlignVertical;
final TextDirection? textDirection;
final bool? autofocus;
final String? obscuringCharacter;
final bool? obscureText;
final bool? autocorrect;
final SmartDashesType? smartDashesType;
final SmartQuotesType? smartQuotesType;
final bool? enableSuggestions;
final int? maxLines;
final int? minLines;
final bool? expands;
final bool? readOnly;
final bool? showCursor;
final int? maxLength;
final MaxLengthEnforcement? maxLengthEnforcement;
final ValueChanged<String>? onChanged;
final VoidCallback? onEditingComplete;
final ValueChanged<String>? onSubmitted;
final AppPrivateCommandCallback? onAppPrivateCommand;
final List<TextInputFormatter>? inputFormatters;
final ValueNotifier<bool>? enabled;
final double? cursorWidth;
final double? cursorHeight;
final Radius? cursorRadius;
final Color? cursorColor;
final BoxHeightStyle? selectionHeightStyle;
final BoxWidthStyle? selectionWidthStyle;
final Brightness? keyboardAppearance;
final EdgeInsets? scrollPadding;
final bool? enableInteractiveSelection;
final TextSelectionControls? selectionControls;
final DragStartBehavior? dragStartBehavior;
final GestureTapCallback? onTap;
final TapRegionCallback? onTapOutside;
final MouseCursor? mouseCursor;
final ScrollPhysics? scrollPhysics;
final ScrollController? scrollController;
final Iterable<String>? autofillHints;
final Clip? clipBehavior;
final String? restorationId;
final bool? scribbleEnabled;
final bool? enableIMEPersonalizedLearning;
final EditableTextContextMenuBuilder? contextMenuBuilder;
final SpellCheckConfiguration? spellCheckConfiguration;
final bool Function(String)? validator;
final String? Function(String)? onError;
final TextInputStyle? normalStyle;
final TextInputStyle? focusedStyle;
final TextInputStyle? errorStyle;
final TextInputStyle? disableStyle;
final bool? expand;
final TextWrapper? label;
final TextWrapper? hint;
final TextWrapper? prefixText;
final TextWrapper? suffixText;
final Icon? prefixIcon;
final Icon? suffixIcon;
}

View File

@ -0,0 +1,157 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'text_input_component.dart';
// **************************************************************************
// ComponentProxyGenerator
// **************************************************************************
abstract class $TextInputComponentCWProxy {
TextInputComponent expand(bool? expand);
TextInputComponent onError(String Function(String)? onError);
TextInputComponent validator(bool Function(String)? validator);
TextInputComponent suffixText(TextWrapper? suffixText);
TextInputComponent prefixText(TextWrapper? prefixText);
TextInputComponent prefixIcon(Icon? prefixIcon);
TextInputComponent suffixIcon(Icon? suffixIcon);
TextInputComponent label(TextWrapper? label);
TextInputComponent hint(TextWrapper? hint);
TextInputComponent normalStyle(TextInputStyle? normalStyle);
TextInputComponent focusedStyle(TextInputStyle? focusedStyle);
TextInputComponent errorStyle(TextInputStyle? errorStyle);
TextInputComponent disableStyle(TextInputStyle? disableStyle);
TextInputComponent controller(TextEditingController? controller);
TextInputComponent focusNode(FocusNode? focusNode);
TextInputComponent keyboardType(TextInputType? keyboardType);
TextInputComponent smartDashesType(SmartDashesType? smartDashesType);
TextInputComponent smartQuotesType(SmartQuotesType? smartQuotesType);
TextInputComponent enableInteractiveSelection(
bool? enableInteractiveSelection);
TextInputComponent textInputAction(TextInputAction? textInputAction);
TextInputComponent textCapitalization(TextCapitalization? textCapitalization);
TextInputComponent style(TextStyle? style);
TextInputComponent strutStyle(StrutStyle? strutStyle);
TextInputComponent textAlign(TextAlign? textAlign);
TextInputComponent textAlignVertical(TextAlignVertical? textAlignVertical);
TextInputComponent textDirection(TextDirection? textDirection);
TextInputComponent readOnly(bool? readOnly);
TextInputComponent showCursor(bool? showCursor);
TextInputComponent autofocus(bool? autofocus);
TextInputComponent obscuringCharacter(String? obscuringCharacter);
TextInputComponent obscureText(bool? obscureText);
TextInputComponent autocorrect(bool? autocorrect);
TextInputComponent enableSuggestions(bool? enableSuggestions);
TextInputComponent maxLines(int? maxLines);
TextInputComponent minLines(int? minLines);
TextInputComponent expands(bool? expands);
TextInputComponent maxLength(int? maxLength);
TextInputComponent maxLengthEnforcement(
MaxLengthEnforcement? maxLengthEnforcement);
TextInputComponent onChanged(void Function(String)? onChanged);
TextInputComponent onEditingComplete(void Function()? onEditingComplete);
TextInputComponent onSubmitted(void Function(String)? onSubmitted);
TextInputComponent onAppPrivateCommand(
void Function(String, Map<String, dynamic>)? onAppPrivateCommand);
TextInputComponent inputFormatters(List<TextInputFormatter>? inputFormatters);
TextInputComponent enabled(ValueNotifier<bool>? enabled);
TextInputComponent cursorWidth(double? cursorWidth);
TextInputComponent cursorHeight(double? cursorHeight);
TextInputComponent cursorRadius(Radius? cursorRadius);
TextInputComponent cursorColor(Color? cursorColor);
TextInputComponent selectionHeightStyle(BoxHeightStyle? selectionHeightStyle);
TextInputComponent selectionWidthStyle(BoxWidthStyle? selectionWidthStyle);
TextInputComponent keyboardAppearance(Brightness? keyboardAppearance);
TextInputComponent scrollPadding(EdgeInsets? scrollPadding);
TextInputComponent dragStartBehavior(DragStartBehavior? dragStartBehavior);
TextInputComponent selectionControls(
TextSelectionControls? selectionControls);
TextInputComponent onTap(void Function()? onTap);
TextInputComponent onTapOutside(
void Function(PointerDownEvent)? onTapOutside);
TextInputComponent mouseCursor(MouseCursor? mouseCursor);
TextInputComponent scrollController(ScrollController? scrollController);
TextInputComponent scrollPhysics(ScrollPhysics? scrollPhysics);
TextInputComponent autofillHints(Iterable<String>? autofillHints);
TextInputComponent clipBehavior(Clip? clipBehavior);
TextInputComponent restorationId(String? restorationId);
TextInputComponent scribbleEnabled(bool? scribbleEnabled);
TextInputComponent enableIMEPersonalizedLearning(
bool? enableIMEPersonalizedLearning);
TextInputComponent contextMenuBuilder(
Widget Function(BuildContext, EditableTextState)? contextMenuBuilder);
TextInputComponent spellCheckConfiguration(
SpellCheckConfiguration? spellCheckConfiguration);
TextInputComponent magnifierConfiguration(
TextMagnifierConfiguration? magnifierConfiguration);
TextInputComponent key(Key? key);
TextInputComponent call({
bool? expand,
String Function(String)? onError,
bool Function(String)? validator,
TextWrapper? suffixText,
TextWrapper? prefixText,
Icon? prefixIcon,
Icon? suffixIcon,
TextWrapper? label,
TextWrapper? hint,
TextInputStyle? normalStyle,
TextInputStyle? focusedStyle,
TextInputStyle? errorStyle,
TextInputStyle? disableStyle,
TextEditingController? controller,
FocusNode? focusNode,
TextInputType? keyboardType,
SmartDashesType? smartDashesType,
SmartQuotesType? smartQuotesType,
bool? enableInteractiveSelection,
TextInputAction? textInputAction,
TextCapitalization? textCapitalization,
TextStyle? style,
StrutStyle? strutStyle,
TextAlign? textAlign,
TextAlignVertical? textAlignVertical,
TextDirection? textDirection,
bool? readOnly,
bool? showCursor,
bool? autofocus,
String? obscuringCharacter,
bool? obscureText,
bool? autocorrect,
bool? enableSuggestions,
int? maxLines,
int? minLines,
bool? expands,
int? maxLength,
MaxLengthEnforcement? maxLengthEnforcement,
void Function(String)? onChanged,
void Function()? onEditingComplete,
void Function(String)? onSubmitted,
void Function(String, Map<String, dynamic>)? onAppPrivateCommand,
List<TextInputFormatter>? inputFormatters,
ValueNotifier<bool>? enabled,
double? cursorWidth,
double? cursorHeight,
Radius? cursorRadius,
Color? cursorColor,
BoxHeightStyle? selectionHeightStyle,
BoxWidthStyle? selectionWidthStyle,
Brightness? keyboardAppearance,
EdgeInsets? scrollPadding,
DragStartBehavior? dragStartBehavior,
TextSelectionControls? selectionControls,
void Function()? onTap,
void Function(PointerDownEvent)? onTapOutside,
MouseCursor? mouseCursor,
ScrollController? scrollController,
ScrollPhysics? scrollPhysics,
Iterable<String>? autofillHints,
Clip? clipBehavior,
String? restorationId,
bool? scribbleEnabled,
bool? enableIMEPersonalizedLearning,
Widget Function(BuildContext, EditableTextState)? contextMenuBuilder,
SpellCheckConfiguration? spellCheckConfiguration,
TextMagnifierConfiguration? magnifierConfiguration,
Key? key,
});
}

View File

@ -0,0 +1,106 @@
// 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:copy_with_extension/copy_with_extension.dart';
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
part 'text_input_style.g.dart';
@CopyWith()
class TextInputStyle extends ThemeStyle<TextInputStyle> {
TextInputStyle({
this.labelStyle,
this.hintStyle,
this.backgroundColors,
this.borderColors,
this.boxShadow,
this.radius,
this.inputStyle,
this.iconColor,
this.prefixStyle,
this.prefixIconColor,
this.suffixStyle,
this.suffixIconColor,
});
final TextStyle? labelStyle;
final TextStyle? hintStyle;
final Color? iconColor;
final TextStyle? prefixStyle;
final Color? prefixIconColor;
final TextStyle? suffixStyle;
final Color? suffixIconColor;
final MultiColor? backgroundColors;
final MultiColor? borderColors;
final BoxShadow? boxShadow;
final BorderRadiusGeometry? radius;
final TextStyle? inputStyle;
static TextInputStyle? merge(TextInputStyle? a, TextInputStyle? b) {
if (b == null) {
return a?.copyWith();
}
if (a == null) {
return b.copyWith();
}
return a.copyWith(
labelStyle: b.labelStyle,
hintStyle: b.hintStyle,
backgroundColors: b.backgroundColors,
borderColors: b.borderColors,
boxShadow: b.boxShadow,
radius: b.radius,
inputStyle: b.inputStyle,
iconColor: b.iconColor,
prefixStyle: b.prefixStyle,
prefixIconColor: b.prefixIconColor,
suffixIconColor: b.suffixIconColor,
suffixStyle: b.suffixStyle,
);
}
static TextInputStyle? lerp(
TextInputStyle? a,
TextInputStyle? b,
double t,
) {
if (a == null || b == null) {
return null;
}
return b.copyWith(
labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t),
hintStyle: TextStyle.lerp(a.hintStyle, b.hintStyle, t),
backgroundColors:
MultiColor.lerp(a.backgroundColors, b.backgroundColors, t),
radius: BorderRadiusGeometry.lerp(a.radius, b.radius, t),
borderColors: MultiColor.lerp(a.borderColors, b.borderColors, t),
boxShadow: BoxShadow.lerp(a.boxShadow, b.boxShadow, t),
inputStyle: TextStyle.lerp(a.inputStyle, b.inputStyle, t),
prefixStyle: TextStyle.lerp(a.prefixStyle, b.prefixStyle, t),
suffixStyle: TextStyle.lerp(a.suffixStyle, b.suffixStyle, t),
prefixIconColor: Color.lerp(a.prefixIconColor, b.prefixIconColor, t),
suffixIconColor: Color.lerp(a.suffixIconColor, b.suffixIconColor, t),
iconColor: Color.lerp(a.iconColor, b.iconColor, t),
);
}
@override
TextInputStyle? mergeWith(TextInputStyle? other) =>
TextInputStyle.merge(this, other);
}

View File

@ -0,0 +1,185 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'text_input_style.dart';
// **************************************************************************
// CopyWithGenerator
// **************************************************************************
abstract class _$TextInputStyleCWProxy {
TextInputStyle labelStyle(TextStyle? labelStyle);
TextInputStyle hintStyle(TextStyle? hintStyle);
TextInputStyle backgroundColors(MultiColor? backgroundColors);
TextInputStyle borderColors(MultiColor? borderColors);
TextInputStyle boxShadow(BoxShadow? boxShadow);
TextInputStyle radius(BorderRadiusGeometry? radius);
TextInputStyle inputStyle(TextStyle? inputStyle);
TextInputStyle iconColor(Color? iconColor);
TextInputStyle prefixStyle(TextStyle? prefixStyle);
TextInputStyle prefixIconColor(Color? prefixIconColor);
TextInputStyle suffixStyle(TextStyle? suffixStyle);
TextInputStyle suffixIconColor(Color? suffixIconColor);
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `TextInputStyle(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
///
/// Usage
/// ```dart
/// TextInputStyle(...).copyWith(id: 12, name: "My name")
/// ````
TextInputStyle call({
TextStyle? labelStyle,
TextStyle? hintStyle,
MultiColor? backgroundColors,
MultiColor? borderColors,
BoxShadow? boxShadow,
BorderRadiusGeometry? radius,
TextStyle? inputStyle,
Color? iconColor,
TextStyle? prefixStyle,
Color? prefixIconColor,
TextStyle? suffixStyle,
Color? suffixIconColor,
});
}
/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfTextInputStyle.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfTextInputStyle.copyWith.fieldName(...)`
class _$TextInputStyleCWProxyImpl implements _$TextInputStyleCWProxy {
const _$TextInputStyleCWProxyImpl(this._value);
final TextInputStyle _value;
@override
TextInputStyle labelStyle(TextStyle? labelStyle) =>
this(labelStyle: labelStyle);
@override
TextInputStyle hintStyle(TextStyle? hintStyle) => this(hintStyle: hintStyle);
@override
TextInputStyle backgroundColors(MultiColor? backgroundColors) =>
this(backgroundColors: backgroundColors);
@override
TextInputStyle borderColors(MultiColor? borderColors) =>
this(borderColors: borderColors);
@override
TextInputStyle boxShadow(BoxShadow? boxShadow) => this(boxShadow: boxShadow);
@override
TextInputStyle radius(BorderRadiusGeometry? radius) => this(radius: radius);
@override
TextInputStyle inputStyle(TextStyle? inputStyle) =>
this(inputStyle: inputStyle);
@override
TextInputStyle iconColor(Color? iconColor) => this(iconColor: iconColor);
@override
TextInputStyle prefixStyle(TextStyle? prefixStyle) =>
this(prefixStyle: prefixStyle);
@override
TextInputStyle prefixIconColor(Color? prefixIconColor) =>
this(prefixIconColor: prefixIconColor);
@override
TextInputStyle suffixStyle(TextStyle? suffixStyle) =>
this(suffixStyle: suffixStyle);
@override
TextInputStyle suffixIconColor(Color? suffixIconColor) =>
this(suffixIconColor: suffixIconColor);
@override
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `TextInputStyle(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
///
/// Usage
/// ```dart
/// TextInputStyle(...).copyWith(id: 12, name: "My name")
/// ````
TextInputStyle call({
Object? labelStyle = const $CopyWithPlaceholder(),
Object? hintStyle = const $CopyWithPlaceholder(),
Object? backgroundColors = const $CopyWithPlaceholder(),
Object? borderColors = const $CopyWithPlaceholder(),
Object? boxShadow = const $CopyWithPlaceholder(),
Object? radius = const $CopyWithPlaceholder(),
Object? inputStyle = const $CopyWithPlaceholder(),
Object? iconColor = const $CopyWithPlaceholder(),
Object? prefixStyle = const $CopyWithPlaceholder(),
Object? prefixIconColor = const $CopyWithPlaceholder(),
Object? suffixStyle = const $CopyWithPlaceholder(),
Object? suffixIconColor = const $CopyWithPlaceholder(),
}) {
return TextInputStyle(
labelStyle: labelStyle == const $CopyWithPlaceholder()
? _value.labelStyle
// ignore: cast_nullable_to_non_nullable
: labelStyle as TextStyle?,
hintStyle: hintStyle == const $CopyWithPlaceholder()
? _value.hintStyle
// ignore: cast_nullable_to_non_nullable
: hintStyle as TextStyle?,
backgroundColors: backgroundColors == const $CopyWithPlaceholder()
? _value.backgroundColors
// ignore: cast_nullable_to_non_nullable
: backgroundColors as MultiColor?,
borderColors: borderColors == const $CopyWithPlaceholder()
? _value.borderColors
// ignore: cast_nullable_to_non_nullable
: borderColors as MultiColor?,
boxShadow: boxShadow == const $CopyWithPlaceholder()
? _value.boxShadow
// ignore: cast_nullable_to_non_nullable
: boxShadow as BoxShadow?,
radius: radius == const $CopyWithPlaceholder()
? _value.radius
// ignore: cast_nullable_to_non_nullable
: radius as BorderRadiusGeometry?,
inputStyle: inputStyle == const $CopyWithPlaceholder()
? _value.inputStyle
// ignore: cast_nullable_to_non_nullable
: inputStyle as TextStyle?,
iconColor: iconColor == const $CopyWithPlaceholder()
? _value.iconColor
// ignore: cast_nullable_to_non_nullable
: iconColor as Color?,
prefixStyle: prefixStyle == const $CopyWithPlaceholder()
? _value.prefixStyle
// ignore: cast_nullable_to_non_nullable
: prefixStyle as TextStyle?,
prefixIconColor: prefixIconColor == const $CopyWithPlaceholder()
? _value.prefixIconColor
// ignore: cast_nullable_to_non_nullable
: prefixIconColor as Color?,
suffixStyle: suffixStyle == const $CopyWithPlaceholder()
? _value.suffixStyle
// ignore: cast_nullable_to_non_nullable
: suffixStyle as TextStyle?,
suffixIconColor: suffixIconColor == const $CopyWithPlaceholder()
? _value.suffixIconColor
// ignore: cast_nullable_to_non_nullable
: suffixIconColor as Color?,
);
}
}
extension $TextInputStyleCopyWith on TextInputStyle {
/// Returns a callable class that can be used as follows: `instanceOfTextInputStyle.copyWith(...)` or like so:`instanceOfTextInputStyle.copyWith.fieldName(...)`.
// ignore: library_private_types_in_public_api
_$TextInputStyleCWProxy get copyWith => _$TextInputStyleCWProxyImpl(this);
}

View File

@ -0,0 +1,18 @@
// 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 './text_input_component.dart';
export './text_input_style.dart';

View File

@ -14,13 +14,9 @@
// 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:flutter_bloc/flutter_bloc.dart';
abstract class ThemeStyle<T> {
const ThemeStyle();
mixin ExportBloc<T extends StateStreamableSource<Object?>> {
T get bloc;
Widget exportBloc({required Widget child}) => BlocProvider<T>.value(
value: bloc,
child: child,
);
/// Merges non-null `other` attributes in `this` and returns a copy.
T? mergeWith(T? other);
}

View File

@ -9,8 +9,8 @@ environment:
sdk: ">=2.17.0 <3.0.0"
dependencies:
copy_with_extension: ^5.0.0
flutter: { sdk: flutter }
copy_with_extension: ^5.0.0
wyatt_component_copy_with_extension:
git:
url: ssh://git@git.wyatt-studio.fr:993/Wyatt-FOSS/wyatt-packages.git

View File

@ -0,0 +1,8 @@
targets:
$default:
builders:
# 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:
generate_for:
# Example glob for only the Dart files under `lib/models`
- lib/**/*.dart

View File

@ -20,10 +20,14 @@ import 'package:wyatt_ui_kit_example/buttons/file_selection_button/file_selectio
import 'package:wyatt_ui_kit_example/buttons/flat_button/flat_buttons.dart';
import 'package:wyatt_ui_kit_example/buttons/simple_icon_button/simple_icon_buttons.dart';
import 'package:wyatt_ui_kit_example/buttons/symbol_button/symbol_buttons.dart';
import 'package:wyatt_ui_kit_example/demo_page.dart';
class Buttons extends StatelessWidget {
class Buttons extends DemoPage {
const Buttons({super.key});
@override
String get title => 'Buttons';
@override
Widget build(BuildContext context) => ListView(
cacheExtent: 1000,
@ -31,7 +35,7 @@ class Buttons extends StatelessWidget {
const Gap(20),
Align(
child: Text(
'Buttons',
title,
style: Theme.of(context).textTheme.titleLarge,
),
),

View File

@ -31,8 +31,14 @@ class FlatButtons extends StatelessWidget {
),
const Gap(20),
Center(
/// You can overwrite global textstyle of the label with [label],
/// but if you only want to override the color/gradient of the text
/// in a particular case you can override the style that will
/// be merge during the build.
child: FlatButton(
label: const TextWrapper('Voir notre savoir faire'),
label: const TextWrapper(
'Voir notre savoir faire',
),
),
),
const Gap(20),

View File

@ -4,10 +4,14 @@ import 'package:wyatt_ui_kit_example/cards/information_card/information_cards.da
import 'package:wyatt_ui_kit_example/cards/portfolio_card/portfolio_cards.dart';
import 'package:wyatt_ui_kit_example/cards/quote_card/quote_cards.dart';
import 'package:wyatt_ui_kit_example/cards/skill_card/skill_cards.dart';
import 'package:wyatt_ui_kit_example/demo_page.dart';
class Cards extends StatelessWidget {
class Cards extends DemoPage {
const Cards({super.key});
@override
String get title => 'Cards';
@override
Widget build(BuildContext context) => ListView(
cacheExtent: 1000,
@ -15,7 +19,7 @@ class Cards extends StatelessWidget {
const Gap(20),
Align(
child: Text(
'Cards',
title,
style: Theme.of(context).textTheme.titleLarge,
),
),

View File

@ -18,13 +18,13 @@ class InformationCards extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
InformationCard(
icons: const [
const InformationCard(
icons: [
FlutterLogo(size: 60),
FlutterLogo(size: 60),
FlutterLogo(size: 60),
],
title: const TextWrapper('Flutter'),
title: TextWrapper('Flutter'),
subtitle: TextWrapper.text('One single code base.'),
body: TextWrapper.text(
'Cupidatat reprehenderit aliqua eiusmod Lorem. '
@ -58,9 +58,9 @@ class InformationCards extends StatelessWidget {
FlutterLogo(size: 60),
],
title: 'Flutter'.wrap(
gradient: [Colors.blue, Colors.green],
gradientColors: const MultiColor([Colors.blue, Colors.green]),
),
subtitle: TextWrapper.text('One single code base.'),
subtitle: const TextWrapper.text('One single code base.'),
body: 'Cupidatat reprehenderit aliqua eiusmod Lorem. '
'Qui ipsum id ea ea nulla labore aute ullamco aute '
'quis elit ut amet velit. Incididunt fugiat proident '
@ -86,8 +86,8 @@ class InformationCards extends StatelessWidget {
FlutterLogo(size: 60),
],
axis: Axis.horizontal,
title: TextWrapper.text('Flutter'),
subtitle: TextWrapper.text('One single code base.'),
title: const TextWrapper.text('Flutter'),
subtitle: const TextWrapper.text('One single code base.'),
body: 'Cupidatat reprehenderit aliqua eiusmod Lorem. '
'Qui ipsum id ea ea nulla labore aute ullamco aute '
'quis elit ut amet velit. Incididunt fugiat proident '
@ -100,10 +100,10 @@ class InformationCards extends StatelessWidget {
'magna cupidatat Lorem nulla cupidatat voluptate '
'irure ex reprehenderit.'
.wrap(
gradient: [
gradientColors: const MultiColor([
Colors.red,
Colors.orange,
],
]),
),
),
const Gap(20),
@ -123,14 +123,14 @@ class InformationCards extends StatelessWidget {
FlutterLogo(size: 60),
],
axis: Axis.horizontal,
title: TextWrapper.text('Flutter'),
title: const TextWrapper.text('Flutter'),
subtitle: 'One single code base.'.wrap(
// gradient: [Colors.blue, Colors.green],
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
body: TextWrapper.text(
body: const TextWrapper.text(
'Cupidatat reprehenderit aliqua eiusmod Lorem. '
'Qui ipsum id ea ea nulla labore aute ullamco aute '
'quis elit ut amet velit. Incididunt fugiat proident '

View File

@ -128,10 +128,10 @@ class PortfolioCards extends StatelessWidget {
),
projectName: const TextWrapper(
'Flutter',
gradient: [
gradientColors: MultiColor([
Colors.blue,
Colors.green,
],
]),
),
subtitle: const TextWrapper('Mobile / Web / Macos.'),
description: const TextWrapper(

View File

@ -49,7 +49,12 @@ class QuoteCards extends StatelessWidget {
'quis elit ut amet velit. Incididunt fugiat proident '
'proident deserunt tempor Lorem cillum qui do '
'ullamco Lorem magna ipsum. Ullamco cupidatat velit '
.wrap(gradient: [Colors.red, Colors.orange]),
.wrap(
gradientColors: const MultiColor([
Colors.red,
Colors.orange,
]),
),
avatar: const FlutterLogo(
size: 40,
),

View File

@ -44,7 +44,7 @@ class SkillCards extends StatelessWidget {
'proident deserunt tempor Lorem cillum qui do '
'ullamco Lorem magna ipsum. Ullamco cupidatat velit '
.wrap(),
skills: [
skills: const [
TextWrapper.text('Firebase'),
TextWrapper.text(
'Qui ipsum id ea ea nulla labore aute ullamco aute ',
@ -62,11 +62,14 @@ class SkillCards extends StatelessWidget {
'proident deserunt tempor Lorem cillum qui do '
'ullamco Lorem magna ipsum. Ullamco cupidatat velit '
.wrap(),
skills: [
skills: const [
TextWrapper.text('Firebase'),
const TextWrapper(
TextWrapper(
'Qui ipsum id ea ea nulla labore aute ullamco aute ',
gradient: [Colors.red, Colors.orange],
gradientColors: MultiColor([
Colors.red,
Colors.orange,
]),
),
TextWrapper.text('Firebase'),
TextWrapper.text('Firebase'),

View File

@ -0,0 +1,23 @@
// 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';
abstract class DemoPage extends StatelessWidget {
const DemoPage({super.key});
String get title;
}

View File

@ -3,6 +3,10 @@ import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_kit_example/buttons/buttons.dart';
import 'package:wyatt_ui_kit_example/cards/cards.dart';
import 'package:wyatt_ui_kit_example/demo_page.dart';
import 'package:wyatt_ui_kit_example/loaders/loaders.dart';
import 'package:wyatt_ui_kit_example/rich_text_builders/rich_text_builders.dart';
import 'package:wyatt_ui_kit_example/text_input/text_inputs.dart';
import 'package:wyatt_ui_kit_example/theme/themes.dart';
const String title = 'Wyatt UIKit Example';
@ -17,7 +21,14 @@ class Home extends StatefulWidget {
}
class _HomeState extends State<Home> {
final List<Widget> pages = const [Cards(), Buttons()];
// Simply add your demo page here.
final List<DemoPage> pages = const [
Cards(),
Buttons(),
Loaders(),
RichTextBuilders(),
TextInputs(),
];
int currentIndex = 0;
@ -27,35 +38,34 @@ class _HomeState extends State<Home> {
super.initState();
}
List<Widget> _drawerTiles(BuildContext context) {
final tiles = <Widget>[];
for (var i = 0; i < pages.length; i++) {
final page = pages[i];
tiles.add(
ListTile(
title: Text(page.title),
onTap: () {
if (currentIndex != i) {
setState(() {
currentIndex = i;
});
Navigator.pop(context);
}
},
),
);
}
return tiles;
}
@override
Widget build(BuildContext context) => Scaffold(
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
ListTile(
title: const Text('Cards'),
onTap: () {
if (currentIndex != 0) {
setState(() {
currentIndex = 0;
});
Navigator.pop(context);
}
},
),
ListTile(
title: const Text('Buttons'),
onTap: () {
if (currentIndex != 1) {
setState(() {
currentIndex = 1;
});
Navigator.pop(context);
}
},
),
],
children: _drawerTiles(context),
),
),
appBar: AppBar(

View File

@ -0,0 +1,68 @@
// 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:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/demo_page.dart';
import 'package:wyatt_ui_kit_example/theme/constants.dart';
class Loaders extends DemoPage {
const Loaders({super.key});
@override
String get title => 'Loaders';
@override
Widget build(BuildContext context) => ListView(
cacheExtent: 1000,
children: [
const Gap(20),
Align(
child: Text(
title,
style: Theme.of(context).textTheme.titleLarge,
),
),
const Gap(20),
const Loader(
radius: 57,
),
const Gap(20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Loader(
stroke: 5,
),
Gap(20),
Loader(
colors: MultiColor([Constants.green2, Constants.white]),
stroke: 5,
),
Gap(20),
Loader(
colors: MultiColor([Constants.red2, Constants.white]),
stroke: 5,
),
],
),
const Gap(20),
],
);
}

View File

@ -0,0 +1,63 @@
// 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:gap/gap.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/demo_page.dart';
class RichTextBuilders extends DemoPage {
const RichTextBuilders({super.key});
@override
String get title => 'RichTextBuilders';
@override
Widget build(BuildContext context) => ListView(
cacheExtent: 1000,
children: [
const Gap(20),
Align(
child: Text(
title,
style: Theme.of(context).textTheme.titleLarge,
),
),
const Gap(20),
const Padding(
padding: EdgeInsets.all(8),
child: RichTextBuilder(
text: '''
Innovation, Expertise et Accompagnement...
Notre agence de développement Wyatt Studio met tout en oeuvre pour vous aider à <gradient-blue>concrétiser vos idées</gradient-blue> de solutions informatiques et mobiles.
Vous aussi, comme beaucoup dautres <gradient-blue>agences ou startups</gradient-blue>, faites nous confiance pour la réalisation de votre projet dès maintenant !
''',
),
),
const Gap(20),
const Padding(
padding: EdgeInsets.all(8),
child: RichTextBuilder(
text: '''
Je peux être <blue>bleu</blue>, ou même <gradient-red>rouge en dégradé</gradient-red>. À vrai dire <green>je peux</green> être <gradient-blue>un peu</gradient-blue> n'importe quelle couleur.
''',
),
),
const Gap(20),
],
);
}

View File

@ -0,0 +1,140 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/demo_page.dart';
class TextInputs extends DemoPage {
const TextInputs({super.key});
@override
Widget build(BuildContext context) => const TextInputsCore();
@override
String get title => 'Text Inputs';
}
class TextInputsCore extends StatefulWidget {
const TextInputsCore({super.key});
@override
State<TextInputsCore> createState() => _TextInputsCoreState();
}
class _TextInputsCoreState extends State<TextInputsCore> {
final _formKey = GlobalKey<FormState>();
final _controller = TextEditingController();
final _focusNode = FocusNode();
final _formKey2 = GlobalKey<FormState>();
final _controller2 = TextEditingController();
final _focusNode2 = FocusNode();
final _formKey3 = GlobalKey<FormState>();
final _controller3 = TextEditingController();
final _focusNode3 = FocusNode();
final _formKey4 = GlobalKey<FormState>();
final _controller4 = TextEditingController();
final _focusNode4 = FocusNode();
final _formKey5 = GlobalKey<FormState>();
final _controller5 = TextEditingController();
final _focusNode5 = FocusNode();
final _formKey6 = GlobalKey<FormState>();
final _controller6 = TextEditingController();
final _focusNode6 = FocusNode();
final ValueNotifier<bool> _enable = ValueNotifier(true);
@override
void initState() {
super.initState();
Future.delayed(const Duration(milliseconds: 500), () {
setState(() {
_enable.value = false;
});
});
}
@override
Widget build(BuildContext context) => Form(
child: ListView(
cacheExtent: 1000,
children: [
const Gap(20),
Align(
child: Text(
'Text inputs',
style: Theme.of(context).textTheme.titleLarge,
),
),
const Gap(20),
TextInput(
key: _formKey6,
controller: _controller6,
focusNode: _focusNode6,
label: 'Nom / Prénom'.wrap(),
onError: (value) => 'Erreur : ${value.length} > 5.',
validator: (value) => value.length > 5,
),
const Gap(20),
TextInput(
key: _formKey,
enabled: _enable,
controller: _controller,
focusNode: _focusNode,
label: 'Nom / Prénom'.wrap(),
onError: (value) => 'Erreur : ${value.length} > 5.',
validator: (value) => value.length > 5,
),
const Gap(20),
TextInput(
key: _formKey2,
controller: _controller2,
focusNode: _focusNode2,
maxLines: 3,
onError: (value) => 'Erreur : ${value.length} > 5.',
validator: (value) => value.length > 5,
onChanged: (value) {},
),
const Gap(20),
TextInput(
key: _formKey3,
controller: _controller3,
focusNode: _focusNode3,
expand: false,
label: 'Nom / Prénom'.wrap(),
onError: (value) => 'Erreur : ${value.length} > 5.',
validator: (value) => value.length > 5,
onChanged: (value) {},
),
const Gap(20),
TextInput(
key: _formKey4,
expand: false,
controller: _controller4,
focusNode: _focusNode4,
label: 'Nom / Prénom'.wrap(),
maxLines: 3,
onError: (value) => 'Erreur : ${value.length} > 5.',
validator: (value) => value.length > 5,
onChanged: (value) {},
),
const Gap(20),
TextInput(
key: _formKey5,
prefixIcon: const Icon(Icons.architecture),
suffixIcon: const Icon(Icons.architecture),
controller: _controller5,
focusNode: _focusNode5,
label: 'Nom / Prénom'.wrap(),
onError: (value) => 'Erreur : ${value.length} > 5.',
validator: (value) => value.length > 5,
),
const Gap(20),
],
),
);
}

View File

@ -0,0 +1,127 @@
// 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:google_fonts/google_fonts.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class CardTheme extends CardThemeExtension {
const CardTheme({
super.backgroundColors,
super.body,
super.borderColors,
super.secondaryBackgroundColor,
super.shadowColor,
super.subtitle,
super.title,
});
factory CardTheme.light() => CardTheme(
backgroundColors: const MultiColor.single(Color(0xFFF6F6F6)),
secondaryBackgroundColor: Colors.white,
borderColors: const MultiColor([
Color(0xFFDDE0E3),
Color(0xFFCACCD4),
]),
title: GoogleFonts.montserrat(
fontSize: 24,
fontWeight: FontWeight.w500,
color: const Color(0xFF24262A),
),
subtitle: GoogleFonts.montserrat(
fontSize: 15,
fontWeight: FontWeight.w300,
color: const Color(0xFF24262A),
),
body: GoogleFonts.montserrat(
fontSize: 12,
fontWeight: FontWeight.w300,
height: 1.7,
color: const Color(0xFF24262A),
),
);
factory CardTheme.dark() => CardTheme(
backgroundColors:
MultiColor.single(const Color(0xFFFFFFFF).withOpacity(0.04)),
secondaryBackgroundColor: const Color(0xFFFFFFFF).withOpacity(0.04),
borderColors: const MultiColor([
Color(0xFF60656A),
Color(0xFF383C40),
]),
title: GoogleFonts.montserrat(
fontSize: 24,
fontWeight: FontWeight.w500,
color: const Color(0xFFFFFFFF),
),
subtitle: GoogleFonts.montserrat(
fontSize: 15,
fontWeight: FontWeight.w300,
color: const Color(0xFFFFFFFF),
),
body: GoogleFonts.montserrat(
fontSize: 12,
fontWeight: FontWeight.w300,
height: 1.7,
color: const Color(0xFFFFFFFF),
),
);
@override
ThemeExtension<CardThemeExtension> copyWith({
MultiColor? backgroundColors,
Color? secondaryBackgroundColor,
MultiColor? borderColors,
BoxShadow? shadowColor,
TextStyle? body,
TextStyle? title,
TextStyle? subtitle,
}) =>
CardTheme(
backgroundColors: backgroundColors ?? this.backgroundColors,
secondaryBackgroundColor:
secondaryBackgroundColor ?? this.secondaryBackgroundColor,
borderColors: borderColors ?? this.borderColors,
shadowColor: shadowColor ?? this.shadowColor,
body: body ?? this.body,
title: title ?? this.title,
subtitle: subtitle ?? this.subtitle,
);
@override
ThemeExtension<CardThemeExtension> lerp(
covariant ThemeExtension<CardThemeExtension>? other,
double t,
) {
if (other is! CardTheme) {
return this;
}
return CardTheme(
backgroundColors: other.backgroundColors,
secondaryBackgroundColor: Color.lerp(
secondaryBackgroundColor,
other.secondaryBackgroundColor,
t,
),
borderColors: other.borderColors,
shadowColor: BoxShadow.lerp(shadowColor, other.shadowColor, t),
body: TextStyle.lerp(body, other.body, t),
title: TextStyle.lerp(title, other.title, t),
subtitle: TextStyle.lerp(subtitle, other.subtitle, t),
);
}
}

View File

@ -0,0 +1,63 @@
// 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:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/theme/constants.dart';
class LoaderTheme extends LoaderThemeExtension {
const LoaderTheme({
super.colors,
super.stroke,
});
factory LoaderTheme.light() => const LoaderTheme(
colors: MultiColor([Constants.blue1, Constants.white]),
stroke: 15,
);
factory LoaderTheme.dark() => const LoaderTheme(
colors: MultiColor([Constants.blue2, Constants.grey2]),
stroke: 15,
);
@override
ThemeExtension<LoaderThemeExtension> copyWith({
MultiColor? colors,
double? stroke,
}) =>
LoaderTheme(
colors: colors ?? this.colors,
stroke: stroke ?? this.stroke,
);
@override
ThemeExtension<LoaderThemeExtension> lerp(
covariant ThemeExtension<LoaderThemeExtension>? other,
double t,
) {
if (other is! LoaderTheme) {
return this;
}
return LoaderTheme(
colors: MultiColor.lerp(colors, other.colors, t),
stroke: lerpDouble(stroke, other.stroke, t),
);
}
}

View File

@ -0,0 +1,120 @@
// 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:google_fonts/google_fonts.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/theme/constants.dart';
final Map<String, TextStyle> _styles = {
'gradient-blue': GradientTextStyle.from(
GoogleFonts.montserrat(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Constants.blue1,
height: 1.8,
),
const MultiColor(Constants.blueGradient),
),
'gradient-red': GradientTextStyle.from(
GoogleFonts.montserrat(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Constants.red1,
height: 1.8,
),
const MultiColor(Constants.redGradient),
),
'gradient-green': GradientTextStyle.from(
GoogleFonts.montserrat(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Constants.green1,
height: 1.8,
),
const MultiColor(Constants.greenGradient),
),
'blue': GoogleFonts.montserrat(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Constants.blue1,
height: 1.8,
),
'red': GoogleFonts.montserrat(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Constants.red1,
height: 1.8,
),
'green': GoogleFonts.montserrat(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Constants.green1,
height: 1.8,
),
};
class RichTextBuilderTheme extends RichTextBuilderThemeExtension {
const RichTextBuilderTheme({
super.defaultStyle,
super.styles,
});
factory RichTextBuilderTheme.light() => RichTextBuilderTheme(
defaultStyle: GoogleFonts.montserrat(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Constants.grey3,
height: 1.8,
),
styles: _styles,
);
factory RichTextBuilderTheme.dark() => RichTextBuilderTheme(
defaultStyle: GoogleFonts.montserrat(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Constants.white,
height: 1.8,
),
styles: _styles,
);
@override
ThemeExtension<RichTextBuilderThemeExtension> copyWith({
TextStyle? defaultStyle,
Map<String, TextStyle>? styles,
}) =>
RichTextBuilderTheme(
defaultStyle: defaultStyle ?? this.defaultStyle,
styles: styles ?? this.styles,
);
@override
ThemeExtension<RichTextBuilderThemeExtension> lerp(
covariant ThemeExtension<RichTextBuilderThemeExtension>? other,
double t,
) {
if (other is! RichTextBuilderTheme) {
return this;
}
return RichTextBuilderTheme(
defaultStyle: TextStyle.lerp(defaultStyle, other.defaultStyle, t),
styles: styles,
);
}
}

View File

@ -0,0 +1,181 @@
// 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:google_fonts/google_fonts.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class TextInputTheme extends TextInputThemeExtension {
const TextInputTheme({
super.normalStyle,
super.focusedStyle,
super.disableStyle,
super.errorStyle,
});
factory TextInputTheme.light() => TextInputTheme(
normalStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const MultiColor([
Color.fromRGBO(221, 224, 227, 1),
Color.fromRGBO(202, 204, 212, 1),
]),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(55, 65, 81, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(55, 65, 81, 1),
),
),
focusedStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const MultiColor([
Color.fromRGBO(60, 125, 251, 1),
Color.fromRGBO(68, 109, 244, 1),
]),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(55, 65, 81, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(55, 65, 81, 1),
),
),
errorStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const MultiColor([
Color.fromRGBO(251, 94, 60, 1),
Color.fromRGBO(244, 68, 100, 1),
]),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(244, 68, 100, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(55, 65, 81, 1),
),
),
disableStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors:
const MultiColor.single(Color.fromRGBO(229, 231, 235, 1)),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(156, 163, 175, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(156, 163, 175, 1),
),
),
);
factory TextInputTheme.dark() => TextInputTheme(
normalStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const MultiColor.single(
Color.fromRGBO(96, 101, 106, 1),
),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(204, 204, 204, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(255, 255, 255, 1),
),
),
focusedStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const MultiColor([
Color.fromRGBO(60, 125, 251, 1),
Color.fromRGBO(68, 109, 244, 1),
]),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(204, 204, 204, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(255, 255, 255, 1),
),
),
errorStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const MultiColor([
Color.fromRGBO(251, 94, 60, 1),
Color.fromRGBO(244, 68, 100, 1),
]),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(244, 68, 100, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(255, 255, 255, 1),
),
),
disableStyle: TextInputStyle(
radius: BorderRadius.circular(12),
borderColors: const MultiColor.single(
Color.fromRGBO(96, 101, 106, 1),
),
labelStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(96, 101, 106, 1),
),
inputStyle: GoogleFonts.montserrat(
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(255, 255, 255, 1),
),
),
);
@override
ThemeExtension<TextInputThemeExtension> lerp(
covariant ThemeExtension<TextInputThemeExtension>? other,
double t,
) {
if (other is! TextInputTheme) {
return this;
}
return TextInputTheme(
normalStyle: TextInputStyle.lerp(normalStyle, other.normalStyle, t),
focusedStyle: TextInputStyle.lerp(focusedStyle, other.focusedStyle, t),
disableStyle: TextInputStyle.lerp(disableStyle, other.disableStyle, t),
errorStyle: TextInputStyle.lerp(errorStyle, other.errorStyle, t),
);
}
@override
ThemeExtension<TextInputThemeExtension> copyWith({
TextInputStyle? normalStyle,
TextInputStyle? focusedStyle,
TextInputStyle? disableStyle,
TextInputStyle? errorStyle,
}) =>
TextInputTheme(
normalStyle: normalStyle ?? this.normalStyle,
focusedStyle: focusedStyle ?? this.focusedStyle,
disableStyle: disableStyle ?? this.disableStyle,
errorStyle: errorStyle ?? this.errorStyle,
);
}

View File

@ -15,13 +15,16 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' hide CardTheme;
import 'package:google_fonts/google_fonts.dart';
import 'package:wyatt_ui_kit_example/theme/card_theme.dart';
import 'package:wyatt_ui_kit_example/theme/file_selection_button_theme.dart';
import 'package:wyatt_ui_kit_example/theme/flat_button_theme.dart';
import 'package:wyatt_ui_kit_example/theme/loader_theme.dart';
import 'package:wyatt_ui_kit_example/theme/rich_text_builder_theme.dart';
import 'package:wyatt_ui_kit_example/theme/simple_icon_button_theme.dart';
import 'package:wyatt_ui_kit_example/theme/symbol_button_theme.dart';
import 'package:wyatt_ui_kit_example/theme_extension.dart';
import 'package:wyatt_ui_kit_example/theme/text_input_theme.dart';
/// Easely switch between Material and Studio themes.
abstract class Themes {
@ -67,46 +70,28 @@ abstract class Themes {
static ThemeData get studioLight => materialLight.copyWith(
appBarTheme: AppBarTheme(
foregroundColor: const Color.fromRGBO(36, 38, 42, 1),
backgroundColor: Colors.white,
foregroundColor: const Color(0xFF24262A),
backgroundColor: const Color(0xFFFFFFFF),
titleTextStyle: GoogleFonts.montserrat(
fontSize: 18,
fontWeight: FontWeight.w500,
color: const Color.fromRGBO(36, 38, 42, 1),
color: const Color(0xFF24262A),
),
),
scaffoldBackgroundColor: Colors.white,
extensions: <ThemeExtension<dynamic>>[
CustomCardColorExtension(
backgroundColors: const [
Color.fromRGBO(246, 246, 246, 1),
],
secondaryBackgroundColors: Colors.white,
borderColor: const [
Color.fromRGBO(221, 224, 227, 1),
Color.fromRGBO(202, 204, 212, 1),
],
title: GoogleFonts.montserrat(
fontSize: 24,
fontWeight: FontWeight.w500,
color: const Color.fromRGBO(36, 38, 42, 1),
),
subtitle: GoogleFonts.montserrat(
fontSize: 15,
fontWeight: FontWeight.w300,
color: const Color.fromRGBO(36, 38, 42, 1),
),
body: GoogleFonts.montserrat(
fontSize: 12,
fontWeight: FontWeight.w300,
height: 1.7,
color: const Color.fromRGBO(36, 38, 42, 1),
),
),
// Cards
CardTheme.light(),
// Buttons
FlatButtonTheme.light(),
SymbolButtonTheme.light(),
SimpleIconButtonTheme.light(),
FileSelectionButtonTheme.light(),
// Loader
LoaderTheme.light(),
// Rich Text
RichTextBuilderTheme.light(),
TextInputTheme.light(),
],
);
@ -114,46 +99,31 @@ abstract class Themes {
static ThemeData get studioDark => materialDark.copyWith(
appBarTheme: AppBarTheme(
foregroundColor: Colors.white,
backgroundColor: const Color.fromRGBO(56, 60, 64, 1),
foregroundColor: const Color(0xFFFFFFFF),
backgroundColor: const Color(0xFF383C40),
titleTextStyle: GoogleFonts.montserrat(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Colors.white,
color: const Color(0xFFFFFFFF),
),
),
scaffoldBackgroundColor: const Color.fromRGBO(56, 60, 64, 1),
drawerTheme: const DrawerThemeData(
backgroundColor: Color(0xFF383C40),
),
scaffoldBackgroundColor: const Color(0xFF383C40),
extensions: <ThemeExtension<dynamic>>[
CustomCardColorExtension(
secondaryBackgroundColors: Colors.white.withOpacity(0.04),
backgroundColors: [
Colors.white.withOpacity(0.04),
],
borderColor: const [
Color.fromRGBO(96, 101, 106, 1),
Color.fromRGBO(56, 60, 64, 1),
],
title: GoogleFonts.montserrat(
fontSize: 24,
fontWeight: FontWeight.w500,
color: Colors.white,
),
subtitle: GoogleFonts.montserrat(
fontSize: 15,
fontWeight: FontWeight.w300,
color: Colors.white,
),
body: GoogleFonts.montserrat(
fontSize: 12,
fontWeight: FontWeight.w300,
height: 1.7,
color: Colors.white,
),
),
// Cards
CardTheme.dark(),
// Buttons
FlatButtonTheme.dark(),
SymbolButtonTheme.dark(),
SimpleIconButtonTheme.dark(),
FileSelectionButtonTheme.dark(),
// Loader
LoaderTheme.dark(),
// Rich Text
RichTextBuilderTheme.dark(),
TextInputTheme.dark(),
],
);
}

View File

@ -1,54 +0,0 @@
import 'package:flutter/material.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart' as ui_kit;
class CustomCardColorExtension extends ui_kit.CardThemeExtension {
const CustomCardColorExtension({
super.backgroundColors,
super.secondaryBackgroundColors,
super.borderColor,
super.shadowColor,
super.body,
super.title,
super.subtitle,
});
@override
CustomCardColorExtension copyWith({
List<Color>? backgroundColors,
Color? secondaryBackgroundColors,
List<Color>? borderColor,
BoxShadow? shadowColor,
TextStyle? body,
TextStyle? title,
TextStyle? subtitle,
}) =>
CustomCardColorExtension(
backgroundColors: backgroundColors ?? this.backgroundColors,
secondaryBackgroundColors:
secondaryBackgroundColors ?? this.secondaryBackgroundColors,
borderColor: borderColor ?? this.borderColor,
body: body ?? this.body,
title: title ?? this.title,
subtitle: subtitle ?? this.subtitle,
);
@override
ThemeExtension<ui_kit.CardThemeExtension> lerp(
covariant ThemeExtension<ui_kit.CardThemeExtension>? other,
double t,
) {
if (other is! CustomCardColorExtension) {
return this;
}
return CustomCardColorExtension(
secondaryBackgroundColors: Color.lerp(
secondaryBackgroundColors,
other.secondaryBackgroundColors,
t,
),
body: TextStyle.lerp(body, other.body, t),
title: TextStyle.lerp(title, other.title, t),
subtitle: TextStyle.lerp(subtitle, other.subtitle, t),
);
}
}

View File

@ -0,0 +1,36 @@
// 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:flutter_bloc/flutter_bloc.dart';
class ExportableBloc<T extends StateStreamableSource<Object?>>
extends StatelessWidget {
const ExportableBloc({
required this.bloc,
required this.child,
super.key,
});
final T bloc;
final Widget child;
@override
Widget build(BuildContext context) => BlocProvider<T>.value(
value: bloc,
child: child,
);
}

View File

@ -0,0 +1,49 @@
// 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:dotted_border/dotted_border.dart';
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
class DotterBorderChild extends StatelessWidget {
const DotterBorderChild({
required this.style,
required this.child,
super.key,
});
final FileSelectionButtonStyle style;
final Widget child;
@override
Widget build(BuildContext context) {
if (style.borderColors != null && style.stroke != null) {
return DottedBorder(
padding: EdgeInsets.zero,
dashPattern: const [5, 5],
strokeWidth: style.stroke!,
color: style.borderColors!.color,
borderType: BorderType.RRect,
radius:
style.radius?.resolve(TextDirection.ltr).bottomLeft ?? Radius.zero,
strokeCap: StrokeCap.square,
child: child,
);
} else {
return child;
}
}
}

View File

@ -18,15 +18,15 @@ import 'package:flutter/material.dart' hide ButtonStyle;
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/buttons/cubit/invalid_button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/exportable_bloc.dart';
import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/file_selection_button_screen.dart';
import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/core/mixin/export_bloc_mixin.dart';
part 'file_selection_button.g.dart';
@ComponentCopyWithExtension()
class FileSelectionButton extends FileSelectionButtonComponent
with $FileSelectionButtonCWMixin, ExportBloc<InvalidButtonCubit> {
with $FileSelectionButtonCWMixin {
FileSelectionButton({
super.leading,
super.title,
@ -46,7 +46,6 @@ class FileSelectionButton extends FileSelectionButtonComponent
final InvalidButtonCubit _cubit = InvalidButtonCubit();
@override
InvalidButtonCubit get bloc => _cubit;
@override
@ -82,7 +81,8 @@ class FileSelectionButton extends FileSelectionButtonComponent
super.themeResolver as FileSelectionButtonThemeResolver?;
@override
Widget build(BuildContext context) => exportBloc(
Widget build(BuildContext context) => ExportableBloc(
bloc: _cubit,
child: FileSelectionButtonScreen(
leading: leading,
title: title,

View File

@ -14,7 +14,6 @@
// 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:dotted_border/dotted_border.dart';
import 'package:flutter/material.dart' hide ButtonStyle;
import 'package:flutter/services.dart';
import 'package:gap/gap.dart';
@ -22,9 +21,9 @@ import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/cubit/invalid_button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/dotter_border_child.dart';
import 'package:wyatt_ui_kit/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart';
import 'package:wyatt_ui_kit/src/core/helpers/linear_gradient_helper.dart';
class FileSelectionButtonScreen
extends CubitScreen<InvalidButtonCubit, ButtonState> {
@ -65,43 +64,9 @@ class FileSelectionButtonScreen
InvalidButtonCubit create(BuildContext context) => InvalidButtonCubit();
/// Negotiate the theme to get a complete style.
FileSelectionButtonStyle resolve(BuildContext context, ButtonState state) {
FileSelectionButtonStyle _resolve(BuildContext context, ButtonState state) {
final FileSelectionButtonThemeResolver resolver = themeResolver ??
FileSelectionButtonThemeResolver(
computeExtensionValueFn: (
context,
defaultValue,
themeExtension, {
extra,
}) {
FileSelectionButtonStyle? style = defaultValue;
switch (extra?.state) {
case ControlState.disabled:
style = themeExtension.disabledStyle;
break;
case ControlState.focused:
style = themeExtension.focusedStyle;
break;
case ControlState.hovered:
style = themeExtension.hoveredStyle;
break;
case ControlState.tapped:
style = themeExtension.tappedStyle;
break;
case ControlState.normal:
case null:
style = themeExtension.normalStyle;
break;
}
if (extra?.isSelected ?? false) {
style = themeExtension.selectedStyle;
}
if (extra?.isInvalid ?? false) {
style = themeExtension.invalidStyle;
}
return style;
},
customStyleFn: (context, {extra}) {
FileSelectionButtonStyle? style;
switch (extra?.state) {
@ -135,31 +100,9 @@ class FileSelectionButtonScreen
return resolver.negotiate(context, extra: state);
}
Widget _border(
BuildContext context,
FileSelectionButtonStyle style,
Widget child,
) {
if (style.borderColors != null && style.stroke != null) {
return DottedBorder(
padding: EdgeInsets.zero,
dashPattern: const [5, 5],
strokeWidth: style.stroke!,
color: style.borderColors!.color,
borderType: BorderType.RRect,
radius:
style.radius?.resolve(TextDirection.ltr).bottomLeft ?? Radius.zero,
strokeCap: StrokeCap.square,
child: child,
);
} else {
return child;
}
}
@override
Widget onBuild(BuildContext context, ButtonState state) {
final style = resolve(context, state);
final style = _resolve(context, state);
return Focus(
onFocusChange: (hasFocus) =>
@ -192,10 +135,9 @@ class FileSelectionButtonScreen
onPressed?.call(state.state);
bloc(context).onClickUpOut();
},
child: _border(
context,
style,
DecoratedBox(
child: DotterBorderChild(
style: style,
child: DecoratedBox(
decoration: BoxDecoration(
color: style.backgroundColors?.color,
// if no gradient colors => no default value
@ -221,7 +163,7 @@ class FileSelectionButtonScreen
children: [
if (leading != null) ...[
leading ?? const SizedBox.shrink(),
Gap((style.padding?.horizontal ?? 10)/2),
Gap((style.padding?.horizontal ?? 10) / 2),
],
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -237,19 +179,13 @@ class FileSelectionButtonScreen
/// buttonStyle.foregroundColor.colors ??
/// null
///
/// More infos in `negociate()` method
/// More infos in `ThemeResolver` class
if (title != null) ...[
Text(
title!.text,
style: title!.style ?? style.title,
).toGradient(
LinearGradientHelper.fromNullableColors(
title?.gradient ??
((style.foregroundColors?.isGradient ??
false)
? style.foregroundColors?.colors
: null),
),
gradientColors: style.foregroundColors,
),
],
@ -263,20 +199,14 @@ class FileSelectionButtonScreen
/// buttonStyle.foregroundColor.colors ??
/// null
///
/// More infos in `negociate()` method
/// More infos in `ThemeResolver` class
if (subTitle != null) ...[
const Gap(5),
Text(
subTitle!.text,
style: subTitle!.style ?? style.subTitle,
).toGradient(
LinearGradientHelper.fromNullableColors(
subTitle?.gradient ??
((style.foregroundColors?.isGradient ??
false)
? style.foregroundColors?.colors
: null),
),
gradientColors: style.foregroundColors,
),
],
],

View File

@ -22,7 +22,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class FileSelectionButtonThemeResolver extends ThemeResolver<
FileSelectionButtonStyle, FileSelectionButtonThemeExtension, ButtonState> {
const FileSelectionButtonThemeResolver({
required this.computeExtensionValueFn,
required this.customStyleFn,
});
@ -57,8 +56,7 @@ class FileSelectionButtonThemeResolver extends ThemeResolver<
}
if (extra?.isInvalid ?? false) {
backgroundColor =
MultiColor.single(context.colorScheme.error);
backgroundColor = MultiColor.single(context.colorScheme.error);
}
return FileSelectionButtonStyle(
@ -73,17 +71,43 @@ class FileSelectionButtonThemeResolver extends ThemeResolver<
);
}
@override
final FileSelectionButtonStyle? Function(
BuildContext context,
FileSelectionButtonStyle defaultValue,
FileSelectionButtonThemeExtension themeExtension, {
ButtonState? extra,
}) computeExtensionValueFn;
@override
final FileSelectionButtonStyle? Function(
BuildContext context, {
ButtonState? extra,
}) customStyleFn;
@override
FileSelectionButtonStyle? computeExtensionValueFn(
BuildContext context,
FileSelectionButtonThemeExtension themeExtension, {
ButtonState? extra,
}) {
FileSelectionButtonStyle? style;
switch (extra?.state) {
case ControlState.disabled:
style = themeExtension.disabledStyle;
break;
case ControlState.focused:
style = themeExtension.focusedStyle;
break;
case ControlState.hovered:
style = themeExtension.hoveredStyle;
break;
case ControlState.tapped:
style = themeExtension.tappedStyle;
break;
case ControlState.normal:
case null:
style = themeExtension.normalStyle;
break;
}
if (extra?.isSelected ?? false) {
style = themeExtension.selectedStyle;
}
if (extra?.isInvalid ?? false) {
style = themeExtension.invalidStyle;
}
return style;
}
}

View File

@ -18,15 +18,14 @@ import 'package:flutter/material.dart' hide ButtonStyle;
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/buttons/cubit/button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/exportable_bloc.dart';
import 'package:wyatt_ui_kit/src/components/buttons/flat_button/flat_button_screen.dart';
import 'package:wyatt_ui_kit/src/components/buttons/flat_button/flat_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/core/mixin/export_bloc_mixin.dart';
part 'flat_button.g.dart';
@ComponentCopyWithExtension()
class FlatButton extends FlatButtonComponent
with $FlatButtonCWMixin, ExportBloc<ButtonCubit> {
class FlatButton extends FlatButtonComponent with $FlatButtonCWMixin {
FlatButton({
super.prefix,
super.suffix,
@ -44,7 +43,6 @@ class FlatButton extends FlatButtonComponent
final ButtonCubit _cubit = ButtonCubit();
@override
ButtonCubit get bloc => _cubit;
@override
@ -67,7 +65,8 @@ class FlatButton extends FlatButtonComponent
super.themeResolver as FlatButtonThemeResolver?;
@override
Widget build(BuildContext context) => exportBloc(
Widget build(BuildContext context) => ExportableBloc(
bloc: _cubit,
child: FlatButtonScreen(
prefix: prefix,
suffix: suffix,

View File

@ -23,7 +23,6 @@ import 'package:wyatt_ui_kit/src/components/buttons/cubit/button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/flat_button/flat_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_box_border.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart';
import 'package:wyatt_ui_kit/src/core/helpers/linear_gradient_helper.dart';
class FlatButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
const FlatButtonScreen({
@ -59,29 +58,9 @@ class FlatButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
ButtonCubit create(BuildContext context) => ButtonCubit();
/// Negotiate the theme to get a complete style.
FlatButtonStyle resolve(BuildContext context, ControlState state) {
FlatButtonStyle _resolve(BuildContext context, ControlState state) {
final FlatButtonThemeResolver resolver = themeResolver ??
FlatButtonThemeResolver(
computeExtensionValueFn: (
context,
defaultValue,
themeExtension, {
extra,
}) {
switch (extra) {
case ControlState.disabled:
return themeExtension.disabledStyle;
case ControlState.focused:
return themeExtension.focusedStyle;
case ControlState.hovered:
return themeExtension.hoveredStyle;
case ControlState.tapped:
return themeExtension.tappedStyle;
case ControlState.normal:
case null:
return themeExtension.normalStyle;
}
},
customStyleFn: (context, {extra}) {
switch (extra) {
case ControlState.disabled:
@ -103,7 +82,7 @@ class FlatButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
@override
Widget onBuild(BuildContext context, ButtonState state) {
final style = resolve(context, state.state);
final style = _resolve(context, state.state);
return Focus(
onFocusChange: (hasFocus) =>
@ -142,7 +121,7 @@ class FlatButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
// If no border color => no default value
border: (style.borderColors != null && style.stroke != null)
? (style.borderColors?.isGradient ?? false)
? GradientBoxBorder(
? CustomGradientBoxBorder(
gradient: LinearGradient(
colors: style.borderColors!.colors,
),
@ -204,12 +183,7 @@ class FlatButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
label!.text,
style: label!.style ?? style.label,
).toGradient(
LinearGradientHelper.fromNullableColors(
label?.gradient ??
((style.foregroundColors?.isGradient ?? false)
? style.foregroundColors?.colors
: null),
),
gradientColors: style.foregroundColors,
)
],
Gap(style.padding?.vertical ?? 10),

View File

@ -21,7 +21,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class FlatButtonThemeResolver extends ThemeResolver<FlatButtonStyle,
FlatButtonThemeExtension, ControlState> {
const FlatButtonThemeResolver({
required this.computeExtensionValueFn,
required this.customStyleFn,
});
@ -70,13 +69,28 @@ class FlatButtonThemeResolver extends ThemeResolver<FlatButtonStyle,
@override
final FlatButtonStyle? Function(
BuildContext context,
FlatButtonStyle defaultValue,
FlatButtonThemeExtension themeExtension, {
BuildContext context, {
ControlState? extra,
}) computeExtensionValueFn;
}) customStyleFn;
@override
final FlatButtonStyle? Function(BuildContext context, {ControlState? extra})
customStyleFn;
FlatButtonStyle? computeExtensionValueFn(
BuildContext context,
FlatButtonThemeExtension themeExtension, {
ControlState? extra,
}) {
switch (extra) {
case ControlState.disabled:
return themeExtension.disabledStyle;
case ControlState.focused:
return themeExtension.focusedStyle;
case ControlState.hovered:
return themeExtension.hoveredStyle;
case ControlState.tapped:
return themeExtension.tappedStyle;
case ControlState.normal:
case null:
return themeExtension.normalStyle;
}
}
}

View File

@ -18,15 +18,15 @@ import 'package:flutter/material.dart' hide ButtonStyle;
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/buttons/cubit/button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/exportable_bloc.dart';
import 'package:wyatt_ui_kit/src/components/buttons/simple_icon_button/simple_icon_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/components/buttons/simple_icon_button/simple_icon_screen.dart';
import 'package:wyatt_ui_kit/src/core/mixin/export_bloc_mixin.dart';
part 'simple_icon_button.g.dart';
@ComponentCopyWithExtension()
class SimpleIconButton extends SimpleIconButtonComponent
with $SimpleIconButtonCWMixin, ExportBloc<ButtonCubit> {
with $SimpleIconButtonCWMixin {
SimpleIconButton({
super.icon,
super.disabledStyle,
@ -41,7 +41,6 @@ class SimpleIconButton extends SimpleIconButtonComponent
final ButtonCubit _cubit = ButtonCubit();
@override
ButtonCubit get bloc => _cubit;
@override
@ -69,7 +68,8 @@ class SimpleIconButton extends SimpleIconButtonComponent
super.themeResolver as SimpleIconButtonThemeResolver?;
@override
Widget build(BuildContext context) => exportBloc(
Widget build(BuildContext context) => ExportableBloc(
bloc: _cubit,
child: SimpleIconButtonScreen(
icon: icon,
disabledStyle: disabledStyle,

View File

@ -21,7 +21,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class SimpleIconButtonThemeResolver extends ThemeResolver<SimpleIconButtonStyle,
SimpleIconButtonThemeExtension, ControlState> {
const SimpleIconButtonThemeResolver({
required this.computeExtensionValueFn,
required this.customStyleFn,
});
@ -66,17 +65,30 @@ class SimpleIconButtonThemeResolver extends ThemeResolver<SimpleIconButtonStyle,
);
}
@override
final SimpleIconButtonStyle? Function(
BuildContext context,
SimpleIconButtonStyle defaultValue,
SimpleIconButtonThemeExtension themeExtension, {
ControlState? extra,
}) computeExtensionValueFn;
@override
final SimpleIconButtonStyle? Function(
BuildContext context, {
ControlState? extra,
}) customStyleFn;
@override
SimpleIconButtonStyle? computeExtensionValueFn(
BuildContext context,
SimpleIconButtonThemeExtension themeExtension, {
ControlState? extra,
}) {
switch (extra) {
case ControlState.disabled:
return themeExtension.disabledStyle;
case ControlState.focused:
return themeExtension.focusedStyle;
case ControlState.hovered:
return themeExtension.hoveredStyle;
case ControlState.tapped:
return themeExtension.tappedStyle;
case ControlState.normal:
case null:
return themeExtension.normalStyle;
}
}
}

View File

@ -52,29 +52,9 @@ class SimpleIconButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
ButtonCubit create(BuildContext context) => ButtonCubit();
/// Negotiate the theme to get a complete style.
SimpleIconButtonStyle resolve(BuildContext context, ControlState state) {
SimpleIconButtonStyle _resolve(BuildContext context, ControlState state) {
final SimpleIconButtonThemeResolver resolver = themeResolver ??
SimpleIconButtonThemeResolver(
computeExtensionValueFn: (
context,
defaultValue,
themeExtension, {
extra,
}) {
switch (extra) {
case ControlState.disabled:
return themeExtension.disabledStyle;
case ControlState.focused:
return themeExtension.focusedStyle;
case ControlState.hovered:
return themeExtension.hoveredStyle;
case ControlState.tapped:
return themeExtension.tappedStyle;
case ControlState.normal:
case null:
return themeExtension.normalStyle;
}
},
customStyleFn: (context, {extra}) {
switch (extra) {
case ControlState.disabled:
@ -96,7 +76,7 @@ class SimpleIconButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
@override
Widget onBuild(BuildContext context, ButtonState state) {
final style = resolve(context, state.state);
final style = _resolve(context, state.state);
return Focus(
onFocusChange: (hasFocus) =>
@ -140,7 +120,7 @@ class SimpleIconButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
// If no border color => no default value
border: (style.borderColors != null && style.stroke != null)
? (style.borderColors?.isGradient ?? false)
? GradientBoxBorder(
? CustomGradientBoxBorder(
gradient: LinearGradient(
colors: style.borderColors!.colors,
),

View File

@ -18,15 +18,15 @@ import 'package:flutter/material.dart' hide ButtonStyle;
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/buttons/cubit/selectable_button_cubit.dart';
import 'package:wyatt_ui_kit/src/components/buttons/exportable_bloc.dart';
import 'package:wyatt_ui_kit/src/components/buttons/symbol_button/symbol_button_screen.dart';
import 'package:wyatt_ui_kit/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/core/mixin/export_bloc_mixin.dart';
part 'symbol_button.g.dart';
@ComponentCopyWithExtension()
class SymbolButton extends SymbolButtonComponent
with $SymbolButtonCWMixin, ExportBloc<SelectableButtonCubit> {
with $SymbolButtonCWMixin{
SymbolButton({
super.icon,
super.label,
@ -44,7 +44,6 @@ class SymbolButton extends SymbolButtonComponent
final SelectableButtonCubit _cubit = SelectableButtonCubit();
@override
SelectableButtonCubit get bloc => _cubit;
@override
@ -74,7 +73,8 @@ class SymbolButton extends SymbolButtonComponent
super.themeResolver as SymbolButtonThemeResolver?;
@override
Widget build(BuildContext context) => exportBloc(
Widget build(BuildContext context) => ExportableBloc(
bloc: _cubit,
child: SymbolButtonScreen(
icon: icon,
label: label,

View File

@ -24,7 +24,6 @@ import 'package:wyatt_ui_kit/src/components/buttons/cubit/selectable_button_cubi
import 'package:wyatt_ui_kit/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_box_border.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart';
import 'package:wyatt_ui_kit/src/core/helpers/linear_gradient_helper.dart';
class SymbolButtonScreen
extends CubitScreen<SelectableButtonCubit, ButtonState> {
@ -61,40 +60,9 @@ class SymbolButtonScreen
SelectableButtonCubit create(BuildContext context) => SelectableButtonCubit();
/// Negotiate the theme to get a complete style.
SymbolButtonStyle resolve(BuildContext context, ButtonState state) {
SymbolButtonStyle _resolve(BuildContext context, ButtonState state) {
final SymbolButtonThemeResolver resolver = themeResolver ??
SymbolButtonThemeResolver(
computeExtensionValueFn: (
context,
defaultValue,
themeExtension, {
extra,
}) {
SymbolButtonStyle? style = defaultValue;
switch (extra?.state) {
case ControlState.disabled:
style = themeExtension.disabledStyle;
break;
case ControlState.focused:
style = themeExtension.focusedStyle;
break;
case ControlState.hovered:
style = themeExtension.hoveredStyle;
break;
case ControlState.tapped:
style = themeExtension.tappedStyle;
break;
case ControlState.normal:
case null:
style = themeExtension.normalStyle;
break;
}
if (extra?.isSelected ?? false) {
style = themeExtension.selectedStyle;
}
return style;
},
customStyleFn: (context, {extra}) {
SymbolButtonStyle? style;
switch (extra?.state) {
@ -127,7 +95,7 @@ class SymbolButtonScreen
@override
Widget onBuild(BuildContext context, ButtonState state) {
final style = resolve(context, state);
final style = _resolve(context, state);
return Focus(
onFocusChange: (hasFocus) =>
@ -176,7 +144,7 @@ class SymbolButtonScreen
border:
(style.borderColors != null && style.stroke != null)
? (style.borderColors?.isGradient ?? false)
? GradientBoxBorder(
? CustomGradientBoxBorder(
gradient: LinearGradient(
colors: style.borderColors!.colors,
),
@ -228,12 +196,7 @@ class SymbolButtonScreen
label!.text,
style: label!.style ?? style.label,
).toGradient(
LinearGradientHelper.fromNullableColors(
label?.gradient ??
((style.foregroundColors?.isGradient ?? false)
? style.foregroundColors?.colors
: null),
),
gradientColors: style.foregroundColors,
),
],
],

View File

@ -22,7 +22,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class SymbolButtonThemeResolver extends ThemeResolver<SymbolButtonStyle,
SymbolButtonThemeExtension, ButtonState> {
const SymbolButtonThemeResolver({
required this.computeExtensionValueFn,
required this.customStyleFn,
});
@ -58,7 +57,7 @@ class SymbolButtonThemeResolver extends ThemeResolver<SymbolButtonStyle,
return SymbolButtonStyle(
label: context.textTheme.labelLarge,
dimension: context.buttonTheme.height*1.5,
dimension: context.buttonTheme.height * 1.5,
radius: (context.buttonTheme.shape is RoundedRectangleBorder)
? (context.buttonTheme.shape as RoundedRectangleBorder).borderRadius
: null,
@ -68,17 +67,41 @@ class SymbolButtonThemeResolver extends ThemeResolver<SymbolButtonStyle,
);
}
@override
final SymbolButtonStyle? Function(
BuildContext context,
SymbolButtonStyle defaultValue,
SymbolButtonThemeExtension themeExtension, {
ButtonState? extra,
}) computeExtensionValueFn;
@override
final SymbolButtonStyle? Function(
BuildContext context, {
ButtonState? extra,
}) customStyleFn;
@override
SymbolButtonStyle? computeExtensionValueFn(
BuildContext context,
SymbolButtonThemeExtension themeExtension, {
ButtonState? extra,
}) {
SymbolButtonStyle? style;
switch (extra?.state) {
case ControlState.disabled:
style = themeExtension.disabledStyle;
break;
case ControlState.focused:
style = themeExtension.focusedStyle;
break;
case ControlState.hovered:
style = themeExtension.hoveredStyle;
break;
case ControlState.tapped:
style = themeExtension.tappedStyle;
break;
case ControlState.normal:
case null:
style = themeExtension.normalStyle;
break;
}
if (extra?.isSelected ?? false) {
style = themeExtension.selectedStyle;
}
return style;
}
}

View File

@ -80,7 +80,7 @@ class InformationCard extends InformationCardComponent
body!.text,
textType: TextType.body,
style: body!.style,
gradient: body!.gradient,
gradientColors: body!.gradientColors,
),
],
],

View File

@ -44,7 +44,7 @@ class InformationCardTitles extends StatelessWidget {
title!.text,
textType: TextType.title,
style: title!.style,
gradient: title!.gradient,
gradientColors: title!.gradientColors,
),
],
if (subtitle != null) ...[
@ -53,7 +53,7 @@ class InformationCardTitles extends StatelessWidget {
subtitle!.text,
textType: TextType.subtitle,
style: subtitle!.style,
gradient: subtitle!.gradient,
gradientColors: subtitle!.gradientColors,
),
],
],

View File

@ -73,7 +73,7 @@ class PortfolioCard extends PortfolioCardComponent with $PortfolioCardCWMixin {
description!.text,
textType: TextType.body,
style: description!.style,
gradient: description!.gradient,
gradientColors: description!.gradientColors,
),
const Gap(20),
PortfolioCardHeader(
@ -108,7 +108,7 @@ class PortfolioCard extends PortfolioCardComponent with $PortfolioCardCWMixin {
description!.text,
textType: TextType.body,
style: description!.style,
gradient: description!.gradient,
gradientColors: description!.gradientColors,
),
],
if (ctas != null) ...[const Gap(20), ...ctas!],

View File

@ -71,7 +71,7 @@ class PortfolioCardHeader extends StatelessWidget {
color: secondaryBackgroundColors ??
Theme.of(context)
.extension<CardThemeExtension>()
?.secondaryBackgroundColors,
?.secondaryBackgroundColor,
borderRadius: BorderRadius.circular(8),
),
child: Text(

View File

@ -20,8 +20,7 @@ import 'package:wyatt_component_copy_with_extension/component_copy_with_extensio
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart';
import 'package:wyatt_ui_kit/src/components/cards/widgets/card_wrapper.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart';
import 'package:wyatt_ui_kit/src/core/extensions/theme_extensions.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
part 'quote_card.g.dart';
@ -63,9 +62,11 @@ class QuoteCard extends QuoteCardComponent with $QuoteCardCWMixin {
alignment: Alignment.topLeft,
child: GradientText(
'',
gradient: gradient,
style: context.textTheme.titleLarge
?.copyWith(fontWeight: FontWeight.bold),
style: GradientTextStyle.from(
context.textTheme.titleLarge
?.copyWith(fontWeight: FontWeight.bold),
MultiColor(gradient?.colors),
),
),
),
if (quote != null) ...[
@ -73,7 +74,7 @@ class QuoteCard extends QuoteCardComponent with $QuoteCardCWMixin {
quote!.text,
textType: TextType.body,
style: quote!.style,
gradient: quote!.gradient,
gradientColors: quote!.gradientColors,
),
],
const Gap(15),
@ -82,9 +83,11 @@ class QuoteCard extends QuoteCardComponent with $QuoteCardCWMixin {
alignment: Alignment.bottomRight,
child: GradientText(
'',
gradient: gradient,
style: context.textTheme.titleLarge
?.copyWith(fontWeight: FontWeight.bold),
style: GradientTextStyle.from(
context.textTheme.titleLarge
?.copyWith(fontWeight: FontWeight.bold),
MultiColor(gradient?.colors),
),
),
),
Row(
@ -102,7 +105,7 @@ class QuoteCard extends QuoteCardComponent with $QuoteCardCWMixin {
name!.text,
textType: TextType.body,
style: name!.style,
gradient: name!.gradient,
gradientColors: name!.gradientColors,
),
],
if (subtitle != null) ...[
@ -110,7 +113,7 @@ class QuoteCard extends QuoteCardComponent with $QuoteCardCWMixin {
subtitle!.text,
textType: TextType.subtitle,
style: subtitle!.style,
gradient: subtitle!.gradient,
gradientColors: subtitle!.gradientColors,
),
],
],

View File

@ -70,7 +70,7 @@ class SkillCard extends SkillCardComponent with $SkillCardCWMixin {
description!.text,
textType: TextType.body,
style: description!.style,
gradient: description!.gradient,
gradientColors: description!.gradientColors,
),
const Gap(25),
],

View File

@ -46,7 +46,7 @@ class SkillCardHeader extends StatelessWidget {
color: secondaryBackgroundColors ??
Theme.of(context)
.extension<CardThemeExtension>()
?.secondaryBackgroundColors,
?.secondaryBackgroundColor,
),
child: gradient != null
? GradientIcon(
@ -67,7 +67,7 @@ class SkillCardHeader extends StatelessWidget {
title!.text,
textType: TextType.title,
style: title!.style,
gradient: title!.gradient,
gradientColors: title!.gradientColors,
),
],
],

View File

@ -50,7 +50,7 @@ class SkillCardSkills extends StatelessWidget {
e.text,
textType: TextType.body,
style: e.style,
gradient: e.gradient,
gradientColors: e.gradientColors,
),
),
],

View File

@ -15,7 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_text.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
enum TextType {
@ -28,13 +28,13 @@ class CardText extends StatelessWidget {
const CardText(
this.data, {
required this.textType,
this.gradient,
this.style,
this.gradientColors,
super.key,
});
final TextType textType;
final TextStyle? style;
final List<Color>? gradient;
final MultiColor? gradientColors;
final String data;
TextStyle? _getStyle(BuildContext context) {
@ -58,9 +58,5 @@ class CardText extends StatelessWidget {
Widget build(BuildContext context) => Text(
data,
style: _getStyle(context),
).toGradient(
LinearGradientHelper.fromNullableColors(
gradient,
),
);
).toGradient(gradientColors: gradientColors);
}

View File

@ -110,8 +110,10 @@ class _CardWrapperState extends State<CardWrapper> {
if (extensionCardColor != null &&
extensionCardColor.backgroundColors != null &&
extensionCardColor.backgroundColors!.length >= 2) {
return LinearGradient(colors: extensionCardColor.backgroundColors!);
extensionCardColor.backgroundColors!.isGradient) {
return LinearGradient(
colors: extensionCardColor.backgroundColors!.colors,
);
}
}
return null;
@ -126,9 +128,8 @@ class _CardWrapperState extends State<CardWrapper> {
Theme.of(context).extension<CardThemeExtension>();
if (extensionCardColor != null &&
extensionCardColor.backgroundColors != null &&
extensionCardColor.backgroundColors!.length == 1) {
return extensionCardColor.backgroundColors!.first;
extensionCardColor.backgroundColors != null) {
return extensionCardColor.backgroundColors!.color;
}
}
return Theme.of(context).cardColor;
@ -137,7 +138,7 @@ class _CardWrapperState extends State<CardWrapper> {
BoxBorder? _boxBorder(BuildContext context) {
if (widget.borderColors != null) {
if (widget.borderColors!.length >= 2) {
return GradientBoxBorder(
return CustomGradientBoxBorder(
gradient: LinearGradient(
colors: widget.borderColors!,
),
@ -151,16 +152,16 @@ class _CardWrapperState extends State<CardWrapper> {
final extensionCardColor =
Theme.of(context).extension<CardThemeExtension>();
if (extensionCardColor != null &&
extensionCardColor.borderColor != null) {
if (extensionCardColor.borderColor!.length >= 2) {
return GradientBoxBorder(
extensionCardColor.borderColors != null) {
if (extensionCardColor.borderColors!.isGradient) {
return CustomGradientBoxBorder(
gradient: LinearGradient(
colors: extensionCardColor.borderColor!,
colors: extensionCardColor.borderColors!.colors,
),
);
} else if (extensionCardColor.backgroundColors!.isNotEmpty) {
} else if (extensionCardColor.backgroundColors!.colors.isNotEmpty) {
return Border.all(
color: extensionCardColor.backgroundColors!.first,
color: extensionCardColor.backgroundColors!.color,
);
}
}

View File

@ -16,3 +16,7 @@
export './buttons/buttons.dart';
export './cards/cards.dart';
export './gradients/gradients.dart';
export './loader/loader.dart';
export './rich_text_builder/rich_text_builder.dart';
export './text_inputs/text_input.dart';

View File

@ -14,10 +14,11 @@
// 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:flutter/painting.dart';
class GradientBoxBorder extends BoxBorder {
const GradientBoxBorder({this.gradient, this.width = 1});
class CustomGradientBoxBorder extends Border {
const CustomGradientBoxBorder({this.gradient, this.width = 1});
final Gradient? gradient;
final double width;
@ -34,9 +35,6 @@ class GradientBoxBorder extends BoxBorder {
@override
bool get isUniform => true;
@override
ShapeBorder scale(double t) => this;
@override
void paint(
Canvas canvas,

View File

@ -17,16 +17,29 @@
// 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';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
extension GradientTextExtension on Text {
GradientText toGradient(Gradient? gradient) =>
GradientText.from(this, gradient);
/// 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);
}
GradientText toFlutterGradient(Gradient? gradient) =>
GradientText.from(this, MultiColor(gradient?.colors));
}
class GradientText extends Text {
const GradientText(
super.data, {
this.gradient,
super.style,
super.strutStyle,
super.textAlign,
@ -43,10 +56,10 @@ class GradientText extends Text {
super.key,
});
factory GradientText.from(Text text, Gradient? gradient) => GradientText(
factory GradientText.from(Text text, MultiColor? gradientColors) =>
GradientText(
text.data ?? '',
style: text.style,
gradient: gradient,
style: GradientTextStyle.from(text.style, gradientColors),
strutStyle: text.strutStyle,
textAlign: text.textAlign,
textDirection: text.textDirection,
@ -62,20 +75,24 @@ class GradientText extends Text {
key: text.key,
);
final Gradient? gradient;
@override
Widget build(BuildContext context) {
if (gradient != null) {
return ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (bounds) => gradient!.createShader(
Rect.fromLTWH(0, 0, bounds.width, bounds.height),
),
child: super.build(context),
);
} else {
return super.build(context);
if (style is GradientTextStyle?) {
// Gradient
final gradientStyle = (style as GradientTextStyle?)?.gradientColors;
final gradient = (gradientStyle?.isGradient ?? false)
? LinearGradientHelper.fromMultiColor(gradientStyle!)
: null;
if (gradient != null) {
return ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (bounds) => gradient.createShader(
Rect.fromLTWH(0, 0, bounds.width, bounds.height),
),
child: super.build(context),
);
}
}
return super.build(context);
}
}

View File

@ -0,0 +1,85 @@
// 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 GradientTextStyle extends TextStyle {
const GradientTextStyle({
this.gradientColors,
super.inherit,
super.color,
super.backgroundColor,
super.fontSize,
super.fontWeight,
super.fontStyle,
super.letterSpacing,
super.wordSpacing,
super.textBaseline,
super.height,
super.leadingDistribution,
super.locale,
super.foreground,
super.background,
super.shadows,
super.fontFeatures,
super.fontVariations,
super.decoration,
super.decorationColor,
super.decorationStyle,
super.decorationThickness,
super.debugLabel,
super.fontFamily,
super.fontFamilyFallback,
super.package,
super.overflow,
});
factory GradientTextStyle.from(
TextStyle? textStyle,
MultiColor? gradientColors,
) =>
GradientTextStyle(
gradientColors: gradientColors,
inherit: textStyle?.inherit ?? true,
color: textStyle?.color,
backgroundColor: textStyle?.backgroundColor,
fontSize: textStyle?.fontSize,
fontWeight: textStyle?.fontWeight,
fontStyle: textStyle?.fontStyle,
letterSpacing: textStyle?.letterSpacing,
wordSpacing: textStyle?.wordSpacing,
textBaseline: textStyle?.textBaseline,
height: textStyle?.height,
leadingDistribution: textStyle?.leadingDistribution,
locale: textStyle?.locale,
foreground: textStyle?.foreground,
background: textStyle?.background,
shadows: textStyle?.shadows,
fontFeatures: textStyle?.fontFeatures,
fontVariations: textStyle?.fontVariations,
decoration: textStyle?.decoration,
decorationColor: textStyle?.decorationColor,
decorationStyle: textStyle?.decorationStyle,
decorationThickness: textStyle?.decorationThickness,
debugLabel: textStyle?.debugLabel,
fontFamily: textStyle?.fontFamily,
fontFamilyFallback: textStyle?.fontFamilyFallback,
overflow: textStyle?.overflow,
);
final MultiColor? gradientColors;
}

View File

@ -0,0 +1,20 @@
// 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 'gradient_box_border.dart';
export 'gradient_icon.dart';
export 'gradient_text.dart';
export 'gradient_text_style.dart';

View File

@ -0,0 +1,135 @@
// 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:math';
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';
@ComponentCopyWithExtension()
class Loader extends LoaderComponent with $LoaderCWMixin {
const Loader({
super.colors,
super.radius,
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(
dimension: dimension,
child: RepaintBoundary(
child: CustomPaint(
painter: _LoaderPainter(
style.colors!,
dimension / 2,
style.stroke!,
flip: flip ?? false,
),
)
.animate(
onPlay: (controller) => controller.repeat(),
)
.rotate(
duration: duration ?? 900.ms,
begin: (flip ?? false) ? 0 : 1,
end: (flip ?? false) ? 1 : 0,
),
),
);
}
}
class _LoaderPainter extends CustomPainter {
_LoaderPainter(
this.colors,
this.radius,
this.stroke, {
required this.flip,
});
final MultiColor colors;
final double radius;
final double stroke;
final bool flip;
@override
void paint(Canvas canvas, Size size) {
final center = Offset(size.width / 2, size.height / 2);
final circleSurface = Rect.fromCircle(center: center, radius: radius);
final dotColor = colors.color;
final dotCenter =
Offset(size.width / 2 + (flip ? -radius : radius), size.height / 2);
final gradient =
colors.isGradient ? colors.colors : [colors.color, colors.color];
final gradientCirclePainter = Paint()
..shader = SweepGradient(
colors: (flip ? gradient.reversed : gradient).toList(),
transform: flip ? const GradientRotation(pi) : null,
).createShader(circleSurface)
..strokeWidth = stroke
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round;
final dotPainter = Paint()
..color = dotColor
..style = PaintingStyle.fill
..strokeCap = StrokeCap.round;
canvas
..drawCircle(center, radius, gradientCirclePainter)
..drawCircle(dotCenter, stroke / 2, dotPainter);
}
@override
bool shouldRepaint(_LoaderPainter oldDelegate) => false;
@override
bool shouldRebuildSemantics(_LoaderPainter oldDelegate) => false;
}

View File

@ -0,0 +1,51 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'loader.dart';
// **************************************************************************
// ComponentCopyWithGenerator
// **************************************************************************
class $LoaderCWProxyImpl implements $LoaderComponentCWProxy {
const $LoaderCWProxyImpl(this._value);
final Loader _value;
@override
Loader colors(MultiColor? colors) => this(colors: colors);
@override
Loader radius(double? radius) => this(radius: radius);
@override
Loader stroke(double? stroke) => this(stroke: stroke);
@override
Loader duration(Duration? duration) => this(duration: duration);
@override
Loader flip(bool? flip) => this(flip: flip);
@override
Loader themeResolver(
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) =>
this(themeResolver: themeResolver);
@override
Loader key(Key? key) => this(key: key);
@override
Loader call({
MultiColor? colors,
double? radius,
double? stroke,
Duration? duration,
bool? flip,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key,
}) =>
Loader(
colors: colors ?? _value.colors,
radius: radius ?? _value.radius,
stroke: stroke ?? _value.stroke,
duration: duration ?? _value.duration,
flip: flip ?? _value.flip,
themeResolver: themeResolver ?? _value.themeResolver,
key: key ?? _value.key,
);
}
mixin $LoaderCWMixin on Component {
$LoaderComponentCWProxy get copyWith => $LoaderCWProxyImpl(this as Loader);
}

View File

@ -0,0 +1,58 @@
// 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,
});
/// 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
final LoaderStyle? Function(
BuildContext context, {
void extra,
}) customStyleFn;
@override
LoaderStyle? computeExtensionValueFn(
BuildContext context,
LoaderThemeExtension themeExtension, {
void extra,
}) =>
LoaderStyle(
colors: themeExtension.colors,
stroke: themeExtension.stroke,
);
}

View File

@ -0,0 +1,98 @@
// 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_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';
@ComponentCopyWithExtension()
class RichTextBuilder extends RichTextBuilderComponent
with $RichTextBuilderCWMixin {
const RichTextBuilder({
super.text,
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 ?? {},
null,
),
);
final customParser = parser ??
RichTextParser(
nodeBuilder: (content, style) {
if (style is GradientTextStyle?) {
return WidgetSpan(
child: GradientText(
content,
style: style,
softWrap: true,
textHeightBehavior: const TextHeightBehavior(
applyHeightToLastDescent: false,
),
),
style: style,
);
}
return TextSpan(
text: content,
style: style,
);
},
);
return SelectionArea(
child: Text.rich(
TextSpan(children: [root.toInlineSpan(customParser)]),
textHeightBehavior:
const TextHeightBehavior(applyHeightToLastDescent: false),
),
);
}
}

View File

@ -0,0 +1,50 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'rich_text_builder.dart';
// **************************************************************************
// ComponentCopyWithGenerator
// **************************************************************************
class $RichTextBuilderCWProxyImpl implements $RichTextBuilderComponentCWProxy {
const $RichTextBuilderCWProxyImpl(this._value);
final RichTextBuilder _value;
@override
RichTextBuilder text(String? text) => this(text: text);
@override
RichTextBuilder parser(RichTextParser? parser) => this(parser: parser);
@override
RichTextBuilder defaultStyle(TextStyle? defaultStyle) =>
this(defaultStyle: defaultStyle);
@override
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({
String? text,
RichTextParser? parser,
TextStyle? defaultStyle,
Map<String, TextStyle>? styles,
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver,
Key? key,
}) =>
RichTextBuilder(
text: text ?? _value.text,
parser: parser ?? _value.parser,
defaultStyle: defaultStyle ?? _value.defaultStyle,
styles: styles ?? _value.styles,
themeResolver: themeResolver ?? _value.themeResolver,
key: key ?? _value.key,
);
}
mixin $RichTextBuilderCWMixin on Component {
$RichTextBuilderComponentCWProxy get copyWith =>
$RichTextBuilderCWProxyImpl(this as RichTextBuilder);
}

View File

@ -0,0 +1,53 @@
// 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,
);
}

View File

@ -0,0 +1,57 @@
// 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:async';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
part 'text_input_state.dart';
class TextInputCubit extends Cubit<TextInputState> {
TextInputCubit() : super(const TextInputState.initial());
// ControlState logic
FutureOr<void> onFocus() async {
if (state.controlState != ControlState.disabled) {
emit(state.copyWith(controlState: ControlState.focused));
}
}
FutureOr<void> onUnfocus() async {
if (state.controlState != ControlState.disabled) {
emit(state.copyWith(controlState: ControlState.normal));
}
}
Future<void> disable() async {
emit(state.copyWith(controlState: ControlState.disabled));
}
Future<void> enable() async {
emit(state.copyWith(controlState: ControlState.normal));
}
// StatusState logic
FutureOr<void> onInvalid(String? error) async {
emit(state.copyWith(statusState: StatusState.error, statusMessage: error));
}
FutureOr<void> onSuccess() async {
emit(state.copyWith(statusState: StatusState.initial, statusMessage: ''));
}
}

View File

@ -0,0 +1,49 @@
// 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/>.
part of 'text_input_cubit.dart';
class TextInputState extends Equatable {
const TextInputState({
required this.controlState,
required this.statusState,
this.statusMessage,
});
const TextInputState.initial()
: controlState = ControlState.normal,
statusState = StatusState.initial,
statusMessage = null;
final ControlState controlState;
final StatusState statusState;
final String? statusMessage;
@override
List<Object?> get props => [controlState, statusState, statusMessage];
TextInputState copyWith({
ControlState? controlState,
StatusState? statusState,
String? statusMessage,
}) =>
TextInputState(
controlState: controlState ?? this.controlState,
statusState: statusState ?? this.statusState,
statusMessage: statusMessage ?? this.statusMessage,
);
}

View File

@ -0,0 +1,168 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// super 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.
//
// super 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 super program. If not, see <https://www.gnu.org/licenses/>.
import 'dart:ui';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.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/text_inputs/text_input_screen.dart';
part 'text_input.g.dart';
@ComponentCopyWithExtension()
class TextInput extends TextInputComponent with $TextInputCWMixin {
TextInput({
super.expand,
super.validator,
super.key,
super.prefixIcon,
super.prefixText,
super.suffixIcon,
super.suffixText,
super.label,
super.onError,
super.hint,
super.normalStyle,
super.focusedStyle,
super.errorStyle,
super.disableStyle,
super.controller,
super.focusNode,
super.keyboardType,
super.smartDashesType,
super.smartQuotesType,
super.enableInteractiveSelection,
super.textInputAction,
super.textCapitalization,
super.style,
super.strutStyle,
super.textAlign,
super.textAlignVertical,
super.textDirection,
super.readOnly,
super.showCursor,
super.autofocus,
super.obscuringCharacter,
super.obscureText,
super.autocorrect,
super.enableSuggestions,
super.maxLines,
super.minLines,
super.expands,
super.maxLength,
super.maxLengthEnforcement,
super.onChanged,
super.onEditingComplete,
super.onSubmitted,
super.onAppPrivateCommand,
super.inputFormatters,
super.enabled,
super.cursorWidth,
super.cursorHeight,
super.cursorRadius,
super.cursorColor,
super.selectionHeightStyle,
super.selectionWidthStyle,
super.keyboardAppearance,
super.scrollPadding,
super.dragStartBehavior,
super.selectionControls,
super.onTap,
super.onTapOutside,
super.mouseCursor,
super.scrollController,
super.scrollPhysics,
super.autofillHints,
super.clipBehavior,
super.restorationId,
super.scribbleEnabled,
super.enableIMEPersonalizedLearning,
super.contextMenuBuilder,
super.spellCheckConfiguration,
super.magnifierConfiguration,
});
@override
Widget build(BuildContext context) => TextInputScreen(
expand: expand,
validator: validator,
label: label,
onError: onError,
hint: hint,
focusedStyle: focusedStyle,
normalStyle: normalStyle,
errorStyle: errorStyle,
disableStyle: disableStyle,
prefixIcon: prefixIcon,
prefixText: prefixText,
suffixIcon: suffixIcon,
magnifierConfiguration: magnifierConfiguration,
controller: controller,
focusNode: focusNode,
keyboardType: keyboardType,
textInputAction: textInputAction,
textCapitalization: textCapitalization,
style: style,
strutStyle: strutStyle,
textAlign: textAlign,
textAlignVertical: textAlignVertical,
textDirection: textDirection,
autofocus: autofocus,
obscuringCharacter: obscuringCharacter,
obscureText: obscureText,
autocorrect: autocorrect,
smartDashesType: smartDashesType,
smartQuotesType: smartQuotesType,
enableSuggestions: enableSuggestions,
maxLines: maxLines,
minLines: minLines,
expands: expands,
readOnly: readOnly,
showCursor: showCursor,
maxLength: maxLength,
maxLengthEnforcement: maxLengthEnforcement,
onChanged: onChanged,
onEditingComplete: onEditingComplete,
onSubmitted: onSubmitted,
onAppPrivateCommand: onAppPrivateCommand,
inputFormatters: inputFormatters,
enabled: enabled,
cursorWidth: cursorWidth,
cursorHeight: cursorHeight,
cursorRadius: cursorRadius,
cursorColor: cursorColor,
selectionHeightStyle: selectionHeightStyle,
selectionWidthStyle: selectionWidthStyle,
keyboardAppearance: keyboardAppearance,
scrollPadding: scrollPadding,
enableInteractiveSelection: enableInteractiveSelection,
selectionControls: selectionControls,
dragStartBehavior: dragStartBehavior,
onTap: onTap,
onTapOutside: onTapOutside,
mouseCursor: mouseCursor,
scrollPhysics: scrollPhysics,
scrollController: scrollController,
autofillHints: autofillHints,
clipBehavior: clipBehavior,
restorationId: restorationId,
scribbleEnabled: scribbleEnabled,
enableIMEPersonalizedLearning: enableIMEPersonalizedLearning,
contextMenuBuilder: contextMenuBuilder,
spellCheckConfiguration: spellCheckConfiguration,
);
}

View File

@ -0,0 +1,348 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'text_input.dart';
// **************************************************************************
// ComponentCopyWithGenerator
// **************************************************************************
class $TextInputCWProxyImpl implements $TextInputComponentCWProxy {
const $TextInputCWProxyImpl(this._value);
final TextInput _value;
@override
TextInput expand(bool? expand) => this(expand: expand);
@override
TextInput onError(String Function(String)? onError) => this(onError: onError);
@override
TextInput validator(bool Function(String)? validator) =>
this(validator: validator);
@override
TextInput suffixText(TextWrapper? suffixText) => this(suffixText: suffixText);
@override
TextInput prefixText(TextWrapper? prefixText) => this(prefixText: prefixText);
@override
TextInput prefixIcon(Icon? prefixIcon) => this(prefixIcon: prefixIcon);
@override
TextInput suffixIcon(Icon? suffixIcon) => this(suffixIcon: suffixIcon);
@override
TextInput label(TextWrapper? label) => this(label: label);
@override
TextInput hint(TextWrapper? hint) => this(hint: hint);
@override
TextInput normalStyle(TextInputStyle? normalStyle) =>
this(normalStyle: normalStyle);
@override
TextInput focusedStyle(TextInputStyle? focusedStyle) =>
this(focusedStyle: focusedStyle);
@override
TextInput errorStyle(TextInputStyle? errorStyle) =>
this(errorStyle: errorStyle);
@override
TextInput disableStyle(TextInputStyle? disableStyle) =>
this(disableStyle: disableStyle);
@override
TextInput controller(TextEditingController? controller) =>
this(controller: controller);
@override
TextInput focusNode(FocusNode? focusNode) => this(focusNode: focusNode);
@override
TextInput keyboardType(TextInputType? keyboardType) =>
this(keyboardType: keyboardType);
@override
TextInput smartDashesType(SmartDashesType? smartDashesType) =>
this(smartDashesType: smartDashesType);
@override
TextInput smartQuotesType(SmartQuotesType? smartQuotesType) =>
this(smartQuotesType: smartQuotesType);
@override
TextInput enableInteractiveSelection(bool? enableInteractiveSelection) =>
this(enableInteractiveSelection: enableInteractiveSelection);
@override
TextInput textInputAction(TextInputAction? textInputAction) =>
this(textInputAction: textInputAction);
@override
TextInput textCapitalization(TextCapitalization? textCapitalization) =>
this(textCapitalization: textCapitalization);
@override
TextInput style(TextStyle? style) => this(style: style);
@override
TextInput strutStyle(StrutStyle? strutStyle) => this(strutStyle: strutStyle);
@override
TextInput textAlign(TextAlign? textAlign) => this(textAlign: textAlign);
@override
TextInput textAlignVertical(TextAlignVertical? textAlignVertical) =>
this(textAlignVertical: textAlignVertical);
@override
TextInput textDirection(TextDirection? textDirection) =>
this(textDirection: textDirection);
@override
TextInput readOnly(bool? readOnly) => this(readOnly: readOnly);
@override
TextInput showCursor(bool? showCursor) => this(showCursor: showCursor);
@override
TextInput autofocus(bool? autofocus) => this(autofocus: autofocus);
@override
TextInput obscuringCharacter(String? obscuringCharacter) =>
this(obscuringCharacter: obscuringCharacter);
@override
TextInput obscureText(bool? obscureText) => this(obscureText: obscureText);
@override
TextInput autocorrect(bool? autocorrect) => this(autocorrect: autocorrect);
@override
TextInput enableSuggestions(bool? enableSuggestions) =>
this(enableSuggestions: enableSuggestions);
@override
TextInput maxLines(int? maxLines) => this(maxLines: maxLines);
@override
TextInput minLines(int? minLines) => this(minLines: minLines);
@override
TextInput expands(bool? expands) => this(expands: expands);
@override
TextInput maxLength(int? maxLength) => this(maxLength: maxLength);
@override
TextInput maxLengthEnforcement(MaxLengthEnforcement? maxLengthEnforcement) =>
this(maxLengthEnforcement: maxLengthEnforcement);
@override
TextInput onChanged(void Function(String)? onChanged) =>
this(onChanged: onChanged);
@override
TextInput onEditingComplete(void Function()? onEditingComplete) =>
this(onEditingComplete: onEditingComplete);
@override
TextInput onSubmitted(void Function(String)? onSubmitted) =>
this(onSubmitted: onSubmitted);
@override
TextInput onAppPrivateCommand(
void Function(String, Map<String, dynamic>)? onAppPrivateCommand) =>
this(onAppPrivateCommand: onAppPrivateCommand);
@override
TextInput inputFormatters(List<TextInputFormatter>? inputFormatters) =>
this(inputFormatters: inputFormatters);
@override
TextInput enabled(ValueNotifier<bool>? enabled) => this(enabled: enabled);
@override
TextInput cursorWidth(double? cursorWidth) => this(cursorWidth: cursorWidth);
@override
TextInput cursorHeight(double? cursorHeight) =>
this(cursorHeight: cursorHeight);
@override
TextInput cursorRadius(Radius? cursorRadius) =>
this(cursorRadius: cursorRadius);
@override
TextInput cursorColor(Color? cursorColor) => this(cursorColor: cursorColor);
@override
TextInput selectionHeightStyle(BoxHeightStyle? selectionHeightStyle) =>
this(selectionHeightStyle: selectionHeightStyle);
@override
TextInput selectionWidthStyle(BoxWidthStyle? selectionWidthStyle) =>
this(selectionWidthStyle: selectionWidthStyle);
@override
TextInput keyboardAppearance(Brightness? keyboardAppearance) =>
this(keyboardAppearance: keyboardAppearance);
@override
TextInput scrollPadding(EdgeInsets? scrollPadding) =>
this(scrollPadding: scrollPadding);
@override
TextInput dragStartBehavior(DragStartBehavior? dragStartBehavior) =>
this(dragStartBehavior: dragStartBehavior);
@override
TextInput selectionControls(TextSelectionControls? selectionControls) =>
this(selectionControls: selectionControls);
@override
TextInput onTap(void Function()? onTap) => this(onTap: onTap);
@override
TextInput onTapOutside(void Function(PointerDownEvent)? onTapOutside) =>
this(onTapOutside: onTapOutside);
@override
TextInput mouseCursor(MouseCursor? mouseCursor) =>
this(mouseCursor: mouseCursor);
@override
TextInput scrollController(ScrollController? scrollController) =>
this(scrollController: scrollController);
@override
TextInput scrollPhysics(ScrollPhysics? scrollPhysics) =>
this(scrollPhysics: scrollPhysics);
@override
TextInput autofillHints(Iterable<String>? autofillHints) =>
this(autofillHints: autofillHints);
@override
TextInput clipBehavior(Clip? clipBehavior) =>
this(clipBehavior: clipBehavior);
@override
TextInput restorationId(String? restorationId) =>
this(restorationId: restorationId);
@override
TextInput scribbleEnabled(bool? scribbleEnabled) =>
this(scribbleEnabled: scribbleEnabled);
@override
TextInput enableIMEPersonalizedLearning(
bool? enableIMEPersonalizedLearning) =>
this(enableIMEPersonalizedLearning: enableIMEPersonalizedLearning);
@override
TextInput contextMenuBuilder(
Widget Function(BuildContext, EditableTextState)?
contextMenuBuilder) =>
this(contextMenuBuilder: contextMenuBuilder);
@override
TextInput spellCheckConfiguration(
SpellCheckConfiguration? spellCheckConfiguration) =>
this(spellCheckConfiguration: spellCheckConfiguration);
@override
TextInput magnifierConfiguration(
TextMagnifierConfiguration? magnifierConfiguration) =>
this(magnifierConfiguration: magnifierConfiguration);
@override
TextInput key(Key? key) => this(key: key);
@override
TextInput call({
bool? expand,
String Function(String)? onError,
bool Function(String)? validator,
TextWrapper? suffixText,
TextWrapper? prefixText,
Icon? prefixIcon,
Icon? suffixIcon,
TextWrapper? label,
TextWrapper? hint,
TextInputStyle? normalStyle,
TextInputStyle? focusedStyle,
TextInputStyle? errorStyle,
TextInputStyle? disableStyle,
TextEditingController? controller,
FocusNode? focusNode,
TextInputType? keyboardType,
SmartDashesType? smartDashesType,
SmartQuotesType? smartQuotesType,
bool? enableInteractiveSelection,
TextInputAction? textInputAction,
TextCapitalization? textCapitalization,
TextStyle? style,
StrutStyle? strutStyle,
TextAlign? textAlign,
TextAlignVertical? textAlignVertical,
TextDirection? textDirection,
bool? readOnly,
bool? showCursor,
bool? autofocus,
String? obscuringCharacter,
bool? obscureText,
bool? autocorrect,
bool? enableSuggestions,
int? maxLines,
int? minLines,
bool? expands,
int? maxLength,
MaxLengthEnforcement? maxLengthEnforcement,
void Function(String)? onChanged,
void Function()? onEditingComplete,
void Function(String)? onSubmitted,
void Function(String, Map<String, dynamic>)? onAppPrivateCommand,
List<TextInputFormatter>? inputFormatters,
ValueNotifier<bool>? enabled,
double? cursorWidth,
double? cursorHeight,
Radius? cursorRadius,
Color? cursorColor,
BoxHeightStyle? selectionHeightStyle,
BoxWidthStyle? selectionWidthStyle,
Brightness? keyboardAppearance,
EdgeInsets? scrollPadding,
DragStartBehavior? dragStartBehavior,
TextSelectionControls? selectionControls,
void Function()? onTap,
void Function(PointerDownEvent)? onTapOutside,
MouseCursor? mouseCursor,
ScrollController? scrollController,
ScrollPhysics? scrollPhysics,
Iterable<String>? autofillHints,
Clip? clipBehavior,
String? restorationId,
bool? scribbleEnabled,
bool? enableIMEPersonalizedLearning,
Widget Function(BuildContext, EditableTextState)? contextMenuBuilder,
SpellCheckConfiguration? spellCheckConfiguration,
TextMagnifierConfiguration? magnifierConfiguration,
Key? key,
}) =>
TextInput(
expand: expand ?? _value.expand,
validator: validator ?? _value.validator,
key: key ?? _value.key,
prefixIcon: prefixIcon ?? _value.prefixIcon,
prefixText: prefixText ?? _value.prefixText,
suffixIcon: suffixIcon ?? _value.suffixIcon,
suffixText: suffixText ?? _value.suffixText,
label: label ?? _value.label,
onError: onError ?? _value.onError,
hint: hint ?? _value.hint,
normalStyle: normalStyle ?? _value.normalStyle,
focusedStyle: focusedStyle ?? _value.focusedStyle,
errorStyle: errorStyle ?? _value.errorStyle,
disableStyle: disableStyle ?? _value.disableStyle,
controller: controller ?? _value.controller,
focusNode: focusNode ?? _value.focusNode,
keyboardType: keyboardType ?? _value.keyboardType,
smartDashesType: smartDashesType ?? _value.smartDashesType,
smartQuotesType: smartQuotesType ?? _value.smartQuotesType,
enableInteractiveSelection:
enableInteractiveSelection ?? _value.enableInteractiveSelection,
textInputAction: textInputAction ?? _value.textInputAction,
textCapitalization: textCapitalization ?? _value.textCapitalization,
style: style ?? _value.style,
strutStyle: strutStyle ?? _value.strutStyle,
textAlign: textAlign ?? _value.textAlign,
textAlignVertical: textAlignVertical ?? _value.textAlignVertical,
textDirection: textDirection ?? _value.textDirection,
readOnly: readOnly ?? _value.readOnly,
showCursor: showCursor ?? _value.showCursor,
autofocus: autofocus ?? _value.autofocus,
obscuringCharacter: obscuringCharacter ?? _value.obscuringCharacter,
obscureText: obscureText ?? _value.obscureText,
autocorrect: autocorrect ?? _value.autocorrect,
enableSuggestions: enableSuggestions ?? _value.enableSuggestions,
maxLines: maxLines ?? _value.maxLines,
minLines: minLines ?? _value.minLines,
expands: expands ?? _value.expands,
maxLength: maxLength ?? _value.maxLength,
maxLengthEnforcement:
maxLengthEnforcement ?? _value.maxLengthEnforcement,
onChanged: onChanged ?? _value.onChanged,
onEditingComplete: onEditingComplete ?? _value.onEditingComplete,
onSubmitted: onSubmitted ?? _value.onSubmitted,
onAppPrivateCommand: onAppPrivateCommand ?? _value.onAppPrivateCommand,
inputFormatters: inputFormatters ?? _value.inputFormatters,
enabled: enabled ?? _value.enabled,
cursorWidth: cursorWidth ?? _value.cursorWidth,
cursorHeight: cursorHeight ?? _value.cursorHeight,
cursorRadius: cursorRadius ?? _value.cursorRadius,
cursorColor: cursorColor ?? _value.cursorColor,
selectionHeightStyle:
selectionHeightStyle ?? _value.selectionHeightStyle,
selectionWidthStyle: selectionWidthStyle ?? _value.selectionWidthStyle,
keyboardAppearance: keyboardAppearance ?? _value.keyboardAppearance,
scrollPadding: scrollPadding ?? _value.scrollPadding,
dragStartBehavior: dragStartBehavior ?? _value.dragStartBehavior,
selectionControls: selectionControls ?? _value.selectionControls,
onTap: onTap ?? _value.onTap,
onTapOutside: onTapOutside ?? _value.onTapOutside,
mouseCursor: mouseCursor ?? _value.mouseCursor,
scrollController: scrollController ?? _value.scrollController,
scrollPhysics: scrollPhysics ?? _value.scrollPhysics,
autofillHints: autofillHints ?? _value.autofillHints,
clipBehavior: clipBehavior ?? _value.clipBehavior,
restorationId: restorationId ?? _value.restorationId,
scribbleEnabled: scribbleEnabled ?? _value.scribbleEnabled,
enableIMEPersonalizedLearning: enableIMEPersonalizedLearning ??
_value.enableIMEPersonalizedLearning,
contextMenuBuilder: contextMenuBuilder ?? _value.contextMenuBuilder,
spellCheckConfiguration:
spellCheckConfiguration ?? _value.spellCheckConfiguration,
magnifierConfiguration:
magnifierConfiguration ?? _value.magnifierConfiguration,
);
}
mixin $TextInputCWMixin on Component {
$TextInputComponentCWProxy get copyWith =>
$TextInputCWProxyImpl(this as TextInput);
}

View File

@ -0,0 +1,393 @@
// 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:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:wyatt_bloc_helper/wyatt_bloc_helper.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/text_inputs/cubit/text_input_cubit.dart';
import 'package:wyatt_ui_kit/src/components/text_inputs/text_input_theme_resolver.dart';
import 'package:wyatt_ui_kit/src/components/text_inputs/widgets/label_widget.dart';
import 'package:wyatt_ui_kit/src/components/text_inputs/widgets/text_input_wrapper.dart';
class TextInputScreen extends CubitScreen<TextInputCubit, TextInputState> {
TextInputScreen({
this.expand,
this.onError,
this.validator,
super.key,
this.suffixText,
this.prefixText,
this.prefixIcon,
this.suffixIcon,
this.label,
this.hint,
this.normalStyle,
this.focusedStyle,
this.errorStyle,
this.disableStyle,
this.magnifierConfiguration,
this.controller,
this.focusNode,
this.keyboardType,
this.textInputAction,
this.textCapitalization,
this.style,
this.strutStyle,
this.textAlign,
this.textAlignVertical,
this.textDirection,
this.autofocus,
this.obscuringCharacter,
this.obscureText,
this.autocorrect,
this.smartDashesType,
this.smartQuotesType,
this.enableSuggestions,
this.maxLines,
this.minLines,
this.expands,
this.readOnly,
this.showCursor,
this.maxLength,
this.maxLengthEnforcement,
this.onChanged,
this.onEditingComplete,
this.onSubmitted,
this.onAppPrivateCommand,
this.inputFormatters,
this.enabled,
this.cursorWidth,
this.cursorHeight,
this.cursorRadius,
this.cursorColor,
this.selectionHeightStyle,
this.selectionWidthStyle,
this.keyboardAppearance,
this.scrollPadding,
this.enableInteractiveSelection,
this.selectionControls,
this.dragStartBehavior,
this.onTap,
this.onTapOutside,
this.mouseCursor,
this.scrollPhysics,
this.scrollController,
this.autofillHints,
this.clipBehavior,
this.restorationId,
this.scribbleEnabled,
this.enableIMEPersonalizedLearning,
this.contextMenuBuilder,
this.spellCheckConfiguration,
});
final TextMagnifierConfiguration? magnifierConfiguration;
final TextEditingController? controller;
final FocusNode? focusNode;
final TextInputType? keyboardType;
final TextInputAction? textInputAction;
final TextCapitalization? textCapitalization;
final TextStyle? style;
final StrutStyle? strutStyle;
final TextAlign? textAlign;
final TextAlignVertical? textAlignVertical;
final TextDirection? textDirection;
final bool? autofocus;
final String? obscuringCharacter;
final bool? obscureText;
final bool? autocorrect;
final SmartDashesType? smartDashesType;
final SmartQuotesType? smartQuotesType;
final bool? enableSuggestions;
final int? maxLines;
final int? minLines;
final bool? expands;
final bool? readOnly;
final bool? showCursor;
final int? maxLength;
final MaxLengthEnforcement? maxLengthEnforcement;
final ValueChanged<String>? onChanged;
final VoidCallback? onEditingComplete;
final ValueChanged<String>? onSubmitted;
final AppPrivateCommandCallback? onAppPrivateCommand;
final List<TextInputFormatter>? inputFormatters;
final double? cursorWidth;
final double? cursorHeight;
final Radius? cursorRadius;
final Color? cursorColor;
final BoxHeightStyle? selectionHeightStyle;
final BoxWidthStyle? selectionWidthStyle;
final Brightness? keyboardAppearance;
final EdgeInsets? scrollPadding;
final bool? enableInteractiveSelection;
final TextSelectionControls? selectionControls;
final DragStartBehavior? dragStartBehavior;
final GestureTapCallback? onTap;
final TapRegionCallback? onTapOutside;
final MouseCursor? mouseCursor;
final ScrollPhysics? scrollPhysics;
final ScrollController? scrollController;
final Iterable<String>? autofillHints;
final Clip? clipBehavior;
final String? restorationId;
final bool? scribbleEnabled;
final bool? enableIMEPersonalizedLearning;
final EditableTextContextMenuBuilder? contextMenuBuilder;
final SpellCheckConfiguration? spellCheckConfiguration;
final bool Function(String)? validator;
final String? Function(String)? onError;
final TextInputStyle? normalStyle;
final TextInputStyle? focusedStyle;
final TextInputStyle? errorStyle;
final TextInputStyle? disableStyle;
final TextWrapper? label;
final TextWrapper? hint;
final ValueNotifier<bool>? enabled;
final bool? expand;
final TextWrapper? prefixText;
final Icon? prefixIcon;
final Icon? suffixIcon;
final TextWrapper? suffixText;
@override
TextInputCubit create(BuildContext context) => TextInputCubit();
@override
TextInputCubit init(BuildContext context, TextInputCubit bloc) {
enabled?.addListener(() {
if (enabled?.value ?? false) {
bloc.enable();
} else {
bloc.disable();
}
});
return bloc;
}
final _focusNode = FocusNode();
final _controller = TextEditingController();
final _notOutilinedBorder = const OutlineInputBorder(
borderSide: BorderSide(color: Colors.transparent),
);
TextInputStyle _resolve(BuildContext context, TextInputState state) {
final resolver = TextInputThemeResolver(
customStyleFn: (context, {extra}) {
TextInputStyle? textInputStyle;
switch (extra?.controlState) {
case ControlState.focused:
textInputStyle = focusedStyle;
break;
case ControlState.disabled:
textInputStyle = disableStyle;
break;
case ControlState.normal:
textInputStyle = normalStyle;
break;
case ControlState.hovered:
break;
case ControlState.tapped:
break;
case null:
break;
}
TextInputStyle? style;
switch (extra?.statusState) {
case StatusState.error:
style = errorStyle;
break;
case StatusState.initial:
break;
case StatusState.success:
break;
case StatusState.loading:
break;
case null:
break;
}
return TextInputStyle.merge(textInputStyle, style);
},
);
return resolver.negotiate(context, extra: state);
}
bool _wrapperExpanded(TextInputState state) {
final fn = focusNode ?? _focusNode;
final tec = controller ?? _controller;
if (fn.hasFocus && label != null) {
return true;
} else if (tec.value.text.isNotEmpty && label != null) {
return true;
} else if (state.statusState == StatusState.error &&
(state.statusMessage?.isNotEmpty ?? false)) {
return true;
}
return false;
}
@override
Widget onBuild(BuildContext context, TextInputState state) {
final style = _resolve(context, state);
return Focus(
onFocusChange: (hasFocus) {
if (hasFocus) {
bloc(context).onFocus();
} else {
bloc(context).onUnfocus();
}
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 600),
decoration: BoxDecoration(
boxShadow: style.boxShadow != null ? [style.boxShadow!] : null,
gradient: style.backgroundColors?.isGradient ?? false
? LinearGradient(colors: style.backgroundColors!.colors)
: null,
color: style.backgroundColors?.isColor ?? false
? style.backgroundColors?.color
: null,
borderRadius: style.radius ?? BorderRadius.circular(4),
border: (style.borderColors?.isGradient ?? false) ||
(style.borderColors?.isColor ?? false)
? Border.all(
width: 1.5,
color: (style.borderColors?.isGradient ?? false)
? style.borderColors!.colors.first
: (style.borderColors?.isColor ?? false)
? style.borderColors!.color
: Colors.transparent,
)
: null,
),
child: TextInputWrapper(
expand: expand ?? true,
expanded: _wrapperExpanded(state),
child: TextField(
onTap: onTap,
onChanged: (value) {
onChanged?.call(value);
if (validator?.call(value) ?? false) {
bloc(context).onInvalid(onError?.call(value));
} else {
bloc(context).onSuccess();
}
},
onTapOutside: onTapOutside,
controller: controller ?? _controller,
focusNode: focusNode ?? _focusNode,
textAlignVertical: textAlignVertical ?? TextAlignVertical.top,
style: style.inputStyle ?? this.style,
decoration: InputDecoration(
focusedErrorBorder: _notOutilinedBorder,
focusedBorder: _notOutilinedBorder,
errorBorder: _notOutilinedBorder,
disabledBorder: _notOutilinedBorder,
enabledBorder: _notOutilinedBorder,
border: _notOutilinedBorder,
isDense: true,
iconColor: style.iconColor,
alignLabelWithHint: true,
label: (state.statusState == StatusState.error &&
(state.statusMessage?.isNotEmpty ?? false)) ||
label != null
? LabelWidget(
focusNode: focusNode ?? _focusNode,
label: (state.statusState == StatusState.error &&
(state.statusMessage?.isNotEmpty ?? false))
? state.statusMessage?.wrap()
: label,
labelStyle: style.labelStyle,
)
: null,
hintText: hint?.text,
hintStyle: hint?.style,
prefixIcon: prefixIcon,
prefixText: prefixText?.text,
prefixStyle: prefixText?.style,
prefixIconColor: style.prefixIconColor,
suffixIcon: suffixIcon,
suffixText: suffixText?.text,
suffixStyle: suffixText?.style,
suffixIconColor: style.suffixIconColor,
enabled: state.controlState != ControlState.disabled,
),
keyboardType: keyboardType,
smartDashesType: smartDashesType,
smartQuotesType: smartQuotesType,
enableInteractiveSelection: enableInteractiveSelection,
textInputAction: textInputAction,
textCapitalization: textCapitalization ?? TextCapitalization.none,
strutStyle: strutStyle,
textAlign: textAlign ?? TextAlign.start,
textDirection: textDirection,
readOnly: readOnly ?? false,
showCursor: showCursor,
autofocus: autofocus ?? false,
obscuringCharacter: obscuringCharacter ?? '*',
obscureText: obscureText ?? false,
autocorrect: autocorrect ?? true,
enableSuggestions: enableSuggestions ?? true,
maxLines: maxLines ?? 1,
minLines: minLines,
expands: expands ?? false,
maxLength: maxLength,
maxLengthEnforcement: maxLengthEnforcement,
onEditingComplete: onEditingComplete,
onSubmitted: onSubmitted,
onAppPrivateCommand: onAppPrivateCommand,
inputFormatters: inputFormatters,
enabled: state.controlState != ControlState.disabled,
cursorWidth: cursorWidth ?? 2.0,
cursorHeight: cursorHeight,
cursorRadius: cursorRadius,
cursorColor: cursorColor,
selectionHeightStyle: selectionHeightStyle ?? BoxHeightStyle.tight,
selectionWidthStyle: selectionWidthStyle ?? BoxWidthStyle.tight,
keyboardAppearance: keyboardAppearance,
scrollPadding: scrollPadding ?? const EdgeInsets.all(20),
dragStartBehavior: dragStartBehavior ?? DragStartBehavior.start,
selectionControls: selectionControls,
mouseCursor: mouseCursor,
scrollController: scrollController,
scrollPhysics: scrollPhysics,
autofillHints: autofillHints,
clipBehavior: clipBehavior ?? Clip.hardEdge,
restorationId: restorationId,
scribbleEnabled: scribbleEnabled ?? true,
enableIMEPersonalizedLearning:
enableIMEPersonalizedLearning ?? true,
contextMenuBuilder: contextMenuBuilder,
spellCheckConfiguration: spellCheckConfiguration,
magnifierConfiguration: magnifierConfiguration,
),
),
),
);
}
}

View File

@ -0,0 +1,167 @@
// 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/src/components/text_inputs/cubit/text_input_cubit.dart';
import 'package:wyatt_ui_kit/src/core/core.dart';
import 'package:wyatt_ui_kit/src/domain/text_input_theme_extension.dart';
class TextInputThemeResolver extends ThemeResolver<TextInputStyle,
TextInputThemeExtension, TextInputState> {
const TextInputThemeResolver({
required this.customStyleFn,
});
@override
final TextInputStyle? Function(
BuildContext context, {
TextInputState? extra,
}) customStyleFn;
@override
TextInputStyle computeDefaultValue(
BuildContext context, {
TextInputState? extra,
}) {
TextStyle? labelStyle = context.textTheme.labelLarge
?.copyWith(color: Theme.of(context).unselectedWidgetColor);
TextStyle? hintStyle = context.textTheme.labelLarge;
TextStyle? prefixStyle = context.textTheme.bodyMedium;
TextStyle? suffixStyle = context.textTheme.bodyMedium;
TextStyle? inputStyle = context.textTheme.bodyMedium;
Color? iconColor = context.colorScheme.inversePrimary;
Color? prefixIconColor = Theme.of(context).unselectedWidgetColor;
Color? suffixIconColor = Theme.of(context).unselectedWidgetColor;
MultiColor? borderColors =
MultiColor.single(Theme.of(context).unselectedWidgetColor);
MultiColor? backgroundColors;
BoxShadow? boxShadow;
final BorderRadiusGeometry radius = BorderRadius.circular(4);
switch (extra?.controlState) {
case ControlState.disabled:
labelStyle =
labelStyle?.copyWith(color: Theme.of(context).disabledColor);
hintStyle = hintStyle?.copyWith(color: Theme.of(context).disabledColor);
prefixStyle =
prefixStyle?.copyWith(color: Theme.of(context).disabledColor);
suffixStyle =
suffixStyle?.copyWith(color: Theme.of(context).disabledColor);
inputStyle =
inputStyle?.copyWith(color: Theme.of(context).disabledColor);
borderColors = MultiColor.single(Theme.of(context).disabledColor);
prefixIconColor = Theme.of(context).disabledColor;
suffixIconColor = Theme.of(context).disabledColor;
break;
case ControlState.focused:
prefixIconColor = context.colorScheme.primary;
suffixIconColor = context.colorScheme.primary;
iconColor = context.colorScheme.primary;
borderColors = MultiColor.single(context.colorScheme.primary);
labelStyle = labelStyle?.copyWith(color: context.colorScheme.primary);
break;
case ControlState.hovered:
break;
case ControlState.tapped:
break;
case ControlState.normal:
break;
case null:
break;
}
switch (extra?.statusState) {
case StatusState.error:
labelStyle = context.textTheme.labelLarge
?.copyWith(color: context.colorScheme.error);
borderColors = MultiColor.single(context.colorScheme.error);
break;
case StatusState.initial:
break;
case StatusState.success:
break;
case StatusState.loading:
break;
case null:
break;
}
return TextInputStyle(
labelStyle: labelStyle,
hintStyle: hintStyle,
iconColor: iconColor,
prefixIconColor: prefixIconColor,
prefixStyle: prefixStyle,
suffixStyle: suffixStyle,
suffixIconColor: suffixIconColor,
backgroundColors: backgroundColors,
borderColors: borderColors,
boxShadow: boxShadow,
radius: radius,
inputStyle: inputStyle,
);
}
@override
TextInputStyle? computeExtensionValueFn(
BuildContext context,
TextInputThemeExtension themeExtension, {
TextInputState? extra,
}) {
TextInputStyle? textInputStyle;
switch (extra?.controlState) {
case ControlState.focused:
textInputStyle = themeExtension.focusedStyle;
break;
case ControlState.disabled:
textInputStyle = themeExtension.disableStyle;
break;
case ControlState.normal:
textInputStyle = themeExtension.normalStyle;
break;
case ControlState.hovered:
break;
case ControlState.tapped:
break;
case null:
break;
}
TextInputStyle? style;
switch (extra?.statusState) {
case StatusState.error:
style = themeExtension.errorStyle;
break;
case StatusState.initial:
break;
case StatusState.success:
break;
case StatusState.loading:
break;
case null:
break;
}
return TextInputStyle.merge(textInputStyle, style);
}
}

View File

@ -0,0 +1,37 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// super 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.
//
// super 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 super program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
class LabelWidget extends StatelessWidget {
const LabelWidget({
required this.label,
required this.focusNode,
required this.labelStyle,
super.key,
});
final TextWrapper? label;
final FocusNode focusNode;
final TextStyle? labelStyle;
@override
Widget build(BuildContext context) => Text(
label?.text ?? '',
style: labelStyle,
);
}

View File

@ -0,0 +1,60 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// super 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.
//
// super 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 super program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
const _defaultPadding = 7.5;
const _paddingAnimationDuration = Duration(milliseconds: 200);
class TextInputWrapper extends StatelessWidget {
const TextInputWrapper({
required this.expand,
required this.expanded,
required this.child,
super.key,
});
final bool expand;
final bool expanded;
final Widget child;
double _top() {
if (expanded) {
return 2 * _defaultPadding;
} else if (!expand) {
return _defaultPadding;
}
return 0;
}
double _bottom() {
if (expanded) {
return 0;
} else if (!expand) {
return _defaultPadding;
}
return 0;
}
@override
Widget build(BuildContext context) => AnimatedPadding(
duration: _paddingAnimationDuration,
padding: EdgeInsets.only(
top: _top(),
bottom: _bottom(),
),
child: child,
);
}

Some files were not shown because too many files have changed in this diff Show More