improve importing comic

This commit is contained in:
2024-11-19 20:52:13 +08:00
parent 6aeaeadb10
commit ce175a2135
3 changed files with 51 additions and 57 deletions

View File

@@ -111,7 +111,7 @@ abstract class CBZ {
var src = files[i]; var src = files[i];
var dst = File( var dst = File(
FilePath.join(dest.path, '${i + 1}.${src.path.split('.').last}')); FilePath.join(dest.path, '${i + 1}.${src.path.split('.').last}'));
src.copy(dst.path); await src.copy(dst.path);
} }
} else { } else {
dest.createSync(); dest.createSync();
@@ -129,7 +129,7 @@ abstract class CBZ {
var src = chapter.value[i]; var src = chapter.value[i];
var dst = File(FilePath.join( var dst = File(FilePath.join(
chapterDir.path, '${i + 1}.${src.path.split('.').last}')); chapterDir.path, '${i + 1}.${src.path.split('.').last}'));
src.copy(dst.path); await src.copy(dst.path);
} }
} }
} }

View File

@@ -18,16 +18,14 @@ class ImportComic {
const ImportComic({this.selectedFolder}); const ImportComic({this.selectedFolder});
Future<bool> cbz() async { Future<bool> cbz() async {
var xFile = await selectFile(ext: ['cbz']); var file = await selectFile(ext: ['cbz']);
if(xFile == null) { if(file == null) {
return false; return false;
} }
var controller = showLoadingDialog(App.rootContext, allowCancel: false); var controller = showLoadingDialog(App.rootContext, allowCancel: false);
var isSuccessful = false; var isSuccessful = false;
try { try {
var cache = FilePath.join(App.cachePath, xFile.name); var comic = await CBZ.import(File(file.path));
await xFile.saveTo(cache);
var comic = await CBZ.import(File(cache));
if (selectedFolder != null) { if (selectedFolder != null) {
LocalFavoritesManager().addComic( LocalFavoritesManager().addComic(
selectedFolder!, selectedFolder!,
@@ -41,7 +39,6 @@ class ImportComic {
), ),
); );
} }
await File(cache).deleteIgnoreError();
isSuccessful = true; isSuccessful = true;
} catch (e, s) { } catch (e, s) {
Log.error("Import Comic", e.toString(), s); Log.error("Import Comic", e.toString(), s);

View File

@@ -24,11 +24,6 @@ class IO {
static bool _isSelectingFiles = false; static bool _isSelectingFiles = false;
} }
/// A finalizer that can be used to dispose resources related to file operations.
final _finalizer = Finalizer<Function>((e) {
e();
});
class FilePath { class FilePath {
const FilePath._(); const FilePath._();
@@ -162,53 +157,43 @@ String findValidDirectoryName(String path, String directory) {
} }
class DirectoryPicker { class DirectoryPicker {
DirectoryPicker() { /// Pick a directory.
_finalizer.attach(this, dispose); ///
} /// The directory may not be usable after the instance is GCed.
DirectoryPicker();
String? _directory; static final _finalizer = Finalizer<String>((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<Directory?> pickDirectory() async { Future<Directory?> pickDirectory() async {
IO._isSelectingFiles = true; IO._isSelectingFiles = true;
try { try {
String? directory;
if (App.isWindows || App.isLinux) { if (App.isWindows || App.isLinux) {
var d = await file_selector.getDirectoryPath(); directory = await file_selector.getDirectoryPath();
_directory = d;
return d == null ? null : Directory(d);
} else if (App.isAndroid) { } else if (App.isAndroid) {
var d = await _methodChannel.invokeMethod<String?>("getDirectoryPath"); directory = await _methodChannel.invokeMethod<String?>("getDirectoryPath");
_directory = d;
return d == null ? null : Directory(d);
} else { } else {
// ios, macos // ios, macos
var d = await _methodChannel.invokeMethod<String?>("getDirectoryPath"); directory = await _methodChannel.invokeMethod<String?>("getDirectoryPath");
_directory = d;
return d == null ? null : Directory(d);
} }
if (directory == null) return null;
_finalizer.attach(this, directory);
return Directory(directory);
} finally { } finally {
Future.delayed(const Duration(milliseconds: 100), () { Future.delayed(const Duration(milliseconds: 100), () {
IO._isSelectingFiles = false; IO._isSelectingFiles = false;
}); });
} }
} }
Future<void> 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 { class IOSDirectoryPicker {
@@ -231,7 +216,7 @@ class IOSDirectoryPicker {
} }
} }
Future<file_selector.XFile?> selectFile({required List<String> ext}) async { Future<FileSelectResult?> selectFile({required List<String> ext}) async {
IO._isSelectingFiles = true; IO._isSelectingFiles = true;
try { try {
var extensions = App.isMacOS || App.isIOS ? null : ext; var extensions = App.isMacOS || App.isIOS ? null : ext;
@@ -239,13 +224,13 @@ Future<file_selector.XFile?> selectFile({required List<String> ext}) async {
label: 'files', label: 'files',
extensions: extensions, extensions: extensions,
); );
file_selector.XFile? file; FileSelectResult? file;
if (App.isAndroid) { if (App.isAndroid) {
const selectFileChannel = MethodChannel("venera/select_file"); const selectFileChannel = MethodChannel("venera/select_file");
String mimeType = "*/*"; String mimeType = "*/*";
if(ext.length == 1) { if (ext.length == 1) {
mimeType = FileType.fromExtension(ext[0]).mime; mimeType = FileType.fromExtension(ext[0]).mime;
if(mimeType == "application/octet-stream") { if (mimeType == "application/octet-stream") {
mimeType = "*/*"; mimeType = "*/*";
} }
} }
@@ -254,12 +239,13 @@ Future<file_selector.XFile?> selectFile({required List<String> ext}) async {
mimeType, mimeType,
); );
if (filePath == null) return null; if (filePath == null) return null;
file = _AndroidFileSelectResult(filePath); file = FileSelectResult(filePath);
} else { } else {
file = await file_selector.openFile( var xFile = await file_selector.openFile(
acceptedTypeGroups: <file_selector.XTypeGroup>[typeGroup], acceptedTypeGroups: <file_selector.XTypeGroup>[typeGroup],
); );
if (file == null) return null; if (xFile == null) return null;
file = FileSelectResult(xFile.path);
} }
if (!ext.contains(file.path.split(".").last)) { if (!ext.contains(file.path.split(".").last)) {
App.rootContext.showMessage(message: "Invalid file type"); App.rootContext.showMessage(message: "Invalid file type");
@@ -360,15 +346,26 @@ String bytesToReadableString(int bytes) {
} }
} }
class _AndroidFileSelectResult extends s.XFile { class FileSelectResult {
_AndroidFileSelectResult(super.path) { final String path;
_finalizer.attach(this, dispose);
}
void dispose() { static final _finalizer = Finalizer<String>((path) {
print("dispose $path");
if (path.startsWith(App.cachePath)) { if (path.startsWith(App.cachePath)) {
File(path).deleteIgnoreError(); File(path).deleteIgnoreError();
} }
});
FileSelectResult(this.path) {
_finalizer.attach(this, path);
} }
}
Future<void> saveTo(String path) async {
await File(this.path).copy(path);
}
Future<Uint8List> readAsBytes() {
return File(path).readAsBytes();
}
String get name => File(path).name;
}