Skip to content

Commit 2d549ad

Browse files
committed
TextField and Dropdown with decoration
1 parent 098e126 commit 2d549ad

File tree

15 files changed

+590
-62
lines changed

15 files changed

+590
-62
lines changed

client/lib/controls/checkbox.dart

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,7 @@ class _CheckboxControlState extends State<CheckboxControl> {
7171
_value = value;
7272
});
7373
List<Map<String, String>> props = [
74-
{
75-
"i": widget.control.id,
76-
"value": value != null ? value.toString() : ""
77-
}
74+
{"i": widget.control.id, "value": svalue}
7875
];
7976
dispatch(UpdateControlPropsAction(
8077
UpdateControlPropsPayload(props: props)));

client/lib/controls/create_control.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import 'radio_group.dart';
2424
import 'row.dart';
2525
import 'snack_bar.dart';
2626
import 'stack.dart';
27+
import 'switch.dart';
2728
import 'text.dart';
2829
import 'text_button.dart';
2930
import 'textfield.dart';
@@ -118,12 +119,18 @@ Widget createControl(Control? parent, String id, bool parentDisabled) {
118119
return TextFieldControl(
119120
parent: parent,
120121
control: controlView.control,
122+
children: controlView.children,
121123
parentDisabled: parentDisabled);
122124
case ControlType.checkbox:
123125
return CheckboxControl(
124126
parent: parent,
125127
control: controlView.control,
126128
parentDisabled: parentDisabled);
129+
case ControlType.Switch:
130+
return SwitchControl(
131+
parent: parent,
132+
control: controlView.control,
133+
parentDisabled: parentDisabled);
127134
case ControlType.radioGroup:
128135
return RadioGroupControl(
129136
parent: parent,

client/lib/controls/dropdown.dart

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import '../models/control_children_view_model.dart';
88
import '../protocol/update_control_props_payload.dart';
99
import '../web_socket_client.dart';
1010
import 'create_control.dart';
11+
import 'form_field.dart';
1112

1213
class DropdownControl extends StatefulWidget {
1314
final Control? parent;
@@ -42,23 +43,23 @@ class _DropdownControlState extends State<DropdownControl> {
4243

4344
bool disabled = widget.control.isDisabled || widget.parentDisabled;
4445

45-
String? value = widget.control.attrs["value"];
46-
if (value == "") {
47-
value = null;
48-
}
46+
String? value = widget.control.attrString("value");
4947
if (_value != value) {
5048
_value = value;
5149
}
5250

53-
var dropDown = DropdownButton<String>(
51+
var prefixControls =
52+
itemsView.children.where((c) => c.name == "prefix");
53+
var suffixControls =
54+
itemsView.children.where((c) => c.name == "suffix");
55+
56+
var dropDown = DropdownButtonFormField<String>(
5457
value: _value,
55-
// icon: const Icon(Icons.arrow_downward),
56-
// elevation: 16,
57-
// style: const TextStyle(color: Colors.deepPurple),
58-
// underline: Container(
59-
// height: 1,
60-
// color: Colors.deepPurpleAccent,
61-
// ),
58+
decoration: buildInputDecoration(
59+
widget.control,
60+
prefixControls.isNotEmpty ? prefixControls.first : null,
61+
suffixControls.isNotEmpty ? suffixControls.first : null,
62+
null),
6263
onChanged: (String? value) {
6364
debugPrint("Dropdown selected value: $value");
6465
setState(() {
@@ -70,8 +71,13 @@ class _DropdownControlState extends State<DropdownControl> {
7071
itemsView.dispatch(UpdateControlPropsAction(
7172
UpdateControlPropsPayload(props: props)));
7273
ws.updateControlProps(props: props);
74+
ws.pageEventFromWeb(
75+
eventTarget: widget.control.id,
76+
eventName: "change",
77+
eventData: value);
7378
},
7479
items: itemsView.children
80+
.where((c) => c.name == null)
7581
.map<DropdownMenuItem<String>>((Control itemCtrl) {
7682
return DropdownMenuItem<String>(
7783
enabled: !(disabled || itemCtrl.isDisabled),
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import 'package:flet_view/controls/create_control.dart';
2+
import 'package:flutter/material.dart';
3+
4+
import '../models/control.dart';
5+
import '../utils/edge_insets.dart';
6+
import '../utils/icons.dart';
7+
8+
enum FormFieldInputBorder { outline, underline, none }
9+
10+
TextInputType parseTextInputType(String type) {
11+
switch (type.toLowerCase()) {
12+
case "datetime":
13+
return TextInputType.datetime;
14+
case "email":
15+
return TextInputType.emailAddress;
16+
case "multiline":
17+
return TextInputType.multiline;
18+
case "name":
19+
return TextInputType.name;
20+
case "none":
21+
return TextInputType.none;
22+
case "number":
23+
return TextInputType.number;
24+
case "phone":
25+
return TextInputType.phone;
26+
case "streetaddress":
27+
return TextInputType.streetAddress;
28+
case "text":
29+
return TextInputType.text;
30+
case "url":
31+
return TextInputType.url;
32+
case "visiblepassword":
33+
return TextInputType.visiblePassword;
34+
}
35+
return TextInputType.none;
36+
}
37+
38+
InputDecoration buildInputDecoration(
39+
Control control, Control? prefix, Control? suffix, Widget? customSuffix) {
40+
String? label = control.attrString("label", "")!;
41+
FormFieldInputBorder inputBorder = FormFieldInputBorder.values.firstWhere(
42+
((b) => b.name == control.attrString("border", "")!.toLowerCase()),
43+
orElse: () => FormFieldInputBorder.outline,
44+
);
45+
var icon = getMaterialIcon(control.attrString("icon", "")!);
46+
47+
var prefixIcon = getMaterialIcon(control.attrString("prefixIcon", "")!);
48+
var prefixText = control.attrString("prefixText");
49+
var suffixIcon = getMaterialIcon(control.attrString("suffixIcon", "")!);
50+
var suffixText = control.attrString("suffixText");
51+
52+
return InputDecoration(
53+
contentPadding: parseEdgeInsets(control, "contentPadding"),
54+
label: label != "" ? Text(label) : null,
55+
border: inputBorder == FormFieldInputBorder.none
56+
? InputBorder.none
57+
: inputBorder == FormFieldInputBorder.outline
58+
? const OutlineInputBorder()
59+
: const UnderlineInputBorder(),
60+
icon: icon != null ? Icon(icon) : null,
61+
filled: control.attrBool("filled", false)!,
62+
hintText: control.attrString("hintText"),
63+
helperText: control.attrString("helperText"),
64+
counterText: control.attrString("counterText"),
65+
errorText: control.attrString("errorText"),
66+
prefixIcon: prefixIcon != null ? Icon(prefixIcon) : null,
67+
prefixText: prefixText,
68+
prefix: prefix != null
69+
? createControl(control, prefix.id, control.isDisabled)
70+
: null,
71+
suffix: suffix != null
72+
? createControl(control, suffix.id, control.isDisabled)
73+
: null,
74+
suffixIcon: suffixIcon != null ? Icon(suffixIcon) : customSuffix,
75+
suffixText: suffixText);
76+
}

client/lib/controls/switch.dart

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_redux/flutter_redux.dart';
3+
4+
import '../actions.dart';
5+
import '../models/app_state.dart';
6+
import '../models/control.dart';
7+
import '../protocol/update_control_props_payload.dart';
8+
import '../web_socket_client.dart';
9+
import 'create_control.dart';
10+
11+
enum LabelPosition { right, left }
12+
13+
class SwitchControl extends StatefulWidget {
14+
final Control? parent;
15+
final Control control;
16+
final bool parentDisabled;
17+
18+
const SwitchControl(
19+
{Key? key,
20+
this.parent,
21+
required this.control,
22+
required this.parentDisabled})
23+
: super(key: key);
24+
25+
@override
26+
State<SwitchControl> createState() => _SwitchControlState();
27+
}
28+
29+
class _SwitchControlState extends State<SwitchControl> {
30+
bool _value = false;
31+
32+
@override
33+
void initState() {
34+
super.initState();
35+
}
36+
37+
@override
38+
void dispose() {
39+
super.dispose();
40+
}
41+
42+
@override
43+
Widget build(BuildContext context) {
44+
debugPrint("SwitchControl build: ${widget.control.id}");
45+
46+
String label = widget.control.attrString("label", "")!;
47+
LabelPosition labelPosition = LabelPosition.values.firstWhere(
48+
(p) =>
49+
p.name.toLowerCase() ==
50+
widget.control.attrString("labelPosition", "")!.toLowerCase(),
51+
orElse: () => LabelPosition.right);
52+
bool disabled = widget.control.isDisabled || widget.parentDisabled;
53+
54+
return StoreConnector<AppState, Function>(
55+
distinct: true,
56+
converter: (store) => store.dispatch,
57+
builder: (context, dispatch) {
58+
debugPrint("Checkbox StoreConnector build: ${widget.control.id}");
59+
60+
bool value = widget.control.attrBool("value", false)!;
61+
if (_value != value) {
62+
_value = value;
63+
}
64+
65+
onChange(bool value) {
66+
var svalue = value.toString();
67+
debugPrint(svalue);
68+
setState(() {
69+
_value = value;
70+
});
71+
List<Map<String, String>> props = [
72+
{"i": widget.control.id, "value": svalue}
73+
];
74+
dispatch(UpdateControlPropsAction(
75+
UpdateControlPropsPayload(props: props)));
76+
ws.updateControlProps(props: props);
77+
ws.pageEventFromWeb(
78+
eventTarget: widget.control.id,
79+
eventName: "change",
80+
eventData: svalue);
81+
}
82+
83+
var swtch = Switch(
84+
value: _value,
85+
onChanged: !disabled
86+
? (bool value) {
87+
onChange(value);
88+
}
89+
: null);
90+
91+
Widget result = swtch;
92+
if (label != "") {
93+
var labelWidget = disabled
94+
? Text(label,
95+
style: TextStyle(color: Theme.of(context).disabledColor))
96+
: MouseRegion(
97+
cursor: SystemMouseCursors.click, child: Text(label));
98+
result = GestureDetector(
99+
onTap: !disabled
100+
? () {
101+
onChange(!_value);
102+
}
103+
: null,
104+
child: labelPosition == LabelPosition.right
105+
? Row(children: [swtch, labelWidget])
106+
: Row(children: [labelWidget, swtch]));
107+
}
108+
109+
return constrainedControl(result, widget.parent, widget.control);
110+
});
111+
}
112+
}

client/lib/controls/textfield.dart

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@ import '../models/control.dart';
77
import '../protocol/update_control_props_payload.dart';
88
import '../web_socket_client.dart';
99
import 'create_control.dart';
10+
import 'form_field.dart';
1011

1112
class TextFieldControl extends StatefulWidget {
1213
final Control? parent;
1314
final Control control;
15+
final List<Control> children;
1416
final bool parentDisabled;
1517

1618
const TextFieldControl(
1719
{Key? key,
1820
this.parent,
1921
required this.control,
22+
required this.children,
2023
required this.parentDisabled})
2124
: super(key: key);
2225

@@ -26,6 +29,7 @@ class TextFieldControl extends StatefulWidget {
2629

2730
class _TextFieldControlState extends State<TextFieldControl> {
2831
String _value = "";
32+
bool _revealPassword = false;
2933
late TextEditingController _controller;
3034

3135
@override
@@ -58,12 +62,59 @@ class _TextFieldControlState extends State<TextFieldControl> {
5862
_controller.text = value;
5963
}
6064

65+
var prefixControls = widget.children.where((c) => c.name == "prefix");
66+
var suffixControls = widget.children.where((c) => c.name == "suffix");
67+
68+
int? minLines = widget.control.attrInt("minLines");
69+
int? maxLines = widget.control.attrInt("maxLines");
70+
71+
bool readOnly = widget.control.attrBool("readOnly", false)!;
72+
bool password = widget.control.attrBool("password", false)!;
73+
bool canRevealPassword =
74+
widget.control.attrBool("canRevealPassword", false)!;
75+
76+
Widget? revealPasswordIcon;
77+
if (password && canRevealPassword) {
78+
revealPasswordIcon = GestureDetector(
79+
child: Icon(
80+
_revealPassword ? Icons.visibility_off : Icons.visibility,
81+
),
82+
onTap: () {
83+
setState(() {
84+
_revealPassword = !_revealPassword;
85+
});
86+
});
87+
}
88+
89+
TextInputType keyboardType = parseTextInputType(
90+
widget.control.attrString("keyboardType", "")!);
91+
92+
if (keyboardType == TextInputType.none &&
93+
minLines != null &&
94+
minLines > 0) {
95+
keyboardType = TextInputType.multiline;
96+
}
97+
98+
TextAlign textAlign = TextAlign.values.firstWhere(
99+
((b) =>
100+
b.name ==
101+
widget.control.attrString("textAlign", "")!.toLowerCase()),
102+
orElse: () => TextAlign.start,
103+
);
104+
61105
var textField = TextFormField(
62-
//initialValue: widget.control.attrs["value"] ?? "",
63106
enabled: !disabled,
64-
decoration: InputDecoration(
65-
labelText: widget.control.attrs["label"] ?? "",
66-
border: const OutlineInputBorder()),
107+
decoration: buildInputDecoration(
108+
widget.control,
109+
prefixControls.isNotEmpty ? prefixControls.first : null,
110+
suffixControls.isNotEmpty ? suffixControls.first : null,
111+
revealPasswordIcon),
112+
keyboardType: keyboardType,
113+
textAlign: textAlign,
114+
minLines: minLines,
115+
maxLines: password ? 1 : maxLines,
116+
readOnly: readOnly,
117+
obscureText: password && !_revealPassword,
67118
controller: _controller,
68119
onChanged: (String value) {
69120
debugPrint(value);

0 commit comments

Comments
 (0)