2023-03-13 12:55:39 +01:00
|
|
|
import 'package:clock/clock.dart';
|
2021-08-01 22:46:16 +02:00
|
|
|
import 'package:nc_photos/account.dart';
|
|
|
|
import 'package:nc_photos/api/api_util.dart' as api_util;
|
2021-04-10 06:28:12 +02:00
|
|
|
import 'package:nc_photos/entity/file.dart';
|
2022-10-15 16:29:18 +02:00
|
|
|
import 'package:nc_photos/entity/file_descriptor.dart';
|
2021-11-12 12:44:31 +01:00
|
|
|
import 'package:nc_photos/remote_storage_util.dart' as remote_storage_util;
|
2023-05-07 16:00:33 +02:00
|
|
|
import 'package:np_api/np_api.dart' as api;
|
2023-08-27 12:58:05 +02:00
|
|
|
import 'package:np_platform_util/np_platform_util.dart';
|
2023-08-25 18:37:17 +02:00
|
|
|
import 'package:np_string/np_string.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
|
|
|
|
2022-10-15 16:29:18 +02:00
|
|
|
bool isSupportedMime(String mime) => supportedFormatMimes.contains(mime);
|
2021-10-06 22:32:36 +02:00
|
|
|
|
2022-10-15 16:29:18 +02:00
|
|
|
bool isSupportedFormat(FileDescriptor file) =>
|
|
|
|
isSupportedMime(file.fdMime ?? "");
|
2021-04-10 06:28:12 +02:00
|
|
|
|
2022-05-06 11:16:56 +02:00
|
|
|
bool isSupportedImageMime(String mime) =>
|
2022-10-15 16:29:18 +02:00
|
|
|
supportedImageFormatMimes.contains(mime);
|
2022-05-06 11:16:56 +02:00
|
|
|
|
2022-10-15 16:29:18 +02:00
|
|
|
bool isSupportedImageFormat(FileDescriptor file) =>
|
|
|
|
isSupportedImageMime(file.fdMime ?? "");
|
2021-05-06 08:29:46 +02:00
|
|
|
|
2023-04-13 17:32:31 +02:00
|
|
|
bool isSupportedVideoMime(String mime) =>
|
|
|
|
supportedVideoFormatMimes.contains(mime);
|
|
|
|
|
2022-10-15 16:29:18 +02:00
|
|
|
bool isSupportedVideoFormat(FileDescriptor file) =>
|
2023-04-13 17:32:31 +02:00
|
|
|
isSupportedVideoMime(file.fdMime ?? "");
|
2021-05-06 13:36:20 +02:00
|
|
|
|
2022-04-21 21:18:57 +02:00
|
|
|
bool isMetadataSupportedMime(String mime) =>
|
|
|
|
_metadataSupportedFormatMimes.contains(mime);
|
|
|
|
|
2022-10-15 16:29:18 +02:00
|
|
|
bool isMetadataSupportedFormat(FileDescriptor file) =>
|
|
|
|
isMetadataSupportedMime(file.fdMime ?? "");
|
2021-05-06 22:11:31 +02:00
|
|
|
|
2022-10-15 16:29:18 +02:00
|
|
|
bool isTrash(Account account, FileDescriptor file) =>
|
|
|
|
file.fdPath.startsWith(api_util.getTrashbinPath(account));
|
2021-08-01 22:46:16 +02:00
|
|
|
|
2023-04-13 17:32:31 +02:00
|
|
|
bool isAlbumFile(Account account, FileDescriptor file) =>
|
|
|
|
file.fdPath.startsWith(remote_storage_util.getRemoteAlbumsDir(account));
|
2021-11-12 12:44:31 +01:00
|
|
|
|
2023-05-07 16:00:33 +02:00
|
|
|
bool isNcAlbumFile(Account account, FileDescriptor file) =>
|
|
|
|
file.fdPath.startsWith("${api.ApiPhotos.path}/");
|
|
|
|
|
2021-11-15 18:55:39 +01:00
|
|
|
/// Return if [file] is located under [dir]
|
|
|
|
///
|
|
|
|
/// Return false if [file] is [dir] itself (since it's not "under")
|
|
|
|
///
|
|
|
|
/// See [isOrUnderDir]
|
2023-04-13 17:32:31 +02:00
|
|
|
bool isUnderDir(FileDescriptor file, FileDescriptor dir) =>
|
|
|
|
file.fdPath.startsWith("${dir.fdPath}/");
|
2021-11-15 18:55:39 +01:00
|
|
|
|
2024-01-12 19:12:32 +01:00
|
|
|
bool isUnderDirPath(String filePath, String dirPath) =>
|
|
|
|
filePath.startsWith("$dirPath/");
|
|
|
|
|
2021-11-15 18:55:39 +01:00
|
|
|
/// Return if [file] is [dir] or located under [dir]
|
|
|
|
///
|
|
|
|
/// See [isUnderDir]
|
2023-04-13 17:32:31 +02:00
|
|
|
bool isOrUnderDir(FileDescriptor file, FileDescriptor dir) =>
|
|
|
|
file.fdPath == dir.fdPath || isUnderDir(file, dir);
|
2021-11-15 18:55:39 +01:00
|
|
|
|
2024-01-12 19:12:32 +01:00
|
|
|
bool isOrUnderDirPath(String filePath, String dirPath) =>
|
|
|
|
filePath == dirPath || isUnderDirPath(filePath, dirPath);
|
|
|
|
|
2021-11-16 16:06:22 +01:00
|
|
|
/// Convert a stripped path to a full path
|
|
|
|
///
|
|
|
|
/// See [File.strippedPath]
|
2021-12-25 12:55:48 +01:00
|
|
|
String unstripPath(Account account, String strippedPath) {
|
|
|
|
final p = strippedPath == "." ? "" : strippedPath;
|
|
|
|
return "${api_util.getWebdavRootUrlRelative(account)}/$p".trimRightAny("/");
|
|
|
|
}
|
2021-11-16 16:06:22 +01:00
|
|
|
|
2021-06-14 15:51:29 +02:00
|
|
|
/// For a path "remote.php/dav/files/foo/bar.jpg", return foo
|
2024-02-13 17:59:05 +01:00
|
|
|
CiString getUserDirName(File file) => getUserDirNamePath(file.path);
|
|
|
|
|
|
|
|
/// For a path "remote.php/dav/files/foo/bar.jpg", return foo
|
|
|
|
CiString getUserDirNamePath(String filePath) {
|
|
|
|
if (filePath.startsWith("remote.php/dav/files/")) {
|
2021-09-15 08:58:06 +02:00
|
|
|
const beg = "remote.php/dav/files/".length;
|
2024-02-13 17:59:05 +01:00
|
|
|
final end = filePath.indexOf("/", beg);
|
2021-06-14 15:51:29 +02:00
|
|
|
if (end != -1) {
|
2024-02-13 17:59:05 +01:00
|
|
|
return filePath.substring(beg, end).toCi();
|
2021-06-14 15:51:29 +02:00
|
|
|
}
|
|
|
|
}
|
2024-02-13 17:59:05 +01:00
|
|
|
throw ArgumentError("Invalid path: $filePath");
|
2021-06-14 15:51:29 +02:00
|
|
|
}
|
|
|
|
|
2021-10-08 09:01:27 +02:00
|
|
|
String renameConflict(String filename, int conflictCount) {
|
2022-01-31 10:47:37 +01:00
|
|
|
final temp =
|
|
|
|
"${path_lib.basenameWithoutExtension(filename)} ($conflictCount)";
|
|
|
|
if (path_lib.extension(filename).isEmpty) {
|
2021-10-08 09:01:27 +02:00
|
|
|
return temp;
|
|
|
|
} else {
|
2022-01-31 10:47:37 +01:00
|
|
|
return "$temp${path_lib.extension(filename)}";
|
2021-10-08 09:01:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-01 21:34:40 +01:00
|
|
|
/// Return if this file is the no media marker
|
|
|
|
///
|
|
|
|
/// A no media marker marks the parent dir and its sub dirs as not containing
|
|
|
|
/// media files of interest
|
2022-02-07 20:22:41 +01:00
|
|
|
bool isNoMediaMarker(File file) => isNoMediaMarkerPath(file.path);
|
|
|
|
|
|
|
|
/// See [isNoMediaMarker]
|
|
|
|
bool isNoMediaMarkerPath(String path) {
|
|
|
|
final filename = path_lib.basename(path);
|
2022-01-01 21:34:40 +01:00
|
|
|
return filename == ".nomedia" || filename == ".noimage";
|
|
|
|
}
|
|
|
|
|
2022-08-20 12:35:59 +02:00
|
|
|
/// Return if there's missing metadata in [file]
|
2022-08-27 17:32:31 +02:00
|
|
|
///
|
|
|
|
/// Current this function will check both [File.metadata] and [File.location]
|
2022-08-20 12:35:59 +02:00
|
|
|
bool isMissingMetadata(File file) =>
|
2022-08-27 17:32:31 +02:00
|
|
|
isSupportedImageFormat(file) &&
|
|
|
|
(file.metadata == null || file.location == null);
|
2022-08-20 12:35:59 +02:00
|
|
|
|
2022-10-29 13:05:23 +02:00
|
|
|
DateTime getBestDateTime({
|
|
|
|
DateTime? overrideDateTime,
|
|
|
|
DateTime? dateTimeOriginal,
|
|
|
|
DateTime? lastModified,
|
2023-03-13 12:55:39 +01:00
|
|
|
}) =>
|
|
|
|
overrideDateTime ?? dateTimeOriginal ?? lastModified ?? clock.now().toUtc();
|
2022-10-29 13:05:23 +02:00
|
|
|
|
2022-10-15 16:29:18 +02:00
|
|
|
final supportedFormatMimes = [
|
2021-04-10 06:28:12 +02:00
|
|
|
"image/jpeg",
|
|
|
|
"image/png",
|
|
|
|
"image/webp",
|
2021-04-14 23:09:31 +02:00
|
|
|
"image/heic",
|
2021-06-22 07:24:37 +02:00
|
|
|
"image/gif",
|
2021-08-05 09:04:12 +02:00
|
|
|
"video/mp4",
|
2021-09-20 10:53:42 +02:00
|
|
|
"video/quicktime",
|
2023-08-27 12:58:05 +02:00
|
|
|
if ([NpPlatform.android, NpPlatform.web].contains(getRawPlatform()))
|
|
|
|
"video/webm",
|
2021-04-10 06:28:12 +02:00
|
|
|
];
|
2021-05-06 22:11:31 +02:00
|
|
|
|
2022-10-15 16:29:18 +02:00
|
|
|
final supportedImageFormatMimes =
|
|
|
|
supportedFormatMimes.where((f) => f.startsWith("image/")).toList();
|
|
|
|
|
2023-04-13 17:32:31 +02:00
|
|
|
final supportedVideoFormatMimes =
|
|
|
|
supportedFormatMimes.where((f) => f.startsWith("video/")).toList();
|
|
|
|
|
2021-05-06 22:11:31 +02:00
|
|
|
const _metadataSupportedFormatMimes = [
|
|
|
|
"image/jpeg",
|
|
|
|
"image/heic",
|
|
|
|
];
|