This commit is contained in:
2025-02-09 20:39:43 +02:00
parent 3641db54d3
commit 4a0ff120f7
47 changed files with 1273 additions and 1159 deletions

View File

@@ -1,16 +1,14 @@
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
//
import 'src/action_field.dart';
import 'src/text_field.dart';
import 'src/configuration.dart';
import 'src/style.dart';
import 'src/action_field.dart';
import 'src/models/models.exports.dart';
//
export 'src/configuration.dart';
export 'src/style.dart';
export 'src/models/models.exports.dart';
export 'src/enums/enums.exports.dart';
class AstromicFields {
//S1 -- Text Field
/// Astromic TextField element.
static Widget text({
required TextEditingController controller,
Key? stateKey,
@@ -18,15 +16,9 @@ class AstromicFields {
void Function(String v)? onChanged,
void Function(String v)? onSubmited,
//
required AstromicFieldConfiguration configuration,
AstromicFieldConfiguration? configuration,
//
AutovalidateMode? validatingMode,
String? Function(bool isEnabled, bool isFocused, String? text)? validator,
List<TextInputFormatter>? inputFormatters,
bool? obscureText,
//
//
required AstromicFieldStyle Function(bool isEnabled, bool isFocused) style,
AstromicFieldStyle Function(bool isEnabled, bool isFocused)? style,
//
String? hint,
//
@@ -44,10 +36,6 @@ class AstromicFields {
onChanged: onChanged,
onSubmited: onSubmited,
configuration: configuration,
validatingMode: validatingMode,
validator: validator,
inputFormatters: inputFormatters,
obscureText: obscureText,
style: style,
hint: hint,
prefixWidget: prefixWidget,
@@ -58,7 +46,7 @@ class AstromicFields {
],
);
//S1 -- Action Field
/// Astromic ActionField element.
static Widget action<T>(
{Key? stateKey,
(T item, String label)? initialValue,
@@ -66,15 +54,13 @@ class AstromicFields {
//
Future<(T item, String label)?> Function((T item, String label)? currentValue)? onTap,
Future<(T item, String label)?> Function((T item, String label)? currentValue)? onHold,
required String Function(String? oldValue, String newValue) textFieldMapper,
/// Map the old controller value and the new selected value to how it will look in the field. e.g Adding a new choosen value as a list in the field.
required String Function(String? oldValue, String newValue) onValueChangedMapper,
//
required AstromicFieldConfiguration configuration,
AstromicFieldConfiguration? configuration,
//
AutovalidateMode? validatingMode,
String? Function(bool isEnabled, String? text)? validator,
List<TextInputFormatter>? inputFormatters,
//
required AstromicFieldStyle Function(bool isEnabled) style,
AstromicFieldStyle Function(bool isEnabled)? style,
//
String? hint,
//
@@ -89,11 +75,8 @@ class AstromicFields {
initialValue: initialValue,
onTap: onTap,
onHold: onHold,
textFieldMapper: textFieldMapper,
onValueChangedMapper: onValueChangedMapper,
configuration: configuration,
validatingMode: validatingMode,
validator: validator,
inputFormatters: inputFormatters,
style: style,
hint: hint,
prefixWidget: prefixWidget,

View File

@@ -1,51 +1,31 @@
// ignore_for_file: depend_on_referenced_packages
//SECTION - Imports
//
//s1 PACKAGES
//---------------
//s2 CORE
import '../../../Infrastructure/insets_extension.dart';
import '../../../Infrastructure/misc_extensions.dart';
import '../../../astromic_mobile_elements.dart';
//s1 Imports
//s2 Core Package Imports
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart' as intl;
import 'dart:ui' as ui;
//s2 1st-party Package Imports
//s2 3rd-party Package Imports
//s2 Dependancies Imports
//s3 Routes
//s3 Services
//s3 Models
import 'base.dart';
import 'models/models.exports.dart';
//s1 Exports
//s2 3RD-PARTY
//
//s1 DEPENDENCIES
//---------------
//s2 SERVICES
//s2 MODELS
//s2 MISC
//!SECTION - Imports
//
//SECTION - Exports
//!SECTION - Exports
//
class AstromicActionField<T> extends StatefulWidget {
//SECTION - Widget Arguments
//s1 -- Functionality
final Key? stateKey;
final (T item, String label)? initialValue;
final TextEditingController textController;
final (T item, String label)? initialValue;
final Future<(T item, String label)?> Function((T item, String label)? currentValue)? onTap;
final Future<(T item, String label)?> Function((T item, String label)? currentValue)? onHold;
final String Function(String? oldValue, String newValue) textFieldMapper;
final String Function(String? oldValue, String newValue) onValueChangedMapper;
//
//s1 -- Configurations
final AstromicFieldConfiguration configuration;
//
final AutovalidateMode? validatingMode;
final String? Function(bool isEnabled, String? text)? validator;
final List<TextInputFormatter>? inputFormatters;
final bool? obscureText;
final AstromicFieldConfiguration? configuration;
//
//s1 -- Style
final AstromicFieldStyle Function(bool isEnabled) style;
final AstromicFieldStyle Function(bool isEnabled)? style;
//
//s1 -- Content
final String? hint;
@@ -61,18 +41,12 @@ class AstromicActionField<T> extends StatefulWidget {
this.initialValue,
this.stateKey,
required this.textController,
required this.textFieldMapper,
required this.onValueChangedMapper,
this.onTap,
this.onHold,
//
required this.configuration,
//
this.validatingMode,
this.validator,
this.inputFormatters,
this.obscureText,
//
required this.style,
this.configuration,
this.style,
//
this.hint,
this.prefixWidget,
@@ -87,15 +61,14 @@ class AstromicActionField<T> extends StatefulWidget {
class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> {
//
//SECTION - State Variables
//s1 --State
(T item, String label)? _currentValue;
//s1 --State
//
//s1 --Controllers
late TextEditingController _textController;
//s1 --Controllers
//
//s1 --State
(T item, String label)? _currentValue;
//
//s1 --State
//
//s1 --Constants
//s1 --Constants
//!SECTION
@@ -105,15 +78,15 @@ class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> {
super.initState();
//
//SECTION - State Variables initializations & Listeners
//s1 --State
//s1 --State
//
//s1 --Controllers & Listeners
_currentValue = widget.initialValue;
_textController = widget.textController;
_textController.text = widget.initialValue?.$2 ?? '';
_textController.text = _currentValue?.$2 ?? '';
//s1 --Controllers & Listeners
//
//s1 --State
//s1 --State
//
//s1 --Late & Async Initializers
//s1 --Late & Async Initializers
//!SECTION
@@ -126,6 +99,10 @@ class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> {
//SECTION - State Variables initializations & Listeners
//s1 --State
//s1 --State
//
//s1 --Controllers & Listeners
//s1 --Controllers & Listeners
//
//!SECTION
}
@@ -133,81 +110,6 @@ class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> {
//!SECTION
//SECTION - Stateless functions
getTextHeight(String text, TextStyle style, ui.TextDirection direction) {
final span = TextSpan(text: text, style: style);
final tp = TextPainter(text: span, textDirection: direction);
tp.layout(maxWidth: double.infinity);
return tp.height;
}
//-
//----------------------------------------------------------------
//-
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, {
bool forceRespectBorder = false,
}) {
double desiredFixedHeight = style.fixedHeight ?? 0;
//
double providedPadding = style.contentPadding.vertical;
//
double borderOffset = widget.configuration.respectBorderWidthPadding || forceRespectBorder ? style.border?.borderSide.strokeInset ?? 0.0 : 0.0;
//
double fontOffset = getTextHeight(
widget.textController.text.isNotEmpty
? widget.textController.text
: (widget.hint?.isNotEmpty ?? false)
? widget.hint!
: "",
widget.textController.text.isNotEmpty && widget.style(widget.configuration.isEnabled).textStyle != null
? widget.style(widget.configuration.isEnabled).textStyle!
: widget.style(widget.configuration.isEnabled).hintStyle != null
? widget.style(widget.configuration.isEnabled).hintStyle!
: const TextStyle(),
finalTextDirection(),
);
//
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 / 2);
//
return EdgeInsets.symmetric(
vertical: finalVertical / 2,
);
}
//!SECTION
//SECTION - Action Callbacks
@@ -222,195 +124,59 @@ class _AstromicActionFieldState<T> extends State<AstromicActionField<T>> {
//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(widget.configuration.isEnabled).isFilled,
fillColor: widget.style(widget.configuration.isEnabled).fillColor,
//
hintStyle: widget.style(widget.configuration.isEnabled).hintStyle,
//
enabledBorder: widget.style(widget.configuration.isEnabled).border,
focusedBorder: widget.style(widget.configuration.isEnabled).border,
disabledBorder: widget.style(widget.configuration.isEnabled).border,
errorBorder: widget.style(widget.configuration.isEnabled).border,
focusedErrorBorder: widget.style(widget.configuration.isEnabled).border,
//
errorStyle: const TextStyle(height: 0),
contentPadding: finalVerticalPadding(widget.style(widget.configuration.isEnabled)),
//s1 -- Content
hintText: widget.hint,
//
prefixIcon: widget.prefixWidget != null &&
widget.prefixWidget!(widget.configuration.isEnabled, () {
setState(() {});
}) !=
null
? Container(
margin: EdgeInsetsDirectional.fromSTEB(
widget.style(widget.configuration.isEnabled).prefixSpacing, 0, widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).start, 0),
child: widget.prefixWidget!(widget.configuration.isEnabled, () {
setState(() {});
}),
)
: SizedBox(width: widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).start),
//
prefixIconConstraints: widget.prefixWidget != null &&
widget.prefixWidget!(widget.configuration.isEnabled, () {
setState(() {});
}) !=
null
? widget.style(widget.configuration.isEnabled).prefixSize != 0
? BoxConstraints.expand(
width: widget.style(widget.configuration.isEnabled).prefixSize +
widget.style(widget.configuration.isEnabled).prefixSpacing +
widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).start,
height: widget.style(widget.configuration.isEnabled).prefixSize,
)
: const BoxConstraints.tightForFinite()
: BoxConstraints.tightForFinite(width: widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).start),
//
suffixIcon: widget.suffixWidget != null &&
widget.suffixWidget!(widget.configuration.isEnabled, () {
setState(() {});
}) !=
null
? Container(
margin: EdgeInsetsDirectional.fromSTEB(
widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).end, 0, widget.style(widget.configuration.isEnabled).suffixSpacing, 0),
child: widget.suffixWidget!(widget.configuration.isEnabled, () {
setState(() {});
}),
)
: SizedBox(width: widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).end),
suffixIconConstraints: widget.suffixWidget != null &&
widget.suffixWidget != null &&
widget.suffixWidget!(widget.configuration.isEnabled, () {
setState(() {});
}) !=
null
? widget.style(widget.configuration.isEnabled).suffixSize != 0
? BoxConstraints.expand(
width: widget.style(widget.configuration.isEnabled).suffixSize +
widget.style(widget.configuration.isEnabled).suffixSpacing +
widget.style(widget.configuration.isEnabled).contentPadding.resolveToDirectional(finalTextDirection()).end,
height: widget.style(widget.configuration.isEnabled).suffixSize,
)
: const BoxConstraints.tightForFinite()
: BoxConstraints.tightForFinite(width: widget.style(widget.configuration.isEnabled).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(widget.configuration.isEnabled).fixedHeight
: null,
alignment: widget.style(widget.configuration.isEnabled).textAlignVertical.toAlignment(),
child: Stack(
children: [
TextFormField(
//s1 -- Functionality
key: widget.stateKey,
controller: _textController,
textInputAction: widget.configuration.inputAction,
//
//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(widget.configuration.isEnabled).minLines,
maxLines: widget.configuration.isFixedHeight
? widget.configuration.isTextArea
? null
: widget.style(widget.configuration.isEnabled).maxLines
: widget.style(widget.configuration.isEnabled).maxLines,
//
maxLength: widget.style(widget.configuration.isEnabled).maxLength,
maxLengthEnforcement: widget.configuration.maxLengthEnforcement,
//
expands: widget.configuration.isFixedHeight && widget.configuration.isTextArea ? true : false,
// - Validation
validator: widget.validator != null ? (s) => widget.validator!(widget.configuration.isEnabled, s) : null,
// - Validation
//s1 -- Style
style: widget.style(widget.configuration.isEnabled).textStyle,
cursorColor: widget.style(widget.configuration.isEnabled).cursorColor,
textAlign: widget.style(widget.configuration.isEnabled).textAlign,
textAlignVertical: widget.style(widget.configuration.isEnabled).textAlignVertical,
//
//s1 -- Input Decoration
decoration: inputDecoration,
),
SizedBox(
width: double.infinity,
height: finalVerticalPadding(widget.style(widget.configuration.isEnabled), forceRespectBorder: true).vertical * 2,
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () async {
if (widget.onTap != null) {
(T item, String label)? c = _currentValue;
(T item, String label)? newValue = await widget.onTap!(_currentValue);
if (newValue != null) {
setState(() {
_currentValue = newValue;
_textController.text = widget.textFieldMapper(c?.$2, newValue.$2);
});
}
}
},
splashFactory: NoSplash.splashFactory,
onLongPress: () async {
if (widget.onHold != null) {
(T item, String label)? c = _currentValue;
(T item, String label)? newValue = await widget.onHold!(_currentValue);
if (newValue != null) {
setState(() {
_currentValue = newValue;
_textController.text = widget.textFieldMapper(c?.$2, newValue.$2);
});
}
}
},
customBorder: widget.style(widget.configuration.isEnabled).border,
highlightColor: Colors.transparent,
),
),
)
],
),
//SECTION - Build Return
return AstromicFieldBase(
key: widget.key,
textController: _textController,
stateKey: widget.stateKey,
// onChanged: (v) {},
// onSubmited: (v) {},
configuration: widget.configuration,
style: widget.style == null ? null : (enabled, focused) => widget.style!(enabled),
hint: widget.hint,
prefixWidget: widget.prefixWidget == null ? null : (enabled, focused, stateSetter) => widget.prefixWidget!(enabled, stateSetter),
suffixWidget: widget.suffixWidget == null ? null : (enabled, focused, stateSetter) => widget.suffixWidget!(enabled, stateSetter),
messageBuilder: widget.messageBuilder == null ? null : (enabled, focused) => widget.messageBuilder!(enabled),
fieldStackedWidget: (finalHeight, border) => SizedBox(
width: double.infinity,
height: finalHeight,
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () async {
if (widget.onTap != null) {
(T item, String label)? c = _currentValue;
(T item, String label)? newValue = await widget.onTap!(_currentValue);
if (newValue != null) {
setState(() {
_currentValue = newValue;
_textController.text = widget.onValueChangedMapper(c?.$2, newValue.$2);
});
}
}
},
splashFactory: NoSplash.splashFactory,
onLongPress: () async {
if (widget.onHold != null) {
(T item, String label)? c = _currentValue;
(T item, String label)? newValue = await widget.onHold!(_currentValue);
if (newValue != null) {
setState(() {
_currentValue = newValue;
_textController.text = widget.onValueChangedMapper(c?.$2, newValue.$2);
});
}
}
},
customBorder: border,
highlightColor: Colors.transparent,
),
),
widget.messageBuilder != null &&
widget.messageBuilder!(
widget.configuration.isEnabled,
) !=
null
? Padding(
padding: widget.style(widget.configuration.isEnabled).messagePadding,
child: widget.messageBuilder!(widget.configuration.isEnabled) ?? Container(),
)
: Container()
],
),
);
//!SECTION
}

View File

@@ -0,0 +1,450 @@
//s1 Imports
//s2 Core Package Imports
import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl;
import 'dart:ui' as ui;
//s2 1st-party Package Imports
import 'package:astromic_extensions/astromic_extensions.dart';
//s2 3rd-party Package Imports
//s2 Dependancies Imports
//s3 Routes
//s3 Services
//s3 Models
import '../../../Dependencies/gradient_border/gradient_borders.dart';
import '../../../Dependencies/gradient_border/input_borders/gradient_underline_input_border.dart';
import 'enums/enums.exports.dart';
import 'models/models.exports.dart';
//s1 Exports
class AstromicFieldBase extends StatefulWidget {
//SECTION - Widget Arguments
//s1 -- Functionality
final TextEditingController textController;
final Key? stateKey;
//
final void Function(String v)? onChanged;
final void Function(String v)? onSubmited;
//
//s1 -- Configurations
final AstromicFieldConfiguration? configuration;
//
//s1 -- Style
final AstromicFieldStyle Function(bool isEnabled, bool isFocused)? style;
//
//s1 -- Content
final Widget Function(double finalHeight, ShapeBorder? border)? fieldStackedWidget;
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<ContextMenuButtonItem>? contextButtons;
//!SECTION
//
const AstromicFieldBase({
super.key,
//
required this.textController,
this.stateKey,
this.onChanged,
this.onSubmited,
//
this.configuration,
//
this.style,
//
this.fieldStackedWidget,
this.hint,
this.prefixWidget,
this.suffixWidget,
this.messageBuilder,
this.contextButtons,
});
@override
State<AstromicFieldBase> createState() => _AstromicFieldBaseState();
}
class _AstromicFieldBaseState extends State<AstromicFieldBase> {
//
//SECTION - State Variables
//s1 --Controllers
late TextEditingController _textController;
//s1 --Controllers
//
//s1 --State
// late bool widget.configuration.isEnabled;
final FocusNode _focusNode = FocusNode();
late bool _isFocused;
//
late AstromicFieldStyle Function([bool isFocused]) _style;
late AstromicFieldConfiguration _config;
//
//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
// widget.configuration.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
_getTextHeight(String text, TextStyle style, ui.TextDirection direction) {
final span = TextSpan(text: text, style: style);
final tp = TextPainter(text: span, textDirection: direction);
tp.layout(maxWidth: double.infinity);
return tp.height;
}
ui.TextDirection _finalTextDirection() {
ui.TextDirection fromLocale = intl.Bidi.isRtlLanguage(Localizations.localeOf(context).languageCode) ? ui.TextDirection.rtl : ui.TextDirection.ltr;
//
if (_config.textDirection != null) {
// Get form Style
return _config.textDirection!;
} else {
// Detect form Text
return _textController.text != ''
? _config.withAutomaticDirectionalitySwitching
? intl.Bidi.startsWithLtr(_textController.text)
? ui.TextDirection.ltr
: ui.TextDirection.rtl
: fromLocale
: fromLocale;
}
}
EdgeInsetsGeometry _finalVerticalPadding(
AstromicFieldStyle style, {
bool? forceRespectBorder,
}) {
double desiredFixedHeight = style.fixedHeight ?? 0;
//
double providedPadding = style.contentPadding.vertical;
//
double borderOffset = (forceRespectBorder ?? _config.respectBorderWidthPadding) ? _finalBorderShape(style)?.borderSide.strokeInset ?? 0.0 : 0.0;
//
double fontOffset = _getTextHeight(
widget.textController.text.isNotEmpty
? widget.textController.text
: (widget.hint?.isNotEmpty ?? false)
? widget.hint!
: "",
widget.textController.text.isNotEmpty && _style().textStyle != null
? _style().textStyle!
: _style().hintStyle != null
? _style().hintStyle!
: const TextStyle(),
_finalTextDirection(),
);
//
double finalVertical =
//-
_config.isFixedHeight
?
//-
_config.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,
);
}
InputBorder? _finalBorderShape(AstromicFieldStyle style) {
InputBorder defaultBorder = const UnderlineInputBorder(borderSide: BorderSide(color: Colors.grey, width: 2));
switch (style.borderType) {
case AstromicFieldBorderType.cusotm:
return style.customBorder ?? defaultBorder;
case AstromicFieldBorderType.outlined:
return style.borderGradient != null
? GradientOutlineInputBorder(
gradient: style.borderGradient!,
gapPadding: 0,
width: style.borderWidth ?? 2.0,
borderRadius: style.borderRadius?.resolve(
_config.textDirection,
) ??
BorderRadius.circular(0))
: OutlineInputBorder(
borderSide: BorderSide(color: style.borderColor ?? Colors.grey, width: style.borderWidth ?? 2.0, style: BorderStyle.solid),
borderRadius: style.borderRadius?.resolve(
_config.textDirection,
) ??
BorderRadius.circular(0));
case AstromicFieldBorderType.underlined:
return style.borderGradient != null
? GradientUnderlineInputBorder(
gradient: style.borderGradient!,
gapPadding: 0,
width: style.borderWidth ?? 2.0,
borderRadius: style.borderRadius?.resolve(
_config.textDirection,
) ??
BorderRadius.circular(0))
: UnderlineInputBorder(
borderSide: BorderSide(color: style.borderColor ?? Colors.grey, width: style.borderWidth ?? 2.0, style: BorderStyle.solid),
borderRadius: style.borderRadius?.resolve(
_config.textDirection,
) ??
BorderRadius.circular(0));
}
}
//!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;
_config = widget.configuration ?? const AstromicFieldConfiguration();
_style = ([bool? isFocused]) => widget.style?.call(_config.isEnabled, isFocused ?? _isFocused) ?? const AstromicFieldStyle();
//s1 --Values
//
//s1 --Contexted Widgets
InputDecoration inputDecoration = InputDecoration(
//s1 -- Functionality
enabled: _config.isEnabled,
//s1 -- Configurations
isDense: true,
hintTextDirection: _config.hintDirection ?? _finalTextDirection(),
//s1 -- Style
filled: _style().isFilled,
fillColor: _style().fillColor,
//
hintStyle: _style().hintStyle,
//
enabledBorder: _finalBorderShape(_style(false)),
focusedBorder: _finalBorderShape(_style(true)),
disabledBorder: _finalBorderShape(_style()),
errorBorder: _finalBorderShape(_style(false)),
focusedErrorBorder: _finalBorderShape(_style(true)),
//
errorStyle: const TextStyle(height: 0),
contentPadding: _finalVerticalPadding(_style()),
//s1 -- Content
hintText: widget.hint,
//
prefixIcon: widget.prefixWidget != null &&
widget.prefixWidget!(_config.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? Container(
margin: EdgeInsetsDirectional.fromSTEB(_style().prefixSpacing, 0, _style().contentPadding.resolveToDirectional(_finalTextDirection()).start, 0),
child: widget.prefixWidget!(_config.isEnabled, _isFocused, () {
setState(() {});
}),
)
: SizedBox(width: _style().contentPadding.resolveToDirectional(_finalTextDirection()).start),
//
prefixIconConstraints: widget.prefixWidget != null &&
widget.prefixWidget!(_config.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? _style().prefixSize != 0
? BoxConstraints.expand(
width: _style().prefixSize + _style().prefixSpacing + _style().contentPadding.resolveToDirectional(_finalTextDirection()).start,
height: _style().prefixSize,
)
: const BoxConstraints.tightForFinite()
: BoxConstraints.tightForFinite(width: _style().contentPadding.resolveToDirectional(_finalTextDirection()).start),
//
suffixIcon: widget.suffixWidget != null &&
widget.suffixWidget!(_config.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? Container(
margin: EdgeInsetsDirectional.fromSTEB(_style().contentPadding.resolveToDirectional(_finalTextDirection()).end, 0, _style().suffixSpacing, 0),
child: widget.suffixWidget!(_config.isEnabled, _isFocused, () {
setState(() {});
}),
)
: SizedBox(width: _style().contentPadding.resolveToDirectional(_finalTextDirection()).end),
suffixIconConstraints: widget.suffixWidget != null &&
widget.suffixWidget != null &&
widget.suffixWidget!(_config.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? _style().suffixSize != 0
? BoxConstraints.expand(
width: _style().suffixSize + _style().suffixSpacing + _style().contentPadding.resolveToDirectional(_finalTextDirection()).end,
height: _style().suffixSize,
)
: const BoxConstraints.tightForFinite()
: BoxConstraints.tightForFinite(width: _style().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: _config.isFixedHeight
? !_config.isTextArea
? null
: _style().fixedHeight
: null,
alignment: _style().textAlignVertical.toAlignment(),
child: Stack(
children: [
TextFormField(
//s1 -- Functionality
key: widget.stateKey,
controller: _textController,
focusNode: _focusNode,
textInputAction: _config.inputAction,
//
onChanged: (v) {
setState(() {
if (widget.onChanged != null) {
widget.onChanged!(v);
}
});
},
//
onFieldSubmitted: (v) {
//
if (_config.inputAction == TextInputAction.next) {
_focusNode.nextFocus();
}
if (widget.onSubmited != null) {
widget.onSubmited!(v);
}
},
//
onTapOutside: (tapEvent) {
if (_config.unfocusOnTapOutside) {
_focusNode.unfocus();
}
},
//
//s1 -- Configurations
autovalidateMode: _config.validatingMode,
autofocus: _config.withAutofocus,
keyboardType: _config.inputType,
textDirection: _finalTextDirection(),
obscureText: _config.withObscurity ? (_config.isTextObscured ?? false) : false,
inputFormatters: _config.inputFormatters,
//
minLines: _config.isFixedHeight && _config.isTextArea ? null : _style().minLines,
maxLines: _config.isFixedHeight
? _config.isTextArea
? null
: _style().maxLines
: _style().maxLines,
//
maxLength: _style().maxLength,
maxLengthEnforcement: _config.maxLengthEnforcement,
//
expands: _config.isFixedHeight && _config.isTextArea ? true : false,
// - Validation
validator: _config.validator != null ? (s) => _config.validator!(_config.isEnabled, _isFocused, s) : null,
// - Validation
//s1 -- Style
style: _style().textStyle,
cursorColor: _style().cursorColor,
textAlign: _style().textAlign,
textAlignVertical: _style().textAlignVertical,
//
//s1 -- Input Decoration
decoration: inputDecoration,
//s1 -- Content
contextMenuBuilder: (_, state) {
List<ContextMenuButtonItem> baseContextButtons = state.contextMenuButtonItems;
if (widget.contextButtons != null) {
baseContextButtons.addAll(widget.contextButtons!);
}
return AdaptiveTextSelectionToolbar.buttonItems(
buttonItems: baseContextButtons,
anchors: state.contextMenuAnchors,
);
},
),
widget.fieldStackedWidget != null ? widget.fieldStackedWidget!(_finalVerticalPadding(_style(), forceRespectBorder: true).vertical * 2, _finalBorderShape(_style())) : Container(),
],
),
),
),
widget.messageBuilder != null &&
widget.messageBuilder!(
_config.isEnabled,
_isFocused,
) !=
null
? Padding(
padding: _style().messagePadding,
child: widget.messageBuilder!(_config.isEnabled, _isFocused) ?? Container(),
)
: Container()
],
);
//!SECTION
}
@override
void dispose() {
//SECTION - Disposable variables
//!SECTION
super.dispose();
}
}

View File

@@ -0,0 +1,5 @@
enum AstromicFieldBorderType {
outlined,
underlined,
cusotm,
}

View File

@@ -0,0 +1 @@
export './border_type.enum.dart';

View File

@@ -1,11 +1,13 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
/// Configuration model for the field element.
class AstromicFieldConfiguration {
//
final bool isEnabled;
final bool? isTextObscured;
final bool isFixedHeight;
final bool isTextArea;
//
@@ -24,8 +26,13 @@ class AstromicFieldConfiguration {
//
final MaxLengthEnforcement maxLengthEnforcement;
//
final AutovalidateMode? validatingMode;
final String? Function(bool isEnabled, bool isFocused, String? text)? validator;
final List<TextInputFormatter>? inputFormatters;
//
const AstromicFieldConfiguration({
this.isEnabled = true,
this.isTextObscured = false,
this.respectBorderWidthPadding = false,
this.isFixedHeight = false,
this.isTextArea = false,
@@ -41,11 +48,17 @@ class AstromicFieldConfiguration {
this.inputType = TextInputType.text,
this.inputAction = TextInputAction.done,
this.maxLengthEnforcement = MaxLengthEnforcement.none,
//
this.validatingMode,
this.validator,
this.inputFormatters,
//
});
//
AstromicFieldConfiguration copyWith({
bool? isEnabled,
bool? isTextObscured,
bool? isFixedHeight,
bool? isTextArea,
bool? withAutofocus,
@@ -60,9 +73,13 @@ class AstromicFieldConfiguration {
TextInputAction? inputAction,
TextCapitalization? capitalizationMode,
MaxLengthEnforcement? maxLengthEnforcement,
AutovalidateMode? validatingMode,
String? Function(bool isEnabled, bool isFocused, String? text)? validator,
List<TextInputFormatter>? inputFormatters,
}) {
return AstromicFieldConfiguration(
isEnabled: isEnabled ?? this.isEnabled,
isTextObscured: isTextObscured ?? this.isTextObscured,
isFixedHeight: isFixedHeight ?? this.isFixedHeight,
isTextArea: isTextArea ?? this.isTextArea,
withAutofocus: withAutofocus ?? this.withAutofocus,
@@ -76,6 +93,9 @@ class AstromicFieldConfiguration {
inputType: inputType ?? this.inputType,
inputAction: inputAction ?? this.inputAction,
maxLengthEnforcement: maxLengthEnforcement ?? this.maxLengthEnforcement,
validatingMode: validatingMode ?? this.validatingMode,
validator: validator ?? this.validator,
inputFormatters: inputFormatters ?? this.inputFormatters,
);
}
}

View File

@@ -0,0 +1,2 @@
export './style.model.dart';
export './configuration.model.dart';

View File

@@ -1,6 +1,7 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:flutter/material.dart';
import '../enums/border_type.enum.dart';
/// Styling model for the field element.
class AstromicFieldStyle {
//s1 - Styling Configs
final bool isFilled;
@@ -16,6 +17,11 @@ class AstromicFieldStyle {
/// Only works when it's a Text Area.
final TextAlignVertical textAlignVertical;
//
final BorderRadiusGeometry? borderRadius;
final double? borderWidth;
final AstromicFieldBorderType borderType;
final InputBorder? customBorder;
//
final EdgeInsetsGeometry contentPadding;
final EdgeInsetsGeometry messagePadding;
//
@@ -27,11 +33,11 @@ class AstromicFieldStyle {
//s1 - Colors
final Color fillColor;
final Color? cursorColor;
final Color? borderColor;
final Gradient? borderGradient;
//s1 - Styling
final TextStyle? hintStyle;
final TextStyle? textStyle;
//s1 - MISC
final InputBorder? border;
const AstromicFieldStyle({
this.isFilled = true,
@@ -43,6 +49,12 @@ class AstromicFieldStyle {
this.textAlignVertical = TextAlignVertical.center,
//
this.fixedHeight,
//
this.borderRadius,
this.borderWidth,
this.borderType = AstromicFieldBorderType.underlined,
this.customBorder,
//
this.contentPadding = EdgeInsets.zero,
this.messagePadding = EdgeInsets.zero,
this.prefixSpacing = 4,
@@ -51,11 +63,11 @@ class AstromicFieldStyle {
this.suffixSize = 24,
//
this.fillColor = const Color(0xffffffff),
this.borderColor,
this.borderGradient,
this.cursorColor,
this.hintStyle,
this.textStyle,
//
this.border,
});
//
AstromicFieldStyle copyWith({
@@ -66,6 +78,10 @@ class AstromicFieldStyle {
int? maxLength,
TextAlign? textAlign,
TextAlignVertical? textAlignVertical,
BorderRadiusGeometry? borderRadius,
double? borderWidth,
AstromicFieldBorderType? borderType,
InputBorder? customBorder,
EdgeInsetsGeometry? contentPadding,
EdgeInsetsGeometry? messagePadding,
double? prefixSpacing,
@@ -76,9 +92,10 @@ class AstromicFieldStyle {
CrossAxisAlignment? suffixAlignment,
Color? fillColor,
Color? cursorColor,
Color? borderColor,
Gradient? borderGradient,
TextStyle? hintStyle,
TextStyle? textStyle,
InputBorder? border,
}) {
return AstromicFieldStyle(
isFilled: isFilled ?? this.isFilled,
@@ -88,6 +105,10 @@ class AstromicFieldStyle {
maxLength: maxLength ?? this.maxLength,
textAlign: textAlign ?? this.textAlign,
textAlignVertical: textAlignVertical ?? this.textAlignVertical,
borderRadius: borderRadius ?? this.borderRadius,
borderWidth: borderWidth ?? this.borderWidth,
borderType: borderType ?? this.borderType,
customBorder: customBorder ?? this.customBorder,
contentPadding: contentPadding ?? this.contentPadding,
messagePadding: messagePadding ?? this.messagePadding,
prefixSpacing: prefixSpacing ?? this.prefixSpacing,
@@ -96,9 +117,10 @@ class AstromicFieldStyle {
suffixSize: suffixSize ?? this.suffixSize,
fillColor: fillColor ?? this.fillColor,
cursorColor: cursorColor ?? this.cursorColor,
borderColor: borderColor ?? this.borderColor,
borderGradient: borderGradient ?? this.borderGradient,
hintStyle: hintStyle ?? this.hintStyle,
textStyle: textStyle ?? this.textStyle,
border: border ?? this.border,
);
}
//

View File

@@ -1,33 +1,18 @@
// ignore_for_file: depend_on_referenced_packages
//SECTION - Imports
//
//s1 PACKAGES
//---------------
//s2 CORE
//s1 Imports
//s2 Core Package Imports
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart' as intl;
import 'dart:ui' as ui;
//s2 1st-party Package Imports
//s2 3rd-party Package Imports
//s2 Dependancies Imports
//s3 Routes
//s3 Services
//s3 Models
import 'base.dart';
import 'models/models.exports.dart';
//s1 Exports
//s2 3RD-PARTY
//
//s1 DEPENDENCIES
//---------------
//s2 SERVICES
//s2 MODELS
import 'configuration.dart';
import 'style.dart';
//s2 MISC
import '../../../Infrastructure/insets_extension.dart';
import '../../../Infrastructure/misc_extensions.dart';
//!SECTION - Imports
//
//SECTION - Exports
//!SECTION - Exports
//
class AstromicTextField extends StatefulWidget {
//SECTION - Widget Arguments
class AstromicTextField extends StatelessWidget {
//SECTION - Widget Arguments
//s1 -- Functionality
final TextEditingController textController;
final Key? stateKey;
@@ -36,15 +21,10 @@ class AstromicTextField extends StatefulWidget {
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<TextInputFormatter>? inputFormatters;
final bool? obscureText;
final AstromicFieldConfiguration? configuration;
//
//s1 -- Style
final AstromicFieldStyle Function(bool isEnabled, bool isFocused) style;
final AstromicFieldStyle Function(bool isEnabled, bool isFocused)? style;
//
//s1 -- Content
final String? hint;
@@ -64,14 +44,9 @@ class AstromicTextField extends StatefulWidget {
this.onChanged,
this.onSubmited,
//
required this.configuration,
this.configuration,
//
this.validatingMode,
this.validator,
this.inputFormatters,
this.obscureText,
//
required this.style,
this.style,
//
this.hint,
this.prefixWidget,
@@ -80,350 +55,33 @@ class AstromicTextField extends StatefulWidget {
this.contextButtons,
});
@override
State<AstromicTextField> createState() => _AstromicTextFieldState();
}
class _AstromicTextFieldState extends State<AstromicTextField> {
//
//SECTION - State Variables
//s1 --Controllers
late TextEditingController _textController;
//s1 --Controllers
//
//s1 --State
// late bool widget.configuration.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
// widget.configuration.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
getTextHeight(String text, TextStyle style, ui.TextDirection direction) {
final span = TextSpan(text: text, style: style);
final tp = TextPainter(text: span, textDirection: direction);
tp.layout(maxWidth: double.infinity);
return tp.height;
}
//-
//----------------------------------------------------------------
//-
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 = getTextHeight(
widget.textController.text.isNotEmpty
? widget.textController.text
: (widget.hint?.isNotEmpty ?? false)
? widget.hint!
: "",
widget.textController.text.isNotEmpty && widget.style(widget.configuration.isEnabled, _isFocused).textStyle != null
? widget.style(widget.configuration.isEnabled, _isFocused).textStyle!
: widget.style(widget.configuration.isEnabled, _isFocused).hintStyle != null
? widget.style(widget.configuration.isEnabled, _isFocused).hintStyle!
: const TextStyle(),
finalTextDirection(),
);
//
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
//s1 -Values
//double w = MediaQuery.of(context).size.width;
//double h = MediaQuery.of(context).size.height;
//s1 --Values
//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(widget.configuration.isEnabled, _isFocused).isFilled,
fillColor: widget.style(widget.configuration.isEnabled, _isFocused).fillColor,
//
hintStyle: widget.style(widget.configuration.isEnabled, _isFocused).hintStyle,
//
enabledBorder: widget.style(widget.configuration.isEnabled, false).border,
focusedBorder: widget.style(widget.configuration.isEnabled, true).border,
disabledBorder: widget.style(widget.configuration.isEnabled, _isFocused).border,
errorBorder: widget.style(widget.configuration.isEnabled, false).border,
focusedErrorBorder: widget.style(widget.configuration.isEnabled, true).border,
//
errorStyle: const TextStyle(height: 0),
contentPadding: finalVerticalPadding(widget.style(widget.configuration.isEnabled, _isFocused)),
//s1 -- Content
hintText: widget.hint,
//
prefixIcon: widget.prefixWidget != null &&
widget.prefixWidget!(widget.configuration.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? Container(
margin: EdgeInsetsDirectional.fromSTEB(widget.style(widget.configuration.isEnabled, _isFocused).prefixSpacing, 0,
widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).start, 0),
child: widget.prefixWidget!(widget.configuration.isEnabled, _isFocused, () {
setState(() {});
}),
)
: SizedBox(width: widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).start),
//
prefixIconConstraints: widget.prefixWidget != null &&
widget.prefixWidget!(widget.configuration.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? widget.style(widget.configuration.isEnabled, _isFocused).prefixSize != 0
? BoxConstraints.expand(
width: widget.style(widget.configuration.isEnabled, _isFocused).prefixSize +
widget.style(widget.configuration.isEnabled, _isFocused).prefixSpacing +
widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).start,
height: widget.style(widget.configuration.isEnabled, _isFocused).prefixSize,
)
: const BoxConstraints.tightForFinite()
: BoxConstraints.tightForFinite(width: widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).start),
//
suffixIcon: widget.suffixWidget != null &&
widget.suffixWidget!(widget.configuration.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? Container(
margin: EdgeInsetsDirectional.fromSTEB(widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).end, 0,
widget.style(widget.configuration.isEnabled, _isFocused).suffixSpacing, 0),
child: widget.suffixWidget!(widget.configuration.isEnabled, _isFocused, () {
setState(() {});
}),
)
: SizedBox(width: widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).end),
suffixIconConstraints: widget.suffixWidget != null &&
widget.suffixWidget != null &&
widget.suffixWidget!(widget.configuration.isEnabled, _isFocused, () {
setState(() {});
}) !=
null
? widget.style(widget.configuration.isEnabled, _isFocused).suffixSize != 0
? BoxConstraints.expand(
width: widget.style(widget.configuration.isEnabled, _isFocused).suffixSize +
widget.style(widget.configuration.isEnabled, _isFocused).suffixSpacing +
widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).end,
height: widget.style(widget.configuration.isEnabled, _isFocused).suffixSize,
)
: const BoxConstraints.tightForFinite()
: BoxConstraints.tightForFinite(width: widget.style(widget.configuration.isEnabled, _isFocused).contentPadding.resolveToDirectional(finalTextDirection()).end),
);
//s1 --Contexted Widgets
//s1 -Widgets
//s1 -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(widget.configuration.isEnabled, _isFocused).fixedHeight
: null,
alignment: widget.style(widget.configuration.isEnabled, _isFocused).textAlignVertical.toAlignment(),
child: TextFormField(
//s1 -- Functionality
key: widget.stateKey,
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(widget.configuration.isEnabled, _isFocused).minLines,
maxLines: widget.configuration.isFixedHeight
? widget.configuration.isTextArea
? null
: widget.style(widget.configuration.isEnabled, _isFocused).maxLines
: widget.style(widget.configuration.isEnabled, _isFocused).maxLines,
//
maxLength: widget.style(widget.configuration.isEnabled, _isFocused).maxLength,
maxLengthEnforcement: widget.configuration.maxLengthEnforcement,
//
expands: widget.configuration.isFixedHeight && widget.configuration.isTextArea ? true : false,
// - Validation
validator: widget.validator != null ? (s) => widget.validator!(widget.configuration.isEnabled, _isFocused, s) : null,
// - Validation
//s1 -- Style
style: widget.style(widget.configuration.isEnabled, _isFocused).textStyle,
cursorColor: widget.style(widget.configuration.isEnabled, _isFocused).cursorColor,
textAlign: widget.style(widget.configuration.isEnabled, _isFocused).textAlign,
textAlignVertical: widget.style(widget.configuration.isEnabled, _isFocused).textAlignVertical,
//
//s1 -- Input Decoration
decoration: inputDecoration,
//s1 -- Content
contextMenuBuilder: (_, state) {
List<ContextMenuButtonItem> baseContextButtons = state.contextMenuButtonItems;
if (widget.contextButtons != null) {
baseContextButtons.addAll(widget.contextButtons!);
}
return AdaptiveTextSelectionToolbar.buttonItems(
buttonItems: baseContextButtons,
anchors: state.contextMenuAnchors,
);
},
),
),
),
widget.messageBuilder != null &&
widget.messageBuilder!(
widget.configuration.isEnabled,
_isFocused,
) !=
null
? Padding(
padding: widget.style(widget.configuration.isEnabled, _isFocused).messagePadding,
child: widget.messageBuilder!(widget.configuration.isEnabled, _isFocused) ?? Container(),
)
: Container()
],
return AstromicFieldBase(
key: key,
textController: textController,
stateKey: stateKey,
onChanged: onChanged,
onSubmited: onSubmited,
configuration: configuration,
style: style,
hint: hint,
prefixWidget: prefixWidget,
suffixWidget: suffixWidget,
messageBuilder: messageBuilder,
contextButtons: contextButtons,
);
//!SECTION
}
@override
void dispose() {
//SECTION - Disposable variables
//!SECTION
super.dispose();
}
}