main
1import 'package:flutter/material.dart';
2import 'package:flutter/services.dart';
3import 'package:blood_pressure_app/l10n/app_localizations.dart';
4
5/// Alert dialoge for prompting single value input from the user.
6class InputDialoge extends StatefulWidget {
7 /// Creates an [AlertDialog] with an text input field.
8 ///
9 /// Pops the context after value submission with object of type [String?].
10 const InputDialoge({super.key,
11 this.hintText,
12 this.initialValue,
13 this.inputFormatters,
14 this.keyboardType,
15 this.validator,});
16
17 /// Initial content of the input field.
18 final String? initialValue;
19
20 /// Supporting text describing the input field.
21 final String? hintText;
22
23 /// Optional input validation and formatting overrides.
24 final List<TextInputFormatter>? inputFormatters;
25
26 /// The type of keyboard to use for editing the text.
27 final TextInputType? keyboardType;
28
29 /// Validation function called after submit.
30 ///
31 /// When the validator returns null the dialoge completes normally,
32 /// in case of receiving a String it will be displayed to the user
33 /// and pressing of the submit button will be ignored.
34 ///
35 /// It is still possible to cancel a dialoge in case the validator fails.
36 final String? Function(String)? validator;
37
38 @override
39 State<InputDialoge> createState() => _InputDialogeState();
40}
41
42class _InputDialogeState extends State<InputDialoge> {
43 final controller = TextEditingController();
44 final focusNode = FocusNode();
45
46 String? errorText;
47
48 @override
49 void initState() {
50 super.initState();
51 if (widget.initialValue != null) controller.text = widget.initialValue!;
52 focusNode.requestFocus();
53 }
54
55 @override
56 void dispose() {
57 controller.dispose();
58 focusNode.dispose();
59 super.dispose();
60 }
61
62 @override
63 Widget build(BuildContext context) {
64 final localizations = AppLocalizations.of(context)!;
65 return AlertDialog(
66 content: TextField(
67 controller: controller,
68 focusNode: focusNode,
69 inputFormatters: widget.inputFormatters,
70 keyboardType: widget.keyboardType,
71 decoration: InputDecoration(
72 hintText: widget.hintText,
73 labelText: widget.hintText,
74 errorText: errorText,
75 ),
76 onSubmitted: _onSubmit,
77 ),
78 actions: [
79 TextButton(
80 onPressed: () => Navigator.pop(context),
81 child: Text(localizations.btnCancel),
82 ),
83 ElevatedButton(
84 onPressed: () => _onSubmit(controller.text),
85 child: Text(localizations.btnConfirm),),
86 ],
87 );
88 }
89
90 void _onSubmit(String value) {
91 final validationResult = widget.validator?.call(value);
92 if (validationResult != null) {
93 setState(() {
94 errorText = validationResult;
95 });
96 return;
97 }
98 Navigator.pop(context, value);
99 }
100}
101
102/// Creates a dialoge for prompting a single user input.
103///
104/// Add supporting text describing the input field through [hintText].
105/// [initialValue] specifies the initial input field content.
106Future<String?> showInputDialoge(BuildContext context, {String? hintText, String? initialValue}) async =>
107 showDialog<String?>(context: context, builder: (context) =>
108 InputDialoge(hintText: hintText, initialValue: initialValue,),);
109
110/// Creates a dialoge that only allows int and double inputs.
111///
112/// Variables behave similar to [showInputDialoge].
113Future<double?> showNumberInputDialoge(BuildContext context, {String? hintText, num? initialValue}) async {
114 final result = await showDialog<String?>(context: context, builder: (context) =>
115 InputDialoge(
116 hintText: hintText,
117 initialValue: initialValue?.toString(),
118 inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'([0-9]+(\.([0-9]*))?)')),],
119 keyboardType: TextInputType.number,
120 validator: (text) {
121 double? value = double.tryParse(text);
122 value ??= int.tryParse(text)?.toDouble();
123 if (text.isEmpty || value == null) {
124 return AppLocalizations.of(context)!.errNaN;
125 }
126 return null;
127 },
128 ),);
129
130 double? value = double.tryParse(result ?? '');
131 value ??= int.tryParse(result ?? '')?.toDouble();
132 return value;
133}