feat: show download progress in file preview modal (#1011)
This commit is contained in:
@@ -2,7 +2,7 @@ import { WebApplication } from '@/UIModels/Application'
|
|||||||
import { concatenateUint8Arrays } from '@/Utils/ConcatenateUint8Arrays'
|
import { concatenateUint8Arrays } from '@/Utils/ConcatenateUint8Arrays'
|
||||||
import { DialogContent, DialogOverlay } from '@reach/dialog'
|
import { DialogContent, DialogOverlay } from '@reach/dialog'
|
||||||
import { SNFile } from '@standardnotes/snjs'
|
import { SNFile } from '@standardnotes/snjs'
|
||||||
import { NoPreviewIllustration } from '@standardnotes/stylekit'
|
import { addToast, NoPreviewIllustration, ToastType } from '@standardnotes/stylekit'
|
||||||
import { FunctionComponent } from 'preact'
|
import { FunctionComponent } from 'preact'
|
||||||
import { useCallback, useEffect, useRef, useState } from 'preact/hooks'
|
import { useCallback, useEffect, useRef, useState } from 'preact/hooks'
|
||||||
import { getFileIconComponent } from '@/Components/AttachedFilesPopover/PopoverFileItem'
|
import { getFileIconComponent } from '@/Components/AttachedFilesPopover/PopoverFileItem'
|
||||||
@@ -28,6 +28,7 @@ export const FilePreviewModal: FunctionComponent<Props> = ({ application, files,
|
|||||||
const [objectUrl, setObjectUrl] = useState<string>()
|
const [objectUrl, setObjectUrl] = useState<string>()
|
||||||
const [isFilePreviewable, setIsFilePreviewable] = useState(false)
|
const [isFilePreviewable, setIsFilePreviewable] = useState(false)
|
||||||
const [isLoadingFile, setIsLoadingFile] = useState(true)
|
const [isLoadingFile, setIsLoadingFile] = useState(true)
|
||||||
|
const [fileDownloadProgress, setFileDownloadProgress] = useState(0)
|
||||||
const [showFileInfoPanel, setShowFileInfoPanel] = useState(false)
|
const [showFileInfoPanel, setShowFileInfoPanel] = useState(false)
|
||||||
const currentFileIdRef = useRef<string>()
|
const currentFileIdRef = useRef<string>()
|
||||||
const closeButtonRef = useRef<HTMLButtonElement>(null)
|
const closeButtonRef = useRef<HTMLButtonElement>(null)
|
||||||
@@ -35,8 +36,12 @@ export const FilePreviewModal: FunctionComponent<Props> = ({ application, files,
|
|||||||
const getObjectUrl = useCallback(async () => {
|
const getObjectUrl = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const chunks: Uint8Array[] = []
|
const chunks: Uint8Array[] = []
|
||||||
await application.files.downloadFile(file, async (decryptedChunk: Uint8Array) => {
|
setFileDownloadProgress(0)
|
||||||
|
await application.files.downloadFile(file, async (decryptedChunk, progress) => {
|
||||||
chunks.push(decryptedChunk)
|
chunks.push(decryptedChunk)
|
||||||
|
if (progress) {
|
||||||
|
setFileDownloadProgress(Math.round(progress.percentComplete))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
const finalDecryptedBytes = concatenateUint8Arrays(chunks)
|
const finalDecryptedBytes = concatenateUint8Arrays(chunks)
|
||||||
setObjectUrl(
|
setObjectUrl(
|
||||||
@@ -150,6 +155,10 @@ export const FilePreviewModal: FunctionComponent<Props> = ({ application, files,
|
|||||||
className="mr-4"
|
className="mr-4"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
application.getArchiveService().downloadData(objectUrl, file.name)
|
application.getArchiveService().downloadData(objectUrl, file.name)
|
||||||
|
addToast({
|
||||||
|
type: ToastType.Success,
|
||||||
|
message: 'Successfully downloaded file',
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Download
|
Download
|
||||||
@@ -168,7 +177,13 @@ export const FilePreviewModal: FunctionComponent<Props> = ({ application, files,
|
|||||||
<div className="flex flex-grow min-h-0">
|
<div className="flex flex-grow min-h-0">
|
||||||
<div className="flex flex-grow items-center justify-center relative max-w-full">
|
<div className="flex flex-grow items-center justify-center relative max-w-full">
|
||||||
{isLoadingFile ? (
|
{isLoadingFile ? (
|
||||||
<div className="sk-spinner w-5 h-5 spinner-info"></div>
|
<div className="flex flex-col items-center">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<div className="sk-spinner w-5 h-5 spinner-info mr-3"></div>
|
||||||
|
<div className="text-base font-semibold">{fileDownloadProgress}%</div>
|
||||||
|
</div>
|
||||||
|
<span className="mt-3">Loading file...</span>
|
||||||
|
</div>
|
||||||
) : objectUrl ? (
|
) : objectUrl ? (
|
||||||
<PreviewComponent file={file} objectUrl={objectUrl} />
|
<PreviewComponent file={file} objectUrl={objectUrl} />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -42,13 +42,11 @@ export class FilesState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (progress) {
|
if (progress) {
|
||||||
const progressPercent = Number.isInteger(progress.percentComplete)
|
const progressPercent = Math.floor(progress.percentComplete)
|
||||||
? progress.percentComplete
|
|
||||||
: progress.percentComplete.toFixed(2)
|
|
||||||
|
|
||||||
updateToast(downloadingToastId, {
|
updateToast(downloadingToastId, {
|
||||||
message: `Downloading file "${file.name}" (${progressPercent}%)`,
|
message: `Downloading file "${file.name}" (${progressPercent}%)`,
|
||||||
progress: progress.percentComplete,
|
progress: progressPercent,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -136,10 +134,9 @@ export class FilesState {
|
|||||||
const onChunk = async (chunk: Uint8Array, index: number, isLast: boolean) => {
|
const onChunk = async (chunk: Uint8Array, index: number, isLast: boolean) => {
|
||||||
await this.application.files.pushBytesForUpload(operation, chunk, index, isLast)
|
await this.application.files.pushBytesForUpload(operation, chunk, index, isLast)
|
||||||
|
|
||||||
const progress = operation.getProgress().percentComplete
|
const progress = Math.round(operation.getProgress().percentComplete)
|
||||||
const formattedProgress = Number.isInteger(progress) ? progress : progress.toFixed(2)
|
|
||||||
updateToast(toastId, {
|
updateToast(toastId, {
|
||||||
message: `Uploading file "${file.name}" (${formattedProgress}%)`,
|
message: `Uploading file "${file.name}" (${progress}%)`,
|
||||||
progress,
|
progress,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ module Web
|
|||||||
img_src: ["'self'", '* data:', 'blob:'],
|
img_src: ["'self'", '* data:', 'blob:'],
|
||||||
manifest_src: %w('self'),
|
manifest_src: %w('self'),
|
||||||
media_src: %w('self' blob: *.standardnotes.com),
|
media_src: %w('self' blob: *.standardnotes.com),
|
||||||
object_src: %w('self'),
|
object_src: %w('self' blob: *.standardnotes.com),
|
||||||
plugin_types: %w(),
|
plugin_types: %w(),
|
||||||
script_src: %w('self' 'unsafe-inline' 'unsafe-eval'),
|
script_src: %w('self' 'unsafe-inline' 'unsafe-eval'),
|
||||||
style_src: %w(* 'unsafe-inline'),
|
style_src: %w(* 'unsafe-inline'),
|
||||||
|
|||||||
Reference in New Issue
Block a user