feat: rename workspace

This commit is contained in:
vardanhakobyan
2022-06-08 16:31:27 +04:00
parent 7ce63cd2d9
commit e8859bdff1
4 changed files with 152 additions and 71 deletions

View File

@@ -14,13 +14,15 @@ import {
SCREEN_INPUT_MODAL_FILE_NAME,
SCREEN_INPUT_MODAL_PASSCODE,
SCREEN_INPUT_MODAL_TAG,
SCREEN_INPUT_MODAL_WORKSPACE_NAME,
SCREEN_MANAGE_SESSIONS,
SCREEN_SETTINGS,
SCREEN_UPLOADED_FILES_LIST,
} from '@Root/Screens/screens'
import { Settings } from '@Root/Screens/Settings/Settings'
import { UploadedFilesList } from '@Root/Screens/UploadedFilesList/UploadedFilesList'
import { Challenge, DeinitMode, DeinitSource, FileItem, SNNote } from '@standardnotes/snjs'
import { WorkspaceInputModal } from '@Screens/InputModal/WorkspaceInputModal'
import { ApplicationDescriptor, Challenge, DeinitMode, DeinitSource, FileItem, SNNote } from '@standardnotes/snjs'
import { ICON_CHECKMARK, ICON_CLOSE } from '@Style/Icons'
import { ThemeService } from '@Style/ThemeService'
import React, { memo, useContext } from 'react'
@@ -48,6 +50,10 @@ export type ModalStackNavigatorParamList = {
[SCREEN_UPLOADED_FILES_LIST]: HeaderTitleParams & {
note: SNNote
}
[SCREEN_INPUT_MODAL_WORKSPACE_NAME]: HeaderTitleParams & {
descriptor: ApplicationDescriptor
renameWorkspace: (descriptor: ApplicationDescriptor, workspaceName: string) => Promise<void>
}
[SCREEN_INPUT_MODAL_PASSCODE]: undefined
[SCREEN_AUTHENTICATE]: {
challenge: Challenge
@@ -275,6 +281,28 @@ export const MainStackComponent = ({ env }: { env: TEnvironment }) => {
})}
component={BlockingModal}
/>
<MainStack.Screen
name={SCREEN_INPUT_MODAL_WORKSPACE_NAME}
options={({ route }) => ({
title: 'Workspace',
gestureEnabled: false,
headerTitle: ({ children }) => {
return <HeaderTitleView title={route.params?.title ?? (children || '')} />
},
headerLeft: ({ disabled, onPress }) => (
<HeaderButtons HeaderButtonComponent={IoniconsHeaderButton}>
<Item
testID="headerButton"
disabled={disabled}
title={Platform.OS === 'ios' ? 'Cancel' : ''}
iconName={Platform.OS === 'ios' ? undefined : ThemeService.nameForIcon(ICON_CLOSE)}
onPress={onPress}
/>
</HeaderButtons>
),
})}
component={WorkspaceInputModal}
/>
</MainStack.Navigator>
)
}

View File

@@ -0,0 +1,61 @@
import { ButtonCell } from '@Root/Components/ButtonCell'
import { SectionedTableCell } from '@Root/Components/SectionedTableCell'
import { TableSection } from '@Root/Components/TableSection'
import { useSafeApplicationContext } from '@Root/Hooks/useSafeApplicationContext'
import { ModalStackNavigationProp } from '@Root/ModalStack'
import { SCREEN_INPUT_MODAL_WORKSPACE_NAME } from '@Root/Screens/screens'
import { ThemeServiceContext } from '@Style/ThemeService'
import React, { FC, useContext, useEffect, useRef, useState } from 'react'
import { TextInput } from 'react-native'
import { Container, Input } from './InputModal.styled'
type Props = ModalStackNavigationProp<typeof SCREEN_INPUT_MODAL_WORKSPACE_NAME>
export const WorkspaceInputModal: FC<Props> = props => {
const { descriptor, renameWorkspace } = props.route.params
const themeService = useContext(ThemeServiceContext)
const application = useSafeApplicationContext()
const workspaceNameInputRef = useRef<TextInput>(null)
const [workspaceName, setWorkspaceName] = useState(descriptor.label)
const onSubmit = async () => {
const trimmedWorkspaceName = workspaceName.trim()
if (trimmedWorkspaceName === '') {
setWorkspaceName(descriptor.label)
await application?.alertService.alert('Workspace name cannot be empty')
workspaceNameInputRef.current?.focus()
return
}
await renameWorkspace(descriptor, trimmedWorkspaceName)
void application.sync.sync()
props.navigation.goBack()
}
useEffect(() => {
workspaceNameInputRef.current?.focus()
}, [])
return (
<Container>
<TableSection>
<SectionedTableCell textInputCell first={true}>
<Input
ref={workspaceNameInputRef as any}
placeholder={'Workspace name'}
onChangeText={setWorkspaceName}
value={workspaceName}
autoCorrect={false}
autoCapitalize={'none'}
keyboardAppearance={themeService?.keyboardColorForActiveTheme()}
underlineColorAndroid={'transparent'}
onSubmitEditing={onSubmit}
/>
</SectionedTableCell>
<ButtonCell maxHeight={45} disabled={workspaceName.length === 0} title={'Save'} bold onPress={onSubmit} />
</TableSection>
</Container>
)
}

