瀏覽代碼

Merge pull request #726 from ente-io/dialog

Dialog with and without icon
Ashil 2 年之前
父節點
當前提交
c72934a95e

+ 2 - 0
lib/core/constants.dart

@@ -54,3 +54,5 @@ const int intMaxValue = 9223372036854775807;
 
 //Screen width of iPhone 14 pro max in points is taken as maximum
 const double restrictedMaxWidth = 430;
+
+const double mobileSmallThreshold = 336;

+ 24 - 23
lib/ui/components/button_widget.dart

@@ -37,9 +37,10 @@ class ButtonWidget extends StatelessWidget {
   final FutureVoidCallback? onTap;
   final bool isDisabled;
   final ButtonSize buttonSize;
-  // iconColor should only be specified when we do not want to honor the default
-  // iconColor based on buttonType. Most of the items, default iconColor is what
-  // we need unless we want to pop out the icon in a non-primary button type
+
+  /// iconColor should only be specified when we do not want to honor the default
+  /// iconColor based on buttonType. Most of the items, default iconColor is what
+  /// we need unless we want to pop out the icon in a non-primary button type
   final Color? iconColor;
 
   ///Button action will only work if isInAlert is true
@@ -322,29 +323,29 @@ class _ButtonChildWidgetState extends State<ButtonChildWidget> {
   }
 
   bool get _shouldRegisterGestures =>
-      !widget.isDisabled &&
-      (widget.onTap != null) &&
-      executionState == ExecutionState.idle;
+      !widget.isDisabled && executionState == ExecutionState.idle;
 
   void _onTap() async {
-    _debouncer.run(
-      () => Future(() {
-        setState(() {
-          executionState = ExecutionState.inProgress;
-        });
-      }),
-    );
-    await widget.onTap!.call().onError((error, stackTrace) {
-      executionState = ExecutionState.error;
+    if (widget.onTap != null) {
+      _debouncer.run(
+        () => Future(() {
+          setState(() {
+            executionState = ExecutionState.inProgress;
+          });
+        }),
+      );
+      await widget.onTap!.call().onError((error, stackTrace) {
+        executionState = ExecutionState.error;
+        _debouncer.cancelDebounce();
+      });
       _debouncer.cancelDebounce();
-    });
-    _debouncer.cancelDebounce();
-    // when the time taken by widget.onTap 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));
+      // when the time taken by widget.onTap 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) {

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

@@ -0,0 +1,146 @@
+import 'dart:math';
+
+import 'package:flutter/material.dart';
+import 'package:photos/core/constants.dart';
+import 'package:photos/theme/colors.dart';
+import 'package:photos/theme/effects.dart';
+import 'package:photos/theme/ente_theme.dart';
+import 'package:photos/ui/components/button_widget.dart';
+import 'package:photos/utils/separators_util.dart';
+
+Future<dynamic> showDialogWidget({
+  required BuildContext context,
+  required String title,
+  required String body,
+  required List<ButtonWidget> buttons,
+  IconData? icon,
+}) {
+  return showDialog(
+    barrierDismissible: false,
+    barrierColor: backdropFaintDark,
+    context: context,
+    builder: (context) {
+      final widthOfScreen = MediaQuery.of(context).size.width;
+      final isMobileSmall = widthOfScreen <= mobileSmallThreshold;
+      return Padding(
+        padding: EdgeInsets.symmetric(horizontal: isMobileSmall ? 8 : 0),
+        child: Dialog(
+          insetPadding: EdgeInsets.zero,
+          child: DialogWidget(
+            title: title,
+            body: body,
+            buttons: buttons,
+            isMobileSmall: isMobileSmall,
+            icon: icon,
+          ),
+        ),
+      );
+    },
+  );
+}
+
+class DialogWidget extends StatelessWidget {
+  final String title;
+  final String body;
+  final List<ButtonWidget> buttons;
+  final IconData? icon;
+  final bool isMobileSmall;
+  const DialogWidget({
+    required this.title,
+    required this.body,
+    required this.buttons,
+    required this.isMobileSmall,
+    this.icon,
+    super.key,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    final widthOfScreen = MediaQuery.of(context).size.width;
+    final colorScheme = getEnteColorScheme(context);
+    return Container(
+      width: min(widthOfScreen, 320),
+      padding: isMobileSmall
+          ? const EdgeInsets.all(0)
+          : const EdgeInsets.fromLTRB(6, 8, 6, 6),
+      decoration: BoxDecoration(
+        color: colorScheme.backgroundElevated,
+        boxShadow: shadowFloatLight,
+        borderRadius: const BorderRadius.all(Radius.circular(8)),
+      ),
+      child: Padding(
+        padding: const EdgeInsets.all(16),
+        child: Column(
+          mainAxisSize: MainAxisSize.min,
+          children: [
+            ContentContainer(
+              title: title,
+              body: body,
+              icon: icon,
+            ),
+            const SizedBox(height: 36),
+            Actions(buttons),
+          ],
+        ),
+      ),
+    );
+  }
+}
+
+class ContentContainer extends StatelessWidget {
+  final String title;
+  final String body;
+  final IconData? icon;
+  const ContentContainer({
+    required this.title,
+    required this.body,
+    this.icon,
+    super.key,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    final textTheme = getEnteTextTheme(context);
+    final colorScheme = getEnteColorScheme(context);
+    return Column(
+      mainAxisSize: MainAxisSize.min,
+      crossAxisAlignment: CrossAxisAlignment.stretch,
+      children: [
+        icon == null
+            ? const SizedBox.shrink()
+            : Row(
+                children: [
+                  Icon(
+                    icon,
+                    size: 48,
+                  ),
+                ],
+              ),
+        icon == null ? const SizedBox.shrink() : const SizedBox(height: 19),
+        Text(title, style: textTheme.h3Bold),
+        const SizedBox(height: 19),
+        Text(
+          body,
+          style: textTheme.body.copyWith(color: colorScheme.textMuted),
+        ),
+      ],
+    );
+  }
+}
+
+class Actions extends StatelessWidget {
+  final List<ButtonWidget> buttons;
+  const Actions(this.buttons, {super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      children: addSeparators(
+        buttons,
+        const SizedBox(
+          height: 8,
+        ),
+      ),
+    );
+  }
+}

+ 3 - 1
lib/ui/settings/storage_card_widget.dart

@@ -2,6 +2,7 @@ import 'dart:math';
 
 import 'package:flutter/material.dart';
 import 'package:logging/logging.dart';
+import 'package:photos/core/constants.dart';
 import 'package:photos/models/user_details.dart';
 import 'package:photos/states/user_details_state.dart';
 import 'package:photos/theme/colors.dart';
@@ -121,7 +122,8 @@ class _StorageCardWidgetState extends State<StorageCardWidget> {
     final totalStorageInBytes = userDetails.getTotalStorage();
     final freeStorageInBytes = totalStorageInBytes - usedStorageInBytes;
 
-    final isMobileScreenSmall = MediaQuery.of(context).size.width <= 336;
+    final isMobileScreenSmall =
+        MediaQuery.of(context).size.width <= mobileSmallThreshold;
     final shouldShowFreeSpaceInMBs = freeStorageInBytes < hundredMBinBytes;
     final shouldShowFreeSpaceInTBs = freeStorageInBytes >= oneTBinBytes;
     final shouldShowUsedStorageInTBs = usedStorageInBytes >= oneTBinBytes;