chore: on android use notification to display file upload progress instead of toast (#2628) [skip e2e]
This commit is contained in:
@@ -22,6 +22,7 @@ import {
|
||||
NoteContent,
|
||||
SNNote,
|
||||
DesktopManagerInterface,
|
||||
FileItem,
|
||||
} from '@standardnotes/snjs'
|
||||
import { action, computed, makeObservable, observable } from 'mobx'
|
||||
import { startAuthentication, startRegistration } from '@simplewebauthn/browser'
|
||||
@@ -76,6 +77,7 @@ import { NoAccountWarningController } from '@/Controllers/NoAccountWarningContro
|
||||
import { SearchOptionsController } from '@/Controllers/SearchOptionsController'
|
||||
import { PersistenceService } from '@/Controllers/Abstract/PersistenceService'
|
||||
import { removeFromArray } from '@standardnotes/utils'
|
||||
import { FileItemActionType } from '@/Components/AttachedFilesPopover/PopoverFileItemAction'
|
||||
|
||||
export type WebEventObserver = (event: WebAppEvent, data?: unknown) => void
|
||||
|
||||
@@ -353,6 +355,21 @@ export class WebApplication extends SNApplication implements WebApplicationInter
|
||||
this.notifyWebEvent(WebAppEvent.MobileKeyboardDidChangeFrame, frame)
|
||||
}
|
||||
|
||||
handleOpenFilePreviewEvent({ id }: { id: string }): void {
|
||||
const file = this.items.findItem<FileItem>(id)
|
||||
if (!file) {
|
||||
return
|
||||
}
|
||||
this.filesController
|
||||
.handleFileAction({
|
||||
type: FileItemActionType.PreviewFile,
|
||||
payload: {
|
||||
file,
|
||||
},
|
||||
})
|
||||
.catch(console.error)
|
||||
}
|
||||
|
||||
handleReceivedFileEvent(file: { name: string; mimeType: string; data: string }): void {
|
||||
const filesController = this.filesController
|
||||
const blob = getBlobFromBase64(file.data, file.mimeType)
|
||||
|
||||
@@ -291,6 +291,11 @@ export class FilesController extends AbstractViewController<FilesControllerEvent
|
||||
|
||||
private async downloadFile(file: FileItem): Promise<void> {
|
||||
let downloadingToastId = ''
|
||||
let canShowProgressNotification = false
|
||||
|
||||
if (this.mobileDevice && this.platform === Platform.Android) {
|
||||
canShowProgressNotification = await this.mobileDevice.canDisplayNotifications()
|
||||
}
|
||||
|
||||
try {
|
||||
const saver = StreamingFileSaver.available() ? new StreamingFileSaver(file.name) : new ClassicFileSaver()
|
||||
@@ -301,11 +306,21 @@ export class FilesController extends AbstractViewController<FilesControllerEvent
|
||||
await saver.selectFileToSaveTo()
|
||||
}
|
||||
|
||||
downloadingToastId = addToast({
|
||||
type: ToastType.Progress,
|
||||
message: `Downloading file "${file.name}" (0%)`,
|
||||
progress: 0,
|
||||
})
|
||||
if (this.mobileDevice && canShowProgressNotification) {
|
||||
downloadingToastId = await this.mobileDevice.displayNotification({
|
||||
title: `Downloading file "${file.name}"`,
|
||||
android: {
|
||||
progress: { max: 100, current: 0, indeterminate: true },
|
||||
onlyAlertOnce: true,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
downloadingToastId = addToast({
|
||||
type: ToastType.Progress,
|
||||
message: `Downloading file "${file.name}" (0%)`,
|
||||
progress: 0,
|
||||
})
|
||||
}
|
||||
|
||||
const decryptedBytesArray: Uint8Array[] = []
|
||||
|
||||
@@ -320,10 +335,23 @@ export class FilesController extends AbstractViewController<FilesControllerEvent
|
||||
|
||||
const progressPercent = Math.floor(progress.percentComplete)
|
||||
|
||||
updateToast(downloadingToastId, {
|
||||
message: fileProgressToHumanReadableString(progress, file.name, { showPercent: true }),
|
||||
progress: progressPercent,
|
||||
})
|
||||
if (this.mobileDevice && canShowProgressNotification) {
|
||||
this.mobileDevice
|
||||
.displayNotification({
|
||||
id: downloadingToastId,
|
||||
title: `Downloading file "${file.name}"`,
|
||||
android: {
|
||||
progress: { max: 100, current: progressPercent, indeterminate: false },
|
||||
onlyAlertOnce: true,
|
||||
},
|
||||
})
|
||||
.catch(console.error)
|
||||
} else {
|
||||
updateToast(downloadingToastId, {
|
||||
message: fileProgressToHumanReadableString(progress, file.name, { showPercent: true }),
|
||||
progress: progressPercent,
|
||||
})
|
||||
}
|
||||
|
||||
lastProgress = progress
|
||||
})
|
||||
@@ -339,7 +367,6 @@ export class FilesController extends AbstractViewController<FilesControllerEvent
|
||||
const blob = new Blob([finalBytes], {
|
||||
type: file.mimeType,
|
||||
})
|
||||
// await downloadOrShareBlobBasedOnPlatform(this, blob, file.name, false)
|
||||
await downloadOrShareBlobBasedOnPlatform({
|
||||
archiveService: this.archiveService,
|
||||
platform: this.platform,
|
||||
@@ -351,12 +378,18 @@ export class FilesController extends AbstractViewController<FilesControllerEvent
|
||||
})
|
||||
}
|
||||
|
||||
addToast({
|
||||
type: ToastType.Success,
|
||||
message: `Successfully downloaded file${
|
||||
lastProgress && lastProgress.source === 'local' ? ' from local backup' : ''
|
||||
}`,
|
||||
})
|
||||
if (this.mobileDevice && canShowProgressNotification) {
|
||||
await this.mobileDevice.displayNotification({
|
||||
title: `Successfully downloaded file "${file.name}"`,
|
||||
})
|
||||
} else {
|
||||
addToast({
|
||||
type: ToastType.Success,
|
||||
message: `Successfully downloaded file${
|
||||
lastProgress && lastProgress.source === 'local' ? ' from local backup' : ''
|
||||
}`,
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
|
||||
@@ -366,8 +399,12 @@ export class FilesController extends AbstractViewController<FilesControllerEvent
|
||||
})
|
||||
}
|
||||
|
||||
if (downloadingToastId.length > 0) {
|
||||
dismissToast(downloadingToastId)
|
||||
if (downloadingToastId) {
|
||||
if (this.mobileDevice && canShowProgressNotification) {
|
||||
this.mobileDevice.cancelNotification(downloadingToastId).catch(console.error)
|
||||
} else {
|
||||
dismissToast(downloadingToastId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,6 +449,11 @@ export class FilesController extends AbstractViewController<FilesControllerEvent
|
||||
const { showToast = true, note } = options
|
||||
|
||||
let toastId: string | undefined
|
||||
let canShowProgressNotification = false
|
||||
|
||||
if (showToast && this.mobileDevice && this.platform === Platform.Android) {
|
||||
canShowProgressNotification = await this.mobileDevice.canDisplayNotifications()
|
||||
}
|
||||
|
||||
try {
|
||||
const minimumChunkSize = this.files.minimumChunkSize()
|
||||
@@ -449,11 +491,21 @@ export class FilesController extends AbstractViewController<FilesControllerEvent
|
||||
const initialProgress = operation.getProgress().percentComplete
|
||||
|
||||
if (showToast) {
|
||||
toastId = addToast({
|
||||
type: ToastType.Progress,
|
||||
message: `Uploading file "${fileToUpload.name}" (${initialProgress}%)`,
|
||||
progress: initialProgress,
|
||||
})
|
||||
if (this.mobileDevice && canShowProgressNotification) {
|
||||
toastId = await this.mobileDevice.displayNotification({
|
||||
title: `Uploading file "${fileToUpload.name}"`,
|
||||
android: {
|
||||
progress: { max: 100, current: initialProgress, indeterminate: true },
|
||||
onlyAlertOnce: true,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
toastId = addToast({
|
||||
type: ToastType.Progress,
|
||||
message: `Uploading file "${fileToUpload.name}" (${initialProgress}%)`,
|
||||
progress: initialProgress,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const onChunk: OnChunkCallbackNoProgress = async ({ data, index, isLast }) => {
|
||||
@@ -461,10 +513,21 @@ export class FilesController extends AbstractViewController<FilesControllerEvent
|
||||
|
||||
const percentComplete = Math.round(operation.getProgress().percentComplete)
|
||||
if (toastId) {
|
||||
updateToast(toastId, {
|
||||
message: `Uploading file "${fileToUpload.name}" (${percentComplete}%)`,
|
||||
progress: percentComplete,
|
||||
})
|
||||
if (this.mobileDevice && canShowProgressNotification) {
|
||||
await this.mobileDevice.displayNotification({
|
||||
id: toastId,
|
||||
title: `Uploading file "${fileToUpload.name}"`,
|
||||
android: {
|
||||
progress: { max: 100, current: percentComplete, indeterminate: false },
|
||||
onlyAlertOnce: true,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
updateToast(toastId, {
|
||||
message: `Uploading file "${fileToUpload.name}" (${percentComplete}%)`,
|
||||
progress: percentComplete,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,32 +543,54 @@ export class FilesController extends AbstractViewController<FilesControllerEvent
|
||||
if (uploadedFile instanceof ClientDisplayableError) {
|
||||
addToast({
|
||||
type: ToastType.Error,
|
||||
message: 'Unable to close upload session',
|
||||
message: uploadedFile.text,
|
||||
})
|
||||
throw new Error('Unable to close upload session')
|
||||
throw new Error(uploadedFile.text)
|
||||
}
|
||||
|
||||
if (toastId) {
|
||||
if (this.mobileDevice && canShowProgressNotification) {
|
||||
this.mobileDevice.cancelNotification(toastId).catch(console.error)
|
||||
}
|
||||
dismissToast(toastId)
|
||||
}
|
||||
if (showToast) {
|
||||
addToast({
|
||||
type: ToastType.Success,
|
||||
message: `Uploaded file "${uploadedFile.name}"`,
|
||||
actions: [
|
||||
{
|
||||
label: 'Open',
|
||||
handler: (toastId) => {
|
||||
void this.handleFileAction({
|
||||
type: FileItemActionType.PreviewFile,
|
||||
payload: { file: uploadedFile },
|
||||
})
|
||||
dismissToast(toastId)
|
||||
if (this.mobileDevice && canShowProgressNotification) {
|
||||
this.mobileDevice
|
||||
.displayNotification({
|
||||
id: uploadedFile.uuid,
|
||||
title: `Uploaded file "${uploadedFile.name}"`,
|
||||
android: {
|
||||
actions: [
|
||||
{
|
||||
title: 'Open',
|
||||
pressAction: {
|
||||
id: 'open-file',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
autoClose: true,
|
||||
})
|
||||
})
|
||||
.catch(console.error)
|
||||
} else {
|
||||
addToast({
|
||||
type: ToastType.Success,
|
||||
message: `Uploaded file "${uploadedFile.name}"`,
|
||||
actions: [
|
||||
{
|
||||
label: 'Open',
|
||||
handler: (toastId) => {
|
||||
void this.handleFileAction({
|
||||
type: FileItemActionType.PreviewFile,
|
||||
payload: { file: uploadedFile },
|
||||
})
|
||||
dismissToast(toastId)
|
||||
},
|
||||
},
|
||||
],
|
||||
autoClose: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return uploadedFile
|
||||
@@ -513,12 +598,23 @@ export class FilesController extends AbstractViewController<FilesControllerEvent
|
||||
console.error(error)
|
||||
|
||||
if (toastId) {
|
||||
if (this.mobileDevice && canShowProgressNotification) {
|
||||
this.mobileDevice.cancelNotification(toastId).catch(console.error)
|
||||
}
|
||||
dismissToast(toastId)
|
||||
}
|
||||
addToast({
|
||||
type: ToastType.Error,
|
||||
message: 'There was an error while uploading the file',
|
||||
})
|
||||
if (this.mobileDevice && canShowProgressNotification) {
|
||||
this.mobileDevice
|
||||
.displayNotification({
|
||||
title: 'There was an error while uploading the file',
|
||||
})
|
||||
.catch(console.error)
|
||||
} else {
|
||||
addToast({
|
||||
type: ToastType.Error,
|
||||
message: 'There was an error while uploading the file',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return undefined
|
||||
|
||||
@@ -98,7 +98,9 @@ export class MobileWebReceiver {
|
||||
case ReactNativeToWebEvent.ReceivedLink:
|
||||
void this.application.handleReceivedLinkEvent(messageData as { link: string; title: string })
|
||||
break
|
||||
|
||||
case ReactNativeToWebEvent.OpenFilePreview:
|
||||
void this.application.handleOpenFilePreviewEvent(messageData as { id: string })
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user