From cbcea137c4f8209e2d229335278d06e16390f974 Mon Sep 17 00:00:00 2001 From: The one with the braid Date: Sat, 26 Aug 2023 07:25:06 +0200 Subject: [PATCH] feat: implement handler for unsupported URI scheme - add high-level callback for unsupported URI schemes - add HTTP and HTTPS file drop handler to example Signed-off-by: The one with the braid --- packages/desktop_drop/example/lib/main.dart | 25 ++++ .../Flutter/GeneratedPluginRegistrant.swift | 2 + packages/desktop_drop/example/pubspec.lock | 114 +++++++++++++++++- packages/desktop_drop/example/pubspec.yaml | 2 + packages/desktop_drop/lib/desktop_drop.dart | 1 + packages/desktop_drop/lib/src/channel.dart | 15 ++- .../lib/src/desktop_drop_public.dart | 14 +++ 7 files changed, 169 insertions(+), 4 deletions(-) create mode 100644 packages/desktop_drop/lib/src/desktop_drop_public.dart diff --git a/packages/desktop_drop/example/lib/main.dart b/packages/desktop_drop/example/lib/main.dart index 0a65ec37..6bb04102 100644 --- a/packages/desktop_drop/example/lib/main.dart +++ b/packages/desktop_drop/example/lib/main.dart @@ -1,8 +1,14 @@ +import 'dart:io'; + import 'package:desktop_drop/desktop_drop.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:cross_file/cross_file.dart'; +import 'package:http/http.dart'; +import 'package:path_provider/path_provider.dart'; void main() { + DesktopDropPlugin.onUnsupportedUriHandler = customHttpsHandler; runApp(const MyApp()); } @@ -105,3 +111,22 @@ class _ExampleDragTargetState extends State { ); } } + +Future customHttpsHandler(String url) async { + if (kIsWeb) return null; + final uri = Uri.tryParse(url); + if (uri == null) return null; + + if (!['http', 'https'].contains(uri.scheme)) return null; + + final response = await get(uri); + + final tmp = + (await getDownloadsDirectory() ?? await getApplicationCacheDirectory()); + await tmp.create(recursive: true); + final file = + File(tmp.path + '/desktop_drop_example/' + uri.path.split('/').last); + await file.create(recursive: true); + await file.writeAsBytes(response.bodyBytes); + return file.path; +} diff --git a/packages/desktop_drop/example/macos/Flutter/GeneratedPluginRegistrant.swift b/packages/desktop_drop/example/macos/Flutter/GeneratedPluginRegistrant.swift index 9c49a5a0..11f05b81 100644 --- a/packages/desktop_drop/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/packages/desktop_drop/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,7 +6,9 @@ import FlutterMacOS import Foundation import desktop_drop +import path_provider_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DesktopDropPlugin.register(with: registry.registrar(forPlugin: "DesktopDropPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) } diff --git a/packages/desktop_drop/example/pubspec.lock b/packages/desktop_drop/example/pubspec.lock index b91344d1..14bfed72 100644 --- a/packages/desktop_drop/example/pubspec.lock +++ b/packages/desktop_drop/example/pubspec.lock @@ -72,6 +72,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + url: "https://pub.dev" + source: hosted + version: "2.1.0" flutter: dependency: "direct main" description: flutter @@ -95,6 +103,22 @@ packages: description: flutter source: sdk version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" js: dependency: transitive description: @@ -143,6 +167,70 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.3" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "909b84830485dbcd0308edf6f7368bc8fd76afa26a270420f34cabea2a6467a0" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "5d44fc3314d969b84816b569070d7ace0f1dea04bd94a83f74c4829615d22ad8" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "1b744d3d774e5a879bb76d6cd1ecee2ba2c6960c03b1020cd35212f6aa267ac5" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: ba2b77f0c52a33db09fc8caf85b12df691bf28d983e84cf87ff6d693cfa007b3 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: bced5679c7df11190e1ddc35f3222c858f328fff85c3942e46e7f5589bf9eb84 + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: ee0e0d164516b90ae1f970bdf29f726f1aa730d7cfc449ecc74c495378b705da + url: "https://pub.dev" + source: hosted + version: "2.2.0" + platform: + dependency: transitive + description: + name: platform + sha256: "57c07bf82207aee366dfaa3867b3164e4f03a238a461a11b0e8a3a510d51203d" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" sky_engine: dependency: transitive description: flutter @@ -196,6 +284,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.0" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" vector_math: dependency: transitive description: @@ -212,6 +308,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.4-beta" + win32: + dependency: transitive + description: + name: win32 + sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa" + url: "https://pub.dev" + source: hosted + version: "5.0.7" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: f0c26453a2d47aa4c2570c6a033246a3fc62da2fe23c7ffdd0a7495086dc0247 + url: "https://pub.dev" + source: hosted + version: "1.0.2" sdks: dart: ">=3.1.0-185.0.dev <4.0.0" - flutter: ">=1.20.0" + flutter: ">=3.3.0" diff --git a/packages/desktop_drop/example/pubspec.yaml b/packages/desktop_drop/example/pubspec.yaml index 4b56f0b2..49e390cc 100644 --- a/packages/desktop_drop/example/pubspec.yaml +++ b/packages/desktop_drop/example/pubspec.yaml @@ -14,6 +14,8 @@ dependencies: path: ../ cross_file: ^0.3.2 cupertino_icons: ^1.0.2 + http: ^1.1.0 + path_provider: ^2.1.0 dev_dependencies: flutter_test: diff --git a/packages/desktop_drop/lib/desktop_drop.dart b/packages/desktop_drop/lib/desktop_drop.dart index 0ad85c88..f17d528f 100644 --- a/packages/desktop_drop/lib/desktop_drop.dart +++ b/packages/desktop_drop/lib/desktop_drop.dart @@ -1 +1,2 @@ export 'src/drop_target.dart'; +export 'src/desktop_drop_public.dart'; diff --git a/packages/desktop_drop/lib/src/channel.dart b/packages/desktop_drop/lib/src/channel.dart index 492a9319..c21b8422 100644 --- a/packages/desktop_drop/lib/src/channel.dart +++ b/packages/desktop_drop/lib/src/channel.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:cross_file/cross_file.dart'; +import 'package:desktop_drop/src/desktop_drop_public.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; @@ -72,15 +73,23 @@ class DesktopDrop { case "performOperation_linux": // gtk notify 'exit' before 'performOperation'. final text = (call.arguments as List)[0] as String; - final offset = ((call.arguments as List)[1] as List).cast(); - final paths = const LineSplitter().convert(text).map((e) { + final offset = ((call.arguments as List)[1] as List) + .cast(); + final paths = (await Future.wait( + const LineSplitter().convert(text).map(((e) async { try { return Uri.tryParse(e)?.toFilePath() ?? ''; + } on UnsupportedError { + final handled = + await DesktopDropPlugin.onUnsupportedUriHandler?.call(e); + if (handled == null || handled.isEmpty) rethrow; + return handled; } catch (error, stacktrace) { debugPrint('failed to parse linux path: $error $stacktrace'); } return ''; - }).where((e) => e.isNotEmpty); + })))) + .where((e) => e.isNotEmpty); _notifyEvent(DropDoneEvent( location: Offset(offset[0], offset[1]), files: paths.map((e) => XFile(e)).toList(), diff --git a/packages/desktop_drop/lib/src/desktop_drop_public.dart b/packages/desktop_drop/lib/src/desktop_drop_public.dart new file mode 100644 index 00000000..a6282a9a --- /dev/null +++ b/packages/desktop_drop/lib/src/desktop_drop_public.dart @@ -0,0 +1,14 @@ +typedef DesktopDropUnsupportedUriCallback = Future Function( + String uri, +); + +abstract class DesktopDropPlugin { + DesktopDropPlugin._(); + + /// set the [onUnsupportedUriHandler] in order to handle custom URI schemes + /// that are not `file:`, e.g. useful for handling `http:`, `https:` or any + /// other custom URI scheme. + /// + /// This callback is only relevant on io platforms. + static DesktopDropUnsupportedUriCallback? onUnsupportedUriHandler; +}