feat(webdav): improve webdav behavior

This commit is contained in:
ZhuJHua
2024-12-13 01:53:10 +08:00
parent e206fdeb75
commit 57bc494382
15 changed files with 275 additions and 51 deletions

View File

@@ -121,6 +121,7 @@ class LocalSendClientLogic extends GetxController {
formData.fields.add(MapEntry('diary', jsonEncode(diary.toJson())));
// 如果有分类,把分类名字带过去
if (diary.categoryId != null) {
Utils().logUtil.printInfo(diary.categoryId);
var categoryName = Utils().isarUtil.getCategoryName(diary.categoryId!)!.categoryName;
formData.fields.add(MapEntry('categoryName', categoryName));
}

View File

@@ -98,8 +98,7 @@ class LocalSendServerLogic extends GetxController {
}
// 插入日记
await Utils().isarUtil.insertADiary(diary);
await Bind.find<DiaryLogic>().updateCategory();
await Bind.find<DiaryLogic>().updateDiary(null);
await Bind.find<DiaryLogic>().refreshAll();
state.receiveCount.value += 1;
return shelf.Response.ok('Data and files received successfully');
}

View File

@@ -49,6 +49,7 @@ class WebDavDashboardLogic extends GetxController {
void _findToUploadDiaries(Map<String, DateTime> localDiaryMap) {
for (var diary in state.diaryList) {
final remoteModifiedTime = state.webdavSyncMap[diary.id];
if (remoteModifiedTime == 'delete') continue;
if (remoteModifiedTime == null || DateTime.parse(remoteModifiedTime).isBefore(diary.lastModified)) {
state.toUploadDiaries.add(diary);
}
@@ -58,6 +59,7 @@ class WebDavDashboardLogic extends GetxController {
void _findToDownloadIds(Map<String, DateTime> localDiaryMap) {
for (var entry in state.webdavSyncMap.entries) {
if (entry.value == 'delete') continue;
final id = entry.key;
final remoteModifiedTime = DateTime.parse(entry.value);
@@ -78,7 +80,7 @@ class WebDavDashboardLogic extends GetxController {
Future<void> fetchingWebDavSyncFlag() async {
state.webdavSyncMap = await Utils().webDavUtil.fetchServerSyncData();
state.webDavDiaryCount.value = state.webdavSyncMap.length.toString();
state.webDavDiaryCount.value = state.webdavSyncMap.values.where((element) => element != 'delete').length.toString();
}
void toWebDavPage() async {
@@ -97,8 +99,7 @@ class WebDavDashboardLogic extends GetxController {
}, onDownload: () async {
state.toDownloadIdsCount.value = (int.parse(state.toDownloadIdsCount.value) - 1).toString();
checkIsDownloading();
await Bind.find<DiaryLogic>().updateCategory();
await Bind.find<DiaryLogic>().updateDiary(null);
await Bind.find<DiaryLogic>().refreshAll();
}, onComplete: () {
Get.backLegacy();
Utils().noticeUtil.showToast('同步完成');

View File

@@ -64,7 +64,8 @@ class DiaryDetailsLogic extends GetxController {
//放入回收站
Future<void> delete(Diary diary) async {
await Utils().isarUtil.updateADiary(diary..show = false);
var newDiary = diary.clone()..show = false;
await Utils().isarUtil.updateADiary(oldDiary: diary, newDiary: newDiary);
Get.backLegacy(result: 'delete');
}

View File

@@ -109,39 +109,39 @@ class EditLogic extends GetxController {
} else {
//如果是编辑,将日记对象赋值
state.isNew = false;
var oldDiary = Get.arguments as Diary;
state.type = DiaryType.values.firstWhere((type) => type.value == oldDiary.type);
state.currentDiary = oldDiary;
state.originalDiary = Get.arguments as Diary;
state.type = DiaryType.values.firstWhere((type) => type.value == state.originalDiary!.type);
state.currentDiary = state.originalDiary!.clone();
// 获取分类名称
if (oldDiary.categoryId != null) {
state.categoryName = Utils().isarUtil.getCategoryName(oldDiary.categoryId!)!.categoryName;
if (state.originalDiary!.categoryId != null) {
state.categoryName = Utils().isarUtil.getCategoryName(state.originalDiary!.categoryId!)!.categoryName;
}
// 初始化标题控制器
titleTextEditingController.text = oldDiary.title;
titleTextEditingController.text = state.originalDiary!.title;
// 待替换的字符串map
Map<String, String> replaceMap = {};
//临时拷贝一份图片数据
for (var name in oldDiary.imageName) {
for (var name in state.originalDiary!.imageName) {
// 生成一个临时文件
var xFile = XFile(Utils().fileUtil.getRealPath('image', name));
replaceMap[name] = xFile.path;
state.imageFileList.add(xFile);
}
//临时拷贝一份拷贝音频数据到缓存目录
for (var name in oldDiary.audioName) {
for (var name in state.originalDiary!.audioName) {
state.audioNameList.add(name);
await File(Utils().fileUtil.getRealPath('audio', name)).copy(Utils().fileUtil.getCachePath(name));
}
//临时拷贝一份视频数据,别忘记了缩略图
for (var name in oldDiary.videoName) {
for (var name in state.originalDiary!.videoName) {
// 生成一个临时文件
var videoXFile = XFile(Utils().fileUtil.getRealPath('video', name));
replaceMap[name] = videoXFile.path;
state.videoFileList.add(videoXFile);
}
quillController = QuillController(
document:
Document.fromJson(jsonDecode(await Kmp.replaceWithKmp(text: oldDiary.content, replacements: replaceMap))),
document: Document.fromJson(
jsonDecode(await Kmp.replaceWithKmp(text: state.originalDiary!.content, replacements: replaceMap))),
selection: const TextSelection.collapsed(offset: 0));
state.totalCount.value = _toPlainText().length;
}
@@ -357,7 +357,6 @@ class EditLogic extends GetxController {
..title = titleTextEditingController.text
..content = content
..type = state.type.value
..lastModified = DateTime.now()
..contentText = _toPlainText()
..audioName = state.audioNameList
..imageName = imageNameMap.values.toList()
@@ -365,9 +364,8 @@ class EditLogic extends GetxController {
..imageColor = await getCoverColor()
..aspect = await getCoverAspect();
await Utils().isarUtil.updateADiary(state.currentDiary);
await Utils().isarUtil.updateADiary(oldDiary: state.originalDiary, newDiary: state.currentDiary);
state.isNew ? Get.backLegacy(result: state.currentDiary.categoryId ?? '') : Get.backLegacy(result: 'changed');
if (Utils().webDavUtil.hasOption) unawaited(Utils().webDavUtil.uploadSingleDiary(state.currentDiary));
Utils().noticeUtil.showToast(state.isNew ? '保存成功' : '修改成功');
}

View File

@@ -2,7 +2,6 @@ import 'package:cross_file/cross_file.dart';
import 'package:get/get_rx/src/rx_types/rx_types.dart';
import 'package:mood_diary/common/models/isar/diary.dart';
import 'package:mood_diary/common/values/diary_type.dart';
import 'package:mood_diary/common/values/keyboard_state.dart';
import '../../utils/utils.dart';
@@ -10,6 +9,9 @@ class EditState {
// 当前编辑的日记对象
late Diary currentDiary;
// 编辑时的原始日记对象
Diary? originalDiary;
List<XFile> imageFileList = [];
List<String> get imagePathList => imageFileList.map((e) => e.path).toList();
@@ -34,7 +36,6 @@ class EditState {
bool isProcessing = false;
// 总字数
RxInt totalCount = 0.obs;

View File

@@ -43,8 +43,7 @@ class DiaryLogic extends GetxController with GetTickerProviderStateMixin {
if (Utils().prefUtil.getValue<bool>('autoSync') == true) {
var diary = await Utils().isarUtil.getAllDiaries();
await Utils().webDavUtil.syncDiary(diary, onDownload: () async {
await updateCategory();
await updateDiary(null);
await refreshAll();
});
}
}
@@ -144,6 +143,16 @@ class DiaryLogic extends GetxController with GetTickerProviderStateMixin {
await Bind.find<DiaryTabViewLogic>(tag: 'default').updateDiary();
}
Future<void> refreshAll() async {
await updateCategory();
await updateDiary(null, jump: true);
await Future.wait(
state.categoryList.map(
(category) => updateDiary(category.id, jump: false),
),
);
}
/// 分类刷新函数
/// 需要在以下情况调用
///

View File

@@ -27,7 +27,7 @@ class DiaryPage extends StatelessWidget {
),
child: RiveAnimatedIcon(
riveIcon: RiveIcon.reload,
color: colorScheme.onSecondaryContainer,
color: colorScheme.onPrimaryContainer,
width: 24,
height: 24,
loopAnimation: true,

View File

@@ -453,7 +453,6 @@ class SettingPage extends StatelessWidget {
assignId: true,
builder: (_) {
return CustomScrollView(
cacheExtent: size.height * 2,
slivers: [
SliverAppBar(
title: Text(i18n.homeNavigatorSetting),
@@ -464,6 +463,7 @@ class SettingPage extends StatelessWidget {
padding: const EdgeInsets.all(4.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
spacing: 4.0,
children: [
buildDashboard(),

View File

@@ -33,8 +33,11 @@ class RecycleLogic extends GetxController {
}
for (var name in state.diaryList[index].videoName) {
Utils().fileUtil.deleteFile(Utils().fileUtil.getRealPath('video', name));
// 删除缩略图
Utils().fileUtil.deleteFile(Utils().fileUtil.getRealPath('thumbnail', name));
}
Utils().noticeUtil.showToast('删除成功');
await Utils().webDavUtil.deleteSingleDiary(state.diaryList[index]);
//重新获取
getDiaryList();
}
@@ -43,9 +46,9 @@ class RecycleLogic extends GetxController {
//重新显示
Future<void> showDiary(Diary diary) async {
//将show置为true
diary.show = true;
final newDiary = diary.clone()..show = true;
//写入数据库
await Utils().isarUtil.updateADiary(diary);
await Utils().isarUtil.updateADiary(oldDiary: diary, newDiary: newDiary);
//重新获取
getDiaryList();
update();

View File

@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
@@ -6,6 +7,7 @@ import 'package:isar/isar.dart';
import 'package:latlong2/latlong.dart';
import 'package:mood_diary/common/models/isar/category.dart';
import 'package:mood_diary/common/models/isar/diary.dart';
import 'package:mood_diary/common/models/isar/sync_record.dart';
import 'package:mood_diary/common/models/map.dart';
import 'package:mood_diary/common/values/diary_type.dart';
import 'package:mood_diary/utils/utils.dart';
@@ -133,10 +135,22 @@ class IsarUtil {
}
//更新日记
Future<void> updateADiary(Diary diary) async {
Future<void> updateADiary({Diary? oldDiary, required Diary newDiary}) async {
// 如果没有旧日记,说明是新增日记
newDiary.lastModified = DateTime.now();
await _isar.writeAsync((isar) {
isar.diarys.put(diary);
isar.diarys.put(newDiary);
});
// 更新日记, 旧日记不为空,说明是更新日记, 需要清理旧日记的媒体文件
if (oldDiary != null) {
// 清理本地媒体文件
await Utils().fileUtil.cleanUpOldMediaFiles(oldDiary, newDiary);
if (Utils().webDavUtil.hasOption) {
unawaited(Utils().webDavUtil.updateSingleDiary(oldDiary: oldDiary, newDiary: newDiary));
}
} else {
if (Utils().webDavUtil.hasOption) unawaited(Utils().webDavUtil.uploadSingleDiary(newDiary));
}
}
//查询日记
@@ -378,4 +392,23 @@ class IsarUtil {
});
}
}
// 添加sync任务
Future<void> addSyncRecord(SyncRecord record) async {
await _isar.writeAsync((isar) {
isar.syncRecords.put(record);
});
}
// 获取sync任务
Future<List<SyncRecord>> getSyncRecords() async {
return await _isar.syncRecords.where().findAllAsync();
}
// 删除sync任务
Future<void> deleteSyncRecord(int id) async {
await _isar.writeAsync((isar) {
isar.syncRecords.delete(id);
});
}
}

View File

@@ -104,6 +104,12 @@ class PrefUtil {
await compute(Utils().isarUtil.mergeToV2_6_0, Utils().fileUtil.getRealPath('database', ''));
}
/// 修复bug
/// v2.6.2
if (appVersion != null && appVersion.split('+')[0].compareTo('2.6.2') < 0) {
await Utils().mediaUtil.regenerateMissingThumbnails();
}
// 如果是首次启动或版本不一致
if (kDebugMode || firstStart || appVersion == null || appVersion != currentVersion) {
await _prefs.setString('appVersion', currentVersion);

View File

@@ -5,6 +5,8 @@ import 'package:mood_diary/utils/utils.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import '../common/models/isar/diary.dart';
class FileUtil {
late final _filePath = Utils().prefUtil.getValue<String>('supportPath')!;
@@ -190,4 +192,21 @@ class FileUtil {
String getErrorLogPath() {
return join(_filePath, 'error.log');
}
Future<void> cleanUpOldMediaFiles(Diary oldDiary, Diary newDiary) async {
// 通用删除方法
Future<void> deleteMediaFiles(List<String> oldFiles, List<String> newFiles, String type) async {
final tasks = oldFiles
.where((file) => !newFiles.contains(file))
.map((file) => Utils().fileUtil.deleteFile(Utils().fileUtil.getRealPath(type, file)))
.toList();
await Future.wait(tasks);
}
// 删除旧的图片、视频和音频文件
await deleteMediaFiles(oldDiary.imageName, newDiary.imageName, 'image');
await deleteMediaFiles(oldDiary.videoName, newDiary.videoName, 'video');
await deleteMediaFiles(oldDiary.audioName, newDiary.audioName, 'audio');
await deleteMediaFiles(oldDiary.videoName, newDiary.videoName, 'thumbnail');
}
}

View File

@@ -10,6 +10,7 @@ import 'package:image_picker_platform_interface/image_picker_platform_interface.
import 'package:mime/mime.dart';
import 'package:mood_diary/src/rust/api/compress.dart';
import 'package:mood_diary/utils/utils.dart';
import 'package:path/path.dart';
import 'package:uuid/uuid.dart';
import '../src/rust/api/constants.dart' as r_type;
@@ -100,6 +101,51 @@ class MediaUtil {
return videoNameMap;
}
Future<void> regenerateMissingThumbnails() async {
// 获取视频和缩略图路径的工具方法
String getThumbnailPath(String videoName) => Utils().fileUtil.getRealPath('thumbnail', videoName);
// 获取视频文件夹中的所有文件
final videoDir = Directory(Utils().fileUtil.getRealPath('video', ''));
if (!videoDir.existsSync()) return;
// 遍历视频文件
final videoFiles = videoDir.listSync().whereType<File>();
for (final videoFile in videoFiles) {
final videoName = basename(videoFile.path);
final thumbnailPath = getThumbnailPath(videoName);
// 检查是否存在缩略图
if (!File(thumbnailPath).existsSync()) {
print("Thumbnail missing for $videoName. Regenerating...");
try {
// 生成临时缩略图路径
final tempThumbnailPath = Utils().fileUtil.getCachePath('${const Uuid().v7()}.jpeg');
// 获取视频缩略图
await Utils().mediaUtil.getVideoThumbnail(XFile(videoFile.path), tempThumbnailPath);
// 压缩并保存缩略图
await _compressRust(
XFile(tempThumbnailPath),
thumbnailPath,
r_type.CompressFormat.jpeg,
);
// 删除临时文件
await File(tempThumbnailPath).delete();
print("Thumbnail regenerated for $videoName.");
} catch (e) {
print("Failed to regenerate thumbnail for $videoName: $e");
}
} else {
print("Thumbnail exists for $videoName.");
}
}
}
//获取图片宽高
Future<Size> getImageSize(ImageProvider imageProvider) async {
final Completer<Size> completer = Completer<Size>();

View File

@@ -91,6 +91,48 @@ class WebDavUtil {
}
}
//删除某一篇日记将webdav中sync.json的对应日记id的value设置为delete
Future<void> deleteSingleDiary(Diary diary) async {
final serverSyncData = await fetchServerSyncData();
if (!serverSyncData.containsKey(diary.id)) {
return;
}
serverSyncData[diary.id] = 'delete';
await updateServerSyncData(serverSyncData);
// 删除日记json
await _client!.remove('${WebDavOptions.diaryPath}/${diary.id}.json');
// 遍历删除日记资源文件
await _deleteFiles(diary.imageName, WebDavOptions.imagePath, 'image');
await _deleteFiles(diary.audioName, WebDavOptions.audioPath, 'audio');
await _deleteFiles(diary.videoName, WebDavOptions.videoPath, 'video');
await _deleteFiles(diary.videoName.map((videoName) => 'thumbnail-${videoName.substring(6, 42)}.jpeg').toList(),
WebDavOptions.videoPath, 'thumbnail');
// 删除对应目录
await _client!.remove('${WebDavOptions.imagePath}/${diary.id}');
await _client!.remove('${WebDavOptions.audioPath}/${diary.id}');
await _client!.remove('${WebDavOptions.videoPath}/${diary.id}');
}
Future<void> _deleteDiary(Diary diary) async {
// 删除文件的通用方法
Future<void> deleteFiles(List<String> names, String folder) async {
final tasks =
names.map((name) => Utils().fileUtil.deleteFile(Utils().fileUtil.getRealPath(folder, name))).toList();
await Future.wait(tasks);
}
// 删除日记和关联文件
if (await Utils().isarUtil.deleteADiary(diary.isarId)) {
// 并行删除图片、音频、视频及其缩略图
await Future.wait([
deleteFiles(diary.imageName, 'image'),
deleteFiles(diary.audioName, 'audio'),
deleteFiles(diary.videoName, 'video'),
deleteFiles(diary.videoName, 'thumbnail'), // 视频缩略图
]);
}
}
Future<void> syncDiary(
List<Diary> localDiaries, {
flutter.VoidCallback? onUpload,
@@ -114,12 +156,30 @@ class WebDavUtil {
}
final localLastModified = localDiaryMap[diaryId];
//如果本地还有日记,但服务器中的日记已经被删除
if (serverLastModified == 'delete') {
if (localLastModified != null) {
syncingDiaries.add(diaryId);
await _deleteDiary(localDiaries.firstWhere((element) => element.id == diaryId));
syncingDiaries.remove(diaryId);
}
continue;
}
if (localLastModified == null || serverLastModified.compareTo(localLastModified) > 0) {
// 本地不存在该日记,下载
//本地不存在该日记,下载
if (localLastModified == null) {
syncingDiaries.add(diaryId);
final updatedDiary = await _downloadDiary(diaryId); // 下载日记的实现
await _saveLocalDiary(updatedDiary); // 保存到本地的实现
await Utils().isarUtil.insertADiary(updatedDiary); // 保存到本地的实现
onDownload?.call();
syncingDiaries.remove(diaryId);
}
// 本地存在该日记,但服务器版本较新,更新本地
if (localLastModified != null && serverLastModified.compareTo(localLastModified) > 0) {
syncingDiaries.add(diaryId);
final oldDiary = localDiaries.firstWhere((element) => element.id == diaryId);
final newDiary = await _downloadDiary(diaryId);
await Utils().isarUtil.updateADiary(oldDiary: oldDiary, newDiary: newDiary);
onDownload?.call();
syncingDiaries.remove(diaryId);
}
@@ -176,6 +236,42 @@ class WebDavUtil {
}
}
Future<void> updateSingleDiary({
required Diary oldDiary,
required Diary newDiary,
flutter.VoidCallback? onUpload,
flutter.VoidCallback? onComplete,
}) async {
if (syncingDiaries.contains(newDiary.id)) {
return; // 避免重复上传
}
syncingDiaries.add(newDiary.id);
try {
// 遍历删除日记资源文件
final needToDeleteImage = oldDiary.imageName.where((element) => !newDiary.imageName.contains(element)).toList();
final needToDeleteAudio = oldDiary.audioName.where((element) => !newDiary.audioName.contains(element)).toList();
final needToDeleteVideo = oldDiary.videoName.where((element) => !newDiary.videoName.contains(element)).toList();
final needToDeleteThumbnail =
needToDeleteVideo.map((videoName) => 'thumbnail-${videoName.substring(6, 42)}.jpeg').toList();
await _deleteFiles(needToDeleteImage, WebDavOptions.imagePath, 'image');
await _deleteFiles(needToDeleteAudio, WebDavOptions.audioPath, 'audio');
await _deleteFiles(needToDeleteVideo, WebDavOptions.videoPath, 'video');
await _deleteFiles(needToDeleteThumbnail, WebDavOptions.videoPath, 'thumbnail');
// 上传日记到服务器
await _uploadDiary(newDiary); // 上传日记的实现
// 更新服务器同步数据
final serverSyncData = await fetchServerSyncData();
serverSyncData[newDiary.id] = newDiary.lastModified.toIso8601String();
await updateServerSyncData(serverSyncData);
onUpload?.call();
} catch (e) {
Utils().logUtil.printInfo('Failed to upload diary: $e');
} finally {
syncingDiaries.remove(newDiary.id);
onComplete?.call(); // 调用完成回调
}
}
Future<void> _uploadDiary(Diary diary) async {
// 检查并上传分类
if (diary.categoryId != null) {
@@ -188,7 +284,7 @@ class WebDavUtil {
// 上传日记 JSON 数据
final diaryPath = '${WebDavOptions.diaryPath}/${diary.id}.json';
final diaryData = jsonEncode(diary.toJson());
Utils().logUtil.printInfo(diaryData);
try {
_client!.setHeaders({
'accept-charset': 'utf-8',
@@ -201,18 +297,20 @@ class WebDavUtil {
rethrow;
}
// 上传资源文件
await _uploadFiles(diary.imageName, WebDavOptions.imagePath, 'image');
await _uploadFiles(diary.audioName, WebDavOptions.audioPath, 'audio');
await _uploadFiles(diary.videoName, WebDavOptions.videoPath, 'video');
// 上传资源文件目标路径是资源文件夹下的日记id
await _uploadFiles(diary.imageName, '${WebDavOptions.imagePath}/${diary.id}', 'image');
await _uploadFiles(diary.audioName, '${WebDavOptions.audioPath}/${diary.id}', 'audio');
await _uploadFiles(diary.videoName, '${WebDavOptions.videoPath}/${diary.id}', 'video');
await _uploadFiles(diary.videoName, '${WebDavOptions.videoPath}/${diary.id}', 'thumbnail');
}
Future<void> _uploadFiles(List<String> fileNames, String resourcePath, String type) async {
// 检查服务器是否已经存在该文件
await _client!.mkdirAll(resourcePath);
final existingFiles = await _client!.readDir(resourcePath);
for (final fileName in fileNames) {
for (var fileName in fileNames) {
final filePath = Utils().fileUtil.getRealPath(type, fileName);
fileName = type == 'thumbnail' ? 'thumbnail-${fileName.substring(6, 42)}.jpeg' : fileName;
if (existingFiles.any((file) => file.name == fileName)) {
Utils().logUtil.printInfo('$type file already exists: $fileName');
continue;
@@ -232,6 +330,18 @@ class WebDavUtil {
}
}
Future<void> _deleteFiles(List<String> fileNames, String resourcePath, String type) async {
for (final fileName in fileNames) {
try {
await _client!.remove('$resourcePath/$fileName');
Utils().logUtil.printInfo('$type file deleted: $fileName');
} catch (e) {
Utils().logUtil.printInfo('Failed to delete $type file: $fileName, Error: $e');
rethrow;
}
}
}
Future<Diary> _downloadDiary(String diaryId) async {
// 下载日记 JSON 数据
final diaryPath = '${WebDavOptions.diaryPath}/$diaryId.json';
@@ -250,7 +360,7 @@ class WebDavUtil {
if (diary.categoryId != null) {
try {
final category = await _downloadCategory(diary.categoryId!);
Utils().isarUtil.insertACategory(Category()
await Utils().isarUtil.updateACategory(Category()
..id = category['id']!
..categoryName = category['name']!);
} catch (e) {
@@ -259,10 +369,11 @@ class WebDavUtil {
}
// 下载资源文件
diary.imageName = await _downloadFiles(diary.imageName, WebDavOptions.imagePath, 'image');
diary.audioName = await _downloadFiles(diary.audioName, WebDavOptions.audioPath, 'audio');
diary.videoName = await _downloadFiles(diary.videoName, WebDavOptions.videoPath, 'video');
diary.imageName = await _downloadFiles(diary.imageName, '${WebDavOptions.imagePath}/$diaryId', 'image');
diary.audioName = await _downloadFiles(diary.audioName, '${WebDavOptions.audioPath}/$diaryId', 'audio');
diary.videoName = await _downloadFiles(diary.videoName, '${WebDavOptions.videoPath}/$diaryId', 'video');
// 下载视频缩略图
await _downloadFiles(diary.videoName, '${WebDavOptions.videoPath}/$diaryId', 'thumbnail');
return diary;
}
@@ -270,7 +381,8 @@ class WebDavUtil {
final localFileNames = <String>[];
for (final fileName in fileNames) {
final serverFilePath = '$resourcePath/$fileName';
final serverFilePath =
type == 'thumbnail' ? '$resourcePath/thumbnail-${fileName.substring(6, 42)}.jpeg' : '$resourcePath/$fileName';
final localFilePath = Utils().fileUtil.getRealPath(type, fileName);
try {
@@ -287,11 +399,6 @@ class WebDavUtil {
return localFileNames;
}
Future<void> _saveLocalDiary(Diary diary) async {
// 使用 Isar 或文件存储
await Utils().isarUtil.insertADiary(diary);
}
Future<void> _uploadCategory(String categoryId, String categoryName) async {
final categoryPath = '${WebDavOptions.categoryPath}/$categoryId.json';
final categoryData = jsonEncode({'id': categoryId, 'name': categoryName});