feat: mobile app package (#1075)

This commit is contained in:
Mo
2022-06-09 09:45:15 -05:00
committed by GitHub
parent 58b63898de
commit 8248a38280
336 changed files with 47696 additions and 22563 deletions

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_FILE_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_FILE_NAME>
export const FileInputModal: FC<Props> = props => {
const { file, renameFile } = props.route.params
const themeService = useContext(ThemeServiceContext)
const application = useSafeApplicationContext()
const fileNameInputRef = useRef<TextInput>(null)
const [fileName, setFileName] = useState(file.name)
const onSubmit = async () => {
const trimmedFileName = fileName.trim()
if (trimmedFileName === '') {
setFileName(file.name)
await application?.alertService.alert('File name cannot be empty')
fileNameInputRef.current?.focus()
return
}
await renameFile(file, trimmedFileName)
void application.sync.sync()
props.navigation.goBack()
}
useEffect(() => {
fileNameInputRef.current?.focus()
}, [])
return (
<Container>
<TableSection>
<SectionedTableCell textInputCell first={true}>
<Input
ref={fileNameInputRef as any}
placeholder={'File name'}
onChangeText={setFileName}
value={fileName}
autoCorrect={false}
autoCapitalize={'none'}
keyboardAppearance={themeService?.keyboardColorForActiveTheme()}
underlineColorAndroid={'transparent'}
onSubmitEditing={onSubmit}
/>
</SectionedTableCell>
<ButtonCell maxHeight={45} disabled={fileName.length === 0} title={'Save'} bold onPress={onSubmit} />
</TableSection>
</Container>
)
}

View File

@@ -0,0 +1,15 @@
import styled from 'styled-components/native'
export const Container = styled.View`
flex: 1;
background-color: ${({ theme }) => theme.stylekitBackgroundColor};
`
export const Input = styled.TextInput.attrs(({ theme }) => ({
placeholderTextColor: theme.stylekitNeutralColor,
}))`
font-size: ${({ theme }) => theme.mainTextFontSize}px;
padding: 0px;
color: ${({ theme }) => theme.stylekitForegroundColor};
height: 100%;
`

View File

@@ -0,0 +1,134 @@
import { PasscodeKeyboardType, UnlockTiming } from '@Lib/ApplicationState'
import { ApplicationContext } from '@Root/ApplicationContext'
import { ButtonCell } from '@Root/Components/ButtonCell'
import { Option, SectionedOptionsTableCell } from '@Root/Components/SectionedOptionsTableCell'
import { SectionedTableCell } from '@Root/Components/SectionedTableCell'
import { TableSection } from '@Root/Components/TableSection'
import { ModalStackNavigationProp } from '@Root/ModalStack'
import { SCREEN_INPUT_MODAL_PASSCODE } from '@Root/Screens/screens'
import { ThemeServiceContext } from '@Style/ThemeService'
import React, { useContext, useMemo, useRef, useState } from 'react'
import { Keyboard, KeyboardType, Platform, TextInput } from 'react-native'
import { Container, Input } from './InputModal.styled'
type Props = ModalStackNavigationProp<typeof SCREEN_INPUT_MODAL_PASSCODE>
export const PasscodeInputModal = (props: Props) => {
// Context
const application = useContext(ApplicationContext)
const themeService = useContext(ThemeServiceContext)
// State
const [settingPassocode, setSettingPassocode] = useState(false)
const [text, setText] = useState('')
const [confirmText, setConfirmText] = useState('')
const [keyboardType, setKeyboardType] = useState<KeyboardType>('default')
// Refs
const textRef = useRef<TextInput>(null)
const confirmTextRef = useRef<TextInput>(null)
const onTextSubmit = () => {
if (!confirmText) {
confirmTextRef.current?.focus()
} else {
Keyboard.dismiss()
}
}
const onSubmit = async () => {
if (settingPassocode) {
return
}
setSettingPassocode(true)
if (text !== confirmText) {
void application?.alertService?.alert(
'The two values you entered do not match. Please try again.',
'Invalid Confirmation',
'OK',
)
setSettingPassocode(false)
} else {
await application?.addPasscode(text)
await application?.getAppState().setPasscodeKeyboardType(keyboardType as PasscodeKeyboardType)
await application?.getAppState().setPasscodeTiming(UnlockTiming.OnQuit)
setSettingPassocode(false)
props.navigation.goBack()
}
}
const keyboardOptions: Option[] = useMemo(
() => [
{
title: 'General',
key: 'default' as PasscodeKeyboardType,
selected: keyboardType === 'default',
},
{
title: 'Numeric',
key: 'numeric' as PasscodeKeyboardType,
selected: keyboardType === 'numeric',
},
],
[keyboardType],
)
const onKeyboardTypeSelect = (option: Option) => {
setKeyboardType(option.key as KeyboardType)
}
return (
<Container>
<TableSection>
<SectionedTableCell textInputCell first={true}>
<Input
ref={textRef as any}
key={Platform.OS === 'android' ? keyboardType + '1' : undefined}
placeholder="Enter a passcode"
onChangeText={setText}
value={text}
secureTextEntry
autoCorrect={false}
autoCapitalize={'none'}
keyboardType={keyboardType}
keyboardAppearance={themeService?.keyboardColorForActiveTheme()}
autoFocus={true}
underlineColorAndroid={'transparent'}
onSubmitEditing={onTextSubmit}
/>
</SectionedTableCell>
<SectionedTableCell textInputCell first={false}>
<Input
ref={confirmTextRef as any}
key={Platform.OS === 'android' ? keyboardType + '2' : undefined}
placeholder="Confirm passcode"
onChangeText={setConfirmText}
value={confirmText}
secureTextEntry
autoCorrect={false}
autoCapitalize={'none'}
keyboardType={keyboardType}
keyboardAppearance={themeService?.keyboardColorForActiveTheme()}
underlineColorAndroid={'transparent'}
onSubmitEditing={onSubmit}
/>
</SectionedTableCell>
<SectionedOptionsTableCell
title={'Keyboard Type'}
leftAligned
options={keyboardOptions}
onPress={onKeyboardTypeSelect}
/>
<ButtonCell
maxHeight={45}
disabled={settingPassocode || text.length === 0}
title={'Save'}
bold
onPress={onSubmit}
/>
</TableSection>
</Container>
)
}

View File

@@ -0,0 +1,92 @@
import { useFocusEffect } from '@react-navigation/native'
import { ApplicationContext } from '@Root/ApplicationContext'
import { ButtonCell } from '@Root/Components/ButtonCell'
import { SectionedTableCell } from '@Root/Components/SectionedTableCell'
import { TableSection } from '@Root/Components/TableSection'
import { ModalStackNavigationProp } from '@Root/ModalStack'
import { SCREEN_INPUT_MODAL_TAG } from '@Root/Screens/screens'
import { SNNote, SNTag, TagMutator } from '@standardnotes/snjs'
import { ThemeServiceContext } from '@Style/ThemeService'
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react'
import { TextInput } from 'react-native'
import { Container, Input } from './InputModal.styled'
type Props = ModalStackNavigationProp<typeof SCREEN_INPUT_MODAL_TAG>
export const TagInputModal = (props: Props) => {
// Context
const application = useContext(ApplicationContext)
const themeService = useContext(ThemeServiceContext)
// State
const [text, setText] = useState('')
// Refs
const textRef = useRef<TextInput>(null)
useEffect(() => {
if (props.route.params.tagUuid) {
const tag = application?.items.findItem(props.route.params.tagUuid) as SNTag
setText(tag.title)
}
}, [application, props.route.params.tagUuid])
useFocusEffect(
useCallback(() => {
setTimeout(() => {
textRef.current?.focus()
}, 1)
}, []),
)
const onSubmit = useCallback(async () => {
if (props.route.params.tagUuid) {
const tag = application?.items.findItem(props.route.params.tagUuid) as SNTag
await application?.mutator.changeItem(tag, mutator => {
const tagMutator = mutator as TagMutator
tagMutator.title = text
if (props.route.params.noteUuid) {
const note = application.items.findItem(props.route.params.noteUuid)
if (note) {
tagMutator.addNote(note as SNNote)
}
}
})
} else {
const tag = await application!.mutator.findOrCreateTag(text)
if (props.route.params.noteUuid) {
await application?.mutator.changeItem(tag, mutator => {
const tagMutator = mutator as TagMutator
const note = application.items.findItem(props.route.params.noteUuid!)
if (note) {
tagMutator.addNote(note as SNNote)
}
})
}
}
void application?.sync.sync()
props.navigation.goBack()
}, [application, props.navigation, props.route.params.noteUuid, props.route.params.tagUuid, text])
return (
<Container>
<TableSection>
<SectionedTableCell textInputCell first={true}>
<Input
ref={textRef as any}
placeholder={props.route.params.tagUuid ? 'Tag name' : 'New tag name'}
onChangeText={setText}
value={text}
autoCorrect={false}
autoCapitalize={'none'}
keyboardAppearance={themeService?.keyboardColorForActiveTheme()}
underlineColorAndroid={'transparent'}
onSubmitEditing={onSubmit}
/>
</SectionedTableCell>
<ButtonCell maxHeight={45} disabled={text.length === 0} title={'Save'} bold onPress={onSubmit} />
</TableSection>
</Container>
)
}