diff --git a/lib/utils/cbz.dart b/lib/utils/cbz.dart index 4458b45..a2458f2 100644 --- a/lib/utils/cbz.dart +++ b/lib/utils/cbz.dart @@ -111,7 +111,7 @@ abstract class CBZ { var src = files[i]; var dst = File( FilePath.join(dest.path, '${i + 1}.${src.path.split('.').last}')); - src.copy(dst.path); + await src.copy(dst.path); } } else { dest.createSync(); @@ -129,7 +129,7 @@ abstract class CBZ { var src = chapter.value[i]; var dst = File(FilePath.join( chapterDir.path, '${i + 1}.${src.path.split('.').last}')); - src.copy(dst.path); + await src.copy(dst.path); } } } diff --git a/lib/utils/import_comic.dart b/lib/utils/import_comic.dart index a5e40b6..87f02ac 100644 --- a/lib/utils/import_comic.dart +++ b/lib/utils/import_comic.dart @@ -18,16 +18,14 @@ class ImportComic { const ImportComic({this.selectedFolder}); Future cbz() async { - var xFile = await selectFile(ext: ['cbz']); - if(xFile == null) { + var file = await selectFile(ext: ['cbz']); + if(file == null) { return false; } var controller = showLoadingDialog(App.rootContext, allowCancel: false); var isSuccessful = false; try { - var cache = FilePath.join(App.cachePath, xFile.name); - await xFile.saveTo(cache); - var comic = await CBZ.import(File(cache)); + var comic = await CBZ.import(File(file.path)); if (selectedFolder != null) { LocalFavoritesManager().addComic( selectedFolder!, @@ -41,7 +39,6 @@ class ImportComic { ), ); } - await File(cache).deleteIgnoreError(); isSuccessful = true; } catch (e, s) { Log.error("Import Comic", e.toString(), s); diff --git a/lib/utils/io.dart b/lib/utils/io.dart index aafeb52..6593f75 100644 --- a/lib/utils/io.dart +++ b/lib/utils/io.dart @@ -24,11 +24,6 @@ class IO { static bool _isSelectingFiles = false; } -/// A finalizer that can be used to dispose resources related to file operations. -final _finalizer = Finalizer((e) { - e(); -}); - class FilePath { const FilePath._(); @@ -162,53 +157,43 @@ String findValidDirectoryName(String path, String directory) { } class DirectoryPicker { - DirectoryPicker() { - _finalizer.attach(this, dispose); - } + /// Pick a directory. + /// + /// The directory may not be usable after the instance is GCed. + DirectoryPicker(); - String? _directory; + static final _finalizer = Finalizer((path) { + if (path.startsWith(App.cachePath)) { + Directory(path).deleteIgnoreError(); + } + if (App.isIOS || App.isMacOS) { + _methodChannel.invokeMethod("stopAccessingSecurityScopedResource"); + } + }); - final _methodChannel = const MethodChannel("venera/method_channel"); + static const _methodChannel = MethodChannel("venera/method_channel"); Future pickDirectory() async { IO._isSelectingFiles = true; try { + String? directory; if (App.isWindows || App.isLinux) { - var d = await file_selector.getDirectoryPath(); - _directory = d; - return d == null ? null : Directory(d); + directory = await file_selector.getDirectoryPath(); } else if (App.isAndroid) { - var d = await _methodChannel.invokeMethod("getDirectoryPath"); - _directory = d; - return d == null ? null : Directory(d); + directory = await _methodChannel.invokeMethod("getDirectoryPath"); } else { // ios, macos - var d = await _methodChannel.invokeMethod("getDirectoryPath"); - _directory = d; - return d == null ? null : Directory(d); + directory = await _methodChannel.invokeMethod("getDirectoryPath"); } + if (directory == null) return null; + _finalizer.attach(this, directory); + return Directory(directory); } finally { Future.delayed(const Duration(milliseconds: 100), () { IO._isSelectingFiles = false; }); } } - - Future dispose() async { - if (_directory == null) { - return; - } - if (App.isAndroid && - _directory != null && - _directory!.startsWith(App.cachePath)) { - await Directory(_directory!).deleteIgnoreError(recursive: true); - _directory = null; - } - if (App.isIOS || App.isMacOS) { - await _methodChannel.invokeMethod("stopAccessingSecurityScopedResource"); - _directory = null; - } - } } class IOSDirectoryPicker { @@ -231,7 +216,7 @@ class IOSDirectoryPicker { } } -Future selectFile({required List ext}) async { +Future selectFile({required List ext}) async { IO._isSelectingFiles = true; try { var extensions = App.isMacOS || App.isIOS ? null : ext; @@ -239,13 +224,13 @@ Future selectFile({required List ext}) async { label: 'files', extensions: extensions, ); - file_selector.XFile? file; + FileSelectResult? file; if (App.isAndroid) { const selectFileChannel = MethodChannel("venera/select_file"); String mimeType = "*/*"; - if(ext.length == 1) { + if (ext.length == 1) { mimeType = FileType.fromExtension(ext[0]).mime; - if(mimeType == "application/octet-stream") { + if (mimeType == "application/octet-stream") { mimeType = "*/*"; } } @@ -254,12 +239,13 @@ Future selectFile({required List ext}) async { mimeType, ); if (filePath == null) return null; - file = _AndroidFileSelectResult(filePath); + file = FileSelectResult(filePath); } else { - file = await file_selector.openFile( + var xFile = await file_selector.openFile( acceptedTypeGroups: [typeGroup], ); - if (file == null) return null; + if (xFile == null) return null; + file = FileSelectResult(xFile.path); } if (!ext.contains(file.path.split(".").last)) { App.rootContext.showMessage(message: "Invalid file type"); @@ -360,15 +346,26 @@ String bytesToReadableString(int bytes) { } } -class _AndroidFileSelectResult extends s.XFile { - _AndroidFileSelectResult(super.path) { - _finalizer.attach(this, dispose); - } +class FileSelectResult { + final String path; - void dispose() { - print("dispose $path"); + static final _finalizer = Finalizer((path) { if (path.startsWith(App.cachePath)) { File(path).deleteIgnoreError(); } + }); + + FileSelectResult(this.path) { + _finalizer.attach(this, path); } -} + + Future saveTo(String path) async { + await File(this.path).copy(path); + } + + Future readAsBytes() { + return File(path).readAsBytes(); + } + + String get name => File(path).name; +} \ No newline at end of file