82 lines
2.6 KiB
Dart
82 lines
2.6 KiB
Dart
import 'dart:io';
|
||
|
||
import 'package:path_provider/path_provider.dart';
|
||
|
||
/// 生图流程创建任务后,按接口返回的 `tree`(任务 id)将用户上传的压缩图存一份到本地;
|
||
/// Gallery 在接口未返回封面 URL 时可用其作为卡片底图。
|
||
abstract final class GalleryUploadCoverStore {
|
||
static const String _subdir = 'gallery_upload_covers';
|
||
static const String _fileExt = '.jpg';
|
||
|
||
/// 本地封面最多保留时长,超时文件会在下次读/写前删除。
|
||
static const Duration maxRetention = Duration(hours: 25);
|
||
|
||
static Future<Directory> _directory() async {
|
||
final base = await getApplicationSupportDirectory();
|
||
final dir = Directory('${base.path}/$_subdir');
|
||
if (!await dir.exists()) {
|
||
await dir.create(recursive: true);
|
||
}
|
||
return dir;
|
||
}
|
||
|
||
static Future<Directory> _directoryAfterPurge() async {
|
||
final dir = await _directory();
|
||
await _purgeExpired(dir);
|
||
return dir;
|
||
}
|
||
|
||
static Future<void> _purgeExpired(Directory dir) async {
|
||
if (!await dir.exists()) return;
|
||
final now = DateTime.now();
|
||
try {
|
||
await for (final entity in dir.list(followLinks: false)) {
|
||
if (entity is! File) continue;
|
||
final name = entity.uri.pathSegments.last;
|
||
if (!name.endsWith(_fileExt)) continue;
|
||
final stat = await entity.stat();
|
||
if (now.difference(stat.modified) >= maxRetention) {
|
||
try {
|
||
await entity.delete();
|
||
} catch (_) {}
|
||
}
|
||
}
|
||
} catch (_) {}
|
||
}
|
||
|
||
static File _fileForTask(Directory dir, int taskId) =>
|
||
File('${dir.path}/$taskId$_fileExt');
|
||
|
||
/// [source] 一般为 [compressImageForUpload] 输出的待上传文件。
|
||
static Future<void> saveForTask(int taskId, File source) async {
|
||
if (taskId <= 0) return;
|
||
if (!await source.exists()) return;
|
||
final dir = await _directoryAfterPurge();
|
||
final dest = _fileForTask(dir, taskId);
|
||
await source.copy(dest.path);
|
||
}
|
||
|
||
static Future<String?> pathIfExists(int taskId) async {
|
||
if (taskId <= 0) return null;
|
||
final dir = await _directoryAfterPurge();
|
||
final f = _fileForTask(dir, taskId);
|
||
return await f.exists() ? f.path : null;
|
||
}
|
||
|
||
/// 仅查询 [ids] 中已有文件的 path,用于列表刷新后一次性填充状态。
|
||
static Future<Map<int, String>> existingPathsForTaskIds(
|
||
Iterable<int> ids,
|
||
) async {
|
||
final dir = await _directoryAfterPurge();
|
||
final out = <int, String>{};
|
||
for (final id in ids) {
|
||
if (id <= 0) continue;
|
||
final f = _fileForTask(dir, id);
|
||
if (await f.exists()) {
|
||
out[id] = f.path;
|
||
}
|
||
}
|
||
return out;
|
||
}
|
||
}
|