250 lines
6.1 KiB
Dart
250 lines
6.1 KiB
Dart
class FileUtils {
|
|
static String safeDecodePathSegment(String value, {int maxPasses = 5}) {
|
|
var decoded = value;
|
|
|
|
for (var i = 0; i < maxPasses; i++) {
|
|
try {
|
|
final next = Uri.decodeComponent(decoded);
|
|
if (next == decoded) break;
|
|
decoded = next;
|
|
} on FormatException {
|
|
break;
|
|
} on ArgumentError {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return decoded;
|
|
}
|
|
|
|
static String decodePathForDisplay(String path) {
|
|
return path
|
|
.split('/')
|
|
.map((segment) => safeDecodePathSegment(segment))
|
|
.join('/');
|
|
}
|
|
|
|
static String toCloudreveUri(String path) {
|
|
if (path.startsWith('cloudreve://')) return path;
|
|
if (path == '/' || path.isEmpty) return 'cloudreve://my';
|
|
final cleanPath = path.startsWith('/') ? path.substring(1) : path;
|
|
return 'cloudreve://my/$cleanPath';
|
|
}
|
|
|
|
static String toCloudreveUriWithQuery(
|
|
String path,
|
|
Map<String, String> queryParameters,
|
|
) {
|
|
final uri = Uri.parse(toCloudreveUri(path));
|
|
return uri.replace(queryParameters: queryParameters).toString();
|
|
}
|
|
|
|
static String getFileExtension(String fileName) {
|
|
final dotIndex = fileName.lastIndexOf('.');
|
|
if (dotIndex == -1) return '';
|
|
return fileName.substring(dotIndex + 1).toLowerCase();
|
|
}
|
|
|
|
static bool isImageFile(String fileName) {
|
|
const imageExtensions = [
|
|
'jpg',
|
|
'jpeg',
|
|
'png',
|
|
'gif',
|
|
'webp',
|
|
'bmp',
|
|
'svg',
|
|
'heic',
|
|
'heif',
|
|
'avif',
|
|
'tif',
|
|
'tiff',
|
|
];
|
|
return imageExtensions.contains(getFileExtension(fileName));
|
|
}
|
|
|
|
static bool isFlutterRenderableImageFile(String fileName) {
|
|
const renderableImageExtensions = [
|
|
'jpg',
|
|
'jpeg',
|
|
'png',
|
|
'gif',
|
|
'webp',
|
|
'bmp',
|
|
];
|
|
return renderableImageExtensions.contains(getFileExtension(fileName));
|
|
}
|
|
|
|
static bool isVideoFile(String fileName) {
|
|
const videoExtensions = [
|
|
'mp4',
|
|
'webm',
|
|
'mkv',
|
|
'avi',
|
|
'mov',
|
|
'flv',
|
|
'wmv',
|
|
'm4v',
|
|
'mpg',
|
|
'mpeg',
|
|
'3gp',
|
|
'ts',
|
|
'm2ts',
|
|
];
|
|
return videoExtensions.contains(getFileExtension(fileName));
|
|
}
|
|
|
|
static bool isAudioFile(String fileName) {
|
|
const audioExtensions = ['mp3', 'wav', 'ogg', 'flac', 'aac', 'm4a'];
|
|
return audioExtensions.contains(getFileExtension(fileName));
|
|
}
|
|
|
|
static bool isPsdFile(String fileName) {
|
|
const psdExtensions = ['psd', 'psb'];
|
|
return psdExtensions.contains(getFileExtension(fileName));
|
|
}
|
|
|
|
static bool isThumbnailableFile(String fileName) {
|
|
final ext = getFileExtension(fileName);
|
|
if (ext.isEmpty || ext == 'svg') return false;
|
|
return isImageFile(fileName) || isVideoFile(fileName) || isPsdFile(fileName);
|
|
}
|
|
|
|
static bool isPdfFile(String fileName) {
|
|
return getFileExtension(fileName) == 'pdf';
|
|
}
|
|
|
|
static bool isTextFile(String fileName) {
|
|
const textExtensions = [
|
|
'txt',
|
|
'md',
|
|
'json',
|
|
'xml',
|
|
'yaml',
|
|
'yml',
|
|
'ini',
|
|
'conf',
|
|
];
|
|
return textExtensions.contains(getFileExtension(fileName));
|
|
}
|
|
|
|
static bool isCodeFile(String fileName) {
|
|
const codeExtensions = [
|
|
'js',
|
|
'ts',
|
|
'tsx',
|
|
'jsx',
|
|
'dart',
|
|
'java',
|
|
'py',
|
|
'c',
|
|
'cpp',
|
|
'h',
|
|
'hpp',
|
|
'cs',
|
|
'php',
|
|
'rb',
|
|
'go',
|
|
'rs',
|
|
'swift',
|
|
'kt',
|
|
'html',
|
|
'css',
|
|
'scss',
|
|
'less',
|
|
'sql',
|
|
'sh',
|
|
'bat',
|
|
];
|
|
return codeExtensions.contains(getFileExtension(fileName));
|
|
}
|
|
|
|
static bool isArchiveFile(String fileName) {
|
|
const archiveExtensions = ['zip', 'rar', '7z', 'tar', 'gz', 'bz2'];
|
|
return archiveExtensions.contains(getFileExtension(fileName));
|
|
}
|
|
|
|
static bool isDocumentFile(String fileName) {
|
|
const docExtensions = [
|
|
'doc',
|
|
'docx',
|
|
'xls',
|
|
'xlsx',
|
|
'ppt',
|
|
'pptx',
|
|
'odt',
|
|
'ods',
|
|
'odp',
|
|
];
|
|
return docExtensions.contains(getFileExtension(fileName));
|
|
}
|
|
|
|
static bool isPreviewable(String fileName) {
|
|
return isImageFile(fileName) ||
|
|
isVideoFile(fileName) ||
|
|
isPdfFile(fileName) ||
|
|
isTextFile(fileName) ||
|
|
isCodeFile(fileName);
|
|
}
|
|
|
|
static String getMimeType(String fileName) {
|
|
final ext = getFileExtension(fileName);
|
|
final mimeTypes = {
|
|
'jpg': 'image/jpeg',
|
|
'jpeg': 'image/jpeg',
|
|
'png': 'image/png',
|
|
'gif': 'image/gif',
|
|
'webp': 'image/webp',
|
|
'svg': 'image/svg+xml',
|
|
'bmp': 'image/bmp',
|
|
'heic': 'image/heic',
|
|
'heif': 'image/heif',
|
|
'avif': 'image/avif',
|
|
'tif': 'image/tiff',
|
|
'tiff': 'image/tiff',
|
|
'psd': 'image/vnd.adobe.photoshop',
|
|
'psb': 'image/vnd.adobe.photoshop',
|
|
'mp4': 'video/mp4',
|
|
'webm': 'video/webm',
|
|
'mkv': 'video/x-matroska',
|
|
'avi': 'video/x-msvideo',
|
|
'mov': 'video/quicktime',
|
|
'flv': 'video/x-flv',
|
|
'wmv': 'video/x-ms-wmv',
|
|
'm4v': 'video/x-m4v',
|
|
'mpg': 'video/mpeg',
|
|
'mpeg': 'video/mpeg',
|
|
'3gp': 'video/3gpp',
|
|
'ts': 'video/mp2t',
|
|
'm2ts': 'video/mp2t',
|
|
'mp3': 'audio/mpeg',
|
|
'wav': 'audio/wav',
|
|
'ogg': 'audio/ogg',
|
|
'flac': 'audio/flac',
|
|
'aac': 'audio/aac',
|
|
'm4a': 'audio/mp4',
|
|
'pdf': 'application/pdf',
|
|
'txt': 'text/plain',
|
|
'json': 'application/json',
|
|
'xml': 'application/xml',
|
|
'html': 'text/html',
|
|
'css': 'text/css',
|
|
'js': 'application/javascript',
|
|
};
|
|
return mimeTypes[ext] ?? 'application/octet-stream';
|
|
}
|
|
|
|
static String getFileIcon(String fileName) {
|
|
if (isImageFile(fileName)) return 'assets/icons/image.svg';
|
|
if (isVideoFile(fileName)) return 'assets/icons/video.svg';
|
|
if (isAudioFile(fileName)) return 'assets/icons/audio.svg';
|
|
if (isPdfFile(fileName)) return 'assets/icons/pdf.svg';
|
|
if (isTextFile(fileName)) return 'assets/icons/text.svg';
|
|
if (isCodeFile(fileName)) return 'assets/icons/code.svg';
|
|
if (isArchiveFile(fileName)) return 'assets/icons/archive.svg';
|
|
if (isDocumentFile(fileName)) return 'assets/icons/document.svg';
|
|
|
|
return 'assets/icons/file.svg';
|
|
}
|
|
}
|