feat(ui_kit): implemement text inputs (#138)

This commit is contained in:
Malo Léon 2023-02-21 08:22:20 +01:00
parent edf72cf4c2
commit 1edb1f7324
23 changed files with 1468 additions and 164 deletions

View File

@ -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:

View File

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

View File

@ -61,27 +61,7 @@ class FlatButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
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<ButtonCubit, ButtonState> {
// If no border color => no default value
border: (style.borderColors != null && style.stroke != null)
? (style.borderColors?.isGradient ?? false)
? GradientBoxBorder(
? CustomGradientBoxBorder(
gradient: LinearGradient(
colors: style.borderColors!.colors,
),

View File

@ -21,7 +21,6 @@ import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
class FlatButtonThemeResolver extends ThemeResolver<FlatButtonStyle,
FlatButtonThemeExtension, ControlState> {
const FlatButtonThemeResolver({
required this.computeExtensionValueFn,
required this.customStyleFn,
});
@ -70,13 +69,30 @@ class FlatButtonThemeResolver extends ThemeResolver<FlatButtonStyle,
@override
final FlatButtonStyle? Function(
BuildContext context,
FlatButtonStyle? extensionValue, {
ControlState? extra,
}) customStyleFn;
@override
FlatButtonStyle? computeExtensionValueFn(
BuildContext context,
FlatButtonStyle defaultValue,
FlatButtonThemeExtension themeExtension, {
ControlState? extra,
}) computeExtensionValueFn;
@override
final FlatButtonStyle? Function(BuildContext context, {ControlState? extra})
customStyleFn;
}) {
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,
SimpleIconButtonThemeExtension, ControlState> {
const SimpleIconButtonThemeResolver({
required this.computeExtensionValueFn,
required this.customStyleFn,
});
@ -68,15 +67,30 @@ class SimpleIconButtonThemeResolver extends ThemeResolver<SimpleIconButtonStyle,
@override
final SimpleIconButtonStyle? Function(
BuildContext context,
SimpleIconButtonStyle? extensionValue, {
ControlState? extra,
}) customStyleFn;
@override
SimpleIconButtonStyle? computeExtensionValueFn(
BuildContext context,
SimpleIconButtonStyle defaultValue,
SimpleIconButtonThemeExtension themeExtension, {
ControlState? extra,
}) computeExtensionValueFn;
@override
final SimpleIconButtonStyle? Function(
BuildContext context, {
ControlState? extra,
}) customStyleFn;
}) {
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,27 +55,7 @@ class SimpleIconButtonScreen extends CubitScreen<ButtonCubit, ButtonState> {
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<ButtonCubit, ButtonState> {
// If no border color => no default value
border: (style.borderColors != null && style.stroke != null)
? (style.borderColors?.isGradient ?? false)
? GradientBoxBorder(
? CustomGradientBoxBorder(
gradient: LinearGradient(
colors: style.borderColors!.colors,
),

View File

@ -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,
),

View File

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

View File

@ -137,7 +137,7 @@ class _CardWrapperState extends State<CardWrapper> {
BoxBorder? _boxBorder(BuildContext context) {
if (widget.borderColors != null) {
if (widget.borderColors!.length >= 2) {
return GradientBoxBorder(
return CustomGradientBoxBorder(
gradient: LinearGradient(
colors: widget.borderColors!,
),
@ -151,9 +151,15 @@ class _CardWrapperState extends State<CardWrapper> {
final extensionCardColor =
Theme.of(context).extension<CardThemeExtension>();
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,
),

View File

@ -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';

View File

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

View File

@ -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,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 <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, 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,
),
),
),
);
}
}

View File

@ -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 <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,
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),
);
}
}

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;
ColorScheme get colorScheme => Theme.of(this).colorScheme;
ButtonThemeData get buttonTheme => Theme.of(this).buttonTheme;
InputDecorationTheme get inputDecorationTheme =>
Theme.of(this).inputDecorationTheme;
}

View File

@ -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 <https://www.gnu.org/licenses/>.
class ThemeHelper {
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

@ -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))

View File

@ -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> {
InputTexThemetExtension({
this.backgroundColors,
this.borderColors,
this.floatingLabelTextStyle,
this.inputStyle,
abstract class TextInputThemeExtension
extends ThemeExtension<TextInputThemeExtension> {
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;
}