Skip to content

Commit 0a16c0f

Browse files
authored
Chip control (#1973)
* added Chip with label property * label, bgcolor for Chip * on_click * on_delete for chip * refactor * refactor * select for Chip * Leading for Chip * autofocus for Chip * check if on_click and on_select are both specified * check_color for Chip * deleteButtonTooltipMessage for Chip * delete_icon for Chip * delete_icon_color for Chip * disabled_color for Chip * elevation for Chip * label_padding for Chip * label_style for Chip * padding for Chip * selected_color for Chip * selected_shadow_color for Chip * shadow_color for Chip * refactor * shape for Chip * show_checkmark for Chip * refactor * refactor * delete_button_tooltip_message renamed to delete_icon_tooltip_message * delete_icon_tooltip_message renamed to delete_icon_tooltip
1 parent b66a1f6 commit 0a16c0f

File tree

5 files changed

+587
-1
lines changed

5 files changed

+587
-1
lines changed

package/lib/src/controls/chip.dart

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
import 'package:flutter/material.dart';
2+
3+
import '../models/control.dart';
4+
import '../utils/colors.dart';
5+
import 'create_control.dart';
6+
import 'error.dart';
7+
import 'package:flet/src/flet_app_services.dart';
8+
import '../actions.dart';
9+
import '../protocol/update_control_props_payload.dart';
10+
import '../utils/edge_insets.dart';
11+
import '../utils/text.dart';
12+
import '../utils/borders.dart';
13+
14+
class ChipControl extends StatefulWidget {
15+
final Control? parent;
16+
final Control control;
17+
final List<Control> children;
18+
final bool parentDisabled;
19+
final dynamic dispatch;
20+
21+
const ChipControl(
22+
{Key? key,
23+
this.parent,
24+
required this.control,
25+
required this.children,
26+
required this.parentDisabled,
27+
required this.dispatch})
28+
: super(key: key);
29+
30+
@override
31+
State<ChipControl> createState() => _ChipControlState();
32+
}
33+
34+
class _ChipControlState extends State<ChipControl> {
35+
bool _selected = false;
36+
37+
late final FocusNode _focusNode;
38+
39+
@override
40+
void initState() {
41+
super.initState();
42+
_focusNode = FocusNode();
43+
_focusNode.addListener(_onFocusChange);
44+
}
45+
46+
@override
47+
void dispose() {
48+
_focusNode.removeListener(_onFocusChange);
49+
_focusNode.dispose();
50+
super.dispose();
51+
}
52+
53+
void _onSelect(bool selected) {
54+
var strSelected = selected.toString();
55+
debugPrint(strSelected);
56+
setState(() {
57+
_selected = selected;
58+
});
59+
List<Map<String, String>> props = [
60+
{"i": widget.control.id, "selected": strSelected}
61+
];
62+
widget.dispatch(
63+
UpdateControlPropsAction(UpdateControlPropsPayload(props: props)));
64+
final server = FletAppServices.of(context).server;
65+
server.updateControlProps(props: props);
66+
server.sendPageEvent(
67+
eventTarget: widget.control.id,
68+
eventName: "select",
69+
eventData: strSelected);
70+
}
71+
72+
void _onFocusChange() {
73+
FletAppServices.of(context).server.sendPageEvent(
74+
eventTarget: widget.control.id,
75+
eventName: _focusNode.hasFocus ? "focus" : "blur",
76+
eventData: "");
77+
}
78+
79+
@override
80+
Widget build(BuildContext context) {
81+
debugPrint("Chip build: ${widget.control.id}");
82+
83+
var labelCtrls =
84+
widget.children.where((c) => c.name == "label" && c.isVisible);
85+
var leadingCtrls =
86+
widget.children.where((c) => c.name == "leading" && c.isVisible);
87+
var deleteIconCtrls =
88+
widget.children.where((c) => c.name == "deleteIcon" && c.isVisible);
89+
90+
if (labelCtrls.isEmpty) {
91+
return const ErrorControl("Chip must have label specified.");
92+
}
93+
94+
bool disabled = widget.control.isDisabled || widget.parentDisabled;
95+
96+
var bgcolor = HexColor.fromString(
97+
Theme.of(context), widget.control.attrString("bgcolor", "")!);
98+
var deleteIconColor = HexColor.fromString(
99+
Theme.of(context), widget.control.attrString("deleteIconColor", "")!);
100+
var disabledColor = HexColor.fromString(
101+
Theme.of(context), widget.control.attrString("disabledColor", "")!);
102+
103+
final server = FletAppServices.of(context).server;
104+
bool onClick = widget.control.attrBool("onclick", false)!;
105+
bool onDelete = widget.control.attrBool("onDelete", false)!;
106+
bool onSelect = widget.control.attrBool("onSelect", false)!;
107+
108+
if (onSelect && onClick) {
109+
return const ErrorControl(
110+
"Chip cannot have both on_select and on_click events specified.");
111+
}
112+
113+
bool autofocus = widget.control.attrBool("autofocus", false)!;
114+
bool selected = widget.control.attrBool("selected", false)!;
115+
if (_selected != selected) {
116+
_selected = selected;
117+
}
118+
bool showCheckmark = widget.control.attrBool("showCheckmark", true)!;
119+
String deleteButtonTooltipMessage =
120+
widget.control.attrString("deleteButtonTooltipMessage", "")!;
121+
122+
var elevation = widget.control.attrDouble("elevation");
123+
124+
Function()? onClickHandler = onClick && !disabled
125+
? () {
126+
debugPrint("Chip ${widget.control.id} clicked!");
127+
server.sendPageEvent(
128+
eventTarget: widget.control.id,
129+
eventName: "click",
130+
eventData: "");
131+
}
132+
: null;
133+
134+
Function()? onDeleteHandler = onDelete && !disabled
135+
? () {
136+
debugPrint("Chip ${widget.control.id} deleted!");
137+
server.sendPageEvent(
138+
eventTarget: widget.control.id,
139+
eventName: "delete",
140+
eventData: "");
141+
}
142+
: null;
143+
144+
return constrainedControl(
145+
context,
146+
InputChip(
147+
autofocus: autofocus,
148+
focusNode: _focusNode,
149+
label: createControl(widget.control, labelCtrls.first.id, disabled),
150+
avatar: leadingCtrls.isNotEmpty
151+
? createControl(widget.control, leadingCtrls.first.id, disabled)
152+
: null,
153+
backgroundColor: bgcolor,
154+
checkmarkColor: HexColor.fromString(
155+
Theme.of(context), widget.control.attrString("checkColor", "")!),
156+
selected: _selected,
157+
showCheckmark: showCheckmark,
158+
deleteButtonTooltipMessage: deleteButtonTooltipMessage,
159+
onPressed: onClickHandler,
160+
onDeleted: onDeleteHandler,
161+
onSelected: onSelect && !disabled
162+
? (bool selected) {
163+
_onSelect(selected);
164+
}
165+
: null,
166+
deleteIcon: deleteIconCtrls.isNotEmpty
167+
? createControl(
168+
widget.control, deleteIconCtrls.first.id, disabled)
169+
: null,
170+
deleteIconColor: deleteIconColor,
171+
disabledColor: disabledColor,
172+
elevation: elevation,
173+
isEnabled: !disabled,
174+
padding: parseEdgeInsets(widget.control, "padding"),
175+
labelPadding: parseEdgeInsets(widget.control, "labelPadding"),
176+
labelStyle:
177+
parseTextStyle(Theme.of(context), widget.control, "labelStyle"),
178+
selectedColor: HexColor.fromString(Theme.of(context),
179+
widget.control.attrString("selectedColor", "")!),
180+
selectedShadowColor: HexColor.fromString(Theme.of(context),
181+
widget.control.attrString("selectedShadowColor", "")!),
182+
shadowColor: HexColor.fromString(
183+
Theme.of(context), widget.control.attrString("shadowColor", "")!),
184+
shape: parseOutlinedBorder(widget.control, "shape"),
185+
),
186+
widget.parent,
187+
widget.control);
188+
}
189+
}

package/lib/src/controls/create_control.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import 'bottom_sheet.dart';
2121
import 'canvas.dart';
2222
import 'card.dart';
2323
import 'checkbox.dart';
24+
import 'chip.dart';
2425
import 'circle_avatar.dart';
2526
import 'clipboard.dart';
2627
import 'column.dart';
@@ -206,6 +207,15 @@ Widget createWidget(Key? key, ControlViewModel controlView, Control? parent,
206207
control: controlView.control,
207208
children: controlView.children,
208209
parentDisabled: parentDisabled);
210+
case "chip":
211+
return ChipControl(
212+
key: key,
213+
parent: parent,
214+
control: controlView.control,
215+
children: controlView.children,
216+
parentDisabled: parentDisabled,
217+
dispatch: controlView.dispatch);
218+
209219
case "progressring":
210220
return ProgressRingControl(
211221
key: key, parent: parent, control: controlView.control);

sdk/python/packages/flet-core/src/flet_core/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
StadiumBorder,
3535
)
3636
from flet_core.card import Card
37+
from flet_core.chip import Chip
3738
from flet_core.charts.bar_chart import BarChart, BarChartEvent
3839
from flet_core.charts.bar_chart_group import BarChartGroup
3940
from flet_core.charts.bar_chart_rod import BarChartRod

sdk/python/packages/flet-core/src/flet_core/card.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,10 @@ def __init__(
8484
visible: Optional[bool] = None,
8585
disabled: Optional[bool] = None,
8686
data: Any = None,
87+
key: Optional[str] = None,
8788
#
8889
# Specific
8990
#
90-
key: Optional[str] = None,
9191
margin: MarginValue = None,
9292
elevation: OptionalNumber = None,
9393
color: Optional[str] = None,

0 commit comments

Comments
 (0)