Skip to content

Commit e181947

Browse files
committed
Shift-Enter mode for TextField
1 parent 6aca794 commit e181947

File tree

4 files changed

+68
-1
lines changed

4 files changed

+68
-1
lines changed

client/lib/controls/textfield.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:flutter/material.dart';
2+
import 'package:flutter/services.dart';
23
import 'package:flutter_redux/flutter_redux.dart';
34

45
import '../actions.dart';
@@ -32,6 +33,22 @@ class _TextFieldControlState extends State<TextFieldControl> {
3233
bool _revealPassword = false;
3334
late TextEditingController _controller;
3435

36+
late final _focusNode = FocusNode(
37+
onKey: (FocusNode node, RawKeyEvent evt) {
38+
if (!evt.isShiftPressed && evt.logicalKey.keyLabel == 'Enter') {
39+
if (evt is RawKeyDownEvent) {
40+
ws.pageEventFromWeb(
41+
eventTarget: widget.control.id,
42+
eventName: "submit",
43+
eventData: "");
44+
}
45+
return KeyEventResult.handled;
46+
} else {
47+
return KeyEventResult.ignored;
48+
}
49+
},
50+
);
51+
3552
@override
3653
void initState() {
3754
super.initState();
@@ -70,8 +87,10 @@ class _TextFieldControlState extends State<TextFieldControl> {
7087

7188
bool readOnly = widget.control.attrBool("readOnly", false)!;
7289
bool password = widget.control.attrBool("password", false)!;
90+
bool shiftEnter = widget.control.attrBool("shiftEnter", false)!;
7391
bool canRevealPassword =
7492
widget.control.attrBool("canRevealPassword", false)!;
93+
bool onChange = widget.control.attrBool("onChange", false)!;
7594

7695
Widget? revealPasswordIcon;
7796
if (password && canRevealPassword) {
@@ -116,6 +135,9 @@ class _TextFieldControlState extends State<TextFieldControl> {
116135
readOnly: readOnly,
117136
obscureText: password && !_revealPassword,
118137
controller: _controller,
138+
focusNode: keyboardType == TextInputType.multiline && shiftEnter
139+
? _focusNode
140+
: null,
119141
onChanged: (String value) {
120142
debugPrint(value);
121143
setState(() {
@@ -127,6 +149,12 @@ class _TextFieldControlState extends State<TextFieldControl> {
127149
dispatch(UpdateControlPropsAction(
128150
UpdateControlPropsPayload(props: props)));
129151
ws.updateControlProps(props: props);
152+
if (onChange) {
153+
ws.pageEventFromWeb(
154+
eventTarget: widget.control.id,
155+
eventName: "change",
156+
eventData: value);
157+
}
130158
});
131159

132160
return constrainedControl(textField, widget.parent, widget.control);

docs/roadmap.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
* Complex embeddable values for `padding`, `marging`, etc, e.g. `.padding = { 'left': 10, 'right': 20 }`
6464
* Visual Density ([more](https://api.flutter.dev/flutter/material/VisualDensity-class.html))
6565
* Early detection of layout issues (like enabling scrolling in unbounded controls) with [Layout Builder](https://api.flutter.dev/flutter/widgets/LayoutBuilder-class.html).
66+
* Scroll speed on Windows Desktop [The issue](https://github.com/flutter/flutter/issues/67985)
6667

6768
* Flet Client
6869
* Web

sdk/python/flet/textfield.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,10 @@ def __init__(
6666
password: bool = None,
6767
can_reveal_password: bool = None,
6868
read_only: bool = None,
69+
shift_enter: bool = None,
6970
text_align: TextAlign = None,
7071
on_change=None,
72+
on_submit=None,
7173
):
7274
FormFieldControl.__init__(
7375
self,
@@ -104,9 +106,11 @@ def __init__(
104106
self.min_lines = min_lines
105107
self.max_lines = max_lines
106108
self.read_only = read_only
109+
self.shift_enter = shift_enter
107110
self.password = password
108111
self.can_reveal_password = can_reveal_password
109112
self.on_change = on_change
113+
self.on_submit = on_submit
110114

111115
def _get_control_name(self):
112116
return "textfield"
@@ -170,6 +174,16 @@ def read_only(self):
170174
def read_only(self, value: Optional[bool]):
171175
self._set_attr("readOnly", value)
172176

177+
# shift_enter
178+
@property
179+
def shift_enter(self):
180+
return self._get_attr("shiftEnter", data_type="bool", def_value=False)
181+
182+
@shift_enter.setter
183+
@beartype
184+
def shift_enter(self, value: Optional[bool]):
185+
self._set_attr("shiftEnter", value)
186+
173187
# password
174188
@property
175189
def password(self):
@@ -202,3 +216,12 @@ def on_change(self, handler):
202216
self._set_attr("onchange", True)
203217
else:
204218
self._set_attr("onchange", None)
219+
220+
# on_submit
221+
@property
222+
def on_submit(self):
223+
return self._get_event_handler("submit")
224+
225+
@on_submit.setter
226+
def on_submit(self, handler):
227+
self._add_event_handler("submit", handler)

sdk/python/playground/textfield-test.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,17 @@ def main(page: Page):
3939
page.theme_mode = "light"
4040
page.padding = padding.all(20)
4141

42-
results = Column(scroll="always", height=100)
42+
def chat_submit(e):
43+
print(f"Submit FieldText: {e.control.value}")
44+
e.control.value = ""
45+
page.update()
46+
47+
chat_input = TextField(
48+
hint_text="Say something...",
49+
min_lines=1,
50+
shift_enter=True,
51+
on_submit=chat_submit,
52+
)
4353

4454
page.add(
4555
Column(
@@ -66,6 +76,11 @@ def main(page: Page):
6676
filled=True,
6777
min_lines=1,
6878
),
79+
Text(
80+
"New line - Shift + Enter and submit on Enter",
81+
style="headlineSmall",
82+
),
83+
chat_input,
6984
Text(
7085
"Login with email/password",
7186
style="headlineSmall",

0 commit comments

Comments
 (0)