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 saveImage(InspirationImage image) async { try { // 验证图片数据完整性 _validateImageData(image); // 保存图片到本地存储 return await _imageDao.insertImage(image); } catch (e) { throw Exception('保存图片失败: ${e.toString()}'); } } @override Future> saveImages(List images) async { try { // 验证所有图片数据 for (final image in images) { _validateImageData(image); } // 批量保存图片 return await _imageDao.insertImages(images); } catch (e) { throw Exception('批量保存图片失败: ${e.toString()}'); } } @override Future getImage(String id) async { try { return await _imageDao.getImageById(id); } catch (e) { throw Exception('获取图片失败: ${e.toString()}'); } } @override Future> getAllImages() async { try { return await _imageDao.getAllImages(); } catch (e) { throw Exception('获取所有图片失败: ${e.toString()}'); } } @override Future> 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> 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> 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> 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> getFavoriteImages() async { try { return await _imageDao.getFavoriteImages(); } catch (e) { throw Exception('获取收藏图片失败: ${e.toString()}'); } } @override Future 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> updateImages(List 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 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 deleteImages(List ids) async { try { if (ids.isEmpty) { return true; } // 获取所有要删除的图片信息 final imagesToDelete = []; 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 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 getImageCount() async { try { return await _imageDao.getImageCount(); } catch (e) { throw Exception('获取图片数量失败: ${e.toString()}'); } } @override Future 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 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 _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'); } } }