View File

@@ -8,7 +8,7 @@ import { TableSection } from '@Root/Components/TableSection'
import { useSafeApplicationContext } from '@Root/Hooks/useSafeApplicationContext'
import { useSafeApplicationGroupContext } from '@Root/Hooks/useSafeApplicationGroupContext'
import { ModalStackNavigationProp } from '@Root/ModalStack'
import { SCREEN_MANAGE_SESSIONS, SCREEN_SETTINGS } from '@Root/Screens/screens'
import { SCREEN_INPUT_MODAL_WORKSPACE_NAME, SCREEN_MANAGE_SESSIONS, SCREEN_SETTINGS } from '@Root/Screens/screens'
import SNReactNative from '@standardnotes/react-native-utils'
import { ApplicationDescriptor, ApplicationGroupEvent, ButtonType, PrefKey } from '@standardnotes/snjs'
import { CustomActionSheetOption, useCustomActionSheet } from '@Style/CustomActionSheet'
@@ -241,70 +241,72 @@ export const OptionsSection = ({ title, encryptionAvailable }: Props) => {
[AddAnother, Open, Remove, SignOutAll, application.alertService],
)
const renameWorkspace = useCallback(
async (descriptor: ApplicationDescriptor, newName: string) => {
appGroup.renameDescriptor(descriptor, newName)
},
[appGroup],
)
const signOutWorkspace = useCallback(async () => {
const confirmed = await getWorkspaceActionConfirmation(Remove)
if (!confirmed) {
return
}
try {
await application.user.signOut() // TODO: do I need to call `SNReactNative.exitApp()` here as well?
} catch (error) {
console.error(error)
}
}, [Remove, application.user, getWorkspaceActionConfirmation])
const openWorkspace = useCallback(
async (descriptor: ApplicationDescriptor) => {
const confirmed = await getWorkspaceActionConfirmation(Open)
if (!confirmed) {
return
}
// await application.getInstallationService().customWipeData()
await appGroup.unloadCurrentAndActivateDescriptor(descriptor)
// TODO: find a way to check if there are memory leaks *without* the below call.
SNReactNative.exitApp()
},
[Open, appGroup, getWorkspaceActionConfirmation],
)
const getSingleWorkspaceItemOptions = useCallback(
(descriptor: ApplicationDescriptor) => {
const worskspaceItemOptions: CustomActionSheetOption[] = []
if (descriptor.primary) {
worskspaceItemOptions.push(
{
// text: 'Rename',
text: Rename,
callback: async () => {
console.log('implement rename...')
// await appGroup.unloadCurrentAndCreateNewDescriptor()
callback: () => {
navigation.navigate(SCREEN_INPUT_MODAL_WORKSPACE_NAME, {
descriptor,
renameWorkspace,
})
},
},
{
// text: 'Remove',
text: Remove,
destructive: true,
callback: async () => {
/*const confirmed = await application.alertService.confirm(
'This action will remove this workspace and its related data from this device. Your synced data will not be affected.',
undefined,
'Quit App',
ButtonType.Danger,
)*/
const confirmed = await getWorkspaceActionConfirmation(Remove)
if (!confirmed) {
return
}
console.log(
'implement remove and destroy the workspace (and probably call `SNReactNative.exitApp()` as well)...',
)
// application.user.signOut().catch(console.error)
try {
await application.user.signOut() // TODO: do I need to call `SNReactNative.exitApp()` here as well?
} catch (error) {
console.error(error)
}
// await appGroup.unloadCurrentAndCreateNewDescriptor()
},
callback: signOutWorkspace,
},
)
} else {
worskspaceItemOptions.push({
text: Open,
callback: async () => {
const confirmed = await getWorkspaceActionConfirmation(Open)
if (!confirmed) {
return
}
// await application.getInstallationService().customWipeData()
await appGroup.unloadCurrentAndActivateDescriptor(descriptor)
// TODO: find a way to check if there are memory leaks *without* the below call.
SNReactNative.exitApp()
},
callback: () => openWorkspace(descriptor),
})
}
return worskspaceItemOptions
},
[Open, Remove, Rename, appGroup, application, getWorkspaceActionConfirmation],
[Open, Remove, Rename, navigation, openWorkspace, renameWorkspace, signOutWorkspace],
)
const getActiveWorkspaceItems = useCallback(() => {
@@ -328,7 +330,18 @@ export const OptionsSection = ({ title, encryptionAvailable }: Props) => {
return descriptorItemOptions
}, [applicationDescriptors, getSingleWorkspaceItemOptions, showActionSheet])
/*const customSignOut = useCallback(async () => {
const addAnotherWorkspace = useCallback(async () => {
const confirmed = await getWorkspaceActionConfirmation(AddAnother)
if (!confirmed) {
return
}
// await application.getInstallationService().wipeData()
// await application.getInstallationService().customWipeData()
await appGroup.unloadCurrentAndCreateNewDescriptor()
SNReactNative.exitApp()
}, [AddAnother, appGroup, getWorkspaceActionConfirmation])
const signOutAllWorkspaces = useCallback(async () => {
try {
const confirmed = await getWorkspaceActionConfirmation(SignOutAll)
if (!confirmed) {
@@ -341,7 +354,7 @@ export const OptionsSection = ({ title, encryptionAvailable }: Props) => {
} catch (error) {
console.error(error)
}
}, [SignOutAll, appGroup, getWorkspaceActionConfirmation])*/
}, [SignOutAll, appGroup, getWorkspaceActionConfirmation])
const handleSwitchWorkspaceClick = useCallback(() => {
const activeDescriptors = getActiveWorkspaceItems()
@@ -349,37 +362,15 @@ export const OptionsSection = ({ title, encryptionAvailable }: Props) => {
...activeDescriptors,
{
text: AddAnother,
callback: async () => {
const confirmed = await getWorkspaceActionConfirmation(AddAnother)
if (!confirmed) {
return
}
// await application.getInstallationService().wipeData()
// await application.getInstallationService().customWipeData()
await appGroup.unloadCurrentAndCreateNewDescriptor()
SNReactNative.exitApp()
},
callback: addAnotherWorkspace,
},
{
text: SignOutAll,
callback: async () => {
try {
const confirmed = await getWorkspaceActionConfirmation(SignOutAll)
if (!confirmed) {
return
}
await appGroup.signOutAllWorkspaces()
// TODO: do we need `exitApp` here as well?
SNReactNative.exitApp()
} catch (error) {
console.error(error)
}
},
callback: signOutAllWorkspaces,
},
]
showActionSheet({ title: '', options })
}, [AddAnother, SignOutAll, appGroup, getActiveWorkspaceItems, getWorkspaceActionConfirmation, showActionSheet])
}, [AddAnother, SignOutAll, addAnotherWorkspace, getActiveWorkspaceItems, showActionSheet, signOutAllWorkspaces])
const showDataBackupAlert = useCallback(() => {
void application.alertService.alert(

View File

@@ -8,6 +8,7 @@ export const SCREEN_INPUT_MODAL_FILE_NAME = 'InputModalFileName'
export const SCREEN_NOTE_HISTORY = 'NoteSessionHistory' as const
export const SCREEN_NOTE_HISTORY_PREVIEW = 'NoteSessionHistoryPreview' as const
export const SCREEN_UPLOADED_FILES_LIST = 'UploadedFilesList' as const
export const SCREEN_INPUT_MODAL_WORKSPACE_NAME = 'InputModalWorkspaceName' as const
export const SCREEN_SETTINGS = 'Settings'
export const SCREEN_MANAGE_SESSIONS = 'ManageSessions' as const