diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 747ad15..86bd0bc 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.4.0\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\sqflite-2.3.3+1\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_android-2.2.4\\\\","native_build":true,"dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\sqflite-2.3.3+1\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.4.0\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\sqflite-2.3.3+1\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_linux-2.2.1\\\\","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_windows-2.2.1\\\\","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2024-05-18 12:11:58.348151","version":"3.19.0"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.4.0\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\sqflite-2.3.3+1\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_android-2.2.4\\\\","native_build":true,"dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\sqflite-2.3.3+1\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.4.0\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\sqflite-2.3.3+1\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_linux-2.2.1\\\\","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\Micazi\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_windows-2.2.1\\\\","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2024-05-20 14:33:38.749112","version":"3.22.0"} \ No newline at end of file diff --git a/.fvmrc b/.fvmrc new file mode 100644 index 0000000..c300356 --- /dev/null +++ b/.fvmrc @@ -0,0 +1,3 @@ +{ + "flutter": "stable" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index ac5aa98..a920017 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ migrate_working_dir/ **/doc/api/ .dart_tool/ build/ + +# FVM Version Cache +.fvm/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1395495 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "dart.flutterSdkPath": ".fvm/versions/stable" +} \ No newline at end of file diff --git a/lib/Infrastructure/insets_extension.dart b/lib/Infrastructure/insets_extension.dart new file mode 100644 index 0000000..974fb6a --- /dev/null +++ b/lib/Infrastructure/insets_extension.dart @@ -0,0 +1,14 @@ +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +extension InsetsExtension on EdgeInsetsGeometry { + copyWith(EdgeInsetsGeometry g) => add(g); + // + EdgeInsetsDirectional resolveToDirectional(ui.TextDirection direction) { + // + return EdgeInsetsDirectional.fromSTEB(direction == ui.TextDirection.ltr ? resolve(direction).left : resolve(direction).right, resolve(direction).top, + direction == ui.TextDirection.ltr ? resolve(direction).right : resolve(direction).left, resolve(direction).bottom); + // + } +} diff --git a/lib/astromic_mobile_elements.dart b/lib/astromic_mobile_elements.dart index 36162cc..d202032 100644 --- a/lib/astromic_mobile_elements.dart +++ b/lib/astromic_mobile_elements.dart @@ -6,8 +6,4 @@ export './src/Widgets/widgets.astromic.dart'; export './src/Selectors/selectors.astromic.dart'; export './src/Toggles/toggles.astromic.dart'; export './src/Buttons/buttons.astromic.dart'; - -// export './src/5.Fields/fields.astromic.dart'; -// // -// export './src/styles/styles.astromic.dart'; -// export './src/configurations/configs.astromic.dart'; \ No newline at end of file +export './src/Fields/fields.astromic.dart'; diff --git a/lib/src/Fields/fields.astromic.dart b/lib/src/Fields/fields.astromic.dart new file mode 100644 index 0000000..fa7d6c5 --- /dev/null +++ b/lib/src/Fields/fields.astromic.dart @@ -0,0 +1,58 @@ +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +// +import 'src/text_field.dart'; +import 'src/configuration.dart'; +import 'src/style.dart'; +// +export 'src/configuration.dart'; +export 'src/style.dart'; + +class AstromicFields { + //S1 -- Text Field + static Widget text({ + required TextEditingController controller, + // + void Function(String v)? onChanged, + void Function(String v)? onSubmited, + // + required AstromicFieldConfiguration configuration, + // + AutovalidateMode? validatingMode, + String? Function(bool isEnabled, bool isFocused, String? text)? validator, + List? inputFormatters, + bool? obscureText, + // + // + required AstromicFieldStyle Function(bool isEnabled, bool isFocused) style, + // + //s1 -- Content + String? hint, + // + Widget Function(bool isEnabled, bool isFocused, VoidCallback stateSetter)? prefixWidget, + Widget Function(bool isEnabled, bool isFocused, VoidCallback stateSetter)? suffixWidget, + Widget Function(bool isEnabled, bool isFocused)? messageBuilder, + // + Iterable? contextButtons, + }) => + Column( + children: [ + AstromicTextField( + textController: controller, + onChanged: onChanged, + onSubmited: onSubmited, + configuration: configuration, + validatingMode: validatingMode, + validator: validator, + inputFormatters: inputFormatters, + obscureText: obscureText, + style: style, + hint: hint, + prefixWidget: prefixWidget, + suffixWidget: suffixWidget, + messageBuilder: messageBuilder, + contextButtons: contextButtons, + ), + ], + ); +} diff --git a/lib/src/Fields/src/configuration.dart b/lib/src/Fields/src/configuration.dart new file mode 100644 index 0000000..c3c4d5d --- /dev/null +++ b/lib/src/Fields/src/configuration.dart @@ -0,0 +1,85 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'dart:ui' as ui; + +import 'package:flutter/services.dart'; + +class AstromicFieldConfiguration { + // + final bool isEnabled; + final bool isFixedHeight; + final bool isTextArea; + // + final bool withAutofocus; + final bool respectBorderWidthPadding; + final bool withObscurity; + final bool withAutomaticDirectionalitySwitching; + final bool unfocusOnTapOutside; + final bool resetMessageOnChange; + // + final ui.TextDirection? hintDirection; + final ui.TextDirection? textDirection; + final ui.TextDirection? messageDirection; + // + final TextInputType inputType; + final TextInputAction inputAction; + // + final MaxLengthEnforcement maxLengthEnforcement; + // + const AstromicFieldConfiguration({ + this.isEnabled = true, + this.respectBorderWidthPadding = false, + this.isFixedHeight = false, + this.isTextArea = false, + this.withAutofocus = false, + this.withObscurity = false, + this.withAutomaticDirectionalitySwitching = false, + this.unfocusOnTapOutside = false, + this.resetMessageOnChange = false, + // + this.hintDirection, + this.textDirection, + this.messageDirection, + // + this.inputType = TextInputType.text, + this.inputAction = TextInputAction.done, + this.maxLengthEnforcement = MaxLengthEnforcement.none, + }); + // + + AstromicFieldConfiguration copyWith({ + bool? isEnabled, + bool? isFixedHeight, + bool? isTextArea, + bool? withAutofocus, + bool? respectBorderWidthPadding, + bool? withObscurity, + bool? withAutomaticDirectionalitySwitching, + bool? unfocusOnTapOutside, + bool? resetMessageOnChange, + ui.TextDirection? hintDirection, + ui.TextDirection? textDirection, + ui.TextDirection? messageDirection, + TextInputType? inputType, + TextInputAction? inputAction, + TextCapitalization? capitalizationMode, + MaxLengthEnforcement? maxLengthEnforcement, + }) { + return AstromicFieldConfiguration( + isEnabled: isEnabled ?? this.isEnabled, + isFixedHeight: isFixedHeight ?? this.isFixedHeight, + isTextArea: isTextArea ?? this.isTextArea, + withAutofocus: withAutofocus ?? this.withAutofocus, + respectBorderWidthPadding: respectBorderWidthPadding ?? this.respectBorderWidthPadding, + withObscurity: withObscurity ?? this.withObscurity, + withAutomaticDirectionalitySwitching: withAutomaticDirectionalitySwitching ?? this.withAutomaticDirectionalitySwitching, + unfocusOnTapOutside: unfocusOnTapOutside ?? this.unfocusOnTapOutside, + resetMessageOnChange: resetMessageOnChange ?? this.resetMessageOnChange, + hintDirection: hintDirection ?? this.hintDirection, + textDirection: textDirection ?? this.textDirection, + messageDirection: messageDirection ?? this.messageDirection, + inputType: inputType ?? this.inputType, + inputAction: inputAction ?? this.inputAction, + maxLengthEnforcement: maxLengthEnforcement ?? this.maxLengthEnforcement, + ); + } +} diff --git a/lib/src/Fields/src/style.dart b/lib/src/Fields/src/style.dart new file mode 100644 index 0000000..469c853 --- /dev/null +++ b/lib/src/Fields/src/style.dart @@ -0,0 +1,107 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:flutter/material.dart'; + +class AstromicFieldStyle { + //s1 - Styling Configs + final bool isFilled; + //s1 - Sizing & Spacing + final double? fixedHeight; + // + final int minLines; + final int maxLines; + final int? maxLength; + // + final TextAlign textAlign; + final TextAlignVertical textAlignVertical; + // + final EdgeInsetsGeometry contentPadding; + final EdgeInsetsGeometry messagePadding; + // + final double prefixSpacing; + final double prefixSize; + final double suffixSpacing; + final double suffixSize; + // + //s1 - Colors + final Color fillColor; + final Color? cursorColor; + //s1 - Styling + final TextStyle? hintStyle; + final TextStyle? textStyle; + final TextStyle? messageStyle; + //s1 - MISC + final InputBorder? border; + + const AstromicFieldStyle({ + this.isFilled = true, + // + this.minLines = 1, + this.maxLines = 1, + this.maxLength, + this.textAlign = TextAlign.start, + this.textAlignVertical = TextAlignVertical.center, + // + this.fixedHeight, + this.contentPadding = EdgeInsets.zero, + this.messagePadding = EdgeInsets.zero, + this.prefixSpacing = 4, + this.prefixSize = 24, + this.suffixSpacing = 4, + this.suffixSize = 24, + // + this.fillColor = const Color(0xffffffff), + this.cursorColor, + this.hintStyle, + this.textStyle, + this.messageStyle, + // + this.border, + }); + // + AstromicFieldStyle copyWith({ + bool? isFilled, + double? fixedHeight, + int? minLines, + int? maxLines, + int? maxLength, + TextAlign? textAlign, + TextAlignVertical? textAlignVertical, + EdgeInsetsGeometry? contentPadding, + EdgeInsetsGeometry? messagePadding, + double? prefixSpacing, + double? prefixSize, + CrossAxisAlignment? prefixAlignment, + double? suffixSpacing, + double? suffixSize, + CrossAxisAlignment? suffixAlignment, + Color? fillColor, + Color? cursorColor, + TextStyle? hintStyle, + TextStyle? textStyle, + TextStyle? messageStyle, + InputBorder? border, + }) { + return AstromicFieldStyle( + isFilled: isFilled ?? this.isFilled, + fixedHeight: fixedHeight ?? this.fixedHeight, + minLines: minLines ?? this.minLines, + maxLines: maxLines ?? this.maxLines, + maxLength: maxLength ?? this.maxLength, + textAlign: textAlign ?? this.textAlign, + textAlignVertical: textAlignVertical ?? this.textAlignVertical, + contentPadding: contentPadding ?? this.contentPadding, + messagePadding: messagePadding ?? this.messagePadding, + prefixSpacing: prefixSpacing ?? this.prefixSpacing, + prefixSize: prefixSize ?? this.prefixSize, + suffixSpacing: suffixSpacing ?? this.suffixSpacing, + suffixSize: suffixSize ?? this.suffixSize, + fillColor: fillColor ?? this.fillColor, + cursorColor: cursorColor ?? this.cursorColor, + hintStyle: hintStyle ?? this.hintStyle, + textStyle: textStyle ?? this.textStyle, + messageStyle: messageStyle ?? this.messageStyle, + border: border ?? this.border, + ); + } + // +} diff --git a/lib/src/Fields/src/text_field.dart b/lib/src/Fields/src/text_field.dart new file mode 100644 index 0000000..20fbf64 --- /dev/null +++ b/lib/src/Fields/src/text_field.dart @@ -0,0 +1,377 @@ +// ignore_for_file: depend_on_referenced_packages +//SECTION - Imports +// +//s1 PACKAGES +//--------------- +//s2 CORE +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:intl/intl.dart' as intl; +import 'dart:ui' as ui; + +//s2 3RD-PARTY +// +//s1 DEPENDENCIES +//--------------- +//s2 SERVICES +//s2 MODELS +import 'configuration.dart'; +import 'style.dart'; +//s2 MISC +import '../../../Infrastructure/insets_extension.dart'; + +//!SECTION - Imports +// +//SECTION - Exports +//!SECTION - Exports +// +class AstromicTextField extends StatefulWidget { + //SECTION - Widget Arguments + //s1 -- Functionality + final TextEditingController textController; + // + final void Function(String v)? onChanged; + final void Function(String v)? onSubmited; + // + //s1 -- Configurations + final AstromicFieldConfiguration configuration; + // + final AutovalidateMode? validatingMode; + final String? Function(bool isEnabled, bool isFocused, String? text)? validator; + final List? inputFormatters; + final bool? obscureText; + // + //s1 -- Style + final AstromicFieldStyle Function(bool isEnabled, bool isFocused) style; + // + //s1 -- Content + final String? hint; + // + final Widget Function(bool isEnabled, bool isFocused, VoidCallback stateSetter)? prefixWidget; + final Widget Function(bool isEnabled, bool isFocused, VoidCallback stateSetter)? suffixWidget; + final Widget Function(bool isEnabled, bool isFocused)? messageBuilder; + // + final Iterable? contextButtons; + //!SECTION + // + const AstromicTextField({ + super.key, + // + required this.textController, + this.onChanged, + this.onSubmited, + // + required this.configuration, + // + this.validatingMode, + this.validator, + this.inputFormatters, + this.obscureText, + // + required this.style, + // + this.hint, + this.prefixWidget, + this.suffixWidget, + this.messageBuilder, + this.contextButtons, + }); + + @override + State createState() => _AstromicTextFieldState(); +} + +class _AstromicTextFieldState extends State { + // + //SECTION - State Variables + //s1 --Controllers + late TextEditingController _textController; + //s1 --Controllers + // + //s1 --State + late bool _isEnabled; + final FocusNode _focusNode = FocusNode(); + late bool _isFocused; + // + //s1 --State + // + //s1 --Constants + //s1 --Constants + //!SECTION + + @override + void initState() { + super.initState(); + // + //SECTION - State Variables initializations & Listeners + //s1 --Controllers & Listeners + _textController = widget.textController; + //s1 --Controllers & Listeners + // + //s1 --State + _isEnabled = widget.configuration.isEnabled; + _isFocused = false; + //s1 --State + // + //s1 --Late & Async Initializers + //s1 --Late & Async Initializers + //!SECTION + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // + //SECTION - State Variables initializations & Listeners + //s1 --State + _focusNode.addListener(() { + if (mounted) { + setState(() { + _isFocused = _focusNode.hasFocus; + }); + } + }); + //s1 --State + //!SECTION + } + + //SECTION - Dumb Widgets + //!SECTION + + //SECTION - Stateless functions + ui.TextDirection finalTextDirection() { + ui.TextDirection fromLocale = intl.Bidi.isRtlLanguage(Localizations.localeOf(context).languageCode) ? ui.TextDirection.rtl : ui.TextDirection.ltr; + // + if (widget.configuration.textDirection != null) { + // Get form Style + return widget.configuration.textDirection!; + } else { + // Detect form Text + return _textController.text != '' + ? widget.configuration.withAutomaticDirectionalitySwitching + ? intl.Bidi.startsWithLtr(_textController.text) + ? ui.TextDirection.ltr + : ui.TextDirection.rtl + : fromLocale + : fromLocale; + } + } + + //- + //---------------------------------------------------------------- + //- + EdgeInsetsGeometry finalVerticalPadding( + AstromicFieldStyle style, + ) { + double desiredFixedHeight = style.fixedHeight ?? 0; + // + double providedPadding = style.contentPadding.vertical; + // + double borderOffset = widget.configuration.respectBorderWidthPadding ? style.border?.borderSide.strokeInset ?? 0.0 : 0.0; + // + double fontOffset = + ((widget.textController.text.isNotEmpty ? widget.style(_isEnabled, _isFocused).textStyle : widget.style(_isEnabled, _isFocused).hintStyle) ?? const TextStyle(fontSize: 16)).fontSize! * + (((widget.textController.text.isNotEmpty ? widget.style(_isEnabled, _isFocused).textStyle : widget.style(_isEnabled, _isFocused).hintStyle) ?? const TextStyle(height: 1.0)).height!); + // + double finalVertical = + //- + widget.configuration.isFixedHeight + ? + //- + widget.configuration.isTextArea + ? + //s1 Fixed Height with Text Area + borderOffset + providedPadding + : + //s1 Fixed Height and not Text Area + desiredFixedHeight - (fontOffset + borderOffset) + //s1 - Not Fixed Height + : providedPadding + borderOffset; + // + return EdgeInsets.symmetric( + vertical: finalVertical / 2, + ); + } + //!SECTION + + //SECTION - Action Callbacks + //!SECTION + + @override + Widget build(BuildContext context) { + //SECTION - Build Setup + //s1 --Values + //double w = MediaQuery.of(context).size.width; + //double h = MediaQuery.of(context).size.height; + //s1 --Values + // + //s1 --Contexted Widgets + InputDecoration inputDecoration = InputDecoration( + //s1 -- Functionality + enabled: widget.configuration.isEnabled, + //s1 -- Configurations + isDense: true, + hintTextDirection: widget.configuration.hintDirection ?? finalTextDirection(), + //s1 -- Style + filled: widget.style(_isEnabled, _isFocused).isFilled, + fillColor: widget.style(_isEnabled, _isFocused).fillColor, + // + hintStyle: widget.style(_isEnabled, _isFocused).hintStyle, + // + enabledBorder: widget.style(_isEnabled, false).border, + focusedBorder: widget.style(_isEnabled, true).border, + disabledBorder: widget.style(_isEnabled, _isFocused).border, + errorBorder: widget.style(_isEnabled, false).border, + focusedErrorBorder: widget.style(_isEnabled, true).border, + // + errorStyle: const TextStyle(height: 0), + contentPadding: finalVerticalPadding(widget.style(_isEnabled, _isFocused)), + //s1 -- Content + hintText: widget.hint, + // + prefixIcon: widget.prefixWidget != null + ? Container( + margin: EdgeInsetsDirectional.fromSTEB( + widget.style(_isEnabled, _isFocused).prefixSpacing, 0, widget.style(_isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).start, 0), + child: widget.prefixWidget!(_isEnabled, _isFocused, () { + setState(() {}); + }), + ) + : SizedBox(width: widget.style(_isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).start), + // + prefixIconConstraints: widget.prefixWidget != null + ? widget.style(_isEnabled, _isFocused).prefixSize != 0 + ? BoxConstraints.expand( + width: widget.style(_isEnabled, _isFocused).prefixSize + + widget.style(_isEnabled, _isFocused).prefixSpacing + + widget.style(_isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).start, + height: widget.style(_isEnabled, _isFocused).prefixSize, + ) + : const BoxConstraints.tightForFinite() + : BoxConstraints.tightForFinite(width: widget.style(_isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).start), + // + suffixIcon: widget.suffixWidget != null + ? Container( + margin: EdgeInsetsDirectional.fromSTEB( + widget.style(_isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).end, 0, widget.style(_isEnabled, _isFocused).suffixSpacing, 0), + child: widget.suffixWidget!(_isEnabled, _isFocused, () { + setState(() {}); + }), + ) + : SizedBox(width: widget.style(_isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).end), + suffixIconConstraints: widget.suffixWidget != null + ? widget.style(_isEnabled, _isFocused).suffixSize != 0 + ? BoxConstraints.expand( + width: widget.style(_isEnabled, _isFocused).suffixSize + + widget.style(_isEnabled, _isFocused).suffixSpacing + + widget.style(_isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).end, + height: widget.style(_isEnabled, _isFocused).suffixSize, + ) + : const BoxConstraints.tightForFinite() + : BoxConstraints.tightForFinite(width: widget.style(_isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).end), + ); + //s1 --Contexted Widgets + //!SECTION + // + //SECTION - Build Return + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Directionality( + textDirection: finalTextDirection(), + child: Container( + height: widget.configuration.isFixedHeight + ? !widget.configuration.isTextArea + ? null + : widget.style(_isEnabled, _isFocused).fixedHeight + : null, + alignment: Alignment.center, + child: TextFormField( + //s1 -- Functionality + controller: _textController, + focusNode: _focusNode, + textInputAction: widget.configuration.inputAction, + // + onChanged: (v) { + setState(() { + if (widget.onChanged != null) { + widget.onChanged!(v); + } + }); + }, + // + onFieldSubmitted: (v) { + // + if (widget.configuration.inputAction == TextInputAction.next) { + _focusNode.nextFocus(); + } + if (widget.onSubmited != null) { + widget.onSubmited!(v); + } + }, + // + onTapOutside: (tapEvent) { + if (widget.configuration.unfocusOnTapOutside) { + _focusNode.unfocus(); + } + }, + // + //s1 -- Configurations + autovalidateMode: widget.validatingMode, + autofocus: widget.configuration.withAutofocus, + keyboardType: widget.configuration.inputType, + textDirection: finalTextDirection(), + obscureText: widget.configuration.withObscurity ? (widget.obscureText ?? false) : false, + inputFormatters: widget.inputFormatters, + // + minLines: widget.configuration.isFixedHeight && widget.configuration.isTextArea ? null : widget.style(_isEnabled, _isFocused).minLines, + maxLines: widget.configuration.isFixedHeight + ? widget.configuration.isTextArea + ? null + : widget.style(_isEnabled, _isFocused).maxLines + : widget.style(_isEnabled, _isFocused).maxLines, + + // + maxLength: widget.style(_isEnabled, _isFocused).maxLength, + maxLengthEnforcement: widget.configuration.maxLengthEnforcement, + // + expands: widget.configuration.isFixedHeight && widget.configuration.isTextArea ? true : false, + // - Validation + validator: widget.validator != null ? (s) => widget.validator!(_isEnabled, _isFocused, s) : null, + // - Validation + //s1 -- Style + style: widget.style(_isEnabled, _isFocused).textStyle, + cursorColor: widget.style(_isEnabled, _isFocused).cursorColor, + textAlign: widget.style(_isEnabled, _isFocused).textAlign, + textAlignVertical: widget.style(_isEnabled, _isFocused).textAlignVertical, + // + //s1 -- Input Decoration + decoration: inputDecoration, + //s1 -- Content + contextMenuBuilder: (_, state) { + List baseContextButtons = state.contextMenuButtonItems; + if (widget.contextButtons != null) { + baseContextButtons.addAll(widget.contextButtons!); + } + return AdaptiveTextSelectionToolbar.buttonItems( + buttonItems: baseContextButtons, + anchors: state.contextMenuAnchors, + ); + }, + ), + ), + ), + widget.messageBuilder != null ? widget.messageBuilder!(_isEnabled, _isFocused) : Container() + ], + ); + //!SECTION + } + + @override + void dispose() { + //SECTION - Disposable variables + //!SECTION + super.dispose(); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 35a7c2f..291eb7d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,7 @@ dependencies: flutter_svg: ^2.0.10+1 octo_image: ^2.0.0 flutter_switch: ^0.3.2 + intl: ^0.19.0 # ##!SECTION --Dependencies #