import 'dart:io'; import 'dart:typed_data'; import 'package:file_picker/file_picker.dart'; import 'package:path/path.dart' as p; import '../../core/subtitle_detector.dart'; import '../../services/storage_service.dart'; import '../../l10n/tr.dart'; class DesktopStorageService implements StorageService { /// [tempDirectory] 의 기준 폴더 (null = 시스템 임시 폴더). 시험이 파일마다 따로 쓰고 끝에 지우게 한다 /// (test/flutter_test_config.dart - 예전에는 시험이 %TEMP%\jj_mkvmaker 를 남겼다, 관리자 지시 10/20) static String? tempRoot; @override Future> pickVideos() async { final files = await FilePicker.pickFiles( dialogTitle: tr('동영상 선택'), type: FileType.custom, allowedExtensions: videoExtensions, ); return files.map((f) => f.path).whereType().toList(); } @override Future> pickSubtitles({String? initialDirectory}) async { final files = await FilePicker.pickFiles( dialogTitle: tr('자막 파일 선택'), initialDirectory: initialDirectory, type: FileType.custom, allowedExtensions: subtitleExtensions, ); return files.map((f) => f.path).whereType().toList(); } @override Future> pickFiles({required String title, required List extensions, String? initialDirectory}) async { final files = await FilePicker.pickFiles( dialogTitle: title, initialDirectory: initialDirectory, // 확장자 목록이 비면 모든 파일 (88: 확장자가 없는 개인 키 파일) type: extensions.isEmpty ? FileType.any : FileType.custom, allowedExtensions: extensions.isEmpty ? null : extensions, ); return files.map((f) => f.path).whereType().toList(); } @override Future> listFiles(String directory) async { final dir = Directory(directory); if (!await dir.exists()) return []; return dir .list(followLinks: false) .where((e) => e is File) .map((e) => e.path) .toList(); } @override Future ensureDirectory(String directory) => Directory(directory).create(recursive: true); @override Future exists(String path) => File(path).exists(); @override Future> readHead(String path, int maxBytes) async { final raf = await File(path).open(); try { return await raf.read(maxBytes); } finally { await raf.close(); } } @override Future readBytes(String path) => File(path).readAsBytes(); @override Future fileSize(String path) => File(path).length(); @override Future readRange(String path, int start, int length) async { final raf = await File(path).open(); try { await raf.setPosition(start); return await raf.read(length); } finally { await raf.close(); } } @override Future writeBytes(String path, Uint8List bytes) async { await File(path).parent.create(recursive: true); await File(path).writeAsBytes(bytes, flush: true); } @override Future delete(String path) async { final f = File(path); if (await f.exists()) await f.delete(); } @override Future replaceFile(String from, String to) async { final old = File(to); if (await old.exists()) await old.delete(); await File(from).rename(to); } @override Future tempDirectory() async { final dir = Directory(p.join(tempRoot ?? Directory.systemTemp.path, 'jj_mkvmaker')); await dir.create(recursive: true); return dir.path; } @override Future saveAs({ required String fileName, required Uint8List bytes, String? initialDirectory, }) async { final uri = await FilePicker.saveFile( dialogTitle: tr('다른 이름으로 저장'), fileName: fileName, bytes: bytes, initialDirectory: initialDirectory, type: FileType.custom, allowedExtensions: const ['srt'], ); if (uri == null) return null; final path = uri.scheme == 'file' ? uri.toFilePath() : uri.toString(); // 데스크톱 구현이 내용을 쓰지 않는 경우를 대비해 한 번 더 기록 if (uri.scheme == 'file') await writeBytes(path, bytes); return path; } }