From 1bccf31d875f871c0d1b924676fba19af1d1a773 Mon Sep 17 00:00:00 2001 From: Bo Lopker Date: Sun, 3 Nov 2024 21:33:55 +0700 Subject: [PATCH] Fix trash bug and allow dock file drops --- lib/compressor.dart | 4 ++-- lib/dockdrop.dart | 17 +++++++++++++++++ lib/dropper.dart | 27 ++------------------------- lib/filesystem.dart | 27 +++++++++++++++++++++++++++ lib/main.dart | 6 +++++- lib/settings.dart | 2 +- lib/trash.dart | 4 ++-- macos/Runner/AppDelegate.swift | 21 ++++++++++++++++++--- macos/Runner/Info.plist | 26 ++++++++++++++++++++++++++ 9 files changed, 100 insertions(+), 34 deletions(-) create mode 100644 lib/dockdrop.dart create mode 100644 lib/filesystem.dart diff --git a/lib/compressor.dart b/lib/compressor.dart index c184094..47d2b9d 100644 --- a/lib/compressor.dart +++ b/lib/compressor.dart @@ -52,7 +52,7 @@ void compressor(ImageFile imageFile, void Function(ImageFile) callback) { if (sizeAfterOptimization.toDouble() / imageFile.size > compressionThreshold) { // delete the file if it's not smaller - trash(outFile); + await trash(outFile); callback(imageFile.copyWith( status: ImageFileStatus.unoptimized, )); @@ -61,7 +61,7 @@ void compressor(ImageFile imageFile, void Function(ImageFile) callback) { // Success! if (!config.enablePostfix) { // If postfix is disabled, replace the original file with the optimized one - trash(File(imageFile.path)); + await trash(File(imageFile.path)); outFile.rename(replaceLast(outFile.path, config.postfix, '')); } callback(imageFile.copyWith( diff --git a/lib/dockdrop.dart b/lib/dockdrop.dart new file mode 100644 index 0000000..5926c6f --- /dev/null +++ b/lib/dockdrop.dart @@ -0,0 +1,17 @@ +import 'dart:io'; + +import 'package:alic/filesystem.dart'; +import 'package:alic/log.dart'; +import 'package:flutter/services.dart'; + +registerDockDropHandler(Function(List) onDrop) async { + const platform = MethodChannel('io.kbl.alic'); + platform.setMethodCallHandler((call) async { + log.d(call); + if (call.method == 'openImage') { + var path = call.arguments as String; + var paths = await resolvePaths([path]); + onDrop(paths); + } + }); +} diff --git a/lib/dropper.dart b/lib/dropper.dart index 7c6ac70..3f795fa 100644 --- a/lib/dropper.dart +++ b/lib/dropper.dart @@ -1,8 +1,8 @@ import 'dart:async'; import 'dart:io'; +import 'package:alic/filesystem.dart'; import 'package:alic/log.dart'; -import 'package:alic/imagefiles.dart'; import 'package:flutter/material.dart'; import 'package:super_clipboard/super_clipboard.dart'; import 'package:super_drag_and_drop/super_drag_and_drop.dart'; @@ -97,7 +97,7 @@ class _ImageDropRegionState extends State { } } } - final paths = await _resolvePaths(mixedPaths); + final paths = await resolvePaths(mixedPaths); widget.onDrop(paths); }, child: Stack(children: [ @@ -140,26 +140,3 @@ Future _getValueFromItem(DropItem item) async { }); return completer.future; } - -Future> _resolvePaths(List paths) async { - List resolvedPaths = []; - for (var path in paths) { - if (path.endsWith('/')) { - resolvedPaths.addAll(await _getImagesFromDirectory(Directory(path))); - } else { - resolvedPaths.add(File(path)); - } - } - return resolvedPaths; -} - -// Return a list of images from a directory, recursively -Future> _getImagesFromDirectory(Directory dir) async { - List imageFiles = []; - await for (var entity in dir.list(recursive: true, followLinks: false)) { - if (entity is File && ImageFormats.isImage(entity.path)) { - imageFiles.add(entity); - } - } - return imageFiles; -} diff --git a/lib/filesystem.dart b/lib/filesystem.dart new file mode 100644 index 0000000..38d5926 --- /dev/null +++ b/lib/filesystem.dart @@ -0,0 +1,27 @@ +import 'dart:io'; + +import 'package:alic/imagefiles.dart'; + +Future> resolvePaths(List paths) async { + List resolvedPaths = []; + for (var path in paths) { + final dir = Directory(path); + final file = File(path); + if (await dir.exists()) { + resolvedPaths.addAll(await getImagesFromDirectory(dir)); + } else if (await file.exists()) { + resolvedPaths.add(file); + } + } + return resolvedPaths; +} + +// Return a list of images from a directory, recursively +Future> getImagesFromDirectory(Directory dir) async { + return await dir + .list(recursive: true, followLinks: false) + .where((entity) => entity is File) + .map((entity) => entity as File) + .where((file) => ImageFormats.isImage(file.path)) + .toList(); +} diff --git a/lib/main.dart b/lib/main.dart index c940a58..7fc78d6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:alic/dockdrop.dart'; import 'package:alic/dropper.dart'; import 'package:alic/imagefiles.dart'; import 'package:alic/settings.dart'; @@ -21,7 +22,6 @@ void main() async { await RustLib.init(); await windowManager.ensureInitialized(); Config.init(); - WindowOptions windowOptions = const WindowOptions( minimumSize: Size(600, 400), skipTaskbar: false, @@ -30,6 +30,10 @@ void main() async { await windowManager.show(); await windowManager.focus(); }); + registerDockDropHandler((files) { + log.d('Dropped: $files'); + ImageFiles.add(files); + }); runApp(const Alic()); } diff --git a/lib/settings.dart b/lib/settings.dart index 5b34490..e117b92 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -87,7 +87,7 @@ class _SettingsWidgetState extends State { return AlertDialog( title: const Text('Reset Settings'), content: const Text( - 'Are you sure you want to reset all settings to default?'), + 'Are you sure you want to reset all settings to the defaults?'), actions: [ TextButton( child: const Text('Cancel'), diff --git a/lib/trash.dart b/lib/trash.dart index c4a7178..1a28695 100644 --- a/lib/trash.dart +++ b/lib/trash.dart @@ -16,6 +16,6 @@ class NativeFileManager { } } -trash(File file) { - NativeFileManager.trashItem(file.path); +trash(File file) async { + await NativeFileManager.trashItem(file.path); } diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index 8e02df2..67cc6a8 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -3,7 +3,22 @@ import FlutterMacOS @main class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + override func application(_ application: NSApplication, open urls: [URL]) { + guard + let flutterViewController = mainFlutterWindow?.contentViewController + as? FlutterViewController + else { + return + } + + let channel = FlutterMethodChannel( + name: "io.kbl.alic", binaryMessenger: flutterViewController.engine.binaryMessenger) + + for url in urls { + channel.invokeMethod("openImage", arguments: url.path) + } + } } diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist index 4789daa..e75e2c3 100644 --- a/macos/Runner/Info.plist +++ b/macos/Runner/Info.plist @@ -28,5 +28,31 @@ MainMenu NSPrincipalClass NSApplication + + CFBundleDocumentTypes + + + CFBundleTypeName + My File Type + CFBundleTypeRole + Editor + LSHandlerRank + Owner + LSItemContentTypes + + public.image + public.folder + + CFBundleTypeExtensions + + jpg + jpeg + png + gif + webp + tiff + + +