ui_kit-ui_components/feat/add-textinputs-components #145

Merged
hugo merged 25 commits from ui_kit-ui_components/feat/add-textinputs-components into master 2023-02-21 15:11:35 +00:00
61 changed files with 2550 additions and 451 deletions

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
export 'enums/control_state.dart'; export 'enums/enums.dart';
export 'extensions/build_context_extensions.dart'; export 'extensions/build_context_extensions.dart';
export 'extensions/string_extension.dart'; export 'extensions/string_extension.dart';
export 'mixins/copy_with_mixin.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

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

View File

@ -35,60 +35,55 @@ abstract class ThemeResolver<S extends ThemeStyle<S>, T, E> {
/// {@macro theme_resolver} /// {@macro theme_resolver}
const ThemeResolver(); const ThemeResolver();
S? Function(
BuildContext context,
S defaultValue,
T themeExtension, {
E? extra,
}) get computeExtensionValueFn;
S? Function(BuildContext context, {E? extra}) get customStyleFn; S? Function(BuildContext context, {E? extra}) get customStyleFn;
/// Compute default value from Flutter Theme or with hardcoded values. /// Compute default value from Flutter Theme or with hardcoded values.
S computeDefaultValue(BuildContext context, {E? extra}); S computeDefaultValue(BuildContext context, {E? extra});
/// Compute values from the extension if found S? computeExtensionValueFn(
S? computeExtensionValue(
BuildContext context, BuildContext context,
S defaultValue, { T themeExtension, {
E? extra,
});
/// Compute values from the extension if found
S? _computeExtensionValue(
BuildContext context, {
E? extra, E? extra,
}) { }) {
final themeExtension = findExtension(context); final themeExtension = Theme.of(context).extension<T>();
if (themeExtension != null) { if (themeExtension != null) {
return computeExtensionValueFn( return computeExtensionValueFn(
context, context,
defaultValue,
themeExtension, themeExtension,
extra: extra, extra: extra,
); );
} }
return defaultValue; return null;
} }
/// Compute custom value /// Compute custom value
S? computeCustomValue( S? _computeCustomValue(
BuildContext context, BuildContext context, {
S previousPhaseValue, {
E? extra, E? extra,
}) { }) {
final customStyle = customStyleFn(context, extra: extra); final customStyle = customStyleFn(
context,
extra: extra,
);
if (customStyle != null) { if (customStyle != null) {
return customStyle; return customStyle;
} }
return previousPhaseValue; return null;
} }
T? findExtension(BuildContext context) => Theme.of(context).extension<T>();
/// Choose most suitable style for a given context. /// Choose most suitable style for a given context.
S negotiate(BuildContext context, {E? extra}) { S negotiate(BuildContext context, {E? extra}) {
S style = computeDefaultValue(context, extra: extra); S style = computeDefaultValue(context, extra: extra);
final S? extensionStyle = style =
computeExtensionValue(context, style, extra: extra); style.mergeWith(_computeExtensionValue(context, extra: extra)) ?? style;
style =
style = style.mergeWith(extensionStyle); style.mergeWith(_computeCustomValue(context, extra: extra)) ?? style;
return style;
final S? customStyle = computeCustomValue(context, style, extra: extra);
return style.mergeWith(customStyle);
} }
} }

View File

