feat: On Android, you can now share text & files from other apps directly into Standard Notes (#2352)

This commit is contained in:
Aman Harwara
2023-07-12 00:16:32 +05:30
committed by GitHub
parent 1f5354c816
commit 3dc179c7b0
16 changed files with 535 additions and 15 deletions

View File

@@ -24,11 +24,13 @@ import {
BackupServiceInterface,
InternalFeatureService,
InternalFeatureServiceInterface,
NoteContent,
SNNote,
} from '@standardnotes/snjs'
import { makeObservable, observable } from 'mobx'
import { startAuthentication, startRegistration } from '@simplewebauthn/browser'
import { PanelResizedData } from '@/Types/PanelResizedData'
import { isAndroid, isDesktopApplication, isDev, isIOS } from '@/Utils'
import { getBlobFromBase64, isAndroid, isDesktopApplication, isDev, isIOS } from '@/Utils'
import { DesktopManager } from './Device/DesktopManager'
import {
ArchiveManager,
@@ -66,6 +68,7 @@ export class WebApplication extends SNApplication implements WebApplicationInter
private readonly mobileWebReceiver?: MobileWebReceiver
private readonly androidBackHandler?: AndroidBackHandler
private readonly visibilityObserver?: VisibilityObserver
private readonly mobileAppEventObserver?: () => void
public readonly devMode?: DevMode
@@ -137,6 +140,9 @@ export class WebApplication extends SNApplication implements WebApplicationInter
if (this.isNativeMobileWeb()) {
this.mobileWebReceiver = new MobileWebReceiver(this)
this.androidBackHandler = new AndroidBackHandler()
this.mobileAppEventObserver = this.addEventObserver(async (event) => {
this.mobileDevice().notifyApplicationEvent(event)
})
// eslint-disable-next-line no-console
console.log = (...args) => {
@@ -186,6 +192,11 @@ export class WebApplication extends SNApplication implements WebApplicationInter
this.visibilityObserver.deinit()
;(this.visibilityObserver as unknown) = undefined
}
if (this.mobileAppEventObserver) {
this.mobileAppEventObserver()
;(this.mobileAppEventObserver as unknown) = undefined
}
} catch (error) {
console.error('Error while deiniting application', error)
}
@@ -376,6 +387,27 @@ export class WebApplication extends SNApplication implements WebApplicationInter
this.notifyWebEvent(WebAppEvent.MobileKeyboardDidChangeFrame, frame)
}
handleReceivedFileEvent(file: { name: string; mimeType: string; data: string }): void {
const filesController = this.getViewControllerManager().filesController
const blob = getBlobFromBase64(file.data, file.mimeType)
const mappedFile = new File([blob], file.name, { type: file.mimeType })
void filesController.uploadNewFile(mappedFile, true)
}
async handleReceivedTextEvent({ text, title }: { text: string; title?: string | undefined }) {
const titleForNote = title || this.getViewControllerManager().itemListController.titleForNewNote()
const note = this.items.createTemplateItem<NoteContent, SNNote>(ContentType.Note, {
title: titleForNote,
text: text,
references: [],
})
const insertedNote = await this.mutator.insertItem(note)
this.getViewControllerManager().selectionController.selectItem(insertedNote.uuid, true).catch(console.error)
}
private async lockApplicationAfterMobileEventIfApplicable(): Promise<void> {
const isLocked = await this.isLocked()
if (isLocked) {

View File

@@ -83,6 +83,18 @@ export class MobileWebReceiver {
messageData as { height: number; contentHeight: number },
)
break
case ReactNativeToWebEvent.ReceivedFile:
void this.application.handleReceivedFileEvent(
messageData as {
name: string
mimeType: string
data: string
},
)
break
case ReactNativeToWebEvent.ReceivedText:
void this.application.handleReceivedTextEvent(messageData as { text: string; title?: string })
break
default:
break

View File

@@ -229,3 +229,23 @@ export const getBase64FromBlob = (blob: Blob) => {
reader.readAsDataURL(blob)
})
}
export const getBlobFromBase64 = (b64Data: string, contentType = '', sliceSize = 512) => {
const byteCharacters = atob(b64Data)
const byteArrays = []
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize)
const byteNumbers = new Array(slice.length)
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i)
}
const byteArray = new Uint8Array(byteNumbers)
byteArrays.push(byteArray)
}
const blob = new Blob(byteArrays, { type: contentType })
return blob
}