fix: extract manual entry dialog into StatefulWidget
Fixes TextEditingController used after being disposed the controller was being manually disposed while the dialog's TextField still held a reference during the pop animation. Now the dialog is its own StatefulWidget so dispose() is called automatically by the framework at the right time.
This commit is contained in:
parent
024c05734b
commit
7635b0d85b
1 changed files with 51 additions and 30 deletions
|
|
@ -212,42 +212,63 @@ class _ScannerScreenState extends State<ScannerScreen> {
|
||||||
|
|
||||||
/// Fallback: let the user type the HW ID manually.
|
/// Fallback: let the user type the HW ID manually.
|
||||||
Future<void> _showManualEntry(BuildContext context) async {
|
Future<void> _showManualEntry(BuildContext context) async {
|
||||||
final controller = TextEditingController();
|
|
||||||
|
|
||||||
final result = await showDialog<String>(
|
final result = await showDialog<String>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AlertDialog(
|
builder: (_) => const _ManualEntryDialog(),
|
||||||
title: const Text('Enter HW ID'),
|
|
||||||
content: TextField(
|
|
||||||
controller: controller,
|
|
||||||
autofocus: true,
|
|
||||||
textCapitalization: TextCapitalization.characters,
|
|
||||||
decoration: const InputDecoration(
|
|
||||||
hintText: 'e.g. JKF21',
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.of(ctx).pop(),
|
|
||||||
child: const Text('Cancel'),
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
final value = controller.text.trim().toUpperCase();
|
|
||||||
if (value.isNotEmpty) Navigator.of(ctx).pop(value);
|
|
||||||
},
|
|
||||||
child: const Text('OK'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result != null && context.mounted) {
|
if (result != null && context.mounted) {
|
||||||
controller.dispose();
|
|
||||||
Navigator.of(context).pop(result);
|
Navigator.of(context).pop(result);
|
||||||
} else {
|
|
||||||
controller.dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Manual Entry Dialog ───────────────────────────────────────────────
|
||||||
|
class _ManualEntryDialog extends StatefulWidget {
|
||||||
|
const _ManualEntryDialog();
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_ManualEntryDialog> createState() => _ManualEntryDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ManualEntryDialogState extends State<_ManualEntryDialog> {
|
||||||
|
final _controller = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _submit() {
|
||||||
|
final value = _controller.text.trim().toUpperCase();
|
||||||
|
if (value.isNotEmpty) Navigator.of(context).pop(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('Enter HW ID'),
|
||||||
|
content: TextField(
|
||||||
|
controller: _controller,
|
||||||
|
autofocus: true,
|
||||||
|
textCapitalization: TextCapitalization.characters,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
hintText: 'e.g. JKF21',
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
onSubmitted: (_) => _submit(),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: const Text('Cancel'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: _submit,
|
||||||
|
child: const Text('OK'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue