nc-photos/app/lib/entity/file.dart

671 lines
19 KiB
Dart
Raw Normal View History

2021-04-10 06:28:12 +02:00
import 'dart:typed_data';
2021-04-15 20:44:25 +02:00
import 'package:equatable/equatable.dart';
2021-04-10 06:28:12 +02:00
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
2021-11-12 22:13:02 +01:00
import 'package:nc_photos/ci_string.dart';
2021-04-10 06:28:12 +02:00
import 'package:nc_photos/entity/exif.dart';
2022-01-25 11:08:13 +01:00
import 'package:nc_photos/json_util.dart' as json_util;
2021-04-28 21:22:33 +02:00
import 'package:nc_photos/or_null.dart';
2021-04-10 06:28:12 +02:00
import 'package:nc_photos/string_extension.dart';
2021-08-06 19:11:00 +02:00
import 'package:nc_photos/type.dart';
2022-01-31 10:47:37 +01:00
import 'package:path/path.dart' as path_lib;
2021-04-10 06:28:12 +02:00
int compareFileDateTimeDescending(File x, File y) {
2021-06-20 13:40:28 +02:00
final tmp = y.bestDateTime.compareTo(x.bestDateTime);
2021-04-10 06:28:12 +02:00
if (tmp != 0) {
return tmp;
} else {
// compare file name if files are modified at the same time
return x.path.compareTo(y.path);
}
}
/// Immutable object that hold metadata of a [File]
2021-04-15 20:44:25 +02:00
class Metadata with EquatableMixin {
2021-04-10 06:28:12 +02:00
Metadata({
2021-07-23 22:05:57 +02:00
DateTime? lastUpdated,
2021-04-10 06:28:12 +02:00
this.fileEtag,
this.imageWidth,
this.imageHeight,
this.exif,
2021-09-15 08:58:06 +02:00
}) : lastUpdated = (lastUpdated ?? DateTime.now()).toUtc();
2021-04-10 06:28:12 +02:00
@override
// ignore: hash_and_equals
2021-07-23 22:05:57 +02:00
bool operator ==(Object? other) => equals(other, isDeep: true);
2021-07-23 22:05:57 +02:00
bool equals(Object? other, {bool isDeep = false}) {
if (other is Metadata) {
return super == other &&
(exif == null) == (other.exif == null) &&
(exif?.equals(other.exif, isDeep: isDeep) ?? true);
} else {
return false;
}
}
2021-04-10 06:28:12 +02:00
/// Parse Metadata from [json]
///
/// If the version saved in json does not match the active one, the
/// corresponding upgrader will be called one by one to upgrade the json,
/// version by version until it reached the active version. If any upgrader
/// in the chain is null, the upgrade process will fail
2021-07-23 22:05:57 +02:00
static Metadata? fromJson(
2021-08-06 19:11:00 +02:00
JsonObj json, {
2021-07-23 22:05:57 +02:00
required MetadataUpgraderV1? upgraderV1,
required MetadataUpgraderV2? upgraderV2,
2021-04-10 06:28:12 +02:00
}) {
final jsonVersion = json["version"];
2021-08-06 19:11:00 +02:00
JsonObj? result = json;
2021-04-10 06:28:12 +02:00
if (jsonVersion < 2) {
2021-07-23 22:05:57 +02:00
result = upgraderV1?.call(result);
if (result == null) {
2021-04-10 06:28:12 +02:00
_log.info("[fromJson] Version $jsonVersion not compatible");
return null;
}
}
if (jsonVersion < 3) {
2021-07-23 22:05:57 +02:00
result = upgraderV2?.call(result);
if (result == null) {
_log.info("[fromJson] Version $jsonVersion not compatible");
return null;
}
}
2021-04-10 06:28:12 +02:00
return Metadata(
2021-07-23 22:05:57 +02:00
lastUpdated: result["lastUpdated"] == null
2021-04-10 06:28:12 +02:00
? null
2021-07-23 22:05:57 +02:00
: DateTime.parse(result["lastUpdated"]),
fileEtag: result["fileEtag"],
imageWidth: result["imageWidth"],
imageHeight: result["imageHeight"],
exif: result["exif"] == null
2021-04-10 06:28:12 +02:00
? null
2021-07-23 22:05:57 +02:00
: Exif.fromJson(result["exif"].cast<String, dynamic>()),
2021-04-10 06:28:12 +02:00
);
}
2021-08-06 19:11:00 +02:00
JsonObj toJson() {
2021-04-10 06:28:12 +02:00
return {
"version": version,
"lastUpdated": lastUpdated.toIso8601String(),
if (fileEtag != null) "fileEtag": fileEtag,
if (imageWidth != null) "imageWidth": imageWidth,
if (imageHeight != null) "imageHeight": imageHeight,
2021-07-23 22:05:57 +02:00
if (exif != null) "exif": exif!.toJson(),
2021-04-10 06:28:12 +02:00
};
}
Metadata copyWith({
OrNull<DateTime>? lastUpdated,
String? fileEtag,
int? imageWidth,
int? imageHeight,
Exif? exif,
}) {
return Metadata(
lastUpdated:
lastUpdated == null ? null : (lastUpdated.obj ?? this.lastUpdated),
fileEtag: fileEtag ?? this.fileEtag,
imageWidth: imageWidth ?? this.imageWidth,
imageHeight: imageHeight ?? this.imageHeight,
exif: exif ?? this.exif,
);
}
2021-04-10 06:28:12 +02:00
@override
toString() {
var product = "$runtimeType {"
"lastUpdated: $lastUpdated, ";
if (fileEtag != null) {
product += "fileEtag: $fileEtag, ";
}
if (imageWidth != null) {
product += "imageWidth: $imageWidth, ";
}
if (imageHeight != null) {
product += "imageHeight: $imageHeight, ";
}
if (exif != null) {
product += "exif: $exif, ";
}
return product + "}";
}
2021-04-15 20:44:25 +02:00
@override
get props => [
lastUpdated,
fileEtag,
imageWidth,
imageHeight,
// exif is handled separately, see [equals]
2021-04-15 20:44:25 +02:00
];
2021-04-10 06:28:12 +02:00
final DateTime lastUpdated;
/// Etag of the parent file when the metadata is saved
2021-07-23 22:05:57 +02:00
final String? fileEtag;
final int? imageWidth;
final int? imageHeight;
final Exif? exif;
2021-04-10 06:28:12 +02:00
/// versioning of this class, use to upgrade old persisted metadata
static const version = 3;
2021-04-10 06:28:12 +02:00
static final _log = Logger("entity.file.Metadata");
}
abstract class MetadataUpgrader {
2021-08-06 19:11:00 +02:00
JsonObj? call(JsonObj json);
2021-04-10 06:28:12 +02:00
}
/// Upgrade v1 Metadata to v2
class MetadataUpgraderV1 implements MetadataUpgrader {
MetadataUpgraderV1({
2021-07-23 22:05:57 +02:00
required this.fileContentType,
this.logFilePath,
2021-04-10 06:28:12 +02:00
});
2021-09-15 08:58:06 +02:00
@override
2021-08-06 19:11:00 +02:00
JsonObj? call(JsonObj json) {
2021-04-10 06:28:12 +02:00
if (fileContentType == "image/webp") {
// Version 1 metadata for webp is bugged, drop it
_log.fine("[call] Upgrade v1 metadata for file: $logFilePath");
2021-04-10 06:28:12 +02:00
return null;
} else {
return json;
}
}
2021-07-23 22:05:57 +02:00
final String? fileContentType;
/// File path for logging only
2021-07-23 22:05:57 +02:00
final String? logFilePath;
static final _log = Logger("entity.file.MetadataUpgraderV1");
}
/// Upgrade v2 Metadata to v3
class MetadataUpgraderV2 implements MetadataUpgrader {
MetadataUpgraderV2({
2021-07-23 22:05:57 +02:00
required this.fileContentType,
this.logFilePath,
});
2021-09-15 08:58:06 +02:00
@override
2021-08-06 19:11:00 +02:00
JsonObj? call(JsonObj json) {
if (fileContentType == "image/jpeg") {
// Version 2 metadata for jpeg doesn't consider orientation
if (json["exif"] != null && json["exif"].containsKey("Orientation")) {
// Check orientation
final orientation = json["exif"]["Orientation"];
if (orientation >= 5 && orientation <= 8) {
_log.fine("[call] Upgrade v2 metadata for file: $logFilePath");
final temp = json["imageWidth"];
json["imageWidth"] = json["imageHeight"];
json["imageHeight"] = temp;
}
}
}
return json;
}
2021-07-23 22:05:57 +02:00
final String? fileContentType;
/// File path for logging only
2021-07-23 22:05:57 +02:00
final String? logFilePath;
static final _log = Logger("entity.file.MetadataUpgraderV2");
2021-04-10 06:28:12 +02:00
}
2021-04-15 20:44:25 +02:00
class File with EquatableMixin {
2021-04-10 06:28:12 +02:00
File({
2021-07-23 22:05:57 +02:00
required String path,
2021-04-10 06:28:12 +02:00
this.contentLength,
this.contentType,
this.etag,
this.lastModified,
this.isCollection,
this.usedBytes,
this.hasPreview,
2021-05-10 07:53:05 +02:00
this.fileId,
2022-01-25 11:08:13 +01:00
this.isFavorite,
2021-06-14 12:44:38 +02:00
this.ownerId,
2021-04-10 06:28:12 +02:00
this.metadata,
2021-05-28 20:45:00 +02:00
this.isArchived,
2021-06-21 12:39:17 +02:00
this.overrideDateTime,
2021-08-01 22:06:28 +02:00
this.trashbinFilename,
this.trashbinOriginalLocation,
this.trashbinDeletionTime,
2021-09-15 08:58:06 +02:00
}) : path = path.trimAny("/");
2021-04-10 06:28:12 +02:00
@override
// ignore: hash_and_equals
2021-07-23 22:05:57 +02:00
bool operator ==(Object? other) => equals(other, isDeep: true);
2021-07-23 22:05:57 +02:00
bool equals(Object? other, {bool isDeep = false}) {
if (other is File) {
return super == other &&
(metadata == null) == (other.metadata == null) &&
(metadata?.equals(other.metadata, isDeep: isDeep) ?? true);
} else {
return false;
}
}
2021-08-06 19:11:00 +02:00
factory File.fromJson(JsonObj json) {
2021-04-10 06:28:12 +02:00
return File(
path: json["path"],
contentLength: json["contentLength"],
contentType: json["contentType"],
etag: json["etag"],
lastModified: json["lastModified"] == null
? null
: DateTime.parse(json["lastModified"]),
isCollection: json["isCollection"],
usedBytes: json["usedBytes"],
hasPreview: json["hasPreview"],
2021-05-10 07:53:05 +02:00
fileId: json["fileId"],
2022-01-25 11:08:13 +01:00
isFavorite: json_util.boolFromJson(json["isFavorite"]),
2021-11-12 22:13:02 +01:00
ownerId: json["ownerId"] == null ? null : CiString(json["ownerId"]),
2021-08-01 22:06:28 +02:00
trashbinFilename: json["trashbinFilename"],
trashbinOriginalLocation: json["trashbinOriginalLocation"],
trashbinDeletionTime: json["trashbinDeletionTime"] == null
? null
: DateTime.parse(json["trashbinDeletionTime"]),
2021-04-10 06:28:12 +02:00
metadata: json["metadata"] == null
? null
: Metadata.fromJson(
json["metadata"].cast<String, dynamic>(),
upgraderV1: MetadataUpgraderV1(
fileContentType: json["contentType"],
logFilePath: json["path"],
),
upgraderV2: MetadataUpgraderV2(
fileContentType: json["contentType"],
logFilePath: json["path"],
2021-04-10 06:28:12 +02:00
),
),
2021-05-28 20:45:00 +02:00
isArchived: json["isArchived"],
2021-06-21 12:39:17 +02:00
overrideDateTime: json["overrideDateTime"] == null
? null
: DateTime.parse(json["overrideDateTime"]),
2021-04-10 06:28:12 +02:00
);
}
@override
toString() {
var product = "$runtimeType {"
"path: '$path', ";
if (contentLength != null) {
product += "contentLength: $contentLength, ";
}
if (contentType != null) {
product += "contentType: '$contentType', ";
}
if (etag != null) {
product += "etag: '$etag', ";
}
if (lastModified != null) {
product += "lastModified: $lastModified, ";
}
if (isCollection != null) {
product += "isCollection: $isCollection, ";
}
if (usedBytes != null) {
product += "usedBytes: $usedBytes, ";
}
if (hasPreview != null) {
product += "hasPreview: $hasPreview, ";
}
2021-05-10 07:53:05 +02:00
if (fileId != null) {
2021-06-14 11:36:40 +02:00
product += "fileId: $fileId, ";
2021-05-10 07:53:05 +02:00
}
2022-01-25 11:08:13 +01:00
if (isFavorite != null) {
product += "isFavorite: $isFavorite, ";
}
2021-06-14 12:44:38 +02:00
if (ownerId != null) {
product += "ownerId: '$ownerId', ";
}
2021-08-01 22:06:28 +02:00
if (trashbinFilename != null) {
product += "trashbinFilename: '$trashbinFilename', ";
}
if (trashbinOriginalLocation != null) {
product += "trashbinOriginalLocation: '$trashbinOriginalLocation', ";
}
if (trashbinDeletionTime != null) {
product += "trashbinDeletionTime: $trashbinDeletionTime, ";
}
2021-04-10 06:28:12 +02:00
if (metadata != null) {
product += "metadata: $metadata, ";
}
2021-05-28 20:45:00 +02:00
if (isArchived != null) {
product += "isArchived: $isArchived, ";
}
2021-06-21 12:39:17 +02:00
if (overrideDateTime != null) {
product += "overrideDateTime: $overrideDateTime, ";
}
2021-04-10 06:28:12 +02:00
return product + "}";
}
2021-08-06 19:11:00 +02:00
JsonObj toJson() {
2021-04-10 06:28:12 +02:00
return {
"path": path,
if (contentLength != null) "contentLength": contentLength,
if (contentType != null) "contentType": contentType,
if (etag != null) "etag": etag,
2021-06-21 11:10:38 +02:00
if (lastModified != null)
2021-07-23 22:05:57 +02:00
"lastModified": lastModified!.toUtc().toIso8601String(),
2021-04-10 06:28:12 +02:00
if (isCollection != null) "isCollection": isCollection,
if (usedBytes != null) "usedBytes": usedBytes,
if (hasPreview != null) "hasPreview": hasPreview,
2021-05-10 07:53:05 +02:00
if (fileId != null) "fileId": fileId,
2022-01-25 11:08:13 +01:00
if (isFavorite != null) "isFavorite": json_util.boolToJson(isFavorite),
2021-11-12 22:13:02 +01:00
if (ownerId != null) "ownerId": ownerId.toString(),
2021-08-01 22:06:28 +02:00
if (trashbinFilename != null) "trashbinFilename": trashbinFilename,
if (trashbinOriginalLocation != null)
"trashbinOriginalLocation": trashbinOriginalLocation,
if (trashbinDeletionTime != null)
"trashbinDeletionTime": trashbinDeletionTime!.toUtc().toIso8601String(),
2021-07-23 22:05:57 +02:00
if (metadata != null) "metadata": metadata!.toJson(),
2021-05-28 20:45:00 +02:00
if (isArchived != null) "isArchived": isArchived,
2021-06-21 12:39:17 +02:00
if (overrideDateTime != null)
2021-07-23 22:05:57 +02:00
"overrideDateTime": overrideDateTime!.toUtc().toIso8601String(),
2021-04-10 06:28:12 +02:00
};
}
File copyWith({
2021-07-23 22:05:57 +02:00
String? path,
int? contentLength,
String? contentType,
OrNull<String>? etag,
2021-07-23 22:05:57 +02:00
DateTime? lastModified,
bool? isCollection,
int? usedBytes,
bool? hasPreview,
int? fileId,
2022-01-25 11:08:13 +01:00
bool? isFavorite,
2021-11-12 22:13:02 +01:00
CiString? ownerId,
2021-08-01 22:06:28 +02:00
String? trashbinFilename,
String? trashbinOriginalLocation,
DateTime? trashbinDeletionTime,
2021-07-23 22:05:57 +02:00
OrNull<Metadata>? metadata,
OrNull<bool>? isArchived,
OrNull<DateTime>? overrideDateTime,
2021-04-10 06:28:12 +02:00
}) {
return File(
path: path ?? this.path,
contentLength: contentLength ?? this.contentLength,
contentType: contentType ?? this.contentType,
etag: etag == null ? this.etag : etag.obj,
2021-04-10 06:28:12 +02:00
lastModified: lastModified ?? this.lastModified,
isCollection: isCollection ?? this.isCollection,
usedBytes: usedBytes ?? this.usedBytes,
hasPreview: hasPreview ?? this.hasPreview,
2021-05-10 07:53:05 +02:00
fileId: fileId ?? this.fileId,
2022-01-25 11:08:13 +01:00
isFavorite: isFavorite ?? this.isFavorite,
2021-06-14 12:44:38 +02:00
ownerId: ownerId ?? this.ownerId,
2021-08-01 22:06:28 +02:00
trashbinFilename: trashbinFilename ?? this.trashbinFilename,
trashbinOriginalLocation:
trashbinOriginalLocation ?? this.trashbinOriginalLocation,
trashbinDeletionTime: trashbinDeletionTime ?? this.trashbinDeletionTime,
2021-04-28 21:22:33 +02:00
metadata: metadata == null ? this.metadata : metadata.obj,
2021-05-28 20:45:00 +02:00
isArchived: isArchived == null ? this.isArchived : isArchived.obj,
2021-06-21 12:39:17 +02:00
overrideDateTime: overrideDateTime == null
? this.overrideDateTime
: overrideDateTime.obj,
2021-04-10 06:28:12 +02:00
);
}
2021-04-15 20:44:25 +02:00
@override
get props => [
path,
contentLength,
contentType,
etag,
lastModified,
isCollection,
usedBytes,
hasPreview,
2021-05-10 07:53:05 +02:00
fileId,
2022-01-25 11:08:13 +01:00
isFavorite,
2021-06-14 12:44:38 +02:00
ownerId,
2021-08-01 22:06:28 +02:00
trashbinFilename,
trashbinOriginalLocation,
trashbinDeletionTime,
// metadata is handled separately, see [equals]
2021-05-28 20:45:00 +02:00
isArchived,
2021-06-21 12:39:17 +02:00
overrideDateTime,
2021-04-15 20:44:25 +02:00
];
2021-04-10 06:28:12 +02:00
final String path;
2021-07-23 22:05:57 +02:00
final int? contentLength;
final String? contentType;
final String? etag;
final DateTime? lastModified;
final bool? isCollection;
final int? usedBytes;
final bool? hasPreview;
final int? fileId;
2022-01-25 11:08:13 +01:00
final bool? isFavorite;
2021-11-12 22:13:02 +01:00
final CiString? ownerId;
2021-08-01 22:06:28 +02:00
final String? trashbinFilename;
final String? trashbinOriginalLocation;
final DateTime? trashbinDeletionTime;
2021-04-10 06:28:12 +02:00
// metadata
2021-07-23 22:05:57 +02:00
final Metadata? metadata;
final bool? isArchived;
final DateTime? overrideDateTime;
2021-04-10 06:28:12 +02:00
}
2021-06-20 13:40:28 +02:00
extension FileExtension on File {
DateTime get bestDateTime =>
overrideDateTime ??
metadata?.exif?.dateTimeOriginal ??
lastModified ??
DateTime.now().toUtc();
2021-07-22 08:16:56 +02:00
2021-11-12 22:13:02 +01:00
bool isOwned(CiString username) => ownerId == null || ownerId == username;
2021-09-04 17:13:52 +02:00
2021-10-06 19:00:42 +02:00
/// Return the path of this file with the DAV part stripped
///
/// WebDAV file path: remote.php/dav/files/{username}/{strippedPath}. If this
/// file points to the user's root dir, return "."
///
/// See: [strippedPathWithEmpty]
2021-10-06 19:00:42 +02:00
String get strippedPath {
if (path.contains("remote.php/dav/files")) {
final position = path.indexOf("/", "remote.php/dav/files/".length) + 1;
if (position == 0) {
// root dir path
return ".";
} else {
return path.substring(position);
}
} else {
return path;
}
}
/// Return the path of this file with the DAV part stripped
///
/// WebDAV file path: remote.php/dav/files/{username}/{strippedPath}. If this
/// file points to the user's root dir, return an empty string
///
/// See: [strippedPath]
String get strippedPathWithEmpty {
final path = strippedPath;
return path == "." ? "" : path;
}
2022-01-31 10:47:37 +01:00
String get filename => path_lib.basename(path);
2021-10-06 19:00:42 +02:00
/// Compare the server identity of two Files
///
/// Return true if two Files point to the same file on server. Be careful that
/// this does NOT mean that the two Files are identical
bool compareServerIdentity(File other) {
if (fileId != null && other.fileId != null) {
return fileId == other.fileId;
} else {
return path == other.path;
}
}
2022-07-12 21:11:29 +02:00
/// hashCode to be used with [compareServerIdentity]
int get identityHashCode => (fileId ?? path).hashCode;
2021-09-04 17:13:52 +02:00
static final _log = Logger("entity.file.FileExtension");
2021-06-20 13:40:28 +02:00
}
class FileServerIdentityComparator {
const FileServerIdentityComparator(this.file);
@override
operator ==(Object other) {
if (other is FileServerIdentityComparator) {
return file.compareServerIdentity(other.file);
} else if (other is File) {
return file.compareServerIdentity(other);
} else {
return false;
}
}
@override
get hashCode => file.fileId?.hashCode ?? file.path.hashCode;
final File file;
}
2021-04-10 06:28:12 +02:00
class FileRepo {
2021-08-16 21:05:00 +02:00
const FileRepo(this.dataSrc);
2021-04-10 06:28:12 +02:00
/// See [FileDataSource.list]
Future<List<File>> list(Account account, File root) =>
2021-09-15 08:58:06 +02:00
dataSrc.list(account, root);
2021-04-10 06:28:12 +02:00
/// See [FileDataSource.listSingle]
Future<File> listSingle(Account account, File root) =>
dataSrc.listSingle(account, root);
2021-04-10 06:28:12 +02:00
/// See [FileDataSource.remove]
Future<void> remove(Account account, File file) =>
2021-09-15 08:58:06 +02:00
dataSrc.remove(account, file);
2021-04-10 06:28:12 +02:00
/// See [FileDataSource.getBinary]
Future<Uint8List> getBinary(Account account, File file) =>
2021-09-15 08:58:06 +02:00
dataSrc.getBinary(account, file);
2021-04-10 06:28:12 +02:00
/// See [FileDataSource.putBinary]
Future<void> putBinary(Account account, String path, Uint8List content) =>
2021-09-15 08:58:06 +02:00
dataSrc.putBinary(account, path, content);
2021-04-10 06:28:12 +02:00
/// See [FileDataSource.updateMetadata]
2021-05-28 19:15:09 +02:00
Future<void> updateProperty(
Account account,
File file, {
2021-07-23 22:05:57 +02:00
OrNull<Metadata>? metadata,
OrNull<bool>? isArchived,
OrNull<DateTime>? overrideDateTime,
2022-01-25 11:17:19 +01:00
bool? favorite,
2021-05-28 19:15:09 +02:00
}) =>
2021-09-15 08:58:06 +02:00
dataSrc.updateProperty(
account,
file,
metadata: metadata,
isArchived: isArchived,
overrideDateTime: overrideDateTime,
2022-01-25 11:17:19 +01:00
favorite: favorite,
2021-09-15 08:58:06 +02:00
);
2021-04-10 06:28:12 +02:00
2021-05-20 17:43:53 +02:00
/// See [FileDataSource.copy]
Future<void> copy(
Account account,
File f,
String destination, {
2021-07-23 22:05:57 +02:00
bool? shouldOverwrite,
2021-05-20 17:43:53 +02:00
}) =>
2021-09-15 08:58:06 +02:00
dataSrc.copy(
account,
f,
destination,
shouldOverwrite: shouldOverwrite,
);
2021-05-20 17:43:53 +02:00
2021-05-20 17:45:06 +02:00
/// See [FileDataSource.move]
Future<void> move(
Account account,
File f,
String destination, {
2021-07-23 22:05:57 +02:00
bool? shouldOverwrite,
2021-05-20 17:45:06 +02:00
}) =>
2021-09-15 08:58:06 +02:00
dataSrc.move(
account,
f,
destination,
shouldOverwrite: shouldOverwrite,
);
2021-05-20 17:45:06 +02:00
2021-05-20 17:47:24 +02:00
/// See [FileDataSource.createDir]
Future<void> createDir(Account account, String path) =>
2021-09-15 08:58:06 +02:00
dataSrc.createDir(account, path);
2021-05-20 17:47:24 +02:00
2021-04-10 06:28:12 +02:00
final FileDataSource dataSrc;
}
abstract class FileDataSource {
2022-02-07 13:50:52 +01:00
/// List all files under [dir]
Future<List<File>> list(Account account, File dir);
2021-04-10 06:28:12 +02:00
/// List a single file [f]
Future<File> listSingle(Account account, File f);
2021-04-10 06:28:12 +02:00
/// Remove file
Future<void> remove(Account account, File f);
/// Read file as binary array
Future<Uint8List> getBinary(Account account, File f);
/// Upload content to [path]
Future<void> putBinary(Account account, String path, Uint8List content);
2021-05-28 19:15:09 +02:00
/// Update one or more properties of a file
Future<void> updateProperty(
Account account,
File f, {
2021-07-23 22:05:57 +02:00
OrNull<Metadata>? metadata,
OrNull<bool>? isArchived,
OrNull<DateTime>? overrideDateTime,
2022-01-25 11:17:19 +01:00
bool? favorite,
2021-05-28 19:15:09 +02:00
});
2021-05-20 17:43:53 +02:00
/// Copy [f] to [destination]
///
/// [destination] should be a relative WebDAV path like
/// remote.php/dav/files/admin/new/location
Future<void> copy(
Account account,
File f,
String destination, {
2021-07-23 22:05:57 +02:00
bool? shouldOverwrite,
2021-05-20 17:43:53 +02:00
});
2021-05-20 17:45:06 +02:00
/// Move [f] to [destination]
///
/// [destination] should be a relative WebDAV path like
/// remote.php/dav/files/admin/new/location
Future<void> move(
Account account,
File f,
String destination, {
2021-07-23 22:05:57 +02:00
bool? shouldOverwrite,
2021-05-20 17:45:06 +02:00
});
2021-05-20 17:47:24 +02:00
/// Create a directory at [path]
///
/// [path] should be a relative WebDAV path like
/// remote.php/dav/files/admin/new/dir
Future<void> createDir(Account account, String path);
2021-04-10 06:28:12 +02:00
}