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}