refactor
This commit is contained in:
parent
b5aaad4df8
commit
0584e8ffa7
175 changed files with 1142 additions and 1051 deletions
3
lib/convert/convert.dart
Normal file
3
lib/convert/convert.dart
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export 'metadata/date_field_source.dart';
|
||||||
|
export 'metadata/fields.dart';
|
||||||
|
export 'metadata/metadata_type.dart';
|
18
lib/convert/metadata/date_field_source.dart
Normal file
18
lib/convert/metadata/date_field_source.dart
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
|
||||||
|
extension ExtraDateFieldSourceConvert on DateFieldSource {
|
||||||
|
MetadataField? toMetadataField() {
|
||||||
|
switch (this) {
|
||||||
|
case DateFieldSource.fileModifiedDate:
|
||||||
|
return null;
|
||||||
|
case DateFieldSource.exifDate:
|
||||||
|
return MetadataField.exifDate;
|
||||||
|
case DateFieldSource.exifDateOriginal:
|
||||||
|
return MetadataField.exifDateOriginal;
|
||||||
|
case DateFieldSource.exifDateDigitized:
|
||||||
|
return MetadataField.exifDateDigitized;
|
||||||
|
case DateFieldSource.exifGpsDate:
|
||||||
|
return MetadataField.exifGpsDatestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,87 +1,6 @@
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
|
||||||
enum MetadataField {
|
extension ExtraMetadataFieldConvert on MetadataField {
|
||||||
exifDate,
|
|
||||||
exifDateOriginal,
|
|
||||||
exifDateDigitized,
|
|
||||||
exifGpsAltitude,
|
|
||||||
exifGpsAltitudeRef,
|
|
||||||
exifGpsAreaInformation,
|
|
||||||
exifGpsDatestamp,
|
|
||||||
exifGpsDestBearing,
|
|
||||||
exifGpsDestBearingRef,
|
|
||||||
exifGpsDestDistance,
|
|
||||||
exifGpsDestDistanceRef,
|
|
||||||
exifGpsDestLatitude,
|
|
||||||
exifGpsDestLatitudeRef,
|
|
||||||
exifGpsDestLongitude,
|
|
||||||
exifGpsDestLongitudeRef,
|
|
||||||
exifGpsDifferential,
|
|
||||||
exifGpsDOP,
|
|
||||||
exifGpsHPositioningError,
|
|
||||||
exifGpsImgDirection,
|
|
||||||
exifGpsImgDirectionRef,
|
|
||||||
exifGpsLatitude,
|
|
||||||
exifGpsLatitudeRef,
|
|
||||||
exifGpsLongitude,
|
|
||||||
exifGpsLongitudeRef,
|
|
||||||
exifGpsMapDatum,
|
|
||||||
exifGpsMeasureMode,
|
|
||||||
exifGpsProcessingMethod,
|
|
||||||
exifGpsSatellites,
|
|
||||||
exifGpsSpeed,
|
|
||||||
exifGpsSpeedRef,
|
|
||||||
exifGpsStatus,
|
|
||||||
exifGpsTimestamp,
|
|
||||||
exifGpsTrack,
|
|
||||||
exifGpsTrackRef,
|
|
||||||
exifGpsVersionId,
|
|
||||||
exifImageDescription,
|
|
||||||
exifUserComment,
|
|
||||||
mp4GpsCoordinates,
|
|
||||||
mp4RotationDegrees,
|
|
||||||
mp4Xmp,
|
|
||||||
xmpXmpCreateDate,
|
|
||||||
}
|
|
||||||
|
|
||||||
class MetadataFields {
|
|
||||||
static const Set<MetadataField> exifGpsFields = {
|
|
||||||
MetadataField.exifGpsAltitude,
|
|
||||||
MetadataField.exifGpsAltitudeRef,
|
|
||||||
MetadataField.exifGpsAreaInformation,
|
|
||||||
MetadataField.exifGpsDatestamp,
|
|
||||||
MetadataField.exifGpsDestBearing,
|
|
||||||
MetadataField.exifGpsDestBearingRef,
|
|
||||||
MetadataField.exifGpsDestDistance,
|
|
||||||
MetadataField.exifGpsDestDistanceRef,
|
|
||||||
MetadataField.exifGpsDestLatitude,
|
|
||||||
MetadataField.exifGpsDestLatitudeRef,
|
|
||||||
MetadataField.exifGpsDestLongitude,
|
|
||||||
MetadataField.exifGpsDestLongitudeRef,
|
|
||||||
MetadataField.exifGpsDifferential,
|
|
||||||
MetadataField.exifGpsDOP,
|
|
||||||
MetadataField.exifGpsHPositioningError,
|
|
||||||
MetadataField.exifGpsImgDirection,
|
|
||||||
MetadataField.exifGpsImgDirectionRef,
|
|
||||||
MetadataField.exifGpsLatitude,
|
|
||||||
MetadataField.exifGpsLatitudeRef,
|
|
||||||
MetadataField.exifGpsLongitude,
|
|
||||||
MetadataField.exifGpsLongitudeRef,
|
|
||||||
MetadataField.exifGpsMapDatum,
|
|
||||||
MetadataField.exifGpsMeasureMode,
|
|
||||||
MetadataField.exifGpsProcessingMethod,
|
|
||||||
MetadataField.exifGpsSatellites,
|
|
||||||
MetadataField.exifGpsSpeed,
|
|
||||||
MetadataField.exifGpsSpeedRef,
|
|
||||||
MetadataField.exifGpsStatus,
|
|
||||||
MetadataField.exifGpsTimestamp,
|
|
||||||
MetadataField.exifGpsTrack,
|
|
||||||
MetadataField.exifGpsTrackRef,
|
|
||||||
MetadataField.exifGpsVersionId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ExtraMetadataField on MetadataField {
|
|
||||||
MetadataType get type {
|
MetadataType get type {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case MetadataField.exifDate:
|
case MetadataField.exifDate:
|
||||||
|
@ -228,21 +147,4 @@ extension ExtraMetadataField on MetadataField {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String get title {
|
|
||||||
switch (this) {
|
|
||||||
case MetadataField.exifDate:
|
|
||||||
return 'Exif date';
|
|
||||||
case MetadataField.exifDateOriginal:
|
|
||||||
return 'Exif original date';
|
|
||||||
case MetadataField.exifDateDigitized:
|
|
||||||
return 'Exif digitized date';
|
|
||||||
case MetadataField.exifGpsDatestamp:
|
|
||||||
return 'Exif GPS date';
|
|
||||||
case MetadataField.xmpXmpCreateDate:
|
|
||||||
return 'XMP xmp:CreateDate';
|
|
||||||
default:
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
28
lib/convert/metadata/metadata_type.dart
Normal file
28
lib/convert/metadata/metadata_type.dart
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
|
||||||
|
extension ExtraMetadataTypeConvert on MetadataType {
|
||||||
|
String get toPlatform {
|
||||||
|
switch (this) {
|
||||||
|
case MetadataType.comment:
|
||||||
|
return 'comment';
|
||||||
|
case MetadataType.exif:
|
||||||
|
return 'exif';
|
||||||
|
case MetadataType.iccProfile:
|
||||||
|
return 'icc_profile';
|
||||||
|
case MetadataType.iptc:
|
||||||
|
return 'iptc';
|
||||||
|
case MetadataType.jfif:
|
||||||
|
return 'jfif';
|
||||||
|
case MetadataType.jpegAdobe:
|
||||||
|
return 'jpeg_adobe';
|
||||||
|
case MetadataType.jpegDucky:
|
||||||
|
return 'jpeg_ducky';
|
||||||
|
case MetadataType.mp4:
|
||||||
|
return 'mp4';
|
||||||
|
case MetadataType.photoshopIrb:
|
||||||
|
return 'photoshop_irb';
|
||||||
|
case MetadataType.xmp:
|
||||||
|
return 'xmp';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,10 +5,10 @@ import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/filters/album.dart';
|
import 'package:aves/model/filters/album.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/vaults/vaults.dart';
|
import 'package:aves/model/vaults/vaults.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:aves/model/storage/relative_dir.dart';
|
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
final entryDirRepo = EntryDirRepo._private();
|
final entryDirRepo = EntryDirRepo._private();
|
||||||
|
@ -52,7 +52,7 @@ class EntryDir {
|
||||||
}
|
}
|
||||||
|
|
||||||
String? _resolve() {
|
String? _resolve() {
|
||||||
final vrl = VolumeRelativeDirectory.fromPath(asIs!);
|
final vrl = androidFileUtils.relativeDirectoryFromPath(asIs!);
|
||||||
if (vrl == null || vrl.relativeDir.isEmpty) return asIs;
|
if (vrl == null || vrl.relativeDir.isEmpty) return asIs;
|
||||||
|
|
||||||
var resolved = vrl.volumePath;
|
var resolved = vrl.volumePath;
|
||||||
|
|
|
@ -7,7 +7,7 @@ import 'package:aves/model/entry/cache.dart';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/utils/math_utils.dart';
|
import 'package:aves/utils/math_utils.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/painting.dart';
|
||||||
|
|
||||||
extension ExtraAvesEntryImages on AvesEntry {
|
extension ExtraAvesEntryImages on AvesEntry {
|
||||||
bool isThumbnailReady({double extent = 0}) => _isReady(_getThumbnailProviderKey(extent));
|
bool isThumbnailReady({double extent = 0}) => _isReady(_getThumbnailProviderKey(extent));
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:aves/convert/convert.dart';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/catalog.dart';
|
import 'package:aves/model/entry/extensions/catalog.dart';
|
||||||
import 'package:aves/model/entry/extensions/props.dart';
|
import 'package:aves/model/entry/extensions/props.dart';
|
||||||
import 'package:aves/model/metadata/date_modifier.dart';
|
import 'package:aves/model/metadata/date_modifier.dart';
|
||||||
import 'package:aves/model/metadata/enums/date_field_source.dart';
|
import 'package:aves/ref/metadata/exif.dart';
|
||||||
import 'package:aves/model/metadata/fields.dart';
|
import 'package:aves/ref/metadata/iptc.dart';
|
||||||
import 'package:aves/ref/exif.dart';
|
|
||||||
import 'package:aves/ref/iptc.dart';
|
|
||||||
import 'package:aves/ref/mime_types.dart';
|
import 'package:aves/ref/mime_types.dart';
|
||||||
|
import 'package:aves/ref/metadata/xmp.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/services/metadata/xmp.dart';
|
import 'package:aves/services/metadata/xmp.dart';
|
||||||
import 'package:aves/utils/time_utils.dart';
|
import 'package:aves/utils/time_utils.dart';
|
||||||
|
@ -54,7 +54,7 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
|
||||||
editCreateDateXmp(descriptions, appliedModifier.setDateTime);
|
editCreateDateXmp(descriptions, appliedModifier.setDateTime);
|
||||||
break;
|
break;
|
||||||
case DateEditAction.shift:
|
case DateEditAction.shift:
|
||||||
final xmpDate = XMP.getString(descriptions, XMP.xmpCreateDate, namespace: Namespaces.xmp);
|
final xmpDate = XMP.getString(descriptions, XmpAttributes.xmpCreateDate, namespace: XmpNamespaces.xmp);
|
||||||
if (xmpDate != null) {
|
if (xmpDate != null) {
|
||||||
final date = DateTime.tryParse(xmpDate);
|
final date = DateTime.tryParse(xmpDate);
|
||||||
if (date != null) {
|
if (date != null) {
|
||||||
|
@ -262,18 +262,18 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
|
||||||
if (editTitle) {
|
if (editTitle) {
|
||||||
modified |= XMP.setAttribute(
|
modified |= XMP.setAttribute(
|
||||||
descriptions,
|
descriptions,
|
||||||
XMP.dcTitle,
|
XmpElements.dcTitle,
|
||||||
title,
|
title,
|
||||||
namespace: Namespaces.dc,
|
namespace: XmpNamespaces.dc,
|
||||||
strat: XmpEditStrategy.always,
|
strat: XmpEditStrategy.always,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (editDescription) {
|
if (editDescription) {
|
||||||
modified |= XMP.setAttribute(
|
modified |= XMP.setAttribute(
|
||||||
descriptions,
|
descriptions,
|
||||||
XMP.dcDescription,
|
XmpElements.dcDescription,
|
||||||
description,
|
description,
|
||||||
namespace: Namespaces.dc,
|
namespace: XmpNamespaces.dc,
|
||||||
strat: XmpEditStrategy.always,
|
strat: XmpEditStrategy.always,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -417,9 +417,9 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
|
||||||
static bool editCreateDateXmp(List<XmlNode> descriptions, DateTime? date) {
|
static bool editCreateDateXmp(List<XmlNode> descriptions, DateTime? date) {
|
||||||
return XMP.setAttribute(
|
return XMP.setAttribute(
|
||||||
descriptions,
|
descriptions,
|
||||||
XMP.xmpCreateDate,
|
XmpAttributes.xmpCreateDate,
|
||||||
date != null ? XMP.toXmpDate(date) : null,
|
date != null ? XMP.toXmpDate(date) : null,
|
||||||
namespace: Namespaces.xmp,
|
namespace: XmpNamespaces.xmp,
|
||||||
strat: XmpEditStrategy.always,
|
strat: XmpEditStrategy.always,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -428,9 +428,9 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
|
||||||
static bool editTagsXmp(List<XmlNode> descriptions, Set<String> tags) {
|
static bool editTagsXmp(List<XmlNode> descriptions, Set<String> tags) {
|
||||||
return XMP.setStringBag(
|
return XMP.setStringBag(
|
||||||
descriptions,
|
descriptions,
|
||||||
XMP.dcSubject,
|
XmpElements.dcSubject,
|
||||||
tags,
|
tags,
|
||||||
namespace: Namespaces.dc,
|
namespace: XmpNamespaces.dc,
|
||||||
strat: XmpEditStrategy.always,
|
strat: XmpEditStrategy.always,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -441,17 +441,17 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
|
||||||
|
|
||||||
modified |= XMP.setAttribute(
|
modified |= XMP.setAttribute(
|
||||||
descriptions,
|
descriptions,
|
||||||
XMP.xmpRating,
|
XmpElements.xmpRating,
|
||||||
(rating ?? 0) == 0 ? null : '$rating',
|
(rating ?? 0) == 0 ? null : '$rating',
|
||||||
namespace: Namespaces.xmp,
|
namespace: XmpNamespaces.xmp,
|
||||||
strat: XmpEditStrategy.always,
|
strat: XmpEditStrategy.always,
|
||||||
);
|
);
|
||||||
|
|
||||||
modified |= XMP.setAttribute(
|
modified |= XMP.setAttribute(
|
||||||
descriptions,
|
descriptions,
|
||||||
XMP.msPhotoRating,
|
XmpElements.msPhotoRating,
|
||||||
XMP.toMsPhotoRating(rating),
|
XMP.toMsPhotoRating(rating),
|
||||||
namespace: Namespaces.microsoftPhoto,
|
namespace: XmpNamespaces.microsoftPhoto,
|
||||||
strat: XmpEditStrategy.updateIfPresent,
|
strat: XmpEditStrategy.updateIfPresent,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -464,23 +464,23 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
|
||||||
|
|
||||||
modified |= XMP.removeElements(
|
modified |= XMP.removeElements(
|
||||||
descriptions,
|
descriptions,
|
||||||
XMP.containerDirectory,
|
XmpElements.containerDirectory,
|
||||||
Namespaces.gContainer,
|
XmpNamespaces.gContainer,
|
||||||
);
|
);
|
||||||
|
|
||||||
modified |= [
|
modified |= [
|
||||||
XMP.gCameraMicroVideo,
|
XmpAttributes.gCameraMicroVideo,
|
||||||
XMP.gCameraMicroVideoVersion,
|
XmpAttributes.gCameraMicroVideoVersion,
|
||||||
XMP.gCameraMicroVideoOffset,
|
XmpAttributes.gCameraMicroVideoOffset,
|
||||||
XMP.gCameraMicroVideoPresentationTimestampUs,
|
XmpAttributes.gCameraMicroVideoPresentationTimestampUs,
|
||||||
XMP.gCameraMotionPhoto,
|
XmpAttributes.gCameraMotionPhoto,
|
||||||
XMP.gCameraMotionPhotoVersion,
|
XmpAttributes.gCameraMotionPhotoVersion,
|
||||||
XMP.gCameraMotionPhotoPresentationTimestampUs,
|
XmpAttributes.gCameraMotionPhotoPresentationTimestampUs,
|
||||||
].fold<bool>(modified, (prev, name) {
|
].fold<bool>(modified, (prev, name) {
|
||||||
return prev |= XMP.removeElements(
|
return prev |= XMP.removeElements(
|
||||||
descriptions,
|
descriptions,
|
||||||
name,
|
name,
|
||||||
Namespaces.gCamera,
|
XmpNamespaces.gCamera,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/model/storage/volume.dart';
|
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
final Favourites favourites = Favourites._private();
|
final Favourites favourites = Favourites._private();
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import 'package:aves/model/covers.dart';
|
import 'package:aves/model/covers.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/identity/aves_icons.dart';
|
import 'package:aves/widgets/common/identity/aves_icons.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/images.dart';
|
import 'package:aves/model/entry/extensions/images.dart';
|
||||||
import 'package:aves/ref/geotiff.dart';
|
import 'package:aves/ref/metadata/geotiff.dart';
|
||||||
import 'package:aves/utils/math_utils.dart';
|
import 'package:aves/utils/math_utils.dart';
|
||||||
import 'package:aves_map/aves_map.dart';
|
import 'package:aves_map/aves_map.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:event_bus/event_bus.dart';
|
import 'package:event_bus/event_bus.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/painting.dart';
|
||||||
|
|
||||||
class HighlightInfo extends ChangeNotifier {
|
class HighlightInfo extends ChangeNotifier {
|
||||||
final EventBus eventBus = EventBus();
|
final EventBus eventBus = EventBus();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:aves/geo/states.dart';
|
import 'package:aves/geo/states.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class AddressDetails extends Equatable {
|
class AddressDetails extends Equatable {
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import 'package:aves/model/metadata/fields.dart';
|
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class DateModifier extends Equatable {
|
class DateModifier extends Equatable {
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
import 'package:aves_model/aves_model.dart';
|
|
||||||
|
|
||||||
class MetadataTypes {
|
|
||||||
static const main = {
|
|
||||||
MetadataType.exif,
|
|
||||||
MetadataType.xmp,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const common = {
|
|
||||||
MetadataType.exif,
|
|
||||||
MetadataType.xmp,
|
|
||||||
MetadataType.comment,
|
|
||||||
MetadataType.iccProfile,
|
|
||||||
MetadataType.iptc,
|
|
||||||
MetadataType.photoshopIrb,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const jpeg = {
|
|
||||||
MetadataType.jfif,
|
|
||||||
MetadataType.jpegAdobe,
|
|
||||||
MetadataType.jpegDucky,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ExtraMetadataType on MetadataType {
|
|
||||||
// match `metadata-extractor` directory names
|
|
||||||
String getText() {
|
|
||||||
switch (this) {
|
|
||||||
case MetadataType.comment:
|
|
||||||
return 'Comment';
|
|
||||||
case MetadataType.exif:
|
|
||||||
return 'Exif';
|
|
||||||
case MetadataType.iccProfile:
|
|
||||||
return 'ICC Profile';
|
|
||||||
case MetadataType.iptc:
|
|
||||||
return 'IPTC';
|
|
||||||
case MetadataType.jfif:
|
|
||||||
return 'JFIF';
|
|
||||||
case MetadataType.jpegAdobe:
|
|
||||||
return 'Adobe JPEG';
|
|
||||||
case MetadataType.jpegDucky:
|
|
||||||
return 'Ducky';
|
|
||||||
case MetadataType.mp4:
|
|
||||||
return 'MP4';
|
|
||||||
case MetadataType.photoshopIrb:
|
|
||||||
return 'Photoshop';
|
|
||||||
case MetadataType.xmp:
|
|
||||||
return 'XMP';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String get toPlatform {
|
|
||||||
switch (this) {
|
|
||||||
case MetadataType.comment:
|
|
||||||
return 'comment';
|
|
||||||
case MetadataType.exif:
|
|
||||||
return 'exif';
|
|
||||||
case MetadataType.iccProfile:
|
|
||||||
return 'icc_profile';
|
|
||||||
case MetadataType.iptc:
|
|
||||||
return 'iptc';
|
|
||||||
case MetadataType.jfif:
|
|
||||||
return 'jfif';
|
|
||||||
case MetadataType.jpegAdobe:
|
|
||||||
return 'jpeg_adobe';
|
|
||||||
case MetadataType.jpegDucky:
|
|
||||||
return 'jpeg_ducky';
|
|
||||||
case MetadataType.mp4:
|
|
||||||
return 'mp4';
|
|
||||||
case MetadataType.photoshopIrb:
|
|
||||||
return 'photoshop_irb';
|
|
||||||
case MetadataType.xmp:
|
|
||||||
return 'xmp';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,7 +2,6 @@ import 'dart:ui';
|
||||||
|
|
||||||
import 'package:aves/model/filters/recent.dart';
|
import 'package:aves/model/filters/recent.dart';
|
||||||
import 'package:aves/model/naming_pattern.dart';
|
import 'package:aves/model/naming_pattern.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/ref/mime_types.dart';
|
import 'package:aves/ref/mime_types.dart';
|
||||||
import 'package:aves/utils/colors.dart';
|
import 'package:aves/utils/colors.dart';
|
||||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/painting.dart';
|
||||||
|
|
||||||
extension ExtraSubtitlePosition on SubtitlePosition {
|
extension ExtraSubtitlePosition on SubtitlePosition {
|
||||||
TextAlignVertical toTextAlignVertical() {
|
TextAlignVertical toTextAlignVertical() {
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
import 'package:aves/theme/icons.dart';
|
|
||||||
import 'package:aves_model/aves_model.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
extension ExtraThumbnailOverlayLocationIcon on ThumbnailOverlayLocationIcon {
|
|
||||||
IconData getIcon(BuildContext context) {
|
|
||||||
switch (this) {
|
|
||||||
case ThumbnailOverlayLocationIcon.unlocated:
|
|
||||||
return AIcons.locationUnlocated;
|
|
||||||
case ThumbnailOverlayLocationIcon.located:
|
|
||||||
case ThumbnailOverlayLocationIcon.none:
|
|
||||||
return AIcons.location;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
import 'package:aves/theme/icons.dart';
|
|
||||||
import 'package:aves_model/aves_model.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
extension ExtraThumbnailOverlayTagIcon on ThumbnailOverlayTagIcon {
|
|
||||||
IconData getIcon(BuildContext context) {
|
|
||||||
switch (this) {
|
|
||||||
case ThumbnailOverlayTagIcon.tagged:
|
|
||||||
return AIcons.tag;
|
|
||||||
case ThumbnailOverlayTagIcon.untagged:
|
|
||||||
return AIcons.tagUntagged;
|
|
||||||
case ThumbnailOverlayTagIcon.none:
|
|
||||||
return AIcons.tag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/painting.dart';
|
||||||
|
|
||||||
extension ExtraWidgetShape on WidgetShape {
|
extension ExtraWidgetShape on WidgetShape {
|
||||||
Path path(Size widgetSize, double devicePixelRatio) {
|
Path path(Size widgetSize, double devicePixelRatio) {
|
||||||
|
|
|
@ -9,7 +9,6 @@ import 'package:aves/model/filters/filters.dart';
|
||||||
import 'package:aves/model/filters/mime.dart';
|
import 'package:aves/model/filters/mime.dart';
|
||||||
import 'package:aves/model/settings/defaults.dart';
|
import 'package:aves/model/settings/defaults.dart';
|
||||||
import 'package:aves/model/settings/enums/map_style.dart';
|
import 'package:aves/model/settings/enums/map_style.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/ref/bursts.dart';
|
import 'package:aves/ref/bursts.dart';
|
||||||
import 'package:aves/services/accessibility_service.dart';
|
import 'package:aves/services/accessibility_service.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
|
|
|
@ -2,13 +2,12 @@ import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/filters/album.dart';
|
import 'package:aves/model/filters/album.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/storage/relative_dir.dart';
|
|
||||||
import 'package:aves/model/vaults/vaults.dart';
|
import 'package:aves/model/vaults/vaults.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
import 'package:aves/utils/collection_utils.dart';
|
import 'package:aves/utils/collection_utils.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/view/view.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
@ -175,27 +174,13 @@ mixin AlbumMixin on SourceBase {
|
||||||
|
|
||||||
final type = androidFileUtils.getAlbumType(dirPath);
|
final type = androidFileUtils.getAlbumType(dirPath);
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
switch (type) {
|
final name = type.getName(context);
|
||||||
case AlbumType.camera:
|
if (name != null) return name;
|
||||||
return context.l10n.albumCamera;
|
|
||||||
case AlbumType.download:
|
|
||||||
return context.l10n.albumDownload;
|
|
||||||
case AlbumType.screenshots:
|
|
||||||
return context.l10n.albumScreenshots;
|
|
||||||
case AlbumType.screenRecordings:
|
|
||||||
return context.l10n.albumScreenRecordings;
|
|
||||||
case AlbumType.videoCaptures:
|
|
||||||
return context.l10n.albumVideoCaptures;
|
|
||||||
case AlbumType.regular:
|
|
||||||
case AlbumType.vault:
|
|
||||||
case AlbumType.app:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == AlbumType.vault) return pContext.basename(dirPath);
|
if (type == AlbumType.vault) return pContext.basename(dirPath);
|
||||||
|
|
||||||
final dir = VolumeRelativeDirectory.fromPath(dirPath);
|
final dir = androidFileUtils.relativeDirectoryFromPath(dirPath);
|
||||||
if (dir == null) return dirPath;
|
if (dir == null) return dirPath;
|
||||||
|
|
||||||
final relativeDir = dir.relativeDir;
|
final relativeDir = dir.relativeDir;
|
||||||
|
|
|
@ -14,7 +14,6 @@ import 'package:aves/model/filters/rating.dart';
|
||||||
import 'package:aves/model/filters/trash.dart';
|
import 'package:aves/model/filters/trash.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/source/events.dart';
|
import 'package:aves/model/source/events.dart';
|
||||||
import 'package:aves/model/source/location/location.dart';
|
import 'package:aves/model/source/location/location.dart';
|
||||||
import 'package:aves/model/source/section_keys.dart';
|
import 'package:aves/model/source/section_keys.dart';
|
||||||
|
|
|
@ -15,7 +15,6 @@ import 'package:aves/model/metadata/trash.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/album.dart';
|
import 'package:aves/model/source/album.dart';
|
||||||
import 'package:aves/model/source/analysis_controller.dart';
|
import 'package:aves/model/source/analysis_controller.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/source/events.dart';
|
import 'package:aves/model/source/events.dart';
|
||||||
import 'package:aves/model/source/location/country.dart';
|
import 'package:aves/model/source/location/country.dart';
|
||||||
import 'package:aves/model/source/location/location.dart';
|
import 'package:aves/model/source/location/location.dart';
|
||||||
|
|
|
@ -7,11 +7,11 @@ import 'package:aves/model/filters/location.dart';
|
||||||
import 'package:aves/model/metadata/address.dart';
|
import 'package:aves/model/metadata/address.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/analysis_controller.dart';
|
import 'package:aves/model/source/analysis_controller.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/source/location/country.dart';
|
import 'package:aves/model/source/location/country.dart';
|
||||||
import 'package:aves/model/source/location/place.dart';
|
import 'package:aves/model/source/location/place.dart';
|
||||||
import 'package:aves/model/source/location/state.dart';
|
import 'package:aves/model/source/location/state.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
|
@ -8,10 +8,10 @@ import 'package:aves/model/favourites.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/analysis_controller.dart';
|
import 'package:aves/model/source/analysis_controller.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/vaults/vaults.dart';
|
import 'package:aves/model/vaults/vaults.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@ import 'package:aves/model/filters/tag.dart';
|
||||||
import 'package:aves/model/metadata/catalog.dart';
|
import 'package:aves/model/metadata/catalog.dart';
|
||||||
import 'package:aves/model/source/analysis_controller.dart';
|
import 'package:aves/model/source/analysis_controller.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/utils/collection_utils.dart';
|
import 'package:aves/utils/collection_utils.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
import 'package:equatable/equatable.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
@immutable
|
|
||||||
class VolumeRelativeDirectory extends Equatable {
|
|
||||||
final String volumePath, relativeDir;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [volumePath, relativeDir];
|
|
||||||
|
|
||||||
String get dirPath => '$volumePath$relativeDir';
|
|
||||||
|
|
||||||
const VolumeRelativeDirectory({
|
|
||||||
required this.volumePath,
|
|
||||||
required this.relativeDir,
|
|
||||||
});
|
|
||||||
|
|
||||||
static VolumeRelativeDirectory fromMap(Map map) {
|
|
||||||
return VolumeRelativeDirectory(
|
|
||||||
volumePath: map['volumePath'] ?? '',
|
|
||||||
relativeDir: map['relativeDir'] ?? '',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> toMap() => {
|
|
||||||
'volumePath': volumePath,
|
|
||||||
'relativeDir': relativeDir,
|
|
||||||
};
|
|
||||||
|
|
||||||
// prefer static method over a null returning factory constructor
|
|
||||||
static VolumeRelativeDirectory? fromPath(String dirPath) {
|
|
||||||
final volume = androidFileUtils.getStorageVolume(dirPath);
|
|
||||||
if (volume == null) return null;
|
|
||||||
|
|
||||||
final root = volume.path;
|
|
||||||
final rootLength = root.length;
|
|
||||||
return VolumeRelativeDirectory(
|
|
||||||
volumePath: root,
|
|
||||||
relativeDir: dirPath.length < rootLength ? '' : dirPath.substring(rootLength),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
String getVolumeDescription(BuildContext context) {
|
|
||||||
final volume = androidFileUtils.storageVolumes.firstWhereOrNull((volume) => volume.path == volumePath);
|
|
||||||
return volume?.getDescription(context) ?? volumePath;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
|
||||||
import 'package:equatable/equatable.dart';
|
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
@immutable
|
|
||||||
class StorageVolume extends Equatable {
|
|
||||||
final String? _description;
|
|
||||||
final String path, state;
|
|
||||||
final bool isPrimary, isRemovable;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [_description, path, state, isPrimary, isRemovable];
|
|
||||||
|
|
||||||
const StorageVolume({
|
|
||||||
required String? description,
|
|
||||||
required this.isPrimary,
|
|
||||||
required this.isRemovable,
|
|
||||||
required this.path,
|
|
||||||
required this.state,
|
|
||||||
}) : _description = description;
|
|
||||||
|
|
||||||
String getDescription(BuildContext? context) {
|
|
||||||
if (_description != null) return _description!;
|
|
||||||
// ideally, the context should always be provided, but in some cases (e.g. album comparison),
|
|
||||||
// this would require numerous additional methods to have the context as argument
|
|
||||||
// for such a minor benefit: fallback volume description on Android < N
|
|
||||||
if (isPrimary) return context?.l10n.storageVolumeDescriptionFallbackPrimary ?? 'Internal Storage';
|
|
||||||
return context?.l10n.storageVolumeDescriptionFallbackNonPrimary ?? 'SD card';
|
|
||||||
}
|
|
||||||
|
|
||||||
factory StorageVolume.fromMap(Map map) {
|
|
||||||
final isPrimary = map['isPrimary'] ?? false;
|
|
||||||
return StorageVolume(
|
|
||||||
description: map['description'],
|
|
||||||
isPrimary: isPrimary,
|
|
||||||
isRemovable: map['isRemovable'] ?? false,
|
|
||||||
path: map['path'] ?? '',
|
|
||||||
state: map['state'] ?? '',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:aves/model/vaults/enums.dart';
|
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
import 'package:aves/utils/collection_utils.dart';
|
import 'package:aves/utils/collection_utils.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,9 @@ import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:aves/model/vaults/details.dart';
|
import 'package:aves/model/vaults/details.dart';
|
||||||
import 'package:aves/model/vaults/enums.dart';
|
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
|
||||||
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
|
||||||
import 'package:aves/widgets/dialogs/filter_editors/password_dialog.dart';
|
|
||||||
import 'package:aves/widgets/dialogs/filter_editors/pattern_dialog.dart';
|
|
||||||
import 'package:aves/widgets/dialogs/filter_editors/pin_dialog.dart';
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:local_auth/error_codes.dart' as auth_error;
|
|
||||||
import 'package:local_auth/local_auth.dart';
|
|
||||||
import 'package:screen_state/screen_state.dart';
|
import 'package:screen_state/screen_state.dart';
|
||||||
|
|
||||||
final Vaults vaults = Vaults._private();
|
final Vaults vaults = Vaults._private();
|
||||||
|
@ -44,7 +35,7 @@ class Vaults extends ChangeNotifier {
|
||||||
|
|
||||||
Set<VaultDetails> get all => Set.unmodifiable(_rows);
|
Set<VaultDetails> get all => Set.unmodifiable(_rows);
|
||||||
|
|
||||||
VaultDetails? _detailsForPath(String dirPath) => _rows.firstWhereOrNull((v) => v.path == dirPath);
|
VaultDetails? detailsForPath(String dirPath) => _rows.firstWhereOrNull((v) => v.path == dirPath);
|
||||||
|
|
||||||
Future<void> create(VaultDetails details) async {
|
Future<void> create(VaultDetails details) async {
|
||||||
await metadataDb.addVaults({details});
|
await metadataDb.addVaults({details});
|
||||||
|
@ -56,7 +47,7 @@ class Vaults extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> remove(Set<String> dirPaths) async {
|
Future<void> remove(Set<String> dirPaths) async {
|
||||||
final details = dirPaths.map(_detailsForPath).whereNotNull().toSet();
|
final details = dirPaths.map(detailsForPath).whereNotNull().toSet();
|
||||||
if (details.isEmpty) return;
|
if (details.isEmpty) return;
|
||||||
|
|
||||||
await metadataDb.removeVaults(details);
|
await metadataDb.removeVaults(details);
|
||||||
|
@ -70,7 +61,7 @@ class Vaults extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> rename(String oldDirPath, String newDirPath) async {
|
Future<void> rename(String oldDirPath, String newDirPath) async {
|
||||||
final oldDetails = _detailsForPath(oldDirPath);
|
final oldDetails = detailsForPath(oldDirPath);
|
||||||
if (oldDetails == null) return;
|
if (oldDetails == null) return;
|
||||||
|
|
||||||
final newName = VaultDetails.nameFromPath(newDirPath);
|
final newName = VaultDetails.nameFromPath(newDirPath);
|
||||||
|
@ -96,7 +87,7 @@ class Vaults extends ChangeNotifier {
|
||||||
|
|
||||||
// update details, except name
|
// update details, except name
|
||||||
Future<void> update(VaultDetails newDetails) async {
|
Future<void> update(VaultDetails newDetails) async {
|
||||||
final oldDetails = _detailsForPath(newDetails.path);
|
final oldDetails = detailsForPath(newDetails.path);
|
||||||
if (oldDetails == null) return;
|
if (oldDetails == null) return;
|
||||||
|
|
||||||
await metadataDb.updateVault(newDetails.name, newDetails);
|
await metadataDb.updateVault(newDetails.name, newDetails);
|
||||||
|
@ -141,119 +132,11 @@ class Vaults extends ChangeNotifier {
|
||||||
_onLockStateChanged();
|
_onLockStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> tryUnlock(String dirPath, BuildContext context) async {
|
void unlock(String dirPath) {
|
||||||
if (!isVault(dirPath) || !isLocked(dirPath)) return true;
|
if (!vaults.isVault(dirPath) || !vaults.isLocked(dirPath)) return;
|
||||||
|
|
||||||
final details = _detailsForPath(dirPath);
|
|
||||||
if (details == null) return false;
|
|
||||||
|
|
||||||
bool? confirmed;
|
|
||||||
switch (details.lockType) {
|
|
||||||
case VaultLockType.system:
|
|
||||||
try {
|
|
||||||
confirmed = await LocalAuthentication().authenticate(
|
|
||||||
localizedReason: context.l10n.authenticateToUnlockVault,
|
|
||||||
);
|
|
||||||
} on PlatformException catch (e, stack) {
|
|
||||||
if (e.code != 'auth_in_progress') {
|
|
||||||
// `auth_in_progress`: `Authentication in progress`
|
|
||||||
await reportService.recordError(e, stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VaultLockType.pattern:
|
|
||||||
final pattern = await showDialog<String>(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => const PatternDialog(needConfirmation: false),
|
|
||||||
routeSettings: const RouteSettings(name: PatternDialog.routeName),
|
|
||||||
);
|
|
||||||
if (pattern != null) {
|
|
||||||
confirmed = pattern == await securityService.readValue(details.passKey);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VaultLockType.pin:
|
|
||||||
final pin = await showDialog<String>(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => const PinDialog(needConfirmation: false),
|
|
||||||
routeSettings: const RouteSettings(name: PinDialog.routeName),
|
|
||||||
);
|
|
||||||
if (pin != null) {
|
|
||||||
confirmed = pin == await securityService.readValue(details.passKey);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VaultLockType.password:
|
|
||||||
final password = await showDialog<String>(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => const PasswordDialog(needConfirmation: false),
|
|
||||||
routeSettings: const RouteSettings(name: PasswordDialog.routeName),
|
|
||||||
);
|
|
||||||
if (password != null) {
|
|
||||||
confirmed = password == await securityService.readValue(details.passKey);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (confirmed == null || !confirmed) return false;
|
|
||||||
|
|
||||||
_unlockedDirPaths.add(dirPath);
|
_unlockedDirPaths.add(dirPath);
|
||||||
_onLockStateChanged();
|
_onLockStateChanged();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> setPass(BuildContext context, VaultDetails details) async {
|
|
||||||
switch (details.lockType) {
|
|
||||||
case VaultLockType.system:
|
|
||||||
final l10n = context.l10n;
|
|
||||||
try {
|
|
||||||
return await LocalAuthentication().authenticate(
|
|
||||||
localizedReason: l10n.authenticateToConfigureVault,
|
|
||||||
);
|
|
||||||
} on PlatformException catch (e, stack) {
|
|
||||||
await showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AvesDialog(
|
|
||||||
content: Text(e.message ?? l10n.genericFailureFeedback),
|
|
||||||
actions: const [OkButton()],
|
|
||||||
),
|
|
||||||
routeSettings: const RouteSettings(name: AvesDialog.warningRouteName),
|
|
||||||
);
|
|
||||||
if (e.code != auth_error.notAvailable) {
|
|
||||||
await reportService.recordError(e, stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VaultLockType.pattern:
|
|
||||||
final pattern = await showDialog<String>(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => const PatternDialog(needConfirmation: true),
|
|
||||||
routeSettings: const RouteSettings(name: PatternDialog.routeName),
|
|
||||||
);
|
|
||||||
if (pattern != null) {
|
|
||||||
return await securityService.writeValue(details.passKey, pattern);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VaultLockType.pin:
|
|
||||||
final pin = await showDialog<String>(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => const PinDialog(needConfirmation: true),
|
|
||||||
routeSettings: const RouteSettings(name: PinDialog.routeName),
|
|
||||||
);
|
|
||||||
if (pin != null) {
|
|
||||||
return await securityService.writeValue(details.passKey, pin);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case VaultLockType.password:
|
|
||||||
final password = await showDialog<String>(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => const PasswordDialog(needConfirmation: true),
|
|
||||||
routeSettings: const RouteSettings(name: PasswordDialog.routeName),
|
|
||||||
);
|
|
||||||
if (password != null) {
|
|
||||||
return await securityService.writeValue(details.passKey, password);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onScreenOff() => lock(all.where((v) => v.autoLockScreenOff).map((v) => v.path).toSet());
|
void _onScreenOff() => lock(all.where((v) => v.autoLockScreenOff).map((v) => v.path).toSet());
|
||||||
|
|
107
lib/ref/metadata/xmp.dart
Normal file
107
lib/ref/metadata/xmp.dart
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
class XmpNamespaces {
|
||||||
|
static const acdsee = 'http://ns.acdsee.com/iptc/1.0/';
|
||||||
|
static const adsmlat = 'http://adsml.org/xmlns/';
|
||||||
|
static const avm = 'http://www.communicatingastronomy.org/avm/1.0/';
|
||||||
|
static const camera = 'http://pix4d.com/camera/1.0/';
|
||||||
|
static const cc = 'http://creativecommons.org/ns#';
|
||||||
|
static const creatorAtom = 'http://ns.adobe.com/creatorAtom/1.0/';
|
||||||
|
static const crd = 'http://ns.adobe.com/camera-raw-defaults/1.0/';
|
||||||
|
static const crlcp = 'http://ns.adobe.com/camera-raw-embedded-lens-profile/1.0/';
|
||||||
|
static const crs = 'http://ns.adobe.com/camera-raw-settings/1.0/';
|
||||||
|
static const crss = 'http://ns.adobe.com/camera-raw-saved-settings/1.0/';
|
||||||
|
static const darktable = 'http://darktable.sf.net/';
|
||||||
|
static const dc = 'http://purl.org/dc/elements/1.1/';
|
||||||
|
static const dcterms = 'http://purl.org/dc/terms/';
|
||||||
|
static const dicom = 'http://ns.adobe.com/DICOM/';
|
||||||
|
static const digiKam = 'http://www.digikam.org/ns/1.0/';
|
||||||
|
static const droneDji = 'http://www.dji.com/drone-dji/1.0/';
|
||||||
|
static const dwc = 'http://rs.tdwg.org/dwc/index.htm';
|
||||||
|
static const dwciri = 'http://rs.tdwg.org/dwc/iri/';
|
||||||
|
static const exif = 'http://ns.adobe.com/exif/1.0/';
|
||||||
|
static const exifAux = 'http://ns.adobe.com/exif/1.0/aux/';
|
||||||
|
static const exifEx = 'http://cipa.jp/exif/1.0/';
|
||||||
|
static const fstop = 'http://www.fstopapp.com/xmp/';
|
||||||
|
static const gAudio = 'http://ns.google.com/photos/1.0/audio/';
|
||||||
|
static const gCamera = 'http://ns.google.com/photos/1.0/camera/';
|
||||||
|
static const gContainer = 'http://ns.google.com/photos/1.0/container/';
|
||||||
|
static const gCreations = 'http://ns.google.com/photos/1.0/creations/';
|
||||||
|
static const gDepth = 'http://ns.google.com/photos/1.0/depthmap/';
|
||||||
|
static const gDevice = 'http://ns.google.com/photos/dd/1.0/device/';
|
||||||
|
static const gDeviceCamera = 'http://ns.google.com/photos/dd/1.0/camera/';
|
||||||
|
static const gDeviceContainer = 'http://ns.google.com/photos/dd/1.0/container/';
|
||||||
|
static const gDeviceItem = 'http://ns.google.com/photos/dd/1.0/item/';
|
||||||
|
static const gFocus = 'http://ns.google.com/photos/1.0/focus/';
|
||||||
|
static const gImage = 'http://ns.google.com/photos/1.0/image/';
|
||||||
|
static const gPano = 'http://ns.google.com/photos/1.0/panorama/';
|
||||||
|
static const gSpherical = 'http://ns.google.com/videos/1.0/spherical/';
|
||||||
|
static const gettyImagesGift = 'http://xmp.gettyimages.com/gift/1.0/';
|
||||||
|
static const gimp210 = 'http://www.gimp.org/ns/2.10/';
|
||||||
|
static const gimpXmp = 'http://www.gimp.org/xmp/';
|
||||||
|
static const illustrator = 'http://ns.adobe.com/illustrator/1.0/';
|
||||||
|
static const iptc4xmpCore = 'http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/';
|
||||||
|
static const iptc4xmpExt = 'http://iptc.org/std/Iptc4xmpExt/2008-02-29/';
|
||||||
|
static const lr = 'http://ns.adobe.com/lightroom/1.0/';
|
||||||
|
static const mediapro = 'http://ns.iview-multimedia.com/mediapro/1.0/';
|
||||||
|
static const miCamera = 'http://ns.xiaomi.com/photos/1.0/camera/';
|
||||||
|
|
||||||
|
// also seen in the wild for prefix `MicrosoftPhoto`: 'http://ns.microsoft.com/photo/1.0'
|
||||||
|
static const microsoftPhoto = 'http://ns.microsoft.com/photo/1.0/';
|
||||||
|
static const mp1 = 'http://ns.microsoft.com/photo/1.1';
|
||||||
|
static const mp = 'http://ns.microsoft.com/photo/1.2/';
|
||||||
|
static const mpri = 'http://ns.microsoft.com/photo/1.2/t/RegionInfo#';
|
||||||
|
static const mpreg = 'http://ns.microsoft.com/photo/1.2/t/Region#';
|
||||||
|
static const mwgrs = 'http://www.metadataworkinggroup.com/schemas/regions/';
|
||||||
|
static const nga = 'https://standards.nga.gov/metadata/media/image/artobject/1.0';
|
||||||
|
static const opMedia = 'http://ns.oneplus.com/media/1.0/';
|
||||||
|
static const panorama = 'http://ns.adobe.com/photoshop/1.0/panorama-profile';
|
||||||
|
static const panoStudio = 'http://www.tshsoft.com/xmlns';
|
||||||
|
static const pdf = 'http://ns.adobe.com/pdf/1.3/';
|
||||||
|
static const pdfX = 'http://ns.adobe.com/pdfx/1.3/';
|
||||||
|
static const photoMechanic = 'http://ns.camerabits.com/photomechanic/1.0/';
|
||||||
|
static const photoshop = 'http://ns.adobe.com/photoshop/1.0/';
|
||||||
|
static const plus = 'http://ns.useplus.org/ldf/xmp/1.0/';
|
||||||
|
static const pmtm = 'http://www.hdrsoft.com/photomatix_settings01';
|
||||||
|
static const rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
||||||
|
static const stCamera = 'http://ns.adobe.com/photoshop/1.0/camera-profile';
|
||||||
|
static const stEvt = 'http://ns.adobe.com/xap/1.0/sType/ResourceEvent#';
|
||||||
|
static const stRef = 'http://ns.adobe.com/xap/1.0/sType/ResourceRef#';
|
||||||
|
static const tiff = 'http://ns.adobe.com/tiff/1.0/';
|
||||||
|
static const x = 'adobe:ns:meta/';
|
||||||
|
static const xmp = 'http://ns.adobe.com/xap/1.0/';
|
||||||
|
static const xmpBJ = 'http://ns.adobe.com/xap/1.0/bj/';
|
||||||
|
static const xmpDM = 'http://ns.adobe.com/xmp/1.0/DynamicMedia/';
|
||||||
|
static const xmpGImg = 'http://ns.adobe.com/xap/1.0/g/img/';
|
||||||
|
static const xmpMM = 'http://ns.adobe.com/xap/1.0/mm/';
|
||||||
|
static const xmpNote = 'http://ns.adobe.com/xmp/note/';
|
||||||
|
static const xmpRights = 'http://ns.adobe.com/xap/1.0/rights/';
|
||||||
|
static const xmpTPg = 'http://ns.adobe.com/xap/1.0/t/pg/';
|
||||||
|
static const xperiaCamera = 'http://xmlns.sony.net/xperia/camera/1.0/';
|
||||||
|
}
|
||||||
|
|
||||||
|
class XmpElements {
|
||||||
|
static const xXmpmeta = 'xmpmeta';
|
||||||
|
static const rdfRoot = 'RDF';
|
||||||
|
static const rdfDescription = 'Description';
|
||||||
|
static const containerDirectory = 'Directory';
|
||||||
|
static const dcDescription = 'description';
|
||||||
|
static const dcSubject = 'subject';
|
||||||
|
static const dcTitle = 'title';
|
||||||
|
static const msPhotoRating = 'Rating';
|
||||||
|
static const xmpRating = 'Rating';
|
||||||
|
}
|
||||||
|
|
||||||
|
class XmpAttributes {
|
||||||
|
static const xXmptk = 'xmptk';
|
||||||
|
static const rdfAbout = 'about';
|
||||||
|
static const gCameraMicroVideo = 'MicroVideo';
|
||||||
|
static const gCameraMicroVideoVersion = 'MicroVideoVersion';
|
||||||
|
static const gCameraMicroVideoOffset = 'MicroVideoOffset';
|
||||||
|
static const gCameraMicroVideoPresentationTimestampUs = 'MicroVideoPresentationTimestampUs';
|
||||||
|
static const gCameraMotionPhoto = 'MotionPhoto';
|
||||||
|
static const gCameraMotionPhotoVersion = 'MotionPhotoVersion';
|
||||||
|
static const gCameraMotionPhotoPresentationTimestampUs = 'MotionPhotoPresentationTimestampUs';
|
||||||
|
static const xmpCreateDate = 'CreateDate';
|
||||||
|
static const xmpMetadataDate = 'MetadataDate';
|
||||||
|
static const xmpModifyDate = 'ModifyDate';
|
||||||
|
static const xmpNoteHasExtendedXMP = 'HasExtendedXMP';
|
||||||
|
}
|
|
@ -5,11 +5,11 @@ import 'package:aves/l10n/l10n.dart';
|
||||||
import 'package:aves/model/device.dart';
|
import 'package:aves/model/device.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/analysis_controller.dart';
|
import 'package:aves/model/source/analysis_controller.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/source/media_store_source.dart';
|
import 'package:aves/model/source/media_store_source.dart';
|
||||||
import 'package:aves/model/source/source_state.dart';
|
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:fijkplayer/fijkplayer.dart';
|
import 'package:fijkplayer/fijkplayer.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:aves/convert/convert.dart';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/props.dart';
|
import 'package:aves/model/entry/extensions/props.dart';
|
||||||
import 'package:aves/model/metadata/date_modifier.dart';
|
import 'package:aves/model/metadata/date_modifier.dart';
|
||||||
import 'package:aves/model/metadata/enums/metadata_type.dart';
|
|
||||||
import 'package:aves/model/metadata/fields.dart';
|
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
import 'package:aves/convert/convert.dart';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/multipage.dart';
|
import 'package:aves/model/entry/extensions/multipage.dart';
|
||||||
import 'package:aves/model/entry/extensions/props.dart';
|
import 'package:aves/model/entry/extensions/props.dart';
|
||||||
import 'package:aves/model/geotiff.dart';
|
import 'package:aves/model/geotiff.dart';
|
||||||
import 'package:aves/model/metadata/catalog.dart';
|
import 'package:aves/model/metadata/catalog.dart';
|
||||||
import 'package:aves/model/metadata/fields.dart';
|
|
||||||
import 'package:aves/model/metadata/overlay.dart';
|
import 'package:aves/model/metadata/overlay.dart';
|
||||||
import 'package:aves/model/multipage.dart';
|
import 'package:aves/model/multipage.dart';
|
||||||
import 'package:aves/model/panorama.dart';
|
import 'package:aves/model/panorama.dart';
|
||||||
|
@ -12,6 +12,7 @@ import 'package:aves/services/common/service_policy.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/services/metadata/xmp.dart';
|
import 'package:aves/services/metadata/xmp.dart';
|
||||||
import 'package:aves/utils/time_utils.dart';
|
import 'package:aves/utils/time_utils.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/model/storage/relative_dir.dart';
|
|
||||||
import 'package:aves/model/storage/volume.dart';
|
|
||||||
import 'package:aves/services/common/output_buffer.dart';
|
import 'package:aves/services/common/output_buffer.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:streams_channel/streams_channel.dart';
|
import 'package:streams_channel/streams_channel.dart';
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:aves/model/wallpaper_target.dart';
|
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
class WallpaperService {
|
class WallpaperService {
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import 'package:aves/model/apps.dart';
|
import 'package:aves/model/apps.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/storage/volume.dart';
|
|
||||||
import 'package:aves/model/vaults/vaults.dart';
|
import 'package:aves/model/vaults/vaults.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
@ -82,6 +81,19 @@ class AndroidFileUtils {
|
||||||
return volume != null || path.endsWith(separator) ? volume : getStorageVolume('$path$separator');
|
return volume != null || path.endsWith(separator) ? volume : getStorageVolume('$path$separator');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prefer static method over a null returning factory constructor
|
||||||
|
VolumeRelativeDirectory? relativeDirectoryFromPath(String dirPath) {
|
||||||
|
final volume = getStorageVolume(dirPath);
|
||||||
|
if (volume == null) return null;
|
||||||
|
|
||||||
|
final root = volume.path;
|
||||||
|
final rootLength = root.length;
|
||||||
|
return VolumeRelativeDirectory(
|
||||||
|
volumePath: root,
|
||||||
|
relativeDir: dirPath.length < rootLength ? '' : dirPath.substring(rootLength),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
bool isOnRemovableStorage(String path) => getStorageVolume(path)?.isRemovable ?? false;
|
bool isOnRemovableStorage(String path) => getStorageVolume(path)?.isRemovable ?? false;
|
||||||
|
|
||||||
AlbumType getAlbumType(String dirPath) {
|
AlbumType getAlbumType(String dirPath) {
|
||||||
|
|
|
@ -1,194 +1,29 @@
|
||||||
|
import 'package:aves/ref/metadata/xmp.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:xml/xml.dart';
|
import 'package:xml/xml.dart';
|
||||||
|
|
||||||
class Namespaces {
|
|
||||||
static const acdsee = 'http://ns.acdsee.com/iptc/1.0/';
|
|
||||||
static const adsmlat = 'http://adsml.org/xmlns/';
|
|
||||||
static const avm = 'http://www.communicatingastronomy.org/avm/1.0/';
|
|
||||||
static const camera = 'http://pix4d.com/camera/1.0/';
|
|
||||||
static const cc = 'http://creativecommons.org/ns#';
|
|
||||||
static const creatorAtom = 'http://ns.adobe.com/creatorAtom/1.0/';
|
|
||||||
static const crd = 'http://ns.adobe.com/camera-raw-defaults/1.0/';
|
|
||||||
static const crlcp = 'http://ns.adobe.com/camera-raw-embedded-lens-profile/1.0/';
|
|
||||||
static const crs = 'http://ns.adobe.com/camera-raw-settings/1.0/';
|
|
||||||
static const crss = 'http://ns.adobe.com/camera-raw-saved-settings/1.0/';
|
|
||||||
static const darktable = 'http://darktable.sf.net/';
|
|
||||||
static const dc = 'http://purl.org/dc/elements/1.1/';
|
|
||||||
static const dcterms = 'http://purl.org/dc/terms/';
|
|
||||||
static const dicom = 'http://ns.adobe.com/DICOM/';
|
|
||||||
static const digiKam = 'http://www.digikam.org/ns/1.0/';
|
|
||||||
static const droneDji = 'http://www.dji.com/drone-dji/1.0/';
|
|
||||||
static const dwc = 'http://rs.tdwg.org/dwc/index.htm';
|
|
||||||
static const dwciri = 'http://rs.tdwg.org/dwc/iri/';
|
|
||||||
static const exif = 'http://ns.adobe.com/exif/1.0/';
|
|
||||||
static const exifAux = 'http://ns.adobe.com/exif/1.0/aux/';
|
|
||||||
static const exifEx = 'http://cipa.jp/exif/1.0/';
|
|
||||||
static const fstop = 'http://www.fstopapp.com/xmp/';
|
|
||||||
static const gAudio = 'http://ns.google.com/photos/1.0/audio/';
|
|
||||||
static const gCamera = 'http://ns.google.com/photos/1.0/camera/';
|
|
||||||
static const gContainer = 'http://ns.google.com/photos/1.0/container/';
|
|
||||||
static const gCreations = 'http://ns.google.com/photos/1.0/creations/';
|
|
||||||
static const gDepth = 'http://ns.google.com/photos/1.0/depthmap/';
|
|
||||||
static const gDevice = 'http://ns.google.com/photos/dd/1.0/device/';
|
|
||||||
static const gDeviceCamera = 'http://ns.google.com/photos/dd/1.0/camera/';
|
|
||||||
static const gDeviceContainer = 'http://ns.google.com/photos/dd/1.0/container/';
|
|
||||||
static const gDeviceItem = 'http://ns.google.com/photos/dd/1.0/item/';
|
|
||||||
static const gFocus = 'http://ns.google.com/photos/1.0/focus/';
|
|
||||||
static const gImage = 'http://ns.google.com/photos/1.0/image/';
|
|
||||||
static const gPano = 'http://ns.google.com/photos/1.0/panorama/';
|
|
||||||
static const gSpherical = 'http://ns.google.com/videos/1.0/spherical/';
|
|
||||||
static const gettyImagesGift = 'http://xmp.gettyimages.com/gift/1.0/';
|
|
||||||
static const gimp210 = 'http://www.gimp.org/ns/2.10/';
|
|
||||||
static const gimpXmp = 'http://www.gimp.org/xmp/';
|
|
||||||
static const illustrator = 'http://ns.adobe.com/illustrator/1.0/';
|
|
||||||
static const iptc4xmpCore = 'http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/';
|
|
||||||
static const iptc4xmpExt = 'http://iptc.org/std/Iptc4xmpExt/2008-02-29/';
|
|
||||||
static const lr = 'http://ns.adobe.com/lightroom/1.0/';
|
|
||||||
static const mediapro = 'http://ns.iview-multimedia.com/mediapro/1.0/';
|
|
||||||
static const miCamera = 'http://ns.xiaomi.com/photos/1.0/camera/';
|
|
||||||
|
|
||||||
// also seen in the wild for prefix `MicrosoftPhoto`: 'http://ns.microsoft.com/photo/1.0'
|
|
||||||
static const microsoftPhoto = 'http://ns.microsoft.com/photo/1.0/';
|
|
||||||
static const mp1 = 'http://ns.microsoft.com/photo/1.1';
|
|
||||||
static const mp = 'http://ns.microsoft.com/photo/1.2/';
|
|
||||||
static const mpri = 'http://ns.microsoft.com/photo/1.2/t/RegionInfo#';
|
|
||||||
static const mpreg = 'http://ns.microsoft.com/photo/1.2/t/Region#';
|
|
||||||
static const mwgrs = 'http://www.metadataworkinggroup.com/schemas/regions/';
|
|
||||||
static const nga = 'https://standards.nga.gov/metadata/media/image/artobject/1.0';
|
|
||||||
static const opMedia = 'http://ns.oneplus.com/media/1.0/';
|
|
||||||
static const panorama = 'http://ns.adobe.com/photoshop/1.0/panorama-profile';
|
|
||||||
static const panoStudio = 'http://www.tshsoft.com/xmlns';
|
|
||||||
static const pdf = 'http://ns.adobe.com/pdf/1.3/';
|
|
||||||
static const pdfX = 'http://ns.adobe.com/pdfx/1.3/';
|
|
||||||
static const photoMechanic = 'http://ns.camerabits.com/photomechanic/1.0/';
|
|
||||||
static const photoshop = 'http://ns.adobe.com/photoshop/1.0/';
|
|
||||||
static const plus = 'http://ns.useplus.org/ldf/xmp/1.0/';
|
|
||||||
static const pmtm = 'http://www.hdrsoft.com/photomatix_settings01';
|
|
||||||
static const rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
|
||||||
static const stCamera = 'http://ns.adobe.com/photoshop/1.0/camera-profile';
|
|
||||||
static const stEvt = 'http://ns.adobe.com/xap/1.0/sType/ResourceEvent#';
|
|
||||||
static const stRef = 'http://ns.adobe.com/xap/1.0/sType/ResourceRef#';
|
|
||||||
static const tiff = 'http://ns.adobe.com/tiff/1.0/';
|
|
||||||
static const x = 'adobe:ns:meta/';
|
|
||||||
static const xmp = 'http://ns.adobe.com/xap/1.0/';
|
|
||||||
static const xmpBJ = 'http://ns.adobe.com/xap/1.0/bj/';
|
|
||||||
static const xmpDM = 'http://ns.adobe.com/xmp/1.0/DynamicMedia/';
|
|
||||||
static const xmpGImg = 'http://ns.adobe.com/xap/1.0/g/img/';
|
|
||||||
static const xmpMM = 'http://ns.adobe.com/xap/1.0/mm/';
|
|
||||||
static const xmpNote = 'http://ns.adobe.com/xmp/note/';
|
|
||||||
static const xmpRights = 'http://ns.adobe.com/xap/1.0/rights/';
|
|
||||||
static const xmpTPg = 'http://ns.adobe.com/xap/1.0/t/pg/';
|
|
||||||
static const xperiaCamera = 'http://xmlns.sony.net/xperia/camera/1.0/';
|
|
||||||
|
|
||||||
// cf https://exiftool.org/TagNames/XMP.html
|
|
||||||
static const Map<String, String> nsTitles = {
|
|
||||||
acdsee: 'ACDSee',
|
|
||||||
adsmlat: 'AdsML',
|
|
||||||
exifAux: 'Exif Aux',
|
|
||||||
avm: 'Astronomy Visualization',
|
|
||||||
camera: 'Pix4D Camera',
|
|
||||||
cc: 'Creative Commons',
|
|
||||||
crd: 'Camera Raw Defaults',
|
|
||||||
creatorAtom: 'After Effects',
|
|
||||||
crs: 'Camera Raw Settings',
|
|
||||||
crss: 'Camera Raw Saved Settings',
|
|
||||||
darktable: 'darktable',
|
|
||||||
dc: 'Dublin Core',
|
|
||||||
digiKam: 'digiKam',
|
|
||||||
droneDji: 'DJI Drone',
|
|
||||||
dwc: 'Darwin Core',
|
|
||||||
exif: 'Exif',
|
|
||||||
exifEx: 'Exif Ex',
|
|
||||||
fstop: 'F-Stop',
|
|
||||||
gAudio: 'Google Audio',
|
|
||||||
gCamera: 'Google Camera',
|
|
||||||
gContainer: 'Google Container',
|
|
||||||
gCreations: 'Google Creations',
|
|
||||||
gDepth: 'Google Depth',
|
|
||||||
gDevice: 'Google Device',
|
|
||||||
gFocus: 'Google Focus',
|
|
||||||
gImage: 'Google Image',
|
|
||||||
gPano: 'Google Panorama',
|
|
||||||
gSpherical: 'Google Spherical',
|
|
||||||
gettyImagesGift: 'Getty Images',
|
|
||||||
gimp210: 'GIMP 2.10',
|
|
||||||
gimpXmp: 'GIMP',
|
|
||||||
illustrator: 'Illustrator',
|
|
||||||
iptc4xmpCore: 'IPTC Core',
|
|
||||||
iptc4xmpExt: 'IPTC Extension',
|
|
||||||
lr: 'Lightroom',
|
|
||||||
mediapro: 'MediaPro',
|
|
||||||
miCamera: 'Mi Camera',
|
|
||||||
microsoftPhoto: 'Microsoft Photo 1.0',
|
|
||||||
mp1: 'Microsoft Photo 1.1',
|
|
||||||
mp: 'Microsoft Photo 1.2',
|
|
||||||
mwgrs: 'Regions',
|
|
||||||
nga: 'National Gallery of Art',
|
|
||||||
opMedia: 'OnePlus Media',
|
|
||||||
panorama: 'Panorama',
|
|
||||||
panoStudio: 'PanoramaStudio',
|
|
||||||
pdf: 'PDF',
|
|
||||||
pdfX: 'PDF/X',
|
|
||||||
photoMechanic: 'Photo Mechanic',
|
|
||||||
photoshop: 'Photoshop',
|
|
||||||
plus: 'PLUS',
|
|
||||||
pmtm: 'Photomatix',
|
|
||||||
tiff: 'TIFF',
|
|
||||||
xmp: 'Basic',
|
|
||||||
xmpBJ: 'Basic Job Ticket',
|
|
||||||
xmpDM: 'Dynamic Media',
|
|
||||||
xmpMM: 'Media Management',
|
|
||||||
xmpNote: 'Note',
|
|
||||||
xmpRights: 'Rights Management',
|
|
||||||
xmpTPg: 'Paged-Text',
|
|
||||||
xperiaCamera: 'Xperia Camera',
|
|
||||||
};
|
|
||||||
|
|
||||||
static final defaultPrefixes = {
|
|
||||||
gContainer: 'Container',
|
|
||||||
dc: 'dc',
|
|
||||||
gCamera: 'GCamera',
|
|
||||||
microsoftPhoto: 'MicrosoftPhoto',
|
|
||||||
rdf: 'rdf',
|
|
||||||
x: 'x',
|
|
||||||
xmp: 'xmp',
|
|
||||||
xmpGImg: 'xmpGImg',
|
|
||||||
xmpNote: 'xmpNote',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class XMP {
|
class XMP {
|
||||||
static const xmlnsPrefix = 'xmlns';
|
static const xmlnsPrefix = 'xmlns';
|
||||||
static const propNamespaceSeparator = ':';
|
static const propNamespaceSeparator = ':';
|
||||||
static const structFieldSeparator = '/';
|
static const structFieldSeparator = '/';
|
||||||
|
|
||||||
static String prefixOf(String ns) => Namespaces.defaultPrefixes[ns] ?? '';
|
static final _defaultPrefixes = {
|
||||||
|
XmpNamespaces.gContainer: 'Container',
|
||||||
|
XmpNamespaces.dc: 'dc',
|
||||||
|
XmpNamespaces.gCamera: 'GCamera',
|
||||||
|
XmpNamespaces.microsoftPhoto: 'MicrosoftPhoto',
|
||||||
|
XmpNamespaces.rdf: 'rdf',
|
||||||
|
XmpNamespaces.x: 'x',
|
||||||
|
XmpNamespaces.xmp: 'xmp',
|
||||||
|
XmpNamespaces.xmpGImg: 'xmpGImg',
|
||||||
|
XmpNamespaces.xmpNote: 'xmpNote',
|
||||||
|
};
|
||||||
|
|
||||||
// elements
|
static String prefixOf(String ns) => _defaultPrefixes[ns] ?? '';
|
||||||
static const xXmpmeta = 'xmpmeta';
|
|
||||||
static const rdfRoot = 'RDF';
|
|
||||||
static const rdfDescription = 'Description';
|
|
||||||
static const containerDirectory = 'Directory';
|
|
||||||
static const dcDescription = 'description';
|
|
||||||
static const dcSubject = 'subject';
|
|
||||||
static const dcTitle = 'title';
|
|
||||||
static const msPhotoRating = 'Rating';
|
|
||||||
static const xmpRating = 'Rating';
|
|
||||||
|
|
||||||
// attributes
|
static const nsRdf = XmpNamespaces.rdf;
|
||||||
static const xXmptk = 'xmptk';
|
static const nsX = XmpNamespaces.x;
|
||||||
static const rdfAbout = 'about';
|
static const nsXmp = XmpNamespaces.xmp;
|
||||||
static const gCameraMicroVideo = 'MicroVideo';
|
|
||||||
static const gCameraMicroVideoVersion = 'MicroVideoVersion';
|
|
||||||
static const gCameraMicroVideoOffset = 'MicroVideoOffset';
|
|
||||||
static const gCameraMicroVideoPresentationTimestampUs = 'MicroVideoPresentationTimestampUs';
|
|
||||||
static const gCameraMotionPhoto = 'MotionPhoto';
|
|
||||||
static const gCameraMotionPhotoVersion = 'MotionPhotoVersion';
|
|
||||||
static const gCameraMotionPhotoPresentationTimestampUs = 'MotionPhotoPresentationTimestampUs';
|
|
||||||
static const xmpCreateDate = 'CreateDate';
|
|
||||||
static const xmpMetadataDate = 'MetadataDate';
|
|
||||||
static const xmpModifyDate = 'ModifyDate';
|
|
||||||
static const xmpNoteHasExtendedXMP = 'HasExtendedXMP';
|
|
||||||
|
|
||||||
// for `rdf:Description` node only
|
// for `rdf:Description` node only
|
||||||
static bool _hasMeaningfulChildren(XmlNode node) => node.children.any((v) => v.nodeType != XmlNodeType.TEXT || v.text.trim().isNotEmpty);
|
static bool _hasMeaningfulChildren(XmlNode node) => node.children.any((v) => v.nodeType != XmlNodeType.TEXT || v.text.trim().isNotEmpty);
|
||||||
|
@ -197,9 +32,9 @@ class XMP {
|
||||||
static bool _hasMeaningfulAttributes(XmlNode description) {
|
static bool _hasMeaningfulAttributes(XmlNode description) {
|
||||||
final hasMeaningfulAttributes = description.attributes.any((v) {
|
final hasMeaningfulAttributes = description.attributes.any((v) {
|
||||||
switch (v.name.local) {
|
switch (v.name.local) {
|
||||||
case rdfAbout:
|
case XmpAttributes.rdfAbout:
|
||||||
case xmpMetadataDate:
|
case XmpAttributes.xmpMetadataDate:
|
||||||
case xmpModifyDate:
|
case XmpAttributes.xmpModifyDate:
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
switch (v.name.prefix) {
|
switch (v.name.prefix) {
|
||||||
|
@ -338,10 +173,10 @@ class XMP {
|
||||||
node.children.add(rootBuilder.buildFragment());
|
node.children.add(rootBuilder.buildFragment());
|
||||||
|
|
||||||
final bagBuilder = XmlBuilder();
|
final bagBuilder = XmlBuilder();
|
||||||
bagBuilder.namespace(Namespaces.rdf, prefixOf(Namespaces.rdf));
|
bagBuilder.namespace(nsRdf, prefixOf(nsRdf));
|
||||||
bagBuilder.element('Bag', namespace: Namespaces.rdf, nest: () {
|
bagBuilder.element('Bag', namespace: nsRdf, nest: () {
|
||||||
values.forEach((v) {
|
values.forEach((v) {
|
||||||
bagBuilder.element('li', namespace: Namespaces.rdf, nest: v);
|
bagBuilder.element('li', namespace: nsRdf, nest: v);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
node.children.last.children.add(bagBuilder.buildFragment());
|
node.children.last.children.add(bagBuilder.buildFragment());
|
||||||
|
@ -363,42 +198,42 @@ class XMP {
|
||||||
}
|
}
|
||||||
if (xmpDoc == null) {
|
if (xmpDoc == null) {
|
||||||
final builder = XmlBuilder();
|
final builder = XmlBuilder();
|
||||||
builder.namespace(Namespaces.x, prefixOf(Namespaces.x));
|
builder.namespace(nsX, prefixOf(nsX));
|
||||||
builder.element(xXmpmeta, namespace: Namespaces.x, namespaces: {
|
builder.element(XmpElements.xXmpmeta, namespace: nsX, namespaces: {
|
||||||
Namespaces.x: prefixOf(Namespaces.x),
|
nsX: prefixOf(nsX),
|
||||||
}, attributes: {
|
}, attributes: {
|
||||||
'${prefixOf(Namespaces.x)}$propNamespaceSeparator$xXmptk': await toolkit(),
|
'${prefixOf(nsX)}$propNamespaceSeparator${XmpAttributes.xXmptk}': await toolkit(),
|
||||||
});
|
});
|
||||||
xmpDoc = builder.buildDocument();
|
xmpDoc = builder.buildDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
final root = xmpDoc.rootElement;
|
final root = xmpDoc.rootElement;
|
||||||
XmlNode? rdf = root.getElement(rdfRoot, namespace: Namespaces.rdf);
|
XmlNode? rdf = root.getElement(XmpElements.rdfRoot, namespace: nsRdf);
|
||||||
if (rdf == null) {
|
if (rdf == null) {
|
||||||
final builder = XmlBuilder();
|
final builder = XmlBuilder();
|
||||||
builder.namespace(Namespaces.rdf, prefixOf(Namespaces.rdf));
|
builder.namespace(nsRdf, prefixOf(nsRdf));
|
||||||
builder.element(rdfRoot, namespace: Namespaces.rdf, namespaces: {
|
builder.element(XmpElements.rdfRoot, namespace: nsRdf, namespaces: {
|
||||||
Namespaces.rdf: prefixOf(Namespaces.rdf),
|
nsRdf: prefixOf(nsRdf),
|
||||||
});
|
});
|
||||||
// get element because doc fragment cannot be used to edit
|
// get element because doc fragment cannot be used to edit
|
||||||
root.children.add(builder.buildFragment());
|
root.children.add(builder.buildFragment());
|
||||||
rdf = root.getElement(rdfRoot, namespace: Namespaces.rdf)!;
|
rdf = root.getElement(XmpElements.rdfRoot, namespace: nsRdf)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
// content can be split in multiple `rdf:Description` elements
|
// content can be split in multiple `rdf:Description` elements
|
||||||
List<XmlNode> descriptions = rdf.children.where((node) {
|
List<XmlNode> descriptions = rdf.children.where((node) {
|
||||||
return node is XmlElement && node.name.local == rdfDescription && node.name.namespaceUri == Namespaces.rdf;
|
return node is XmlElement && node.name.local == XmpElements.rdfDescription && node.name.namespaceUri == nsRdf;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
if (descriptions.isEmpty) {
|
if (descriptions.isEmpty) {
|
||||||
final builder = XmlBuilder();
|
final builder = XmlBuilder();
|
||||||
builder.namespace(Namespaces.rdf, prefixOf(Namespaces.rdf));
|
builder.namespace(nsRdf, prefixOf(nsRdf));
|
||||||
builder.element(rdfDescription, namespace: Namespaces.rdf, attributes: {
|
builder.element(XmpElements.rdfDescription, namespace: nsRdf, attributes: {
|
||||||
'${prefixOf(Namespaces.rdf)}$propNamespaceSeparator$rdfAbout': '',
|
'${prefixOf(nsRdf)}$propNamespaceSeparator${XmpAttributes.rdfAbout}': '',
|
||||||
});
|
});
|
||||||
rdf.children.add(builder.buildFragment());
|
rdf.children.add(builder.buildFragment());
|
||||||
// get element because doc fragment cannot be used to edit
|
// get element because doc fragment cannot be used to edit
|
||||||
descriptions.add(rdf.getElement(rdfDescription, namespace: Namespaces.rdf)!);
|
descriptions.add(rdf.getElement(XmpElements.rdfDescription, namespace: nsRdf)!);
|
||||||
}
|
}
|
||||||
final modified = apply(descriptions);
|
final modified = apply(descriptions);
|
||||||
|
|
||||||
|
@ -410,10 +245,10 @@ class XMP {
|
||||||
|
|
||||||
if (rdf.children.isNotEmpty) {
|
if (rdf.children.isNotEmpty) {
|
||||||
if (modified) {
|
if (modified) {
|
||||||
_addNamespaces(descriptions.first, {Namespaces.xmp: prefixOf(Namespaces.xmp)});
|
_addNamespaces(descriptions.first, {nsXmp: prefixOf(nsXmp)});
|
||||||
final xmpDate = toXmpDate(modifyDate ?? DateTime.now());
|
final xmpDate = toXmpDate(modifyDate ?? DateTime.now());
|
||||||
setAttribute(descriptions, xmpMetadataDate, xmpDate, namespace: Namespaces.xmp, strat: XmpEditStrategy.always);
|
setAttribute(descriptions, XmpAttributes.xmpMetadataDate, xmpDate, namespace: nsXmp, strat: XmpEditStrategy.always);
|
||||||
setAttribute(descriptions, xmpModifyDate, xmpDate, namespace: Namespaces.xmp, strat: XmpEditStrategy.always);
|
setAttribute(descriptions, XmpAttributes.xmpModifyDate, xmpDate, namespace: nsXmp, strat: XmpEditStrategy.always);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// clear XMP if there are no attributes or elements worth preserving
|
// clear XMP if there are no attributes or elements worth preserving
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
extension ExtraChipAction on ChipAction {
|
extension ExtraChipActionView on ChipAction {
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case ChipAction.goToAlbumPage:
|
case ChipAction.goToAlbumPage:
|
|
@ -3,7 +3,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
extension ExtraChipSetAction on ChipSetAction {
|
extension ExtraChipSetActionView on ChipSetAction {
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
// general
|
// general
|
|
@ -4,7 +4,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
extension ExtraEntryAction on EntryAction {
|
extension ExtraEntryActionView on EntryAction {
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case EntryAction.info:
|
case EntryAction.info:
|
|
@ -3,7 +3,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
extension ExtraEntrySetAction on EntrySetAction {
|
extension ExtraEntrySetActionView on EntrySetAction {
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
// general
|
// general
|
|
@ -3,7 +3,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
extension ExtraMapAction on MapAction {
|
extension ExtraMapActionView on MapAction {
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case MapAction.selectStyle:
|
case MapAction.selectStyle:
|
|
@ -3,7 +3,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
extension ExtraMapClusterAction on MapClusterAction {
|
extension ExtraMapClusterActionView on MapClusterAction {
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case MapClusterAction.editLocation:
|
case MapClusterAction.editLocation:
|
|
@ -3,7 +3,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
extension ExtraShareAction on ShareAction {
|
extension ExtraShareActionView on ShareAction {
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case ShareAction.imageOnly:
|
case ShareAction.imageOnly:
|
|
@ -3,7 +3,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
extension ExtraSlideshowAction on SlideshowAction {
|
extension ExtraSlideshowActionView on SlideshowAction {
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case SlideshowAction.resume:
|
case SlideshowAction.resume:
|
|
@ -2,7 +2,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
extension ExtraDateEditAction on DateEditAction {
|
extension ExtraDateEditActionView on DateEditAction {
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case DateEditAction.setCustom:
|
case DateEditAction.setCustom:
|
|
@ -1,9 +1,8 @@
|
||||||
import 'package:aves/model/metadata/fields.dart';
|
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
extension ExtraDateFieldSource on DateFieldSource {
|
extension ExtraDateFieldSourceView on DateFieldSource {
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case DateFieldSource.fileModifiedDate:
|
case DateFieldSource.fileModifiedDate:
|
||||||
|
@ -18,19 +17,4 @@ extension ExtraDateFieldSource on DateFieldSource {
|
||||||
return 'Exif GPS date';
|
return 'Exif GPS date';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MetadataField? toMetadataField() {
|
|
||||||
switch (this) {
|
|
||||||
case DateFieldSource.fileModifiedDate:
|
|
||||||
return null;
|
|
||||||
case DateFieldSource.exifDate:
|
|
||||||
return MetadataField.exifDate;
|
|
||||||
case DateFieldSource.exifDateOriginal:
|
|
||||||
return MetadataField.exifDateOriginal;
|
|
||||||
case DateFieldSource.exifDateDigitized:
|
|
||||||
return MetadataField.exifDateDigitized;
|
|
||||||
case DateFieldSource.exifGpsDate:
|
|
||||||
return MetadataField.exifGpsDatestamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
20
lib/view/src/metadata/fields.dart
Normal file
20
lib/view/src/metadata/fields.dart
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
|
||||||
|
extension ExtraMetadataFieldView on MetadataField {
|
||||||
|
String get title {
|
||||||
|
switch (this) {
|
||||||
|
case MetadataField.exifDate:
|
||||||
|
return 'Exif date';
|
||||||
|
case MetadataField.exifDateOriginal:
|
||||||
|
return 'Exif original date';
|
||||||
|
case MetadataField.exifDateDigitized:
|
||||||
|
return 'Exif digitized date';
|
||||||
|
case MetadataField.exifGpsDatestamp:
|
||||||
|
return 'Exif GPS date';
|
||||||
|
case MetadataField.xmpXmpCreateDate:
|
||||||
|
return 'XMP xmp:CreateDate';
|
||||||
|
default:
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
extension ExtraLengthUnit on LengthUnit {
|
extension ExtraLengthUnitView on LengthUnit {
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case LengthUnit.px:
|
case LengthUnit.px:
|
|
@ -2,7 +2,7 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
extension ExtraLocationEditAction on LocationEditAction {
|
extension ExtraLocationEditActionView on LocationEditAction {
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case LocationEditAction.chooseOnMap:
|
case LocationEditAction.chooseOnMap:
|
29
lib/view/src/metadata/metadata_type.dart
Normal file
29
lib/view/src/metadata/metadata_type.dart
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
|
||||||
|
extension ExtraMetadataTypeView on MetadataType {
|
||||||
|
// match `metadata-extractor` directory names
|
||||||
|
String getText() {
|
||||||
|
switch (this) {
|
||||||
|
case MetadataType.comment:
|
||||||
|
return 'Comment';
|
||||||
|
case MetadataType.exif:
|
||||||
|
return 'Exif';
|
||||||
|
case MetadataType.iccProfile:
|
||||||
|
return 'ICC Profile';
|
||||||
|
case MetadataType.iptc:
|
||||||
|
return 'IPTC';
|
||||||
|
case MetadataType.jfif:
|
||||||
|
return 'JFIF';
|
||||||
|
case MetadataType.jpegAdobe:
|
||||||
|
return 'Adobe JPEG';
|
||||||
|
case MetadataType.jpegDucky:
|
||||||
|
return 'Ducky';
|
||||||
|
case MetadataType.mp4:
|
||||||
|
return 'MP4';
|
||||||
|
case MetadataType.photoshopIrb:
|
||||||
|
return 'Photoshop';
|
||||||
|
case MetadataType.xmp:
|
||||||
|
return 'XMP';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ import 'package:aves_map/aves_map.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
extension ExtraAccessibilityAnimationsName on AccessibilityAnimations {
|
extension ExtraAccessibilityAnimationsView on AccessibilityAnimations {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case AccessibilityAnimations.system:
|
case AccessibilityAnimations.system:
|
||||||
|
@ -16,7 +16,7 @@ extension ExtraAccessibilityAnimationsName on AccessibilityAnimations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraAccessibilityTimeoutName on AccessibilityTimeout {
|
extension ExtraAccessibilityTimeoutView on AccessibilityTimeout {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case AccessibilityTimeout.system:
|
case AccessibilityTimeout.system:
|
||||||
|
@ -35,7 +35,7 @@ extension ExtraAccessibilityTimeoutName on AccessibilityTimeout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraAvesThemeBrightnessName on AvesThemeBrightness {
|
extension ExtraAvesThemeBrightnessView on AvesThemeBrightness {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case AvesThemeBrightness.system:
|
case AvesThemeBrightness.system:
|
||||||
|
@ -50,7 +50,7 @@ extension ExtraAvesThemeBrightnessName on AvesThemeBrightness {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraCoordinateFormatName on CoordinateFormat {
|
extension ExtraCoordinateFormatView on CoordinateFormat {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case CoordinateFormat.dms:
|
case CoordinateFormat.dms:
|
||||||
|
@ -61,7 +61,7 @@ extension ExtraCoordinateFormatName on CoordinateFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraDisplayRefreshRateModeName on DisplayRefreshRateMode {
|
extension ExtraDisplayRefreshRateModeView on DisplayRefreshRateMode {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case DisplayRefreshRateMode.auto:
|
case DisplayRefreshRateMode.auto:
|
||||||
|
@ -74,7 +74,7 @@ extension ExtraDisplayRefreshRateModeName on DisplayRefreshRateMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraEntryMapStyleName on EntryMapStyle {
|
extension ExtraEntryMapStyleView on EntryMapStyle {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case EntryMapStyle.googleNormal:
|
case EntryMapStyle.googleNormal:
|
||||||
|
@ -97,7 +97,7 @@ extension ExtraEntryMapStyleName on EntryMapStyle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraHomePageSettingName on HomePageSetting {
|
extension ExtraHomePageSettingView on HomePageSetting {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case HomePageSetting.collection:
|
case HomePageSetting.collection:
|
||||||
|
@ -108,7 +108,7 @@ extension ExtraHomePageSettingName on HomePageSetting {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraKeepScreenOnName on KeepScreenOn {
|
extension ExtraKeepScreenOnView on KeepScreenOn {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case KeepScreenOn.never:
|
case KeepScreenOn.never:
|
||||||
|
@ -123,7 +123,7 @@ extension ExtraKeepScreenOnName on KeepScreenOn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraSlideshowVideoPlaybackName on SlideshowVideoPlayback {
|
extension ExtraSlideshowVideoPlaybackView on SlideshowVideoPlayback {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case SlideshowVideoPlayback.skip:
|
case SlideshowVideoPlayback.skip:
|
||||||
|
@ -136,7 +136,7 @@ extension ExtraSlideshowVideoPlaybackName on SlideshowVideoPlayback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraSubtitlePositionName on SubtitlePosition {
|
extension ExtraSubtitlePositionView on SubtitlePosition {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case SubtitlePosition.top:
|
case SubtitlePosition.top:
|
||||||
|
@ -147,33 +147,7 @@ extension ExtraSubtitlePositionName on SubtitlePosition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraThumbnailOverlayLocationIconName on ThumbnailOverlayLocationIcon {
|
extension ExtraUnitSystemView on UnitSystem {
|
||||||
String getName(BuildContext context) {
|
|
||||||
switch (this) {
|
|
||||||
case ThumbnailOverlayLocationIcon.located:
|
|
||||||
return context.l10n.filterLocatedLabel;
|
|
||||||
case ThumbnailOverlayLocationIcon.unlocated:
|
|
||||||
return context.l10n.filterNoLocationLabel;
|
|
||||||
case ThumbnailOverlayLocationIcon.none:
|
|
||||||
return context.l10n.settingsDisabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ExtraThumbnailOverlayTagIconName on ThumbnailOverlayTagIcon {
|
|
||||||
String getName(BuildContext context) {
|
|
||||||
switch (this) {
|
|
||||||
case ThumbnailOverlayTagIcon.tagged:
|
|
||||||
return context.l10n.filterTaggedLabel;
|
|
||||||
case ThumbnailOverlayTagIcon.untagged:
|
|
||||||
return context.l10n.filterNoTagLabel;
|
|
||||||
case ThumbnailOverlayTagIcon.none:
|
|
||||||
return context.l10n.settingsDisabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ExtraUnitSystemName on UnitSystem {
|
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case UnitSystem.metric:
|
case UnitSystem.metric:
|
||||||
|
@ -184,7 +158,7 @@ extension ExtraUnitSystemName on UnitSystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraVideoAutoPlayModeName on VideoAutoPlayMode {
|
extension ExtraVideoAutoPlayModeView on VideoAutoPlayMode {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case VideoAutoPlayMode.disabled:
|
case VideoAutoPlayMode.disabled:
|
||||||
|
@ -197,7 +171,7 @@ extension ExtraVideoAutoPlayModeName on VideoAutoPlayMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraVideoBackgroundModeName on VideoBackgroundMode {
|
extension ExtraVideoBackgroundModeView on VideoBackgroundMode {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case VideoBackgroundMode.disabled:
|
case VideoBackgroundMode.disabled:
|
||||||
|
@ -208,7 +182,7 @@ extension ExtraVideoBackgroundModeName on VideoBackgroundMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraVideoControlsName on VideoControls {
|
extension ExtraVideoControlsView on VideoControls {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case VideoControls.play:
|
case VideoControls.play:
|
||||||
|
@ -223,7 +197,7 @@ extension ExtraVideoControlsName on VideoControls {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraVideoLoopModeName on VideoLoopMode {
|
extension ExtraVideoLoopModeView on VideoLoopMode {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case VideoLoopMode.never:
|
case VideoLoopMode.never:
|
||||||
|
@ -236,7 +210,7 @@ extension ExtraVideoLoopModeName on VideoLoopMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraViewerTransitionName on ViewerTransition {
|
extension ExtraViewerTransitionView on ViewerTransition {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case ViewerTransition.slide:
|
case ViewerTransition.slide:
|
||||||
|
@ -253,7 +227,7 @@ extension ExtraViewerTransitionName on ViewerTransition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraWidgetDisplayedItemName on WidgetDisplayedItem {
|
extension ExtraWidgetDisplayedItemView on WidgetDisplayedItem {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case WidgetDisplayedItem.random:
|
case WidgetDisplayedItem.random:
|
||||||
|
@ -264,7 +238,7 @@ extension ExtraWidgetDisplayedItemName on WidgetDisplayedItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraWidgetOpenPageName on WidgetOpenPage {
|
extension ExtraWidgetOpenPageView on WidgetOpenPage {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case WidgetOpenPage.home:
|
case WidgetOpenPage.home:
|
27
lib/view/src/settings/thumbnail_overlay_location_icon.dart
Normal file
27
lib/view/src/settings/thumbnail_overlay_location_icon.dart
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import 'package:aves/theme/icons.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
extension ExtraThumbnailOverlayLocationIconView on ThumbnailOverlayLocationIcon {
|
||||||
|
String getName(BuildContext context) {
|
||||||
|
switch (this) {
|
||||||
|
case ThumbnailOverlayLocationIcon.located:
|
||||||
|
return context.l10n.filterLocatedLabel;
|
||||||
|
case ThumbnailOverlayLocationIcon.unlocated:
|
||||||
|
return context.l10n.filterNoLocationLabel;
|
||||||
|
case ThumbnailOverlayLocationIcon.none:
|
||||||
|
return context.l10n.settingsDisabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconData getIcon(BuildContext context) {
|
||||||
|
switch (this) {
|
||||||
|
case ThumbnailOverlayLocationIcon.unlocated:
|
||||||
|
return AIcons.locationUnlocated;
|
||||||
|
case ThumbnailOverlayLocationIcon.located:
|
||||||
|
case ThumbnailOverlayLocationIcon.none:
|
||||||
|
return AIcons.location;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
lib/view/src/settings/thumbnail_overlay_tag_icon.dart
Normal file
28
lib/view/src/settings/thumbnail_overlay_tag_icon.dart
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import 'package:aves/theme/icons.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
extension ExtraThumbnailOverlayTagIconView on ThumbnailOverlayTagIcon {
|
||||||
|
String getName(BuildContext context) {
|
||||||
|
switch (this) {
|
||||||
|
case ThumbnailOverlayTagIcon.tagged:
|
||||||
|
return context.l10n.filterTaggedLabel;
|
||||||
|
case ThumbnailOverlayTagIcon.untagged:
|
||||||
|
return context.l10n.filterNoTagLabel;
|
||||||
|
case ThumbnailOverlayTagIcon.none:
|
||||||
|
return context.l10n.settingsDisabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconData getIcon(BuildContext context) {
|
||||||
|
switch (this) {
|
||||||
|
case ThumbnailOverlayTagIcon.tagged:
|
||||||
|
return AIcons.tag;
|
||||||
|
case ThumbnailOverlayTagIcon.untagged:
|
||||||
|
return AIcons.tagUntagged;
|
||||||
|
case ThumbnailOverlayTagIcon.none:
|
||||||
|
return AIcons.tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
lib/view/src/source/album.dart
Normal file
24
lib/view/src/source/album.dart
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
extension ExtraAlbumTypeView on AlbumType {
|
||||||
|
String? getName(BuildContext context) {
|
||||||
|
switch (this) {
|
||||||
|
case AlbumType.camera:
|
||||||
|
return context.l10n.albumCamera;
|
||||||
|
case AlbumType.download:
|
||||||
|
return context.l10n.albumDownload;
|
||||||
|
case AlbumType.screenshots:
|
||||||
|
return context.l10n.albumScreenshots;
|
||||||
|
case AlbumType.screenRecordings:
|
||||||
|
return context.l10n.albumScreenRecordings;
|
||||||
|
case AlbumType.videoCaptures:
|
||||||
|
return context.l10n.albumVideoCaptures;
|
||||||
|
case AlbumType.regular:
|
||||||
|
case AlbumType.vault:
|
||||||
|
case AlbumType.app:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
lib/view/src/source/group.dart
Normal file
62
lib/view/src/source/group.dart
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import 'package:aves/theme/icons.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
extension ExtraEntryGroupFactorView on EntryGroupFactor {
|
||||||
|
String getName(BuildContext context) {
|
||||||
|
final l10n = context.l10n;
|
||||||
|
switch (this) {
|
||||||
|
case EntryGroupFactor.album:
|
||||||
|
return l10n.collectionGroupAlbum;
|
||||||
|
case EntryGroupFactor.month:
|
||||||
|
return l10n.collectionGroupMonth;
|
||||||
|
case EntryGroupFactor.day:
|
||||||
|
return l10n.collectionGroupDay;
|
||||||
|
case EntryGroupFactor.none:
|
||||||
|
return l10n.collectionGroupNone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconData get icon {
|
||||||
|
switch (this) {
|
||||||
|
case EntryGroupFactor.album:
|
||||||
|
return AIcons.album;
|
||||||
|
case EntryGroupFactor.month:
|
||||||
|
return AIcons.dateByMonth;
|
||||||
|
case EntryGroupFactor.day:
|
||||||
|
return AIcons.dateByDay;
|
||||||
|
case EntryGroupFactor.none:
|
||||||
|
return AIcons.clear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ExtraAlbumChipGroupFactorView on AlbumChipGroupFactor {
|
||||||
|
String getName(BuildContext context) {
|
||||||
|
final l10n = context.l10n;
|
||||||
|
switch (this) {
|
||||||
|
case AlbumChipGroupFactor.importance:
|
||||||
|
return l10n.albumGroupTier;
|
||||||
|
case AlbumChipGroupFactor.mimeType:
|
||||||
|
return l10n.albumGroupType;
|
||||||
|
case AlbumChipGroupFactor.volume:
|
||||||
|
return l10n.albumGroupVolume;
|
||||||
|
case AlbumChipGroupFactor.none:
|
||||||
|
return l10n.albumGroupNone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconData get icon {
|
||||||
|
switch (this) {
|
||||||
|
case AlbumChipGroupFactor.importance:
|
||||||
|
return AIcons.important;
|
||||||
|
case AlbumChipGroupFactor.mimeType:
|
||||||
|
return AIcons.mimeType;
|
||||||
|
case AlbumChipGroupFactor.volume:
|
||||||
|
return AIcons.removableStorage;
|
||||||
|
case AlbumChipGroupFactor.none:
|
||||||
|
return AIcons.clear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
lib/view/src/source/layout.dart
Normal file
29
lib/view/src/source/layout.dart
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import 'package:aves/theme/icons.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
extension ExtraTileLayoutView on TileLayout {
|
||||||
|
String getName(BuildContext context) {
|
||||||
|
final l10n = context.l10n;
|
||||||
|
switch (this) {
|
||||||
|
case TileLayout.mosaic:
|
||||||
|
return l10n.tileLayoutMosaic;
|
||||||
|
case TileLayout.grid:
|
||||||
|
return l10n.tileLayoutGrid;
|
||||||
|
case TileLayout.list:
|
||||||
|
return l10n.tileLayoutList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconData get icon {
|
||||||
|
switch (this) {
|
||||||
|
case TileLayout.mosaic:
|
||||||
|
return AIcons.layoutMosaic;
|
||||||
|
case TileLayout.grid:
|
||||||
|
return AIcons.layoutGrid;
|
||||||
|
case TileLayout.list:
|
||||||
|
return AIcons.layoutList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
extension ExtraEntrySortFactor on EntrySortFactor {
|
extension ExtraEntrySortFactorView on EntrySortFactor {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
final l10n = context.l10n;
|
final l10n = context.l10n;
|
||||||
switch (this) {
|
switch (this) {
|
||||||
|
@ -46,7 +46,7 @@ extension ExtraEntrySortFactor on EntrySortFactor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraChipSortFactor on ChipSortFactor {
|
extension ExtraChipSortFactorView on ChipSortFactor {
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
final l10n = context.l10n;
|
final l10n = context.l10n;
|
||||||
switch (this) {
|
switch (this) {
|
||||||
|
@ -87,86 +87,3 @@ extension ExtraChipSortFactor on ChipSortFactor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ExtraEntryGroupFactor on EntryGroupFactor {
|
|
||||||
String getName(BuildContext context) {
|
|
||||||
final l10n = context.l10n;
|
|
||||||
switch (this) {
|
|
||||||
case EntryGroupFactor.album:
|
|
||||||
return l10n.collectionGroupAlbum;
|
|
||||||
case EntryGroupFactor.month:
|
|
||||||
return l10n.collectionGroupMonth;
|
|
||||||
case EntryGroupFactor.day:
|
|
||||||
return l10n.collectionGroupDay;
|
|
||||||
case EntryGroupFactor.none:
|
|
||||||
return l10n.collectionGroupNone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IconData get icon {
|
|
||||||
switch (this) {
|
|
||||||
case EntryGroupFactor.album:
|
|
||||||
return AIcons.album;
|
|
||||||
case EntryGroupFactor.month:
|
|
||||||
return AIcons.dateByMonth;
|
|
||||||
case EntryGroupFactor.day:
|
|
||||||
return AIcons.dateByDay;
|
|
||||||
case EntryGroupFactor.none:
|
|
||||||
return AIcons.clear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ExtraAlbumChipGroupFactor on AlbumChipGroupFactor {
|
|
||||||
String getName(BuildContext context) {
|
|
||||||
final l10n = context.l10n;
|
|
||||||
switch (this) {
|
|
||||||
case AlbumChipGroupFactor.importance:
|
|
||||||
return l10n.albumGroupTier;
|
|
||||||
case AlbumChipGroupFactor.mimeType:
|
|
||||||
return l10n.albumGroupType;
|
|
||||||
case AlbumChipGroupFactor.volume:
|
|
||||||
return l10n.albumGroupVolume;
|
|
||||||
case AlbumChipGroupFactor.none:
|
|
||||||
return l10n.albumGroupNone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IconData get icon {
|
|
||||||
switch (this) {
|
|
||||||
case AlbumChipGroupFactor.importance:
|
|
||||||
return AIcons.important;
|
|
||||||
case AlbumChipGroupFactor.mimeType:
|
|
||||||
return AIcons.mimeType;
|
|
||||||
case AlbumChipGroupFactor.volume:
|
|
||||||
return AIcons.removableStorage;
|
|
||||||
case AlbumChipGroupFactor.none:
|
|
||||||
return AIcons.clear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ExtraTileLayout on TileLayout {
|
|
||||||
String getName(BuildContext context) {
|
|
||||||
final l10n = context.l10n;
|
|
||||||
switch (this) {
|
|
||||||
case TileLayout.mosaic:
|
|
||||||
return l10n.tileLayoutMosaic;
|
|
||||||
case TileLayout.grid:
|
|
||||||
return l10n.tileLayoutGrid;
|
|
||||||
case TileLayout.list:
|
|
||||||
return l10n.tileLayoutList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IconData get icon {
|
|
||||||
switch (this) {
|
|
||||||
case TileLayout.mosaic:
|
|
||||||
return AIcons.layoutMosaic;
|
|
||||||
case TileLayout.grid:
|
|
||||||
return AIcons.layoutGrid;
|
|
||||||
case TileLayout.list:
|
|
||||||
return AIcons.layoutList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:aves/l10n/l10n.dart';
|
import 'package:aves/l10n/l10n.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
|
||||||
extension ExtraSourceState on SourceState {
|
extension ExtraSourceStateView on SourceState {
|
||||||
String? getName(AppLocalizations l10n) {
|
String? getName(AppLocalizations l10n) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case SourceState.loading:
|
case SourceState.loading:
|
|
@ -1,9 +1,8 @@
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
enum VaultLockType { system, pattern, pin, password }
|
extension ExtraVaultLockTypeView on VaultLockType {
|
||||||
|
|
||||||
extension ExtraVaultLockType on VaultLockType {
|
|
||||||
String getText(BuildContext context) {
|
String getText(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case VaultLockType.system:
|
case VaultLockType.system:
|
12
lib/view/src/storage/relative_dir.dart
Normal file
12
lib/view/src/storage/relative_dir.dart
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
extension ExtraVolumeRelativeDirectoryView on VolumeRelativeDirectory {
|
||||||
|
String getVolumeDescription(BuildContext context) {
|
||||||
|
final volume = androidFileUtils.storageVolumes.firstWhereOrNull((volume) => volume.path == volumePath);
|
||||||
|
return volume?.getDescription(context) ?? volumePath;
|
||||||
|
}
|
||||||
|
}
|
15
lib/view/src/storage/volume.dart
Normal file
15
lib/view/src/storage/volume.dart
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
extension ExtraStorageVolumeView on StorageVolume {
|
||||||
|
String getDescription(BuildContext? context) {
|
||||||
|
if (description != null) return description!;
|
||||||
|
// ideally, the context should always be provided, but in some cases (e.g. album comparison),
|
||||||
|
// this would require numerous additional methods to have the context as argument
|
||||||
|
// for such a minor benefit: fallback volume description on Android < N
|
||||||
|
final l10n = context?.l10n;
|
||||||
|
if (isPrimary) return l10n?.storageVolumeDescriptionFallbackPrimary ?? 'Internal Storage';
|
||||||
|
return l10n?.storageVolumeDescriptionFallbackNonPrimary ?? 'SD card';
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
enum WallpaperTarget { home, lock, homeLock }
|
extension ExtraWallpaperTargetView on WallpaperTarget {
|
||||||
|
|
||||||
extension ExtraWallpaperTarget on WallpaperTarget {
|
|
||||||
String getName(BuildContext context) {
|
String getName(BuildContext context) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case WallpaperTarget.home:
|
case WallpaperTarget.home:
|
67
lib/view/src/xmp.dart
Normal file
67
lib/view/src/xmp.dart
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import 'package:aves/ref/metadata/xmp.dart';
|
||||||
|
|
||||||
|
class XmpNamespaceView {
|
||||||
|
// cf https://exiftool.org/TagNames/XMP.html
|
||||||
|
static const Map<String, String> nsTitles = {
|
||||||
|
XmpNamespaces.acdsee: 'ACDSee',
|
||||||
|
XmpNamespaces.adsmlat: 'AdsML',
|
||||||
|
XmpNamespaces.exifAux: 'Exif Aux',
|
||||||
|
XmpNamespaces.avm: 'Astronomy Visualization',
|
||||||
|
XmpNamespaces.camera: 'Pix4D Camera',
|
||||||
|
XmpNamespaces.cc: 'Creative Commons',
|
||||||
|
XmpNamespaces.crd: 'Camera Raw Defaults',
|
||||||
|
XmpNamespaces.creatorAtom: 'After Effects',
|
||||||
|
XmpNamespaces.crs: 'Camera Raw Settings',
|
||||||
|
XmpNamespaces.crss: 'Camera Raw Saved Settings',
|
||||||
|
XmpNamespaces.darktable: 'darktable',
|
||||||
|
XmpNamespaces.dc: 'Dublin Core',
|
||||||
|
XmpNamespaces.digiKam: 'digiKam',
|
||||||
|
XmpNamespaces.droneDji: 'DJI Drone',
|
||||||
|
XmpNamespaces.dwc: 'Darwin Core',
|
||||||
|
XmpNamespaces.exif: 'Exif',
|
||||||
|
XmpNamespaces.exifEx: 'Exif Ex',
|
||||||
|
XmpNamespaces.fstop: 'F-Stop',
|
||||||
|
XmpNamespaces.gAudio: 'Google Audio',
|
||||||
|
XmpNamespaces.gCamera: 'Google Camera',
|
||||||
|
XmpNamespaces.gContainer: 'Google Container',
|
||||||
|
XmpNamespaces.gCreations: 'Google Creations',
|
||||||
|
XmpNamespaces.gDepth: 'Google Depth',
|
||||||
|
XmpNamespaces.gDevice: 'Google Device',
|
||||||
|
XmpNamespaces.gFocus: 'Google Focus',
|
||||||
|
XmpNamespaces.gImage: 'Google Image',
|
||||||
|
XmpNamespaces.gPano: 'Google Panorama',
|
||||||
|
XmpNamespaces.gSpherical: 'Google Spherical',
|
||||||
|
XmpNamespaces.gettyImagesGift: 'Getty Images',
|
||||||
|
XmpNamespaces.gimp210: 'GIMP 2.10',
|
||||||
|
XmpNamespaces.gimpXmp: 'GIMP',
|
||||||
|
XmpNamespaces.illustrator: 'Illustrator',
|
||||||
|
XmpNamespaces.iptc4xmpCore: 'IPTC Core',
|
||||||
|
XmpNamespaces.iptc4xmpExt: 'IPTC Extension',
|
||||||
|
XmpNamespaces.lr: 'Lightroom',
|
||||||
|
XmpNamespaces.mediapro: 'MediaPro',
|
||||||
|
XmpNamespaces.miCamera: 'Mi Camera',
|
||||||
|
XmpNamespaces.microsoftPhoto: 'Microsoft Photo 1.0',
|
||||||
|
XmpNamespaces.mp1: 'Microsoft Photo 1.1',
|
||||||
|
XmpNamespaces.mp: 'Microsoft Photo 1.2',
|
||||||
|
XmpNamespaces.mwgrs: 'Regions',
|
||||||
|
XmpNamespaces.nga: 'National Gallery of Art',
|
||||||
|
XmpNamespaces.opMedia: 'OnePlus Media',
|
||||||
|
XmpNamespaces.panorama: 'Panorama',
|
||||||
|
XmpNamespaces.panoStudio: 'PanoramaStudio',
|
||||||
|
XmpNamespaces.pdf: 'PDF',
|
||||||
|
XmpNamespaces.pdfX: 'PDF/X',
|
||||||
|
XmpNamespaces.photoMechanic: 'Photo Mechanic',
|
||||||
|
XmpNamespaces.photoshop: 'Photoshop',
|
||||||
|
XmpNamespaces.plus: 'PLUS',
|
||||||
|
XmpNamespaces.pmtm: 'Photomatix',
|
||||||
|
XmpNamespaces.tiff: 'TIFF',
|
||||||
|
XmpNamespaces.xmp: 'Basic',
|
||||||
|
XmpNamespaces.xmpBJ: 'Basic Job Ticket',
|
||||||
|
XmpNamespaces.xmpDM: 'Dynamic Media',
|
||||||
|
XmpNamespaces.xmpMM: 'Media Management',
|
||||||
|
XmpNamespaces.xmpNote: 'Note',
|
||||||
|
XmpNamespaces.xmpRights: 'Rights Management',
|
||||||
|
XmpNamespaces.xmpTPg: 'Paged-Text',
|
||||||
|
XmpNamespaces.xperiaCamera: 'Xperia Camera',
|
||||||
|
};
|
||||||
|
}
|
27
lib/view/view.dart
Normal file
27
lib/view/view.dart
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
export 'src/actions/chip.dart';
|
||||||
|
export 'src/actions/chip_set.dart';
|
||||||
|
export 'src/actions/entry.dart';
|
||||||
|
export 'src/actions/entry_set.dart';
|
||||||
|
export 'src/actions/map.dart';
|
||||||
|
export 'src/actions/map_cluster.dart';
|
||||||
|
export 'src/actions/share.dart';
|
||||||
|
export 'src/actions/slideshow.dart';
|
||||||
|
export 'src/metadata/date_edit_action.dart';
|
||||||
|
export 'src/metadata/date_field_source.dart';
|
||||||
|
export 'src/metadata/fields.dart';
|
||||||
|
export 'src/metadata/length_unit.dart';
|
||||||
|
export 'src/metadata/location_edit_action.dart';
|
||||||
|
export 'src/metadata/metadata_type.dart';
|
||||||
|
export 'src/settings/enums.dart';
|
||||||
|
export 'src/settings/thumbnail_overlay_location_icon.dart';
|
||||||
|
export 'src/settings/thumbnail_overlay_tag_icon.dart';
|
||||||
|
export 'src/source/album.dart';
|
||||||
|
export 'src/source/group.dart';
|
||||||
|
export 'src/source/layout.dart';
|
||||||
|
export 'src/source/sort.dart';
|
||||||
|
export 'src/source/state.dart';
|
||||||
|
export 'src/source/vault.dart';
|
||||||
|
export 'src/storage/relative_dir.dart';
|
||||||
|
export 'src/storage/volume.dart';
|
||||||
|
export 'src/wallpaper_target.dart';
|
||||||
|
export 'src/xmp.dart';
|
|
@ -1,7 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/app_mode.dart';
|
import 'package:aves/app_mode.dart';
|
||||||
import 'package:aves/model/actions/entry_set.dart';
|
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
import 'package:aves/model/filters/query.dart';
|
import 'package:aves/model/filters/query.dart';
|
||||||
|
@ -11,10 +10,9 @@ import 'package:aves/model/selection.dart';
|
||||||
import 'package:aves/model/settings/settings.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/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/source/enums/view.dart';
|
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
|
import 'package:aves/view/view.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/collection/entry_set_action_delegate.dart';
|
||||||
import 'package:aves/widgets/collection/filter_bar.dart';
|
import 'package:aves/widgets/collection/filter_bar.dart';
|
||||||
|
|
|
@ -10,7 +10,6 @@ import 'package:aves/model/selection.dart';
|
||||||
import 'package:aves/model/settings/settings.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/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/source/section_keys.dart';
|
import 'package:aves/model/source/section_keys.dart';
|
||||||
import 'package:aves/ref/mime_types.dart';
|
import 'package:aves/ref/mime_types.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
|
@ -45,6 +44,7 @@ import 'package:aves/widgets/common/thumbnail/notifications.dart';
|
||||||
import 'package:aves/widgets/common/tile_extent_controller.dart';
|
import 'package:aves/widgets/common/tile_extent_controller.dart';
|
||||||
import 'package:aves/widgets/navigation/nav_bar/nav_bar.dart';
|
import 'package:aves/widgets/navigation/nav_bar/nav_bar.dart';
|
||||||
import 'package:aves/widgets/viewer/entry_viewer_page.dart';
|
import 'package:aves/widgets/viewer/entry_viewer_page.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
|
@ -2,11 +2,11 @@ import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/filters/rating.dart';
|
import 'package:aves/model/filters/rating.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/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/utils/file_utils.dart';
|
import 'package:aves/utils/file_utils.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/grid/draggable_thumb_label.dart';
|
import 'package:aves/widgets/common/grid/draggable_thumb_label.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/list_layout.dart';
|
import 'package:aves/widgets/common/grid/sections/list_layout.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import 'package:aves/model/covers.dart';
|
import 'package:aves/model/covers.dart';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/source/section_keys.dart';
|
import 'package:aves/model/source/section_keys.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/grid/header.dart';
|
import 'package:aves/widgets/common/grid/header.dart';
|
||||||
import 'package:aves/widgets/common/identity/aves_icons.dart';
|
import 'package:aves/widgets/common/identity/aves_icons.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class AlbumSectionHeader extends StatelessWidget {
|
class AlbumSectionHeader extends StatelessWidget {
|
||||||
|
|
|
@ -3,12 +3,12 @@ import 'dart:math';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.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/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/source/section_keys.dart';
|
import 'package:aves/model/source/section_keys.dart';
|
||||||
import 'package:aves/widgets/collection/grid/headers/album.dart';
|
import 'package:aves/widgets/collection/grid/headers/album.dart';
|
||||||
import 'package:aves/widgets/collection/grid/headers/date.dart';
|
import 'package:aves/widgets/collection/grid/headers/date.dart';
|
||||||
import 'package:aves/widgets/collection/grid/headers/rating.dart';
|
import 'package:aves/widgets/collection/grid/headers/rating.dart';
|
||||||
import 'package:aves/widgets/common/grid/header.dart';
|
import 'package:aves/widgets/common/grid/header.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class CollectionSectionHeader extends StatelessWidget {
|
class CollectionSectionHeader extends StatelessWidget {
|
||||||
|
|
|
@ -2,13 +2,13 @@ import 'package:aves/app_mode.dart';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/selection.dart';
|
import 'package:aves/model/selection.dart';
|
||||||
import 'package:aves/model/source/collection_lens.dart';
|
import 'package:aves/model/source/collection_lens.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/services/intent_service.dart';
|
import 'package:aves/services/intent_service.dart';
|
||||||
import 'package:aves/widgets/collection/grid/list_details.dart';
|
import 'package:aves/widgets/collection/grid/list_details.dart';
|
||||||
import 'package:aves/widgets/collection/grid/list_details_theme.dart';
|
import 'package:aves/widgets/collection/grid/list_details_theme.dart';
|
||||||
import 'package:aves/widgets/common/grid/scaling.dart';
|
import 'package:aves/widgets/common/grid/scaling.dart';
|
||||||
import 'package:aves/widgets/common/thumbnail/decorated.dart';
|
import 'package:aves/widgets/common/thumbnail/decorated.dart';
|
||||||
import 'package:aves/widgets/common/thumbnail/notifications.dart';
|
import 'package:aves/widgets/common/thumbnail/notifications.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:aves/model/actions/entry.dart';
|
|
||||||
import 'package:aves/model/filters/album.dart';
|
import 'package:aves/model/filters/album.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/action_controls/quick_choosers/album_chooser.dart';
|
import 'package:aves/widgets/common/action_controls/quick_choosers/album_chooser.dart';
|
||||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/button.dart';
|
import 'package:aves/widgets/common/action_controls/quick_choosers/common/button.dart';
|
||||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/menu.dart';
|
import 'package:aves/widgets/common/action_controls/quick_choosers/common/menu.dart';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:aves/model/actions/entry.dart';
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/button.dart';
|
import 'package:aves/widgets/common/action_controls/quick_choosers/common/button.dart';
|
||||||
import 'package:aves/widgets/common/action_controls/quick_choosers/rate_chooser.dart';
|
import 'package:aves/widgets/common/action_controls/quick_choosers/rate_chooser.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:aves/model/actions/entry.dart';
|
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/multipage.dart';
|
import 'package:aves/model/entry/extensions/multipage.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/button.dart';
|
import 'package:aves/widgets/common/action_controls/quick_choosers/common/button.dart';
|
||||||
import 'package:aves/widgets/common/action_controls/quick_choosers/share_chooser.dart';
|
import 'package:aves/widgets/common/action_controls/quick_choosers/share_chooser.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:aves/model/actions/share.dart';
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/menu.dart';
|
import 'package:aves/widgets/common/action_controls/quick_choosers/common/menu.dart';
|
||||||
import 'package:aves/widgets/common/basic/popup/menu_row.dart';
|
import 'package:aves/widgets/common/basic/popup/menu_row.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:aves/model/actions/entry.dart';
|
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
import 'package:aves/model/filters/tag.dart';
|
import 'package:aves/model/filters/tag.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/button.dart';
|
import 'package:aves/widgets/common/action_controls/quick_choosers/common/button.dart';
|
||||||
import 'package:aves/widgets/common/action_controls/quick_choosers/common/menu.dart';
|
import 'package:aves/widgets/common/action_controls/quick_choosers/common/menu.dart';
|
||||||
import 'package:aves/widgets/common/action_controls/quick_choosers/tag_chooser.dart';
|
import 'package:aves/widgets/common/action_controls/quick_choosers/tag_chooser.dart';
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/props.dart';
|
import 'package:aves/model/entry/extensions/props.dart';
|
||||||
import 'package:aves/model/storage/relative_dir.dart';
|
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
@ -25,7 +27,7 @@ mixin PermissionAwareMixin {
|
||||||
final uris = <String>[], mimeTypes = <String>[];
|
final uris = <String>[], mimeTypes = <String>[];
|
||||||
entries.where((entry) {
|
entries.where((entry) {
|
||||||
final dir = entry.directory;
|
final dir = entry.directory;
|
||||||
return dir != null && restrictedInaccessibleDirs.contains(VolumeRelativeDirectory.fromPath(dir));
|
return dir != null && restrictedInaccessibleDirs.contains(androidFileUtils.relativeDirectoryFromPath(dir));
|
||||||
}).forEach((entry) {
|
}).forEach((entry) {
|
||||||
uris.add(entry.uri);
|
uris.add(entry.uri);
|
||||||
mimeTypes.add(entry.mimeType);
|
mimeTypes.add(entry.mimeType);
|
||||||
|
|
|
@ -2,11 +2,11 @@ import 'dart:async';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/storage/volume.dart';
|
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
import 'package:aves/utils/collection_utils.dart';
|
import 'package:aves/utils/collection_utils.dart';
|
||||||
import 'package:aves/utils/file_utils.dart';
|
import 'package:aves/utils/file_utils.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
||||||
import 'package:aves_model/aves_model.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
|
|
@ -1,13 +1,81 @@
|
||||||
import 'package:aves/model/filters/album.dart';
|
import 'package:aves/model/filters/album.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
|
import 'package:aves/model/vaults/details.dart';
|
||||||
import 'package:aves/model/vaults/vaults.dart';
|
import 'package:aves/model/vaults/vaults.dart';
|
||||||
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves/widgets/dialogs/aves_dialog.dart';
|
||||||
|
import 'package:aves/widgets/dialogs/filter_editors/password_dialog.dart';
|
||||||
|
import 'package:aves/widgets/dialogs/filter_editors/pattern_dialog.dart';
|
||||||
|
import 'package:aves/widgets/dialogs/filter_editors/pin_dialog.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:local_auth/error_codes.dart' as auth_error;
|
||||||
|
import 'package:local_auth/local_auth.dart';
|
||||||
|
|
||||||
mixin VaultAwareMixin on FeedbackMixin {
|
mixin VaultAwareMixin on FeedbackMixin {
|
||||||
|
Future<bool> _tryUnlock(String dirPath, BuildContext context) async {
|
||||||
|
if (!vaults.isVault(dirPath) || !vaults.isLocked(dirPath)) return true;
|
||||||
|
|
||||||
|
final details = vaults.detailsForPath(dirPath);
|
||||||
|
if (details == null) return false;
|
||||||
|
|
||||||
|
bool? confirmed;
|
||||||
|
switch (details.lockType) {
|
||||||
|
case VaultLockType.system:
|
||||||
|
try {
|
||||||
|
confirmed = await LocalAuthentication().authenticate(
|
||||||
|
localizedReason: context.l10n.authenticateToUnlockVault,
|
||||||
|
);
|
||||||
|
} on PlatformException catch (e, stack) {
|
||||||
|
if (e.code != 'auth_in_progress') {
|
||||||
|
// `auth_in_progress`: `Authentication in progress`
|
||||||
|
await reportService.recordError(e, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VaultLockType.pattern:
|
||||||
|
final pattern = await showDialog<String>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => const PatternDialog(needConfirmation: false),
|
||||||
|
routeSettings: const RouteSettings(name: PatternDialog.routeName),
|
||||||
|
);
|
||||||
|
if (pattern != null) {
|
||||||
|
confirmed = pattern == await securityService.readValue(details.passKey);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VaultLockType.pin:
|
||||||
|
final pin = await showDialog<String>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => const PinDialog(needConfirmation: false),
|
||||||
|
routeSettings: const RouteSettings(name: PinDialog.routeName),
|
||||||
|
);
|
||||||
|
if (pin != null) {
|
||||||
|
confirmed = pin == await securityService.readValue(details.passKey);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VaultLockType.password:
|
||||||
|
final password = await showDialog<String>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => const PasswordDialog(needConfirmation: false),
|
||||||
|
routeSettings: const RouteSettings(name: PasswordDialog.routeName),
|
||||||
|
);
|
||||||
|
if (password != null) {
|
||||||
|
confirmed = password == await securityService.readValue(details.passKey);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (confirmed == null || !confirmed) return false;
|
||||||
|
|
||||||
|
vaults.unlock(dirPath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> unlockAlbum(BuildContext context, String dirPath) async {
|
Future<bool> unlockAlbum(BuildContext context, String dirPath) async {
|
||||||
final success = await vaults.tryUnlock(dirPath, context);
|
final success = await _tryUnlock(dirPath, context);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
showFeedback(context, context.l10n.genericFailureFeedback);
|
showFeedback(context, context.l10n.genericFailureFeedback);
|
||||||
}
|
}
|
||||||
|
@ -29,4 +97,60 @@ mixin VaultAwareMixin on FeedbackMixin {
|
||||||
}
|
}
|
||||||
|
|
||||||
void lockFilters(Set<AlbumFilter> filters) => vaults.lock(filters.map((v) => v.album).toSet());
|
void lockFilters(Set<AlbumFilter> filters) => vaults.lock(filters.map((v) => v.album).toSet());
|
||||||
|
|
||||||
|
Future<bool> setVaultPass(BuildContext context, VaultDetails details) async {
|
||||||
|
switch (details.lockType) {
|
||||||
|
case VaultLockType.system:
|
||||||
|
final l10n = context.l10n;
|
||||||
|
try {
|
||||||
|
return await LocalAuthentication().authenticate(
|
||||||
|
localizedReason: l10n.authenticateToConfigureVault,
|
||||||
|
);
|
||||||
|
} on PlatformException catch (e, stack) {
|
||||||
|
await showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AvesDialog(
|
||||||
|
content: Text(e.message ?? l10n.genericFailureFeedback),
|
||||||
|
actions: const [OkButton()],
|
||||||
|
),
|
||||||
|
routeSettings: const RouteSettings(name: AvesDialog.warningRouteName),
|
||||||
|
);
|
||||||
|
if (e.code != auth_error.notAvailable) {
|
||||||
|
await reportService.recordError(e, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VaultLockType.pattern:
|
||||||
|
final pattern = await showDialog<String>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => const PatternDialog(needConfirmation: true),
|
||||||
|
routeSettings: const RouteSettings(name: PatternDialog.routeName),
|
||||||
|
);
|
||||||
|
if (pattern != null) {
|
||||||
|
return await securityService.writeValue(details.passKey, pattern);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VaultLockType.pin:
|
||||||
|
final pin = await showDialog<String>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => const PinDialog(needConfirmation: true),
|
||||||
|
routeSettings: const RouteSettings(name: PinDialog.routeName),
|
||||||
|
);
|
||||||
|
if (pin != null) {
|
||||||
|
return await securityService.writeValue(details.passKey, pin);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VaultLockType.password:
|
||||||
|
final password = await showDialog<String>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => const PasswordDialog(needConfirmation: true),
|
||||||
|
routeSettings: const RouteSettings(name: PasswordDialog.routeName),
|
||||||
|
);
|
||||||
|
if (password != null) {
|
||||||
|
return await securityService.writeValue(details.passKey, password);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/source/events.dart';
|
import 'package:aves/model/source/events.dart';
|
||||||
import 'package:aves/model/source/source_state.dart';
|
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class SourceStateAwareAppBarTitle extends StatelessWidget {
|
class SourceStateAwareAppBarTitle extends StatelessWidget {
|
||||||
|
|
|
@ -2,9 +2,9 @@ import 'dart:async';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:aves/model/highlight.dart';
|
import 'package:aves/model/highlight.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/list_layout.dart';
|
import 'package:aves/widgets/common/grid/sections/list_layout.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import 'package:aves/model/highlight.dart';
|
import 'package:aves/model/highlight.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/widgets/common/behaviour/eager_scale_gesture_recognizer.dart';
|
import 'package:aves/widgets/common/behaviour/eager_scale_gesture_recognizer.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/fixed/scale_overlay.dart';
|
import 'package:aves/widgets/common/grid/sections/fixed/scale_overlay.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/mosaic/scale_overlay.dart';
|
import 'package:aves/widgets/common/grid/sections/mosaic/scale_overlay.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/section_layout_builder.dart';
|
import 'package:aves/widgets/common/grid/sections/section_layout_builder.dart';
|
||||||
import 'package:aves/widgets/common/grid/theme.dart';
|
import 'package:aves/widgets/common/grid/theme.dart';
|
||||||
import 'package:aves/widgets/common/tile_extent_controller.dart';
|
import 'package:aves/widgets/common/tile_extent_controller.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class FixedExtentGridPainter extends CustomPainter {
|
class FixedExtentGridPainter extends CustomPainter {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/utils/colors.dart';
|
import 'package:aves/utils/colors.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/source/section_keys.dart';
|
import 'package:aves/model/source/section_keys.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/fixed/section_layout_builder.dart';
|
import 'package:aves/widgets/common/grid/sections/fixed/section_layout_builder.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/list_layout.dart';
|
import 'package:aves/widgets/common/grid/sections/list_layout.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/mosaic/section_layout_builder.dart';
|
import 'package:aves/widgets/common/grid/sections/mosaic/section_layout_builder.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/section_layout_builder.dart';
|
import 'package:aves/widgets/common/grid/sections/section_layout_builder.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/source/section_keys.dart';
|
import 'package:aves/model/source/section_keys.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/list_layout.dart';
|
import 'package:aves/widgets/common/grid/sections/list_layout.dart';
|
||||||
import 'package:aves/widgets/common/grid/sections/section_layout.dart';
|
import 'package:aves/widgets/common/grid/sections/section_layout.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
|
@ -2,7 +2,6 @@ import 'dart:async';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:aves/app_mode.dart';
|
import 'package:aves/app_mode.dart';
|
||||||
import 'package:aves/model/actions/chip.dart';
|
|
||||||
import 'package:aves/model/covers.dart';
|
import 'package:aves/model/covers.dart';
|
||||||
import 'package:aves/model/filters/album.dart';
|
import 'package:aves/model/filters/album.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
|
@ -13,6 +12,7 @@ import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/theme/colors.dart';
|
import 'package:aves/theme/colors.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/collection/filter_bar.dart';
|
import 'package:aves/widgets/collection/filter_bar.dart';
|
||||||
import 'package:aves/widgets/common/basic/font_size_icon_theme.dart';
|
import 'package:aves/widgets/common/basic/font_size_icon_theme.dart';
|
||||||
import 'package:aves/widgets/common/basic/popup/menu_row.dart';
|
import 'package:aves/widgets/common/basic/popup/menu_row.dart';
|
||||||
|
|
|
@ -3,11 +3,11 @@ import 'package:aves/model/covers.dart';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/multipage.dart';
|
import 'package:aves/model/entry/extensions/multipage.dart';
|
||||||
import 'package:aves/model/entry/extensions/props.dart';
|
import 'package:aves/model/entry/extensions/props.dart';
|
||||||
import 'package:aves/model/source/enums/enums.dart';
|
|
||||||
import 'package:aves/model/vaults/vaults.dart';
|
import 'package:aves/model/vaults/vaults.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/grid/theme.dart';
|
import 'package:aves/widgets/common/grid/theme.dart';
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:aves/model/actions/map.dart';
|
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/map/buttons/button.dart';
|
import 'package:aves/widgets/common/map/buttons/button.dart';
|
||||||
import 'package:aves/widgets/common/map/buttons/coordinate_filter.dart';
|
import 'package:aves/widgets/common/map/buttons/coordinate_filter.dart';
|
||||||
|
|
|
@ -6,7 +6,6 @@ import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/images.dart';
|
import 'package:aves/model/entry/extensions/images.dart';
|
||||||
import 'package:aves/model/entry/extensions/location.dart';
|
import 'package:aves/model/entry/extensions/location.dart';
|
||||||
import 'package:aves/model/entry/sort.dart';
|
import 'package:aves/model/entry/sort.dart';
|
||||||
import 'package:aves/model/settings/enums/l10n.dart';
|
|
||||||
import 'package:aves/model/settings/enums/map_style.dart';
|
import 'package:aves/model/settings/enums/map_style.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/ref/poi.dart';
|
import 'package:aves/ref/poi.dart';
|
||||||
|
@ -14,6 +13,7 @@ import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/utils/math_utils.dart';
|
import 'package:aves/utils/math_utils.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/identity/buttons/overlay_button.dart';
|
import 'package:aves/widgets/common/identity/buttons/overlay_button.dart';
|
||||||
import 'package:aves/widgets/common/map/attribution.dart';
|
import 'package:aves/widgets/common/map/attribution.dart';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:aves/model/settings/enums/l10n.dart';
|
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/dialogs/selection_dialogs/common.dart';
|
import 'package:aves/widgets/dialogs/selection_dialogs/common.dart';
|
||||||
import 'package:aves/widgets/dialogs/selection_dialogs/single_selection.dart';
|
import 'package:aves/widgets/dialogs/selection_dialogs/single_selection.dart';
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
import 'package:aves/utils/file_utils.dart';
|
import 'package:aves/utils/file_utils.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
import 'package:aves/widgets/common/identity/aves_expansion_tile.dart';
|
||||||
import 'package:aves/widgets/viewer/info/common.dart';
|
import 'package:aves/widgets/viewer/info/common.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import 'package:aves/model/app/support.dart';
|
import 'package:aves/model/app/support.dart';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/metadata/enums/length_unit.dart';
|
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/ref/mime_types.dart';
|
import 'package:aves/ref/mime_types.dart';
|
||||||
import 'package:aves/services/media/media_edit_service.dart';
|
import 'package:aves/services/media/media_edit_service.dart';
|
||||||
|
@ -8,6 +7,7 @@ import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/theme/text.dart';
|
import 'package:aves/theme/text.dart';
|
||||||
import 'package:aves/theme/themes.dart';
|
import 'package:aves/theme/themes.dart';
|
||||||
import 'package:aves/utils/mime_utils.dart';
|
import 'package:aves/utils/mime_utils.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/basic/text_dropdown_button.dart';
|
import 'package:aves/widgets/common/basic/text_dropdown_button.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/fx/transitions.dart';
|
import 'package:aves/widgets/common/fx/transitions.dart';
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/metadata/date_modifier.dart';
|
import 'package:aves/model/metadata/date_modifier.dart';
|
||||||
import 'package:aves/model/metadata/enums/date_edit_action.dart';
|
|
||||||
import 'package:aves/model/metadata/enums/date_field_source.dart';
|
|
||||||
import 'package:aves/model/metadata/fields.dart';
|
|
||||||
import 'package:aves/model/source/collection_lens.dart';
|
import 'package:aves/model/source/collection_lens.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/theme/format.dart';
|
import 'package:aves/theme/format.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/theme/themes.dart';
|
import 'package:aves/theme/themes.dart';
|
||||||
import 'package:aves/utils/time_utils.dart';
|
import 'package:aves/utils/time_utils.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/basic/text_dropdown_button.dart';
|
import 'package:aves/widgets/common/basic/text_dropdown_button.dart';
|
||||||
import 'package:aves/widgets/common/basic/wheel.dart';
|
import 'package:aves/widgets/common/basic/wheel.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/extensions/location.dart';
|
import 'package:aves/model/entry/extensions/location.dart';
|
||||||
import 'package:aves/model/entry/extensions/metadata_edition.dart';
|
import 'package:aves/model/entry/extensions/metadata_edition.dart';
|
||||||
import 'package:aves/model/metadata/enums/location_edit_action.dart';
|
|
||||||
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
import 'package:aves/model/settings/enums/coordinate_format.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/collection_lens.dart';
|
import 'package:aves/model/source/collection_lens.dart';
|
||||||
|
@ -9,6 +8,7 @@ import 'package:aves/ref/poi.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/theme/themes.dart';
|
import 'package:aves/theme/themes.dart';
|
||||||
|
import 'package:aves/view/view.dart';
|
||||||
import 'package:aves/widgets/common/basic/text_dropdown_button.dart';
|
import 'package:aves/widgets/common/basic/text_dropdown_button.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/fx/transitions.dart';
|
import 'package:aves/widgets/common/fx/transitions.dart';
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue