From ab2e88a710c65771312bd9d02cec0b400d352a0e Mon Sep 17 00:00:00 2001 From: Aman Harwara Date: Fri, 21 Jul 2023 15:53:36 +0530 Subject: [PATCH] fix: Shared image links are now correctly handled on iOS --- .../mobile/src/ReceivedSharedItemsHandler.ts | 51 ++++++++----------- .../snjs/lib/Client/ReactNativeToWebEvent.ts | 1 + .../WebApplication/WebApplicationInterface.ts | 1 + .../javascripts/Application/WebApplication.ts | 39 +++++++++++++- .../NativeMobileWeb/MobileWebReceiver.ts | 5 +- 5 files changed, 64 insertions(+), 33 deletions(-) diff --git a/packages/mobile/src/ReceivedSharedItemsHandler.ts b/packages/mobile/src/ReceivedSharedItemsHandler.ts index f2ecb5044..169a7bb6a 100644 --- a/packages/mobile/src/ReceivedSharedItemsHandler.ts +++ b/packages/mobile/src/ReceivedSharedItemsHandler.ts @@ -109,42 +109,16 @@ export class ReceivedSharedItemsHandler { return } - if (isReceivedAndroidFile(item)) { - const data = await readFile(item.contentUri, 'base64') - const file = { - name: item.fileName || item.contentUri, - data, - mimeType: item.mimeType, - } - this.webViewRef.current?.postMessage( - JSON.stringify({ - reactNativeEvent: ReactNativeToWebEvent.ReceivedFile, - messageType: 'event', - messageData: file, - }), - ) - } else if (isReceivedIosFile(item)) { - const data = await readFile(item.path, 'base64') - const file = { - name: item.fileName || item.path, - data, - mimeType: item.mimeType, - } - this.webViewRef.current?.postMessage( - JSON.stringify({ - reactNativeEvent: ReactNativeToWebEvent.ReceivedFile, - messageType: 'event', - messageData: file, - }), - ) + if (isReceivedAndroidFile(item) || isReceivedIosFile(item)) { + this.sendFileToWebView(item).catch(console.error) } else if (isReceivedWeblink(item)) { this.webViewRef.current?.postMessage( JSON.stringify({ - reactNativeEvent: ReactNativeToWebEvent.ReceivedText, + reactNativeEvent: ReactNativeToWebEvent.ReceivedLink, messageType: 'event', messageData: { title: item.subject || item.weblink, - text: item.weblink, + link: item.weblink, }, }), ) @@ -163,6 +137,23 @@ export class ReceivedSharedItemsHandler { this.handleItemsQueue().catch(console.error) } + sendFileToWebView = async (item: ReceivedAndroidFile | ReceivedIosFile) => { + const path = isReceivedAndroidFile(item) ? item.contentUri : item.path + const data = await readFile(path, 'base64') + const file = { + name: item.fileName || item.path, + data, + mimeType: item.mimeType, + } + this.webViewRef.current?.postMessage( + JSON.stringify({ + reactNativeEvent: ReactNativeToWebEvent.ReceivedFile, + messageType: 'event', + messageData: file, + }), + ) + } + private addSharedItemsToQueue = async (url?: string) => { const received = Platform.OS === 'ios' ? await ReceiveSharingIntent.getFileNames(url) : await ReceiveSharingIntent.getFileNames() diff --git a/packages/snjs/lib/Client/ReactNativeToWebEvent.ts b/packages/snjs/lib/Client/ReactNativeToWebEvent.ts index c232859ee..e30ffcb0d 100644 --- a/packages/snjs/lib/Client/ReactNativeToWebEvent.ts +++ b/packages/snjs/lib/Client/ReactNativeToWebEvent.ts @@ -10,5 +10,6 @@ export enum ReactNativeToWebEvent { KeyboardWillShow = 'KeyboardWillShow', KeyboardWillHide = 'KeyboardWillHide', ReceivedFile = 'ReceivedFile', + ReceivedLink = 'ReceivedLink', ReceivedText = 'ReceivedText', } diff --git a/packages/ui-services/src/WebApplication/WebApplicationInterface.ts b/packages/ui-services/src/WebApplication/WebApplicationInterface.ts index 0f2602839..3a8af4132 100644 --- a/packages/ui-services/src/WebApplication/WebApplicationInterface.ts +++ b/packages/ui-services/src/WebApplication/WebApplicationInterface.ts @@ -18,6 +18,7 @@ export interface WebApplicationInterface extends ApplicationInterface { handleMobileKeyboardDidChangeFrameEvent(frame: { height: number; contentHeight: number }): void handleReceivedFileEvent(file: { name: string; mimeType: string; data: string }): void handleReceivedTextEvent(item: { text: string; title?: string }): Promise + handleReceivedLinkEvent(item: { link: string; title: string }): Promise isNativeMobileWeb(): boolean mobileDevice(): MobileDeviceInterface handleAndroidBackButtonPressed(): void diff --git a/packages/web/src/javascripts/Application/WebApplication.ts b/packages/web/src/javascripts/Application/WebApplication.ts index 81433a0c6..5b4955f76 100644 --- a/packages/web/src/javascripts/Application/WebApplication.ts +++ b/packages/web/src/javascripts/Application/WebApplication.ts @@ -54,7 +54,7 @@ import { ItemGroupController } from '@/Components/NoteView/Controller/ItemGroupC import { VisibilityObserver } from './VisibilityObserver' import { MomentsService } from '@/Controllers/Moments/MomentsService' import { DevMode } from './DevMode' -import { ToastType, addToast } from '@standardnotes/toast' +import { ToastType, addToast, dismissToast } from '@standardnotes/toast' export type WebEventObserver = (event: WebAppEvent, data?: unknown) => void @@ -395,7 +395,7 @@ export class WebApplication extends SNApplication implements WebApplicationInter const filesController = this.controllers.filesController const blob = getBlobFromBase64(file.data, file.mimeType) const mappedFile = new File([blob], file.name, { type: file.mimeType }) - void filesController.uploadNewFile(mappedFile, true) + filesController.uploadNewFile(mappedFile, true).catch(console.error) } async handleReceivedTextEvent({ text, title }: { text: string; title?: string | undefined }) { @@ -417,6 +417,41 @@ export class WebApplication extends SNApplication implements WebApplicationInter }) } + async handleReceivedLinkEvent({ link, title }: { link: string; title: string | undefined }) { + const url = new URL(link) + const paths = url.pathname.split('/') + const finalPath = paths[paths.length - 1] + const isImagePath = !!finalPath && /\.(png|svg|webp|jpe?g)/.test(finalPath) + + if (isImagePath) { + const fetchToastUuid = addToast({ + type: ToastType.Loading, + message: 'Fetching image from link...', + }) + try { + const imgResponse = await fetch(link) + if (!imgResponse.ok) { + throw new Error(`${imgResponse.status}: Could not fetch image`) + } + const imgBlob = await imgResponse.blob() + const file = new File([imgBlob], finalPath, { + type: imgBlob.type, + }) + this.controllers.filesController.uploadNewFile(file, true).catch(console.error) + } catch (error) { + console.error(error) + } finally { + dismissToast(fetchToastUuid) + } + return + } + + this.handleReceivedTextEvent({ + title: title, + text: link, + }).catch(console.error) + } + private async lockApplicationAfterMobileEventIfApplicable(): Promise { const isLocked = await this.isLocked() if (isLocked) { diff --git a/packages/web/src/javascripts/NativeMobileWeb/MobileWebReceiver.ts b/packages/web/src/javascripts/NativeMobileWeb/MobileWebReceiver.ts index 0e26d6e2a..428740b3e 100644 --- a/packages/web/src/javascripts/NativeMobileWeb/MobileWebReceiver.ts +++ b/packages/web/src/javascripts/NativeMobileWeb/MobileWebReceiver.ts @@ -93,7 +93,10 @@ export class MobileWebReceiver { ) break case ReactNativeToWebEvent.ReceivedText: - void this.application.handleReceivedTextEvent(messageData as { text: string; title?: string }) + void this.application.handleReceivedTextEvent(messageData as { text: string }) + break + case ReactNativeToWebEvent.ReceivedLink: + void this.application.handleReceivedLinkEvent(messageData as { link: string; title: string }) break default: