magic_util.dart 5.1 KB

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