From 805005bb874fe7c3f18d40bf7e442172eaf500e6 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Thu, 28 Oct 2021 15:23:31 +0900 Subject: [PATCH] #117 info: set date from title --- lib/l10n/app_en.arb | 2 + lib/model/entry.dart | 11 ++++ lib/model/metadata/enums.dart | 1 + lib/utils/time_utils.dart | 55 +++++++++++++++++++ .../dialogs/edit_entry_date_dialog.dart | 8 +++ test/utils/time_utils_test.dart | 11 ++++ untranslated.json | 5 ++ 7 files changed, 93 insertions(+) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index cfd5adebd..7891609e3 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -360,6 +360,8 @@ "@editEntryDateDialogSet": {}, "editEntryDateDialogShift": "Shift", "@editEntryDateDialogShift": {}, + "editEntryDateDialogFromTitle": "From title", + "@editEntryDateDialogFromTitle": {}, "editEntryDateDialogClear": "Clear", "@editEntryDateDialogClear": {}, "editEntryDateDialogFieldSelection": "Field selection", diff --git a/lib/model/entry.dart b/lib/model/entry.dart index a3bd9f7d3..4117e774b 100644 --- a/lib/model/entry.dart +++ b/lib/model/entry.dart @@ -18,6 +18,7 @@ import 'package:aves/services/geocoding_service.dart'; import 'package:aves/services/metadata/svg_metadata_service.dart'; import 'package:aves/theme/format.dart'; import 'package:aves/utils/change_notifier.dart'; +import 'package:aves/utils/time_utils.dart'; import 'package:collection/collection.dart'; import 'package:country_code/country_code.dart'; import 'package:flutter/foundation.dart'; @@ -635,6 +636,16 @@ class AvesEntry { } Future editDate(DateModifier modifier) async { + if (modifier.action == DateEditAction.fromTitle) { + final _title = bestTitle; + if (_title == null) return false; + final date = parseUnknownDateFormat(_title); + if (date == null) { + await reportService.recordError('failed to parse date from title=$_title', null); + return false; + } + modifier = DateModifier(DateEditAction.set, modifier.fields, dateTime: date); + } final newFields = await metadataEditService.editDate(this, modifier); return newFields.isNotEmpty; } diff --git a/lib/model/metadata/enums.dart b/lib/model/metadata/enums.dart index 97e548d6e..750725b2b 100644 --- a/lib/model/metadata/enums.dart +++ b/lib/model/metadata/enums.dart @@ -8,6 +8,7 @@ enum MetadataField { enum DateEditAction { set, shift, + fromTitle, clear, } diff --git a/lib/utils/time_utils.dart b/lib/utils/time_utils.dart index 505387930..cf36f57c6 100644 --- a/lib/utils/time_utils.dart +++ b/lib/utils/time_utils.dart @@ -13,3 +13,58 @@ extension ExtraDateTime on DateTime { bool get isThisYear => isAtSameYearAs(DateTime.now()); } + +final _unixStampMillisPattern = RegExp(r'\d{13}'); +final _unixStampSecPattern = RegExp(r'\d{10}'); +final _plainPattern = RegExp(r'(\d{8})([_-\s](\d{6})([_-\s](\d{3}))?)?'); + +DateTime? parseUnknownDateFormat(String s) { + var match = _unixStampMillisPattern.firstMatch(s); + if (match != null) { + final stampString = match.group(0); + if (stampString != null) { + final stampMillis = int.tryParse(stampString); + if (stampMillis != null) { + return DateTime.fromMillisecondsSinceEpoch(stampMillis, isUtc: false); + } + } + } + + match = _unixStampSecPattern.firstMatch(s); + if (match != null) { + final stampString = match.group(0); + if (stampString != null) { + final stampMillis = int.tryParse(stampString); + if (stampMillis != null) { + return DateTime.fromMillisecondsSinceEpoch(stampMillis * 1000, isUtc: false); + } + } + } + + match = _plainPattern.firstMatch(s); + if (match != null) { + final dateString = match.group(1); + final timeString = match.group(3); + final millisString = match.group(5); + + if (dateString != null) { + final year = int.tryParse(dateString.substring(0, 4)); + final month = int.tryParse(dateString.substring(4, 6)); + final day = int.tryParse(dateString.substring(6, 8)); + + if (year != null && month != null && day != null) { + var hour = 0, minute = 0, second = 0, millis = 0; + if (timeString != null) { + hour = int.tryParse(timeString.substring(0, 2)) ?? 0; + minute = int.tryParse(timeString.substring(2, 4)) ?? 0; + second = int.tryParse(timeString.substring(4, 6)) ?? 0; + + if (millisString != null) { + millis = int.tryParse(millisString) ?? 0; + } + } + return DateTime(year, month, day, hour, minute, second, millis); + } + } + } +} diff --git a/lib/widgets/dialogs/edit_entry_date_dialog.dart b/lib/widgets/dialogs/edit_entry_date_dialog.dart index 87aa06ff1..0a20d05aa 100644 --- a/lib/widgets/dialogs/edit_entry_date_dialog.dart +++ b/lib/widgets/dialogs/edit_entry_date_dialog.dart @@ -106,6 +106,12 @@ class _EditEntryDateDialogState extends State { ), ], ); + final fromTitleTile = RadioListTile( + value: DateEditAction.fromTitle, + groupValue: _action, + onChanged: _updateAction, + title: _tileText(l10n.editEntryDateDialogFromTitle), + ); final clearTile = RadioListTile( value: DateEditAction.clear, groupValue: _action, @@ -128,6 +134,7 @@ class _EditEntryDateDialogState extends State { scrollableContent: [ setTile, shiftTile, + fromTitleTile, clearTile, Padding( padding: const EdgeInsets.only(bottom: 1), @@ -243,6 +250,7 @@ class _EditEntryDateDialogState extends State { case DateEditAction.shift: modifier = DateModifier(_action, _fields, shiftMinutes: _shiftMinutes); break; + case DateEditAction.fromTitle: case DateEditAction.clear: modifier = DateModifier(_action, _fields); break; diff --git a/test/utils/time_utils_test.dart b/test/utils/time_utils_test.dart index bf911d522..62c822018 100644 --- a/test/utils/time_utils_test.dart +++ b/test/utils/time_utils_test.dart @@ -15,4 +15,15 @@ void main() { expect(DateTime(1903, 9, 25).isAtSameDayAs(DateTime(1970, 2, 25)), false); expect(DateTime(1929, 3, 22).isAtSameDayAs(DateTime(1929, 3, 22)), true); }); + + test('Parse dates', () { + expect(parseUnknownDateFormat('1600995564713'), DateTime(2020, 09, 25, 09, 59, 24, 713)); + expect(parseUnknownDateFormat('pre1600995564713suf'), DateTime(2020, 09, 25, 09, 59, 24, 713)); + + expect(parseUnknownDateFormat('1600995564'), DateTime(2020, 09, 25, 09, 59, 24, 0)); + expect(parseUnknownDateFormat('pre1600995564suf'), DateTime(2020, 09, 25, 09, 59, 24, 0)); + + expect(parseUnknownDateFormat('IMG_20210901_142523_783'), DateTime(2021, 09, 1, 14, 25, 23, 783)); + expect(parseUnknownDateFormat('Screenshot_20211028-115056_Aves'), DateTime(2021, 10, 28, 11, 50, 56, 0)); + }); } diff --git a/untranslated.json b/untranslated.json index 3d5126e85..3ca3faa57 100644 --- a/untranslated.json +++ b/untranslated.json @@ -1,5 +1,10 @@ { + "ko": [ + "editEntryDateDialogFromTitle" + ], + "ru": [ + "editEntryDateDialogFromTitle", "aboutCreditsTranslators" ] }