dialog_util.dart 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. import 'dart:math';
  2. import 'package:confetti/confetti.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:photos/core/constants.dart';
  5. import "package:photos/models/search/button_result.dart";
  6. import 'package:photos/models/typedefs.dart';
  7. import 'package:photos/theme/colors.dart';
  8. import 'package:photos/ui/common/loading_widget.dart';
  9. import 'package:photos/ui/common/progress_dialog.dart';
  10. import 'package:photos/ui/components/action_sheet_widget.dart';
  11. import 'package:photos/ui/components/button_widget.dart';
  12. import 'package:photos/ui/components/dialog_widget.dart';
  13. import 'package:photos/ui/components/models/button_type.dart';
  14. typedef DialogBuilder = DialogWidget Function(BuildContext context);
  15. ///Will return null if dismissed by tapping outside
  16. Future<ButtonResult?> showErrorDialog(
  17. BuildContext context,
  18. String title,
  19. String? body, {
  20. bool isDismissable = true,
  21. }) async {
  22. return showDialogWidget(
  23. context: context,
  24. title: title,
  25. body: body,
  26. isDismissible: isDismissable,
  27. buttons: const [
  28. ButtonWidget(
  29. buttonType: ButtonType.secondary,
  30. labelText: "OK",
  31. isInAlert: true,
  32. buttonAction: ButtonAction.first,
  33. ),
  34. ],
  35. );
  36. }
  37. ///Will return null if dismissed by tapping outside
  38. Future<ButtonResult?> showGenericErrorDialog({
  39. required BuildContext context,
  40. bool isDismissible = true,
  41. }) async {
  42. return showDialogWidget(
  43. context: context,
  44. title: "Error",
  45. icon: Icons.error_outline_outlined,
  46. body:
  47. "It looks like something went wrong. Please retry after some time. If the error persists, please contact our support team.",
  48. isDismissible: isDismissible,
  49. buttons: const [
  50. ButtonWidget(
  51. buttonType: ButtonType.secondary,
  52. labelText: "OK",
  53. isInAlert: true,
  54. ),
  55. ],
  56. );
  57. }
  58. DialogWidget choiceDialog({
  59. required String title,
  60. String? body,
  61. required String firstButtonLabel,
  62. String secondButtonLabel = "Cancel",
  63. ButtonType firstButtonType = ButtonType.neutral,
  64. ButtonType secondButtonType = ButtonType.secondary,
  65. ButtonAction firstButtonAction = ButtonAction.first,
  66. ButtonAction secondButtonAction = ButtonAction.cancel,
  67. FutureVoidCallback? firstButtonOnTap,
  68. FutureVoidCallback? secondButtonOnTap,
  69. bool isCritical = false,
  70. IconData? icon,
  71. }) {
  72. final buttons = [
  73. ButtonWidget(
  74. buttonType: isCritical ? ButtonType.critical : firstButtonType,
  75. labelText: firstButtonLabel,
  76. isInAlert: true,
  77. onTap: firstButtonOnTap,
  78. buttonAction: firstButtonAction,
  79. ),
  80. ButtonWidget(
  81. buttonType: secondButtonType,
  82. labelText: secondButtonLabel,
  83. isInAlert: true,
  84. onTap: secondButtonOnTap,
  85. buttonAction: secondButtonAction,
  86. ),
  87. ];
  88. return DialogWidget(title: title, body: body, buttons: buttons, icon: icon);
  89. }
  90. ///Will return null if dismissed by tapping outside
  91. Future<ButtonResult?> showChoiceDialog(
  92. BuildContext context, {
  93. required String title,
  94. String? body,
  95. required String firstButtonLabel,
  96. String secondButtonLabel = "Cancel",
  97. ButtonType firstButtonType = ButtonType.neutral,
  98. ButtonType secondButtonType = ButtonType.secondary,
  99. ButtonAction firstButtonAction = ButtonAction.first,
  100. ButtonAction secondButtonAction = ButtonAction.cancel,
  101. FutureVoidCallback? firstButtonOnTap,
  102. FutureVoidCallback? secondButtonOnTap,
  103. bool isCritical = false,
  104. IconData? icon,
  105. bool isDismissible = true,
  106. }) async {
  107. final buttons = [
  108. ButtonWidget(
  109. buttonType: isCritical ? ButtonType.critical : firstButtonType,
  110. labelText: firstButtonLabel,
  111. isInAlert: true,
  112. onTap: firstButtonOnTap,
  113. buttonAction: firstButtonAction,
  114. ),
  115. ButtonWidget(
  116. buttonType: secondButtonType,
  117. labelText: secondButtonLabel,
  118. isInAlert: true,
  119. onTap: secondButtonOnTap,
  120. buttonAction: secondButtonAction,
  121. ),
  122. ];
  123. return showDialogWidget(
  124. context: context,
  125. title: title,
  126. body: body,
  127. buttons: buttons,
  128. icon: icon,
  129. isDismissible: isDismissible,
  130. );
  131. }
  132. ///Will return null if dismissed by tapping outside
  133. Future<ButtonResult?> showChoiceActionSheet(
  134. BuildContext context, {
  135. required String title,
  136. String? body,
  137. required String firstButtonLabel,
  138. String secondButtonLabel = "Cancel",
  139. ButtonType firstButtonType = ButtonType.neutral,
  140. ButtonType secondButtonType = ButtonType.secondary,
  141. ButtonAction firstButtonAction = ButtonAction.first,
  142. ButtonAction secondButtonAction = ButtonAction.cancel,
  143. FutureVoidCallback? firstButtonOnTap,
  144. FutureVoidCallback? secondButtonOnTap,
  145. bool isCritical = false,
  146. IconData? icon,
  147. bool isDismissible = true,
  148. }) async {
  149. final buttons = [
  150. ButtonWidget(
  151. buttonType: isCritical ? ButtonType.critical : firstButtonType,
  152. labelText: firstButtonLabel,
  153. isInAlert: true,
  154. onTap: firstButtonOnTap,
  155. buttonAction: firstButtonAction,
  156. shouldStickToDarkTheme: true,
  157. ),
  158. ButtonWidget(
  159. buttonType: secondButtonType,
  160. labelText: secondButtonLabel,
  161. isInAlert: true,
  162. onTap: secondButtonOnTap,
  163. buttonAction: secondButtonAction,
  164. shouldStickToDarkTheme: true,
  165. ),
  166. ];
  167. return showActionSheet(
  168. context: context,
  169. title: title,
  170. body: body,
  171. buttons: buttons,
  172. isDismissible: isDismissible,
  173. );
  174. }
  175. ProgressDialog createProgressDialog(
  176. BuildContext context,
  177. String message, {
  178. isDismissible = false,
  179. }) {
  180. final dialog = ProgressDialog(
  181. context,
  182. type: ProgressDialogType.normal,
  183. isDismissible: isDismissible,
  184. barrierColor: Colors.black12,
  185. );
  186. dialog.style(
  187. message: message,
  188. messageTextStyle: Theme.of(context).textTheme.caption,
  189. backgroundColor: Theme.of(context).dialogTheme.backgroundColor,
  190. progressWidget: const EnteLoadingWidget(),
  191. borderRadius: 10,
  192. elevation: 10.0,
  193. insetAnimCurve: Curves.easeInOut,
  194. );
  195. return dialog;
  196. }
  197. Future<ButtonResult?> showConfettiDialog<T>({
  198. required BuildContext context,
  199. required DialogBuilder dialogBuilder,
  200. bool barrierDismissible = true,
  201. Color? barrierColor,
  202. bool useSafeArea = true,
  203. bool useRootNavigator = true,
  204. RouteSettings? routeSettings,
  205. Alignment confettiAlignment = Alignment.center,
  206. }) {
  207. final widthOfScreen = MediaQuery.of(context).size.width;
  208. final isMobileSmall = widthOfScreen <= mobileSmallThreshold;
  209. final pageBuilder = Builder(
  210. builder: dialogBuilder,
  211. );
  212. final ConfettiController confettiController =
  213. ConfettiController(duration: const Duration(seconds: 1));
  214. confettiController.play();
  215. return showDialog(
  216. context: context,
  217. builder: (BuildContext buildContext) {
  218. return Padding(
  219. padding: EdgeInsets.symmetric(horizontal: isMobileSmall ? 8 : 0),
  220. child: Stack(
  221. children: [
  222. Align(alignment: Alignment.center, child: pageBuilder),
  223. Align(
  224. alignment: confettiAlignment,
  225. child: ConfettiWidget(
  226. confettiController: confettiController,
  227. blastDirection: pi / 2,
  228. emissionFrequency: 0,
  229. numberOfParticles: 100,
  230. // a lot of particles at once
  231. gravity: 1,
  232. blastDirectionality: BlastDirectionality.explosive,
  233. ),
  234. ),
  235. ],
  236. ),
  237. );
  238. },
  239. barrierDismissible: barrierDismissible,
  240. barrierColor: barrierColor,
  241. useSafeArea: useSafeArea,
  242. useRootNavigator: useRootNavigator,
  243. routeSettings: routeSettings,
  244. );
  245. }
  246. //Can return ButtonResult? from ButtonWidget or Exception? from TextInputDialog
  247. Future<dynamic> showTextInputDialog(
  248. BuildContext context, {
  249. required String title,
  250. String? body,
  251. required String submitButtonLabel,
  252. IconData? icon,
  253. String? label,
  254. String? message,
  255. String? hintText,
  256. required FutureVoidCallbackParamStr onSubmit,
  257. IconData? prefixIcon,
  258. String? initialValue,
  259. Alignment? alignMessage,
  260. int? maxLength,
  261. bool showOnlyLoadingState = false,
  262. TextCapitalization textCapitalization = TextCapitalization.none,
  263. bool alwaysShowSuccessState = false,
  264. bool isPasswordInput = false,
  265. }) {
  266. return showDialog(
  267. barrierColor: backdropFaintDark,
  268. context: context,
  269. builder: (context) {
  270. final bottomInset = MediaQuery.of(context).viewInsets.bottom;
  271. final isKeyboardUp = bottomInset > 100;
  272. return Center(
  273. child: Padding(
  274. padding: EdgeInsets.only(bottom: isKeyboardUp ? bottomInset : 0),
  275. child: TextInputDialog(
  276. title: title,
  277. message: message,
  278. label: label,
  279. body: body,
  280. icon: icon,
  281. submitButtonLabel: submitButtonLabel,
  282. onSubmit: onSubmit,
  283. hintText: hintText,
  284. prefixIcon: prefixIcon,
  285. initialValue: initialValue,
  286. alignMessage: alignMessage,
  287. maxLength: maxLength,
  288. showOnlyLoadingState: showOnlyLoadingState,
  289. textCapitalization: textCapitalization,
  290. alwaysShowSuccessState: alwaysShowSuccessState,
  291. isPasswordInput: isPasswordInput,
  292. ),
  293. ),
  294. );
  295. },
  296. );
  297. }