Skip to content
This repository has been archived by the owner on Jun 15, 2022. It is now read-only.

Commit

Permalink
feat: app group update (#617)
Browse files Browse the repository at this point in the history
  • Loading branch information
moughxyz authored May 17, 2022
1 parent 08b7b28 commit bf1dccc
Show file tree
Hide file tree
Showing 14 changed files with 741 additions and 175 deletions.
13 changes: 8 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"android:bundle": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/build/intermediates/res/merged/release/"
},
"resolutions": {
"@types/react": "^17"
"@types/react": "^17",
"react-native/react-devtools-core": "4.24.0"
},
"dependencies": {
"@expo/react-native-action-sheet": "^3.13.0",
Expand All @@ -32,14 +33,14 @@
"@react-navigation/elements": "^1.3.3",
"@react-navigation/native": "^6.0.10",
"@react-navigation/stack": "^6.2.1",
"@standardnotes/components": "^1.8.0",
"@standardnotes/filepicker": "^1.13.7",
"@standardnotes/components": "^1.8.1",
"@standardnotes/filepicker": "^1.14.7",
"@standardnotes/react-native-aes": "^1.4.3",
"@standardnotes/react-native-textview": "1.0.2",
"@standardnotes/react-native-utils": "1.0.1",
"@standardnotes/sncrypto-common": "1.8.2",
"@standardnotes/snjs": "2.106.9",
"@standardnotes/stylekit": "5.25.0",
"@standardnotes/snjs": "2.109.0",
"@standardnotes/stylekit": "5.26.0",
"@types/styled-components-react-native": "5.1.3",
"js-base64": "^3.7.2",
"moment": "^2.29.2",
Expand Down Expand Up @@ -111,6 +112,8 @@
"postinstall-postinstall": "^2.1.0",
"prettier": "^2.6.0",
"prettier-plugin-organize-imports": "^2.3.4",
"react-devtools": "^4.24.6",
"react-devtools-core": "^4.24.6",
"react-native-pager-view": "^5.4.15",
"react-test-renderer": "17.0.2",
"replace-in-file": "^6.3.2",
Expand Down
41 changes: 25 additions & 16 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ApplicationGroup } from '@Lib/ApplicationGroup'
import { navigationRef } from '@Lib/NavigationService'
import { DefaultTheme, NavigationContainer } from '@react-navigation/native'
import { MobileThemeVariables } from '@Root/Style/Themes/styled-components'
import { DeinitSource } from '@standardnotes/snjs'
import { ApplicationGroupEvent, DeinitMode, DeinitSource } from '@standardnotes/snjs'
import { ThemeService, ThemeServiceContext } from '@Style/ThemeService'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { StatusBar } from 'react-native'
Expand Down Expand Up @@ -66,11 +66,13 @@ const AppComponent: React.FC<{
const loadApplication = async () => {
themeServiceInstance = new ThemeService(application)
setThemeServiceRef(themeServiceInstance)
await application?.prepareForLaunch({

await application.prepareForLaunch({
receiveChallenge: async challenge => {
application!.promptForChallenge(challenge)
application.promptForChallenge(challenge)
},
})

await themeServiceInstance.init()
launchApp(true, false)
}
Expand All @@ -80,8 +82,9 @@ const AppComponent: React.FC<{
return () => {
themeServiceInstance?.deinit()
setThemeServiceRef(undefined)

if (!application.hasStartedDeinit()) {
application.deinit(DeinitSource.Lock)
application.deinit(DeinitMode.Soft, DeinitSource.Lock)
}
}
}, [application, application.Uuid, env, launchApp, setThemeServiceRef])
Expand Down Expand Up @@ -120,28 +123,34 @@ const AppComponent: React.FC<{
)
}

/**
* AppGroupInstance is only created once per application lifetime
* so it is created outside of a component
*/
const AppGroupInstance = new ApplicationGroup()
void AppGroupInstance.initialize()

export const App = (props: { env: TEnvironment }) => {
const applicationGroupRef = useRef(AppGroupInstance)
const [application, setApplication] = useState<MobileApplication | undefined>()

const createNewAppGroup = useCallback(() => {
const group = new ApplicationGroup()
void group.initialize()
return group
}, [])

const [appGroup, setAppGroup] = useState<ApplicationGroup>(() => createNewAppGroup())

useEffect(() => {
const removeAppChangeObserver = applicationGroupRef.current.addApplicationChangeObserver(() => {
const mobileApplication = applicationGroupRef.current.primaryApplication as MobileApplication
setApplication(mobileApplication)
const removeAppChangeObserver = appGroup.addEventObserver(event => {
if (event === ApplicationGroupEvent.PrimaryApplicationSet) {
const mobileApplication = appGroup.primaryApplication as MobileApplication
setApplication(mobileApplication)
} else if (event === ApplicationGroupEvent.DeviceWillRestart) {
setApplication(undefined)
setAppGroup(createNewAppGroup())
}
})
return removeAppChangeObserver
}, [applicationGroupRef.current.primaryApplication])
}, [appGroup, appGroup.primaryApplication, setAppGroup, createNewAppGroup])

if (!application) {
return null
}

return (
<ApplicationContext.Provider value={application}>
<AppComponent env={props.env} key={application.Uuid} application={application} />
Expand Down
38 changes: 19 additions & 19 deletions src/Hooks/useFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from '@Root/Screens/UploadedFilesList/UploadedFileItemAction'
import { Tabs } from '@Screens/UploadedFilesList/UploadedFilesList'
import { FileDownloadProgress } from '@standardnotes/files/dist/Domain/Types/FileDownloadProgress'
import { ButtonType, ChallengeReason, ClientDisplayableError, ContentType, SNFile, SNNote } from '@standardnotes/snjs'
import { ButtonType, ChallengeReason, ClientDisplayableError, ContentType, FileItem, SNNote } from '@standardnotes/snjs'
import { CustomActionSheetOption, useCustomActionSheet } from '@Style/CustomActionSheet'
import { useCallback, useEffect, useState } from 'react'
import { Platform } from 'react-native'
Expand All @@ -25,7 +25,7 @@ type Props = {
note: SNNote
}
type TDownloadFileAndReturnLocalPathParams = {
file: SNFile
file: FileItem
saveInTempLocation?: boolean
showSuccessToast?: boolean
}
Expand All @@ -51,8 +51,8 @@ export const useFiles = ({ note }: Props) => {
const { showActionSheet } = useCustomActionSheet()
const navigation = useNavigation<TAppStackNavigationProp>()

const [attachedFiles, setAttachedFiles] = useState<SNFile[]>([])
const [allFiles, setAllFiles] = useState<SNFile[]>([])
const [attachedFiles, setAttachedFiles] = useState<FileItem[]>([])
const [allFiles, setAllFiles] = useState<FileItem[]>([])
const [isDownloading, setIsDownloading] = useState(false)

const { GeneralText } = ErrorMessage
Expand All @@ -65,7 +65,7 @@ export const useFiles = ({ note }: Props) => {
}, [application.items, filesService.sortByName, note])

const reloadAllFiles = useCallback(() => {
setAllFiles(application.items.getItems<SNFile>(ContentType.File).sort(filesService.sortByName) as SNFile[])
setAllFiles(application.items.getItems<FileItem>(ContentType.File).sort(filesService.sortByName) as FileItem[])
}, [application.items, filesService.sortByName])

const deleteFileAtPath = useCallback(async (path: string) => {
Expand Down Expand Up @@ -215,7 +215,7 @@ export const useFiles = ({ note }: Props) => {
)

const shareFile = useCallback(
async (file: SNFile) => {
async (file: FileItem) => {
const downloadedFilePath = await downloadFileAndReturnLocalPath({
file,
saveInTempLocation: true,
Expand Down Expand Up @@ -261,7 +261,7 @@ export const useFiles = ({ note }: Props) => {
)

const attachFileToNote = useCallback(
async (file: SNFile, showToastAfterAction = true) => {
async (file: FileItem, showToastAfterAction = true) => {
await application.items.associateFileWithNote(file, note)
void application.sync.sync()

Expand All @@ -277,7 +277,7 @@ export const useFiles = ({ note }: Props) => {
)

const detachFileFromNote = useCallback(
async (file: SNFile) => {
async (file: FileItem) => {
await application.items.disassociateFileWithNote(file, note)
void application.sync.sync()
Toast.show({
Expand All @@ -290,9 +290,9 @@ export const useFiles = ({ note }: Props) => {
)

const toggleFileProtection = useCallback(
async (file: SNFile) => {
async (file: FileItem) => {
try {
let result: SNFile | undefined
let result: FileItem | undefined
if (file.protected) {
result = await application.mutator.unprotectFile(file)
} else {
Expand All @@ -309,22 +309,22 @@ export const useFiles = ({ note }: Props) => {
)

const authorizeProtectedActionForFile = useCallback(
async (file: SNFile, challengeReason: ChallengeReason) => {
async (file: FileItem, challengeReason: ChallengeReason) => {
const authorizedFiles = await application.protections.authorizeProtectedActionForFiles([file], challengeReason)
return authorizedFiles.length > 0 && authorizedFiles.includes(file)
},
[application]
)

const renameFile = useCallback(
async (file: SNFile, fileName: string) => {
async (file: FileItem, fileName: string) => {
await application.items.renameFile(file, fileName)
},
[application]
)

const previewFile = useCallback(
async (file: SNFile) => {
async (file: FileItem) => {
let downloadedFilePath: string | undefined = ''
try {
const isPreviewable = isFileTypePreviewable(file.mimeType)
Expand Down Expand Up @@ -369,7 +369,7 @@ export const useFiles = ({ note }: Props) => {
)

const deleteFile = useCallback(
async (file: SNFile) => {
async (file: FileItem) => {
const shouldDelete = await application.alertService.confirm(
`Are you sure you want to permanently delete "${file.name}"?`,
undefined,
Expand Down Expand Up @@ -436,7 +436,7 @@ export const useFiles = ({ note }: Props) => {
}
}

const uploadSingleFile = async (file: DocumentPickerResponse | Asset, size: number): Promise<SNFile | void> => {
const uploadSingleFile = async (file: DocumentPickerResponse | Asset, size: number): Promise<FileItem | void> => {
try {
const fileName = filesService.getFileName(file)
const operation = await application.files.beginNewFileUpload(size)
Expand Down Expand Up @@ -476,13 +476,13 @@ export const useFiles = ({ note }: Props) => {
}
}

const uploadFiles = async (): Promise<SNFile[] | void> => {
const uploadFiles = async (): Promise<FileItem[] | void> => {
try {
const selectedFiles = await pickFiles()
if (!selectedFiles || selectedFiles.length === 0) {
return
}
const uploadedFiles: SNFile[] = []
const uploadedFiles: FileItem[] = []
for (const file of selectedFiles) {
if (!file.uri || !file.size) {
continue
Expand Down Expand Up @@ -597,7 +597,7 @@ export const useFiles = ({ note }: Props) => {
const uploadFileFromCameraOrImageGallery = async ({
uploadFromGallery = false,
mediaType = 'photo',
}: TUploadFileFromCameraOrImageGalleryParams): Promise<SNFile | void> => {
}: TUploadFileFromCameraOrImageGalleryParams): Promise<FileItem | void> => {
try {
const result = uploadFromGallery
? await launchImageLibrary({ mediaType: 'mixed' })
Expand Down Expand Up @@ -703,7 +703,7 @@ export const useFiles = ({ note }: Props) => {
}, [application, reloadAllFiles, reloadAttachedFiles])

const showActionsMenu = useCallback(
(file: SNFile | undefined) => {
(file: FileItem | undefined) => {
if (!file) {
return
}
Expand Down
5 changes: 3 additions & 2 deletions src/Lib/Application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ChallengePrompt,
ChallengeReason,
ChallengeValidation,
DeinitMode,
DeinitSource,
Environment,
IconsController,
Expand Down Expand Up @@ -93,7 +94,7 @@ export class MobileApplication extends SNApplication {
return this.startedDeinit
}

override deinit(source: DeinitSource): void {
override deinit(mode: DeinitMode, source: DeinitSource): void {
this.startedDeinit = true

for (const service of Object.values(this.MobileServices)) {
Expand All @@ -109,7 +110,7 @@ export class MobileApplication extends SNApplication {

this.MobileServices = {} as MobileServices
this.editorGroup.deinit()
super.deinit(source)
super.deinit(mode, source)
}

override getLaunchChallenge() {
Expand Down
2 changes: 1 addition & 1 deletion src/Lib/ApplicationGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class ApplicationGroup extends SNApplicationGroup {
})
}

private createApplication = (descriptor: ApplicationDescriptor, deviceInterface: DeviceInterface) => {
private createApplication = async (descriptor: ApplicationDescriptor, deviceInterface: DeviceInterface) => {
const application = new MobileApplication(deviceInterface as MobileDeviceInterface, descriptor.identifier)
const internalEventBus = new InternalEventBus()
const applicationState = new ApplicationState(application)
Expand Down
6 changes: 3 additions & 3 deletions src/Lib/FilesService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ByteChunker, FileSelectionResponse, OnChunkCallback } from '@standardnotes/filepicker'
import { FileDownloadProgress } from '@standardnotes/files/dist/Domain/Types/FileDownloadProgress'
import { ClientDisplayableError } from '@standardnotes/responses'
import { ApplicationService, SNFile } from '@standardnotes/snjs'
import { ApplicationService, FileItem } from '@standardnotes/snjs'
import { Buffer } from 'buffer'
import { Base64 } from 'js-base64'
import { PermissionsAndroid, Platform } from 'react-native'
Expand Down Expand Up @@ -41,7 +41,7 @@ export class FilesService extends ApplicationService {
}

async downloadFileInChunks(
file: SNFile,
file: FileItem,
path: string,
handleOnChunk: (progress: FileDownloadProgress | undefined) => unknown
): Promise<ClientDisplayableError | undefined> {
Expand Down Expand Up @@ -88,7 +88,7 @@ export class FilesService extends ApplicationService {
}
}

sortByName(file1: SNFile, file2: SNFile): number {
sortByName(file1: FileItem, file2: FileItem): number {
return file1.name.toLocaleLowerCase() > file2.name.toLocaleLowerCase() ? 1 : -1
}

Expand Down
12 changes: 12 additions & 0 deletions src/Lib/Interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,11 @@ export class MobileDeviceInterface implements DeviceInterface {
})
)
}

removeRawDatabasePayloadWithId(id: string, identifier: ApplicationIdentifier): Promise<void> {
return this.removeRawStorageValue(this.keyForPayloadId(id, identifier))
}

async removeAllRawDatabasePayloads(identifier: ApplicationIdentifier): Promise<void> {
const keys = await this.getAllDatabaseKeys(identifier)
return AsyncStorage.multiRemove(keys)
Expand Down Expand Up @@ -302,4 +304,14 @@ export class MobileDeviceInterface implements DeviceInterface {
})
.catch(() => showAlert())
}

// eslint-disable-next-line @typescript-eslint/no-empty-function
performSoftReset() {}

// eslint-disable-next-line @typescript-eslint/no-empty-function
performHardReset() {}

isDeviceDestroyed() {
return false
}
}
8 changes: 7 additions & 1 deletion src/Lib/SnjsHelperHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,13 @@ export const useIsLocked = () => {
const application = React.useContext(ApplicationContext)

// State
const [isLocked, setIsLocked] = React.useState<boolean>(() => Boolean(application?.getAppState().locked))
const [isLocked, setIsLocked] = React.useState<boolean>(() => {
if (!application || !application.getAppState()) {
return true
}

return Boolean(application?.getAppState().locked)
})

useEffect(() => {
let isMounted = true
Expand Down
Loading

0 comments on commit bf1dccc

Please sign in to comment.