Browse Source

Dialog for custom radius with input restrictions

ashilkn 2 years ago
parent
commit
9277a83783

+ 3 - 0
lib/ui/components/dialog_widget.dart

@@ -177,6 +177,7 @@ class TextInputDialog extends StatefulWidget {
   final bool isPasswordInput;
   final bool isPasswordInput;
   final TextEditingController? textEditingController;
   final TextEditingController? textEditingController;
   final List<TextInputFormatter>? textInputFormatter;
   final List<TextInputFormatter>? textInputFormatter;
+  final TextInputType? textInputType;
   const TextInputDialog({
   const TextInputDialog({
     required this.title,
     required this.title,
     this.body,
     this.body,
@@ -196,6 +197,7 @@ class TextInputDialog extends StatefulWidget {
     this.isPasswordInput = false,
     this.isPasswordInput = false,
     this.textEditingController,
     this.textEditingController,
     this.textInputFormatter,
     this.textInputFormatter,
+    this.textInputType,
     super.key,
     super.key,
   });
   });
 
 
@@ -258,6 +260,7 @@ class _TextInputDialogState extends State<TextInputDialog> {
                 isPasswordInput: widget.isPasswordInput,
                 isPasswordInput: widget.isPasswordInput,
                 textEditingController: widget.textEditingController,
                 textEditingController: widget.textEditingController,
                 textInputFormatter: widget.textInputFormatter,
                 textInputFormatter: widget.textInputFormatter,
+                textInputType: widget.textInputType,
               ),
               ),
             ),
             ),
             const SizedBox(height: 36),
             const SizedBox(height: 36),

+ 3 - 0
lib/ui/components/text_input_widget.dart

