snap_wish/lib/data/repositories/image_repository_impl.dart
2025-09-17 09:49:37 +08:00

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');
}
}
}