diff --git a/lib/services/file_service.dart b/lib/services/file_service.dart index b88ed48..f1ea177 100644 --- a/lib/services/file_service.dart +++ b/lib/services/file_service.dart @@ -39,24 +39,54 @@ return filePath; } + /// 候補名が衝突した場合に `_1`, `_2`, ... と連番サフィックスを付与し, + /// 一意な名前を決定する(同期版). + /// + /// [baseName] 自体が衝突しなければ [baseName] を返し,衝突する場合は + /// suffix=1 から順に空きを探して `${baseName}_$suffix` を返す. + /// 衝突判定(拡張子の付与等)は [exists] クロージャが吸収する. + static String _resolveUniqueName( + String baseName, + bool Function(String name) exists, + ) { + if (!exists(baseName)) { + return baseName; + } + + var suffix = 1; + while (exists('${baseName}_$suffix')) { + suffix++; + } + return '${baseName}_$suffix'; + } + + /// [_resolveUniqueName] の非同期版.[exists] が `Future` を返す点のみが異なる. + static Future _resolveUniqueNameAsync( + String baseName, + Future Function(String name) exists, + ) async { + if (!await exists(baseName)) { + return baseName; + } + + var suffix = 1; + while (await exists('${baseName}_$suffix')) { + suffix++; + } + return '${baseName}_$suffix'; + } + /// ファイル名を生成する. /// /// 形式: MiniTIAS_YYYYMMDD_HHmmss.png /// 同秒の重複がある場合は _1, _2, ... と連番を付与する. Future generateFileName() async { - final timestamp = _buildTimestamp(DateTime.now()); - final baseName = 'MiniTIAS_$timestamp'; - final candidate = '$baseName.png'; - - if (!await File('$directoryPath/$candidate').exists()) { - return candidate; - } - - var suffix = 1; - while (await File('$directoryPath/${baseName}_$suffix.png').exists()) { - suffix++; - } - return '${baseName}_$suffix.png'; + final baseName = 'MiniTIAS_${_buildTimestamp(DateTime.now())}'; + final resolved = await _resolveUniqueNameAsync( + baseName, + (name) => File('$directoryPath/$name.png').exists(), + ); + return '$resolved.png'; } /// カメラ診断情報を JSON ファイルとして保存する. @@ -83,17 +113,11 @@ List existingFiles, ) { final baseName = 'MiniTIAS_$timestamp'; - final candidate = '$baseName.png'; - - if (!existingFiles.contains(candidate)) { - return candidate; - } - - var suffix = 1; - while (existingFiles.contains('${baseName}_$suffix.png')) { - suffix++; - } - return '${baseName}_$suffix.png'; + final resolved = _resolveUniqueName( + baseName, + (name) => existingFiles.contains('$name.png'), + ); + return '$resolved.png'; } /// 定量モード撮影用のファイル名 prefix を生成する. @@ -102,17 +126,11 @@ /// 同秒の重複がある場合は `_1`, `_2` ...と連番を付与する. /// 重複判定は `.dng` の存在チェックで行う. Future generateQuantitativeBaseName() async { - final candidate = 'MiniTIAS_QM_${_buildTimestamp(DateTime.now())}'; - - if (!await File('$directoryPath/$candidate.dng').exists()) { - return candidate; - } - - var suffix = 1; - while (await File('$directoryPath/${candidate}_$suffix.dng').exists()) { - suffix++; - } - return '${candidate}_$suffix'; + final baseName = 'MiniTIAS_QM_${_buildTimestamp(DateTime.now())}'; + return _resolveUniqueNameAsync( + baseName, + (name) => File('$directoryPath/$name.dng').exists(), + ); } /// テスト用同期版.既存ファイル名のリストとタイムスタンプを受け取って baseName を返す. @@ -122,17 +140,11 @@ String timestamp, List existingFiles, ) { - final candidate = 'MiniTIAS_QM_$timestamp'; - - if (!existingFiles.contains('$candidate.dng')) { - return candidate; - } - - var suffix = 1; - while (existingFiles.contains('${candidate}_$suffix.dng')) { - suffix++; - } - return '${candidate}_$suffix'; + final baseName = 'MiniTIAS_QM_$timestamp'; + return _resolveUniqueName( + baseName, + (name) => existingFiles.contains('$name.dng'), + ); } /// ライブプレビューのスナップショット JPEG を `.preview.jpg` として保存する.