@ -104,18 +104,11 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
final TextStyle? subTitle; final TextStyle? subTitle;
@override @override
FileSelectionButtonStyle mergeWith(FileSelectionButtonStyle? other) => FileSelectionButtonStyle? mergeWith(FileSelectionButtonStyle? other) =>
FileSelectionButtonStyle.merge(this, other)!; FileSelectionButtonStyle.merge(this, other);
@override @override
FileSelectionButtonStyle? lerpWith( FileSelectionButtonStyle? copyWith({
FileSelectionButtonStyle? other,
double t,
) =>
FileSelectionButtonStyle.lerp(this, other, t);
@override
FileSelectionButtonStyle copyWith({
TextStyle? title, TextStyle? title,
TextStyle? subTitle, TextStyle? subTitle,
BorderRadiusGeometry? radius, BorderRadiusGeometry? radius,

View File

@ -96,15 +96,11 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
final TextStyle? label; final TextStyle? label;
@override @override
FlatButtonStyle mergeWith(FlatButtonStyle? other) => FlatButtonStyle? mergeWith(FlatButtonStyle? other) =>
FlatButtonStyle.merge(this, other)!; FlatButtonStyle.merge(this, other);
@override @override
FlatButtonStyle? lerpWith(FlatButtonStyle? other, double t) => FlatButtonStyle? copyWith({
FlatButtonStyle.lerp(this, other, t);
@override
FlatButtonStyle copyWith({
TextStyle? label, TextStyle? label,
BorderRadiusGeometry? radius, BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding, EdgeInsetsGeometry? padding,

View File

@ -96,12 +96,8 @@ class SimpleIconButtonStyle extends ButtonStyle<SimpleIconButtonStyle> {
final double? dimension; final double? dimension;
@override @override
SimpleIconButtonStyle mergeWith(SimpleIconButtonStyle? other) => SimpleIconButtonStyle? mergeWith(SimpleIconButtonStyle? other) =>
SimpleIconButtonStyle.merge(this, other)!; SimpleIconButtonStyle.merge(this, other);
@override
SimpleIconButtonStyle? lerpWith(SimpleIconButtonStyle? other, double t) =>
SimpleIconButtonStyle.lerp(this, other, t);
@override @override
SimpleIconButtonStyle copyWith({ SimpleIconButtonStyle copyWith({

View File

@ -104,15 +104,11 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
final double? dimension; final double? dimension;
@override @override
SymbolButtonStyle mergeWith(SymbolButtonStyle? other) => SymbolButtonStyle? mergeWith(SymbolButtonStyle? other) =>
SymbolButtonStyle.merge(this, other)!; SymbolButtonStyle.merge(this, other);
@override @override
SymbolButtonStyle? lerpWith(SymbolButtonStyle? other, double t) => SymbolButtonStyle? copyWith({
SymbolButtonStyle.lerp(this, other, t);
@override
SymbolButtonStyle copyWith({
TextStyle? label, TextStyle? label,
double? dimension, double? dimension,
BorderRadiusGeometry? radius, BorderRadiusGeometry? radius,

View File

@ -15,6 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/widgets.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/component.dart'; import 'package:wyatt_ui_components/src/domain/entities/component.dart';
abstract class CardComponent extends Component { abstract class CardComponent extends Component {
@ -41,10 +42,10 @@ abstract class CardComponent extends Component {
final double? padding; final double? padding;
/// Border gradient color (from left to right) /// Border gradient color (from left to right)
final List<Color>? borderColors; final MultiColor? borderColors;
/// Card background color /// Card background color
final List<Color>? backgroundColors; final MultiColor? backgroundColors;
/// Minimum size for this card /// Minimum size for this card
final Size? minSize; final Size? minSize;

View File

@ -14,8 +14,8 @@ abstract class $InformationCardComponentCWProxy {
InformationCardComponent axis(Axis? axis); InformationCardComponent axis(Axis? axis);
InformationCardComponent radius(double? radius); InformationCardComponent radius(double? radius);
InformationCardComponent padding(double? padding); InformationCardComponent padding(double? padding);
InformationCardComponent borderColors(List<Color>? borderColors); InformationCardComponent borderColors(MultiColor? borderColors);
InformationCardComponent backgroundColors(List<Color>? backgroundColors); InformationCardComponent backgroundColors(MultiColor? backgroundColors);
InformationCardComponent minSize(Size? minSize); InformationCardComponent minSize(Size? minSize);
InformationCardComponent maxSize(Size? maxSize); InformationCardComponent maxSize(Size? maxSize);
InformationCardComponent shadow(BoxShadow? shadow); InformationCardComponent shadow(BoxShadow? shadow);
@ -29,8 +29,8 @@ abstract class $InformationCardComponentCWProxy {
Axis? axis, Axis? axis,
double? radius, double? radius,
double? padding, double? padding,
List<Color>? borderColors, MultiColor? borderColors,
List<Color>? backgroundColors, MultiColor? backgroundColors,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,

View File

@ -19,8 +19,8 @@ abstract class $PortfolioCardComponentCWProxy {
PortfolioCardComponent assets(List<Widget>? assets); PortfolioCardComponent assets(List<Widget>? assets);
PortfolioCardComponent radius(double? radius); PortfolioCardComponent radius(double? radius);
PortfolioCardComponent padding(double? padding); PortfolioCardComponent padding(double? padding);
PortfolioCardComponent borderColors(List<Color>? borderColors); PortfolioCardComponent borderColors(MultiColor? borderColors);
PortfolioCardComponent backgroundColors(List<Color>? backgroundColors); PortfolioCardComponent backgroundColors(MultiColor? backgroundColors);
PortfolioCardComponent minSize(Size? minSize); PortfolioCardComponent minSize(Size? minSize);
PortfolioCardComponent maxSize(Size? maxSize); PortfolioCardComponent maxSize(Size? maxSize);
PortfolioCardComponent shadow(BoxShadow? shadow); PortfolioCardComponent shadow(BoxShadow? shadow);
@ -38,8 +38,8 @@ abstract class $PortfolioCardComponentCWProxy {
List<Widget>? assets, List<Widget>? assets,
double? radius, double? radius,
double? padding, double? padding,
List<Color>? borderColors, MultiColor? borderColors,
List<Color>? backgroundColors, MultiColor? backgroundColors,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,

View File

@ -16,8 +16,8 @@ abstract class $QuoteCardComponentCWProxy {
QuoteCardComponent rightQuote(Widget? rightQuote); QuoteCardComponent rightQuote(Widget? rightQuote);
QuoteCardComponent radius(double? radius); QuoteCardComponent radius(double? radius);
QuoteCardComponent padding(double? padding); QuoteCardComponent padding(double? padding);
QuoteCardComponent borderColors(List<Color>? borderColors); QuoteCardComponent borderColors(MultiColor? borderColors);
QuoteCardComponent backgroundColors(List<Color>? backgroundColors); QuoteCardComponent backgroundColors(MultiColor? backgroundColors);
QuoteCardComponent minSize(Size? minSize); QuoteCardComponent minSize(Size? minSize);
QuoteCardComponent maxSize(Size? maxSize); QuoteCardComponent maxSize(Size? maxSize);
QuoteCardComponent shadow(BoxShadow? shadow); QuoteCardComponent shadow(BoxShadow? shadow);
@ -33,8 +33,8 @@ abstract class $QuoteCardComponentCWProxy {
Widget? rightQuote, Widget? rightQuote,
double? radius, double? radius,
double? padding, double? padding,
List<Color>? borderColors, MultiColor? borderColors,
List<Color>? backgroundColors, MultiColor? backgroundColors,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,

View File

@ -17,8 +17,8 @@ abstract class $SkillCardComponentCWProxy {
Color? secondaryBackgroundColors); Color? secondaryBackgroundColors);
SkillCardComponent radius(double? radius); SkillCardComponent radius(double? radius);
SkillCardComponent padding(double? padding); SkillCardComponent padding(double? padding);
SkillCardComponent borderColors(List<Color>? borderColors); SkillCardComponent borderColors(MultiColor? borderColors);
SkillCardComponent backgroundColors(List<Color>? backgroundColors); SkillCardComponent backgroundColors(MultiColor? backgroundColors);
SkillCardComponent minSize(Size? minSize); SkillCardComponent minSize(Size? minSize);
SkillCardComponent maxSize(Size? maxSize); SkillCardComponent maxSize(Size? maxSize);
SkillCardComponent shadow(BoxShadow? shadow); SkillCardComponent shadow(BoxShadow? shadow);
@ -34,8 +34,8 @@ abstract class $SkillCardComponentCWProxy {
Color? secondaryBackgroundColors, Color? secondaryBackgroundColors,
double? radius, double? radius,
double? padding, double? padding,
List<Color>? borderColors, MultiColor? borderColors,
List<Color>? backgroundColors, MultiColor? backgroundColors,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,

View File

@ -24,4 +24,5 @@ export './loader_component.dart';
export './loader_style.dart'; export './loader_style.dart';
export './loading_widget_component.dart'; export './loading_widget_component.dart';
export './rich_text_builder/rich_text_builder.dart'; export './rich_text_builder/rich_text_builder.dart';
export './text_inputs/text_inputs.dart';
export './theme_style.dart'; export './theme_style.dart';

View File

@ -65,11 +65,7 @@ class LoaderStyle extends ThemeStyle<LoaderStyle> {
final double? stroke; final double? stroke;
@override @override
LoaderStyle mergeWith(LoaderStyle? other) => LoaderStyle.merge(this, other)!; LoaderStyle? mergeWith(LoaderStyle? other) => LoaderStyle.merge(this, other);
@override
LoaderStyle? lerpWith(LoaderStyle? other, double t) =>
LoaderStyle.lerp(this, other, t);
@override @override
LoaderStyle copyWith({ LoaderStyle copyWith({

View File

@ -23,7 +23,7 @@ class RichTextStyleParameter {
this.styleName, this.styleName,
); );
final TextStyle defaultStyle; final TextStyle? defaultStyle;
final Map<String, TextStyle> definedStyle; final Map<String, TextStyle> definedStyle;
final String? styleName; final String? styleName;
@ -31,7 +31,7 @@ class RichTextStyleParameter {
if (definedStyle.containsKey(styleName)) { if (definedStyle.containsKey(styleName)) {
return definedStyle[styleName]!; return definedStyle[styleName]!;
} }
return defaultStyle; return defaultStyle ?? const TextStyle();
} }
RichTextStyleParameter copyWith({ RichTextStyleParameter copyWith({

View File

@ -64,15 +64,11 @@ class RichTextBuilderStyle extends ThemeStyle<RichTextBuilderStyle> {
final Map<String, TextStyle>? styles; final Map<String, TextStyle>? styles;
@override @override
RichTextBuilderStyle mergeWith(RichTextBuilderStyle? other) => RichTextBuilderStyle? mergeWith(RichTextBuilderStyle? other) =>
RichTextBuilderStyle.merge(this, other)!; RichTextBuilderStyle.merge(this, other);
@override @override
RichTextBuilderStyle? lerpWith(RichTextBuilderStyle? other, double t) => RichTextBuilderStyle? copyWith({
RichTextBuilderStyle.lerp(this, other, t);
@override
RichTextBuilderStyle copyWith({
TextStyle? defaultStyle, TextStyle? defaultStyle,
Map<String, TextStyle>? styles, Map<String, TextStyle>? styles,
}) => }) =>

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,133 @@
// 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';
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 Color? 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: Color.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);
@override
TextInputStyle copyWith({
TextStyle? labelStyle,
TextStyle? hintStyle,
MultiColor? backgroundColors,
Color? borderColors,
BoxShadow? boxShadow,
BorderRadiusGeometry? radius,
TextStyle? inputStyle,
Color? iconColor,
TextStyle? prefixStyle,
Color? prefixIconColor,
TextStyle? suffixStyle,
Color? suffixIconColor,
}) =>
TextInputStyle(
labelStyle: labelStyle ?? this.labelStyle,
hintStyle: hintStyle ?? this.hintStyle,
backgroundColors: backgroundColors ?? this.backgroundColors,
radius: radius ?? this.radius,
borderColors: borderColors ?? this.borderColors,
boxShadow: boxShadow ?? this.boxShadow,
inputStyle: inputStyle ?? this.inputStyle,
prefixStyle: prefixStyle ?? this.prefixStyle,
suffixStyle: suffixStyle ?? this.suffixStyle,
prefixIconColor: prefixIconColor ?? this.prefixIconColor,
suffixIconColor: suffixIconColor ?? this.suffixIconColor,
iconColor: iconColor ?? this.iconColor,
);
}

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

@ -18,11 +18,8 @@ abstract class ThemeStyle<T> {
const ThemeStyle(); const ThemeStyle();
/// Merges non-null `other` attributes in `this` and returns a copy. /// Merges non-null `other` attributes in `this` and returns a copy.
T mergeWith(T? other); T? mergeWith(T? other);
/// Used for interpolation.
T? lerpWith(T? other, double t);
/// Copy with (mandatory for mergeWith, needs to be simple and ignore `null`) /// Copy with (mandatory for mergeWith, needs to be simple and ignore `null`)
T copyWith(); T? copyWith();
} }

View File

@ -6,6 +6,7 @@ import 'package:wyatt_ui_kit_example/cards/cards.dart';
import 'package:wyatt_ui_kit_example/demo_page.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/loaders/loaders.dart';
import 'package:wyatt_ui_kit_example/rich_text_builders/rich_text_builders.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'; import 'package:wyatt_ui_kit_example/theme/themes.dart';
const String title = 'Wyatt UIKit Example'; const String title = 'Wyatt UIKit Example';
@ -26,6 +27,7 @@ class _HomeState extends State<Home> {
Buttons(), Buttons(),
Loaders(), Loaders(),
RichTextBuilders(), RichTextBuilders(),
TextInputs(),
]; ];
int currentIndex = 0; int currentIndex = 0;

View File

@ -64,5 +64,4 @@ class Loaders extends DemoPage {
const Gap(20), 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,161 @@
// 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 Color.fromRGBO(221, 224, 227, 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 Color.fromRGBO(60, 125, 251, 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 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 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 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 Color.fromRGBO(60, 125, 251, 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 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 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

@ -24,6 +24,7 @@ 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/rich_text_builder_theme.dart';
import 'package:wyatt_ui_kit_example/theme/simple_icon_button_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/symbol_button_theme.dart';
import 'package:wyatt_ui_kit_example/theme/text_input_theme.dart';
/// Easely switch between Material and Studio themes. /// Easely switch between Material and Studio themes.
abstract class Themes { abstract class Themes {
@ -90,6 +91,7 @@ abstract class Themes {
LoaderTheme.light(), LoaderTheme.light(),
// Rich Text // Rich Text
RichTextBuilderTheme.light(), RichTextBuilderTheme.light(),
TextInputTheme.light(),
], ],
); );
@ -121,6 +123,7 @@ abstract class Themes {
LoaderTheme.dark(), LoaderTheme.dark(),
// Rich Text // Rich Text
RichTextBuilderTheme.dark(), RichTextBuilderTheme.dark(),
TextInputTheme.dark(),
], ],
); );
} }

View File

@ -67,40 +67,6 @@ class FileSelectionButtonScreen
FileSelectionButtonStyle _resolve(BuildContext context, ButtonState state) { FileSelectionButtonStyle _resolve(BuildContext context, ButtonState state) {
final FileSelectionButtonThemeResolver resolver = themeResolver ?? final FileSelectionButtonThemeResolver resolver = themeResolver ??
FileSelectionButtonThemeResolver( 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}) { customStyleFn: (context, {extra}) {
FileSelectionButtonStyle? style; FileSelectionButtonStyle? style;
switch (extra?.state) { switch (extra?.state) {

View File

@ -22,7 +22,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class FileSelectionButtonThemeResolver extends ThemeResolver< class FileSelectionButtonThemeResolver extends ThemeResolver<
FileSelectionButtonStyle, FileSelectionButtonThemeExtension, ButtonState> { FileSelectionButtonStyle, FileSelectionButtonThemeExtension, ButtonState> {
const FileSelectionButtonThemeResolver({ const FileSelectionButtonThemeResolver({
required this.computeExtensionValueFn,
required this.customStyleFn, required this.customStyleFn,
}); });
@ -57,8 +56,7 @@ class FileSelectionButtonThemeResolver extends ThemeResolver<
} }
if (extra?.isInvalid ?? false) { if (extra?.isInvalid ?? false) {
backgroundColor = backgroundColor = MultiColor.single(context.colorScheme.error);
MultiColor.single(context.colorScheme.error);
} }
return FileSelectionButtonStyle( return FileSelectionButtonStyle(
@ -73,17 +71,43 @@ class FileSelectionButtonThemeResolver extends ThemeResolver<
); );
} }
@override
final FileSelectionButtonStyle? Function(
BuildContext context,
FileSelectionButtonStyle defaultValue,
FileSelectionButtonThemeExtension themeExtension, {
ButtonState? extra,
}) computeExtensionValueFn;
@override @override
final FileSelectionButtonStyle? Function( final FileSelectionButtonStyle? Function(
BuildContext context, { BuildContext context, {
ButtonState? extra, ButtonState? extra,
}) customStyleFn; }) 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

@ -61,26 +61,6 @@ class FlatButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
FlatButtonStyle _resolve(BuildContext context, ControlState state) { FlatButtonStyle _resolve(BuildContext context, ControlState state) {
final FlatButtonThemeResolver resolver = themeResolver ?? final FlatButtonThemeResolver resolver = themeResolver ??
FlatButtonThemeResolver( 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}) { customStyleFn: (context, {extra}) {
switch (extra) { switch (extra) {
case ControlState.disabled: case ControlState.disabled:

View File

@ -21,7 +21,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class FlatButtonThemeResolver extends ThemeResolver<FlatButtonStyle, class FlatButtonThemeResolver extends ThemeResolver<FlatButtonStyle,
FlatButtonThemeExtension, ControlState> { FlatButtonThemeExtension, ControlState> {
const FlatButtonThemeResolver({ const FlatButtonThemeResolver({
required this.computeExtensionValueFn,
required this.customStyleFn, required this.customStyleFn,
}); });
@ -70,13 +69,28 @@ class FlatButtonThemeResolver extends ThemeResolver<FlatButtonStyle,
@override @override
final FlatButtonStyle? Function( final FlatButtonStyle? Function(
BuildContext context, BuildContext context, {
FlatButtonStyle defaultValue,
FlatButtonThemeExtension themeExtension, {
ControlState? extra, ControlState? extra,
}) computeExtensionValueFn; }) customStyleFn;
@override @override
final FlatButtonStyle? Function(BuildContext context, {ControlState? extra}) FlatButtonStyle? computeExtensionValueFn(
customStyleFn; 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

@ -21,7 +21,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class SimpleIconButtonThemeResolver extends ThemeResolver<SimpleIconButtonStyle, class SimpleIconButtonThemeResolver extends ThemeResolver<SimpleIconButtonStyle,
SimpleIconButtonThemeExtension, ControlState> { SimpleIconButtonThemeExtension, ControlState> {
const SimpleIconButtonThemeResolver({ const SimpleIconButtonThemeResolver({
required this.computeExtensionValueFn,
required this.customStyleFn, 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 @override
final SimpleIconButtonStyle? Function( final SimpleIconButtonStyle? Function(
BuildContext context, { BuildContext context, {
ControlState? extra, ControlState? extra,
}) customStyleFn; }) 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

@ -55,26 +55,6 @@ class SimpleIconButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
SimpleIconButtonStyle _resolve(BuildContext context, ControlState state) { SimpleIconButtonStyle _resolve(BuildContext context, ControlState state) {
final SimpleIconButtonThemeResolver resolver = themeResolver ?? final SimpleIconButtonThemeResolver resolver = themeResolver ??
SimpleIconButtonThemeResolver( 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}) { customStyleFn: (context, {extra}) {
switch (extra) { switch (extra) {
case ControlState.disabled: case ControlState.disabled:

View File

@ -63,37 +63,6 @@ class SymbolButtonScreen
SymbolButtonStyle _resolve(BuildContext context, ButtonState state) { SymbolButtonStyle _resolve(BuildContext context, ButtonState state) {
final SymbolButtonThemeResolver resolver = themeResolver ?? final SymbolButtonThemeResolver resolver = themeResolver ??
SymbolButtonThemeResolver( 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}) { customStyleFn: (context, {extra}) {
SymbolButtonStyle? style; SymbolButtonStyle? style;
switch (extra?.state) { switch (extra?.state) {

View File

@ -22,7 +22,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class SymbolButtonThemeResolver extends ThemeResolver<SymbolButtonStyle, class SymbolButtonThemeResolver extends ThemeResolver<SymbolButtonStyle,
SymbolButtonThemeExtension, ButtonState> { SymbolButtonThemeExtension, ButtonState> {
const SymbolButtonThemeResolver({ const SymbolButtonThemeResolver({
required this.computeExtensionValueFn,
required this.customStyleFn, required this.customStyleFn,
}); });
@ -58,7 +57,7 @@ class SymbolButtonThemeResolver extends ThemeResolver<SymbolButtonStyle,
return SymbolButtonStyle( return SymbolButtonStyle(
label: context.textTheme.labelLarge, label: context.textTheme.labelLarge,
dimension: context.buttonTheme.height*1.5, dimension: context.buttonTheme.height * 1.5,
radius: (context.buttonTheme.shape is RoundedRectangleBorder) radius: (context.buttonTheme.shape is RoundedRectangleBorder)
? (context.buttonTheme.shape as RoundedRectangleBorder).borderRadius ? (context.buttonTheme.shape as RoundedRectangleBorder).borderRadius
: null, : null,
@ -68,17 +67,41 @@ class SymbolButtonThemeResolver extends ThemeResolver<SymbolButtonStyle,
); );
} }
@override
final SymbolButtonStyle? Function(
BuildContext context,
SymbolButtonStyle defaultValue,
SymbolButtonThemeExtension themeExtension, {
ButtonState? extra,
}) computeExtensionValueFn;
@override @override
final SymbolButtonStyle? Function( final SymbolButtonStyle? Function(
BuildContext context, { BuildContext context, {
ButtonState? extra, ButtonState? extra,
}) customStyleFn; }) 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

@ -24,10 +24,10 @@ class $InformationCardCWProxyImpl implements $InformationCardComponentCWProxy {
@override @override
InformationCard padding(double? padding) => this(padding: padding); InformationCard padding(double? padding) => this(padding: padding);
@override @override
InformationCard borderColors(List<Color>? borderColors) => InformationCard borderColors(MultiColor? borderColors) =>
this(borderColors: borderColors); this(borderColors: borderColors);
@override @override
InformationCard backgroundColors(List<Color>? backgroundColors) => InformationCard backgroundColors(MultiColor? backgroundColors) =>
this(backgroundColors: backgroundColors); this(backgroundColors: backgroundColors);
@override @override
InformationCard minSize(Size? minSize) => this(minSize: minSize); InformationCard minSize(Size? minSize) => this(minSize: minSize);
@ -49,8 +49,8 @@ class $InformationCardCWProxyImpl implements $InformationCardComponentCWProxy {
Axis? axis, Axis? axis,
double? radius, double? radius,
double? padding, double? padding,
List<Color>? borderColors, MultiColor? borderColors,
List<Color>? backgroundColors, MultiColor? backgroundColors,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,

View File

@ -36,10 +36,10 @@ class $PortfolioCardCWProxyImpl implements $PortfolioCardComponentCWProxy {
@override @override
PortfolioCard padding(double? padding) => this(padding: padding); PortfolioCard padding(double? padding) => this(padding: padding);
@override @override
PortfolioCard borderColors(List<Color>? borderColors) => PortfolioCard borderColors(MultiColor? borderColors) =>
this(borderColors: borderColors); this(borderColors: borderColors);
@override @override
PortfolioCard backgroundColors(List<Color>? backgroundColors) => PortfolioCard backgroundColors(MultiColor? backgroundColors) =>
this(backgroundColors: backgroundColors); this(backgroundColors: backgroundColors);
@override @override
PortfolioCard minSize(Size? minSize) => this(minSize: minSize); PortfolioCard minSize(Size? minSize) => this(minSize: minSize);
@ -64,8 +64,8 @@ class $PortfolioCardCWProxyImpl implements $PortfolioCardComponentCWProxy {
List<Widget>? assets, List<Widget>? assets,
double? radius, double? radius,
double? padding, double? padding,
List<Color>? borderColors, MultiColor? borderColors,
List<Color>? backgroundColors, MultiColor? backgroundColors,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,

View File

@ -28,10 +28,10 @@ class $QuoteCardCWProxyImpl implements $QuoteCardComponentCWProxy {
@override @override
QuoteCard padding(double? padding) => this(padding: padding); QuoteCard padding(double? padding) => this(padding: padding);
@override @override
QuoteCard borderColors(List<Color>? borderColors) => QuoteCard borderColors(MultiColor? borderColors) =>
this(borderColors: borderColors); this(borderColors: borderColors);
@override @override
QuoteCard backgroundColors(List<Color>? backgroundColors) => QuoteCard backgroundColors(MultiColor? backgroundColors) =>
this(backgroundColors: backgroundColors); this(backgroundColors: backgroundColors);
@override @override
QuoteCard minSize(Size? minSize) => this(minSize: minSize); QuoteCard minSize(Size? minSize) => this(minSize: minSize);
@ -54,8 +54,8 @@ class $QuoteCardCWProxyImpl implements $QuoteCardComponentCWProxy {
Widget? rightQuote, Widget? rightQuote,
double? radius, double? radius,
double? padding, double? padding,
List<Color>? borderColors, MultiColor? borderColors,
List<Color>? backgroundColors, MultiColor? backgroundColors,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,

View File

@ -31,10 +31,10 @@ class $SkillCardCWProxyImpl implements $SkillCardComponentCWProxy {
@override @override
SkillCard padding(double? padding) => this(padding: padding); SkillCard padding(double? padding) => this(padding: padding);
@override @override
SkillCard borderColors(List<Color>? borderColors) => SkillCard borderColors(MultiColor? borderColors) =>
this(borderColors: borderColors); this(borderColors: borderColors);
@override @override
SkillCard backgroundColors(List<Color>? backgroundColors) => SkillCard backgroundColors(MultiColor? backgroundColors) =>
this(backgroundColors: backgroundColors); this(backgroundColors: backgroundColors);
@override @override
SkillCard minSize(Size? minSize) => this(minSize: minSize); SkillCard minSize(Size? minSize) => this(minSize: minSize);
@ -57,8 +57,8 @@ class $SkillCardCWProxyImpl implements $SkillCardComponentCWProxy {
Color? secondaryBackgroundColors, Color? secondaryBackgroundColors,
double? radius, double? radius,
double? padding, double? padding,
List<Color>? borderColors, MultiColor? borderColors,
List<Color>? backgroundColors, MultiColor? backgroundColors,
Size? minSize, Size? minSize,
Size? maxSize, Size? maxSize,
BoxShadow? shadow, BoxShadow? shadow,

View File

@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
class CardBackground extends StatefulWidget {
const CardBackground({super.key, this.background, this.cardKey});
final Widget? background;
final GlobalKey? cardKey;
@override
State<CardBackground> createState() => _CardBackgroundState();
}
class _CardBackgroundState extends State<CardBackground> {
Size _cardSize = Size.zero;
@override
void initState() {
super.initState();
if (widget.background != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_resizeCard();
});
}
}
@override
void didUpdateWidget(covariant CardBackground oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.background != null) {
_resizeCard();
}
}
void _resizeCard() {
final RenderObject? renderBox =
widget.cardKey?.currentContext?.findRenderObject();
if (renderBox != null) {
setState(() {
_cardSize =
Size(renderBox.paintBounds.width, renderBox.paintBounds.height);
});
}
}
@override
Widget build(BuildContext context) => SizedBox(
width: _cardSize.width,
height: _cardSize.height,
child: Center(child: widget.background),
);
}

View File

@ -15,11 +15,12 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:wyatt_ui_kit/src/components/gradients/gradient_box_border.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/domain/card_theme_extension.dart'; import 'package:wyatt_ui_kit/src/components/cards/widgets/card_background.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class CardWrapper extends StatefulWidget { class CardWrapper extends StatelessWidget {
const CardWrapper({ CardWrapper({
required this.child, required this.child,
required this.backgroundColors, required this.backgroundColors,
required this.borderColors, required this.borderColors,
@ -33,61 +34,26 @@ class CardWrapper extends StatefulWidget {
final Widget? background; final Widget? background;
final Widget child; final Widget child;
final List<Color>? backgroundColors; final MultiColor? backgroundColors;
final List<Color>? borderColors; final MultiColor? borderColors;
final BoxShadow? shadow; final BoxShadow? shadow;
final Size? minSize; final Size? minSize;
final Size? maxSize; final Size? maxSize;
final double? padding; final double? padding;
@override
State<CardWrapper> createState() => _CardWrapperState();
}
class _CardWrapperState extends State<CardWrapper> {
Size _cardSize = Size.zero;
final GlobalKey _key = GlobalKey(); final GlobalKey _key = GlobalKey();
@override Widget _buildChild(Widget child) => (background != null)
void initState() {
super.initState();
if (widget.background != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_resizeCard();
});
}
}
@override
void didUpdateWidget(covariant CardWrapper oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.background != null) {
_resizeCard();
}
}
void _resizeCard() {
final RenderObject? renderBox = _key.currentContext?.findRenderObject();
if (renderBox != null) {
setState(() {
_cardSize =
Size(renderBox.paintBounds.width, renderBox.paintBounds.height);
});
}
}
Widget _buildChild(Widget child) => (widget.background != null)
? Stack( ? Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
SizedBox( CardBackground(
width: _cardSize.width, cardKey: _key,
height: _cardSize.height, background: background,
child: Center(child: widget.background),
), ),
Padding( Padding(
padding: EdgeInsets.all( padding: EdgeInsets.all(
widget.padding ?? 25, padding ?? 25,
), ),
child: child, child: child,
), ),
@ -95,92 +61,22 @@ class _CardWrapperState extends State<CardWrapper> {
) )
: Padding( : Padding(
padding: EdgeInsets.all( padding: EdgeInsets.all(
widget.padding ?? 25, padding ?? 25,
), ),
child: child, child: child,
); );
Gradient? _cardGradient(BuildContext context) {
if (widget.backgroundColors != null &&
widget.backgroundColors!.length >= 2) {
return LinearGradient(colors: widget.backgroundColors!);
} else {
final extensionCardColor =
Theme.of(context).extension<CardThemeExtension>();
if (extensionCardColor != null &&
extensionCardColor.backgroundColors != null &&
extensionCardColor.backgroundColors!.isGradient) {
return LinearGradient(
colors: extensionCardColor.backgroundColors!.colors,);
}
}
return null;
}
Color? _cardColor(BuildContext context) {
if (widget.backgroundColors != null &&
widget.backgroundColors!.length == 1) {
return widget.backgroundColors!.first;
} else {
final extensionCardColor =
Theme.of(context).extension<CardThemeExtension>();
if (extensionCardColor != null &&
extensionCardColor.backgroundColors != null) {
return extensionCardColor.backgroundColors!.color;
}
}
return Theme.of(context).cardColor;
}
BoxBorder? _boxBorder(BuildContext context) {
if (widget.borderColors != null) {
if (widget.borderColors!.length >= 2) {
return GradientBoxBorder(
gradient: LinearGradient(
colors: widget.borderColors!,
),
);
} else if (widget.borderColors!.isNotEmpty) {
return Border.all(
color: widget.borderColors!.first,
);
}
} else {
final extensionCardColor =
Theme.of(context).extension<CardThemeExtension>();
if (extensionCardColor != null &&
extensionCardColor.borderColors != null) {
if (extensionCardColor.borderColors!.isGradient) {
return GradientBoxBorder(
gradient: LinearGradient(
colors: extensionCardColor.borderColors!.colors,
),
);
} else if (extensionCardColor.backgroundColors!.colors.isNotEmpty) {
return Border.all(
color: extensionCardColor.backgroundColors!.color,
);
}
}
}
return null;
}
List<BoxShadow> _shadow(BuildContext context) { List<BoxShadow> _shadow(BuildContext context) {
final shadows = List<BoxShadow>.empty(growable: true); final themeShadow = ThemeHelper.getThemeElement<BoxShadow, BoxShadow>(
if (widget.shadow != null) { [
shadows.add(widget.shadow!); shadow,
} else { Theme.of(context).extension<CardThemeExtension>()?.shadowColor,
final extensionCardColor = ],
Theme.of(context).extension<CardThemeExtension>(); valueValidator: (shadow) => shadow != null,
if (extensionCardColor != null && transform: (shadow) => shadow,
extensionCardColor.shadowColor != null) { defaultValue: null,
shadows.add(extensionCardColor.shadowColor!); );
} return (themeShadow != null) ? [themeShadow] : [];
}
return shadows;
} }
@override @override
@ -189,22 +85,66 @@ class _CardWrapperState extends State<CardWrapper> {
key: _key, key: _key,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(12)), borderRadius: const BorderRadius.all(Radius.circular(12)),
gradient: _cardGradient(context), gradient: ThemeHelper.getThemeElement<MultiColor, Gradient>(
color: _cardColor(context), [
border: _boxBorder(context), backgroundColors,
Theme.of(context)
.extension<CardThemeExtension>()
?.backgroundColors,
],
valueValidator: (multiColor) =>
multiColor != null && multiColor.isGradient,
transform: (multiColor) =>
LinearGradientHelper.fromMultiColor(multiColor!),
defaultValue: null,
),
color: ThemeHelper.getThemeElement<MultiColor, Color>(
[
backgroundColors,
Theme.of(context)
.extension<CardThemeExtension>()
?.backgroundColors,
],
valueValidator: (multiColor) =>
multiColor != null && multiColor.isColor,
transform: (multiColor) => multiColor?.color,
defaultValue: Theme.of(context).cardColor,
),
border: ThemeHelper.getThemeElement<MultiColor, BoxBorder>(
[
borderColors,
Theme.of(context).extension<CardThemeExtension>()?.borderColors,
Theme.of(context)
.extension<CardThemeExtension>()
?.backgroundColors,
],
valueValidator: (multiColor) =>
multiColor != null && multiColor.isColor,
transform: (multiColor) {
if (multiColor!.isGradient) {
return GradientBoxBorder(
gradient: LinearGradientHelper.fromMultiColor(multiColor),
);
}
return Border.all(
color: multiColor.color,
);
},
defaultValue: null,
),
boxShadow: _shadow(context), boxShadow: _shadow(context),
), ),
child: (widget.minSize != null && widget.maxSize != null) child: (minSize != null && maxSize != null)
? ConstrainedBox( ? ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(
minWidth: widget.minSize!.width, minWidth: minSize!.width,
minHeight: widget.minSize!.height, minHeight: minSize!.height,
maxWidth: widget.maxSize!.width, maxWidth: maxSize!.width,
maxHeight: widget.maxSize!.height, maxHeight: maxSize!.height,
), ),
child: _buildChild(widget.child), child: _buildChild(child),
) )
: _buildChild(widget.child), : _buildChild(child),
), ),
); );
} }

View File

@ -19,3 +19,4 @@ export './cards/cards.dart';
export './gradients/gradients.dart'; export './gradients/gradients.dart';
export './loader/loader.dart'; export './loader/loader.dart';
export './rich_text_builder/rich_text_builder.dart'; export './rich_text_builder/rich_text_builder.dart';
export './text_inputs/text_input.dart';

View File

@ -14,9 +14,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
class GradientBoxBorder extends BoxBorder { class GradientBoxBorder extends Border {
const GradientBoxBorder({this.gradient, this.width = 1}); const GradientBoxBorder({this.gradient, this.width = 1});
final Gradient? gradient; final Gradient? gradient;
@ -34,9 +35,6 @@ class GradientBoxBorder extends BoxBorder {
@override @override
bool get isUniform => true; bool get isUniform => true;
@override
ShapeBorder scale(double t) => this;
@override @override
void paint( void paint(
Canvas canvas, Canvas canvas,

View File

@ -45,16 +45,6 @@ class Loader extends LoaderComponent with $LoaderCWMixin {
LoaderStyle _resolve(BuildContext context) { LoaderStyle _resolve(BuildContext context) {
final LoaderThemeResolver resolver = themeResolver ?? final LoaderThemeResolver resolver = themeResolver ??
LoaderThemeResolver( LoaderThemeResolver(
computeExtensionValueFn: (
context,
defaultValue,
themeExtension, {
extra,
}) =>
LoaderStyle(
colors: themeExtension.colors,
stroke: themeExtension.stroke,
),
customStyleFn: (context, {extra}) => LoaderStyle( customStyleFn: (context, {extra}) => LoaderStyle(
colors: colors, colors: colors,
stroke: stroke, stroke: stroke,
@ -69,15 +59,14 @@ class Loader extends LoaderComponent with $LoaderCWMixin {
final style = _resolve(context); final style = _resolve(context);
final dimension = final dimension =
(radius != null) ? radius! * 2 : context.buttonTheme.height; (radius != null) ? radius! * 2 : context.buttonTheme.height;
return SizedBox.square( return SizedBox.square(
dimension: dimension, dimension: dimension,
child: RepaintBoundary( child: RepaintBoundary(
child: CustomPaint( child: CustomPaint(
painter: _LoaderPainter( painter: _LoaderPainter(
style.colors!, style.colors ?? const MultiColor([]),
dimension / 2, dimension / 2,
style.stroke!, style.stroke ?? 4,
flip: flip ?? false, flip: flip ?? false,
), ),
) )

View File

@ -21,10 +21,15 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class LoaderThemeResolver class LoaderThemeResolver
extends ThemeResolver<LoaderStyle, LoaderThemeExtension, void> { extends ThemeResolver<LoaderStyle, LoaderThemeExtension, void> {
const LoaderThemeResolver({ const LoaderThemeResolver({
required this.computeExtensionValueFn,
required this.customStyleFn, required this.customStyleFn,
}); });
@override
final LoaderStyle? Function(
BuildContext context, {
void extra,
}) customStyleFn;
/// Values taken from <https://api.flutter.dev/flutter/material/ElevatedButton/defaultStyleOf.html> /// Values taken from <https://api.flutter.dev/flutter/material/ElevatedButton/defaultStyleOf.html>
@override @override
LoaderStyle computeDefaultValue( LoaderStyle computeDefaultValue(
@ -41,13 +46,13 @@ class LoaderThemeResolver
); );
@override @override
final LoaderStyle? Function( LoaderStyle? computeExtensionValueFn(
BuildContext context, BuildContext context,
LoaderStyle defaultValue,
LoaderThemeExtension themeExtension, { LoaderThemeExtension themeExtension, {
void extra, void extra,
}) computeExtensionValueFn; }) =>
LoaderStyle(
@override colors: themeExtension.colors,
final LoaderStyle? Function(BuildContext context, {void extra}) customStyleFn; stroke: themeExtension.stroke,
);
} }

View File

@ -42,16 +42,6 @@ class RichTextBuilder extends RichTextBuilderComponent
RichTextBuilderStyle _resolve(BuildContext context) { RichTextBuilderStyle _resolve(BuildContext context) {
final RichTextBuilderThemeResolver resolver = themeResolver ?? final RichTextBuilderThemeResolver resolver = themeResolver ??
RichTextBuilderThemeResolver( RichTextBuilderThemeResolver(
computeExtensionValueFn: (
context,
defaultValue,
themeExtension, {
extra,
}) =>
RichTextBuilderStyle(
defaultStyle: themeExtension.defaultStyle,
styles: themeExtension.styles,
),
customStyleFn: (context, {extra}) => RichTextBuilderStyle( customStyleFn: (context, {extra}) => RichTextBuilderStyle(
defaultStyle: defaultStyle, defaultStyle: defaultStyle,
styles: styles, styles: styles,
@ -69,7 +59,7 @@ class RichTextBuilder extends RichTextBuilderComponent
text ?? '', text ?? '',
regex, regex,
RichTextStyleParameter( RichTextStyleParameter(
style.defaultStyle!, style.defaultStyle,
style.styles ?? {}, style.styles ?? {},
null, null,
), ),

View File

@ -21,7 +21,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class RichTextBuilderThemeResolver extends ThemeResolver<RichTextBuilderStyle, class RichTextBuilderThemeResolver extends ThemeResolver<RichTextBuilderStyle,
RichTextBuilderThemeExtension, void> { RichTextBuilderThemeExtension, void> {
const RichTextBuilderThemeResolver({ const RichTextBuilderThemeResolver({
required this.computeExtensionValueFn,
required this.customStyleFn, required this.customStyleFn,
}); });
@ -37,13 +36,18 @@ class RichTextBuilderThemeResolver extends ThemeResolver<RichTextBuilderStyle,
@override @override
final RichTextBuilderStyle? Function( final RichTextBuilderStyle? Function(
BuildContext context, BuildContext context, {
RichTextBuilderStyle defaultValue,
RichTextBuilderThemeExtension themeExtension, {
void extra, void extra,
}) computeExtensionValueFn; }) customStyleFn;
@override @override
final RichTextBuilderStyle? Function(BuildContext context, {void extra}) RichTextBuilderStyle? computeExtensionValueFn(
customStyleFn; 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,383 @@
// 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:
case ControlState.tapped:
case null:
break;
}
TextInputStyle? style;
switch (extra?.statusState) {
case StatusState.error:
style = errorStyle;
break;
case StatusState.initial:
case StatusState.success:
case StatusState.loading:
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 != null)
? Border.all(
width: 1.5,
color: style.borderColors!,
)
: 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,155 @@
// 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;
Color? borderColors = 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 = 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 = context.colorScheme.primary;
labelStyle = labelStyle?.copyWith(color: context.colorScheme.primary);
break;
case ControlState.hovered:
case ControlState.tapped:
case ControlState.normal:
case null:
break;
}
switch (extra?.statusState) {
case StatusState.error:
labelStyle = context.textTheme.labelLarge
?.copyWith(color: context.colorScheme.error);
borderColors = context.colorScheme.error;
break;
case StatusState.initial:
case StatusState.success:
case StatusState.loading:
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:
case ControlState.tapped:
case null:
break;
}
TextInputStyle? style;
switch (extra?.statusState) {
case StatusState.error:
style = themeExtension.errorStyle;
break;
case StatusState.initial:
case StatusState.success:
case StatusState.loading:
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,
);
}

View File

@ -21,4 +21,6 @@ extension BuildContextThemeExtension on BuildContext {
TextTheme get textTheme => Theme.of(this).textTheme; TextTheme get textTheme => Theme.of(this).textTheme;
ColorScheme get colorScheme => Theme.of(this).colorScheme; ColorScheme get colorScheme => Theme.of(this).colorScheme;
ButtonThemeData get buttonTheme => Theme.of(this).buttonTheme; ButtonThemeData get buttonTheme => Theme.of(this).buttonTheme;
InputDecorationTheme get inputDecorationTheme =>
Theme.of(this).inputDecorationTheme;
} }

View File

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

View File

@ -0,0 +1,41 @@
// 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/>.
/// A helper class for getting theme elements.
abstract class ThemeHelper {
/// Gets a theme element from a list of styles.
/// Styles are checked in order, and the first one that passes the
/// [valueValidator] is returned.
/// If no style passes the [valueValidator], the [defaultValue] is returned.
/// If [styles] is null or empty, the [defaultValue] is returned.
/// Style elements are transformed using the [transform] function.
static T? getThemeElement<P, T>(
List<P?>? styles, {
required T? Function(P?)? transform,
required T? defaultValue,
bool? Function(P?)? valueValidator,
}) {
if (styles?.isNotEmpty ?? false) {
for (final element in styles!) {
if (valueValidator?.call(element) ?? false) {
return transform?.call(element);
}
}
}
return defaultValue;
}
}

View File

@ -18,3 +18,4 @@ export './button_theme_extension/button_theme_extension.dart';
export './card_theme_extension.dart'; export './card_theme_extension.dart';
export './loader_theme_extension.dart'; export './loader_theme_extension.dart';
export './rich_text_builder_theme_extension.dart'; export './rich_text_builder_theme_extension.dart';
export './text_input_theme_extension.dart';

View File

@ -0,0 +1,33 @@
// 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';
abstract class TextInputThemeExtension
extends ThemeExtension<TextInputThemeExtension> {
const TextInputThemeExtension({
this.normalStyle,
this.focusedStyle,
this.errorStyle,
this.disableStyle,
});
final TextInputStyle? normalStyle;
final TextInputStyle? focusedStyle;
final TextInputStyle? errorStyle;
final TextInputStyle? disableStyle;
}