diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_screen.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_screen.dart index bc45bec9..18a2cf0b 100644 --- a/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_screen.dart +++ b/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_screen.dart @@ -67,41 +67,7 @@ class FileSelectionButtonScreen FileSelectionButtonStyle _resolve(BuildContext context, ButtonState state) { final FileSelectionButtonThemeResolver resolver = themeResolver ?? FileSelectionButtonThemeResolver( - computeExtensionValueFn: ( - context, - defaultValue, - themeExtension, { - extra, - }) { - FileSelectionButtonStyle? style = defaultValue; - switch (extra?.state) { - case ControlState.disabled: - style = themeExtension.disabledStyle; - break; - case ControlState.focused: - style = themeExtension.focusedStyle; - break; - case ControlState.hovered: - style = themeExtension.hoveredStyle; - break; - case ControlState.tapped: - style = themeExtension.tappedStyle; - break; - case ControlState.normal: - case null: - style = themeExtension.normalStyle; - break; - } - if (extra?.isSelected ?? false) { - style = themeExtension.selectedStyle; - } - if (extra?.isInvalid ?? false) { - style = themeExtension.invalidStyle; - } - - return style; - }, - customStyleFn: (context, {extra}) { + customStyleFn: (context, extensionValue, {extra}) { FileSelectionButtonStyle? style; switch (extra?.state) { case ControlState.disabled: diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart index 7c1f9634..92399773 100644 --- a/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart +++ b/packages/wyatt_ui_kit/lib/src/components/buttons/file_selection_button/file_selection_button_theme_resolver.dart @@ -22,7 +22,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; class FileSelectionButtonThemeResolver extends ThemeResolver< FileSelectionButtonStyle, FileSelectionButtonThemeExtension, ButtonState> { const FileSelectionButtonThemeResolver({ - required this.computeExtensionValueFn, required this.customStyleFn, }); @@ -57,8 +56,7 @@ class FileSelectionButtonThemeResolver extends ThemeResolver< } if (extra?.isInvalid ?? false) { - backgroundColor = - MultiColor.single(context.colorScheme.error); + backgroundColor = MultiColor.single(context.colorScheme.error); } return FileSelectionButtonStyle( @@ -75,15 +73,43 @@ class FileSelectionButtonThemeResolver extends ThemeResolver< @override final FileSelectionButtonStyle? Function( + BuildContext context, + FileSelectionButtonStyle? extensionValue, { + ButtonState? extra, + }) customStyleFn; + + @override + FileSelectionButtonStyle? computeExtensionValueFn( BuildContext context, FileSelectionButtonStyle defaultValue, FileSelectionButtonThemeExtension themeExtension, { ButtonState? extra, - }) computeExtensionValueFn; - - @override - final FileSelectionButtonStyle? Function( - BuildContext context, { - ButtonState? extra, - }) customStyleFn; + }) { + 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; + } } diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_screen.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_screen.dart index 803c68cc..88ff27f5 100644 --- a/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_screen.dart +++ b/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_screen.dart @@ -61,27 +61,7 @@ class FlatButtonScreen extends CubitScreen { FlatButtonStyle _resolve(BuildContext context, ControlState state) { final FlatButtonThemeResolver resolver = themeResolver ?? FlatButtonThemeResolver( - computeExtensionValueFn: ( - context, - defaultValue, - themeExtension, { - extra, - }) { - switch (extra) { - case ControlState.disabled: - return themeExtension.disabledStyle; - case ControlState.focused: - return themeExtension.focusedStyle; - case ControlState.hovered: - return themeExtension.hoveredStyle; - case ControlState.tapped: - return themeExtension.tappedStyle; - case ControlState.normal: - case null: - return themeExtension.normalStyle; - } - }, - customStyleFn: (context, {extra}) { + customStyleFn: (context, extensionValue, {extra}) { switch (extra) { case ControlState.disabled: return disabledStyle; @@ -141,7 +121,7 @@ class FlatButtonScreen extends CubitScreen { // If no border color => no default value border: (style.borderColors != null && style.stroke != null) ? (style.borderColors?.isGradient ?? false) - ? GradientBoxBorder( + ? CustomGradientBoxBorder( gradient: LinearGradient( colors: style.borderColors!.colors, ), diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_theme_resolver.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_theme_resolver.dart index c48c6b8e..cef92e2f 100644 --- a/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_theme_resolver.dart +++ b/packages/wyatt_ui_kit/lib/src/components/buttons/flat_button/flat_button_theme_resolver.dart @@ -21,7 +21,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; class FlatButtonThemeResolver extends ThemeResolver { const FlatButtonThemeResolver({ - required this.computeExtensionValueFn, required this.customStyleFn, }); @@ -70,13 +69,30 @@ class FlatButtonThemeResolver extends ThemeResolver { const SimpleIconButtonThemeResolver({ - required this.computeExtensionValueFn, required this.customStyleFn, }); @@ -68,15 +67,30 @@ class SimpleIconButtonThemeResolver extends ThemeResolver { SimpleIconButtonStyle _resolve(BuildContext context, ControlState state) { final SimpleIconButtonThemeResolver resolver = themeResolver ?? SimpleIconButtonThemeResolver( - computeExtensionValueFn: ( - context, - defaultValue, - themeExtension, { - extra, - }) { - switch (extra) { - case ControlState.disabled: - return themeExtension.disabledStyle; - case ControlState.focused: - return themeExtension.focusedStyle; - case ControlState.hovered: - return themeExtension.hoveredStyle; - case ControlState.tapped: - return themeExtension.tappedStyle; - case ControlState.normal: - case null: - return themeExtension.normalStyle; - } - }, - customStyleFn: (context, {extra}) { + customStyleFn: (context, extensionValue, {extra}) { switch (extra) { case ControlState.disabled: return disabledStyle; @@ -140,7 +120,7 @@ class SimpleIconButtonScreen extends CubitScreen { // If no border color => no default value border: (style.borderColors != null && style.stroke != null) ? (style.borderColors?.isGradient ?? false) - ? GradientBoxBorder( + ? CustomGradientBoxBorder( gradient: LinearGradient( colors: style.borderColors!.colors, ), diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_screen.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_screen.dart index b8c84633..e2e427fd 100644 --- a/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_screen.dart +++ b/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_screen.dart @@ -63,38 +63,7 @@ class SymbolButtonScreen SymbolButtonStyle _resolve(BuildContext context, ButtonState state) { final SymbolButtonThemeResolver resolver = themeResolver ?? SymbolButtonThemeResolver( - computeExtensionValueFn: ( - context, - defaultValue, - themeExtension, { - extra, - }) { - SymbolButtonStyle? style = defaultValue; - switch (extra?.state) { - case ControlState.disabled: - style = themeExtension.disabledStyle; - break; - case ControlState.focused: - style = themeExtension.focusedStyle; - break; - case ControlState.hovered: - style = themeExtension.hoveredStyle; - break; - case ControlState.tapped: - style = themeExtension.tappedStyle; - break; - case ControlState.normal: - case null: - style = themeExtension.normalStyle; - break; - } - if (extra?.isSelected ?? false) { - style = themeExtension.selectedStyle; - } - - return style; - }, - customStyleFn: (context, {extra}) { + customStyleFn: (context, extensionValue, {extra}) { SymbolButtonStyle? style; switch (extra?.state) { case ControlState.disabled: @@ -175,7 +144,7 @@ class SymbolButtonScreen border: (style.borderColors != null && style.stroke != null) ? (style.borderColors?.isGradient ?? false) - ? GradientBoxBorder( + ? CustomGradientBoxBorder( gradient: LinearGradient( colors: style.borderColors!.colors, ), diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart index 8d679e22..bed01568 100644 --- a/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart +++ b/packages/wyatt_ui_kit/lib/src/components/buttons/symbol_button/symbol_button_theme_resolver.dart @@ -22,7 +22,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; class SymbolButtonThemeResolver extends ThemeResolver { const SymbolButtonThemeResolver({ - required this.computeExtensionValueFn, required this.customStyleFn, }); @@ -58,7 +57,7 @@ class SymbolButtonThemeResolver extends ThemeResolver { BoxBorder? _boxBorder(BuildContext context) { if (widget.borderColors != null) { if (widget.borderColors!.length >= 2) { - return GradientBoxBorder( + return CustomGradientBoxBorder( gradient: LinearGradient( colors: widget.borderColors!, ), @@ -151,9 +151,15 @@ class _CardWrapperState extends State { final extensionCardColor = Theme.of(context).extension(); if (extensionCardColor != null && +<<<<<<< HEAD extensionCardColor.borderColors != null) { if (extensionCardColor.borderColors!.isGradient) { return GradientBoxBorder( +======= + extensionCardColor.borderColor != null) { + if (extensionCardColor.borderColor!.length >= 2) { + return CustomGradientBoxBorder( +>>>>>>> 548df1c (feat(ui_kit): implemement text inputs (#138)) gradient: LinearGradient( colors: extensionCardColor.borderColors!.colors, ), diff --git a/packages/wyatt_ui_kit/lib/src/components/components.dart b/packages/wyatt_ui_kit/lib/src/components/components.dart index e78cb40d..34d4753d 100644 --- a/packages/wyatt_ui_kit/lib/src/components/components.dart +++ b/packages/wyatt_ui_kit/lib/src/components/components.dart @@ -19,3 +19,4 @@ export './cards/cards.dart'; export './gradients/gradients.dart'; export './loader/loader.dart'; export './rich_text_builder/rich_text_builder.dart'; +export './text_inputs/text_input.dart'; diff --git a/packages/wyatt_ui_kit/lib/src/components/gradients/gradient_box_border.dart b/packages/wyatt_ui_kit/lib/src/components/gradients/gradient_box_border.dart index 912a9c53..10372a96 100644 --- a/packages/wyatt_ui_kit/lib/src/components/gradients/gradient_box_border.dart +++ b/packages/wyatt_ui_kit/lib/src/components/gradients/gradient_box_border.dart @@ -14,10 +14,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +import 'package:flutter/material.dart'; import 'package:flutter/painting.dart'; -class GradientBoxBorder extends BoxBorder { - const GradientBoxBorder({this.gradient, this.width = 1}); +class CustomGradientBoxBorder extends Border { + const CustomGradientBoxBorder({this.gradient, this.width = 1}); final Gradient? gradient; final double width; @@ -34,9 +35,6 @@ class GradientBoxBorder extends BoxBorder { @override bool get isUniform => true; - @override - ShapeBorder scale(double t) => this; - @override void paint( Canvas canvas, diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/cubit/text_input_cubit.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/cubit/text_input_cubit.dart new file mode 100644 index 00000000..4c50a1b9 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/cubit/text_input_cubit.dart @@ -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 . + +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 { + TextInputCubit() : super(const TextInputState.initial()); + + // ControlState logic + FutureOr onFocus() async { + if (state.controlState != ControlState.disabled) { + emit(state.copyWith(controlState: ControlState.focused)); + } + } + + FutureOr onUnfocus() async { + if (state.controlState != ControlState.disabled) { + emit(state.copyWith(controlState: ControlState.normal)); + } + } + + Future disable() async { + emit(state.copyWith(controlState: ControlState.disabled)); + } + + Future enable() async { + emit(state.copyWith(controlState: ControlState.normal)); + } + + // StatusState logic + FutureOr onInvalid(String? error) async { + emit(state.copyWith(statusState: StatusState.error, statusMessage: error)); + } + + FutureOr onSuccess() async { + emit(state.copyWith(statusState: StatusState.initial, statusMessage: '')); + } +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/cubit/text_input_state.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/cubit/text_input_state.dart new file mode 100644 index 00000000..2b91bd2d --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/cubit/text_input_state.dart @@ -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 . + +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 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, + ); +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input.dart new file mode 100644 index 00000000..8e5139c7 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input.dart @@ -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 . + +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, + ); +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input.g.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input.g.dart new file mode 100644 index 00000000..2547f95c --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input.g.dart @@ -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)? onAppPrivateCommand) => + this(onAppPrivateCommand: onAppPrivateCommand); + @override + TextInput inputFormatters(List? inputFormatters) => + this(inputFormatters: inputFormatters); + @override + TextInput enabled(ValueNotifier? 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? 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)? onAppPrivateCommand, + List? inputFormatters, + ValueNotifier? 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? 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); +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input_screen.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input_screen.dart new file mode 100644 index 00000000..51a9d291 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input_screen.dart @@ -0,0 +1,396 @@ +// 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 . + +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 { + 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? onChanged; + final VoidCallback? onEditingComplete; + final ValueChanged? onSubmitted; + final AppPrivateCommandCallback? onAppPrivateCommand; + final List? 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? 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? 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, extensionValue, {extra}) { + TextInputStyle? textInputStyle; + switch (extra?.controlState) { + case ControlState.focused: + textInputStyle = focusedStyle; + break; + case ControlState.disabled: + textInputStyle = disableStyle; + break; + case ControlState.normal: + textInputStyle = normalStyle; + break; + case ControlState.hovered: + break; + case ControlState.tapped: + break; + case null: + break; + } + + TextInputStyle? style; + switch (extra?.statusState) { + case StatusState.error: + style = errorStyle; + break; + case StatusState.initial: + break; + case StatusState.success: + break; + case StatusState.loading: + break; + case null: + break; + } + + return TextInputStyle.merge( + extensionValue, + TextInputStyle.merge(textInputStyle, style), + ); + }, + ); + + return resolver.negotiate(context, extra: state); + } + + bool _wrapperExpanded(TextInputState state) { + final fn = focusNode ?? _focusNode; + final tec = controller ?? _controller; + if (fn.hasFocus && label != null) { + return true; + } else if (tec.value.text.isNotEmpty && label != null) { + return true; + } else if (state.statusState == StatusState.error && + (state.statusMessage?.isNotEmpty ?? false)) { + return true; + } + return false; + } + + @override + Widget onBuild(BuildContext context, TextInputState state) { + final style = _resolve(context, state); + return Focus( + onFocusChange: (hasFocus) { + if (hasFocus) { + bloc(context).onFocus(); + } else { + bloc(context).onUnfocus(); + } + }, + child: AnimatedContainer( + duration: const Duration(milliseconds: 600), + decoration: BoxDecoration( + boxShadow: style.boxShadow != null ? [style.boxShadow!] : null, + gradient: style.backgroundColors?.isGradient ?? false + ? LinearGradient(colors: style.backgroundColors!.colors) + : null, + color: style.backgroundColors?.isColor ?? false + ? style.backgroundColors?.color + : null, + borderRadius: style.radius ?? BorderRadius.circular(4), + border: (style.borderColors?.isGradient ?? false) || + (style.borderColors?.isColor ?? false) + ? Border.all( + width: 1.5, + color: (style.borderColors?.isGradient ?? false) + ? style.borderColors!.colors.first + : (style.borderColors?.isColor ?? false) + ? style.borderColors!.color + : Colors.transparent, + ) + : null, + ), + child: TextInputWrapper( + expand: expand ?? true, + expanded: _wrapperExpanded(state), + child: TextField( + onTap: onTap, + onChanged: (value) { + onChanged?.call(value); + if (validator?.call(value) ?? false) { + bloc(context).onInvalid(onError?.call(value)); + } else { + bloc(context).onSuccess(); + } + }, + onTapOutside: onTapOutside, + controller: controller ?? _controller, + focusNode: focusNode ?? _focusNode, + textAlignVertical: textAlignVertical ?? TextAlignVertical.top, + style: style.inputStyle ?? this.style, + decoration: InputDecoration( + focusedErrorBorder: _notOutilinedBorder, + focusedBorder: _notOutilinedBorder, + errorBorder: _notOutilinedBorder, + disabledBorder: _notOutilinedBorder, + enabledBorder: _notOutilinedBorder, + border: _notOutilinedBorder, + isDense: true, + iconColor: style.iconColor, + alignLabelWithHint: true, + label: (state.statusState == StatusState.error && + (state.statusMessage?.isNotEmpty ?? false)) || + label != null + ? LabelWidget( + focusNode: focusNode ?? _focusNode, + label: (state.statusState == StatusState.error && + (state.statusMessage?.isNotEmpty ?? false)) + ? state.statusMessage?.wrap() + : label, + labelStyle: style.labelStyle, + ) + : null, + hintText: hint?.text, + hintStyle: hint?.style, + prefixIcon: prefixIcon, + prefixText: prefixText?.text, + prefixStyle: prefixText?.style, + prefixIconColor: style.prefixIconColor, + suffixIcon: suffixIcon, + suffixText: suffixText?.text, + suffixStyle: suffixText?.style, + suffixIconColor: style.suffixIconColor, + enabled: state.controlState != ControlState.disabled, + ), + keyboardType: keyboardType, + smartDashesType: smartDashesType, + smartQuotesType: smartQuotesType, + enableInteractiveSelection: enableInteractiveSelection, + textInputAction: textInputAction, + textCapitalization: textCapitalization ?? TextCapitalization.none, + strutStyle: strutStyle, + textAlign: textAlign ?? TextAlign.start, + textDirection: textDirection, + readOnly: readOnly ?? false, + showCursor: showCursor, + autofocus: autofocus ?? false, + obscuringCharacter: obscuringCharacter ?? '*', + obscureText: obscureText ?? false, + autocorrect: autocorrect ?? true, + enableSuggestions: enableSuggestions ?? true, + maxLines: maxLines ?? 1, + minLines: minLines, + expands: expands ?? false, + maxLength: maxLength, + maxLengthEnforcement: maxLengthEnforcement, + onEditingComplete: onEditingComplete, + onSubmitted: onSubmitted, + onAppPrivateCommand: onAppPrivateCommand, + inputFormatters: inputFormatters, + enabled: state.controlState != ControlState.disabled, + cursorWidth: cursorWidth ?? 2.0, + cursorHeight: cursorHeight, + cursorRadius: cursorRadius, + cursorColor: cursorColor, + selectionHeightStyle: selectionHeightStyle ?? BoxHeightStyle.tight, + selectionWidthStyle: selectionWidthStyle ?? BoxWidthStyle.tight, + keyboardAppearance: keyboardAppearance, + scrollPadding: scrollPadding ?? const EdgeInsets.all(20), + dragStartBehavior: dragStartBehavior ?? DragStartBehavior.start, + selectionControls: selectionControls, + mouseCursor: mouseCursor, + scrollController: scrollController, + scrollPhysics: scrollPhysics, + autofillHints: autofillHints, + clipBehavior: clipBehavior ?? Clip.hardEdge, + restorationId: restorationId, + scribbleEnabled: scribbleEnabled ?? true, + enableIMEPersonalizedLearning: + enableIMEPersonalizedLearning ?? true, + contextMenuBuilder: contextMenuBuilder, + spellCheckConfiguration: spellCheckConfiguration, + magnifierConfiguration: magnifierConfiguration, + ), + ), + ), + ); + } +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input_theme_resolver.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input_theme_resolver.dart new file mode 100644 index 00000000..b774c720 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/text_input_theme_resolver.dart @@ -0,0 +1,172 @@ +// 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 . + +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 { + const TextInputThemeResolver({ + required this.customStyleFn, + }); + + @override + final TextInputStyle? Function( + BuildContext context, + TextInputStyle extensionValue, { + TextInputState? extra, + }) customStyleFn; + + @override + TextInputStyle computeDefaultValue( + BuildContext context, { + TextInputState? extra, + }) { + TextStyle? labelStyle = context.textTheme.labelLarge + ?.copyWith(color: Theme.of(context).unselectedWidgetColor); + + TextStyle? hintStyle = context.textTheme.labelLarge; + TextStyle? prefixStyle = context.textTheme.bodyMedium; + TextStyle? suffixStyle = context.textTheme.bodyMedium; + TextStyle? inputStyle = context.textTheme.bodyMedium; + + Color? iconColor = context.colorScheme.inversePrimary; + Color? prefixIconColor = Theme.of(context).unselectedWidgetColor; + Color? suffixIconColor = Theme.of(context).unselectedWidgetColor; + + MultiColor? borderColors = + MultiColor.single(Theme.of(context).unselectedWidgetColor); + + MultiColor? backgroundColors; + BoxShadow? boxShadow; + + final BorderRadiusGeometry radius = BorderRadius.circular(4); + + switch (extra?.controlState) { + case ControlState.disabled: + labelStyle = + labelStyle?.copyWith(color: Theme.of(context).disabledColor); + hintStyle = hintStyle?.copyWith(color: Theme.of(context).disabledColor); + prefixStyle = + prefixStyle?.copyWith(color: Theme.of(context).disabledColor); + suffixStyle = + suffixStyle?.copyWith(color: Theme.of(context).disabledColor); + inputStyle = + inputStyle?.copyWith(color: Theme.of(context).disabledColor); + borderColors = MultiColor.single(Theme.of(context).disabledColor); + prefixIconColor = Theme.of(context).disabledColor; + suffixIconColor = Theme.of(context).disabledColor; + + break; + + case ControlState.focused: + prefixIconColor = context.colorScheme.primary; + suffixIconColor = context.colorScheme.primary; + iconColor = context.colorScheme.primary; + borderColors = MultiColor.single(context.colorScheme.primary); + labelStyle = labelStyle?.copyWith(color: context.colorScheme.primary); + break; + case ControlState.hovered: + break; + case ControlState.tapped: + break; + case ControlState.normal: + break; + case null: + break; + } + + switch (extra?.statusState) { + case StatusState.error: + labelStyle = context.textTheme.labelLarge + ?.copyWith(color: context.colorScheme.error); + borderColors = MultiColor.single(context.colorScheme.error); + break; + case StatusState.initial: + break; + case StatusState.success: + break; + case StatusState.loading: + break; + case null: + break; + } + return TextInputStyle( + labelStyle: labelStyle, + hintStyle: hintStyle, + iconColor: iconColor, + prefixIconColor: prefixIconColor, + prefixStyle: prefixStyle, + suffixStyle: suffixStyle, + suffixIconColor: suffixIconColor, + backgroundColors: backgroundColors, + borderColors: borderColors, + boxShadow: boxShadow, + radius: radius, + inputStyle: inputStyle, + ); + } + + @override + TextInputStyle? computeExtensionValueFn( + BuildContext context, + TextInputStyle defaultValue, + TextInputThemeExtension themeExtension, { + TextInputState? extra, + }) { + TextInputStyle? textInputStyle; + switch (extra?.controlState) { + case ControlState.focused: + textInputStyle = themeExtension.focusedStyle; + break; + case ControlState.disabled: + textInputStyle = themeExtension.disableStyle; + break; + case ControlState.normal: + textInputStyle = themeExtension.normalStyle; + break; + case ControlState.hovered: + break; + case ControlState.tapped: + break; + case null: + break; + } + + TextInputStyle? style; + switch (extra?.statusState) { + case StatusState.error: + style = themeExtension.errorStyle; + break; + case StatusState.initial: + break; + case StatusState.success: + break; + case StatusState.loading: + break; + case null: + break; + } + + return TextInputStyle.merge( + defaultValue, + TextInputStyle.merge(textInputStyle, style), + ); + } +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/widgets/label_widget.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/widgets/label_widget.dart new file mode 100644 index 00000000..0312c62e --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/widgets/label_widget.dart @@ -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 . + +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, + ); +} diff --git a/packages/wyatt_ui_kit/lib/src/components/text_inputs/widgets/text_input_wrapper.dart b/packages/wyatt_ui_kit/lib/src/components/text_inputs/widgets/text_input_wrapper.dart new file mode 100644 index 00000000..ba868365 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/components/text_inputs/widgets/text_input_wrapper.dart @@ -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 . + +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, + ); +} diff --git a/packages/wyatt_ui_kit/lib/src/core/extensions/theme_extensions.dart b/packages/wyatt_ui_kit/lib/src/core/extensions/theme_extensions.dart index 5e39a69c..c874454a 100644 --- a/packages/wyatt_ui_kit/lib/src/core/extensions/theme_extensions.dart +++ b/packages/wyatt_ui_kit/lib/src/core/extensions/theme_extensions.dart @@ -21,4 +21,6 @@ extension BuildContextThemeExtension on BuildContext { TextTheme get textTheme => Theme.of(this).textTheme; ColorScheme get colorScheme => Theme.of(this).colorScheme; ButtonThemeData get buttonTheme => Theme.of(this).buttonTheme; + InputDecorationTheme get inputDecorationTheme => + Theme.of(this).inputDecorationTheme; } diff --git a/packages/wyatt_ui_kit/lib/src/core/helpers/theme_helper.dart b/packages/wyatt_ui_kit/lib/src/core/helpers/theme_helper.dart new file mode 100644 index 00000000..f5164d65 --- /dev/null +++ b/packages/wyatt_ui_kit/lib/src/core/helpers/theme_helper.dart @@ -0,0 +1,33 @@ +// 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 . + +class ThemeHelper { + static T? getThemeElement( + List? 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; + } +} diff --git a/packages/wyatt_ui_kit/lib/src/domain/domain.dart b/packages/wyatt_ui_kit/lib/src/domain/domain.dart index 51fa4377..7456e08c 100644 --- a/packages/wyatt_ui_kit/lib/src/domain/domain.dart +++ b/packages/wyatt_ui_kit/lib/src/domain/domain.dart @@ -16,5 +16,9 @@ export './button_theme_extension/button_theme_extension.dart'; export './card_theme_extension.dart'; +<<<<<<< HEAD export './loader_theme_extension.dart'; export './rich_text_builder_theme_extension.dart'; +======= +export 'text_input_theme_extension.dart'; +>>>>>>> 548df1c (feat(ui_kit): implemement text inputs (#138)) diff --git a/packages/wyatt_ui_kit/lib/src/domain/input_text_theme_extension.dart b/packages/wyatt_ui_kit/lib/src/domain/text_input_theme_extension.dart similarity index 67% rename from packages/wyatt_ui_kit/lib/src/domain/input_text_theme_extension.dart rename to packages/wyatt_ui_kit/lib/src/domain/text_input_theme_extension.dart index d71340fc..8fe456bb 100644 --- a/packages/wyatt_ui_kit/lib/src/domain/input_text_theme_extension.dart +++ b/packages/wyatt_ui_kit/lib/src/domain/text_input_theme_extension.dart @@ -17,20 +17,17 @@ import 'package:flutter/material.dart'; import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; -abstract class InputTexThemetExtension - extends ThemeExtension { - InputTexThemetExtension({ - this.backgroundColors, - this.borderColors, - this.floatingLabelTextStyle, - this.inputStyle, +abstract class TextInputThemeExtension + extends ThemeExtension { + const TextInputThemeExtension({ + this.normalStyle, + this.focusedStyle, + this.errorStyle, + this.disableStyle, }); - // Colors: - final MultiColor? backgroundColors; - final MultiColor? borderColors; - - // TextStyles: - final TextStyle? floatingLabelTextStyle; - final TextStyle? inputStyle; + final TextInputStyle? normalStyle; + final TextInputStyle? focusedStyle; + final TextInputStyle? errorStyle; + final TextInputStyle? disableStyle; }