action_sheet_widget.dart 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import 'dart:ui';
  2. import 'package:flutter/material.dart';
  3. import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
  4. import 'package:photos/core/constants.dart';
  5. import 'package:photos/theme/colors.dart';
  6. import 'package:photos/theme/effects.dart';
  7. import 'package:photos/theme/ente_theme.dart';
  8. import 'package:photos/ui/components/button_widget.dart';
  9. import 'package:photos/utils/separators_util.dart';
  10. enum ActionSheetType {
  11. defaultActionSheet,
  12. iconOnly,
  13. }
  14. Future<ButtonAction?> showCommonActionSheet({
  15. required BuildContext context,
  16. required List<ButtonWidget> buttons,
  17. required ActionSheetType actionSheetType,
  18. bool isCheckIconGreen = false,
  19. String? title,
  20. String? body,
  21. }) {
  22. return showMaterialModalBottomSheet(
  23. backgroundColor: Colors.transparent,
  24. barrierColor: backdropFaintDark,
  25. useRootNavigator: true,
  26. context: context,
  27. builder: (_) {
  28. return ActionSheetWidget(
  29. title: title,
  30. body: body,
  31. actionButtons: buttons,
  32. actionSheetType: actionSheetType,
  33. isCheckIconGreen: isCheckIconGreen,
  34. );
  35. },
  36. isDismissible: false,
  37. enableDrag: false,
  38. );
  39. }
  40. Future<ButtonAction?> showActionSheet({
  41. required BuildContext context,
  42. required List<ButtonWidget> buttons,
  43. required ActionSheetType actionSheetType,
  44. bool isCheckIconGreen = false,
  45. String? title,
  46. String? body,
  47. }) {
  48. return showMaterialModalBottomSheet(
  49. backgroundColor: Colors.transparent,
  50. barrierColor: backdropFaintDark,
  51. useRootNavigator: true,
  52. context: context,
  53. builder: (_) {
  54. return ActionSheetWidget(
  55. title: title,
  56. body: body,
  57. actionButtons: buttons,
  58. actionSheetType: actionSheetType,
  59. isCheckIconGreen: isCheckIconGreen,
  60. );
  61. },
  62. isDismissible: false,
  63. enableDrag: false,
  64. );
  65. }
  66. class ActionSheetWidget extends StatelessWidget {
  67. final String? title;
  68. final String? body;
  69. final List<ButtonWidget> actionButtons;
  70. final ActionSheetType actionSheetType;
  71. final bool isCheckIconGreen;
  72. const ActionSheetWidget({
  73. required this.actionButtons,
  74. required this.actionSheetType,
  75. required this.isCheckIconGreen,
  76. this.title,
  77. this.body,
  78. super.key,
  79. });
  80. @override
  81. Widget build(BuildContext context) {
  82. final isTitleAndBodyNull = title == null && body == null;
  83. final blur = MediaQuery.of(context).platformBrightness == Brightness.light
  84. ? blurMuted
  85. : blurBase;
  86. final extraWidth = MediaQuery.of(context).size.width - restrictedMaxWidth;
  87. final double? horizontalPadding = extraWidth > 0 ? extraWidth / 2 : null;
  88. return Padding(
  89. padding: EdgeInsets.fromLTRB(
  90. horizontalPadding ?? 12,
  91. 12,
  92. horizontalPadding ?? 12,
  93. 32,
  94. ),
  95. child: Container(
  96. decoration: BoxDecoration(boxShadow: shadowMenuLight),
  97. child: ClipRRect(
  98. borderRadius: const BorderRadius.all(Radius.circular(8)),
  99. child: BackdropFilter(
  100. filter: ImageFilter.blur(sigmaX: blur, sigmaY: blur),
  101. child: Container(
  102. color: backdropMutedDark,
  103. child: Padding(
  104. padding: EdgeInsets.fromLTRB(
  105. 24,
  106. 24,
  107. 24,
  108. isTitleAndBodyNull ? 24 : 28,
  109. ),
  110. child: Column(
  111. mainAxisSize: MainAxisSize.min,
  112. children: [
  113. isTitleAndBodyNull
  114. ? const SizedBox.shrink()
  115. : Padding(
  116. padding: const EdgeInsets.only(bottom: 36),
  117. child: ContentContainerWidget(
  118. title: title,
  119. body: body,
  120. actionSheetType: actionSheetType,
  121. isCheckIconGreen: isCheckIconGreen,
  122. ),
  123. ),
  124. ActionButtons(
  125. actionButtons,
  126. ),
  127. ],
  128. ),
  129. ),
  130. ),
  131. ),
  132. ),
  133. ),
  134. );
  135. }
  136. }
  137. class ContentContainerWidget extends StatelessWidget {
  138. final String? title;
  139. final String? body;
  140. final ActionSheetType actionSheetType;
  141. final bool isCheckIconGreen;
  142. const ContentContainerWidget({
  143. required this.actionSheetType,
  144. required this.isCheckIconGreen,
  145. this.title,
  146. this.body,
  147. super.key,
  148. });
  149. @override
  150. Widget build(BuildContext context) {
  151. final textTheme = getEnteTextTheme(context);
  152. return Column(
  153. mainAxisSize: MainAxisSize.min,
  154. //todo: set cross axis to center when icon should be shown in place of body
  155. crossAxisAlignment: actionSheetType == ActionSheetType.defaultActionSheet
  156. ? CrossAxisAlignment.stretch
  157. : CrossAxisAlignment.center,
  158. children: [
  159. title == null
  160. ? const SizedBox.shrink()
  161. : Text(
  162. title!,
  163. style: textTheme.h3Bold
  164. .copyWith(color: textBaseDark), //constant color
  165. ),
  166. title == null || body == null
  167. ? const SizedBox.shrink()
  168. : const SizedBox(height: 19),
  169. actionSheetType == ActionSheetType.defaultActionSheet
  170. ? body == null
  171. ? const SizedBox.shrink()
  172. : Text(
  173. body!,
  174. style: textTheme.body
  175. .copyWith(color: textMutedDark), //constant color
  176. )
  177. : Icon(
  178. Icons.check_outlined,
  179. size: 48,
  180. color: isCheckIconGreen
  181. ? getEnteColorScheme(context).primary700
  182. : strokeBaseDark,
  183. )
  184. ],
  185. );
  186. }
  187. }
  188. class ActionButtons extends StatelessWidget {
  189. final List<Widget> actionButtons;
  190. const ActionButtons(this.actionButtons, {super.key});
  191. @override
  192. Widget build(BuildContext context) {
  193. final actionButtonsWithSeparators = actionButtons;
  194. return Column(
  195. children:
  196. //Separator height is 8pts in figma. -2pts here as the action
  197. //buttons are 2pts extra in height in code compared to figma because
  198. //of the border(1pt top + 1pt bottom) of action buttons.
  199. addSeparators(actionButtonsWithSeparators, const SizedBox(height: 6)),
  200. );
  201. }
  202. }