save method

Future<String> save({
  1. String? id,
  2. required String title,
  3. required ProjectState state,
})

Saves state and returns the project id (a new one when id is null).

Implementation

Future<String> save({
  String? id,
  required String title,
  required ProjectState state,
}) async {
  final projectId = id ?? 'project_${DateTime.now().microsecondsSinceEpoch}';
  final root = await _root();
  final dir = Directory('${root.path}/$projectId');
  final media = Directory('${dir.path}/media');
  await media.create(recursive: true);

  final temp = await _tempPath();
  final copied = <String, String>{};
  Future<File> keep(File file) async {
    final path = file.path;
    if (temp == null || !path.startsWith(temp) || !await file.exists()) {
      return file;
    }
    final known = copied[path];
    if (known != null) return File(known);
    final target = File('${media.path}/${fileBaseName(path)}');
    if (!await target.exists() ||
        await target.length() != await file.length()) {
      await file.copy(target.path);
    }
    copied[path] = target.path;
    return target;
  }

  final clips = <VideoEditorClip>[];
  for (final clip in state.clips) {
    final thumbs = <File>[];
    for (final thumb in clip.thumbnails) {
      thumbs.add(await keep(thumb));
    }
    clips.add(clip.copyWith(file: await keep(clip.file), thumbnails: thumbs));
  }
  final tracks = <VideoEditorAudioTrack>[];
  for (final track in state.audioTracks) {
    tracks.add(track.copyWith(file: await keep(track.file)));
  }
  final saved = ProjectState(
    clips: clips,
    audioTracks: tracks,
    textOverlays: state.textOverlays,
    effects: state.effects,
    aspectRatio: state.aspectRatio,
  );

  final duration = clips.fold<Duration>(
    Duration.zero,
    (sum, c) => sum + c.effectiveDuration,
  );
  String? thumbnail;
  if (clips.isNotEmpty) {
    final first = clips.first;
    thumbnail = first.isImage
        ? first.file.path
        : (first.thumbnails.isEmpty ? null : first.thumbnails.first.path);
  }

  final document = {
    'version': 1,
    'id': projectId,
    'title': title,
    'modified': DateTime.now().toIso8601String(),
    'durationMs': duration.inMilliseconds,
    'thumbnail': thumbnail,
    'aspect': state.aspectRatio.label,
    'state': saved.toJson(),
  };
  final file = File('${dir.path}/project.json');
  final tmp = File('${dir.path}/project.json.tmp');
  await tmp.writeAsString(jsonEncode(document), flush: true);
  await tmp.rename(file.path);
  return projectId;
}