magic_util.dart 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import 'package:flutter/material.dart';
  2. import 'package:logging/logging.dart';
  3. import 'package:path/path.dart';
  4. import 'package:photos/core/event_bus.dart';
  5. import 'package:photos/events/force_reload_home_gallery_event.dart';
  6. import "package:photos/generated/l10n.dart";
  7. import 'package:photos/models/collection.dart';
  8. import 'package:photos/models/file.dart';
  9. import 'package:photos/models/magic_metadata.dart';
  10. import 'package:photos/services/collections_service.dart';
  11. import 'package:photos/services/file_magic_service.dart';
  12. import 'package:photos/ui/common/progress_dialog.dart';
  13. import 'package:photos/utils/dialog_util.dart';
  14. import 'package:photos/utils/toast_util.dart';
  15. final _logger = Logger('MagicUtil');
  16. Future<void> changeVisibility(
  17. BuildContext context,
  18. List<File> files,
  19. int newVisibility,
  20. ) async {
  21. final dialog = createProgressDialog(
  22. context,
  23. newVisibility == visibilityArchive
  24. ? S.of(context).archiving
  25. : S.of(context).unarchiving,
  26. );
  27. await dialog.show();
  28. try {
  29. await FileMagicService.instance.changeVisibility(files, newVisibility);
  30. showShortToast(
  31. context,
  32. newVisibility == visibilityArchive
  33. ? S.of(context).successfullyArchived
  34. : S.of(context).successfullyUnarchived,
  35. );
  36. await dialog.hide();
  37. } catch (e, s) {
  38. _logger.severe("failed to update file visibility", e, s);
  39. await dialog.hide();
  40. rethrow;
  41. }
  42. }
  43. Future<void> changeCollectionVisibility(
  44. BuildContext context,
  45. Collection collection,
  46. int newVisibility,
  47. ) async {
  48. final dialog = createProgressDialog(
  49. context,
  50. newVisibility == visibilityArchive
  51. ? S.of(context).archiving
  52. : S.of(context).unarchiving,
  53. );
  54. await dialog.show();
  55. try {
  56. final Map<String, dynamic> update = {magicKeyVisibility: newVisibility};
  57. await CollectionsService.instance.updateMagicMetadata(collection, update);
  58. // Force reload home gallery to pull in the now unarchived files
  59. Bus.instance.fire(ForceReloadHomeGalleryEvent("CollectionArchiveChange"));
  60. showShortToast(
  61. context,
  62. newVisibility == visibilityArchive
  63. ? S.of(context).successfullyArchived
  64. : S.of(context).successfullyUnarchived,
  65. );
  66. await dialog.hide();
  67. } catch (e, s) {
  68. _logger.severe("failed to update collection visibility", e, s);
  69. await dialog.hide();
  70. rethrow;
  71. }
  72. }
  73. Future<bool> editTime(
  74. BuildContext context,
  75. List<File> files,
  76. int editedTime,
  77. ) async {
  78. try {
  79. await _updatePublicMetadata(
  80. context,
  81. files,
  82. pubMagicKeyEditedTime,
  83. editedTime,
  84. );
  85. return true;
  86. } catch (e) {
  87. showShortToast(context, S.of(context).somethingWentWrong);
  88. return false;
  89. }
  90. }
  91. Future<void> editFilename(
  92. BuildContext context,
  93. File file,
  94. ) async {
  95. final fileName = file.displayName;
  96. final nameWithoutExt = basenameWithoutExtension(fileName);
  97. final extName = extension(fileName);
  98. final result = await showTextInputDialog(
  99. context,
  100. title: S.of(context).renameFile,
  101. submitButtonLabel: S.of(context).rename,
  102. initialValue: nameWithoutExt,
  103. message: extName.toUpperCase(),
  104. alignMessage: Alignment.centerRight,
  105. hintText: S.of(context).enterFileName,
  106. maxLength: 50,
  107. alwaysShowSuccessState: true,
  108. onSubmit: (String text) async {
  109. if (text.isEmpty || text.trim() == nameWithoutExt.trim()) {
  110. return;
  111. }
  112. final newName = text + extName;
  113. await _updatePublicMetadata(
  114. context,
  115. List.of([file]),
  116. pubMagicKeyEditedName,
  117. newName,
  118. showProgressDialogs: false,
  119. showDoneToast: false,
  120. );
  121. },
  122. );
  123. if (result is Exception) {
  124. _logger.severe("Failed to rename file");
  125. showGenericErrorDialog(context: context);
  126. }
  127. }
  128. Future<bool> editFileCaption(
  129. BuildContext? context,
  130. File file,
  131. String caption,
  132. ) async {
  133. try {
  134. await _updatePublicMetadata(
  135. context,
  136. [file],
  137. pubMagicKeyCaption,
  138. caption,
  139. showDoneToast: false,
  140. );
  141. return true;
  142. } catch (e) {
  143. if (context != null) {
  144. showShortToast(context, S.of(context).somethingWentWrong);
  145. }
  146. return false;
  147. }
  148. }
  149. Future<void> _updatePublicMetadata(
  150. BuildContext? context,
  151. List<File> files,
  152. String key,
  153. dynamic value, {
  154. bool showDoneToast = true,
  155. bool showProgressDialogs = true,
  156. }) async {
  157. if (files.isEmpty) {
  158. return;
  159. }
  160. ProgressDialog? dialog;
  161. if (context != null && showProgressDialogs) {
  162. dialog = createProgressDialog(context, S.of(context).pleaseWait);
  163. await dialog.show();
  164. }
  165. try {
  166. final Map<String, dynamic> update = {key: value};
  167. await FileMagicService.instance.updatePublicMagicMetadata(files, update);
  168. if (context != null) {
  169. if (showDoneToast) {
  170. showShortToast(context, S.of(context).done);
  171. }
  172. await dialog?.hide();
  173. }
  174. if (_shouldReloadGallery(key)) {
  175. Bus.instance.fire(ForceReloadHomeGalleryEvent("FileMetadataChange-$key"));
  176. }
  177. } catch (e, s) {
  178. _logger.severe("failed to update $key = $value", e, s);
  179. if (context != null) {
  180. await dialog?.hide();
  181. }
  182. rethrow;
  183. }
  184. }
  185. bool _shouldReloadGallery(String key) {
  186. return key == pubMagicKeyEditedTime;
  187. }