|
|
|
|
|
|
using Unity.UIWidgets.service; |
|
|
|
using Unity.UIWidgets.ui; |
|
|
|
using Unity.UIWidgets.widgets; |
|
|
|
using UnityEngine; |
|
|
|
using Color = Unity.UIWidgets.ui.Color; |
|
|
|
|
|
|
|
public delegate Widget InputCounterWidgetBuilder( |
|
|
|
BuildContext buildContext, |
|
|
|
int? currentLength, |
|
|
|
int? maxLength, |
|
|
|
bool? isFocused); |
|
|
|
|
|
|
|
public class TextField : StatefulWidget { |
|
|
|
public TextField(Key key = null, TextEditingController controller = null, FocusNode focusNode = null, |
|
|
|
InputDecoration decoration = null, bool noDecoration = false, TextInputType keyboardType = null, |
|
|
|
|
|
|
ValueChanged<string> onSubmitted = null, List<TextInputFormatter> inputFormatters = null, |
|
|
|
bool? enabled = null, float? cursorWidth = 2.0f, Radius cursorRadius = null, Color cursorColor = null, |
|
|
|
Brightness? keyboardAppearance = null, EdgeInsets scrollPadding = null, |
|
|
|
bool enableInteractiveSelection = true, |
|
|
|
GestureTapCallback onTap = null |
|
|
|
DragStartBehavior dragStartBehavior = DragStartBehavior.down, |
|
|
|
bool? enableInteractiveSelection = null, |
|
|
|
GestureTapCallback onTap = null, |
|
|
|
InputCounterWidgetBuilder buildCounter = null |
|
|
|
D.assert(maxLength == null || maxLength > 0); |
|
|
|
D.assert(maxLength == null || maxLength == TextField.noMaxLength || maxLength > 0); |
|
|
|
|
|
|
|
this.controller = controller; |
|
|
|
this.focusNode = focusNode; |
|
|
|
|
|
|
this.onTap = onTap; |
|
|
|
this.keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline); |
|
|
|
this.scrollPadding = scrollPadding ?? EdgeInsets.all(20.0f); |
|
|
|
this.dragStartBehavior = dragStartBehavior; |
|
|
|
this.buildCounter = buildCounter; |
|
|
|
} |
|
|
|
|
|
|
|
public readonly TextEditingController controller; |
|
|
|
|
|
|
public readonly bool autocorrect; |
|
|
|
|
|
|
|
public readonly int? maxLines; |
|
|
|
|
|
|
|
public const long noMaxLength = 9007199254740992; // math.pow(2, 53);
|
|
|
|
|
|
|
|
public const long noMaxLength = -1; |
|
|
|
|
|
|
|
public readonly int? maxLength; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public readonly EdgeInsets scrollPadding; |
|
|
|
|
|
|
|
public readonly bool enableInteractiveSelection; |
|
|
|
public readonly bool? enableInteractiveSelection; |
|
|
|
|
|
|
|
public readonly DragStartBehavior dragStartBehavior; |
|
|
|
|
|
|
|
public bool selectionEnabled { |
|
|
|
get { |
|
|
|
return this.enableInteractiveSelection ?? !this.obscureText; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public readonly InputCounterWidgetBuilder buildCounter; |
|
|
|
|
|
|
|
public override State createState() { |
|
|
|
return new _TextFieldState(); |
|
|
|
|
|
|
new DiagnosticsProperty<TextEditingController>("controller", this.controller, defaultValue: null)); |
|
|
|
properties.add(new DiagnosticsProperty<FocusNode>("focusNode", this.focusNode, defaultValue: null)); |
|
|
|
properties.add(new DiagnosticsProperty<bool?>("enabled", this.enabled, defaultValue: null)); |
|
|
|
properties.add(new DiagnosticsProperty<InputDecoration>("decoration", this.decoration)); |
|
|
|
properties.add(new DiagnosticsProperty<InputDecoration>("decoration", this.decoration, defaultValue: new InputDecoration())); |
|
|
|
properties.add(new DiagnosticsProperty<bool>("autocorrect", this.autocorrect, defaultValue: false)); |
|
|
|
properties.add(new DiagnosticsProperty<bool>("autocorrect", this.autocorrect, defaultValue: true)); |
|
|
|
properties.add(new FlagProperty("maxLengthEnforced", value: this.maxLengthEnforced, |
|
|
|
ifTrue: "max length enforced")); |
|
|
|
properties.add(new DiagnosticsProperty<GestureTapCallback>("onTap", this.onTap, defaultValue: null)); |
|
|
|
properties.add(new FlagProperty("maxLengthEnforced", value: this.maxLengthEnforced, defaultValue: true, |
|
|
|
ifFalse: "maxLength not enforced")); |
|
|
|
properties.add(new EnumProperty<TextInputAction?>("textInputAction", this.textInputAction, defaultValue: null)); |
|
|
|
properties.add(new EnumProperty<TextCapitalization>("textCapitalization", this.textCapitalization, defaultValue: TextCapitalization.none)); |
|
|
|
properties.add(new EnumProperty<TextAlign>("textAlign", this.textAlign, defaultValue: TextAlign.left)); |
|
|
|
properties.add(new EnumProperty<TextDirection>("textDirection", this.textDirection, defaultValue: null)); |
|
|
|
properties.add(new FloatProperty("cursorWidth", this.cursorWidth, defaultValue: 2.0)); |
|
|
|
properties.add(new DiagnosticsProperty<Radius>("cursorRadius", this.cursorRadius, defaultValue: null)); |
|
|
|
properties.add(new DiagnosticsProperty<Color>("cursorColor", this.cursorColor, defaultValue: null)); |
|
|
|
properties.add(new DiagnosticsProperty<Brightness?>("keyboardAppearance", this.keyboardAppearance, defaultValue: null)); |
|
|
|
properties.add(new DiagnosticsProperty<EdgeInsets>("scrollPadding", this.scrollPadding, defaultValue: EdgeInsets.all(20.0f))); |
|
|
|
properties.add(new FlagProperty("selectionEnabled", value: this.selectionEnabled, defaultValue: true, ifFalse: "selection disabled")); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
InputDecoration _getEffectiveDecoration() { |
|
|
|
MaterialLocalizations localizations = MaterialLocalizations.of(this.context); |
|
|
|
ThemeData themeData = Theme.of(this.context); |
|
|
|
.applyDefaults(Theme.of(this.context).inputDecorationTheme) |
|
|
|
.applyDefaults(themeData.inputDecorationTheme) |
|
|
|
enabled: this.widget.enabled |
|
|
|
enabled: this.widget.enabled, |
|
|
|
hintMaxLines: this.widget.decoration?.hintMaxLines ?? this.widget.maxLines |
|
|
|
if (!this.needsCounter) { |
|
|
|
if (effectiveDecoration.counter != null || effectiveDecoration.counterText != null) { |
|
|
|
Widget counter; |
|
|
|
if (effectiveDecoration.counter == null |
|
|
|
&& effectiveDecoration.counterText == null |
|
|
|
&& this.widget.buildCounter != null) { |
|
|
|
bool isFocused = this._effectiveFocusNode.hasFocus; |
|
|
|
counter = this.widget.buildCounter( |
|
|
|
this.context, |
|
|
|
currentLength: currentLength, |
|
|
|
maxLength: this.widget.maxLength, |
|
|
|
isFocused: isFocused |
|
|
|
); |
|
|
|
return effectiveDecoration.copyWith(counter: counter); |
|
|
|
} |
|
|
|
|
|
|
|
if (this.widget.maxLength == null) |
|
|
|
return effectiveDecoration; |
|
|
|
|
|
|
|
|
|
|
|
if (this.widget.maxLength != TextField.noMaxLength) { |
|
|
|
if (this.widget.maxLength > 0) { |
|
|
|
if (this._effectiveController.value.text.Length > this.widget.maxLength) { |
|
|
|
return effectiveDecoration.copyWith( |
|
|
|
errorText: effectiveDecoration.errorText ?? "", |
|
|
|
counterStyle: effectiveDecoration.errorStyle |
|
|
|
?? themeData.textTheme.caption.copyWith(color: themeData.errorColor), |
|
|
|
counterText: counterText |
|
|
|
); |
|
|
|
} |
|
|
|
if (this._effectiveController.value.text.Length > this.widget.maxLength) { |
|
|
|
ThemeData themeData = Theme.of(this.context); |
|
|
|
return effectiveDecoration.copyWith( |
|
|
|
errorText: effectiveDecoration.errorText ?? "", |
|
|
|
counterStyle: effectiveDecoration.errorStyle |
|
|
|
?? themeData.textTheme.caption.copyWith(color: themeData.errorColor), |
|
|
|
counterText: counterText |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
return effectiveDecoration.copyWith( |
|
|
|
counterText: counterText |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
void _handleSelectionChanged(TextSelection selection, SelectionChangedCause cause) { |
|
|
|
if (cause == SelectionChangedCause.longPress) { |
|
|
|
// Feedback.forLongPress(context); todo add feedback
|
|
|
|
if (Theme.of(this.context).platform == RuntimePlatform.IPhonePlayer |
|
|
|
&& cause == SelectionChangedCause.longPress) { |
|
|
|
this._editableTextKey.currentState?.bringIntoView(selection.basePos); |
|
|
|
ThemeData themeData = Theme.of(this.context); |
|
|
|
Color color = Theme.of(this.context).splashColor; |
|
|
|
Color color = themeData.splashColor; |
|
|
|
|
|
|
|
InteractiveInkFeature splash = null; |
|
|
|
|
|
|
|
|
|
|
} // else we're probably in deactivate()
|
|
|
|
} |
|
|
|
|
|
|
|
splash = Theme.of(this.context).splashFactory.create( |
|
|
|
splash = themeData.splashFactory.create( |
|
|
|
controller: inkController, |
|
|
|
referenceBox: referenceBox, |
|
|
|
position: position, |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
void _handleSingleTapUp(TapUpDetails details) { |
|
|
|
if (this.widget.enableInteractiveSelection) { |
|
|
|
if (this.widget.enableInteractiveSelection == true) { |
|
|
|
this._renderEditable.handleTap(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
void _handleLongPress() { |
|
|
|
if (this.widget.enableInteractiveSelection) { |
|
|
|
if (this.widget.enableInteractiveSelection == true) { |
|
|
|
this._renderEditable.handleLongPress(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
base.build(context); // See AutomaticKeepAliveClientMixin.
|
|
|
|
D.assert(MaterialD.debugCheckHasMaterial(context)); |
|
|
|
D.assert(WidgetsD.debugCheckHasDirectionality(context)); |
|
|
|
D.assert( |
|
|
|
!(this.widget.style != null && this.widget.style.inherit == false && |
|
|
|
(this.widget.style.fontSize == null || this.widget.style.textBaseline == null)), |
|
|
|
"inherit false style must supply fontSize and textBaseline" |
|
|
|
); |
|
|
|
TextStyle style = this.widget.style ?? themeData.textTheme.subhead; |
|
|
|
TextStyle style = themeData.textTheme.subhead.merge(this.widget.style); |
|
|
|
Brightness keyboardAppearance = this.widget.keyboardAppearance ?? themeData.primaryColorBrightness; |
|
|
|
TextEditingController controller = this._effectiveController; |
|
|
|
FocusNode focusNode = this._effectiveFocusNode; |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool forcePressEnabled = false; |
|
|
|
TextSelectionControls textSelectionControls = MaterialUtils.materialTextSelectionControls;; |
|
|
|
bool paintCursorAboveText = false; |
|
|
|
bool cursorOpacityAnimates = false; |
|
|
|
Offset cursorOffset = null; |
|
|
|
Color cursorColor = this.widget.cursorColor ?? themeData.cursorColor; |
|
|
|
Radius cursorRadius = this.widget.cursorRadius; |
|
|
|
|
|
|
|
Widget child = new RepaintBoundary( |
|
|
|
child: new EditableText( |
|
|
|
|
|
|
autocorrect: this.widget.autocorrect, |
|
|
|
maxLines: this.widget.maxLines, |
|
|
|
selectionColor: themeData.textSelectionColor, |
|
|
|
selectionControls: this.widget.enableInteractiveSelection |
|
|
|
? MaterialUtils.materialTextSelectionControls |
|
|
|
: null, |
|
|
|
selectionControls: this.widget.selectionEnabled ? textSelectionControls : null, |
|
|
|
onSelectionChanged: this._handleSelectionChanged, |
|
|
|
onSelectionChanged: this._handleSelectionChanged, |
|
|
|
cursorRadius: this.widget.cursorRadius, |
|
|
|
cursorColor: this.widget.cursorColor ?? Theme.of(context).cursorColor, |
|
|
|
cursorRadius: cursorRadius, |
|
|
|
cursorColor: cursorColor, |
|
|
|
cursorOpacityAnimates: cursorOpacityAnimates, |
|
|
|
cursorOffset: cursorOffset, |
|
|
|
paintCursorAboveText: paintCursorAboveText, |
|
|
|
backgroundCursorColor: new Color(0xFF8E8E93),// TODO: CupertinoColors.inactiveGray,
|
|
|
|
enableInteractiveSelection: this.widget.enableInteractiveSelection |
|
|
|
enableInteractiveSelection: this.widget.enableInteractiveSelection == true, |
|
|
|
dragStartBehavior: this.widget.dragStartBehavior |
|
|
|
) |
|
|
|
); |
|
|
|
|
|
|
|