366 lines
10 KiB
Dart
366 lines
10 KiB
Dart
import 'dart:io';
|
|
import '../../domain/entities/inspiration_image.dart';
|
|
import '../../domain/repositories/image_repository.dart';
|
|
import '../datasources/local/image_dao.dart';
|
|
|
|
/// 图片仓库实现类 - 实现图片数据访问的具体逻辑
|
|
/// 负责协调不同数据源,实现业务规则和数据转换
|
|
class ImageRepositoryImpl implements ImageRepository {
|
|
final ImageDao _imageDao;
|
|
|
|
/// 构造函数 - 注入图片数据访问对象
|
|
ImageRepositoryImpl({required ImageDao imageDao}) : _imageDao = imageDao;
|
|
|
|
@override
|
|
Future<String> saveImage(InspirationImage image) async {
|
|
try {
|
|
// 验证图片数据完整性
|
|
_validateImageData(image);
|
|
|
|
// 保存图片到本地存储
|
|
return await _imageDao.insertImage(image);
|
|
} catch (e) {
|
|
throw Exception('保存图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<List<String>> saveImages(List<InspirationImage> images) async {
|
|
try {
|
|
// 验证所有图片数据
|
|
for (final image in images) {
|
|
_validateImageData(image);
|
|
}
|
|
|
|
// 批量保存图片
|
|
return await _imageDao.insertImages(images);
|
|
} catch (e) {
|
|
throw Exception('批量保存图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<InspirationImage?> getImage(String id) async {
|
|
try {
|
|
return await _imageDao.getImageById(id);
|
|
} catch (e) {
|
|
throw Exception('获取图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<List<InspirationImage>> getAllImages() async {
|
|
try {
|
|
return await _imageDao.getAllImages();
|
|
} catch (e) {
|
|
throw Exception('获取所有图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<List<InspirationImage>> getImagesPaginated(int page, int pageSize) async {
|
|
try {
|
|
// 计算偏移量
|
|
final offset = page * pageSize;
|
|
|
|
return await _imageDao.getImagesPaginated(offset, pageSize);
|
|
} catch (e) {
|
|
throw Exception('分页获取图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<List<InspirationImage>> getImagesByFolder(String folderId) async {
|
|
try {
|
|
// 验证文件夹ID
|
|
if (folderId.isEmpty) {
|
|
throw Exception('文件夹ID不能为空');
|
|
}
|
|
|
|
return await _imageDao.getImagesByFolder(folderId);
|
|
} catch (e) {
|
|
throw Exception('获取文件夹图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<List<InspirationImage>> getImagesByTag(String tagId) async {
|
|
try {
|
|
// 验证标签ID
|
|
if (tagId.isEmpty) {
|
|
throw Exception('标签ID不能为空');
|
|
}
|
|
|
|
return await _imageDao.getImagesByTag(tagId);
|
|
} catch (e) {
|
|
throw Exception('获取标签图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<List<InspirationImage>> searchImages(String query) async {
|
|
try {
|
|
// 验证搜索关键词
|
|
if (query.trim().isEmpty) {
|
|
return [];
|
|
}
|
|
|
|
// 执行搜索
|
|
final results = await _imageDao.searchImages(query.trim());
|
|
|
|
// 如果搜索结果为空,尝试搜索相关标签的图片
|
|
if (results.isEmpty) {
|
|
// TODO: 这里可以添加标签搜索逻辑
|
|
// 需要注入TagRepository来获取标签信息
|
|
}
|
|
|
|
return results;
|
|
} catch (e) {
|
|
throw Exception('搜索图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<List<InspirationImage>> getFavoriteImages() async {
|
|
try {
|
|
return await _imageDao.getFavoriteImages();
|
|
} catch (e) {
|
|
throw Exception('获取收藏图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<InspirationImage> updateImage(InspirationImage image) async {
|
|
try {
|
|
// 验证图片数据完整性
|
|
_validateImageData(image);
|
|
|
|
// 检查图片是否存在
|
|
final existingImage = await _imageDao.getImageById(image.id);
|
|
if (existingImage == null) {
|
|
throw Exception('图片不存在: ${image.id}');
|
|
}
|
|
|
|
// 更新图片信息
|
|
return await _imageDao.updateImage(image);
|
|
} catch (e) {
|
|
throw Exception('更新图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<List<InspirationImage>> updateImages(List<InspirationImage> images) async {
|
|
try {
|
|
// 验证所有图片数据
|
|
for (final image in images) {
|
|
_validateImageData(image);
|
|
}
|
|
|
|
// 检查所有图片是否存在
|
|
for (final image in images) {
|
|
final existingImage = await _imageDao.getImageById(image.id);
|
|
if (existingImage == null) {
|
|
throw Exception('图片不存在: ${image.id}');
|
|
}
|
|
}
|
|
|
|
// 批量更新图片
|
|
return await _imageDao.updateImages(images);
|
|
} catch (e) {
|
|
throw Exception('批量更新图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<bool> deleteImage(String id) async {
|
|
try {
|
|
// 验证图片ID
|
|
if (id.isEmpty) {
|
|
throw Exception('图片ID不能为空');
|
|
}
|
|
|
|
// 检查图片是否存在
|
|
final existingImage = await _imageDao.getImageById(id);
|
|
if (existingImage == null) {
|
|
throw Exception('图片不存在: $id');
|
|
}
|
|
|
|
// 删除图片文件(这里需要实现文件删除逻辑)
|
|
await _deleteImageFiles(existingImage);
|
|
|
|
// 从数据库删除图片记录
|
|
return await _imageDao.deleteImage(id);
|
|
} catch (e) {
|
|
throw Exception('删除图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<bool> deleteImages(List<String> ids) async {
|
|
try {
|
|
if (ids.isEmpty) {
|
|
return true;
|
|
}
|
|
|
|
// 获取所有要删除的图片信息
|
|
final imagesToDelete = <InspirationImage>[];
|
|
for (final id in ids) {
|
|
final image = await _imageDao.getImageById(id);
|
|
if (image != null) {
|
|
imagesToDelete.add(image);
|
|
}
|
|
}
|
|
|
|
// 删除所有图片文件
|
|
for (final image in imagesToDelete) {
|
|
await _deleteImageFiles(image);
|
|
}
|
|
|
|
// 从数据库批量删除图片记录
|
|
return await _imageDao.deleteImages(ids);
|
|
} catch (e) {
|
|
throw Exception('批量删除图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<int> deleteImagesByFolder(String folderId) async {
|
|
try {
|
|
// 验证文件夹ID
|
|
if (folderId.isEmpty) {
|
|
throw Exception('文件夹ID不能为空');
|
|
}
|
|
|
|
// 获取文件夹内的所有图片
|
|
final imagesInFolder = await _imageDao.getImagesByFolder(folderId);
|
|
|
|
// 删除所有图片文件
|
|
for (final image in imagesInFolder) {
|
|
await _deleteImageFiles(image);
|
|
}
|
|
|
|
// 删除数据库记录
|
|
return await _imageDao.deleteImagesByFolder(folderId);
|
|
} catch (e) {
|
|
throw Exception('删除文件夹图片失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<int> getImageCount() async {
|
|
try {
|
|
return await _imageDao.getImageCount();
|
|
} catch (e) {
|
|
throw Exception('获取图片数量失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<int> getImageCountByFolder(String folderId) async {
|
|
try {
|
|
// 验证文件夹ID
|
|
if (folderId.isEmpty) {
|
|
throw Exception('文件夹ID不能为空');
|
|
}
|
|
|
|
return await _imageDao.getImageCountByFolder(folderId);
|
|
} catch (e) {
|
|
throw Exception('获取文件夹图片数量失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<bool> imageExists(String id) async {
|
|
try {
|
|
// 验证图片ID
|
|
if (id.isEmpty) {
|
|
return false;
|
|
}
|
|
|
|
return await _imageDao.imageExists(id);
|
|
} catch (e) {
|
|
throw Exception('检查图片存在性失败: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
/// 验证图片数据完整性 - 确保图片数据符合业务规则
|
|
/// [image] 要验证的图片实体
|
|
/// 如果数据无效则抛出异常
|
|
void _validateImageData(InspirationImage image) {
|
|
// 验证ID
|
|
if (image.id.isEmpty) {
|
|
throw Exception('图片ID不能为空');
|
|
}
|
|
|
|
// 验证文件路径
|
|
if (image.filePath.isEmpty) {
|
|
throw Exception('图片文件路径不能为空');
|
|
}
|
|
|
|
// 验证缩略图路径
|
|
if (image.thumbnailPath.isEmpty) {
|
|
throw Exception('缩略图路径不能为空');
|
|
}
|
|
|
|
// 验证文件存在性
|
|
final file = File(image.filePath);
|
|
if (!file.existsSync()) {
|
|
throw Exception('图片文件不存在: ${image.filePath}');
|
|
}
|
|
|
|
// 验证缩略图文件存在性
|
|
final thumbnailFile = File(image.thumbnailPath);
|
|
if (!thumbnailFile.existsSync()) {
|
|
throw Exception('缩略图文件不存在: ${image.thumbnailPath}');
|
|
}
|
|
|
|
// 验证文件大小
|
|
if (image.fileSize <= 0) {
|
|
throw Exception('文件大小必须大于0');
|
|
}
|
|
|
|
// 验证MIME类型
|
|
if (image.mimeType.isEmpty) {
|
|
throw Exception('MIME类型不能为空');
|
|
}
|
|
|
|
// 验证创建时间
|
|
if (image.createdAt.isAfter(DateTime.now())) {
|
|
throw Exception('创建时间不能是未来时间');
|
|
}
|
|
|
|
// 验证更新时间
|
|
if (image.updatedAt.isBefore(image.createdAt)) {
|
|
throw Exception('更新时间不能早于创建时间');
|
|
}
|
|
}
|
|
|
|
/// 删除图片文件 - 从文件系统中删除图片文件和缩略图
|
|
/// [image] 要删除的图片实体
|
|
/// 删除失败时会记录错误但不会抛出异常
|
|
Future<void> _deleteImageFiles(InspirationImage image) async {
|
|
try {
|
|
// 删除原图文件
|
|
final imageFile = File(image.filePath);
|
|
if (imageFile.existsSync()) {
|
|
await imageFile.delete();
|
|
}
|
|
} catch (e) {
|
|
// 记录错误但不抛出异常,避免影响数据库操作
|
|
// TODO: 使用日志系统替代print
|
|
// print('删除图片文件失败: ${image.filePath}, 错误: $e');
|
|
}
|
|
|
|
try {
|
|
// 删除缩略图文件
|
|
final thumbnailFile = File(image.thumbnailPath);
|
|
if (thumbnailFile.existsSync()) {
|
|
await thumbnailFile.delete();
|
|
}
|
|
} catch (e) {
|
|
// 记录错误但不抛出异常,避免影响数据库操作
|
|
// TODO: 使用日志系统替代print
|
|
// print('删除缩略图文件失败: ${image.thumbnailPath}, 错误: $e');
|
|
}
|
|
}
|
|
} |