Skip to content

Commit

Permalink
TextField and Dropdown formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
FeodorFitsner committed Aug 2, 2022
1 parent c4f07ed commit acd30e3
Show file tree
Hide file tree
Showing 9 changed files with 449 additions and 32 deletions.
28 changes: 27 additions & 1 deletion client/lib/controls/dropdown.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import '../models/app_state.dart';
import '../models/control.dart';
import '../models/control_children_view_model.dart';
import '../protocol/update_control_props_payload.dart';
import '../utils/borders.dart';
import '../utils/colors.dart';
import '../web_socket_client.dart';
import 'create_control.dart';
import 'form_field.dart';
Expand All @@ -30,12 +32,16 @@ class DropdownControl extends StatefulWidget {

class _DropdownControlState extends State<DropdownControl> {
String? _value;
bool _focused = false;
final FocusNode _focusNode = FocusNode();

@override
void initState() {
super.initState();
_focusNode.addListener(() {
setState(() {
_focused = _focusNode.hasFocus;
});
ws.pageEventFromWeb(
eventTarget: widget.control.id,
eventName: _focusNode.hasFocus ? "focus" : "blur",
Expand All @@ -58,6 +64,20 @@ class _DropdownControlState extends State<DropdownControl> {
bool autofocus = widget.control.attrBool("autofocus", false)!;
bool disabled = widget.control.isDisabled || widget.parentDisabled;

var textSize = widget.control.attrDouble("textSize");

var color = HexColor.fromString(
Theme.of(context), widget.control.attrString("color", "")!);
var focusedColor = HexColor.fromString(Theme.of(context),
widget.control.attrString("focusedColor", "")!);

TextStyle? textStyle;
if (textSize != null || color != null || focusedColor != null) {
textStyle = TextStyle(
fontSize: textSize,
color: _focused ? focusedColor ?? color : color);
}

var items = itemsView.children
.where((c) => c.name == null)
.map<DropdownMenuItem<String>>(
Expand Down Expand Up @@ -96,15 +116,21 @@ class _DropdownControlState extends State<DropdownControl> {
}
}

var borderRadius = parseBorderRadius(widget.control, "borderRadius");

Widget dropDown = DropdownButtonFormField<String>(
style: textStyle,
autofocus: autofocus,
focusNode: _focusNode,
value: _value,
borderRadius: borderRadius,
decoration: buildInputDecoration(
context,
widget.control,
prefixControls.isNotEmpty ? prefixControls.first : null,
suffixControls.isNotEmpty ? suffixControls.first : null,
null),
null,
_focused),
onChanged: (String? value) {
debugPrint("Dropdown selected value: $value");
setState(() {
Expand Down
68 changes: 61 additions & 7 deletions client/lib/controls/form_field.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'package:flutter/material.dart';

import '../models/control.dart';
import '../utils/borders.dart';
import '../utils/colors.dart';
import '../utils/edge_insets.dart';
import '../utils/icons.dart';
import 'create_control.dart';
Expand Down Expand Up @@ -35,8 +37,8 @@ TextInputType parseTextInputType(String type) {
return TextInputType.text;
}

InputDecoration buildInputDecoration(
Control control, Control? prefix, Control? suffix, Widget? customSuffix) {
InputDecoration buildInputDecoration(BuildContext context, Control control,
Control? prefix, Control? suffix, Widget? customSuffix, bool focused) {
String? label = control.attrString("label", "")!;
FormFieldInputBorder inputBorder = FormFieldInputBorder.values.firstWhere(
((b) => b.name == control.attrString("border", "")!.toLowerCase()),
Expand All @@ -49,16 +51,68 @@ InputDecoration buildInputDecoration(
var suffixIcon = getMaterialIcon(control.attrString("suffixIcon", "")!);
var suffixText = control.attrString("suffixText");

var bgcolor = HexColor.fromString(
Theme.of(context), control.attrString("bgcolor", "")!);
var focusedBgcolor = HexColor.fromString(
Theme.of(context), control.attrString("focusedBgcolor", "")!);

var borderRadius = parseBorderRadius(control, "borderRadius");
var borderColor = HexColor.fromString(
Theme.of(context), control.attrString("borderColor", "")!);
var focusedBorderColor = HexColor.fromString(
Theme.of(context), control.attrString("focusedBorderColor", "")!);
var borderWidth = control.attrDouble("borderWidth");
var focusedBorderWidth = control.attrDouble("focusedBorderWidth");

InputBorder? border;
if (inputBorder == FormFieldInputBorder.underline) {
border = const UnderlineInputBorder();
} else if (inputBorder == FormFieldInputBorder.none) {
border = InputBorder.none;
} else if (inputBorder == FormFieldInputBorder.outline ||
borderRadius != null ||
borderColor != null ||
borderWidth != null) {
border = const OutlineInputBorder();
if (borderRadius != null) {
border =
(border as OutlineInputBorder).copyWith(borderRadius: borderRadius);
}
if (borderColor != null || borderWidth != null) {
border = (border as OutlineInputBorder).copyWith(
borderSide: borderWidth == 0
? BorderSide.none
: BorderSide(
color: borderColor ??
Theme.of(context).colorScheme.onSurface.withOpacity(0.38),
width: borderWidth ?? 1.0));
}
}

InputBorder? focusedBorder;
if (borderColor != null ||
borderWidth != null ||
focusedBorderColor != null ||
focusedBorderWidth != null) {
focusedBorder = border?.copyWith(
borderSide: borderWidth == 0
? BorderSide.none
: BorderSide(
color: focusedBorderColor ??
borderColor ??
Theme.of(context).colorScheme.primary,
width: focusedBorderWidth ?? borderWidth ?? 2.0));
}

return InputDecoration(
contentPadding: parseEdgeInsets(control, "contentPadding"),
label: label != "" ? Text(label) : null,
border: inputBorder == FormFieldInputBorder.none
? InputBorder.none
: inputBorder == FormFieldInputBorder.outline
? const OutlineInputBorder()
: const UnderlineInputBorder(),
border: border,
enabledBorder: border,
focusedBorder: focusedBorder,
icon: icon != null ? Icon(icon) : null,
filled: control.attrBool("filled", false)!,
fillColor: focused ? focusedBgcolor ?? bgcolor : bgcolor,
hintText: control.attrString("hintText"),
helperText: control.attrString("helperText"),
counterText: control.attrString("counterText"),
Expand Down
120 changes: 119 additions & 1 deletion client/lib/controls/textfield.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import '../actions.dart';
import '../models/app_state.dart';
import '../models/control.dart';
import '../protocol/update_control_props_payload.dart';
import '../utils/colors.dart';
import '../web_socket_client.dart';
import 'create_control.dart';
import 'form_field.dart';
Expand All @@ -33,6 +34,7 @@ class TextFieldControl extends StatefulWidget {
class _TextFieldControlState extends State<TextFieldControl> {
String _value = "";
bool _revealPassword = false;
bool _focused = false;
late TextEditingController _controller;
late final FocusNode _focusNode = FocusNode();

Expand All @@ -57,12 +59,18 @@ class _TextFieldControlState extends State<TextFieldControl> {
super.initState();
_controller = TextEditingController();
_shiftEnterfocusNode.addListener(() {
setState(() {
_focused = _shiftEnterfocusNode.hasFocus;
});
ws.pageEventFromWeb(
eventTarget: widget.control.id,
eventName: _shiftEnterfocusNode.hasFocus ? "focus" : "blur",
eventData: "");
});
_focusNode.addListener(() {
setState(() {
_focused = _focusNode.hasFocus;
});
ws.pageEventFromWeb(
eventTarget: widget.control.id,
eventName: _focusNode.hasFocus ? "focus" : "blur",
Expand Down Expand Up @@ -113,6 +121,36 @@ class _TextFieldControlState extends State<TextFieldControl> {
widget.control.attrBool("canRevealPassword", false)!;
bool onChange = widget.control.attrBool("onChange", false)!;

var cursorColor = HexColor.fromString(
Theme.of(context), widget.control.attrString("cursorColor", "")!);
var selectionColor = HexColor.fromString(Theme.of(context),
widget.control.attrString("selectionColor", "")!);

int? maxLength = widget.control.attrInt("maxLength");

var textSize = widget.control.attrDouble("textSize");

var color = HexColor.fromString(
Theme.of(context), widget.control.attrString("color", "")!);
var focusedColor = HexColor.fromString(Theme.of(context),
widget.control.attrString("focusedColor", "")!);

TextStyle? textStyle;
if (textSize != null || color != null || focusedColor != null) {
textStyle = TextStyle(
fontSize: textSize,
color: _focused ? focusedColor ?? color : color);
}

TextCapitalization? textCapitalization = TextCapitalization.values
.firstWhere(
(a) =>
a.name.toLowerCase() ==
widget.control
.attrString("capitalization", "")!
.toLowerCase(),
orElse: () => TextCapitalization.none);

Widget? revealPasswordIcon;
if (password && canRevealPassword) {
revealPasswordIcon = GestureDetector(
Expand Down Expand Up @@ -153,6 +191,7 @@ class _TextFieldControlState extends State<TextFieldControl> {
}

Widget textField = TextFormField(
style: textStyle,
autofocus: autofocus,
enabled: !disabled,
onFieldSubmitted: !multiline
Expand All @@ -164,15 +203,23 @@ class _TextFieldControlState extends State<TextFieldControl> {
}
: null,
decoration: buildInputDecoration(
context,
widget.control,
prefixControls.isNotEmpty ? prefixControls.first : null,
suffixControls.isNotEmpty ? suffixControls.first : null,
revealPasswordIcon),
revealPasswordIcon,
_focused),
keyboardType: keyboardType,
textAlign: textAlign,
minLines: minLines,
maxLines: maxLines,
maxLength: maxLength,
readOnly: readOnly,
inputFormatters: textCapitalization != TextCapitalization.none
? [
TextCapitalizationFormatter(textCapitalization),
]
: null,
obscureText: password && !_revealPassword,
controller: _controller,
focusNode: focusNode,
Expand All @@ -195,6 +242,13 @@ class _TextFieldControlState extends State<TextFieldControl> {
}
});

if (cursorColor != null || selectionColor != null) {
textField = TextSelectionTheme(
data: TextSelectionTheme.of(context).copyWith(
cursorColor: cursorColor, selectionColor: selectionColor),
child: textField);
}

if (widget.control.attrInt("expand", 0)! > 0) {
return constrainedControl(textField, widget.parent, widget.control);
} else {
Expand All @@ -216,3 +270,67 @@ class _TextFieldControlState extends State<TextFieldControl> {
});
}
}

class TextCapitalizationFormatter extends TextInputFormatter {
final TextCapitalization capitalization;

TextCapitalizationFormatter(this.capitalization);

@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
String text = '';

switch (capitalization) {
case TextCapitalization.words:
text = capitalizeFirstofEach(newValue.text);
break;
case TextCapitalization.sentences:
List<String> sentences = newValue.text.split('.');
for (int i = 0; i < sentences.length; i++) {
sentences[i] = inCaps(sentences[i]);
print(sentences[i]);
}
text = sentences.join('.');
break;
case TextCapitalization.characters:
text = allInCaps(newValue.text);
break;
case TextCapitalization.none:
text = newValue.text;
break;
}

return TextEditingValue(
text: text,
selection: newValue.selection,
);
}

/// 'Hello world'
static String inCaps(String text) {
if (text.isEmpty) {
return text;
}
String result = '';
for (int i = 0; i < text.length; i++) {
if (text[i] != ' ') {
result += '${text[i].toUpperCase()}${text.substring(i + 1)}';
break;
} else {
result += text[i];
}
}
return result;
}

/// 'HELLO WORLD'
static String allInCaps(String text) => text.toUpperCase();

/// 'Hello World'
static String capitalizeFirstofEach(String text) => text
.replaceAll(RegExp(' +'), ' ')
.split(" ")
.map((str) => inCaps(str))
.join(" ");
}
1 change: 1 addition & 0 deletions client/lib/utils/colors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ Map<String, Color> _plainColors = {
"black54": Colors.black54,
"black87": Colors.black87,
"black": Colors.black,
"transparent": Colors.transparent
};

Map<String, MaterialColor> _materialColors = {
Expand Down
Loading

0 comments on commit acd30e3

Please sign in to comment.