fix: export/sharing notes on mobile webview (#1644)
This commit is contained in:
@@ -121,11 +121,7 @@ export const AppStackComponent = (props: ModalStackNavigationProp<'AppStack'>) =
|
||||
[application],
|
||||
)
|
||||
|
||||
if (!application) {
|
||||
return null
|
||||
}
|
||||
|
||||
const shouldOpenWebApp = application.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped) as boolean
|
||||
const shouldOpenWebApp = application?.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped) as boolean
|
||||
|
||||
if (IsMobileWeb || shouldOpenWebApp) {
|
||||
return (
|
||||
|
||||
@@ -7,16 +7,27 @@ import {
|
||||
LegacyRawKeychainValue,
|
||||
MobileDeviceInterface,
|
||||
NamespacedRootKeyInKeychain,
|
||||
Platform as SNPlatform,
|
||||
RawKeychainValue,
|
||||
removeFromArray,
|
||||
TransferPayload,
|
||||
} from '@standardnotes/snjs'
|
||||
import { Alert, Linking, Platform, StatusBar } from 'react-native'
|
||||
import { Alert, Linking, PermissionsAndroid, Platform, StatusBar } from 'react-native'
|
||||
import FingerprintScanner from 'react-native-fingerprint-scanner'
|
||||
import FlagSecure from 'react-native-flag-secure-android'
|
||||
import {
|
||||
CachesDirectoryPath,
|
||||
DocumentDirectoryPath,
|
||||
DownloadDirectoryPath,
|
||||
exists,
|
||||
unlink,
|
||||
writeFile,
|
||||
} from 'react-native-fs'
|
||||
import { hide, show } from 'react-native-privacy-snapshot'
|
||||
import Share from 'react-native-share'
|
||||
import { AppStateObserverService } from './../AppStateObserverService'
|
||||
import Keychain from './Keychain'
|
||||
import { SNReactNativeCrypto } from './ReactNativeCrypto'
|
||||
import { IsMobileWeb } from './Utils'
|
||||
|
||||
export type BiometricsType = 'Fingerprint' | 'Face ID' | 'Biometrics' | 'Touch ID'
|
||||
@@ -64,10 +75,14 @@ const showLoadFailForItemIds = (failedItemIds: string[]) => {
|
||||
|
||||
export class MobileDevice implements MobileDeviceInterface {
|
||||
environment: Environment.Mobile = Environment.Mobile
|
||||
platform: SNPlatform.Ios | SNPlatform.Android = Platform.OS === 'ios' ? SNPlatform.Ios : SNPlatform.Android
|
||||
private eventObservers: MobileDeviceEventHandler[] = []
|
||||
public isDarkMode = false
|
||||
private crypto: SNReactNativeCrypto
|
||||
|
||||
constructor(private stateObserverService?: AppStateObserverService) {}
|
||||
constructor(private stateObserverService?: AppStateObserverService) {
|
||||
this.crypto = new SNReactNativeCrypto()
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.stateObserverService?.deinit()
|
||||
@@ -455,4 +470,76 @@ export class MobileDevice implements MobileDeviceInterface {
|
||||
isDeviceDestroyed() {
|
||||
return false
|
||||
}
|
||||
|
||||
async deleteFileAtPathIfExists(path: string) {
|
||||
if (await exists(path)) {
|
||||
await unlink(path)
|
||||
}
|
||||
}
|
||||
|
||||
async shareBase64AsFile(base64: string, filename: string) {
|
||||
let downloadedTempFilePath: string | undefined
|
||||
try {
|
||||
downloadedTempFilePath = await this.downloadBase64AsFile(base64, filename, true)
|
||||
if (!downloadedTempFilePath) {
|
||||
return
|
||||
}
|
||||
await Share.open({
|
||||
url: `file://${downloadedTempFilePath}`,
|
||||
failOnCancel: false,
|
||||
})
|
||||
} catch (error) {
|
||||
this.consoleLog(`${error}`)
|
||||
} finally {
|
||||
if (downloadedTempFilePath) {
|
||||
void this.deleteFileAtPathIfExists(downloadedTempFilePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getFileDestinationPath(filename: string, saveInTempLocation: boolean): string {
|
||||
let directory = DocumentDirectoryPath
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
directory = saveInTempLocation ? CachesDirectoryPath : DownloadDirectoryPath
|
||||
}
|
||||
|
||||
return `${directory}/${filename}`
|
||||
}
|
||||
|
||||
async hasStoragePermissionOnAndroid(): Promise<boolean> {
|
||||
if (Platform.OS !== 'android') {
|
||||
return true
|
||||
}
|
||||
const grantedStatus = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE)
|
||||
if (grantedStatus === PermissionsAndroid.RESULTS.GRANTED) {
|
||||
return true
|
||||
}
|
||||
Alert.alert(
|
||||
'Storage permissions are required in order to download files. Please accept the permissions prompt and try again.',
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
async downloadBase64AsFile(
|
||||
base64: string,
|
||||
filename: string,
|
||||
saveInTempLocation = false,
|
||||
): Promise<string | undefined> {
|
||||
const isGrantedStoragePermissionOnAndroid = await this.hasStoragePermissionOnAndroid()
|
||||
|
||||
if (!isGrantedStoragePermissionOnAndroid) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const path = this.getFileDestinationPath(filename, saveInTempLocation)
|
||||
void this.deleteFileAtPathIfExists(path)
|
||||
const decodedContents = this.crypto.base64Decode(base64.replace(/data.*base64,/, ''))
|
||||
await writeFile(path, decodedContents)
|
||||
return path
|
||||
} catch (error) {
|
||||
this.consoleLog(`${error}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => vo
|
||||
constructor(messageSender) {
|
||||
this.appVersion = '${pjson.version} (${VersionInfo.buildVersion})'
|
||||
this.environment = 4
|
||||
this.platform = ${device.platform}
|
||||
this.databases = []
|
||||
this.messageSender = messageSender
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user