#117 collection: edit date in bulk
This commit is contained in:
parent
eb299c2feb
commit
0bf238245f
10 changed files with 273 additions and 59 deletions
|
@ -289,6 +289,18 @@
|
|||
}
|
||||
},
|
||||
|
||||
"unsupportedTypeDialogTitle": "Unsupported Types",
|
||||
"@unsupportedTypeDialogTitle": {},
|
||||
"unsupportedTypeDialogMessage": "{count, plural, =1{This operation is not supported for items of the following type: {types}.} other{This operation is not supported for items of the following types: {types}.}}",
|
||||
"@unsupportedTypeDialogMessage": {
|
||||
"placeholders": {
|
||||
"count": {},
|
||||
"types": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"nameConflictDialogSingleSourceMessage": "Some files in the destination folder have the same name.",
|
||||
"@nameConflictDialogSingleSourceMessage": {},
|
||||
"nameConflictDialogMultipleSourceMessage": "Some files have the same name.",
|
||||
|
@ -360,8 +372,8 @@
|
|||
"@editEntryDateDialogSet": {},
|
||||
"editEntryDateDialogShift": "Shift",
|
||||
"@editEntryDateDialogShift": {},
|
||||
"editEntryDateDialogFromTitle": "From title",
|
||||
"@editEntryDateDialogFromTitle": {},
|
||||
"editEntryDateDialogExtractFromTitle": "Extract from title",
|
||||
"@editEntryDateDialogExtractFromTitle": {},
|
||||
"editEntryDateDialogClear": "Clear",
|
||||
"@editEntryDateDialogClear": {},
|
||||
"editEntryDateDialogFieldSelection": "Field selection",
|
||||
|
@ -493,6 +505,8 @@
|
|||
"@collectionActionMove": {},
|
||||
"collectionActionRescan": "Rescan",
|
||||
"@collectionActionRescan": {},
|
||||
"collectionActionEdit": "Edit",
|
||||
"@collectionActionEdit": {},
|
||||
|
||||
"collectionSortTitle": "Sort",
|
||||
"@collectionSortTitle": {},
|
||||
|
@ -540,6 +554,12 @@
|
|||
"count": {}
|
||||
}
|
||||
},
|
||||
"collectionEditFailureFeedback": "{count, plural, =1{Failed to edit 1 item} other{Failed to edit {count} items}}",
|
||||
"@collectionEditFailureFeedback": {
|
||||
"placeholders": {
|
||||
"count": {}
|
||||
}
|
||||
},
|
||||
"collectionExportFailureFeedback": "{count, plural, =1{Failed to export 1 page} other{Failed to export {count} pages}}",
|
||||
"@collectionExportFailureFeedback": {
|
||||
"placeholders": {
|
||||
|
@ -558,6 +578,12 @@
|
|||
"count": {}
|
||||
}
|
||||
},
|
||||
"collectionEditSuccessFeedback": "{count, plural, =1{Edited 1 item} other{Edited {count} items}}",
|
||||
"@collectionEditSuccessFeedback": {
|
||||
"placeholders": {
|
||||
"count": {}
|
||||
}
|
||||
},
|
||||
|
||||
"collectionEmptyFavourites": "No favourites",
|
||||
"@collectionEmptyFavourites": {},
|
||||
|
|
|
@ -139,7 +139,7 @@
|
|||
"noMatchingAppDialogTitle": "Нет подходящего приложения",
|
||||
"noMatchingAppDialogMessage": "Нет приложений, которые могли бы с этим справиться.",
|
||||
|
||||
"deleteEntriesConfirmationDialogMessage": "{count, plural, =1{Вы уверены, что хотите удалить этот объект?} few{Вы уверены, что хотите удалить эти {count} объекта?} other{Вы уверены, что хотите удалить эти {count} объектов)?}}",
|
||||
"deleteEntriesConfirmationDialogMessage": "{count, plural, =1{Вы уверены, что хотите удалить этот объект?} few{Вы уверены, что хотите удалить эти {count} объекта?} other{Вы уверены, что хотите удалить эти {count} объектов?}}",
|
||||
|
||||
"setCoverDialogTitle": "Установить обложку",
|
||||
"setCoverDialogLatest": "Последний объект",
|
||||
|
@ -228,7 +228,7 @@
|
|||
|
||||
"collectionPageTitle": "Коллекция",
|
||||
"collectionPickPageTitle": "Выбрать",
|
||||
"collectionSelectionPageTitle": "{count, plural, =0{Выберите объекты} =1{1 объект} few{{count} объекта} other{{count} объектов)}}",
|
||||
"collectionSelectionPageTitle": "{count, plural, =0{Выберите объекты} =1{1 объект} few{{count} объекта} other{{count} объектов}}",
|
||||
|
||||
"collectionActionAddShortcut": "Добавить ярлык",
|
||||
"collectionActionCopy": "Скопировать в альбом",
|
||||
|
|
|
@ -20,6 +20,7 @@ enum EntrySetAction {
|
|||
copy,
|
||||
move,
|
||||
rescan,
|
||||
editDate,
|
||||
}
|
||||
|
||||
class EntrySetActions {
|
||||
|
@ -67,6 +68,8 @@ extension ExtraEntrySetAction on EntrySetAction {
|
|||
return context.l10n.collectionActionMove;
|
||||
case EntrySetAction.rescan:
|
||||
return context.l10n.collectionActionRescan;
|
||||
case EntrySetAction.editDate:
|
||||
return context.l10n.entryInfoActionEditDate;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,6 +109,8 @@ extension ExtraEntrySetAction on EntrySetAction {
|
|||
return AIcons.move;
|
||||
case EntrySetAction.rescan:
|
||||
return AIcons.refresh;
|
||||
case EntrySetAction.editDate:
|
||||
return AIcons.date;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -636,7 +636,7 @@ class AvesEntry {
|
|||
}
|
||||
|
||||
Future<bool> editDate(DateModifier modifier) async {
|
||||
if (modifier.action == DateEditAction.fromTitle) {
|
||||
if (modifier.action == DateEditAction.extractFromTitle) {
|
||||
final _title = bestTitle;
|
||||
if (_title == null) return false;
|
||||
final date = parseUnknownDateFormat(_title);
|
||||
|
|
|
@ -8,7 +8,7 @@ enum MetadataField {
|
|||
enum DateEditAction {
|
||||
set,
|
||||
shift,
|
||||
fromTitle,
|
||||
extractFromTitle,
|
||||
clear,
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:aves/model/source/collection_source.dart';
|
|||
import 'package:aves/model/source/enums.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/widgets/collection/entry_set_action_delegate.dart';
|
||||
import 'package:aves/widgets/collection/filter_bar.dart';
|
||||
import 'package:aves/widgets/common/app_bar_subtitle.dart';
|
||||
|
@ -143,14 +144,16 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
}
|
||||
|
||||
Widget? _buildAppBarTitle(bool isSelecting) {
|
||||
final l10n = context.l10n;
|
||||
|
||||
if (isSelecting) {
|
||||
return Selector<Selection<AvesEntry>, int>(
|
||||
selector: (context, selection) => selection.selectedItems.length,
|
||||
builder: (context, count, child) => Text(context.l10n.collectionSelectionPageTitle(count)),
|
||||
builder: (context, count, child) => Text(l10n.collectionSelectionPageTitle(count)),
|
||||
);
|
||||
} else {
|
||||
final appMode = context.watch<ValueNotifier<AppMode>>().value;
|
||||
Widget title = Text(appMode.isPicking ? context.l10n.collectionPickPageTitle : context.l10n.collectionPageTitle);
|
||||
Widget title = Text(appMode.isPicking ? l10n.collectionPickPageTitle : l10n.collectionPageTitle);
|
||||
if (appMode == AppMode.main) {
|
||||
title = SourceStateAwareAppBarTitle(
|
||||
title: title,
|
||||
|
@ -209,7 +212,21 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
enabled: hasItems,
|
||||
),
|
||||
const PopupMenuDivider(),
|
||||
if (isSelecting) ...EntrySetActions.selection.where((v) => !selectionQuickActions.contains(v)).map((v) => _toMenuItem(v, enabled: hasSelection)),
|
||||
if (isSelecting) ...[
|
||||
...EntrySetActions.selection.where((v) => !selectionQuickActions.contains(v)).map((v) => _toMenuItem(v, enabled: hasSelection)),
|
||||
PopupMenuItem(
|
||||
enabled: hasSelection,
|
||||
padding: EdgeInsets.zero,
|
||||
child: PopupMenuItemExpansionPanel<EntrySetAction>(
|
||||
enabled: hasSelection,
|
||||
icon: AIcons.edit,
|
||||
title: context.l10n.collectionActionEdit,
|
||||
items: [
|
||||
_toMenuItem(EntrySetAction.editDate, enabled: hasSelection),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
if (!isSelecting)
|
||||
...[
|
||||
EntrySetAction.map,
|
||||
|
@ -285,6 +302,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
case EntrySetAction.rescan:
|
||||
case EntrySetAction.map:
|
||||
case EntrySetAction.stats:
|
||||
case EntrySetAction.editDate:
|
||||
_actionDelegate.onActionSelected(context, action);
|
||||
break;
|
||||
case EntrySetAction.select:
|
||||
|
@ -302,16 +320,19 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
case EntrySetAction.group:
|
||||
final value = await showDialog<EntryGroupFactor>(
|
||||
context: context,
|
||||
builder: (context) => AvesSelectionDialog<EntryGroupFactor>(
|
||||
initialValue: settings.collectionSectionFactor,
|
||||
options: {
|
||||
EntryGroupFactor.album: context.l10n.collectionGroupAlbum,
|
||||
EntryGroupFactor.month: context.l10n.collectionGroupMonth,
|
||||
EntryGroupFactor.day: context.l10n.collectionGroupDay,
|
||||
EntryGroupFactor.none: context.l10n.collectionGroupNone,
|
||||
},
|
||||
title: context.l10n.collectionGroupTitle,
|
||||
),
|
||||
builder: (context) {
|
||||
final l10n = context.l10n;
|
||||
return AvesSelectionDialog<EntryGroupFactor>(
|
||||
initialValue: settings.collectionSectionFactor,
|
||||
options: {
|
||||
EntryGroupFactor.album: l10n.collectionGroupAlbum,
|
||||
EntryGroupFactor.month: l10n.collectionGroupMonth,
|
||||
EntryGroupFactor.day: l10n.collectionGroupDay,
|
||||
EntryGroupFactor.none: l10n.collectionGroupNone,
|
||||
},
|
||||
title: l10n.collectionGroupTitle,
|
||||
);
|
||||
},
|
||||
);
|
||||
// wait for the dialog to hide as applying the change may block the UI
|
||||
await Future.delayed(Durations.dialogTransitionAnimation * timeDilation);
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:aves/model/actions/move_type.dart';
|
|||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/album.dart';
|
||||
import 'package:aves/model/highlight.dart';
|
||||
import 'package:aves/model/metadata/date_modifier.dart';
|
||||
import 'package:aves/model/selection.dart';
|
||||
import 'package:aves/model/source/analysis_controller.dart';
|
||||
import 'package:aves/model/source/collection_lens.dart';
|
||||
|
@ -14,6 +15,7 @@ import 'package:aves/services/common/image_op_events.dart';
|
|||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/services/media/enums.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/utils/mime_utils.dart';
|
||||
import 'package:aves/widgets/collection/collection_page.dart';
|
||||
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
||||
import 'package:aves/widgets/common/action_mixins/permission_aware.dart';
|
||||
|
@ -21,6 +23,7 @@ import 'package:aves/widgets/common/action_mixins/size_aware.dart';
|
|||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
||||
import 'package:aves/widgets/dialogs/aves_selection_dialog.dart';
|
||||
import 'package:aves/widgets/dialogs/edit_entry_date_dialog.dart';
|
||||
import 'package:aves/widgets/filter_grids/album_pick.dart';
|
||||
import 'package:aves/widgets/map/map_page.dart';
|
||||
import 'package:aves/widgets/stats/stats_page.dart';
|
||||
|
@ -47,6 +50,9 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
case EntrySetAction.rescan:
|
||||
_rescan(context);
|
||||
break;
|
||||
case EntrySetAction.editDate:
|
||||
_editDate(context);
|
||||
break;
|
||||
case EntrySetAction.map:
|
||||
_goToMap(context);
|
||||
break;
|
||||
|
@ -81,6 +87,59 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
selection.browse();
|
||||
}
|
||||
|
||||
Future<void> _showDeleteDialog(BuildContext context) async {
|
||||
final source = context.read<CollectionSource>();
|
||||
final selection = context.read<Selection<AvesEntry>>();
|
||||
final selectedItems = _getExpandedSelectedItems(selection);
|
||||
final selectionDirs = selectedItems.map((e) => e.directory).whereNotNull().toSet();
|
||||
final todoCount = selectedItems.length;
|
||||
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AvesDialog(
|
||||
context: context,
|
||||
content: Text(context.l10n.deleteEntriesConfirmationDialogMessage(todoCount)),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
child: Text(context.l10n.deleteButtonLabel),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
if (confirmed == null || !confirmed) return;
|
||||
|
||||
if (!await checkStoragePermissionForAlbums(context, selectionDirs, entries: selectedItems)) return;
|
||||
|
||||
source.pauseMonitoring();
|
||||
showOpReport<ImageOpEvent>(
|
||||
context: context,
|
||||
opStream: mediaFileService.delete(selectedItems),
|
||||
itemCount: todoCount,
|
||||
onDone: (processed) async {
|
||||
final deletedUris = processed.where((event) => event.success).map((event) => event.uri).toSet();
|
||||
await source.removeEntries(deletedUris);
|
||||
selection.browse();
|
||||
source.resumeMonitoring();
|
||||
|
||||
final deletedCount = deletedUris.length;
|
||||
if (deletedCount < todoCount) {
|
||||
final count = todoCount - deletedCount;
|
||||
showFeedback(context, context.l10n.collectionDeleteFailureFeedback(count));
|
||||
}
|
||||
|
||||
// cleanup
|
||||
await storageService.deleteEmptyDirectories(selectionDirs);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _moveSelection(BuildContext context, {required MoveType moveType}) async {
|
||||
final l10n = context.l10n;
|
||||
final source = context.read<CollectionSource>();
|
||||
|
@ -213,55 +272,74 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> _showDeleteDialog(BuildContext context) async {
|
||||
Future<void> _editDate(BuildContext context) async {
|
||||
final l10n = context.l10n;
|
||||
final source = context.read<CollectionSource>();
|
||||
final selection = context.read<Selection<AvesEntry>>();
|
||||
final selectedItems = _getExpandedSelectedItems(selection);
|
||||
final selectionDirs = selectedItems.map((e) => e.directory).whereNotNull().toSet();
|
||||
final todoCount = selectedItems.length;
|
||||
|
||||
final confirmed = await showDialog<bool>(
|
||||
final bySupported = groupBy<AvesEntry, bool>(selectedItems, (entry) => entry.canEditExif);
|
||||
final todoEntries = (bySupported[true] ?? []).toSet();
|
||||
final unsupportedItems = (bySupported[false] ?? []);
|
||||
if (unsupportedItems.isNotEmpty) {
|
||||
final unsupportedTypes = unsupportedItems.map((entry) => entry.mimeType).toSet().map(MimeUtils.displayType).toList()..sort();
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AvesDialog(
|
||||
context: context,
|
||||
title: l10n.unsupportedTypeDialogTitle,
|
||||
content: Text(l10n.unsupportedTypeDialogMessage(unsupportedTypes.length, unsupportedTypes.join(', '))),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
|
||||
),
|
||||
if (todoEntries.isNotEmpty)
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
child: Text(l10n.continueButtonLabel),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
if (confirmed == null || !confirmed) return;
|
||||
}
|
||||
|
||||
final selectionDirs = todoEntries.map((e) => e.directory).whereNotNull().toSet();
|
||||
final todoCount = todoEntries.length;
|
||||
|
||||
final modifier = await showDialog<DateModifier>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AvesDialog(
|
||||
context: context,
|
||||
content: Text(context.l10n.deleteEntriesConfirmationDialogMessage(todoCount)),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
child: Text(context.l10n.deleteButtonLabel),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
builder: (context) => EditEntryDateDialog(entry: todoEntries.first),
|
||||
);
|
||||
if (confirmed == null || !confirmed) return;
|
||||
if (modifier == null) return;
|
||||
|
||||
if (!await checkStoragePermissionForAlbums(context, selectionDirs, entries: selectedItems)) return;
|
||||
if (!await checkStoragePermissionForAlbums(context, selectionDirs, entries: todoEntries)) return;
|
||||
|
||||
source.pauseMonitoring();
|
||||
showOpReport<ImageOpEvent>(
|
||||
context: context,
|
||||
opStream: mediaFileService.delete(selectedItems),
|
||||
opStream: Stream.fromIterable(todoEntries).asyncMap((entry) async {
|
||||
final success = await entry.editDate(modifier);
|
||||
return ImageOpEvent(success: success, uri: entry.uri);
|
||||
}).asBroadcastStream(),
|
||||
itemCount: todoCount,
|
||||
onDone: (processed) async {
|
||||
final deletedUris = processed.where((event) => event.success).map((event) => event.uri).toSet();
|
||||
await source.removeEntries(deletedUris);
|
||||
final successOps = processed.where((e) => e.success).toSet();
|
||||
selection.browse();
|
||||
source.resumeMonitoring();
|
||||
unawaited(source.refreshUris(successOps.map((v) => v.uri).toSet()));
|
||||
|
||||
final deletedCount = deletedUris.length;
|
||||
if (deletedCount < todoCount) {
|
||||
final count = todoCount - deletedCount;
|
||||
showFeedback(context, context.l10n.collectionDeleteFailureFeedback(count));
|
||||
final successCount = successOps.length;
|
||||
if (successCount < todoCount) {
|
||||
final count = todoCount - successCount;
|
||||
showFeedback(context, l10n.collectionEditFailureFeedback(count));
|
||||
} else {
|
||||
final count = successCount;
|
||||
showFeedback(context, l10n.collectionEditSuccessFeedback(count));
|
||||
}
|
||||
|
||||
// cleanup
|
||||
await storageService.deleteEmptyDirectories(selectionDirs);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class MenuRow extends StatelessWidget {
|
||||
final String text;
|
||||
|
@ -45,3 +47,75 @@ class MenuIconTheme extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PopupMenuItemExpansionPanel<T> extends StatefulWidget {
|
||||
final bool enabled;
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final List<PopupMenuItem<T>> items;
|
||||
|
||||
const PopupMenuItemExpansionPanel({
|
||||
Key? key,
|
||||
this.enabled = true,
|
||||
required this.icon,
|
||||
required this.title,
|
||||
required this.items,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_PopupMenuItemExpansionPanelState createState() => _PopupMenuItemExpansionPanelState<T>();
|
||||
}
|
||||
|
||||
class _PopupMenuItemExpansionPanelState<T> extends State<PopupMenuItemExpansionPanel<T>> {
|
||||
bool _isExpanded = false;
|
||||
|
||||
// ref `_kMenuHorizontalPadding` used in `PopupMenuItem`
|
||||
static const double _horizontalPadding = 16;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
var style = PopupMenuTheme.of(context).textStyle ?? theme.textTheme.subtitle1!;
|
||||
if (!widget.enabled) {
|
||||
style = style.copyWith(color: theme.disabledColor);
|
||||
}
|
||||
final animationDuration = context.select<DurationsData, Duration>((v) => v.expansionTileAnimation);
|
||||
|
||||
Widget child = ExpansionPanelList(
|
||||
expansionCallback: (index, isExpanded) {
|
||||
setState(() => _isExpanded = !isExpanded);
|
||||
},
|
||||
animationDuration: animationDuration,
|
||||
expandedHeaderPadding: EdgeInsets.zero,
|
||||
elevation: 0,
|
||||
children: [
|
||||
ExpansionPanel(
|
||||
headerBuilder: (context, isExpanded) => DefaultTextStyle(
|
||||
style: style,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: _horizontalPadding),
|
||||
child: MenuRow(
|
||||
text: widget.title,
|
||||
icon: Icon(widget.icon),
|
||||
),
|
||||
),
|
||||
),
|
||||
body: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const PopupMenuDivider(height: 0),
|
||||
...widget.items,
|
||||
const PopupMenuDivider(height: 0),
|
||||
],
|
||||
),
|
||||
isExpanded: _isExpanded,
|
||||
canTapOnHeader: true,
|
||||
),
|
||||
],
|
||||
);
|
||||
if (!widget.enabled) {
|
||||
child = IgnorePointer(child: child);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,11 +106,11 @@ class _EditEntryDateDialogState extends State<EditEntryDateDialog> {
|
|||
),
|
||||
],
|
||||
);
|
||||
final fromTitleTile = RadioListTile<DateEditAction>(
|
||||
value: DateEditAction.fromTitle,
|
||||
final extractFromTitleTile = RadioListTile<DateEditAction>(
|
||||
value: DateEditAction.extractFromTitle,
|
||||
groupValue: _action,
|
||||
onChanged: _updateAction,
|
||||
title: _tileText(l10n.editEntryDateDialogFromTitle),
|
||||
title: _tileText(l10n.editEntryDateDialogExtractFromTitle),
|
||||
);
|
||||
final clearTile = RadioListTile<DateEditAction>(
|
||||
value: DateEditAction.clear,
|
||||
|
@ -134,7 +134,7 @@ class _EditEntryDateDialogState extends State<EditEntryDateDialog> {
|
|||
scrollableContent: [
|
||||
setTile,
|
||||
shiftTile,
|
||||
fromTitleTile,
|
||||
extractFromTitleTile,
|
||||
clearTile,
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 1),
|
||||
|
@ -250,7 +250,7 @@ class _EditEntryDateDialogState extends State<EditEntryDateDialog> {
|
|||
case DateEditAction.shift:
|
||||
modifier = DateModifier(_action, _fields, shiftMinutes: _shiftMinutes);
|
||||
break;
|
||||
case DateEditAction.fromTitle:
|
||||
case DateEditAction.extractFromTitle:
|
||||
case DateEditAction.clear:
|
||||
modifier = DateModifier(_action, _fields);
|
||||
break;
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
{
|
||||
"ko": [
|
||||
"editEntryDateDialogFromTitle"
|
||||
"unsupportedTypeDialogTitle",
|
||||
"unsupportedTypeDialogMessage",
|
||||
"editEntryDateDialogExtractFromTitle",
|
||||
"collectionActionEdit",
|
||||
"collectionEditFailureFeedback",
|
||||
"collectionEditSuccessFeedback"
|
||||
],
|
||||
|
||||
"ru": [
|
||||
"editEntryDateDialogFromTitle",
|
||||
"aboutCreditsTranslators"
|
||||
"unsupportedTypeDialogTitle",
|
||||
"unsupportedTypeDialogMessage",
|
||||
"editEntryDateDialogExtractFromTitle",
|
||||
"aboutCreditsTranslators",
|
||||
"collectionActionEdit",
|
||||
"collectionEditFailureFeedback",
|
||||
"collectionEditSuccessFeedback"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue