file_actions.dart 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import "package:flutter/cupertino.dart";
  2. import "package:modal_bottom_sheet/modal_bottom_sheet.dart";
  3. import "package:photos/generated/l10n.dart";
  4. import "package:photos/models/file.dart";
  5. import "package:photos/models/file_type.dart";
  6. import "package:photos/theme/colors.dart";
  7. import "package:photos/theme/ente_theme.dart";
  8. import "package:photos/ui/components/action_sheet_widget.dart";
  9. import 'package:photos/ui/components/buttons/button_widget.dart';
  10. import "package:photos/ui/components/models/button_type.dart";
  11. import 'package:photos/ui/viewer/file/file_details_widget.dart';
  12. import "package:photos/utils/delete_file_util.dart";
  13. import "package:photos/utils/dialog_util.dart";
  14. import "package:photos/utils/toast_util.dart";
  15. Future<void> showSingleFileDeleteSheet(
  16. BuildContext context,
  17. EnteFile file, {
  18. Function(EnteFile)? onFileRemoved,
  19. }) async {
  20. final List<ButtonWidget> buttons = [];
  21. final String fileType = file.fileType == FileType.video
  22. ? S.of(context).videoSmallCase
  23. : S.of(context).photoSmallCase;
  24. final bool isBothLocalAndRemote =
  25. file.uploadedFileID != null && file.localID != null;
  26. final bool isLocalOnly = file.uploadedFileID == null && file.localID != null;
  27. final bool isRemoteOnly = file.uploadedFileID != null && file.localID == null;
  28. final String bodyHighlight = S.of(context).singleFileDeleteHighlight;
  29. String body = "";
  30. if (isBothLocalAndRemote) {
  31. body = S.of(context).singleFileInBothLocalAndRemote(fileType);
  32. } else if (isRemoteOnly) {
  33. body = S.of(context).singleFileInRemoteOnly(fileType);
  34. } else if (isLocalOnly) {
  35. body = S.of(context).singleFileDeleteFromDevice(fileType);
  36. } else {
  37. throw AssertionError("Unexpected state");
  38. }
  39. // Add option to delete from ente
  40. if (isBothLocalAndRemote || isRemoteOnly) {
  41. buttons.add(
  42. ButtonWidget(
  43. labelText: isBothLocalAndRemote
  44. ? S.of(context).deleteFromEnte
  45. : S.of(context).yesDelete,
  46. buttonType: ButtonType.neutral,
  47. buttonSize: ButtonSize.large,
  48. shouldStickToDarkTheme: true,
  49. buttonAction: ButtonAction.first,
  50. shouldSurfaceExecutionStates: true,
  51. isInAlert: true,
  52. onTap: () async {
  53. await deleteFilesFromRemoteOnly(context, [file]);
  54. showShortToast(context, S.of(context).movedToTrash);
  55. if (isRemoteOnly) {
  56. if (onFileRemoved != null) {
  57. onFileRemoved(file);
  58. }
  59. }
  60. },
  61. ),
  62. );
  63. }
  64. // Add option to delete from local
  65. if (isBothLocalAndRemote || isLocalOnly) {
  66. buttons.add(
  67. ButtonWidget(
  68. labelText: isBothLocalAndRemote
  69. ? S.of(context).deleteFromDevice
  70. : S.of(context).yesDelete,
  71. buttonType: ButtonType.neutral,
  72. buttonSize: ButtonSize.large,
  73. shouldStickToDarkTheme: true,
  74. buttonAction: ButtonAction.second,
  75. shouldSurfaceExecutionStates: false,
  76. isInAlert: true,
  77. onTap: () async {
  78. await deleteFilesOnDeviceOnly(context, [file]);
  79. if (isLocalOnly) {
  80. if (onFileRemoved != null) {
  81. onFileRemoved(file);
  82. }
  83. }
  84. },
  85. ),
  86. );
  87. }
  88. if (isBothLocalAndRemote) {
  89. buttons.add(
  90. ButtonWidget(
  91. labelText: S.of(context).deleteFromBoth,
  92. buttonType: ButtonType.neutral,
  93. buttonSize: ButtonSize.large,
  94. shouldStickToDarkTheme: true,
  95. buttonAction: ButtonAction.third,
  96. shouldSurfaceExecutionStates: true,
  97. isInAlert: true,
  98. onTap: () async {
  99. await deleteFilesFromEverywhere(context, [file]);
  100. Navigator.of(context, rootNavigator: true).pop();
  101. if (onFileRemoved != null) {
  102. onFileRemoved(file);
  103. }
  104. },
  105. ),
  106. );
  107. }
  108. buttons.add(
  109. ButtonWidget(
  110. labelText: S.of(context).cancel,
  111. buttonType: ButtonType.secondary,
  112. buttonSize: ButtonSize.large,
  113. shouldStickToDarkTheme: true,
  114. buttonAction: ButtonAction.fourth,
  115. isInAlert: true,
  116. ),
  117. );
  118. final actionResult = await showActionSheet(
  119. context: context,
  120. buttons: buttons,
  121. actionSheetType: ActionSheetType.defaultActionSheet,
  122. body: body,
  123. bodyHighlight: bodyHighlight,
  124. );
  125. if (actionResult?.action != null &&
  126. actionResult!.action == ButtonAction.error) {
  127. showGenericErrorDialog(context: context);
  128. }
  129. }
  130. Future<void> showDetailsSheet(BuildContext context, EnteFile file) async {
  131. final colorScheme = getEnteColorScheme(context);
  132. return showBarModalBottomSheet(
  133. topControl: const SizedBox.shrink(),
  134. shape: const RoundedRectangleBorder(
  135. borderRadius: BorderRadius.vertical(
  136. top: Radius.circular(5),
  137. ),
  138. ),
  139. backgroundColor: colorScheme.backgroundElevated,
  140. barrierColor: backdropFaintDark,
  141. context: context,
  142. builder: (BuildContext context) {
  143. return Padding(
  144. padding:
  145. EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
  146. child: FileDetailsWidget(file),
  147. );
  148. },
  149. );
  150. }