mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-01-01 09:09:34 -06:00
[client] Handle paste file on web
This commit is contained in:
@@ -156,7 +156,7 @@ Map<ShortcutActivator, Intent> get appShortcuts => const {
|
||||
SingleActivator(LogicalKeyboardKey.keyN, control: true): NewFolderIntent(),
|
||||
SingleActivator(LogicalKeyboardKey.keyU, control: true): UploadFilesIntent(),
|
||||
SingleActivator(LogicalKeyboardKey.keyU, control: true, shift: true): UploadFolderIntent(),
|
||||
SingleActivator(LogicalKeyboardKey.keyV, control: true): PasteFromClipboardIntent(),
|
||||
if (!kIsWeb) SingleActivator(LogicalKeyboardKey.keyV, control: true): PasteFromClipboardIntent(),
|
||||
|
||||
// Top-level Navigation
|
||||
SingleActivator(LogicalKeyboardKey.arrowUp, alt: true): NavUpIntent(),
|
||||
|
||||
@@ -9,11 +9,13 @@ import 'package:phylum/ui/destination_picker/destination_picker.dart';
|
||||
import 'package:phylum/ui/explorer/explorer_actions.dart';
|
||||
import 'package:phylum/ui/explorer/explorer_gesture_handler.dart';
|
||||
import 'package:phylum/ui/explorer/path_view.dart';
|
||||
import 'package:phylum/ui/explorer/resource_drop_and_drop.dart';
|
||||
import 'package:phylum/util/dialogs.dart';
|
||||
import 'package:phylum/util/upload_utils.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
||||
import 'package:super_clipboard/super_clipboard.dart';
|
||||
|
||||
import 'explorer_controller.dart';
|
||||
import 'folder_empty_view.dart';
|
||||
@@ -47,14 +49,32 @@ class _ExplorerViewState extends State<ExplorerView> {
|
||||
handleShareIntent(value).then((value) => ReceiveSharingIntent.instance.reset());
|
||||
});
|
||||
}
|
||||
ClipboardEvents.instance?.registerPasteEventListener(_handlePaste);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_intentSub?.cancel();
|
||||
ClipboardEvents.instance?.unregisterPasteEventListener(_handlePaste);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _handlePaste(ClipboardReadEvent event) async {
|
||||
final folderId = context.read<ExplorerState>().folderId;
|
||||
if (folderId == null) {
|
||||
showAlertDialog(context, title: 'Cannot paste here');
|
||||
return;
|
||||
}
|
||||
final reader = await event.getClipboardReader();
|
||||
final items = reader.items;
|
||||
for (final item in items) {
|
||||
if (!mounted) return;
|
||||
final err = await processDataReader(context, folderId, item);
|
||||
if (!mounted || err == null) return;
|
||||
showAlertDialog(context, title: 'Error uploading file', message: err, barrierDismissible: true);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> handleShareIntent(List<SharedMediaFile> files) async {
|
||||
if (files.isEmpty) return;
|
||||
final paths = files.map((f) => f.path).toList(growable: false);
|
||||
|
||||
@@ -15,6 +15,7 @@ import 'package:phylum/util/dialogs.dart';
|
||||
import 'package:phylum/util/logging.dart';
|
||||
import 'package:phylum/util/upload_utils.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:super_clipboard/super_clipboard.dart';
|
||||
import 'package:super_drag_and_drop/super_drag_and_drop.dart';
|
||||
|
||||
@pragma('vm:platform-const')
|
||||
@@ -75,6 +76,56 @@ class _ResourceDragTargetState extends State<ResourceDragTarget> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> processDataReader(BuildContext context, String folderId, DataReader reader) async {
|
||||
final uploadError = Completer<String?>();
|
||||
reader.getFile(null, (file) async {
|
||||
try {
|
||||
final data = await file.readAll();
|
||||
if (context.mounted) {
|
||||
await uploadDirect(context, folderId, [
|
||||
XFile.fromData(
|
||||
data,
|
||||
path: file.fileName,
|
||||
name: file.fileName,
|
||||
length: data.length,
|
||||
)
|
||||
]);
|
||||
}
|
||||
uploadError.complete(null);
|
||||
} catch (e) {
|
||||
logger.d('Error reading file data', error: e);
|
||||
uploadError.complete(e.toString());
|
||||
}
|
||||
}, onError: (err) {
|
||||
logger.e('Error calling getFile', error: err);
|
||||
});
|
||||
final err = await uploadError.future;
|
||||
if (err == null) {
|
||||
return null;
|
||||
}
|
||||
if (kIsWeb) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// Try reading paths from filesystem
|
||||
final c = Completer<String?>();
|
||||
reader.getValue(
|
||||
Formats.fileUri,
|
||||
(value) {
|
||||
final path = value?.toFilePath(windows: Platform.isWindows);
|
||||
if (path == null) {
|
||||
c.complete('Unable to get file path');
|
||||
} else {
|
||||
if (context.mounted) {
|
||||
uploadRecursive(context, folderId, [path]).then((value) => c.complete(null));
|
||||
}
|
||||
}
|
||||
},
|
||||
onError: (value) => c.complete(value.toString()),
|
||||
);
|
||||
return c.future;
|
||||
}
|
||||
|
||||
class ExternalDropRegion extends StatefulWidget {
|
||||
final DropWidgetBuilder buildItem;
|
||||
|
||||
@@ -111,58 +162,14 @@ class _ExternalDropRegionState extends State<ExternalDropRegion> {
|
||||
onPerformDrop: (event) async {
|
||||
final folderId = context.read<ExplorerState>().folderId;
|
||||
if (folderId == null) return;
|
||||
final paths = <String>[];
|
||||
for (final item in event.session.items) {
|
||||
final reader = item.dataReader;
|
||||
if (reader == null) continue;
|
||||
final uploadError = Completer<String?>();
|
||||
reader.getFile(null, (file) async {
|
||||
try {
|
||||
final data = await file.readAll();
|
||||
if (context.mounted) {
|
||||
await uploadDirect(context, folderId, [
|
||||
XFile.fromData(
|
||||
data,
|
||||
path: file.fileName,
|
||||
name: file.fileName,
|
||||
length: data.length,
|
||||
)
|
||||
]);
|
||||
}
|
||||
uploadError.complete(null);
|
||||
// ignore: empty_catches
|
||||
} catch (e) {
|
||||
logger.d('[onPerformDrop] Error reading file data', error: e);
|
||||
uploadError.complete(e.toString());
|
||||
}
|
||||
}, onError: (err) {
|
||||
logger.e('[onPerformDrop] error calling getFile', error: err);
|
||||
});
|
||||
final err = await uploadError.future;
|
||||
if (err == null) {
|
||||
continue;
|
||||
}
|
||||
if (kIsWeb) {
|
||||
if (context.mounted) {
|
||||
showAlertDialog(context, title: 'Error uploading file', message: err, barrierDismissible: true);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try reading paths from filesystem
|
||||
final c = Completer<String?>();
|
||||
reader.getValue(
|
||||
Formats.fileUri,
|
||||
(value) => c.complete(value?.toFilePath(windows: Platform.isWindows)),
|
||||
onError: (value) => c.complete(null),
|
||||
);
|
||||
final path = await c.future;
|
||||
if (path != null) {
|
||||
paths.add(path);
|
||||
}
|
||||
}
|
||||
if (context.mounted) {
|
||||
uploadRecursive(context, folderId, paths);
|
||||
if (!context.mounted) return;
|
||||
final err = await processDataReader(context, folderId, reader);
|
||||
if (!context.mounted) return;
|
||||
showAlertDialog(context, title: 'Error uploading file', message: err, barrierDismissible: true);
|
||||
}
|
||||
setState(() => dropTargetActive = false);
|
||||
},
|
||||
|
||||
@@ -125,7 +125,9 @@ Future<void> uploadRecursive(BuildContext context, String folderId, Iterable<Str
|
||||
);
|
||||
if (id == null) {
|
||||
if (!context.mounted) return;
|
||||
final confirm = await showAlertDialog(context, title: 'Cancel operation?') ?? false;
|
||||
final confirm =
|
||||
await showAlertDialog(context, title: 'Cancel operation?', positiveText: 'No', negativeText: 'Yes') ??
|
||||
false;
|
||||
if (!confirm) return;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user