diff --git a/lib/app/folder_readme.dart b/lib/app/folder_readme.dart new file mode 100644 index 0000000..ed75626 --- /dev/null +++ b/lib/app/folder_readme.dart @@ -0,0 +1,24 @@ +// l10n-skip-file: README.txt 의 영어 · 한국어 글 (화면 언어와 상관없이 둘 다 쓴다) +import 'dart:io'; + +import 'package:path/path.dart' as p; + +/// Download 아래에 만드는 한국어 이름 폴더 ("설정 보관" · "AI 모델 보관") 를 한국어를 모르는 사용자도 알아보게 +/// 그 폴더 안에 README.txt (영어 · 한국어). 이미 있으면 그대로. 실패해도 보관에는 영향 없음. +/// 작은 파일이라 바로 쓴다 (보관 흐름에 기다릴 단계를 더하지 않게). +void writeFolderReadme(String dir, String text) { + try { + final f = File(p.join(dir, 'README.txt')); + if (f.existsSync()) return; + Directory(dir).createSync(recursive: true); + f.writeAsStringSync('$text\r\n'); + } catch (_) {} +} + +const settingsBackupReadme = 'JJ_MKVMaker settings backup / 설정 보관\r\n' + 'Settings kept for each app version (one folder per version), used when going back to that version.\r\n' + '앱 버전마다 보관한 설정입니다 (버전마다 폴더 하나). 그 버전으로 되돌릴 때 씁니다.'; + +const modelBackupReadme = 'JJ_MKVMaker AI model backup / AI 모델 보관\r\n' + 'AI models copied aside before going back to an older version, so they do not have to be downloaded again.\r\n' + '예전 버전으로 되돌리기 전에 옮겨 둔 AI 모델입니다. 다시 받지 않아도 되게 되살립니다.'; diff --git a/lib/app/model_backup.dart b/lib/app/model_backup.dart index d74694e..c631141 100644 --- a/lib/app/model_backup.dart +++ b/lib/app/model_backup.dart @@ -5,6 +5,7 @@ import 'package:crypto/crypto.dart'; import 'package:path/path.dart' as p; import 'component_store.dart' show AccumulatorSink; +import 'folder_readme.dart'; /// P0 (되돌리기): Android 에서 예전 버전으로 되돌리면 앱을 지워야 해서 앱 안에 받은 AI 모델이 사라진다. /// 공용 폴더 (Download/JJ_MKVMaker/AI 모델 보관) 에 옮겨 두었다가, 다시 설치한 앱 (이 기능이 있는 판) 이 켜질 때 @@ -20,6 +21,7 @@ class ModelBackup { /// 공용 폴더 Download/JJ_MKVMaker (Android, main 에서 정함) static String? sharedRoot; + // l10n-skip: 실제 폴더 이름 (예전 보관을 찾아야 하므로 바꾸지 않음) static ModelBackup? get shared => sharedRoot == null ? null : ModelBackup(p.join(sharedRoot!, 'AI 모델 보관')); File get _manifest => File(p.join(dir, 'manifest.json')); @@ -89,6 +91,7 @@ class ModelBackup { }); list.add({'root': root, 'rel': p.posix.joinAll(p.split(rel)), 'size': f.lengthSync(), 'sha256': sha}); } + writeFolderReadme(dir, modelBackupReadme); // "AI 모델 보관" 은 한국어 이름이라 (영어 · 한국어) // 목록은 마지막에 (목록이 있으면 다 복사된 것) await _manifest.writeAsString(jsonEncode({'saved': DateTime.now().toIso8601String(), 'files': list})); } catch (_) { diff --git a/lib/app/version_snapshot.dart b/lib/app/version_snapshot.dart index 74d0b39..6c3df20 100644 --- a/lib/app/version_snapshot.dart +++ b/lib/app/version_snapshot.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:path/path.dart' as p; import '../core/app_update.dart'; +import 'folder_readme.dart'; /// 버전을 바꿀 때 (업데이트 · 예전 버전으로 되돌리기) 그 버전의 설정을 보관하고, 그 버전으로 돌아오면 되살린다. /// @@ -60,6 +61,8 @@ class VersionSnapshot { /// 지금 버전 ([version]) 의 설정을 보관한다 (같은 버전의 보관본은 새것으로). 공용 폴더에도 (있으면). Future save(String version) async { + // Download 아래 "설정 보관" 은 한국어 이름이라 안에 README.txt (영어 · 한국어) + if (sharedDir != null) writeFolderReadme(sharedDir!, settingsBackupReadme); for (final dir in [dirOf(version), if (sharedDir != null) p.join(sharedDir!, version)]) { final d = Directory(dir); if (await d.exists()) await d.delete(recursive: true); diff --git a/test/model_backup_test.dart b/test/model_backup_test.dart index c2b7cf7..a5c2dce 100644 --- a/test/model_backup_test.dart +++ b/test/model_backup_test.dart @@ -38,6 +38,7 @@ void main() { expect(progress.last, size); expect(backup.exists, true); expect(backup.savedSize, size); + expect(File(p.join(backup.dir, 'README.txt')).readAsStringSync(), startsWith('JJ_MKVMaker AI model backup / AI 모델 보관')); final before = File(p.join(roots['ai']!, 'models', 'sd15.safetensors')).readAsBytesSync(); wipeAppData(); // 앱을 지움 final r = await backup.restore(roots); diff --git a/test/version_snapshot_test.dart b/test/version_snapshot_test.dart index d6aebdf..d080ccb 100644 --- a/test/version_snapshot_test.dart +++ b/test/version_snapshot_test.dart @@ -42,6 +42,8 @@ void main() { await snap.save('2026.10.05_003'); await snap.save('2026.10.07_001'); expect(File(p.join(shared, '2026.10.05_003', 'settings.json')).existsSync(), isTrue); + // 한국어 이름 폴더 ("설정 보관") 를 알아보게 README.txt (영어 · 한국어) - 보관본 고르기에는 끼지 않는다 + expect(File(p.join(shared, 'README.txt')).readAsStringSync(), startsWith('JJ_MKVMaker settings backup / 설정 보관')); expect(p.basename(snap.sharedFor('2026.10.05_003')!), '2026.10.05_003'); expect(p.basename(snap.sharedFor('2026.10.01_001')!), '2026.10.07_001'); expect(VersionSnapshot(data.path).sharedFor('x'), isNull);