dialog_util.dart 8.5 KB

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