import 'dart:io'; import 'dart:typed_data'; /// 撮影画像の保存・命名・削除を行うサービス. class FileService { static const _basePath = '/storage/emulated/0/Pictures/MiniTIAS'; /// 保存先ディレクトリのパスを返す. String get directoryPath => _basePath; /// PNG バイト列をファイルに書き込んで保存する. /// /// Android ネイティブ側で YUV→RGB→PNG 変換済みのバイト列を受け取り, /// そのまま書き込むため高速に動作する. Future saveImage(Uint8List pngBytes) async { final directory = Directory(_basePath); if (!await directory.exists()) { await directory.create(recursive: true); } final fileName = await generateFileName(); final filePath = '$_basePath/$fileName'; await File(filePath).writeAsBytes(pngBytes); return filePath; } /// ファイル名を生成する. /// /// 形式: MiniTIAS_YYYYMMDD_HHmmss.png /// 同秒の重複がある場合は _1, _2, ... と連番を付与する. Future generateFileName() async { final now = DateTime.now(); final timestamp = '${now.year}' '${now.month.toString().padLeft(2, '0')}' '${now.day.toString().padLeft(2, '0')}' '_' '${now.hour.toString().padLeft(2, '0')}' '${now.minute.toString().padLeft(2, '0')}' '${now.second.toString().padLeft(2, '0')}'; final baseName = 'MiniTIAS_$timestamp'; final candidate = '$baseName.png'; if (!await File('$_basePath/$candidate').exists()) { return candidate; } var suffix = 1; while (await File('$_basePath/${baseName}_$suffix.png').exists()) { suffix++; } return '${baseName}_$suffix.png'; } /// テスト用: タイムスタンプとファイル名一覧からファイル名を生成する. static String generateFileNameSync( String timestamp, 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'; } }