mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-02-14 23:48:30 -06:00
[client][web] Upload folders (where supported)
This commit is contained in:
@@ -1,38 +1,76 @@
|
||||
import 'dart:async';
|
||||
import 'dart:js_interop';
|
||||
import 'dart:js_interop_unsafe';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:phylum/libphylum/repositories/resource_repository.dart';
|
||||
import 'package:phylum/util/upload_utils.dart';
|
||||
import 'package:web/web.dart' as web;
|
||||
|
||||
bool get folderUploadSupported => true;
|
||||
bool _folderUploadSupported = web.window.has('showDirectoryPicker');
|
||||
bool get folderUploadSupported => _folderUploadSupported;
|
||||
|
||||
@JS()
|
||||
external JSPromise<web.FileSystemDirectoryHandle> showDirectoryPicker();
|
||||
|
||||
Future<void> pickAndUploadDirectory(BuildContext context, String parent) async {
|
||||
final dir = await showDirectoryPicker().toDart;
|
||||
processDirs(dir);
|
||||
Future<void> pickAndUploadDirectory(BuildContext context, String folderId) async {
|
||||
final dir =
|
||||
await (web.window.callMethod('showDirectoryPicker'.toJS) as JSPromise<web.FileSystemDirectoryHandle>).toDart;
|
||||
final tree = await enumerateDir(dir, '');
|
||||
uploadDirTree(context, folderId, tree);
|
||||
}
|
||||
|
||||
Future<void> processDirs(web.FileSystemDirectoryHandle dir) async {
|
||||
print('Processing ${dir.name}');
|
||||
final it = dir.entries().asStream();
|
||||
it.forEach((e) async {
|
||||
final l = e.toDart;
|
||||
Future<DirTree> enumerateDir(web.FileSystemDirectoryHandle dir, String prefix) async {
|
||||
if (prefix.isNotEmpty) prefix += '/';
|
||||
final files = <UploadFile>[];
|
||||
final dirs = <String>['$prefix${dir.name}'];
|
||||
int totalSize = 0;
|
||||
|
||||
if (l[1].isA<web.FileSystemDirectoryHandle>()) {
|
||||
await processDirs(l[1] as web.FileSystemDirectoryHandle);
|
||||
} else if (l[1].isA<web.FileSystemFileHandle>()) {
|
||||
final file = await (l[1] as web.FileSystemFileHandle).getFile().toDart;
|
||||
final reader = web.FileReader();
|
||||
reader.onload = () {
|
||||
// final bytes = (reader.result as JSArrayBuffer).toDart;
|
||||
print('contents of ${file.name}: ${reader.result}');
|
||||
}.toJS;
|
||||
final entries = dir.entries();
|
||||
while (true) {
|
||||
final result = await entries.next().toDart;
|
||||
if (result.done) break;
|
||||
final handle = result.value.toDart;
|
||||
|
||||
reader.readAsText(file);
|
||||
// reader.readAsArrayBuffer(file);
|
||||
if (handle[1].isA<web.FileSystemDirectoryHandle>()) {
|
||||
final subtree = await enumerateDir(handle[1] as web.FileSystemDirectoryHandle, '$prefix${dir.name}');
|
||||
dirs.addAll(subtree.dirs);
|
||||
files.addAll(subtree.files);
|
||||
totalSize += subtree.totalSize;
|
||||
} else if (handle[1].isA<web.FileSystemFileHandle>()) {
|
||||
final f = handle[1] as web.FileSystemFileHandle;
|
||||
final file = await f.getFile().toDart;
|
||||
totalSize += file.size;
|
||||
files.add(UploadFile(
|
||||
size: file.size,
|
||||
contentType: getMimeType(file.name),
|
||||
byteStream: ByteStream(byteStream(file)),
|
||||
path: '$prefix${dir.name}/${file.name}'));
|
||||
}
|
||||
});
|
||||
}
|
||||
;
|
||||
return DirTree(
|
||||
totalSize: totalSize,
|
||||
files: files,
|
||||
dirs: dirs,
|
||||
);
|
||||
}
|
||||
|
||||
Stream<Uint8List> byteStream(web.File file) async* {
|
||||
// Hack: wait to allocate the array buffer until after the first yield
|
||||
yield Uint8List(0);
|
||||
|
||||
const int size = 64 * 1024;
|
||||
final stream = file.stream();
|
||||
final reader = stream.getReader(web.ReadableStreamGetReaderOptions(mode: "byob")) as web.ReadableStreamBYOBReader;
|
||||
final buffer = JSArrayBuffer(size);
|
||||
final view = JSUint8Array(buffer, 0, size);
|
||||
|
||||
var result = await reader.read(view).toDart;
|
||||
while (!result.done) {
|
||||
final buf = result.value.dartify() as Uint8List;
|
||||
yield buf;
|
||||
result = await reader.read(buf.toJS).toDart;
|
||||
}
|
||||
}
|
||||
|
||||
extension on web.FileSystemDirectoryHandle {
|
||||
@@ -41,14 +79,6 @@ extension on web.FileSystemDirectoryHandle {
|
||||
|
||||
extension type JsAsyncIterator<T extends JSAny>._(JSObject _) implements JSObject {
|
||||
external JSPromise<JsAsyncIteratorState<T>> next();
|
||||
|
||||
Stream<T> asStream() async* {
|
||||
while (true) {
|
||||
final result = await next().toDart;
|
||||
if (result.done) break;
|
||||
yield result.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension type JsAsyncIteratorState<T extends JSAny>._(JSObject _) implements JSObject {
|
||||
|
||||
@@ -109,7 +109,6 @@ Future<void> uploadFiles(BuildContext context, String folderId, Iterable<UploadF
|
||||
}
|
||||
|
||||
Future<void> uploadPath(BuildContext context, String folderId, Iterable<String> paths) async {
|
||||
final account = context.read<PhylumAccount>();
|
||||
showProgressDialog(context, message: 'Counting Files');
|
||||
DirTree? tree;
|
||||
for (final path in paths) {
|
||||
@@ -121,6 +120,11 @@ Future<void> uploadPath(BuildContext context, String folderId, Iterable<String>
|
||||
Navigator.of(context).pop();
|
||||
|
||||
if (tree == null) return;
|
||||
return uploadDirTree(context, folderId, tree);
|
||||
}
|
||||
|
||||
Future<void> uploadDirTree(BuildContext context, String folderId, DirTree tree) async {
|
||||
final account = context.read<PhylumAccount>();
|
||||
final confirm = await showAlertDialog(
|
||||
context,
|
||||
title: 'Upload Files?',
|
||||
|
||||
Reference in New Issue
Block a user