Pārlūkot izejas kodu

Changed code for setting execution states + other minor fixes

ashilkn 2 gadi atpakaļ
vecāks
revīzija
c03a5ee194

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

@@ -230,6 +230,7 @@ class _TextInputDialogState extends State<TextInputDialog> {
                 maxLength: widget.maxLength,
                 submitNotifier: _submitNotifier,
                 onSubmit: widget.onSubmit,
+                popNavAfterSubmission: true,
               ),
             ),
             const SizedBox(height: 36),

+ 93 - 37
lib/ui/components/text_input_widget.dart

@@ -26,6 +26,8 @@ class TextInputWidget extends StatefulWidget {
   final bool alwaysShowSuccessState;
   final bool showOnlyLoadingState;
   final FutureVoidCallbackParamStr onSubmit;
+  final bool popNavAfterSubmission;
+  final bool shouldSurfaceExecutionStates;
   const TextInputWidget({
     required this.onSubmit,
     this.label,
@@ -37,8 +39,10 @@ class TextInputWidget extends StatefulWidget {
     this.autoFocus,
     this.maxLength,
     this.submitNotifier,
-    this.alwaysShowSuccessState = true,
+    this.alwaysShowSuccessState = false,
     this.showOnlyLoadingState = false,
+    this.popNavAfterSubmission = false,
+    this.shouldSurfaceExecutionStates = true,
     super.key,
   });
 
@@ -47,19 +51,16 @@ class TextInputWidget extends StatefulWidget {
 }
 
 class _TextInputWidgetState extends State<TextInputWidget> {
+  ExecutionState executionState = ExecutionState.idle;
   final _textController = TextEditingController();
   final _debouncer = Debouncer(const Duration(milliseconds: 300));
-  final ValueNotifier<ExecutionState> _executionStateNotifier =
-      ValueNotifier(ExecutionState.idle);
 
   @override
   void initState() {
     widget.submitNotifier?.addListener(() {
       _onSubmit();
     });
-    _executionStateNotifier.addListener(() {
-      setState(() {});
-    });
+
     if (widget.initialValue != null) {
       _textController.value = TextEditingValue(
         text: widget.initialValue!,
@@ -72,12 +73,19 @@ class _TextInputWidgetState extends State<TextInputWidget> {
   @override
   void dispose() {
     widget.submitNotifier?.dispose();
-    _executionStateNotifier.dispose();
     super.dispose();
   }
 
   @override
   Widget build(BuildContext context) {
+    if (executionState == ExecutionState.successful) {
+      Future.delayed(Duration(seconds: widget.popNavAfterSubmission ? 1 : 2),
+          () {
+        setState(() {
+          executionState = ExecutionState.idle;
+        });
+      });
+    }
     final colorScheme = getEnteColorScheme(context);
     final textTheme = getEnteTextTheme(context);
     var textInputChildren = <Widget>[];
@@ -117,8 +125,10 @@ class _TextInputWidgetState extends State<TextInputWidget> {
                   switchInCurve: Curves.easeInExpo,
                   switchOutCurve: Curves.easeOutExpo,
                   child: SuffixIconWidget(
-                    _executionStateNotifier.value,
-                    key: ValueKey(_executionStateNotifier.value),
+                    key: ValueKey(executionState),
+                    executionState: executionState,
+                    shouldSurfaceExecutionStates:
+                        widget.shouldSurfaceExecutionStates,
                   ),
                 ),
               ),
@@ -169,51 +179,97 @@ class _TextInputWidgetState extends State<TextInputWidget> {
     );
   }
 
-  Future<void> _onSubmit() async {
+  void _onSubmit() async {
     _debouncer.run(
-      () => Future(
-        () {
-          _executionStateNotifier.value = ExecutionState.inProgress;
-        },
-      ),
-    );
-    await widget.onSubmit.call(_textController.text).then(
-      (value) {
-        widget.alwaysShowSuccessState
-            ? _executionStateNotifier.value = ExecutionState.successful
-            : null;
-      },
-      onError: (error, stackTrace) => _debouncer.cancelDebounce(),
+      () => Future(() {
+        setState(() {
+          executionState = ExecutionState.inProgress;
+        });
+      }),
     );
+    await widget.onSubmit!
+        .call(_textController.text)
+        .onError((error, stackTrace) {
+      executionState = ExecutionState.error;
+      _debouncer.cancelDebounce();
+    });
+    widget.alwaysShowSuccessState && _debouncer.isActive()
+        ? executionState = ExecutionState.successful
+        : null;
     _debouncer.cancelDebounce();
-    if (widget.alwaysShowSuccessState) {
-      Future.delayed(const Duration(seconds: 2), () {
-        _executionStateNotifier.value = ExecutionState.idle;
-      });
-      return;
+    if (executionState == ExecutionState.successful) {
+      setState(() {});
     }
-    if (_executionStateNotifier.value == ExecutionState.inProgress) {
-      if (widget.showOnlyLoadingState) {
-        _executionStateNotifier.value = ExecutionState.idle;
-      } else {
-        _executionStateNotifier.value = ExecutionState.successful;
-        Future.delayed(const Duration(seconds: 2), () {
-          _executionStateNotifier.value = ExecutionState.idle;
+
+    // when the time taken by widget.onSubmit is approximately equal to the debounce
+    // time, the callback is getting executed when/after the if condition
+    // below is executing/executed which results in execution state stuck at
+    // idle state. This Future is for delaying the execution of the if
+    // condition so that the calback in the debouncer finishes execution before.
+    await Future.delayed(const Duration(milliseconds: 5));
+    if (executionState == ExecutionState.inProgress ||
+        executionState == ExecutionState.error) {
+      if (executionState == ExecutionState.inProgress) {
+        if (mounted) {
+          setState(() {
+            executionState = ExecutionState.successful;
+            Future.delayed(
+                Duration(
+                  seconds: widget.shouldSurfaceExecutionStates
+                      ? (widget.popNavAfterSubmission ? 1 : 2)
+                      : 0,
+                ), () {
+              widget.popNavAfterSubmission ? _popNavigatorStack(context) : null;
+              if (mounted) {
+                setState(() {
+                  executionState = ExecutionState.idle;
+                });
+              }
+            });
+          });
+        }
+      }
+      if (executionState == ExecutionState.error) {
+        setState(() {
+          executionState = ExecutionState.idle;
+          widget.popNavAfterSubmission
+              ? Future.delayed(
+                  const Duration(seconds: 0),
+                  () => _popNavigatorStack(context),
+                )
+              : null;
         });
       }
+    } else {
+      if (widget.popNavAfterSubmission) {
+        Future.delayed(
+          Duration(seconds: widget.alwaysShowSuccessState ? 1 : 0),
+          () => _popNavigatorStack(context),
+        );
+      }
     }
   }
+
+  void _popNavigatorStack(BuildContext context) {
+    Navigator.of(context).canPop() ? Navigator.of(context).pop() : null;
+  }
 }
 
 class SuffixIconWidget extends StatelessWidget {
   final ExecutionState executionState;
-  const SuffixIconWidget(this.executionState, {super.key});
+  final bool shouldSurfaceExecutionStates;
+  const SuffixIconWidget({
+    required this.executionState,
+    required this.shouldSurfaceExecutionStates,
+    super.key,
+  });
 
   @override
   Widget build(BuildContext context) {
     final Widget trailingWidget;
     final colorScheme = getEnteColorScheme(context);
-    if (executionState == ExecutionState.idle) {
+    if (executionState == ExecutionState.idle ||
+        !shouldSurfaceExecutionStates) {
       trailingWidget = const SizedBox.shrink();
     } else if (executionState == ExecutionState.inProgress) {
       trailingWidget = EnteLoadingWidget(