@@ -42,6 +42,7 @@ class TextInputWidget extends StatefulWidget {
   final TextEditingController? textEditingController;
   final TextEditingController? textEditingController;
   final ValueNotifier? isEmptyNotifier;
   final ValueNotifier? isEmptyNotifier;
   final List<TextInputFormatter>? textInputFormatter;
   final List<TextInputFormatter>? textInputFormatter;
+  final TextInputType? textInputType;
   const TextInputWidget({
   const TextInputWidget({
     this.onSubmit,
     this.onSubmit,
     this.onChange,
     this.onChange,
@@ -69,6 +70,7 @@ class TextInputWidget extends StatefulWidget {
     this.textEditingController,
     this.textEditingController,
     this.isEmptyNotifier,
     this.isEmptyNotifier,
     this.textInputFormatter,
     this.textInputFormatter,
+    this.textInputType,
     super.key,
     super.key,
   });
   });
 
 
@@ -145,6 +147,7 @@ class _TextInputWidgetState extends State<TextInputWidget> {
         borderRadius: BorderRadius.all(Radius.circular(widget.borderRadius)),
         borderRadius: BorderRadius.all(Radius.circular(widget.borderRadius)),
         child: Material(
         child: Material(
           child: TextFormField(
           child: TextFormField(
+            keyboardType: widget.textInputType,
             textCapitalization: widget.textCapitalization!,
             textCapitalization: widget.textCapitalization!,
             autofocus: widget.autoFocus ?? false,
             autofocus: widget.autoFocus ?? false,
             controller: _textController,
             controller: _textController,

+ 73 - 29
lib/ui/viewer/location/radius_picker_widget.dart

@@ -1,9 +1,11 @@
 import "package:flutter/material.dart";
 import "package:flutter/material.dart";
+import "package:flutter/services.dart";
 import "package:photos/core/constants.dart";
 import "package:photos/core/constants.dart";
 import "package:photos/generated/l10n.dart";
 import "package:photos/generated/l10n.dart";
 import "package:photos/states/location_state.dart";
 import "package:photos/states/location_state.dart";
 import "package:photos/theme/colors.dart";
 import "package:photos/theme/colors.dart";
 import "package:photos/theme/ente_theme.dart";
 import "package:photos/theme/ente_theme.dart";
+import "package:photos/utils/dialog_util.dart";
 
 
 class CustomTrackShape extends RoundedRectSliderTrackShape {
 class CustomTrackShape extends RoundedRectSliderTrackShape {
   @override
   @override
@@ -56,37 +58,52 @@ class _RadiusPickerWidgetState extends State<RadiusPickerWidget> {
     return Row(
     return Row(
       crossAxisAlignment: CrossAxisAlignment.start,
       crossAxisAlignment: CrossAxisAlignment.start,
       children: [
       children: [
-        Container(
-          height: 48,
-          width: 48,
-          decoration: BoxDecoration(
-            color: colorScheme.fillFaint,
-            borderRadius: const BorderRadius.all(Radius.circular(2)),
-          ),
-          padding: const EdgeInsets.all(4),
-          child: Column(
-            mainAxisSize: MainAxisSize.min,
-            mainAxisAlignment: MainAxisAlignment.center,
-            crossAxisAlignment: CrossAxisAlignment.center,
-            children: [
-              Expanded(
-                flex: 6,
-                child: Text(
-                  roundedRadius,
-                  style: double.parse(roundedRadius) < 1000
-                      ? textTheme.largeBold
-                      : textTheme.bodyBold,
-                  textAlign: TextAlign.center,
+        GestureDetector(
+          onTap: () {
+            showTextInputDialog(
+              context,
+              title: "Custom radius",
+              onSubmit: (customRadius) async {},
+              submitButtonLabel: "Done",
+              textInputFormatter: [
+                NumberWithDecimalInputFormatter(maxValue: 10000)
+              ],
+              textInputType:
+                  const TextInputType.numberWithOptions(decimal: true),
+            );
+          },
+          child: Container(
+            height: 48,
+            width: 48,
+            decoration: BoxDecoration(
+              color: colorScheme.fillFaint,
+              borderRadius: const BorderRadius.all(Radius.circular(2)),
+            ),
+            padding: const EdgeInsets.all(4),
+            child: Column(
+              mainAxisSize: MainAxisSize.min,
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                Expanded(
+                  flex: 6,
+                  child: Text(
+                    roundedRadius,
+                    style: double.parse(roundedRadius) < 1000
+                        ? textTheme.largeBold
+                        : textTheme.bodyBold,
+                    textAlign: TextAlign.center,
+                  ),
                 ),
                 ),
-              ),
-              Expanded(
-                flex: 5,
-                child: Text(
-                  S.of(context).kiloMeterUnit,
-                  style: textTheme.miniMuted,
+                Expanded(
+                  flex: 5,
+                  child: Text(
+                    S.of(context).kiloMeterUnit,
+                    style: textTheme.miniMuted,
+                  ),
                 ),
                 ),
-              ),
-            ],
+              ],
+            ),
           ),
           ),
         ),
         ),
         const SizedBox(width: 4),
         const SizedBox(width: 4),
@@ -161,3 +178,30 @@ class _RadiusPickerWidgetState extends State<RadiusPickerWidget> {
     return result;
     return result;
   }
   }
 }
 }
+
+class NumberWithDecimalInputFormatter extends TextInputFormatter {
+  final RegExp _pattern = RegExp(r'^(?:\d+(\.\d*)?)?$');
+  final double maxValue;
+
+  NumberWithDecimalInputFormatter({required this.maxValue});
+
+  @override
+  TextEditingValue formatEditUpdate(
+    TextEditingValue oldValue,
+    TextEditingValue newValue,
+  ) {
+    // Check if the new value matches the pattern
+    if (_pattern.hasMatch(newValue.text)) {
+      if (newValue.text.isEmpty) {
+        return newValue;
+      }
+      final newValueAsDouble = double.tryParse(newValue.text);
+
+      // Check if the new value is within the allowed range
+      if (newValueAsDouble != null && newValueAsDouble <= maxValue) {
+        return newValue;
+      }
+    }
+    return oldValue;
+  }
+}

+ 2 - 0
lib/utils/dialog_util.dart

@@ -306,6 +306,7 @@ Future<dynamic> showTextInputDialog(
   bool isPasswordInput = false,
   bool isPasswordInput = false,
   TextEditingController? textEditingController,
   TextEditingController? textEditingController,
   List<TextInputFormatter>? textInputFormatter,
   List<TextInputFormatter>? textInputFormatter,
+  TextInputType? textInputType,
 }) {
 }) {
   return showDialog(
   return showDialog(
     barrierColor: backdropFaintDark,
     barrierColor: backdropFaintDark,
@@ -335,6 +336,7 @@ Future<dynamic> showTextInputDialog(
             isPasswordInput: isPasswordInput,
             isPasswordInput: isPasswordInput,
             textEditingController: textEditingController,
             textEditingController: textEditingController,
             textInputFormatter: textInputFormatter,
             textInputFormatter: textInputFormatter,
+            textInputType: textInputType,
           ),
           ),
         ),
         ),
       );
       );