-

+
);
}
diff --git a/src/pages/FileSharing.jsx b/src/pages/FileSharing.jsx
index 9956b53..dafe48b 100644
--- a/src/pages/FileSharing.jsx
+++ b/src/pages/FileSharing.jsx
@@ -161,6 +161,7 @@ export default function FileSharing() {
const [uploading, setUploading] = useState(false);
const [uploadProgress, setUploadProgress] = useState(null);
const [downloadingSelection, setDownloadingSelection] = useState(false);
+ const [downloadProgress, setDownloadProgress] = useState(null);
const [ctxMenu, setCtxMenu] = useState(null);
const [clipboard, setClipboard] = useState(null);
const [hoveredNavPath, setHoveredNavPath] = useState(null);
@@ -420,18 +421,24 @@ export default function FileSharing() {
localStorage.setItem(pinsStorageKey, JSON.stringify(next));
}
+ function triggerDownload(url, filename) {
+ const link = document.createElement('a');
+ link.href = url;
+ link.download = filename;
+ link.style.display = 'none';
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ URL.revokeObjectURL(url);
+ }
+
async function handleDownload(entry) {
const nextPath = entry.path ?? (path === '/' ? `/${entry.name}` : `${path}/${entry.name}`);
try {
const blob = await (await fbqProxy('download', nextPath)).blob();
- const url = URL.createObjectURL(blob);
- const link = document.createElement('a');
- link.href = url;
- link.download = entry.name;
- link.click();
- URL.revokeObjectURL(url);
- } catch {
- setError('Download failed.');
+ triggerDownload(URL.createObjectURL(blob), entry.name);
+ } catch (err) {
+ setError(err?.message || 'Download failed.');
}
}
@@ -461,6 +468,7 @@ export default function FileSharing() {
async function handleDownloadSelected() {
if (!selected.size) return;
setDownloadingSelection(true);
+ setDownloadProgress(0);
setError('');
try {
const selectedEntries = [...selected]
@@ -475,53 +483,42 @@ export default function FileSharing() {
if (!isDir) {
const blob = await (await fbqProxy('download', targetPath)).blob();
- const url = URL.createObjectURL(blob);
- const link = document.createElement('a');
- link.href = url;
- link.download = name;
- link.click();
- URL.revokeObjectURL(url);
+ setDownloadProgress(100);
+ triggerDownload(URL.createObjectURL(blob), name);
return;
}
const zip = new JSZip();
+ setDownloadProgress(50);
await addPathToZip(zip, targetPath, name);
- const blob = await zip.generateAsync({ type: 'blob' });
- const url = URL.createObjectURL(blob);
- const link = document.createElement('a');
- link.href = url;
- link.download = `${name}.zip`;
- link.click();
- URL.revokeObjectURL(url);
+ setDownloadProgress(100);
+ triggerDownload(URL.createObjectURL(await zip.generateAsync({ type: 'blob' })), `${name}.zip`);
return;
}
const zip = new JSZip();
- for (const entry of selectedEntries) {
+ for (let i = 0; i < selectedEntries.length; i++) {
+ const entry = selectedEntries[i];
const name = entry.name ?? entry.filename ?? '';
const targetPath = entry.path ?? (path === '/' ? `/${name}` : `${path}/${name}`);
const isDir = entry.type === 'directory' || entry.isDir;
if (isDir) {
await addPathToZip(zip, targetPath, name);
- continue;
+ } else {
+ const blob = await (await fbqProxy('download', targetPath)).blob();
+ zip.file(name, blob);
}
- const blob = await (await fbqProxy('download', targetPath)).blob();
- zip.file(name, blob);
+ setDownloadProgress(Math.round(((i + 1) / selectedEntries.length) * 100));
}
- const blob = await zip.generateAsync({ type: 'blob' });
- const url = URL.createObjectURL(blob);
- const link = document.createElement('a');
const folderName = parsePath(path).at(-1) || 'files';
- link.href = url;
- link.download = `${folderName}-selection.zip`;
- link.click();
- URL.revokeObjectURL(url);
- } catch {
- setError('Download failed.');
+ triggerDownload(URL.createObjectURL(await zip.generateAsync({ type: 'blob' })), `${folderName}-selection.zip`);
+ } catch (err) {
+ setError(err?.message || 'Download failed.');
} finally {
setDownloadingSelection(false);
+ setDownloadProgress(null);
}
}
@@ -938,6 +935,56 @@ export default function FileSharing() {