action_sheet_widget.dart 6.4 KB

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