Skip to content

Commit 6daabb2

Browse files
Merge pull request #3 from flet-dev/s1-lazy-builders
S1 lazy builders
2 parents 68cb70d + aabe29b commit 6daabb2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1018
-85
lines changed

client/lib/controls/checkbox.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,17 @@ class CheckboxControl extends StatefulWidget {
2828

2929
class _CheckboxControlState extends State<CheckboxControl> {
3030
bool? _value;
31+
final FocusNode _focusNode = FocusNode();
3132

3233
@override
3334
void initState() {
3435
super.initState();
36+
_focusNode.addListener(() {
37+
ws.pageEventFromWeb(
38+
eventTarget: widget.control.id,
39+
eventName: _focusNode.hasFocus ? "focus" : "blur",
40+
eventData: "");
41+
});
3542
}
3643

3744
@override
@@ -50,6 +57,7 @@ class _CheckboxControlState extends State<CheckboxControl> {
5057
widget.control.attrString("labelPosition", "")!.toLowerCase(),
5158
orElse: () => LabelPosition.right);
5259
bool tristate = widget.control.attrBool("tristate", false)!;
60+
bool autofocus = widget.control.attrBool("autofocus", false)!;
5361
bool disabled = widget.control.isDisabled || widget.parentDisabled;
5462

5563
return StoreConnector<AppState, Function>(
@@ -66,7 +74,7 @@ class _CheckboxControlState extends State<CheckboxControl> {
6674

6775
onChange(bool? value) {
6876
var svalue = value != null ? value.toString() : "";
69-
debugPrint(svalue);
77+
//debugPrint(svalue);
7078
setState(() {
7179
_value = value;
7280
});
@@ -83,6 +91,8 @@ class _CheckboxControlState extends State<CheckboxControl> {
8391
}
8492

8593
var checkbox = Checkbox(
94+
autofocus: autofocus,
95+
focusNode: _focusNode,
8696
value: _value,
8797
tristate: tristate,
8898
onChanged: !disabled

client/lib/controls/clipboard.dart

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import 'dart:convert';
2+
3+
import 'package:flutter/services.dart';
4+
import 'package:flutter/widgets.dart';
5+
6+
import '../models/control.dart';
7+
8+
class ClipboardControl extends StatelessWidget {
9+
final Control? parent;
10+
final Control control;
11+
12+
const ClipboardControl({Key? key, this.parent, required this.control})
13+
: super(key: key);
14+
15+
@override
16+
Widget build(BuildContext context) {
17+
debugPrint("Clipboard build: ${control.id}");
18+
19+
var value = control.attrString("value");
20+
21+
if (value != null) {
22+
debugPrint("Clipboard JSON value: $value");
23+
24+
var jv = json.decode(value);
25+
Clipboard.setData(ClipboardData(text: jv["d"] as String?));
26+
}
27+
28+
return const SizedBox.shrink();
29+
}
30+
}

client/lib/controls/container.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter/widgets.dart';
33

4+
import '../models/control.dart';
45
import '../utils/alignment.dart';
56
import '../utils/borders.dart';
6-
import 'create_control.dart';
7-
import 'error.dart';
87
import '../utils/colors.dart';
9-
import '../models/control.dart';
108
import '../utils/edge_insets.dart';
9+
import 'create_control.dart';
10+
import 'error.dart';
1111

1212
class ContainerControl extends StatelessWidget {
1313
final Control? parent;
@@ -25,7 +25,7 @@ class ContainerControl extends StatelessWidget {
2525

2626
@override
2727
Widget build(BuildContext context) {
28-
debugPrint("Icon build: ${control.id}");
28+
debugPrint("Container build: ${control.id}");
2929

3030
var bgColor =
3131
HexColor.fromString(context, control.attrString("bgColor", "")!);

client/lib/controls/create_control.dart

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import '../models/control_view_model.dart';
88
import 'alert_dialog.dart';
99
import 'banner.dart';
1010
import 'checkbox.dart';
11+
import 'clipboard.dart';
1112
import 'column.dart';
1213
import 'container.dart';
1314
import 'dropdown.dart';
@@ -45,17 +46,22 @@ import 'textfield.dart';
4546
// }
4647

4748
Widget createControl(Control? parent, String id, bool parentDisabled) {
49+
//debugPrint("createControl(): $id");
4850
return StoreConnector<AppState, ControlViewModel>(
4951
distinct: true,
5052
converter: (store) {
5153
//debugPrint("ControlViewModel $id converter");
5254
return ControlViewModel.fromStore(store, id);
5355
},
54-
onWillChange: (prev, next) {
55-
//debugPrint("${next.type} $id will change");
56+
// onWillChange: (prev, next) {
57+
// debugPrint("onWillChange() $id: $prev, $next");
58+
// },
59+
ignoreChange: (state) {
60+
//debugPrint("ignoreChange: $id");
61+
return state.controls[id] == null;
5662
},
5763
builder: (context, controlView) {
58-
//debugPrint("${control.type} ${control.id} builder");
64+
//debugPrint("createControl builder(): $id");
5965
switch (controlView.control.type) {
6066
case ControlType.page:
6167
return PageControl(
@@ -64,6 +70,8 @@ Widget createControl(Control? parent, String id, bool parentDisabled) {
6470
return TextControl(control: controlView.control);
6571
case ControlType.icon:
6672
return IconControl(control: controlView.control);
73+
case ControlType.clipboard:
74+
return ClipboardControl(control: controlView.control);
6775
case ControlType.image:
6876
return ImageControl(parent: parent, control: controlView.control);
6977
case ControlType.progressRing:
@@ -205,12 +213,18 @@ Widget createControl(Control? parent, String id, bool parentDisabled) {
205213
}
206214

207215
Widget baseControl(Widget widget, Control? parent, Control control) {
208-
return _expandable(_opacity(widget, parent, control), parent, control);
216+
return _expandable(
217+
_tooltip(_opacity(widget, parent, control), parent, control),
218+
parent,
219+
control);
209220
}
210221

211222
Widget constrainedControl(Widget widget, Control? parent, Control control) {
212223
return _expandable(
213-
_sizedControl(_opacity(widget, parent, control), parent, control),
224+
_sizedControl(
225+
_tooltip(_opacity(widget, parent, control), parent, control),
226+
parent,
227+
control),
214228
parent,
215229
control);
216230
}
@@ -225,6 +239,18 @@ Widget _opacity(Widget widget, Control? parent, Control control) {
225239
: widget;
226240
}
227241

242+
Widget _tooltip(Widget widget, Control? parent, Control control) {
243+
var tooltip = control.attrString("tooltip");
244+
return tooltip != null
245+
? Tooltip(
246+
message: tooltip,
247+
padding: const EdgeInsets.all(4.0),
248+
child: widget,
249+
waitDuration: const Duration(milliseconds: 800),
250+
)
251+
: widget;
252+
}
253+
228254
Widget _sizedControl(Widget widget, Control? parent, Control control) {
229255
var width = control.attrDouble("width", null);
230256
var height = control.attrDouble("height", null);

client/lib/controls/dropdown.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ class DropdownControl extends StatefulWidget {
2828

2929
class _DropdownControlState extends State<DropdownControl> {
3030
String? _value;
31+
final FocusNode _focusNode = FocusNode();
32+
33+
@override
34+
void initState() {
35+
super.initState();
36+
_focusNode.addListener(() {
37+
ws.pageEventFromWeb(
38+
eventTarget: widget.control.id,
39+
eventName: _focusNode.hasFocus ? "focus" : "blur",
40+
eventData: "");
41+
});
42+
}
3143

3244
@override
3345
Widget build(BuildContext context) {
@@ -41,6 +53,7 @@ class _DropdownControlState extends State<DropdownControl> {
4153
builder: (context, itemsView) {
4254
debugPrint("Dropdown StoreConnector build: ${widget.control.id}");
4355

56+
bool autofocus = widget.control.attrBool("autofocus", false)!;
4457
bool disabled = widget.control.isDisabled || widget.parentDisabled;
4558

4659
String? value = widget.control.attrString("value");
@@ -54,6 +67,8 @@ class _DropdownControlState extends State<DropdownControl> {
5467
itemsView.children.where((c) => c.name == "suffix");
5568

5669
var dropDown = DropdownButtonFormField<String>(
70+
autofocus: autofocus,
71+
focusNode: _focusNode,
5772
value: _value,
5873
decoration: buildInputDecoration(
5974
widget.control,

client/lib/controls/elevated_button.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class ElevatedButtonControl extends StatelessWidget {
2929
Color? iconColor =
3030
HexColor.fromString(context, control.attrString("iconColor", "")!);
3131
var contentCtrls = children.where((c) => c.name == "content");
32+
bool autofocus = control.attrBool("autofocus", false)!;
3233
bool disabled = control.isDisabled || parentDisabled;
3334

3435
Function()? onPressed = disabled
@@ -45,6 +46,7 @@ class ElevatedButtonControl extends StatelessWidget {
4546

4647
if (icon != null) {
4748
button = ElevatedButton.icon(
49+
autofocus: autofocus,
4850
onPressed: onPressed,
4951
icon: Icon(
5052
icon,
@@ -53,6 +55,7 @@ class ElevatedButtonControl extends StatelessWidget {
5355
label: Text(text));
5456
} else if (contentCtrls.isNotEmpty) {
5557
button = ElevatedButton(
58+
autofocus: autofocus,
5659
onPressed: onPressed,
5760
child: createControl(control, contentCtrls.first.id, disabled));
5861
} else {

client/lib/controls/floating_action_button.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class FloatingActionButtonControl extends StatelessWidget {
3030
Color? bgColor =
3131
HexColor.fromString(context, control.attrString("bgColor", "")!);
3232
var contentCtrls = children.where((c) => c.name == "content");
33+
bool autofocus = control.attrBool("autofocus", false)!;
3334
bool disabled = control.isDisabled || parentDisabled;
3435

3536
Function()? onPressed = disabled
@@ -49,16 +50,19 @@ class FloatingActionButtonControl extends StatelessWidget {
4950
Widget button;
5051
if (contentCtrls.isNotEmpty) {
5152
button = FloatingActionButton(
53+
autofocus: autofocus,
5254
onPressed: onPressed,
5355
child: createControl(control, contentCtrls.first.id, disabled));
5456
} else if (icon != null && text == null) {
5557
button = FloatingActionButton(
58+
autofocus: autofocus,
5659
onPressed: onPressed,
5760
child: Icon(icon),
5861
backgroundColor: bgColor,
5962
);
6063
} else if (icon != null && text != null) {
6164
button = FloatingActionButton.extended(
65+
autofocus: autofocus,
6266
onPressed: onPressed,
6367
label: Text(text),
6468
icon: Icon(icon),

client/lib/controls/grid_view.dart

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,35 @@ class GridViewControl extends StatelessWidget {
2626

2727
final horizontal = control.attrBool("horizontal", false)!;
2828
final runsCount = control.attrInt("runsCount", 1)!;
29+
final maxExtent = control.attrDouble("maxExtent");
2930
final spacing = control.attrDouble("spacing", 10)!;
3031
final runSpacing = control.attrDouble("runSpacing", 10)!;
3132
final padding = parseEdgeInsets(control, "padding");
32-
33-
List<Widget> controls =
34-
children.map((c) => createControl(control, c.id, disabled)).toList();
33+
final childAspectRatio = control.attrDouble("childAspectRatio", 1)!;
34+
35+
List<Control> visibleControls = children.where((c) => c.isVisible).toList();
36+
37+
var gridDelegate = maxExtent == null
38+
? SliverGridDelegateWithFixedCrossAxisCount(
39+
crossAxisCount: runsCount,
40+
mainAxisSpacing: spacing,
41+
crossAxisSpacing: runSpacing,
42+
childAspectRatio: childAspectRatio)
43+
: SliverGridDelegateWithMaxCrossAxisExtent(
44+
maxCrossAxisExtent: maxExtent,
45+
mainAxisSpacing: spacing,
46+
crossAxisSpacing: runSpacing,
47+
childAspectRatio: childAspectRatio);
3548

3649
return constrainedControl(
37-
GridView.count(
50+
GridView.builder(
3851
scrollDirection: horizontal ? Axis.horizontal : Axis.vertical,
39-
crossAxisCount: runsCount,
40-
mainAxisSpacing: spacing,
41-
crossAxisSpacing: runSpacing,
4252
padding: padding,
43-
children: controls,
53+
gridDelegate: gridDelegate,
54+
itemCount: visibleControls.length,
55+
itemBuilder: (context, index) {
56+
return createControl(control, visibleControls[index].id, disabled);
57+
},
4458
),
4559
parent,
4660
control);

client/lib/controls/icon_button.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ class IconButtonControl extends StatelessWidget {
2525
Widget build(BuildContext context) {
2626
debugPrint("Button build: ${control.id}");
2727

28-
String? tooltip = control.attrString("tooltip");
2928
IconData? icon = getMaterialIcon(control.attrString("icon", "")!);
3029
Color? iconColor =
3130
HexColor.fromString(context, control.attrString("iconColor", "")!);
3231
double? iconSize = control.attrDouble("iconSize");
3332
var contentCtrls = children.where((c) => c.name == "content");
33+
bool autofocus = control.attrBool("autofocus", false)!;
3434
bool disabled = control.isDisabled || parentDisabled;
3535

3636
Function()? onPressed = disabled
@@ -47,18 +47,18 @@ class IconButtonControl extends StatelessWidget {
4747

4848
if (icon != null) {
4949
button = IconButton(
50+
autofocus: autofocus,
5051
icon: Icon(
5152
icon,
5253
color: iconColor,
5354
),
5455
iconSize: iconSize,
55-
tooltip: tooltip,
5656
onPressed: onPressed);
5757
} else if (contentCtrls.isNotEmpty) {
5858
button = IconButton(
59+
autofocus: autofocus,
5960
onPressed: onPressed,
6061
iconSize: iconSize,
61-
tooltip: tooltip,
6262
icon: createControl(control, contentCtrls.first.id, disabled));
6363
} else {
6464
return const ErrorControl(

0 commit comments

Comments
 (0)