Newer
Older
MiniTias / lib / services / file_service.dart
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<String> 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<String> 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<String> 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';
  }
}