warn and optionally set metadata date before moving undated items
This commit is contained in:
parent
150e94cee5
commit
1101400ae2
14 changed files with 289 additions and 130 deletions
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## <a id="unreleased"></a>[Unreleased]
|
## <a id="unreleased"></a>[Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Theme: light/dark/black and poly/monochrome settings
|
||||||
|
- Video: speed and muted state indicators
|
||||||
|
- Info: option to set date from other item
|
||||||
|
- warn and optionally set metadata date before moving undated items
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Viewer: quick action defaults
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- app launch despite faulty storage volumes on Android 11+
|
||||||
|
|
||||||
## <a id="v1.6.2"></a>[v1.6.2] - 2022-03-07
|
## <a id="v1.6.2"></a>[v1.6.2] - 2022-03-07
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -286,6 +286,8 @@
|
||||||
"count": {}
|
"count": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"moveUndatedConfirmationDialogMessage": "Some items have no metadata date. Their current date will be reset by this operation unless a metadata date is set.",
|
||||||
|
"moveUndatedConfirmationDialogSetDate": "Set date",
|
||||||
|
|
||||||
"videoResumeDialogMessage": "Do you want to resume playing at {time}?",
|
"videoResumeDialogMessage": "Do you want to resume playing at {time}?",
|
||||||
"@videoResumeDialogMessage": {
|
"@videoResumeDialogMessage": {
|
||||||
|
@ -568,6 +570,7 @@
|
||||||
"settingsConfirmationDialogTitle": "Confirmation Dialogs",
|
"settingsConfirmationDialogTitle": "Confirmation Dialogs",
|
||||||
"settingsConfirmationDialogDeleteItems": "Ask before deleting items forever",
|
"settingsConfirmationDialogDeleteItems": "Ask before deleting items forever",
|
||||||
"settingsConfirmationDialogMoveToBinItems": "Ask before moving items to the recycle bin",
|
"settingsConfirmationDialogMoveToBinItems": "Ask before moving items to the recycle bin",
|
||||||
|
"settingsConfirmationDialogMoveUndatedItems": "Ask before moving items without a metadata date",
|
||||||
|
|
||||||
"settingsNavigationDrawerTile": "Navigation menu",
|
"settingsNavigationDrawerTile": "Navigation menu",
|
||||||
"settingsNavigationDrawerEditorTitle": "Navigation Menu",
|
"settingsNavigationDrawerEditorTitle": "Navigation Menu",
|
||||||
|
|
|
@ -23,7 +23,10 @@ class SettingsDefaults {
|
||||||
static const mustBackTwiceToExit = true;
|
static const mustBackTwiceToExit = true;
|
||||||
static const keepScreenOn = KeepScreenOn.viewerOnly;
|
static const keepScreenOn = KeepScreenOn.viewerOnly;
|
||||||
static const homePage = HomePageSetting.collection;
|
static const homePage = HomePageSetting.collection;
|
||||||
static const confirmationDialogs = ConfirmationDialog.values;
|
static const confirmDeleteForever = true;
|
||||||
|
static const confirmMoveToBin = true;
|
||||||
|
static const confirmMoveUndatedItems = true;
|
||||||
|
static const setMetadataDateBeforeFileOp = false;
|
||||||
static final drawerTypeBookmarks = [
|
static final drawerTypeBookmarks = [
|
||||||
null,
|
null,
|
||||||
MimeFilter.video,
|
MimeFilter.video,
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
import 'enums.dart';
|
|
||||||
|
|
||||||
extension ExtraConfirmationDialog on ConfirmationDialog {
|
|
||||||
String getName(BuildContext context) {
|
|
||||||
switch (this) {
|
|
||||||
case ConfirmationDialog.delete:
|
|
||||||
return context.l10n.settingsConfirmationDialogDeleteItems;
|
|
||||||
case ConfirmationDialog.moveToBin:
|
|
||||||
return context.l10n.settingsConfirmationDialogMoveToBinItems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,7 @@ enum AvesThemeColorMode { monochrome, polychrome }
|
||||||
|
|
||||||
enum AvesThemeBrightness { system, light, dark, black }
|
enum AvesThemeBrightness { system, light, dark, black }
|
||||||
|
|
||||||
enum ConfirmationDialog { delete, moveToBin }
|
enum ConfirmationDialog { deleteForever, moveToBin, moveUndatedItems }
|
||||||
|
|
||||||
enum CoordinateFormat { dms, decimal }
|
enum CoordinateFormat { dms, decimal }
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,10 @@ class Settings extends ChangeNotifier {
|
||||||
static const mustBackTwiceToExitKey = 'must_back_twice_to_exit';
|
static const mustBackTwiceToExitKey = 'must_back_twice_to_exit';
|
||||||
static const keepScreenOnKey = 'keep_screen_on';
|
static const keepScreenOnKey = 'keep_screen_on';
|
||||||
static const homePageKey = 'home_page';
|
static const homePageKey = 'home_page';
|
||||||
static const confirmationDialogsKey = 'confirmation_dialogs';
|
static const confirmDeleteForeverKey = 'confirm_delete_forever';
|
||||||
|
static const confirmMoveToBinKey = 'confirm_move_to_bin';
|
||||||
|
static const confirmMoveUndatedItemsKey = 'confirm_move_undated_items';
|
||||||
|
static const setMetadataDateBeforeFileOpKey = 'set_metadata_date_before_file_op';
|
||||||
static const drawerTypeBookmarksKey = 'drawer_type_bookmarks';
|
static const drawerTypeBookmarksKey = 'drawer_type_bookmarks';
|
||||||
static const drawerAlbumBookmarksKey = 'drawer_album_bookmarks';
|
static const drawerAlbumBookmarksKey = 'drawer_album_bookmarks';
|
||||||
static const drawerPageBookmarksKey = 'drawer_page_bookmarks';
|
static const drawerPageBookmarksKey = 'drawer_page_bookmarks';
|
||||||
|
@ -279,9 +282,21 @@ class Settings extends ChangeNotifier {
|
||||||
|
|
||||||
set homePage(HomePageSetting newValue) => setAndNotify(homePageKey, newValue.toString());
|
set homePage(HomePageSetting newValue) => setAndNotify(homePageKey, newValue.toString());
|
||||||
|
|
||||||
List<ConfirmationDialog> get confirmationDialogs => getEnumListOrDefault(confirmationDialogsKey, SettingsDefaults.confirmationDialogs, ConfirmationDialog.values);
|
bool get confirmDeleteForever => getBoolOrDefault(confirmDeleteForeverKey, SettingsDefaults.confirmDeleteForever);
|
||||||
|
|
||||||
set confirmationDialogs(List<ConfirmationDialog> newValue) => setAndNotify(confirmationDialogsKey, newValue.map((v) => v.toString()).toList());
|
set confirmDeleteForever(bool newValue) => setAndNotify(confirmDeleteForeverKey, newValue);
|
||||||
|
|
||||||
|
bool get confirmMoveToBin => getBoolOrDefault(confirmMoveToBinKey, SettingsDefaults.confirmMoveToBin);
|
||||||
|
|
||||||
|
set confirmMoveToBin(bool newValue) => setAndNotify(confirmMoveToBinKey, newValue);
|
||||||
|
|
||||||
|
bool get confirmMoveUndatedItems => getBoolOrDefault(confirmMoveUndatedItemsKey, SettingsDefaults.confirmMoveUndatedItems);
|
||||||
|
|
||||||
|
set confirmMoveUndatedItems(bool newValue) => setAndNotify(confirmMoveUndatedItemsKey, newValue);
|
||||||
|
|
||||||
|
bool get setMetadataDateBeforeFileOp => getBoolOrDefault(setMetadataDateBeforeFileOpKey, SettingsDefaults.setMetadataDateBeforeFileOp);
|
||||||
|
|
||||||
|
set setMetadataDateBeforeFileOp(bool newValue) => setAndNotify(setMetadataDateBeforeFileOpKey, newValue);
|
||||||
|
|
||||||
List<CollectionFilter?> get drawerTypeBookmarks =>
|
List<CollectionFilter?> get drawerTypeBookmarks =>
|
||||||
(getStringList(drawerTypeBookmarksKey))?.map((v) {
|
(getStringList(drawerTypeBookmarksKey))?.map((v) {
|
||||||
|
@ -656,6 +671,10 @@ class Settings extends ChangeNotifier {
|
||||||
case isInstalledAppAccessAllowedKey:
|
case isInstalledAppAccessAllowedKey:
|
||||||
case isErrorReportingAllowedKey:
|
case isErrorReportingAllowedKey:
|
||||||
case mustBackTwiceToExitKey:
|
case mustBackTwiceToExitKey:
|
||||||
|
case confirmDeleteForeverKey:
|
||||||
|
case confirmMoveToBinKey:
|
||||||
|
case confirmMoveUndatedItemsKey:
|
||||||
|
case setMetadataDateBeforeFileOpKey:
|
||||||
case showThumbnailFavouriteKey:
|
case showThumbnailFavouriteKey:
|
||||||
case showThumbnailLocationKey:
|
case showThumbnailLocationKey:
|
||||||
case showThumbnailMotionPhotoKey:
|
case showThumbnailMotionPhotoKey:
|
||||||
|
@ -710,7 +729,6 @@ class Settings extends ChangeNotifier {
|
||||||
debugPrint('failed to import key=$key, value=$newValue is not a string');
|
debugPrint('failed to import key=$key, value=$newValue is not a string');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case confirmationDialogsKey:
|
|
||||||
case drawerTypeBookmarksKey:
|
case drawerTypeBookmarksKey:
|
||||||
case drawerAlbumBookmarksKey:
|
case drawerAlbumBookmarksKey:
|
||||||
case drawerPageBookmarksKey:
|
case drawerPageBookmarksKey:
|
||||||
|
|
|
@ -75,7 +75,7 @@ mixin LocationMixin on SourceBase {
|
||||||
// full reverse geocoding, requiring Play Services and some connectivity
|
// full reverse geocoding, requiring Play Services and some connectivity
|
||||||
Future<void> _locatePlaces(AnalysisController controller, Set<AvesEntry> candidateEntries) async {
|
Future<void> _locatePlaces(AnalysisController controller, Set<AvesEntry> candidateEntries) async {
|
||||||
if (controller.isStopping) return;
|
if (controller.isStopping) return;
|
||||||
if (!(await availability.canLocatePlaces)) return;
|
if (!await availability.canLocatePlaces) return;
|
||||||
|
|
||||||
final force = controller.force;
|
final force = controller.force;
|
||||||
final todo = (force ? candidateEntries.where((entry) => entry.hasGps) : candidateEntries.where(locatePlacesTest)).toSet();
|
final todo = (force ? candidateEntries.where((entry) => entry.hasGps) : candidateEntries.where(locatePlacesTest)).toSet();
|
||||||
|
|
|
@ -8,6 +8,7 @@ import 'package:aves/model/entry.dart';
|
||||||
import 'package:aves/model/entry_metadata_edition.dart';
|
import 'package:aves/model/entry_metadata_edition.dart';
|
||||||
import 'package:aves/model/favourites.dart';
|
import 'package:aves/model/favourites.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
|
import 'package:aves/model/metadata/date_modifier.dart';
|
||||||
import 'package:aves/model/query.dart';
|
import 'package:aves/model/query.dart';
|
||||||
import 'package:aves/model/selection.dart';
|
import 'package:aves/model/selection.dart';
|
||||||
import 'package:aves/model/settings/enums/enums.dart';
|
import 'package:aves/model/settings/enums/enums.dart';
|
||||||
|
@ -197,7 +198,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
_flip(context);
|
_flip(context);
|
||||||
break;
|
break;
|
||||||
case EntrySetAction.editDate:
|
case EntrySetAction.editDate:
|
||||||
_editDate(context);
|
editDate(context);
|
||||||
break;
|
break;
|
||||||
case EntrySetAction.editLocation:
|
case EntrySetAction.editLocation:
|
||||||
_editLocation(context);
|
_editLocation(context);
|
||||||
|
@ -214,6 +215,11 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _leaveSelectionMode(BuildContext context) {
|
||||||
|
final selection = context.read<Selection<AvesEntry>?>();
|
||||||
|
selection?.browse();
|
||||||
|
}
|
||||||
|
|
||||||
Set<AvesEntry> _getTargetItems(BuildContext context) {
|
Set<AvesEntry> _getTargetItems(BuildContext context) {
|
||||||
final selection = context.read<Selection<AvesEntry>>();
|
final selection = context.read<Selection<AvesEntry>>();
|
||||||
final groupedEntries = (selection.isSelecting ? selection.selectedItems : context.read<CollectionLens>().sortedEntries);
|
final groupedEntries = (selection.isSelecting ? selection.selectedItems : context.read<CollectionLens>().sortedEntries);
|
||||||
|
@ -234,8 +240,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
final collection = context.read<CollectionLens>();
|
final collection = context.read<CollectionLens>();
|
||||||
collection.source.analyze(controller, entries: entries);
|
collection.source.analyze(controller, entries: entries);
|
||||||
|
|
||||||
final selection = context.read<Selection<AvesEntry>>();
|
_leaveSelectionMode(context);
|
||||||
selection.browse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _toggleFavourite(BuildContext context) async {
|
Future<void> _toggleFavourite(BuildContext context) async {
|
||||||
|
@ -246,8 +251,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
await favourites.add(entries);
|
await favourites.add(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
final selection = context.read<Selection<AvesEntry>>();
|
_leaveSelectionMode(context);
|
||||||
selection.browse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _delete(BuildContext context) async {
|
Future<void> _delete(BuildContext context) async {
|
||||||
|
@ -264,12 +268,12 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
final selectionDirs = entries.map((e) => e.directory).whereNotNull().toSet();
|
final selectionDirs = entries.map((e) => e.directory).whereNotNull().toSet();
|
||||||
final todoCount = entries.length;
|
final todoCount = entries.length;
|
||||||
|
|
||||||
if (!(await showConfirmationDialog(
|
if (!await showConfirmationDialog(
|
||||||
context: context,
|
context: context,
|
||||||
type: ConfirmationDialog.delete,
|
type: ConfirmationDialog.deleteForever,
|
||||||
message: l10n.deleteEntriesConfirmationDialogMessage(todoCount),
|
message: l10n.deleteEntriesConfirmationDialogMessage(todoCount),
|
||||||
confirmationButtonLabel: l10n.deleteButtonLabel,
|
confirmationButtonLabel: l10n.deleteButtonLabel,
|
||||||
))) return;
|
)) return;
|
||||||
|
|
||||||
if (!pureTrash && !await checkStoragePermissionForAlbums(context, selectionDirs, entries: entries)) return;
|
if (!pureTrash && !await checkStoragePermissionForAlbums(context, selectionDirs, entries: entries)) return;
|
||||||
|
|
||||||
|
@ -298,23 +302,22 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
final selection = context.read<Selection<AvesEntry>>();
|
_leaveSelectionMode(context);
|
||||||
selection.browse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _move(BuildContext context, {required MoveType moveType}) async {
|
Future<void> _move(BuildContext context, {required MoveType moveType}) async {
|
||||||
final entries = _getTargetItems(context);
|
final entries = _getTargetItems(context);
|
||||||
await move(context, moveType: moveType, entries: entries);
|
await move(context, moveType: moveType, entries: entries);
|
||||||
|
|
||||||
final selection = context.read<Selection<AvesEntry>>();
|
_leaveSelectionMode(context);
|
||||||
selection.browse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _edit(
|
Future<void> _edit(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
Set<AvesEntry> todoItems,
|
Set<AvesEntry> todoItems,
|
||||||
Future<Set<EntryDataType>> Function(AvesEntry entry) op,
|
Future<Set<EntryDataType>> Function(AvesEntry entry) op, {
|
||||||
) async {
|
bool showResult = true,
|
||||||
|
}) async {
|
||||||
final selectionDirs = todoItems.map((e) => e.directory).whereNotNull().toSet();
|
final selectionDirs = todoItems.map((e) => e.directory).whereNotNull().toSet();
|
||||||
final todoCount = todoItems.length;
|
final todoCount = todoItems.length;
|
||||||
|
|
||||||
|
@ -355,19 +358,20 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
final l10n = context.l10n;
|
if (showResult) {
|
||||||
final successCount = successOps.length;
|
final l10n = context.l10n;
|
||||||
if (successCount < todoCount) {
|
final successCount = successOps.length;
|
||||||
final count = todoCount - successCount;
|
if (successCount < todoCount) {
|
||||||
showFeedback(context, l10n.collectionEditFailureFeedback(count));
|
final count = todoCount - successCount;
|
||||||
} else {
|
showFeedback(context, l10n.collectionEditFailureFeedback(count));
|
||||||
final count = editedOps.length;
|
} else {
|
||||||
showFeedback(context, l10n.collectionEditSuccessFeedback(count));
|
final count = editedOps.length;
|
||||||
|
showFeedback(context, l10n.collectionEditSuccessFeedback(count));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
final selection = context.read<Selection<AvesEntry>>();
|
_leaveSelectionMode(context);
|
||||||
selection.browse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Set<AvesEntry>?> _getEditableTargetItems(
|
Future<Set<AvesEntry>?> _getEditableTargetItems(
|
||||||
|
@ -410,78 +414,80 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _rotate(BuildContext context, {required bool clockwise}) async {
|
Future<void> _rotate(BuildContext context, {required bool clockwise}) async {
|
||||||
final todoItems = await _getEditableTargetItems(context, canEdit: (entry) => entry.canRotateAndFlip);
|
final entries = await _getEditableTargetItems(context, canEdit: (entry) => entry.canRotateAndFlip);
|
||||||
if (todoItems == null || todoItems.isEmpty) return;
|
if (entries == null || entries.isEmpty) return;
|
||||||
|
|
||||||
await _edit(context, todoItems, (entry) => entry.rotate(clockwise: clockwise));
|
await _edit(context, entries, (entry) => entry.rotate(clockwise: clockwise));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _flip(BuildContext context) async {
|
Future<void> _flip(BuildContext context) async {
|
||||||
final todoItems = await _getEditableTargetItems(context, canEdit: (entry) => entry.canRotateAndFlip);
|
final entries = await _getEditableTargetItems(context, canEdit: (entry) => entry.canRotateAndFlip);
|
||||||
if (todoItems == null || todoItems.isEmpty) return;
|
if (entries == null || entries.isEmpty) return;
|
||||||
|
|
||||||
await _edit(context, todoItems, (entry) => entry.flip());
|
await _edit(context, entries, (entry) => entry.flip());
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _editDate(BuildContext context) async {
|
Future<void> editDate(BuildContext context, {Set<AvesEntry>? entries, DateModifier? modifier, bool showResult = true}) async {
|
||||||
final todoItems = await _getEditableTargetItems(context, canEdit: (entry) => entry.canEditDate);
|
entries ??= await _getEditableTargetItems(context, canEdit: (entry) => entry.canEditDate);
|
||||||
if (todoItems == null || todoItems.isEmpty) return;
|
if (entries == null || entries.isEmpty) return;
|
||||||
|
|
||||||
final collection = context.read<CollectionLens>();
|
if (modifier == null) {
|
||||||
final modifier = await selectDateModifier(context, todoItems, collection);
|
final collection = context.read<CollectionLens>();
|
||||||
|
modifier = await selectDateModifier(context, entries, collection);
|
||||||
|
}
|
||||||
if (modifier == null) return;
|
if (modifier == null) return;
|
||||||
|
|
||||||
await _edit(context, todoItems, (entry) => entry.editDate(modifier));
|
await _edit(context, entries, (entry) => entry.editDate(modifier!), showResult: showResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _editLocation(BuildContext context) async {
|
Future<void> _editLocation(BuildContext context) async {
|
||||||
final todoItems = await _getEditableTargetItems(context, canEdit: (entry) => entry.canEditLocation);
|
final entries = await _getEditableTargetItems(context, canEdit: (entry) => entry.canEditLocation);
|
||||||
if (todoItems == null || todoItems.isEmpty) return;
|
if (entries == null || entries.isEmpty) return;
|
||||||
|
|
||||||
final collection = context.read<CollectionLens>();
|
final collection = context.read<CollectionLens>();
|
||||||
final location = await selectLocation(context, todoItems, collection);
|
final location = await selectLocation(context, entries, collection);
|
||||||
if (location == null) return;
|
if (location == null) return;
|
||||||
|
|
||||||
await _edit(context, todoItems, (entry) => entry.editLocation(location));
|
await _edit(context, entries, (entry) => entry.editLocation(location));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _editRating(BuildContext context) async {
|
Future<void> _editRating(BuildContext context) async {
|
||||||
final todoItems = await _getEditableTargetItems(context, canEdit: (entry) => entry.canEditRating);
|
final entries = await _getEditableTargetItems(context, canEdit: (entry) => entry.canEditRating);
|
||||||
if (todoItems == null || todoItems.isEmpty) return;
|
if (entries == null || entries.isEmpty) return;
|
||||||
|
|
||||||
final rating = await selectRating(context, todoItems);
|
final rating = await selectRating(context, entries);
|
||||||
if (rating == null) return;
|
if (rating == null) return;
|
||||||
|
|
||||||
await _edit(context, todoItems, (entry) => entry.editRating(rating));
|
await _edit(context, entries, (entry) => entry.editRating(rating));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _editTags(BuildContext context) async {
|
Future<void> _editTags(BuildContext context) async {
|
||||||
final todoItems = await _getEditableTargetItems(context, canEdit: (entry) => entry.canEditTags);
|
final entries = await _getEditableTargetItems(context, canEdit: (entry) => entry.canEditTags);
|
||||||
if (todoItems == null || todoItems.isEmpty) return;
|
if (entries == null || entries.isEmpty) return;
|
||||||
|
|
||||||
final newTagsByEntry = await selectTags(context, todoItems);
|
final newTagsByEntry = await selectTags(context, entries);
|
||||||
if (newTagsByEntry == null) return;
|
if (newTagsByEntry == null) return;
|
||||||
|
|
||||||
// only process modified items
|
// only process modified items
|
||||||
todoItems.removeWhere((entry) {
|
entries.removeWhere((entry) {
|
||||||
final newTags = newTagsByEntry[entry] ?? entry.tags;
|
final newTags = newTagsByEntry[entry] ?? entry.tags;
|
||||||
final currentTags = entry.tags;
|
final currentTags = entry.tags;
|
||||||
return newTags.length == currentTags.length && newTags.every(currentTags.contains);
|
return newTags.length == currentTags.length && newTags.every(currentTags.contains);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (todoItems.isEmpty) return;
|
if (entries.isEmpty) return;
|
||||||
|
|
||||||
await _edit(context, todoItems, (entry) => entry.editTags(newTagsByEntry[entry]!));
|
await _edit(context, entries, (entry) => entry.editTags(newTagsByEntry[entry]!));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _removeMetadata(BuildContext context) async {
|
Future<void> _removeMetadata(BuildContext context) async {
|
||||||
final todoItems = await _getEditableTargetItems(context, canEdit: (entry) => entry.canRemoveMetadata);
|
final entries = await _getEditableTargetItems(context, canEdit: (entry) => entry.canRemoveMetadata);
|
||||||
if (todoItems == null || todoItems.isEmpty) return;
|
if (entries == null || entries.isEmpty) return;
|
||||||
|
|
||||||
final types = await selectMetadataToRemove(context, todoItems);
|
final types = await selectMetadataToRemove(context, entries);
|
||||||
if (types == null || types.isEmpty) return;
|
if (types == null || types.isEmpty) return;
|
||||||
|
|
||||||
await _edit(context, todoItems, (entry) => entry.removeMetadata(types));
|
await _edit(context, entries, (entry) => entry.removeMetadata(types));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _goToMap(BuildContext context) {
|
void _goToMap(BuildContext context) {
|
||||||
|
|
|
@ -7,7 +7,10 @@ import 'package:aves/model/entry.dart';
|
||||||
import 'package:aves/model/filters/album.dart';
|
import 'package:aves/model/filters/album.dart';
|
||||||
import 'package:aves/model/filters/trash.dart';
|
import 'package:aves/model/filters/trash.dart';
|
||||||
import 'package:aves/model/highlight.dart';
|
import 'package:aves/model/highlight.dart';
|
||||||
|
import 'package:aves/model/metadata/date_modifier.dart';
|
||||||
|
import 'package:aves/model/metadata/enums.dart';
|
||||||
import 'package:aves/model/settings/enums/enums.dart';
|
import 'package:aves/model/settings/enums/enums.dart';
|
||||||
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/collection_lens.dart';
|
import 'package:aves/model/source/collection_lens.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/services/common/image_op_events.dart';
|
import 'package:aves/services/common/image_op_events.dart';
|
||||||
|
@ -16,6 +19,7 @@ import 'package:aves/services/media/enums.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
import 'package:aves/widgets/collection/collection_page.dart';
|
import 'package:aves/widgets/collection/collection_page.dart';
|
||||||
|
import 'package:aves/widgets/collection/entry_set_action_delegate.dart';
|
||||||
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
||||||
import 'package:aves/widgets/common/action_mixins/permission_aware.dart';
|
import 'package:aves/widgets/common/action_mixins/permission_aware.dart';
|
||||||
import 'package:aves/widgets/common/action_mixins/size_aware.dart';
|
import 'package:aves/widgets/common/action_mixins/size_aware.dart';
|
||||||
|
@ -42,12 +46,12 @@ mixin EntryStorageMixin on FeedbackMixin, PermissionAwareMixin, SizeAwareMixin {
|
||||||
|
|
||||||
final l10n = context.l10n;
|
final l10n = context.l10n;
|
||||||
if (toBin) {
|
if (toBin) {
|
||||||
if (!(await showConfirmationDialog(
|
if (!await showConfirmationDialog(
|
||||||
context: context,
|
context: context,
|
||||||
type: ConfirmationDialog.moveToBin,
|
type: ConfirmationDialog.moveToBin,
|
||||||
message: l10n.binEntriesConfirmationDialogMessage(todoCount),
|
message: l10n.binEntriesConfirmationDialogMessage(todoCount),
|
||||||
confirmationButtonLabel: l10n.deleteButtonLabel,
|
confirmationButtonLabel: l10n.deleteButtonLabel,
|
||||||
))) return;
|
)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final entriesByDestination = <String, Set<AvesEntry>>{};
|
final entriesByDestination = <String, Set<AvesEntry>>{};
|
||||||
|
@ -108,6 +112,8 @@ mixin EntryStorageMixin on FeedbackMixin, PermissionAwareMixin, SizeAwareMixin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ({MoveType.move, MoveType.copy}.contains(moveType) && !await _checkUndatedItems(context, entries)) return;
|
||||||
|
|
||||||
final source = context.read<CollectionSource>();
|
final source = context.read<CollectionSource>();
|
||||||
source.pauseMonitoring();
|
source.pauseMonitoring();
|
||||||
final opId = mediaFileService.newOpId;
|
final opId = mediaFileService.newOpId;
|
||||||
|
@ -196,4 +202,60 @@ mixin EntryStorageMixin on FeedbackMixin, PermissionAwareMixin, SizeAwareMixin {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> _checkUndatedItems(BuildContext context, Set<AvesEntry> entries) async {
|
||||||
|
final undatedItems = entries.where((entry) {
|
||||||
|
if (!entry.isCatalogued) return false;
|
||||||
|
final dateMillis = entry.catalogMetadata?.dateMillis;
|
||||||
|
return dateMillis == null || dateMillis == 0;
|
||||||
|
}).toSet();
|
||||||
|
if (undatedItems.isNotEmpty) {
|
||||||
|
if (!await showConfirmationDialog(
|
||||||
|
context: context,
|
||||||
|
type: ConfirmationDialog.moveUndatedItems,
|
||||||
|
delegate: MoveUndatedConfirmationDialogDelegate(),
|
||||||
|
confirmationButtonLabel: context.l10n.continueButtonLabel,
|
||||||
|
)) return false;
|
||||||
|
|
||||||
|
if (settings.setMetadataDateBeforeFileOp) {
|
||||||
|
final entriesToDate = undatedItems.where((entry) => entry.canEditDate).toSet();
|
||||||
|
if (entriesToDate.isNotEmpty) {
|
||||||
|
await EntrySetActionDelegate().editDate(
|
||||||
|
context,
|
||||||
|
entries: entriesToDate,
|
||||||
|
modifier: DateModifier.copyField(DateFieldSource.fileModifiedDate),
|
||||||
|
showResult: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MoveUndatedConfirmationDialogDelegate extends ConfirmationDialogDelegate {
|
||||||
|
final ValueNotifier<bool> _setMetadataDate = ValueNotifier(false);
|
||||||
|
|
||||||
|
MoveUndatedConfirmationDialogDelegate() {
|
||||||
|
_setMetadataDate.value = settings.setMetadataDateBeforeFileOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Widget> build(BuildContext context) => [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(16) + const EdgeInsets.only(top: 8),
|
||||||
|
child: Text(context.l10n.moveUndatedConfirmationDialogMessage),
|
||||||
|
),
|
||||||
|
ValueListenableBuilder<bool>(
|
||||||
|
valueListenable: _setMetadataDate,
|
||||||
|
builder: (context, flag, child) => SwitchListTile(
|
||||||
|
value: flag,
|
||||||
|
onChanged: (v) => _setMetadataDate.value = v,
|
||||||
|
title: Text(context.l10n.moveUndatedConfirmationDialogSetDate),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void apply() => settings.setMetadataDateBeforeFileOp = _setMetadataDate.value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,56 +5,107 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'aves_dialog.dart';
|
import 'aves_dialog.dart';
|
||||||
|
|
||||||
|
abstract class ConfirmationDialogDelegate {
|
||||||
|
List<Widget> build(BuildContext context);
|
||||||
|
|
||||||
|
void apply() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageConfirmationDialogDelegate extends ConfirmationDialogDelegate {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
MessageConfirmationDialogDelegate(this.message);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Widget> build(BuildContext context) => [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(16) + const EdgeInsets.only(top: 8),
|
||||||
|
child: Text(message),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> showConfirmationDialog({
|
Future<bool> showConfirmationDialog({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required ConfirmationDialog type,
|
required ConfirmationDialog type,
|
||||||
required String message,
|
String? message,
|
||||||
|
ConfirmationDialogDelegate? delegate,
|
||||||
required String confirmationButtonLabel,
|
required String confirmationButtonLabel,
|
||||||
}) async {
|
}) async {
|
||||||
if (!settings.confirmationDialogs.contains(type)) return true;
|
if (!_shouldConfirm(type)) return true;
|
||||||
|
|
||||||
|
assert((message != null) ^ (delegate != null));
|
||||||
|
final effectiveDelegate = delegate ?? MessageConfirmationDialogDelegate(message!);
|
||||||
final confirmed = await showDialog<bool>(
|
final confirmed = await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AvesConfirmationDialog(
|
builder: (context) => _AvesConfirmationDialog(
|
||||||
type: type,
|
type: type,
|
||||||
message: message,
|
delegate: effectiveDelegate,
|
||||||
confirmationButtonLabel: confirmationButtonLabel,
|
confirmationButtonLabel: confirmationButtonLabel,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return confirmed == true;
|
if (confirmed == null) return false;
|
||||||
|
|
||||||
|
if (confirmed) {
|
||||||
|
effectiveDelegate.apply();
|
||||||
|
}
|
||||||
|
return confirmed;
|
||||||
}
|
}
|
||||||
|
|
||||||
class AvesConfirmationDialog extends StatefulWidget {
|
bool _shouldConfirm(ConfirmationDialog type) {
|
||||||
final ConfirmationDialog type;
|
switch (type) {
|
||||||
final String message, confirmationButtonLabel;
|
case ConfirmationDialog.deleteForever:
|
||||||
|
return settings.confirmDeleteForever;
|
||||||
|
case ConfirmationDialog.moveToBin:
|
||||||
|
return settings.confirmMoveToBin;
|
||||||
|
case ConfirmationDialog.moveUndatedItems:
|
||||||
|
return settings.confirmMoveUndatedItems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const AvesConfirmationDialog({
|
void _skipConfirmation(ConfirmationDialog type) {
|
||||||
|
switch (type) {
|
||||||
|
case ConfirmationDialog.deleteForever:
|
||||||
|
settings.confirmDeleteForever = false;
|
||||||
|
break;
|
||||||
|
case ConfirmationDialog.moveToBin:
|
||||||
|
settings.confirmMoveToBin = false;
|
||||||
|
break;
|
||||||
|
case ConfirmationDialog.moveUndatedItems:
|
||||||
|
settings.confirmMoveUndatedItems = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AvesConfirmationDialog extends StatefulWidget {
|
||||||
|
final ConfirmationDialog type;
|
||||||
|
final ConfirmationDialogDelegate delegate;
|
||||||
|
final String confirmationButtonLabel;
|
||||||
|
|
||||||
|
const _AvesConfirmationDialog({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.type,
|
required this.type,
|
||||||
required this.message,
|
required this.delegate,
|
||||||
required this.confirmationButtonLabel,
|
required this.confirmationButtonLabel,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AvesConfirmationDialog> createState() => _AvesConfirmationDialogState();
|
State<_AvesConfirmationDialog> createState() => _AvesConfirmationDialogState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AvesConfirmationDialogState extends State<AvesConfirmationDialog> {
|
class _AvesConfirmationDialogState extends State<_AvesConfirmationDialog> {
|
||||||
final ValueNotifier<bool> _skipConfirmation = ValueNotifier(false);
|
final ValueNotifier<bool> _skip = ValueNotifier(false);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AvesDialog(
|
return AvesDialog(
|
||||||
scrollableContent: [
|
scrollableContent: [
|
||||||
Padding(
|
...widget.delegate.build(context),
|
||||||
padding: const EdgeInsets.all(16) + const EdgeInsets.only(top: 8),
|
|
||||||
child: Text(widget.message),
|
|
||||||
),
|
|
||||||
ValueListenableBuilder<bool>(
|
ValueListenableBuilder<bool>(
|
||||||
valueListenable: _skipConfirmation,
|
valueListenable: _skip,
|
||||||
builder: (context, ask, child) => SwitchListTile(
|
builder: (context, flag, child) => SwitchListTile(
|
||||||
value: ask,
|
value: flag,
|
||||||
onChanged: (v) => _skipConfirmation.value = v,
|
onChanged: (v) => _skip.value = v,
|
||||||
title: Text(context.l10n.doNotAskAgain),
|
title: Text(context.l10n.doNotAskAgain),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -66,8 +117,8 @@ class _AvesConfirmationDialogState extends State<AvesConfirmationDialog> {
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (_skipConfirmation.value) {
|
if (_skip.value) {
|
||||||
settings.confirmationDialogs = settings.confirmationDialogs.toList()..remove(widget.type);
|
_skipConfirmation(widget.type);
|
||||||
}
|
}
|
||||||
Navigator.pop(context, true);
|
Navigator.pop(context, true);
|
||||||
},
|
},
|
||||||
|
|
|
@ -290,7 +290,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
|
||||||
|
|
||||||
if (!await checkStoragePermissionForAlbums(context, {album})) return;
|
if (!await checkStoragePermissionForAlbums(context, {album})) return;
|
||||||
|
|
||||||
if (!(await File(destinationAlbum).exists())) {
|
if (!await File(destinationAlbum).exists()) {
|
||||||
// access to the destination parent is required to create the underlying destination folder
|
// access to the destination parent is required to create the underlying destination folder
|
||||||
if (!await checkStoragePermissionForAlbums(context, {destinationAlbumParent})) return;
|
if (!await checkStoragePermissionForAlbums(context, {destinationAlbumParent})) return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import 'package:aves/model/settings/enums/confirmation_dialogs.dart';
|
|
||||||
import 'package:aves/model/settings/enums/enums.dart';
|
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves/widgets/settings/common/tiles.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
class ConfirmationDialogTile extends StatelessWidget {
|
class ConfirmationDialogTile extends StatelessWidget {
|
||||||
const ConfirmationDialogTile({Key? key}) : super(key: key);
|
const ConfirmationDialogTile({Key? key}) : super(key: key);
|
||||||
|
@ -37,29 +35,23 @@ class ConfirmationDialogPage extends StatelessWidget {
|
||||||
title: Text(context.l10n.settingsConfirmationDialogTitle),
|
title: Text(context.l10n.settingsConfirmationDialogTitle),
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Selector<Settings, List<ConfirmationDialog>>(
|
child: ListView(children: [
|
||||||
selector: (context, s) => s.confirmationDialogs,
|
SettingsSwitchListTile(
|
||||||
builder: (context, current, child) => ListView(
|
selector: (context, s) => s.confirmMoveUndatedItems,
|
||||||
children: [
|
onChanged: (v) => settings.confirmMoveUndatedItems = v,
|
||||||
ConfirmationDialog.moveToBin,
|
title: context.l10n.settingsConfirmationDialogMoveUndatedItems,
|
||||||
ConfirmationDialog.delete,
|
|
||||||
]
|
|
||||||
.map((dialog) => SwitchListTile(
|
|
||||||
value: current.contains(dialog),
|
|
||||||
onChanged: (v) {
|
|
||||||
final dialogs = current.toList();
|
|
||||||
if (v) {
|
|
||||||
dialogs.add(dialog);
|
|
||||||
} else {
|
|
||||||
dialogs.remove(dialog);
|
|
||||||
}
|
|
||||||
settings.confirmationDialogs = dialogs;
|
|
||||||
},
|
|
||||||
title: Text(dialog.getName(context)),
|
|
||||||
))
|
|
||||||
.toList(),
|
|
||||||
),
|
),
|
||||||
),
|
SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.confirmMoveToBin,
|
||||||
|
onChanged: (v) => settings.confirmMoveToBin = v,
|
||||||
|
title: context.l10n.settingsConfirmationDialogMoveToBinItems,
|
||||||
|
),
|
||||||
|
SettingsSwitchListTile(
|
||||||
|
selector: (context, s) => s.confirmDeleteForever,
|
||||||
|
onChanged: (v) => settings.confirmDeleteForever = v,
|
||||||
|
title: context.l10n.settingsConfirmationDialogDeleteItems,
|
||||||
|
),
|
||||||
|
]),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,12 +187,12 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
||||||
}
|
}
|
||||||
|
|
||||||
final l10n = context.l10n;
|
final l10n = context.l10n;
|
||||||
if (!(await showConfirmationDialog(
|
if (!await showConfirmationDialog(
|
||||||
context: context,
|
context: context,
|
||||||
type: ConfirmationDialog.delete,
|
type: ConfirmationDialog.deleteForever,
|
||||||
message: l10n.deleteEntriesConfirmationDialogMessage(1),
|
message: l10n.deleteEntriesConfirmationDialogMessage(1),
|
||||||
confirmationButtonLabel: l10n.deleteButtonLabel,
|
confirmationButtonLabel: l10n.deleteButtonLabel,
|
||||||
))) return;
|
)) return;
|
||||||
|
|
||||||
if (!await checkStoragePermission(context, {entry})) return;
|
if (!await checkStoragePermission(context, {entry})) return;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,10 @@
|
||||||
"themeBrightnessLight",
|
"themeBrightnessLight",
|
||||||
"themeBrightnessDark",
|
"themeBrightnessDark",
|
||||||
"themeBrightnessBlack",
|
"themeBrightnessBlack",
|
||||||
|
"moveUndatedConfirmationDialogMessage",
|
||||||
|
"moveUndatedConfirmationDialogSetDate",
|
||||||
"editEntryDateDialogCopyItem",
|
"editEntryDateDialogCopyItem",
|
||||||
|
"settingsConfirmationDialogMoveUndatedItems",
|
||||||
"settingsSectionDisplay",
|
"settingsSectionDisplay",
|
||||||
"settingsThemeBrightness",
|
"settingsThemeBrightness",
|
||||||
"settingsThemeColorful"
|
"settingsThemeColorful"
|
||||||
|
@ -13,7 +16,10 @@
|
||||||
"themeBrightnessLight",
|
"themeBrightnessLight",
|
||||||
"themeBrightnessDark",
|
"themeBrightnessDark",
|
||||||
"themeBrightnessBlack",
|
"themeBrightnessBlack",
|
||||||
|
"moveUndatedConfirmationDialogMessage",
|
||||||
|
"moveUndatedConfirmationDialogSetDate",
|
||||||
"editEntryDateDialogCopyItem",
|
"editEntryDateDialogCopyItem",
|
||||||
|
"settingsConfirmationDialogMoveUndatedItems",
|
||||||
"settingsSectionDisplay",
|
"settingsSectionDisplay",
|
||||||
"settingsThemeBrightness",
|
"settingsThemeBrightness",
|
||||||
"settingsThemeColorful"
|
"settingsThemeColorful"
|
||||||
|
@ -23,7 +29,10 @@
|
||||||
"themeBrightnessLight",
|
"themeBrightnessLight",
|
||||||
"themeBrightnessDark",
|
"themeBrightnessDark",
|
||||||
"themeBrightnessBlack",
|
"themeBrightnessBlack",
|
||||||
|
"moveUndatedConfirmationDialogMessage",
|
||||||
|
"moveUndatedConfirmationDialogSetDate",
|
||||||
"editEntryDateDialogCopyItem",
|
"editEntryDateDialogCopyItem",
|
||||||
|
"settingsConfirmationDialogMoveUndatedItems",
|
||||||
"settingsSectionDisplay",
|
"settingsSectionDisplay",
|
||||||
"settingsThemeBrightness",
|
"settingsThemeBrightness",
|
||||||
"settingsThemeColorful"
|
"settingsThemeColorful"
|
||||||
|
@ -39,7 +48,10 @@
|
||||||
"themeBrightnessLight",
|
"themeBrightnessLight",
|
||||||
"themeBrightnessDark",
|
"themeBrightnessDark",
|
||||||
"themeBrightnessBlack",
|
"themeBrightnessBlack",
|
||||||
|
"moveUndatedConfirmationDialogMessage",
|
||||||
|
"moveUndatedConfirmationDialogSetDate",
|
||||||
"editEntryDateDialogCopyItem",
|
"editEntryDateDialogCopyItem",
|
||||||
|
"settingsConfirmationDialogMoveUndatedItems",
|
||||||
"settingsViewerShowOverlayThumbnails",
|
"settingsViewerShowOverlayThumbnails",
|
||||||
"settingsVideoControlsTile",
|
"settingsVideoControlsTile",
|
||||||
"settingsVideoControlsTitle",
|
"settingsVideoControlsTitle",
|
||||||
|
@ -56,7 +68,10 @@
|
||||||
"themeBrightnessLight",
|
"themeBrightnessLight",
|
||||||
"themeBrightnessDark",
|
"themeBrightnessDark",
|
||||||
"themeBrightnessBlack",
|
"themeBrightnessBlack",
|
||||||
|
"moveUndatedConfirmationDialogMessage",
|
||||||
|
"moveUndatedConfirmationDialogSetDate",
|
||||||
"editEntryDateDialogCopyItem",
|
"editEntryDateDialogCopyItem",
|
||||||
|
"settingsConfirmationDialogMoveUndatedItems",
|
||||||
"settingsSectionDisplay",
|
"settingsSectionDisplay",
|
||||||
"settingsThemeBrightness",
|
"settingsThemeBrightness",
|
||||||
"settingsThemeColorful"
|
"settingsThemeColorful"
|
||||||
|
@ -66,7 +81,10 @@
|
||||||
"themeBrightnessLight",
|
"themeBrightnessLight",
|
||||||
"themeBrightnessDark",
|
"themeBrightnessDark",
|
||||||
"themeBrightnessBlack",
|
"themeBrightnessBlack",
|
||||||
|
"moveUndatedConfirmationDialogMessage",
|
||||||
|
"moveUndatedConfirmationDialogSetDate",
|
||||||
"editEntryDateDialogCopyItem",
|
"editEntryDateDialogCopyItem",
|
||||||
|
"settingsConfirmationDialogMoveUndatedItems",
|
||||||
"settingsSectionDisplay",
|
"settingsSectionDisplay",
|
||||||
"settingsThemeBrightness",
|
"settingsThemeBrightness",
|
||||||
"settingsThemeColorful"
|
"settingsThemeColorful"
|
||||||
|
@ -76,7 +94,10 @@
|
||||||
"themeBrightnessLight",
|
"themeBrightnessLight",
|
||||||
"themeBrightnessDark",
|
"themeBrightnessDark",
|
||||||
"themeBrightnessBlack",
|
"themeBrightnessBlack",
|
||||||
|
"moveUndatedConfirmationDialogMessage",
|
||||||
|
"moveUndatedConfirmationDialogSetDate",
|
||||||
"editEntryDateDialogCopyItem",
|
"editEntryDateDialogCopyItem",
|
||||||
|
"settingsConfirmationDialogMoveUndatedItems",
|
||||||
"settingsSectionDisplay",
|
"settingsSectionDisplay",
|
||||||
"settingsThemeBrightness",
|
"settingsThemeBrightness",
|
||||||
"settingsThemeColorful"
|
"settingsThemeColorful"
|
||||||
|
@ -86,7 +107,10 @@
|
||||||
"themeBrightnessLight",
|
"themeBrightnessLight",
|
||||||
"themeBrightnessDark",
|
"themeBrightnessDark",
|
||||||
"themeBrightnessBlack",
|
"themeBrightnessBlack",
|
||||||
|
"moveUndatedConfirmationDialogMessage",
|
||||||
|
"moveUndatedConfirmationDialogSetDate",
|
||||||
"editEntryDateDialogCopyItem",
|
"editEntryDateDialogCopyItem",
|
||||||
|
"settingsConfirmationDialogMoveUndatedItems",
|
||||||
"settingsSectionDisplay",
|
"settingsSectionDisplay",
|
||||||
"settingsThemeBrightness",
|
"settingsThemeBrightness",
|
||||||
"settingsThemeColorful"
|
"settingsThemeColorful"
|
||||||
|
|
Loading…
Reference in a new issue