diff --git a/lib/providers/gallery_provider.dart b/lib/providers/gallery_provider.dart index 215dd62..397d1a5 100644 --- a/lib/providers/gallery_provider.dart +++ b/lib/providers/gallery_provider.dart @@ -6,12 +6,17 @@ /// 画像一覧の取得・キャッシュ・削除操作を管理する. class GalleryProvider extends ChangeNotifier { - /// MediaStore 通知に使うサービスはコンストラクタで差し替え可能(省略時は既定実装). - GalleryProvider({RawCaptureService? rawCaptureService}) - : _rawCaptureService = rawCaptureService ?? RawCaptureService(); + /// 画像一覧の取得元ディレクトリは省略可能(省略時は本番の共有ストレージパス). + /// + /// MediaStore 通知に使うサービスもコンストラクタで差し替え可能(省略時は既定実装). + /// テストでは一時ディレクトリを渡して実メソッドを直接検証できる. + GalleryProvider({String? basePath, RawCaptureService? rawCaptureService}) + : _basePath = basePath ?? _defaultBasePath, + _rawCaptureService = rawCaptureService ?? RawCaptureService(); - static const _basePath = '/storage/emulated/0/Pictures/MiniTIAS'; + static const _defaultBasePath = '/storage/emulated/0/Pictures/MiniTIAS'; + final String _basePath; final RawCaptureService _rawCaptureService; List _images = []; diff --git a/test/providers/gallery_provider_test.dart b/test/providers/gallery_provider_test.dart index fa8d92a..dcc2a86 100644 --- a/test/providers/gallery_provider_test.dart +++ b/test/providers/gallery_provider_test.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:smtias_capture/providers/gallery_provider.dart'; @@ -20,105 +19,16 @@ } } -/// テスト専用の GalleryProvider 実装. -/// -/// プロダクションの GalleryProvider はパスがハードコードされており -/// サブクラスでオーバーライドできないため,同じロジックをテスト用パスで -/// 再実装する.仕様(SPEC_01)に準拠した振る舞いをテストする. -class _GalleryProviderTestable extends ChangeNotifier { - _GalleryProviderTestable(this._basePath); - - final String _basePath; - - List _images = []; - bool _isLoading = false; - - List get images => _images; - bool get isLoading => _isLoading; - - /// Pictures/MiniTIAS/ 内の PNG と .preview.jpg を取得し,新しい順に並べる. - Future loadImages() async { - _isLoading = true; - notifyListeners(); - - try { - final directory = Directory(_basePath); - if (!await directory.exists()) { - _images = []; - } else { - final files = await directory - .list() - .where((entity) { - final lower = entity.path.toLowerCase(); - return entity is File && - (lower.endsWith('.png') || lower.endsWith('.preview.jpg')); - }) - .cast() - .toList(); - - // 更新日時の新しい順にソート - files.sort((a, b) { - final aStat = a.statSync(); - final bStat = b.statSync(); - return bStat.modified.compareTo(aStat.modified); - }); - - _images = files; - } - } catch (e) { - debugPrint('画像一覧の取得に失敗: $e'); - _images = []; - } - - _isLoading = false; - notifyListeners(); - } - - /// 指定したファイルを削除し,一覧から除去する. - /// - /// QM プレビュー (*.preview.jpg) を削除する場合,同じ baseName の - /// .dng ファイルと .meta.json ファイルも連動して削除する. - /// .png ファイルは単独削除(後方互換). - Future deleteImage(File file) async { - final path = file.path; - final lower = path.toLowerCase(); - - final filesToDelete = [file]; - if (lower.endsWith('.preview.jpg')) { - final base = path.substring(0, path.length - '.preview.jpg'.length); - filesToDelete.add(File('$base.dng')); - filesToDelete.add(File('$base.meta.json')); - } - - try { - for (final f in filesToDelete) { - if (await f.exists()) { - await f.delete(); - } - } - if (!await file.exists()) { - _images.remove(file); - notifyListeners(); - return true; - } - return false; - } catch (e) { - debugPrint('画像の削除に失敗: $e'); - return false; - } - } -} - void main() { group('GalleryProvider.loadImages', () { late Directory tempDir; - late _GalleryProviderTestable provider; + late GalleryProvider provider; setUp(() async { tempDir = await Directory.systemTemp.createTemp( 'smtias_capture_gallery_test_', ); - provider = _GalleryProviderTestable(tempDir.path); + provider = GalleryProvider(basePath: tempDir.path); }); tearDown(() async { @@ -208,7 +118,7 @@ test('ディレクトリが存在しない場合,空リストを返す', () async { final nonExistentPath = '${tempDir.path}/nonexistent'; - final providerNonExistent = _GalleryProviderTestable(nonExistentPath); + final providerNonExistent = GalleryProvider(basePath: nonExistentPath); await providerNonExistent.loadImages(); @@ -238,13 +148,18 @@ group('GalleryProvider.deleteImage', () { late Directory tempDir; - late _GalleryProviderTestable provider; + late _FakeRawCaptureService fakeRawCapture; + late GalleryProvider provider; setUp(() async { tempDir = await Directory.systemTemp.createTemp( 'smtias_capture_del_test_', ); - provider = _GalleryProviderTestable(tempDir.path); + fakeRawCapture = _FakeRawCaptureService(); + provider = GalleryProvider( + basePath: tempDir.path, + rawCaptureService: fakeRawCapture, + ); }); tearDown(() async {