#117 info: set date from title
This commit is contained in:
parent
91da9db1c0
commit
805005bb87
7 changed files with 93 additions and 0 deletions
|
@ -360,6 +360,8 @@
|
||||||
"@editEntryDateDialogSet": {},
|
"@editEntryDateDialogSet": {},
|
||||||
"editEntryDateDialogShift": "Shift",
|
"editEntryDateDialogShift": "Shift",
|
||||||
"@editEntryDateDialogShift": {},
|
"@editEntryDateDialogShift": {},
|
||||||
|
"editEntryDateDialogFromTitle": "From title",
|
||||||
|
"@editEntryDateDialogFromTitle": {},
|
||||||
"editEntryDateDialogClear": "Clear",
|
"editEntryDateDialogClear": "Clear",
|
||||||
"@editEntryDateDialogClear": {},
|
"@editEntryDateDialogClear": {},
|
||||||
"editEntryDateDialogFieldSelection": "Field selection",
|
"editEntryDateDialogFieldSelection": "Field selection",
|
||||||
|
|
|
@ -18,6 +18,7 @@ import 'package:aves/services/geocoding_service.dart';
|
||||||
import 'package:aves/services/metadata/svg_metadata_service.dart';
|
import 'package:aves/services/metadata/svg_metadata_service.dart';
|
||||||
import 'package:aves/theme/format.dart';
|
import 'package:aves/theme/format.dart';
|
||||||
import 'package:aves/utils/change_notifier.dart';
|
import 'package:aves/utils/change_notifier.dart';
|
||||||
|
import 'package:aves/utils/time_utils.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:country_code/country_code.dart';
|
import 'package:country_code/country_code.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -635,6 +636,16 @@ class AvesEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> editDate(DateModifier modifier) async {
|
Future<bool> 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);
|
final newFields = await metadataEditService.editDate(this, modifier);
|
||||||
return newFields.isNotEmpty;
|
return newFields.isNotEmpty;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ enum MetadataField {
|
||||||
enum DateEditAction {
|
enum DateEditAction {
|
||||||
set,
|
set,
|
||||||
shift,
|
shift,
|
||||||
|
fromTitle,
|
||||||
clear,
|
clear,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,3 +13,58 @@ extension ExtraDateTime on DateTime {
|
||||||
|
|
||||||
bool get isThisYear => isAtSameYearAs(DateTime.now());
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -106,6 +106,12 @@ class _EditEntryDateDialogState extends State<EditEntryDateDialog> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
final fromTitleTile = RadioListTile<DateEditAction>(
|
||||||
|
value: DateEditAction.fromTitle,
|
||||||
|
groupValue: _action,
|
||||||
|
onChanged: _updateAction,
|
||||||
|
title: _tileText(l10n.editEntryDateDialogFromTitle),
|
||||||
|
);
|
||||||
final clearTile = RadioListTile<DateEditAction>(
|
final clearTile = RadioListTile<DateEditAction>(
|
||||||
value: DateEditAction.clear,
|
value: DateEditAction.clear,
|
||||||
groupValue: _action,
|
groupValue: _action,
|
||||||
|
@ -128,6 +134,7 @@ class _EditEntryDateDialogState extends State<EditEntryDateDialog> {
|
||||||
scrollableContent: [
|
scrollableContent: [
|
||||||
setTile,
|
setTile,
|
||||||
shiftTile,
|
shiftTile,
|
||||||
|
fromTitleTile,
|
||||||
clearTile,
|
clearTile,
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 1),
|
padding: const EdgeInsets.only(bottom: 1),
|
||||||
|
@ -243,6 +250,7 @@ class _EditEntryDateDialogState extends State<EditEntryDateDialog> {
|
||||||
case DateEditAction.shift:
|
case DateEditAction.shift:
|
||||||
modifier = DateModifier(_action, _fields, shiftMinutes: _shiftMinutes);
|
modifier = DateModifier(_action, _fields, shiftMinutes: _shiftMinutes);
|
||||||
break;
|
break;
|
||||||
|
case DateEditAction.fromTitle:
|
||||||
case DateEditAction.clear:
|
case DateEditAction.clear:
|
||||||
modifier = DateModifier(_action, _fields);
|
modifier = DateModifier(_action, _fields);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -15,4 +15,15 @@ void main() {
|
||||||
expect(DateTime(1903, 9, 25).isAtSameDayAs(DateTime(1970, 2, 25)), false);
|
expect(DateTime(1903, 9, 25).isAtSameDayAs(DateTime(1970, 2, 25)), false);
|
||||||
expect(DateTime(1929, 3, 22).isAtSameDayAs(DateTime(1929, 3, 22)), true);
|
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));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
{
|
{
|
||||||
|
"ko": [
|
||||||
|
"editEntryDateDialogFromTitle"
|
||||||
|
],
|
||||||
|
|
||||||
"ru": [
|
"ru": [
|
||||||
|
"editEntryDateDialogFromTitle",
|
||||||
"aboutCreditsTranslators"
|
"aboutCreditsTranslators"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue