fix(desktop-pin-code-issue): persist FocusNode so KeyboardListener works on macOS
Previously, every rebuild created a new FocusNode, so KeyboardListener never held focus and missed key events on macOS. This change: - Moves the FocusNode into state and initializes it in initState - Requests focus once after the first frame - Disposes of the FocusNode in dispose - Removes the inline FocusNode creation from build
Blazebrain committed
Apr 17, 2025 at 07:51 UTC
d9c01a5d07c2ce44064c2e9f2191ab31e93995ad
1 file changed
+23
-8
lib/src/screens/pin_code/pin_code_widget.dart
+23
-8
@@ -38,6 +38,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
38
static const fourPinLength = 4;
39
final _gridViewKey = GlobalKey();
40
final _key = GlobalKey<ScaffoldState>();
41
+ late final FocusNode _focusNode;
42
43
int pinLength;
44
String pin;
@@ -54,7 +55,17 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
55
pin = '';
56
title = S.current.enter_your_pin;
57
_aspectRatio = 0;
57
- WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
58
+ _focusNode = FocusNode();
59
+ WidgetsBinding.instance.addPostFrameCallback((_) {
60
+ _focusNode.requestFocus();
61
+ _afterLayout(_);
62
+ });
63
+ }
64
+
65
+ @override
66
+ void dispose() {
67
+ _focusNode.dispose();
68
+ super.dispose();
69
}
70
71
void setTitle(String title) => setState(() => this.title = title);
@@ -120,8 +131,8 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
131
);
132
133
return KeyboardListener(
123
- focusNode: FocusNode(),
124
- autofocus: true,
134
+ focusNode: _focusNode,
135
+ autofocus: false,
136
onKeyEvent: (keyEvent) {
137
if (keyEvent is KeyDownEvent) {
138
if (keyEvent.logicalKey.keyLabel == "Backspace") {
@@ -144,8 +155,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
155
style: TextStyle(
156
fontSize: 20,
157
fontWeight: FontWeight.w500,
147
- color:
148
- Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
158
+ color: Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
159
Spacer(flex: 8),
160
Container(
161
width: 180,
@@ -162,7 +172,9 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
172
shape: BoxShape.circle,
173
color: isFilled
174
? Theme.of(context).extension<CakeTextTheme>()!.titleColor
165
- : Theme.of(context).extension<PinCodeTheme>()!.indicatorsColor
175
+ : Theme.of(context)
176
+ .extension<PinCodeTheme>()!
177
+ .indicatorsColor
178
.withOpacity(0.25),
179
));
180
}),
@@ -225,7 +237,8 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
237
child: TextButton(
238
onPressed: () => _pop(),
239
style: TextButton.styleFrom(
228
- backgroundColor: Theme.of(context).colorScheme.background,
240
+ backgroundColor:
241
+ Theme.of(context).colorScheme.background,
242
shape: CircleBorder(),
243
),
244
child: deleteIconImage,
@@ -250,7 +263,9 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
263
style: TextStyle(
264
fontSize: 25.0,
265
fontWeight: FontWeight.w600,
253
- color: Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
266
+ color: Theme.of(context)
267
+ .extension<CakeTextTheme>()!
268
+ .titleColor)),
269
),
270
);
271
}),