mirror of
https://github.com/standardnotes/mobile.git
synced 2026-05-18 19:44:31 -04:00
chore: prettier
This commit is contained in:
@@ -41,9 +41,7 @@ export type AppStackNavigationProp<T extends keyof AppStackNavigatorParamList> =
|
||||
|
||||
const AppStack = createStackNavigator<AppStackNavigatorParamList>()
|
||||
|
||||
export const AppStackComponent = (
|
||||
props: ModalStackNavigationProp<'AppStack'> & { env: TEnvironment }
|
||||
) => {
|
||||
export const AppStackComponent = (props: ModalStackNavigationProp<'AppStack'> & { env: TEnvironment }) => {
|
||||
// Context
|
||||
const application = useContext(ApplicationContext)
|
||||
const theme = useContext(ThemeContext)
|
||||
@@ -52,9 +50,7 @@ export const AppStackComponent = (
|
||||
|
||||
// State
|
||||
const [dimensions, setDimensions] = useState(() => Dimensions.get('window'))
|
||||
const [isInTabletMode, setIsInTabletMode] = useState(
|
||||
() => application?.getAppState().isInTabletMode
|
||||
)
|
||||
const [isInTabletMode, setIsInTabletMode] = useState(() => application?.getAppState().isInTabletMode)
|
||||
const [notesStatus, setNotesStatus] = useState<ScreenStatus>()
|
||||
const [composeStatus, setComposeStatus] = useState<ScreenStatus>()
|
||||
const [noteDrawerOpen, setNoteDrawerOpen] = useState(false)
|
||||
@@ -96,18 +92,16 @@ export const AppStackComponent = (
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const remoteTabletModeSubscription = application
|
||||
?.getAppState()
|
||||
.addStateEventObserver((event, data) => {
|
||||
if (event === AppStateEventType.TabletModeChange) {
|
||||
const eventData = data as TabletModeChangeData
|
||||
if (eventData.new_isInTabletMode && !eventData.old_isInTabletMode) {
|
||||
setIsInTabletMode(true)
|
||||
} else if (!eventData.new_isInTabletMode && eventData.old_isInTabletMode) {
|
||||
setIsInTabletMode(false)
|
||||
}
|
||||
const remoteTabletModeSubscription = application?.getAppState().addStateEventObserver((event, data) => {
|
||||
if (event === AppStateEventType.TabletModeChange) {
|
||||
const eventData = data as TabletModeChangeData
|
||||
if (eventData.new_isInTabletMode && !eventData.old_isInTabletMode) {
|
||||
setIsInTabletMode(true)
|
||||
} else if (!eventData.new_isInTabletMode && eventData.old_isInTabletMode) {
|
||||
setIsInTabletMode(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return remoteTabletModeSubscription
|
||||
}, [application])
|
||||
@@ -141,13 +135,7 @@ export const AppStackComponent = (
|
||||
drawerType="slide"
|
||||
drawerLockMode={hasEditor ? 'unlocked' : 'locked-closed'}
|
||||
renderNavigationView={() =>
|
||||
hasEditor && (
|
||||
<NoteSideMenu
|
||||
drawerOpen={noteDrawerOpen}
|
||||
drawerRef={noteDrawerRef.current}
|
||||
env={props.env}
|
||||
/>
|
||||
)
|
||||
hasEditor && <NoteSideMenu drawerOpen={noteDrawerOpen} drawerRef={noteDrawerRef.current} env={props.env} />
|
||||
}
|
||||
>
|
||||
<AppStack.Navigator
|
||||
@@ -170,17 +158,9 @@ export const AppStackComponent = (
|
||||
const screenStatus = isInTabletMode ? composeStatus || notesStatus : notesStatus
|
||||
|
||||
const title = route.params?.title ?? (children || '')
|
||||
const subtitle = [screenStatus?.status, route.params?.subTitle]
|
||||
.filter(x => !!x)
|
||||
.join(' • ')
|
||||
const subtitle = [screenStatus?.status, route.params?.subTitle].filter(x => !!x).join(' • ')
|
||||
|
||||
return (
|
||||
<HeaderTitleView
|
||||
title={title}
|
||||
subtitle={subtitle}
|
||||
subtitleColor={screenStatus?.color}
|
||||
/>
|
||||
)
|
||||
return <HeaderTitleView title={title} subtitle={subtitle} subtitleColor={screenStatus?.color} />
|
||||
},
|
||||
headerLeft: () => (
|
||||
<HeaderButtons HeaderButtonComponent={IoniconsHeaderButton}>
|
||||
|
||||
@@ -35,10 +35,7 @@ const ButtonLabel = styled.Text<ButtonLabelProps>`
|
||||
text-align: ${props => (props.leftAligned ? 'left' : 'center')};
|
||||
text-align-vertical: center;
|
||||
color: ${props => {
|
||||
let color =
|
||||
Platform.OS === 'android'
|
||||
? props.theme.stylekitForegroundColor
|
||||
: props.theme.stylekitInfoColor
|
||||
let color = Platform.OS === 'android' ? props.theme.stylekitForegroundColor : props.theme.stylekitInfoColor
|
||||
if (props.disabled) {
|
||||
color = 'gray'
|
||||
} else if (props.important) {
|
||||
|
||||
@@ -26,9 +26,7 @@ const TitleContainer = styled.View``
|
||||
const Title = styled.Text<Pick<Props, 'tinted'>>`
|
||||
background-color: ${props => props.theme.stylekitBackgroundColor};
|
||||
font-size: ${props => {
|
||||
return Platform.OS === 'android'
|
||||
? props.theme.mainTextFontSize - 2
|
||||
: props.theme.mainTextFontSize - 4
|
||||
return Platform.OS === 'android' ? props.theme.mainTextFontSize - 2 : props.theme.mainTextFontSize - 4
|
||||
}}px;
|
||||
padding-left: ${props => props.theme.paddingLeft}px;
|
||||
color: ${props => {
|
||||
@@ -36,9 +34,7 @@ const Title = styled.Text<Pick<Props, 'tinted'>>`
|
||||
return props.theme.stylekitInfoColor
|
||||
}
|
||||
|
||||
return Platform.OS === 'android'
|
||||
? props.theme.stylekitInfoColor
|
||||
: props.theme.stylekitNeutralColor
|
||||
return Platform.OS === 'android' ? props.theme.stylekitInfoColor : props.theme.stylekitNeutralColor
|
||||
}};
|
||||
font-weight: ${Platform.OS === 'android' ? 'bold' : 'normal'};
|
||||
`
|
||||
|
||||
@@ -88,11 +88,7 @@ export const SectionedAccessoryTableCell: React.FC<Props> = props => {
|
||||
}
|
||||
|
||||
const checkmarkName = Platform.OS === 'android' ? 'md-checkbox' : 'ios-checkmark-circle'
|
||||
const iconName = props.iconName
|
||||
? props.iconName
|
||||
: props.selected && props.selected()
|
||||
? checkmarkName
|
||||
: null
|
||||
const iconName = props.iconName ? props.iconName : props.selected && props.selected() ? checkmarkName : null
|
||||
|
||||
const left = props.leftAlignIcon
|
||||
let iconSize = left ? 25 : 30
|
||||
@@ -129,15 +125,8 @@ export const SectionedAccessoryTableCell: React.FC<Props> = props => {
|
||||
)
|
||||
|
||||
return (
|
||||
<TouchableContainer
|
||||
first={props.first}
|
||||
last={props.last}
|
||||
onPress={onPress}
|
||||
onLongPress={onLongPress}
|
||||
>
|
||||
<ContentContainer>
|
||||
{props.leftAlignIcon ? [icon, textWrapper] : [textWrapper, icon]}
|
||||
</ContentContainer>
|
||||
<TouchableContainer first={props.first} last={props.last} onPress={onPress} onLongPress={onLongPress}>
|
||||
<ContentContainer>{props.leftAlignIcon ? [icon, textWrapper] : [textWrapper, icon]}</ContentContainer>
|
||||
</TouchableContainer>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,9 +15,7 @@ import { ThemeContext } from 'styled-components'
|
||||
import { HeaderTitleParams } from './App'
|
||||
|
||||
type HistoryStackNavigatorParamList = {
|
||||
[SCREEN_NOTE_HISTORY]:
|
||||
| (HeaderTitleParams & { noteUuid: string })
|
||||
| (undefined & { noteUuid: string })
|
||||
[SCREEN_NOTE_HISTORY]: (HeaderTitleParams & { noteUuid: string }) | (undefined & { noteUuid: string })
|
||||
[SCREEN_NOTE_HISTORY_PREVIEW]: HeaderTitleParams & {
|
||||
revision: NoteHistoryEntry
|
||||
originalNoteUuid: string
|
||||
@@ -54,9 +52,7 @@ export const HistoryStack = () => {
|
||||
testID="headerButton"
|
||||
disabled={disabled}
|
||||
title={Platform.OS === 'ios' ? 'Done' : ''}
|
||||
iconName={
|
||||
Platform.OS === 'ios' ? undefined : ThemeService.nameForIcon(ICON_CHECKMARK)
|
||||
}
|
||||
iconName={Platform.OS === 'ios' ? undefined : ThemeService.nameForIcon(ICON_CHECKMARK)}
|
||||
onPress={onPress}
|
||||
/>
|
||||
</HeaderButtons>
|
||||
|
||||
@@ -4,10 +4,7 @@ import { Alert, AlertButton } from 'react-native'
|
||||
import { goBack, navigate } from './NavigationService'
|
||||
|
||||
export class AlertService implements SNAlertService {
|
||||
blockingDialog(
|
||||
text: string,
|
||||
title?: string
|
||||
): DismissBlockingDialog | Promise<DismissBlockingDialog> {
|
||||
blockingDialog(text: string, title?: string): DismissBlockingDialog | Promise<DismissBlockingDialog> {
|
||||
navigate(MODAL_BLOCKING_ALERT, { text, title })
|
||||
|
||||
return goBack
|
||||
|
||||
@@ -21,14 +21,8 @@ export class ApplicationGroup extends SNApplicationGroup {
|
||||
})
|
||||
}
|
||||
|
||||
private createApplication = (
|
||||
descriptor: ApplicationDescriptor,
|
||||
deviceInterface: DeviceInterface
|
||||
) => {
|
||||
const application = new MobileApplication(
|
||||
deviceInterface as MobileDeviceInterface,
|
||||
descriptor.identifier
|
||||
)
|
||||
private createApplication = (descriptor: ApplicationDescriptor, deviceInterface: DeviceInterface) => {
|
||||
const application = new MobileApplication(deviceInterface as MobileDeviceInterface, descriptor.identifier)
|
||||
const internalEventBus = new InternalEventBus()
|
||||
const applicationState = new ApplicationState(application)
|
||||
const reviewService = new ReviewService(application, internalEventBus)
|
||||
|
||||
@@ -80,10 +80,7 @@ export enum MobileStorageKey {
|
||||
PasscodeKeyboardTypeKey = 'passcodeKeyboardType',
|
||||
}
|
||||
|
||||
type EventObserverCallback = (
|
||||
event: AppStateEventType,
|
||||
data?: TabletModeChangeData
|
||||
) => void | Promise<void>
|
||||
type EventObserverCallback = (event: AppStateEventType, data?: TabletModeChangeData) => void | Promise<void>
|
||||
type ObserverCallback = (event: AppStateType, data?: any) => void | Promise<void>
|
||||
type LockStateObserverCallback = (event: LockStateType) => void | Promise<void>
|
||||
|
||||
@@ -147,10 +144,7 @@ export class ApplicationState extends ApplicationService {
|
||||
if (this.selectedTagRestored) {
|
||||
return
|
||||
}
|
||||
const savedTagUuid: string | undefined = this.prefService.getValue(
|
||||
PrefKey.SelectedTagUuid,
|
||||
undefined
|
||||
)
|
||||
const savedTagUuid: string | undefined = this.prefService.getValue(PrefKey.SelectedTagUuid, undefined)
|
||||
|
||||
if (isNullOrUndefined(savedTagUuid)) {
|
||||
this.selectedTagRestored = true
|
||||
@@ -275,11 +269,7 @@ export class ApplicationState extends ApplicationService {
|
||||
|
||||
const defaultEditor = this.application.componentManager.getDefaultEditor()
|
||||
if (defaultEditor) {
|
||||
await associateComponentWithNote(
|
||||
this.application,
|
||||
defaultEditor,
|
||||
this.getActiveNoteController().note!
|
||||
)
|
||||
await associateComponentWithNote(this.application, defaultEditor, this.getActiveNoteController().note!)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,10 +346,7 @@ export class ApplicationState extends ApplicationService {
|
||||
this.removeItemChangesListener = this.application.streamItems<SNNote | SNTag>(
|
||||
[ContentType.Note, ContentType.Tag],
|
||||
async ({ changed, inserted, removed, source }) => {
|
||||
if (
|
||||
source === PayloadEmitSource.PreSyncSave ||
|
||||
source === PayloadEmitSource.RemoteRetrieved
|
||||
) {
|
||||
if (source === PayloadEmitSource.PreSyncSave || source === PayloadEmitSource.RemoteRetrieved) {
|
||||
const removedNotes = removed.filter(i => i.content_type === ContentType.Note)
|
||||
for (const removedNote of removedNotes) {
|
||||
const editor = this.editorForNote(removedNote.uuid)
|
||||
@@ -368,17 +355,13 @@ export class ApplicationState extends ApplicationService {
|
||||
}
|
||||
}
|
||||
|
||||
const notes = [...changed, ...inserted].filter(
|
||||
candidate => candidate.content_type === ContentType.Note
|
||||
)
|
||||
const notes = [...changed, ...inserted].filter(candidate => candidate.content_type === ContentType.Note)
|
||||
|
||||
const isBrowswingTrashedNotes =
|
||||
this.selectedTag instanceof SmartView &&
|
||||
this.selectedTag.uuid === SystemViewId.TrashedNotes
|
||||
this.selectedTag instanceof SmartView && this.selectedTag.uuid === SystemViewId.TrashedNotes
|
||||
|
||||
const isBrowsingArchivedNotes =
|
||||
this.selectedTag instanceof SmartView &&
|
||||
this.selectedTag.uuid === SystemViewId.ArchivedNotes
|
||||
this.selectedTag instanceof SmartView && this.selectedTag.uuid === SystemViewId.ArchivedNotes
|
||||
|
||||
for (const note of notes) {
|
||||
const editor = this.editorForNote(note.uuid)
|
||||
@@ -395,9 +378,7 @@ export class ApplicationState extends ApplicationService {
|
||||
}
|
||||
|
||||
if (this.selectedTag) {
|
||||
const matchingTag = [...changed, ...inserted].find(
|
||||
candidate => candidate.uuid === this.selectedTag!.uuid
|
||||
)
|
||||
const matchingTag = [...changed, ...inserted].find(candidate => candidate.uuid === this.selectedTag!.uuid)
|
||||
if (matchingTag) {
|
||||
this.selectedTag = matchingTag as SNTag
|
||||
}
|
||||
@@ -441,9 +422,7 @@ export class ApplicationState extends ApplicationService {
|
||||
this.selectedTag = tag
|
||||
|
||||
if (saveSelection) {
|
||||
void this.application
|
||||
.getLocalPreferences()
|
||||
.setUserPrefValue(PrefKey.SelectedTagUuid, tag.uuid)
|
||||
void this.application.getLocalPreferences().setUserPrefValue(PrefKey.SelectedTagUuid, tag.uuid)
|
||||
}
|
||||
|
||||
this.notifyOfStateChange(AppStateType.TagChanged, {
|
||||
@@ -538,11 +517,7 @@ export class ApplicationState extends ApplicationService {
|
||||
const hasPasscode = this.application.hasPasscode()
|
||||
if (hasPasscode && this.passcodeTiming === UnlockTiming.Immediately) {
|
||||
await this.application.lock()
|
||||
} else if (
|
||||
hasBiometrics &&
|
||||
this.biometricsTiming === UnlockTiming.Immediately &&
|
||||
!this.locked
|
||||
) {
|
||||
} else if (hasBiometrics && this.biometricsTiming === UnlockTiming.Immediately && !this.locked) {
|
||||
const challenge = new Challenge(
|
||||
[new ChallengePrompt(ChallengeValidation.Biometric)],
|
||||
ChallengeReason.ApplicationUnlock,
|
||||
@@ -574,8 +549,7 @@ export class ApplicationState extends ApplicationService {
|
||||
// from inactive to active, which doesn't really happen unless you, say, swipe
|
||||
// notification center in iOS down then back up. We don't want to lock on this state change.
|
||||
const isResuming = nextAppState === 'active'
|
||||
const isResumingFromBackground =
|
||||
isResuming && this.mostRecentState === AppStateType.EnteringBackground
|
||||
const isResumingFromBackground = isResuming && this.mostRecentState === AppStateType.EnteringBackground
|
||||
const isEnteringBackground = nextAppState === 'background'
|
||||
const isLosingFocus = nextAppState === 'inactive'
|
||||
|
||||
@@ -624,51 +598,36 @@ export class ApplicationState extends ApplicationService {
|
||||
}
|
||||
|
||||
private async getScreenshotPrivacyEnabled(): Promise<boolean | undefined> {
|
||||
return this.application.getValue(
|
||||
StorageKey.MobileScreenshotPrivacyEnabled,
|
||||
StorageValueModes.Default
|
||||
) as Promise<boolean | undefined>
|
||||
return this.application.getValue(StorageKey.MobileScreenshotPrivacyEnabled, StorageValueModes.Default) as Promise<
|
||||
boolean | undefined
|
||||
>
|
||||
}
|
||||
|
||||
private async getPasscodeTiming(): Promise<UnlockTiming | undefined> {
|
||||
return this.application.getValue(
|
||||
StorageKey.MobilePasscodeTiming,
|
||||
StorageValueModes.Nonwrapped
|
||||
) as Promise<UnlockTiming | undefined>
|
||||
return this.application.getValue(StorageKey.MobilePasscodeTiming, StorageValueModes.Nonwrapped) as Promise<
|
||||
UnlockTiming | undefined
|
||||
>
|
||||
}
|
||||
|
||||
private async getBiometricsTiming(): Promise<UnlockTiming | undefined> {
|
||||
return this.application.getValue(
|
||||
StorageKey.MobileBiometricsTiming,
|
||||
StorageValueModes.Nonwrapped
|
||||
) as Promise<UnlockTiming | undefined>
|
||||
return this.application.getValue(StorageKey.MobileBiometricsTiming, StorageValueModes.Nonwrapped) as Promise<
|
||||
UnlockTiming | undefined
|
||||
>
|
||||
}
|
||||
|
||||
public async setScreenshotPrivacyEnabled(enabled: boolean) {
|
||||
await this.application.setValue(
|
||||
StorageKey.MobileScreenshotPrivacyEnabled,
|
||||
enabled,
|
||||
StorageValueModes.Default
|
||||
)
|
||||
await this.application.setValue(StorageKey.MobileScreenshotPrivacyEnabled, enabled, StorageValueModes.Default)
|
||||
this.screenshotPrivacyEnabled = enabled
|
||||
void this.setAndroidScreenshotPrivacy(enabled)
|
||||
}
|
||||
|
||||
public async setPasscodeTiming(timing: UnlockTiming) {
|
||||
await this.application.setValue(
|
||||
StorageKey.MobilePasscodeTiming,
|
||||
timing,
|
||||
StorageValueModes.Nonwrapped
|
||||
)
|
||||
await this.application.setValue(StorageKey.MobilePasscodeTiming, timing, StorageValueModes.Nonwrapped)
|
||||
this.passcodeTiming = timing
|
||||
}
|
||||
|
||||
public async setBiometricsTiming(timing: UnlockTiming) {
|
||||
await this.application.setValue(
|
||||
StorageKey.MobileBiometricsTiming,
|
||||
timing,
|
||||
StorageValueModes.Nonwrapped
|
||||
)
|
||||
await this.application.setValue(StorageKey.MobileBiometricsTiming, timing, StorageValueModes.Nonwrapped)
|
||||
this.biometricsTiming = timing
|
||||
}
|
||||
|
||||
@@ -680,11 +639,7 @@ export class ApplicationState extends ApplicationService {
|
||||
}
|
||||
|
||||
public async setPasscodeKeyboardType(type: PasscodeKeyboardType) {
|
||||
await this.application.setValue(
|
||||
MobileStorageKey.PasscodeKeyboardTypeKey,
|
||||
type,
|
||||
StorageValueModes.Nonwrapped
|
||||
)
|
||||
await this.application.setValue(MobileStorageKey.PasscodeKeyboardTypeKey, type, StorageValueModes.Nonwrapped)
|
||||
}
|
||||
|
||||
public onDrawerOpen() {
|
||||
@@ -695,10 +650,7 @@ export class ApplicationState extends ApplicationService {
|
||||
Allows other parts of the code to perform external actions without triggering state change notifications.
|
||||
This is useful on Android when you present a share sheet and dont want immediate authentication to appear.
|
||||
*/
|
||||
async performActionWithoutStateChangeImpact(
|
||||
block: () => void | Promise<void>,
|
||||
notAwaited?: boolean
|
||||
) {
|
||||
async performActionWithoutStateChangeImpact(block: () => void | Promise<void>, notAwaited?: boolean) {
|
||||
this.ignoreStateChanges = true
|
||||
if (notAwaited) {
|
||||
void block()
|
||||
|
||||
@@ -62,20 +62,18 @@ export class BackupsService extends ApplicationService {
|
||||
|
||||
private async exportIOS(filename: string, data: string) {
|
||||
return new Promise<boolean>(resolve => {
|
||||
void (this.application! as MobileApplication)
|
||||
.getAppState()
|
||||
.performActionWithoutStateChangeImpact(async () => {
|
||||
Share.share({
|
||||
title: filename,
|
||||
message: data,
|
||||
})
|
||||
.then(result => {
|
||||
resolve(result.action !== Share.dismissedAction)
|
||||
})
|
||||
.catch(() => {
|
||||
resolve(false)
|
||||
})
|
||||
void (this.application! as MobileApplication).getAppState().performActionWithoutStateChangeImpact(async () => {
|
||||
Share.share({
|
||||
title: filename,
|
||||
message: data,
|
||||
})
|
||||
.then(result => {
|
||||
resolve(result.action !== Share.dismissedAction)
|
||||
})
|
||||
.catch(() => {
|
||||
resolve(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -152,9 +150,7 @@ export class BackupsService extends ApplicationService {
|
||||
}
|
||||
|
||||
private async requestStoragePermissionsAndroid() {
|
||||
const writeStorageGranted = await PermissionsAndroid.request(
|
||||
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE
|
||||
)
|
||||
const writeStorageGranted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE)
|
||||
return writeStorageGranted === PermissionsAndroid.RESULTS.GRANTED
|
||||
}
|
||||
|
||||
|
||||
@@ -108,15 +108,12 @@ export class ComponentManager extends SNComponentManager {
|
||||
this.log('Existing package version', existingVersion)
|
||||
this.log('Latest package version', version)
|
||||
|
||||
const shouldDownload =
|
||||
!existingPackageJson || isRightVersionGreaterThanLeft(existingVersion, version!)
|
||||
const shouldDownload = !existingPackageJson || isRightVersionGreaterThanLeft(existingVersion, version!)
|
||||
|
||||
return shouldDownload
|
||||
}
|
||||
|
||||
public async downloadComponentOffline(
|
||||
component: SNComponent
|
||||
): Promise<ComponentLoadingError | undefined> {
|
||||
public async downloadComponentOffline(component: SNComponent): Promise<ComponentLoadingError | undefined> {
|
||||
const identifier = component.identifier
|
||||
const nativeFeature = this.nativeFeatureForIdentifier(identifier)
|
||||
const downloadUrl = nativeFeature?.download_url || component.package_info?.download_url
|
||||
@@ -170,9 +167,7 @@ export class ComponentManager extends SNComponentManager {
|
||||
return false
|
||||
}
|
||||
if (checksum !== desiredChecksum) {
|
||||
this.log(
|
||||
`Checksums don't match for ${featureIdentifier}; ${checksum} != ${desiredChecksum}; aborting install`
|
||||
)
|
||||
this.log(`Checksums don't match for ${featureIdentifier}; ${checksum} != ${desiredChecksum}; aborting install`)
|
||||
return false
|
||||
}
|
||||
this.log(`Checksum ${checksum} matches ${desiredChecksum} for ${featureIdentifier}`)
|
||||
@@ -191,14 +186,7 @@ export class ComponentManager extends SNComponentManager {
|
||||
await RNFS.unlink(tmpLocation)
|
||||
}
|
||||
|
||||
this.log(
|
||||
'Downloading component',
|
||||
identifier,
|
||||
'from url',
|
||||
downloadUrl,
|
||||
'to location',
|
||||
tmpLocation
|
||||
)
|
||||
this.log('Downloading component', identifier, 'from url', downloadUrl, 'to location', tmpLocation)
|
||||
|
||||
const result = await RNFS.downloadFile({
|
||||
fromUrl: downloadUrl,
|
||||
@@ -338,11 +326,7 @@ export class ComponentManager extends SNComponentManager {
|
||||
}
|
||||
}
|
||||
|
||||
export async function associateComponentWithNote(
|
||||
application: SNApplication,
|
||||
component: SNComponent,
|
||||
note: SNNote
|
||||
) {
|
||||
export async function associateComponentWithNote(application: SNApplication, component: SNComponent, note: SNNote) {
|
||||
return application.mutator.changeItem<ComponentMutator>(component, mutator => {
|
||||
mutator.removeDisassociatedItemId(note.uuid)
|
||||
mutator.associateWithItem(note.uuid)
|
||||
|
||||
@@ -4,14 +4,9 @@ import { ModalStackNavigatorParamList } from '@Root/ModalStack'
|
||||
import * as React from 'react'
|
||||
|
||||
export const navigationRef =
|
||||
React.createRef<
|
||||
NavigationContainerRef<AppStackNavigatorParamList & ModalStackNavigatorParamList>
|
||||
>()
|
||||
React.createRef<NavigationContainerRef<AppStackNavigatorParamList & ModalStackNavigatorParamList>>()
|
||||
|
||||
export function navigate(
|
||||
name: keyof AppStackNavigatorParamList | keyof ModalStackNavigatorParamList,
|
||||
params?: any
|
||||
) {
|
||||
export function navigate(name: keyof AppStackNavigatorParamList | keyof ModalStackNavigatorParamList, params?: any) {
|
||||
navigationRef.current?.navigate(name, params)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,12 +24,7 @@ export class SNReactNativeCrypto implements SNPureCrypto {
|
||||
return
|
||||
}
|
||||
|
||||
pbkdf2(
|
||||
password: Utf8String,
|
||||
salt: Utf8String,
|
||||
iterations: number,
|
||||
length: number
|
||||
): Promise<string | null> {
|
||||
pbkdf2(password: Utf8String, salt: Utf8String, iterations: number, length: number): Promise<string | null> {
|
||||
return Aes.pbkdf2(password, salt, iterations, length)
|
||||
}
|
||||
|
||||
@@ -43,11 +38,7 @@ export class SNReactNativeCrypto implements SNPureCrypto {
|
||||
return Aes.encrypt(plaintext, key, iv)
|
||||
}
|
||||
|
||||
async aes256CbcDecrypt(
|
||||
ciphertext: Base64String,
|
||||
iv: HexString,
|
||||
key: HexString
|
||||
): Promise<Utf8String | null> {
|
||||
async aes256CbcDecrypt(ciphertext: Base64String, iv: HexString, key: HexString): Promise<Utf8String | null> {
|
||||
try {
|
||||
return Aes.decrypt(ciphertext, key, iv)
|
||||
} catch (e) {
|
||||
@@ -71,29 +62,11 @@ export class SNReactNativeCrypto implements SNPureCrypto {
|
||||
return Aes.sha1(text)
|
||||
}
|
||||
|
||||
public argon2(
|
||||
password: Utf8String,
|
||||
salt: HexString,
|
||||
iterations: number,
|
||||
bytes: number,
|
||||
length: number
|
||||
): HexString {
|
||||
return Sodium.crypto_pwhash(
|
||||
length,
|
||||
password,
|
||||
salt,
|
||||
iterations,
|
||||
bytes,
|
||||
Sodium.constants.crypto_pwhash_ALG_DEFAULT
|
||||
)
|
||||
public argon2(password: Utf8String, salt: HexString, iterations: number, bytes: number, length: number): HexString {
|
||||
return Sodium.crypto_pwhash(length, password, salt, iterations, bytes, Sodium.constants.crypto_pwhash_ALG_DEFAULT)
|
||||
}
|
||||
|
||||
xchacha20Encrypt(
|
||||
plaintext: Utf8String,
|
||||
nonce: HexString,
|
||||
key: HexString,
|
||||
assocData: Utf8String
|
||||
): Base64String {
|
||||
xchacha20Encrypt(plaintext: Utf8String, nonce: HexString, key: HexString, assocData: Utf8String): Base64String {
|
||||
return Sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, nonce, key, assocData)
|
||||
}
|
||||
|
||||
@@ -104,12 +77,7 @@ export class SNReactNativeCrypto implements SNPureCrypto {
|
||||
assocData: Utf8String
|
||||
): string | null {
|
||||
try {
|
||||
const result = Sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||
ciphertext,
|
||||
nonce,
|
||||
key,
|
||||
assocData
|
||||
)
|
||||
const result = Sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(ciphertext, nonce, key, assocData)
|
||||
return result
|
||||
} catch (e) {
|
||||
return null
|
||||
@@ -136,10 +104,7 @@ export class SNReactNativeCrypto implements SNPureCrypto {
|
||||
return new Uint8Array(encryptedBuffer)
|
||||
}
|
||||
|
||||
public xchacha20StreamInitDecryptor(
|
||||
header: Base64String,
|
||||
key: HexString
|
||||
): Sodium.MobileStreamDecryptor {
|
||||
public xchacha20StreamInitDecryptor(header: Base64String, key: HexString): Sodium.MobileStreamDecryptor {
|
||||
const decryptor = Sodium.crypto_secretstream_xchacha20poly1305_init_pull(header, key)
|
||||
return decryptor
|
||||
}
|
||||
@@ -153,11 +118,7 @@ export class SNReactNativeCrypto implements SNPureCrypto {
|
||||
throw new Error('Invalid ciphertext size')
|
||||
}
|
||||
|
||||
const result = Sodium.crypto_secretstream_xchacha20poly1305_pull(
|
||||
decryptor,
|
||||
encryptedBuffer.buffer,
|
||||
assocData
|
||||
)
|
||||
const result = Sodium.crypto_secretstream_xchacha20poly1305_pull(decryptor, encryptedBuffer.buffer, assocData)
|
||||
|
||||
if (!result) {
|
||||
return false
|
||||
|
||||
@@ -93,9 +93,7 @@ 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>(() => Boolean(application?.getAppState().locked))
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true
|
||||
@@ -127,11 +125,9 @@ export const useHasEditor = () => {
|
||||
const [hasEditor, setHasEditor] = React.useState<boolean>(false)
|
||||
|
||||
useEffect(() => {
|
||||
const removeEditorObserver = application?.editorGroup.addActiveControllerChangeObserver(
|
||||
newEditor => {
|
||||
setHasEditor(Boolean(newEditor))
|
||||
}
|
||||
)
|
||||
const removeEditorObserver = application?.editorGroup.addActiveControllerChangeObserver(newEditor => {
|
||||
setHasEditor(Boolean(newEditor))
|
||||
})
|
||||
return removeEditorObserver
|
||||
}, [application])
|
||||
|
||||
@@ -208,10 +204,7 @@ export const useSyncStatus = () => {
|
||||
const unsubscribeAppEvents = application?.addEventObserver(async eventName => {
|
||||
if (eventName === ApplicationEvent.LocalDataIncrementalLoad) {
|
||||
updateLocalDataStatus()
|
||||
} else if (
|
||||
eventName === ApplicationEvent.SyncStatusChanged ||
|
||||
eventName === ApplicationEvent.FailedSync
|
||||
) {
|
||||
} else if (eventName === ApplicationEvent.SyncStatusChanged || eventName === ApplicationEvent.FailedSync) {
|
||||
updateSyncStatus()
|
||||
} else if (eventName === ApplicationEvent.LocalDataLoaded) {
|
||||
setDecrypting(false)
|
||||
@@ -226,13 +219,9 @@ export const useSyncStatus = () => {
|
||||
setLoading(false)
|
||||
updateSyncStatus()
|
||||
} else if (eventName === ApplicationEvent.LocalDatabaseReadError) {
|
||||
void application!.alertService!.alert(
|
||||
'Unable to load local storage. Please restart the app and try again.'
|
||||
)
|
||||
void application!.alertService!.alert('Unable to load local storage. Please restart the app and try again.')
|
||||
} else if (eventName === ApplicationEvent.LocalDatabaseWriteError) {
|
||||
void application!.alertService!.alert(
|
||||
'Unable to write to local storage. Please restart the app and try again.'
|
||||
)
|
||||
void application!.alertService!.alert('Unable to write to local storage. Please restart the app and try again.')
|
||||
} else if (eventName === ApplicationEvent.SignedIn) {
|
||||
setLoading(true)
|
||||
}
|
||||
@@ -245,12 +234,7 @@ export const useSyncStatus = () => {
|
||||
setRefreshing(true)
|
||||
}
|
||||
|
||||
return [loading, decrypting, refreshing, startRefreshing] as [
|
||||
boolean,
|
||||
boolean,
|
||||
boolean,
|
||||
() => void
|
||||
]
|
||||
return [loading, decrypting, refreshing, startRefreshing] as [boolean, boolean, boolean, () => void]
|
||||
}
|
||||
|
||||
export const useDeleteNoteWithPrivileges = (
|
||||
@@ -266,12 +250,7 @@ export const useDeleteNoteWithPrivileges = (
|
||||
const title = 'Move to Trash'
|
||||
const message = 'Are you sure you want to move this note to the trash?'
|
||||
|
||||
const confirmed = await application?.alertService?.confirm(
|
||||
message,
|
||||
title,
|
||||
'Confirm',
|
||||
ButtonType.Danger
|
||||
)
|
||||
const confirmed = await application?.alertService?.confirm(message, title, 'Confirm', ButtonType.Danger)
|
||||
if (confirmed) {
|
||||
onTrashCallback()
|
||||
}
|
||||
@@ -286,13 +265,7 @@ export const useDeleteNoteWithPrivileges = (
|
||||
)
|
||||
return
|
||||
}
|
||||
const confirmed = await application?.alertService?.confirm(
|
||||
message,
|
||||
title,
|
||||
'Delete',
|
||||
ButtonType.Danger,
|
||||
'Cancel'
|
||||
)
|
||||
const confirmed = await application?.alertService?.confirm(message, title, 'Delete', ButtonType.Danger, 'Cancel')
|
||||
if (confirmed) {
|
||||
onDeleteCallback()
|
||||
}
|
||||
@@ -358,18 +331,11 @@ export const useProtectionSessionExpiry = () => {
|
||||
}, [application])
|
||||
|
||||
// State
|
||||
const [protectionsDisabledUntil, setProtectionsDisabledUntil] = React.useState(
|
||||
getProtectionsDisabledUntil()
|
||||
)
|
||||
const [protectionsDisabledUntil, setProtectionsDisabledUntil] = React.useState(getProtectionsDisabledUntil())
|
||||
|
||||
useEffect(() => {
|
||||
const removeProtectionLengthSubscriber = application?.addEventObserver(async event => {
|
||||
if (
|
||||
[
|
||||
ApplicationEvent.UnprotectedSessionBegan,
|
||||
ApplicationEvent.UnprotectedSessionExpired,
|
||||
].includes(event)
|
||||
) {
|
||||
if ([ApplicationEvent.UnprotectedSessionBegan, ApplicationEvent.UnprotectedSessionExpired].includes(event)) {
|
||||
setProtectionsDisabledUntil(getProtectionsDisabledUntil())
|
||||
}
|
||||
})
|
||||
@@ -381,10 +347,7 @@ export const useProtectionSessionExpiry = () => {
|
||||
return [protectionsDisabledUntil]
|
||||
}
|
||||
|
||||
export const useChangeNoteChecks = (
|
||||
note: SNNote | undefined,
|
||||
editor: NoteViewController | undefined = undefined
|
||||
) => {
|
||||
export const useChangeNoteChecks = (note: SNNote | undefined, editor: NoteViewController | undefined = undefined) => {
|
||||
// Context
|
||||
const application = useSafeApplicationContext()
|
||||
|
||||
@@ -410,10 +373,7 @@ export const useChangeNoteChecks = (
|
||||
return [canChangeNote]
|
||||
}
|
||||
|
||||
export const useChangeNote = (
|
||||
note: SNNote | undefined,
|
||||
editor: NoteViewController | undefined = undefined
|
||||
) => {
|
||||
export const useChangeNote = (note: SNNote | undefined, editor: NoteViewController | undefined = undefined) => {
|
||||
const application = React.useContext(ApplicationContext)
|
||||
|
||||
const [canChangeNote] = useChangeNoteChecks(note, editor)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { ChallengePrompt, ChallengeValidation, ChallengeValue } from '@standardnotes/snjs'
|
||||
|
||||
export const isInActiveState = (state: AuthenticationValueStateType) =>
|
||||
state !== AuthenticationValueStateType.WaitingInput &&
|
||||
state !== AuthenticationValueStateType.Success
|
||||
state !== AuthenticationValueStateType.WaitingInput && state !== AuthenticationValueStateType.Success
|
||||
|
||||
export enum AuthenticationValueStateType {
|
||||
WaitingTurn = 0,
|
||||
@@ -29,10 +28,7 @@ type SetChallengeValue = {
|
||||
}
|
||||
|
||||
type Action = SetChallengeValueState | SetChallengeValue
|
||||
export const authenticationReducer = (
|
||||
state: ChallengeValueState,
|
||||
action: Action
|
||||
): ChallengeValueState => {
|
||||
export const authenticationReducer = (state: ChallengeValueState, action: Action): ChallengeValueState => {
|
||||
switch (action.type) {
|
||||
case 'setState': {
|
||||
return {
|
||||
@@ -68,10 +64,7 @@ export const findIndexInObject = (
|
||||
return Object.keys(map).indexOf(id)
|
||||
}
|
||||
|
||||
export const getChallengePromptTitle = (
|
||||
prompt: ChallengePrompt,
|
||||
state: AuthenticationValueStateType
|
||||
) => {
|
||||
export const getChallengePromptTitle = (prompt: ChallengePrompt, state: AuthenticationValueStateType) => {
|
||||
const title = prompt.title
|
||||
switch (state) {
|
||||
case AuthenticationValueStateType.WaitingTurn:
|
||||
@@ -83,10 +76,7 @@ export const getChallengePromptTitle = (
|
||||
}
|
||||
}
|
||||
|
||||
export const getLabelForStateAndType = (
|
||||
validation: ChallengeValidation,
|
||||
state: AuthenticationValueStateType
|
||||
) => {
|
||||
export const getLabelForStateAndType = (validation: ChallengeValidation, state: AuthenticationValueStateType) => {
|
||||
switch (validation) {
|
||||
case ChallengeValidation.Biometric: {
|
||||
switch (state) {
|
||||
|
||||
@@ -126,9 +126,7 @@ export const ComponentView = ({
|
||||
)
|
||||
|
||||
if (confirmed) {
|
||||
void application
|
||||
?.getLocalPreferences()
|
||||
.setUserPrefValue(PrefKey.DoNotShowAgainUnsupportedEditors, true)
|
||||
void application?.getLocalPreferences().setUserPrefValue(PrefKey.DoNotShowAgainUnsupportedEditors, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,8 +273,8 @@ export const ComponentView = ({
|
||||
<LockedContainer>
|
||||
<StyledIcon />
|
||||
<LockedText>
|
||||
Subscription expired. Editors are in a read-only state. To edit immediately, please
|
||||
switch to the Plain Editor.
|
||||
Subscription expired. Editors are in a read-only state. To edit immediately, please switch to the Plain
|
||||
Editor.
|
||||
</LockedText>
|
||||
</LockedContainer>
|
||||
)}
|
||||
@@ -308,9 +306,7 @@ export const ComponentView = ({
|
||||
setSupportMultipleWindows={false}
|
||||
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
|
||||
cacheEnabled={true}
|
||||
autoManageStatusBarEnabled={
|
||||
false /* To prevent StatusBar from changing colors when focusing */
|
||||
}
|
||||
autoManageStatusBarEnabled={false /* To prevent StatusBar from changing colors when focusing */}
|
||||
injectedJavaScript={defaultInjectedJavaScript()}
|
||||
onContentProcessDidTerminate={() => onLoadErrorHandler()}
|
||||
/>
|
||||
|
||||
@@ -53,8 +53,7 @@ type State = {
|
||||
componentViewer?: ComponentViewer
|
||||
}
|
||||
|
||||
const EditingIsDisabledText =
|
||||
'This note has editing disabled. Please enable editing on this note to make changes.'
|
||||
const EditingIsDisabledText = 'This note has editing disabled. Please enable editing on this note to make changes.'
|
||||
|
||||
export class Compose extends React.Component<Record<string, unknown>, State> {
|
||||
static override contextType = ApplicationContext
|
||||
@@ -71,10 +70,7 @@ export class Compose extends React.Component<Record<string, unknown>, State> {
|
||||
removeAppEventObserver?: () => void
|
||||
removeComponentHandler?: () => void
|
||||
|
||||
constructor(
|
||||
props: Record<string, unknown>,
|
||||
context: React.ContextType<typeof ApplicationContext>
|
||||
) {
|
||||
constructor(props: Record<string, unknown>, context: React.ContextType<typeof ApplicationContext>) {
|
||||
super(props)
|
||||
this.context = context
|
||||
const initialEditor = context?.editorGroup.activeNoteViewController
|
||||
@@ -90,52 +86,46 @@ export class Compose extends React.Component<Record<string, unknown>, State> {
|
||||
}
|
||||
|
||||
override componentDidMount() {
|
||||
this.removeNoteInnerValueObserver = this.editor?.addNoteInnerValueChangeObserver(
|
||||
(note, source) => {
|
||||
if (isPayloadSourceRetrieved(source!)) {
|
||||
this.setState({
|
||||
title: note.title,
|
||||
text: note.text,
|
||||
})
|
||||
}
|
||||
this.removeNoteInnerValueObserver = this.editor?.addNoteInnerValueChangeObserver((note, source) => {
|
||||
if (isPayloadSourceRetrieved(source!)) {
|
||||
this.setState({
|
||||
title: note.title,
|
||||
text: note.text,
|
||||
})
|
||||
}
|
||||
|
||||
const isTemplateNoteInsertedToBeInteractableWithEditor =
|
||||
source === PayloadEmitSource.LocalInserted && note.dirty
|
||||
if (isTemplateNoteInsertedToBeInteractableWithEditor) {
|
||||
return
|
||||
}
|
||||
const isTemplateNoteInsertedToBeInteractableWithEditor = source === PayloadEmitSource.LocalInserted && note.dirty
|
||||
if (isTemplateNoteInsertedToBeInteractableWithEditor) {
|
||||
return
|
||||
}
|
||||
|
||||
if (note.lastSyncBegan || note.dirty) {
|
||||
if (note.lastSyncEnd) {
|
||||
if (note.dirty || note.lastSyncBegan!.getTime() > note.lastSyncEnd.getTime()) {
|
||||
this.showSavingStatus()
|
||||
} else if (
|
||||
this.context?.getStatusManager().hasMessage(SCREEN_COMPOSE) &&
|
||||
note.lastSyncEnd.getTime() > note.lastSyncBegan!.getTime()
|
||||
) {
|
||||
this.showAllChangesSavedStatus()
|
||||
}
|
||||
} else {
|
||||
if (note.lastSyncBegan || note.dirty) {
|
||||
if (note.lastSyncEnd) {
|
||||
if (note.dirty || note.lastSyncBegan!.getTime() > note.lastSyncEnd.getTime()) {
|
||||
this.showSavingStatus()
|
||||
} else if (
|
||||
this.context?.getStatusManager().hasMessage(SCREEN_COMPOSE) &&
|
||||
note.lastSyncEnd.getTime() > note.lastSyncBegan!.getTime()
|
||||
) {
|
||||
this.showAllChangesSavedStatus()
|
||||
}
|
||||
} else {
|
||||
this.showSavingStatus()
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
this.removeStreamComponents = this.context?.streamItems(
|
||||
ContentType.Component,
|
||||
async ({ source }) => {
|
||||
if (isPayloadSourceInternalChange(source)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.note) {
|
||||
return
|
||||
}
|
||||
|
||||
void this.reloadComponentEditorState()
|
||||
this.removeStreamComponents = this.context?.streamItems(ContentType.Component, async ({ source }) => {
|
||||
if (isPayloadSourceInternalChange(source)) {
|
||||
return
|
||||
}
|
||||
)
|
||||
|
||||
if (!this.note) {
|
||||
return
|
||||
}
|
||||
|
||||
void this.reloadComponentEditorState()
|
||||
})
|
||||
|
||||
this.removeAppEventObserver = this.context?.addEventObserver(async eventName => {
|
||||
if (eventName === ApplicationEvent.CompletedFullSync) {
|
||||
@@ -349,9 +339,7 @@ export class Compose extends React.Component<Record<string, unknown>, State> {
|
||||
}
|
||||
|
||||
if (!this.context?.items.findItem(note!.uuid)) {
|
||||
void this.context?.alertService!.alert(
|
||||
'Attempting to save this note has failed. The note cannot be found.'
|
||||
)
|
||||
void this.context?.alertService!.alert('Attempting to save this note has failed. The note cannot be found.')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -479,10 +467,7 @@ export class Compose extends React.Component<Record<string, unknown>, State> {
|
||||
|
||||
override render() {
|
||||
const shouldDisplayEditor =
|
||||
this.state.componentViewer &&
|
||||
Boolean(this.note) &&
|
||||
!this.note?.prefersPlainEditor &&
|
||||
!this.state.webViewError
|
||||
this.state.componentViewer && Boolean(this.note) && !this.note?.prefersPlainEditor && !this.state.webViewError
|
||||
|
||||
return (
|
||||
<Container>
|
||||
@@ -491,24 +476,15 @@ export class Compose extends React.Component<Record<string, unknown>, State> {
|
||||
<>
|
||||
{this.noteLocked && (
|
||||
<LockedContainer>
|
||||
<Icon
|
||||
name={ThemeService.nameForIcon(ICON_LOCK)}
|
||||
size={16}
|
||||
color={theme.stylekitBackgroundColor}
|
||||
/>
|
||||
<Icon name={ThemeService.nameForIcon(ICON_LOCK)} size={16} color={theme.stylekitBackgroundColor} />
|
||||
<LockedText>Note Editing Disabled</LockedText>
|
||||
</LockedContainer>
|
||||
)}
|
||||
{this.state.webViewError && (
|
||||
<LockedContainer>
|
||||
<Icon
|
||||
name={ThemeService.nameForIcon(ICON_ALERT)}
|
||||
size={16}
|
||||
color={theme.stylekitBackgroundColor}
|
||||
/>
|
||||
<Icon name={ThemeService.nameForIcon(ICON_ALERT)} size={16} color={theme.stylekitBackgroundColor} />
|
||||
<LockedText>
|
||||
Unable to load {this.state.componentViewer?.component.name} —{' '}
|
||||
{this.getErrorText()}
|
||||
Unable to load {this.state.componentViewer?.component.name} — {this.getErrorText()}
|
||||
</LockedText>
|
||||
<WebViewReloadButton
|
||||
onPress={() => {
|
||||
@@ -535,8 +511,7 @@ export class Compose extends React.Component<Record<string, unknown>, State> {
|
||||
autoCapitalize={'sentences'}
|
||||
/>
|
||||
{(this.state.downloadingEditor ||
|
||||
(this.state.loadingWebview &&
|
||||
themeService?.isLikelyUsingDarkColorTheme())) && (
|
||||
(this.state.loadingWebview && themeService?.isLikelyUsingDarkColorTheme())) && (
|
||||
<LoadingWebViewContainer locked={this.noteLocked}>
|
||||
<LoadingText>
|
||||
{'Loading '}
|
||||
@@ -557,22 +532,20 @@ export class Compose extends React.Component<Record<string, unknown>, State> {
|
||||
/>
|
||||
)}
|
||||
|
||||
{!shouldDisplayEditor &&
|
||||
!isNullOrUndefined(this.note) &&
|
||||
Platform.OS === 'android' && (
|
||||
<TextContainer>
|
||||
<StyledTextView
|
||||
testID="noteContentField"
|
||||
ref={this.editorViewRef}
|
||||
autoFocus={false}
|
||||
value={this.state.text}
|
||||
selectionColor={lighten(theme.stylekitInfoColor, 0.35)}
|
||||
handlesColor={theme.stylekitInfoColor}
|
||||
onChangeText={this.onContentChange}
|
||||
errorState={false}
|
||||
/>
|
||||
</TextContainer>
|
||||
)}
|
||||
{!shouldDisplayEditor && !isNullOrUndefined(this.note) && Platform.OS === 'android' && (
|
||||
<TextContainer>
|
||||
<StyledTextView
|
||||
testID="noteContentField"
|
||||
ref={this.editorViewRef}
|
||||
autoFocus={false}
|
||||
value={this.state.text}
|
||||
selectionColor={lighten(theme.stylekitInfoColor, 0.35)}
|
||||
handlesColor={theme.stylekitInfoColor}
|
||||
onChangeText={this.onContentChange}
|
||||
errorState={false}
|
||||
/>
|
||||
</TextContainer>
|
||||
)}
|
||||
{/* Empty wrapping view fixes native textview crashing */}
|
||||
{!shouldDisplayEditor && Platform.OS === 'ios' && (
|
||||
<View key={this.note?.uuid}>
|
||||
|
||||
@@ -54,13 +54,7 @@ export const FileInputModal: FC<Props> = props => {
|
||||
/>
|
||||
</SectionedTableCell>
|
||||
|
||||
<ButtonCell
|
||||
maxHeight={45}
|
||||
disabled={fileName.length === 0}
|
||||
title={'Save'}
|
||||
bold
|
||||
onPress={onSubmit}
|
||||
/>
|
||||
<ButtonCell maxHeight={45} disabled={fileName.length === 0} title={'Save'} bold onPress={onSubmit} />
|
||||
</TableSection>
|
||||
</Container>
|
||||
)
|
||||
|
||||
@@ -85,13 +85,7 @@ export const TagInputModal = (props: Props) => {
|
||||
/>
|
||||
</SectionedTableCell>
|
||||
|
||||
<ButtonCell
|
||||
maxHeight={45}
|
||||
disabled={text.length === 0}
|
||||
title={'Save'}
|
||||
bold
|
||||
onPress={onSubmit}
|
||||
/>
|
||||
<ButtonCell maxHeight={45} disabled={text.length === 0} title={'Save'} bold onPress={onSubmit} />
|
||||
</TableSection>
|
||||
</Container>
|
||||
)
|
||||
|
||||
@@ -78,8 +78,7 @@ export const ManageSessions: React.FC = () => {
|
||||
const theme = useContext(ThemeContext)
|
||||
const insets = useSafeAreaInsets()
|
||||
|
||||
const [sessions, getSessions, refreshSessions, refreshing, revokeSession, errorMessage] =
|
||||
useSessions()
|
||||
const [sessions, getSessions, refreshSessions, refreshing, revokeSession, errorMessage] = useSessions()
|
||||
|
||||
const onItemPress = (item: RemoteSession) => {
|
||||
showActionSheet({
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import {
|
||||
Props as TableCellProps,
|
||||
SectionedTableCellTouchableHighlight,
|
||||
} from '@Root/Components/SectionedTableCell'
|
||||
import { Props as TableCellProps, SectionedTableCellTouchableHighlight } from '@Root/Components/SectionedTableCell'
|
||||
import React from 'react'
|
||||
import styled, { css } from 'styled-components/native'
|
||||
|
||||
|
||||
@@ -22,9 +22,7 @@ export const NoteHistory = (props: Props) => {
|
||||
const themeService = useContext(ThemeServiceContext)
|
||||
|
||||
// State
|
||||
const [note] = useState<SNNote>(
|
||||
() => application?.items.findItem(props.route.params.noteUuid) as SNNote
|
||||
)
|
||||
const [note] = useState<SNNote>(() => application?.items.findItem(props.route.params.noteUuid) as SNNote)
|
||||
const [routes] = React.useState([
|
||||
{ key: 'session', title: 'Session' },
|
||||
{ key: 'remote', title: 'Remote' },
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import {
|
||||
Props as TableCellProps,
|
||||
SectionedTableCellTouchableHighlight,
|
||||
} from '@Root/Components/SectionedTableCell'
|
||||
import { Props as TableCellProps, SectionedTableCellTouchableHighlight } from '@Root/Components/SectionedTableCell'
|
||||
import React from 'react'
|
||||
import styled, { css } from 'styled-components/native'
|
||||
|
||||
|
||||
@@ -9,13 +9,7 @@ import { ThemeService } from '@Style/ThemeService'
|
||||
import React, { useCallback, useContext, useLayoutEffect } from 'react'
|
||||
import { LogBox } from 'react-native'
|
||||
import { HeaderButtons, Item } from 'react-navigation-header-buttons'
|
||||
import {
|
||||
Container,
|
||||
StyledTextView,
|
||||
TextContainer,
|
||||
Title,
|
||||
TitleContainer,
|
||||
} from './NoteHistoryPreview.styled'
|
||||
import { Container, StyledTextView, TextContainer, Title, TitleContainer } from './NoteHistoryPreview.styled'
|
||||
|
||||
LogBox.ignoreLogs(['Non-serializable values were found in the navigation state'])
|
||||
|
||||
@@ -40,9 +34,7 @@ export const NoteHistoryPreview = ({
|
||||
if (asCopy) {
|
||||
await application?.mutator.duplicateItem(originalNote!, {
|
||||
...revision.payload.content,
|
||||
title: revision.payload.content.title
|
||||
? revision.payload.content.title + ' (copy)'
|
||||
: undefined,
|
||||
title: revision.payload.content.title ? revision.payload.content.title + ' (copy)' : undefined,
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
|
||||
@@ -43,11 +43,7 @@ export const RemoteHistory: React.FC<Props> = ({ note, onPress }) => {
|
||||
async (item: RevisionListEntry) => {
|
||||
const remoteRevision = await application?.historyManager!.fetchRemoteRevision(note, item)
|
||||
if (remoteRevision) {
|
||||
onPress(
|
||||
item.uuid,
|
||||
remoteRevision as NoteHistoryEntry,
|
||||
new Date(item.updated_at).toLocaleString()
|
||||
)
|
||||
onPress(item.uuid, remoteRevision as NoteHistoryEntry, new Date(item.updated_at).toLocaleString())
|
||||
} else {
|
||||
void application?.alertService!.alert(
|
||||
'The remote revision could not be loaded. Please try again later.',
|
||||
@@ -60,19 +56,10 @@ export const RemoteHistory: React.FC<Props> = ({ note, onPress }) => {
|
||||
)
|
||||
|
||||
const renderItem: ListRenderItem<RevisionListEntry> | null | undefined = ({ item }) => {
|
||||
return (
|
||||
<NoteHistoryCell
|
||||
onPress={() => onItemPress(item)}
|
||||
title={new Date(item.updated_at).toLocaleString()}
|
||||
/>
|
||||
)
|
||||
return <NoteHistoryCell onPress={() => onItemPress(item)} title={new Date(item.updated_at).toLocaleString()} />
|
||||
}
|
||||
|
||||
if (
|
||||
fetchingRemoteHistory ||
|
||||
!remoteHistoryList ||
|
||||
(remoteHistoryList && remoteHistoryList.length === 0)
|
||||
) {
|
||||
if (fetchingRemoteHistory || !remoteHistoryList || (remoteHistoryList && remoteHistoryList.length === 0)) {
|
||||
const placeholderText = fetchingRemoteHistory ? 'Loading entries...' : 'No entries.'
|
||||
return (
|
||||
<LoadingContainer>
|
||||
|
||||
@@ -1,18 +1,8 @@
|
||||
import {
|
||||
useChangeNote,
|
||||
useDeleteNoteWithPrivileges,
|
||||
useProtectOrUnprotectNote,
|
||||
} from '@Lib/SnjsHelperHooks'
|
||||
import { useChangeNote, useDeleteNoteWithPrivileges, useProtectOrUnprotectNote } from '@Lib/SnjsHelperHooks'
|
||||
import { ApplicationContext } from '@Root/ApplicationContext'
|
||||
import { SnIcon } from '@Root/Components/SnIcon'
|
||||
import { NoteCellIconFlags } from '@Root/Screens/Notes/NoteCellIconFlags'
|
||||
import {
|
||||
CollectionSort,
|
||||
CollectionSortProperty,
|
||||
IconType,
|
||||
isNullOrUndefined,
|
||||
SNNote,
|
||||
} from '@standardnotes/snjs'
|
||||
import { CollectionSort, CollectionSortProperty, IconType, isNullOrUndefined, SNNote } from '@standardnotes/snjs'
|
||||
import { CustomActionSheetOption, useCustomActionSheet } from '@Style/CustomActionSheet'
|
||||
import { getTintColorForEditor } from '@Style/Utils'
|
||||
import React, { useContext, useRef, useState } from 'react'
|
||||
@@ -194,9 +184,10 @@ export const NoteCell = ({
|
||||
const showDetails = !hideDates || note.protected
|
||||
|
||||
const editorForNote = application?.componentManager.editorForNote(note)
|
||||
const [icon, tint] = application?.iconsController.getIconAndTintForEditor(
|
||||
editorForNote?.identifier
|
||||
) as [IconType, number]
|
||||
const [icon, tint] = application?.iconsController.getIconAndTintForEditor(editorForNote?.identifier) as [
|
||||
IconType,
|
||||
number
|
||||
]
|
||||
|
||||
return (
|
||||
<TouchableContainer
|
||||
@@ -207,19 +198,13 @@ export const NoteCell = ({
|
||||
delayPressIn={150}
|
||||
>
|
||||
<Container ref={elementRef as any} selected={highlight} distance={padding}>
|
||||
{!hideEditorIcon && (
|
||||
<SnIcon type={icon} fill={getTintColorForEditor(theme, tint)} style={styles.editorIcon} />
|
||||
)}
|
||||
{!hideEditorIcon && <SnIcon type={icon} fill={getTintColorForEditor(theme, tint)} style={styles.editorIcon} />}
|
||||
<NoteDataContainer distance={padding}>
|
||||
<NoteCellFlags note={note} highlight={highlight} />
|
||||
|
||||
<FlexContainer>
|
||||
<NoteContentsContainer>
|
||||
{note.title.length > 0 ? (
|
||||
<TitleText selected={highlight}>{note.title}</TitleText>
|
||||
) : (
|
||||
<View />
|
||||
)}
|
||||
{note.title.length > 0 ? <TitleText selected={highlight}>{note.title}</TitleText> : <View />}
|
||||
{hasPlainPreview && showPreview && (
|
||||
<NoteText selected={highlight} numberOfLines={2}>
|
||||
{note.preview_plain}
|
||||
@@ -245,9 +230,7 @@ export const NoteCell = ({
|
||||
)}
|
||||
{!hideDates && (
|
||||
<Text>
|
||||
{sortType === CollectionSort.UpdatedAt
|
||||
? 'Modified ' + note.updatedAtString
|
||||
: note.createdAtString}
|
||||
{sortType === CollectionSort.UpdatedAt ? 'Modified ' + note.updatedAtString : note.createdAtString}
|
||||
</Text>
|
||||
)}
|
||||
</DetailsText>
|
||||
|
||||
@@ -7,15 +7,7 @@ import { Chip } from '@Root/Components/Chip'
|
||||
import { SearchBar } from '@Root/Components/SearchBar'
|
||||
import { SCREEN_NOTES } from '@Root/Screens/screens'
|
||||
import { CollectionSortProperty, SNNote } from '@standardnotes/snjs'
|
||||
import React, {
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import React, { Dispatch, SetStateAction, useCallback, useContext, useEffect, useRef, useState } from 'react'
|
||||
import { Animated, FlatList, ListRenderItem, RefreshControl } from 'react-native'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import IosSearchBar from 'react-native-search-bar'
|
||||
@@ -90,13 +82,11 @@ export const NoteList = (props: Props) => {
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribeStateEventObserver = application
|
||||
?.getAppState()
|
||||
.addStateEventObserver(state => {
|
||||
if (state === AppStateEventType.DrawerOpen) {
|
||||
dismissKeyboard()
|
||||
}
|
||||
})
|
||||
const unsubscribeStateEventObserver = application?.getAppState().addStateEventObserver(state => {
|
||||
if (state === AppStateEventType.DrawerOpen) {
|
||||
dismissKeyboard()
|
||||
}
|
||||
})
|
||||
|
||||
return unsubscribeStateEventObserver
|
||||
}, [application])
|
||||
@@ -109,13 +99,11 @@ export const NoteList = (props: Props) => {
|
||||
}, [noteListScrolled, props.notes])
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribeTagChangedEventObserver = application
|
||||
?.getAppState()
|
||||
.addStateChangeObserver(event => {
|
||||
if (event === AppStateType.TagChanged) {
|
||||
scrollListToTop()
|
||||
}
|
||||
})
|
||||
const unsubscribeTagChangedEventObserver = application?.getAppState().addStateChangeObserver(event => {
|
||||
if (event === AppStateType.TagChanged) {
|
||||
scrollListToTop()
|
||||
}
|
||||
})
|
||||
|
||||
return unsubscribeTagChangedEventObserver
|
||||
}, [application, scrollListToTop])
|
||||
@@ -232,10 +220,7 @@ export const NoteList = (props: Props) => {
|
||||
ref={noteListRef}
|
||||
style={styles.list}
|
||||
keyExtractor={item => item.uuid}
|
||||
contentContainerStyle={[
|
||||
{ paddingBottom: insets.bottom },
|
||||
props.notes.length > 0 ? {} : { height: '100%' },
|
||||
]}
|
||||
contentContainerStyle={[{ paddingBottom: insets.bottom }, props.notes.length > 0 ? {} : { height: '100%' }]}
|
||||
initialNumToRender={6}
|
||||
windowSize={6}
|
||||
maxToRenderPerBatch={6}
|
||||
@@ -260,9 +245,7 @@ export const NoteList = (props: Props) => {
|
||||
data={props.notes}
|
||||
renderItem={renderItem}
|
||||
extraData={signedIn}
|
||||
ListHeaderComponent={() => (
|
||||
<HeaderContainer>{!signedIn && <OfflineBanner />}</HeaderContainer>
|
||||
)}
|
||||
ListHeaderComponent={() => <HeaderContainer>{!signedIn && <OfflineBanner />}</HeaderContainer>}
|
||||
onScroll={onScroll}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
@@ -77,9 +77,7 @@ export const Notes = React.memo(
|
||||
const [shouldFocusSearch, setShouldFocusSearch] = useState<boolean>(false)
|
||||
|
||||
const haveDisplayOptions = useRef(false)
|
||||
const protectionsEnabled = useRef(
|
||||
application.hasProtectionSources() && !application.hasUnprotectedAccessSession()
|
||||
)
|
||||
const protectionsEnabled = useRef(application.hasProtectionSources() && !application.hasUnprotectedAccessSession())
|
||||
|
||||
const reloadTitle = useCallback(
|
||||
(newNotes?: SNNote[], newFilter?: string) => {
|
||||
@@ -90,8 +88,7 @@ export const Notes = React.memo(
|
||||
|
||||
if (newNotes && (newFilter ?? searchText).length > 0) {
|
||||
const resultCount = newNotes.length
|
||||
title =
|
||||
resultCount === 1 ? `${resultCount} search result` : `${resultCount} search results`
|
||||
title = resultCount === 1 ? `${resultCount} search result` : `${resultCount} search results`
|
||||
} else if (selectedTag) {
|
||||
title = selectedTag.title
|
||||
if (selectedTag instanceof SNTag && selectedTag.parentId) {
|
||||
@@ -164,13 +161,11 @@ export const Notes = React.memo(
|
||||
|
||||
useEffect(() => {
|
||||
let mounted = true
|
||||
const removeEditorObserver = application.editorGroup.addActiveControllerChangeObserver(
|
||||
activeEditor => {
|
||||
if (mounted) {
|
||||
setSelectedNoteId(activeEditor?.note?.uuid)
|
||||
}
|
||||
const removeEditorObserver = application.editorGroup.addActiveControllerChangeObserver(activeEditor => {
|
||||
if (mounted) {
|
||||
setSelectedNoteId(activeEditor?.note?.uuid)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
return () => {
|
||||
mounted = false
|
||||
@@ -264,8 +259,7 @@ export const Notes = React.memo(
|
||||
}, [includeTrashedNotes, reloadNotesDisplayOptions])
|
||||
|
||||
const reloadSearchOptions = useCallback(() => {
|
||||
const protections =
|
||||
application.hasProtectionSources() && !application.hasUnprotectedAccessSession()
|
||||
const protections = application.hasProtectionSources() && !application.hasUnprotectedAccessSession()
|
||||
|
||||
if (protections !== protectionsEnabled.current) {
|
||||
protectionsEnabled.current = !!protections
|
||||
@@ -281,10 +275,8 @@ export const Notes = React.memo(
|
||||
},
|
||||
]
|
||||
|
||||
const isArchiveView =
|
||||
selectedTag instanceof SmartView && selectedTag.uuid === SystemViewId.ArchivedNotes
|
||||
const isTrashView =
|
||||
selectedTag instanceof SmartView && selectedTag.uuid === SystemViewId.TrashedNotes
|
||||
const isArchiveView = selectedTag instanceof SmartView && selectedTag.uuid === SystemViewId.ArchivedNotes
|
||||
const isTrashView = selectedTag instanceof SmartView && selectedTag.uuid === SystemViewId.TrashedNotes
|
||||
if (!isArchiveView && !isTrashView) {
|
||||
setSearchOptions([
|
||||
...options,
|
||||
@@ -312,10 +304,7 @@ export const Notes = React.memo(
|
||||
toggleIncludeTrashed,
|
||||
])
|
||||
|
||||
const getFirstSelectableNote = useCallback(
|
||||
(newNotes: SNNote[]) => newNotes.find(note => !note.protected),
|
||||
[]
|
||||
)
|
||||
const getFirstSelectableNote = useCallback((newNotes: SNNote[]) => newNotes.find(note => !note.protected), [])
|
||||
|
||||
const selectFirstNote = useCallback(
|
||||
(newNotes: SNNote[]) => {
|
||||
@@ -383,20 +372,11 @@ export const Notes = React.memo(
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
application,
|
||||
reloadNotesDisplayOptions,
|
||||
reloadSearchOptions,
|
||||
reloadTitle,
|
||||
selectFirstNote,
|
||||
selectNextOrCreateNew,
|
||||
]
|
||||
[application, reloadNotesDisplayOptions, reloadSearchOptions, reloadTitle, selectFirstNote, selectNextOrCreateNew]
|
||||
)
|
||||
|
||||
const onNoteCreate = useCallback(async () => {
|
||||
const title = application.getAppState().isTabletDevice
|
||||
? `Note ${notes.length + 1}`
|
||||
: undefined
|
||||
const title = application.getAppState().isTabletDevice ? `Note ${notes.length + 1}` : undefined
|
||||
await application.getAppState().createEditor(title)
|
||||
openCompose(true)
|
||||
reloadNotes(true)
|
||||
@@ -422,21 +402,13 @@ export const Notes = React.memo(
|
||||
}, [application, reloadNotes, reloadNotesDisplayOptions])
|
||||
|
||||
const reloadPreferences = useCallback(async () => {
|
||||
const newSortBy = application
|
||||
.getLocalPreferences()
|
||||
.getValue(PrefKey.SortNotesBy, CollectionSort.CreatedAt)
|
||||
const newSortBy = application.getLocalPreferences().getValue(PrefKey.SortNotesBy, CollectionSort.CreatedAt)
|
||||
let displayOptionsChanged = false
|
||||
|
||||
const newSortReverse = application
|
||||
.getLocalPreferences()
|
||||
.getValue(PrefKey.SortNotesReverse, false)
|
||||
const newHidePreview = application
|
||||
.getLocalPreferences()
|
||||
.getValue(PrefKey.NotesHideNotePreview, false)
|
||||
const newSortReverse = application.getLocalPreferences().getValue(PrefKey.SortNotesReverse, false)
|
||||
const newHidePreview = application.getLocalPreferences().getValue(PrefKey.NotesHideNotePreview, false)
|
||||
const newHideDate = application.getLocalPreferences().getValue(PrefKey.NotesHideDate, false)
|
||||
const newHideEditorIcon = application
|
||||
.getLocalPreferences()
|
||||
.getValue(PrefKey.NotesHideEditorIcon, false)
|
||||
const newHideEditorIcon = application.getLocalPreferences().getValue(PrefKey.NotesHideEditorIcon, false)
|
||||
|
||||
if (sortBy !== newSortBy) {
|
||||
setSortBy(newSortBy)
|
||||
@@ -494,30 +466,22 @@ export const Notes = React.memo(
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
void reloadPreferences()
|
||||
const removeAppStateChangeHandler = application
|
||||
.getAppState()
|
||||
.addStateChangeObserver(state => {
|
||||
if (state === AppStateType.TagChanged) {
|
||||
reloadNotesDisplayOptions()
|
||||
reloadNotes(true, true)
|
||||
}
|
||||
if (state === AppStateType.PreferencesChanged) {
|
||||
void reloadPreferences()
|
||||
}
|
||||
})
|
||||
const removeAppStateChangeHandler = application.getAppState().addStateChangeObserver(state => {
|
||||
if (state === AppStateType.TagChanged) {
|
||||
reloadNotesDisplayOptions()
|
||||
reloadNotes(true, true)
|
||||
}
|
||||
if (state === AppStateType.PreferencesChanged) {
|
||||
void reloadPreferences()
|
||||
}
|
||||
})
|
||||
const removeStreams = streamNotesAndTags()
|
||||
|
||||
return () => {
|
||||
removeAppStateChangeHandler()
|
||||
removeStreams()
|
||||
}
|
||||
}, [
|
||||
application,
|
||||
reloadNotes,
|
||||
reloadNotesDisplayOptions,
|
||||
reloadPreferences,
|
||||
streamNotesAndTags,
|
||||
])
|
||||
}, [application, reloadNotes, reloadNotesDisplayOptions, reloadPreferences, streamNotesAndTags])
|
||||
)
|
||||
|
||||
return (
|
||||
@@ -551,9 +515,7 @@ export const Notes = React.memo(
|
||||
onClickAction={onNoteCreate}
|
||||
visible={true}
|
||||
size={30}
|
||||
iconTextComponent={
|
||||
<StyledIcon testID="newNoteButton" name={ThemeService.nameForIcon(ICON_ADD)} />
|
||||
}
|
||||
iconTextComponent={<StyledIcon testID="newNoteButton" name={ThemeService.nameForIcon(ICON_ADD)} />}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -38,13 +38,4 @@ const SubText = styled.Text`
|
||||
color: ${props => props.theme.stylekitNeutralColor};
|
||||
`
|
||||
|
||||
export {
|
||||
Touchable,
|
||||
Container,
|
||||
CenterContainer,
|
||||
UserIcon,
|
||||
ForwardIcon,
|
||||
TextContainer,
|
||||
BoldText,
|
||||
SubText,
|
||||
}
|
||||
export { Touchable, Container, CenterContainer, UserIcon, ForwardIcon, TextContainer, BoldText, SubText }
|
||||
|
||||
@@ -10,13 +10,7 @@ import Icon from 'react-native-vector-icons/Ionicons'
|
||||
import { ThemeContext } from 'styled-components'
|
||||
import { Compose } from './Compose/Compose'
|
||||
import { Notes } from './Notes/Notes'
|
||||
import {
|
||||
ComposeContainer,
|
||||
Container,
|
||||
ExpandTouchable,
|
||||
iconNames,
|
||||
NotesContainer,
|
||||
} from './Root.styled'
|
||||
import { ComposeContainer, Container, ExpandTouchable, iconNames, NotesContainer } from './Root.styled'
|
||||
|
||||
export const Root = () => {
|
||||
// Context
|
||||
@@ -62,11 +56,9 @@ export const Root = () => {
|
||||
}
|
||||
}
|
||||
})
|
||||
const removeNoteObserver = application?.editorGroup.addActiveControllerChangeObserver(
|
||||
activeController => {
|
||||
setActiveNoteId(activeController?.note.uuid)
|
||||
}
|
||||
)
|
||||
const removeNoteObserver = application?.editorGroup.addActiveControllerChangeObserver(activeController => {
|
||||
setActiveNoteId(activeController?.note.uuid)
|
||||
})
|
||||
return () => {
|
||||
if (removeApplicationStateEventHandler) {
|
||||
removeApplicationStateEventHandler()
|
||||
@@ -112,8 +104,7 @@ export const Root = () => {
|
||||
setNoteListCollapsed(value => !value)
|
||||
}
|
||||
|
||||
const collapseIconBottomPosition =
|
||||
(keyboardHeight ?? 0) > (height ?? 0) / 2 ? (keyboardHeight ?? 0) + 40 : '50%'
|
||||
const collapseIconBottomPosition = (keyboardHeight ?? 0) > (height ?? 0) / 2 ? (keyboardHeight ?? 0) + 40 : '50%'
|
||||
|
||||
if (isLocked) {
|
||||
return null
|
||||
@@ -128,11 +119,7 @@ export const Root = () => {
|
||||
<ComposeContainer>
|
||||
<Compose key={activeNoteId} />
|
||||
<ExpandTouchable style={{ bottom: collapseIconBottomPosition }} onPress={toggleNoteList}>
|
||||
<Icon
|
||||
name={collapseIconName}
|
||||
size={24}
|
||||
color={hexToRGBA(theme.stylekitInfoColor, 0.85)}
|
||||
/>
|
||||
<Icon name={collapseIconName} size={24} color={hexToRGBA(theme.stylekitInfoColor, 0.85)} />
|
||||
</ExpandTouchable>
|
||||
</ComposeContainer>
|
||||
)}
|
||||
|
||||
@@ -56,11 +56,7 @@ export const AuthSection = (props: Props) => {
|
||||
|
||||
const validate = () => {
|
||||
if (!email) {
|
||||
void application?.alertService?.alert(
|
||||
'Please enter a valid email address.',
|
||||
'Missing Email',
|
||||
'OK'
|
||||
)
|
||||
void application?.alertService?.alert('Please enter a valid email address.', 'Missing Email', 'OK')
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -125,8 +121,8 @@ export const AuthSection = (props: Props) => {
|
||||
<SectionHeader title={'Confirm Password'} />
|
||||
|
||||
<RegistrationDescription>
|
||||
Due to the nature of our encryption, Standard Notes cannot offer password reset
|
||||
functionality. If you forget your password, you will permanently lose access to your data.
|
||||
Due to the nature of our encryption, Standard Notes cannot offer password reset functionality. If you forget
|
||||
your password, you will permanently lose access to your data.
|
||||
</RegistrationDescription>
|
||||
|
||||
<SectionedTableCell first textInputCell>
|
||||
@@ -241,11 +237,7 @@ export const AuthSection = (props: Props) => {
|
||||
/>
|
||||
|
||||
{!showAdvanced && (
|
||||
<ButtonCell
|
||||
testID="advancedOptionsButton"
|
||||
title="Advanced Options"
|
||||
onPress={() => setShowAdvanced(true)}
|
||||
/>
|
||||
<ButtonCell testID="advancedOptionsButton" title="Advanced Options" onPress={() => setShowAdvanced(true)} />
|
||||
)}
|
||||
</TableSection>
|
||||
)
|
||||
|
||||
@@ -8,9 +8,9 @@ import { Platform, Share } from 'react-native'
|
||||
import { ContentContainer, Label } from './CompanySection.styled'
|
||||
|
||||
const URLS = {
|
||||
feedback: `mailto:help@standardnotes.com?subject=${
|
||||
Platform.OS === 'android' ? 'Android' : 'iOS'
|
||||
} app feedback (v${ApplicationState.version})`,
|
||||
feedback: `mailto:help@standardnotes.com?subject=${Platform.OS === 'android' ? 'Android' : 'iOS'} app feedback (v${
|
||||
ApplicationState.version
|
||||
})`,
|
||||
learn_more: 'https://standardnotes.com',
|
||||
privacy: 'https://standardnotes.com/privacy',
|
||||
help: 'https://standardnotes.com/help',
|
||||
@@ -47,8 +47,7 @@ export const CompanySection = (props: Props) => {
|
||||
|
||||
const shareWithFriend = () => {
|
||||
const title = 'Standard Notes'
|
||||
let message =
|
||||
'Check out Standard Notes, a free, open-source, and completely encrypted notes app.'
|
||||
let message = 'Check out Standard Notes, a free, open-source, and completely encrypted notes app.'
|
||||
const url = 'https://standardnotes.com'
|
||||
// Android ignores url. iOS ignores title.
|
||||
if (Platform.OS === 'android') {
|
||||
@@ -80,19 +79,11 @@ export const CompanySection = (props: Props) => {
|
||||
<Label>Share Standard Notes with a friend.</Label>
|
||||
</ButtonCell>
|
||||
|
||||
<ButtonCell
|
||||
leftAligned={true}
|
||||
title="Learn About Standard Notes"
|
||||
onPress={() => openUrl('learn_more')}
|
||||
>
|
||||
<ButtonCell leftAligned={true} title="Learn About Standard Notes" onPress={() => openUrl('learn_more')}>
|
||||
<Label>https://standardnotes.com</Label>
|
||||
</ButtonCell>
|
||||
|
||||
<ButtonCell
|
||||
leftAligned={true}
|
||||
title="Our Privacy Manifesto"
|
||||
onPress={() => openUrl('privacy')}
|
||||
>
|
||||
<ButtonCell leftAligned={true} title="Our Privacy Manifesto" onPress={() => openUrl('privacy')}>
|
||||
<Label>https://standardnotes.com/privacy</Label>
|
||||
</ButtonCell>
|
||||
|
||||
|
||||
@@ -106,9 +106,7 @@ export const OptionsSection = ({ title, encryptionAvailable }: Props) => {
|
||||
return RNFS.readFile(fileUri)
|
||||
.then(result => JSON.parse(result))
|
||||
.catch(() => {
|
||||
void application!.alertService!.alert(
|
||||
'Unable to open file. Ensure it is a proper JSON file and try again.'
|
||||
)
|
||||
void application!.alertService!.alert('Unable to open file. Ensure it is a proper JSON file and try again.')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -134,8 +132,7 @@ export const OptionsSection = ({ title, encryptionAvailable }: Props) => {
|
||||
type: [DocumentPicker.types.plainText],
|
||||
})
|
||||
const selectedFile = selectedFiles[0]
|
||||
const selectedFileURI =
|
||||
Platform.OS === 'ios' ? decodeURIComponent(selectedFile.uri) : selectedFile.uri
|
||||
const selectedFileURI = Platform.OS === 'ios' ? decodeURIComponent(selectedFile.uri) : selectedFile.uri
|
||||
const data = await readImportFile(selectedFileURI)
|
||||
if (!data) {
|
||||
return
|
||||
|
||||
@@ -45,9 +45,7 @@ export const PreferencesSection = () => {
|
||||
setSortBy(key)
|
||||
}
|
||||
const toggleNotesPreviewHidden = () => {
|
||||
void application
|
||||
?.getLocalPreferences()
|
||||
.setUserPrefValue(PrefKey.NotesHideNotePreview, !hidePreviews)
|
||||
void application?.getLocalPreferences().setUserPrefValue(PrefKey.NotesHideNotePreview, !hidePreviews)
|
||||
setHidePreviews(value => !value)
|
||||
}
|
||||
const toggleNotesDateHidden = () => {
|
||||
@@ -55,9 +53,7 @@ export const PreferencesSection = () => {
|
||||
setHideDates(value => !value)
|
||||
}
|
||||
const toggleNotesEditorIconHidden = () => {
|
||||
void application
|
||||
?.getLocalPreferences()
|
||||
.setUserPrefValue(PrefKey.NotesHideEditorIcon, !hideEditorIcon)
|
||||
void application?.getLocalPreferences().setUserPrefValue(PrefKey.NotesHideEditorIcon, !hideEditorIcon)
|
||||
setHideEditorIcon(value => !value)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,7 @@ import { SectionHeader } from '@Root/Components/SectionHeader'
|
||||
import { TableSection } from '@Root/Components/TableSection'
|
||||
import { useSafeApplicationContext } from '@Root/Hooks/useSafeApplicationContext'
|
||||
import React from 'react'
|
||||
import {
|
||||
BaseView,
|
||||
StyledSectionedTableCell,
|
||||
SubText,
|
||||
Subtitle,
|
||||
Title,
|
||||
} from './ProtectionsSection.styled'
|
||||
import { BaseView, StyledSectionedTableCell, SubText, Subtitle, Title } from './ProtectionsSection.styled'
|
||||
|
||||
type Props = {
|
||||
title: string
|
||||
@@ -23,9 +17,7 @@ export const ProtectionsSection = (props: Props) => {
|
||||
// State
|
||||
const [protectionsDisabledUntil] = useProtectionSessionExpiry()
|
||||
|
||||
const protectionsEnabledSubtitle = protectionsDisabledUntil
|
||||
? `Disabled until ${protectionsDisabledUntil}`
|
||||
: 'Enabled'
|
||||
const protectionsEnabledSubtitle = protectionsDisabledUntil ? `Disabled until ${protectionsDisabledUntil}` : 'Enabled'
|
||||
|
||||
const protectionsEnabledSubtext =
|
||||
'Actions like viewing protected notes, exporting decrypted backups, or revoking an active session, require additional authentication like entering your account password or application passcode.'
|
||||
@@ -40,9 +32,7 @@ export const ProtectionsSection = (props: Props) => {
|
||||
<StyledSectionedTableCell first>
|
||||
<BaseView>
|
||||
<Title>Status</Title>
|
||||
<Subtitle>
|
||||
{props.protectionsAvailable ? protectionsEnabledSubtitle : 'Disabled'}
|
||||
</Subtitle>
|
||||
<Subtitle>{props.protectionsAvailable ? protectionsEnabledSubtitle : 'Disabled'}</Subtitle>
|
||||
</BaseView>
|
||||
</StyledSectionedTableCell>
|
||||
{props.protectionsAvailable && protectionsDisabledUntil && (
|
||||
|
||||
@@ -26,9 +26,7 @@ export const SecuritySection = (props: Props) => {
|
||||
const application = useContext(ApplicationContext)
|
||||
|
||||
// State
|
||||
const [encryptionPolicy, setEncryptionPolicy] = useState(() =>
|
||||
application?.getStorageEncryptionPolicy()
|
||||
)
|
||||
const [encryptionPolicy, setEncryptionPolicy] = useState(() => application?.getStorageEncryptionPolicy())
|
||||
const [encryptionPolictChangeInProgress, setEncryptionPolictChangeInProgress] = useState(false)
|
||||
const [hasScreenshotPrivacy, setHasScreenshotPrivacy] = useState<boolean | undefined>(false)
|
||||
const [hasBiometrics, setHasBiometrics] = useState(false)
|
||||
@@ -178,8 +176,7 @@ export const SecuritySection = (props: Props) => {
|
||||
message =
|
||||
'Are you sure you want to disable your local passcode? This will not affect your encryption status, as your data is currently being encrypted through your sync account keys.'
|
||||
} else {
|
||||
message =
|
||||
'Are you sure you want to disable your local passcode? This will disable encryption on your data.'
|
||||
message = 'Are you sure you want to disable your local passcode? This will disable encryption on your data.'
|
||||
}
|
||||
|
||||
const confirmed = await application?.alertService?.confirm(
|
||||
|
||||
@@ -20,12 +20,8 @@ export const Settings = (props: Props) => {
|
||||
|
||||
// State
|
||||
const [hasPasscode, setHasPasscode] = useState(() => Boolean(application?.hasPasscode()))
|
||||
const [protectionsAvailable, setProtectionsAvailable] = useState(
|
||||
application?.hasProtectionSources()
|
||||
)
|
||||
const [encryptionAvailable, setEncryptionAvailable] = useState(() =>
|
||||
application?.isEncryptionAvailable()
|
||||
)
|
||||
const [protectionsAvailable, setProtectionsAvailable] = useState(application?.hasProtectionSources())
|
||||
const [encryptionAvailable, setEncryptionAvailable] = useState(() => application?.isEncryptionAvailable())
|
||||
|
||||
const updateProtectionsAvailable = useCallback(() => {
|
||||
setProtectionsAvailable(application?.hasProtectionSources())
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import { SnIcon } from '@Root/Components/SnIcon'
|
||||
import { useSafeApplicationContext } from '@Root/Hooks/useSafeApplicationContext'
|
||||
import {
|
||||
CantLoadActionsText,
|
||||
CreateBlogContainer,
|
||||
ListedItemRow,
|
||||
styles,
|
||||
} from '@Root/Screens/SideMenu/Listed.styled'
|
||||
import { CantLoadActionsText, CreateBlogContainer, ListedItemRow, styles } from '@Root/Screens/SideMenu/Listed.styled'
|
||||
import { SideMenuCell } from '@Root/Screens/SideMenu/SideMenuCell'
|
||||
import { SideMenuOptionIconDescriptionType } from '@Root/Screens/SideMenu/SideMenuSection'
|
||||
import { Action, ButtonType, ListedAccount, ListedAccountInfo, SNNote } from '@standardnotes/snjs'
|
||||
@@ -28,9 +23,7 @@ export const Listed: FC<TProps> = ({ note }) => {
|
||||
|
||||
const [listedAccounts, setListedAccounts] = useState<ListedAccount[]>([])
|
||||
const [listedAccountDetails, setListedAccountDetails] = useState<TListedAccountItem[]>([])
|
||||
const [authorUrlWithInProgressAction, setAuthorUrlWithInProgressAction] = useState<string | null>(
|
||||
null
|
||||
)
|
||||
const [authorUrlWithInProgressAction, setAuthorUrlWithInProgressAction] = useState<string | null>(null)
|
||||
|
||||
const { showActionSheet } = useCustomActionSheet()
|
||||
|
||||
@@ -41,9 +34,7 @@ export const Listed: FC<TProps> = ({ note }) => {
|
||||
for (const listedAccountItem of accounts) {
|
||||
const listedItemInfo = await application.getListedAccountInfo(listedAccountItem, note?.uuid)
|
||||
|
||||
listedAccountsArray.push(
|
||||
listedItemInfo ? listedItemInfo : { display_name: listedAccountItem.authorId }
|
||||
)
|
||||
listedAccountsArray.push(listedItemInfo ? listedItemInfo : { display_name: listedAccountItem.authorId })
|
||||
}
|
||||
return listedAccountsArray
|
||||
},
|
||||
@@ -124,9 +115,7 @@ export const Listed: FC<TProps> = ({ note }) => {
|
||||
setAuthorUrlWithInProgressAction(null)
|
||||
return
|
||||
}
|
||||
const listedDetails = (await getListedAccountsDetails(
|
||||
listedAccounts
|
||||
)) as TListedAccountItem[]
|
||||
const listedDetails = (await getListedAccountsDetails(listedAccounts)) as TListedAccountItem[]
|
||||
setListedAccountDetails(listedDetails)
|
||||
|
||||
showActionsMenu(listedDetails[index], index)
|
||||
@@ -159,10 +148,9 @@ export const Listed: FC<TProps> = ({ note }) => {
|
||||
value: <SnIcon type={'notes'} style={styles.blogItemIcon} />,
|
||||
}}
|
||||
/>
|
||||
{isActionInProgress &&
|
||||
(item as ListedAccountInfo).author_url === authorUrlWithInProgressAction && (
|
||||
<ActivityIndicator style={styles.blogActionInProgressIndicator} />
|
||||
)}
|
||||
{isActionInProgress && (item as ListedAccountInfo).author_url === authorUrlWithInProgressAction && (
|
||||
<ActivityIndicator style={styles.blogActionInProgressIndicator} />
|
||||
)}
|
||||
</ListedItemRow>
|
||||
{!isLoading && !doesListedItemHaveActions(item) && (
|
||||
<CantLoadActionsText>Unable to load actions</CantLoadActionsText>
|
||||
@@ -183,9 +171,7 @@ export const Listed: FC<TProps> = ({ note }) => {
|
||||
value: <SnIcon type={'user-add'} style={styles.blogItemIcon} />,
|
||||
}}
|
||||
/>
|
||||
{isRequestingAccount && (
|
||||
<ActivityIndicator style={styles.blogActionInProgressIndicator} />
|
||||
)}
|
||||
{isRequestingAccount && <ActivityIndicator style={styles.blogActionInProgressIndicator} />}
|
||||
</ListedItemRow>
|
||||
<ListedItemRow>
|
||||
<SideMenuCell
|
||||
|
||||
@@ -16,11 +16,7 @@ import Icon from 'react-native-vector-icons/Ionicons'
|
||||
import { ThemeContext } from 'styled-components'
|
||||
import { FirstSafeAreaView, MainSafeAreaView, useStyles } from './MainSideMenu.styled'
|
||||
import { SideMenuHero } from './SideMenuHero'
|
||||
import {
|
||||
SideMenuOption,
|
||||
SideMenuOptionIconDescriptionType,
|
||||
SideMenuSection,
|
||||
} from './SideMenuSection'
|
||||
import { SideMenuOption, SideMenuOptionIconDescriptionType, SideMenuSection } from './SideMenuSection'
|
||||
import { TagSelectionList } from './TagSelectionList'
|
||||
|
||||
type Props = {
|
||||
@@ -252,11 +248,7 @@ export const MainSideMenu = React.memo(({ drawerRef }: Props) => {
|
||||
<Fragment>
|
||||
<FirstSafeAreaView />
|
||||
<MainSafeAreaView>
|
||||
<SideMenuHero
|
||||
testID="settingsButton"
|
||||
onPress={openSettings}
|
||||
onOutOfSyncPress={outOfSyncPressed}
|
||||
/>
|
||||
<SideMenuHero testID="settingsButton" onPress={openSettings} onOutOfSyncPress={outOfSyncPressed} />
|
||||
<FlatList
|
||||
style={styles.sections}
|
||||
data={['themes-section', 'views-section', 'tags-section'].map(key => ({
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { associateComponentWithNote } from '@Lib/ComponentManager'
|
||||
import {
|
||||
useChangeNote,
|
||||
useDeleteNoteWithPrivileges,
|
||||
useProtectOrUnprotectNote,
|
||||
} from '@Lib/SnjsHelperHooks'
|
||||
import { useChangeNote, useDeleteNoteWithPrivileges, useProtectOrUnprotectNote } from '@Lib/SnjsHelperHooks'
|
||||
import { isUnfinishedFeaturesEnabled } from '@Lib/Utils'
|
||||
import { useFocusEffect, useNavigation } from '@react-navigation/native'
|
||||
import { TEnvironment } from '@Root/App'
|
||||
@@ -50,11 +46,7 @@ import DrawerLayout from 'react-native-gesture-handler/DrawerLayout'
|
||||
import Icon from 'react-native-vector-icons/Ionicons'
|
||||
import { ThemeContext } from 'styled-components'
|
||||
import { SafeAreaContainer, useStyles } from './NoteSideMenu.styled'
|
||||
import {
|
||||
SideMenuOption,
|
||||
SideMenuOptionIconDescriptionType,
|
||||
SideMenuSection,
|
||||
} from './SideMenuSection'
|
||||
import { SideMenuOption, SideMenuOptionIconDescriptionType, SideMenuSection } from './SideMenuSection'
|
||||
import { TagSelectionList } from './TagSelectionList'
|
||||
|
||||
function sortAlphabetically(array: SNComponent[]): SNComponent[] {
|
||||
@@ -74,9 +66,7 @@ function useEditorComponents(): SNComponent[] {
|
||||
const [components, setComponents] = useState<SNComponent[]>([])
|
||||
useEffect(() => {
|
||||
const removeComponentsObserver = application.streamItems(ContentType.Component, () => {
|
||||
const displayComponents = sortAlphabetically(
|
||||
application.componentManager.componentsForArea(ComponentArea.Editor)
|
||||
)
|
||||
const displayComponents = sortAlphabetically(application.componentManager.componentsForArea(ComponentArea.Editor))
|
||||
setComponents(displayComponents)
|
||||
})
|
||||
return () => {
|
||||
@@ -108,12 +98,9 @@ export const NoteSideMenu = React.memo((props: Props) => {
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const removeEventObserver = application.addSingleEventObserver(
|
||||
ApplicationEvent.PreferencesChanged,
|
||||
async () => {
|
||||
setShouldAddTagHierachy(application.getPreference(PrefKey.NoteAddToParentFolders, true))
|
||||
}
|
||||
)
|
||||
const removeEventObserver = application.addSingleEventObserver(ApplicationEvent.PreferencesChanged, async () => {
|
||||
setShouldAddTagHierachy(application.getPreference(PrefKey.NoteAddToParentFolders, true))
|
||||
})
|
||||
|
||||
return () => {
|
||||
removeEventObserver()
|
||||
@@ -276,10 +263,7 @@ export const NoteSideMenu = React.memo((props: Props) => {
|
||||
false
|
||||
)
|
||||
}
|
||||
if (
|
||||
activeEditorComponent?.isExplicitlyEnabledForItem(note!.uuid) ||
|
||||
activeEditorComponent?.isMobileDefault
|
||||
) {
|
||||
if (activeEditorComponent?.isExplicitlyEnabledForItem(note!.uuid) || activeEditorComponent?.isMobileDefault) {
|
||||
await disassociateComponentWithCurrentNote(activeEditorComponent)
|
||||
}
|
||||
} else if (selectedComponent.area === ComponentArea.Editor) {
|
||||
@@ -632,19 +616,15 @@ export const NoteSideMenu = React.memo((props: Props) => {
|
||||
selectedTags,
|
||||
}))}
|
||||
renderItem={({ item }) => {
|
||||
const { OptionsSection, EditorsSection, ListedSection, TagsSection, FilesSection } =
|
||||
MenuSections
|
||||
const { OptionsSection, EditorsSection, ListedSection, TagsSection, FilesSection } = MenuSections
|
||||
|
||||
if (
|
||||
item.key === FilesSection &&
|
||||
(isEntitledToFiles || isUnfinishedFeaturesEnabled(props.env))
|
||||
) {
|
||||
if (item.key === FilesSection && (isEntitledToFiles || isUnfinishedFeaturesEnabled(props.env))) {
|
||||
return (
|
||||
<SideMenuSection
|
||||
title={'Files'}
|
||||
customCollapsedLabel={`${
|
||||
attachedFilesLength ? `${attachedFilesLength}` : 'No'
|
||||
} attached file${attachedFilesLength === 1 ? '' : 's'}`}
|
||||
customCollapsedLabel={`${attachedFilesLength ? `${attachedFilesLength}` : 'No'} attached file${
|
||||
attachedFilesLength === 1 ? '' : 's'
|
||||
}`}
|
||||
collapsed={false}
|
||||
>
|
||||
<Files note={note} />
|
||||
@@ -655,9 +635,7 @@ export const NoteSideMenu = React.memo((props: Props) => {
|
||||
return <SideMenuSection title="Options" options={item.noteOptions} />
|
||||
}
|
||||
if (item.key === EditorsSection) {
|
||||
return (
|
||||
<SideMenuSection title="Editors" options={item.editorComponents} collapsed={true} />
|
||||
)
|
||||
return <SideMenuSection title="Editors" options={item.editorComponents} collapsed={true} />
|
||||
}
|
||||
if (item.key === ListedSection) {
|
||||
return (
|
||||
@@ -674,9 +652,7 @@ export const NoteSideMenu = React.memo((props: Props) => {
|
||||
contentType={ContentType.Tag}
|
||||
onTagSelect={tag => item.onTagSelect(tag, shouldAddTagHierarchy)}
|
||||
selectedTags={item.selectedTags}
|
||||
emptyPlaceholder={
|
||||
'Create a new tag using the tag button in the bottom right corner.'
|
||||
}
|
||||
emptyPlaceholder={'Create a new tag using the tag button in the bottom right corner.'}
|
||||
/>
|
||||
</SideMenuSection>
|
||||
)
|
||||
|
||||
@@ -71,9 +71,7 @@ export const SideMenuCell: React.FC<SideMenuOption> = props => {
|
||||
>
|
||||
<CellContent iconSide={iconSide} style={props.cellContentStyle || {}}>
|
||||
{iconSide === 'left' && (
|
||||
<IconContainerLeft>
|
||||
{renderIcon(props.iconDesc, theme.stylekitInfoColor)}
|
||||
</IconContainerLeft>
|
||||
<IconContainerLeft>{renderIcon(props.iconDesc, theme.stylekitInfoColor)}</IconContainerLeft>
|
||||
)}
|
||||
|
||||
<TextContainer selected={props.selected} isSubtext={Boolean(props.subtext)}>
|
||||
@@ -88,9 +86,7 @@ export const SideMenuCell: React.FC<SideMenuOption> = props => {
|
||||
{props.children}
|
||||
|
||||
{iconSide === 'right' && (
|
||||
<IconContainerRight>
|
||||
{renderIcon(props.iconDesc, theme.stylekitInfoColor)}
|
||||
</IconContainerRight>
|
||||
<IconContainerRight>{renderIcon(props.iconDesc, theme.stylekitInfoColor)}</IconContainerRight>
|
||||
)}
|
||||
</CellContent>
|
||||
</Touchable>
|
||||
|
||||
@@ -5,15 +5,7 @@ import { ContentType } from '@standardnotes/snjs'
|
||||
import React, { useContext, useEffect, useMemo, useState } from 'react'
|
||||
import { ViewProps } from 'react-native'
|
||||
import { ThemeContext } from 'styled-components'
|
||||
import {
|
||||
Cell,
|
||||
IconCircle,
|
||||
OutOfSyncContainer,
|
||||
OutOfSyncLabel,
|
||||
SubTitle,
|
||||
Title,
|
||||
Touchable,
|
||||
} from './SideMenuHero.styled'
|
||||
import { Cell, IconCircle, OutOfSyncContainer, OutOfSyncLabel, SubTitle, Title, Touchable } from './SideMenuHero.styled'
|
||||
|
||||
type Props = {
|
||||
onPress: () => void
|
||||
@@ -78,11 +70,7 @@ export const SideMenuHero: React.FC<Props> = props => {
|
||||
{isOutOfSync && (
|
||||
<OutOfSyncContainer onPress={props.onOutOfSyncPress}>
|
||||
<IconCircle>
|
||||
<Circle
|
||||
size={10}
|
||||
backgroundColor={theme.stylekitWarningColor}
|
||||
borderColor={theme.stylekitWarningColor}
|
||||
/>
|
||||
<Circle size={10} backgroundColor={theme.stylekitWarningColor} borderColor={theme.stylekitWarningColor} />
|
||||
</IconCircle>
|
||||
<OutOfSyncLabel>Potentially Out of Sync</OutOfSyncLabel>
|
||||
</OutOfSyncContainer>
|
||||
|
||||
@@ -3,14 +3,7 @@ import { AppStackNavigationProp } from '@Root/AppStack'
|
||||
import { useSafeApplicationContext } from '@Root/Hooks/useSafeApplicationContext'
|
||||
import { SCREEN_COMPOSE, SCREEN_INPUT_MODAL_TAG } from '@Root/Screens/screens'
|
||||
import { SideMenuOptionIconDescriptionType } from '@Root/Screens/SideMenu/SideMenuSection'
|
||||
import {
|
||||
ButtonType,
|
||||
CollectionSort,
|
||||
ContentType,
|
||||
FindItem,
|
||||
SmartView,
|
||||
SNTag,
|
||||
} from '@standardnotes/snjs'
|
||||
import { ButtonType, CollectionSort, ContentType, FindItem, SmartView, SNTag } from '@standardnotes/snjs'
|
||||
import { useCustomActionSheet } from '@Style/CustomActionSheet'
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { FlatList, ListRenderItem } from 'react-native'
|
||||
@@ -117,9 +110,7 @@ export const TagSelectionList = React.memo(
|
||||
children = (tags as SNTag[]).filter((tag: SNTag) => rawChildren.includes(tag.uuid))
|
||||
}
|
||||
|
||||
const isSelected = selectedTags.some(
|
||||
(selectedTag: SNTag | SmartView) => selectedTag.uuid === item.uuid
|
||||
)
|
||||
const isSelected = selectedTags.some((selectedTag: SNTag | SmartView) => selectedTag.uuid === item.uuid)
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -32,16 +32,8 @@ export const ViewProtectedNote = ({
|
||||
return (
|
||||
<Container>
|
||||
<Title>This note is protected</Title>
|
||||
<Text>
|
||||
Add a passcode or biometrics lock, or create an account, to require authentication to view
|
||||
this note.
|
||||
</Text>
|
||||
<Button
|
||||
label="Go to Settings"
|
||||
primary={true}
|
||||
fullWidth={true}
|
||||
onPress={onPressGoToSettings}
|
||||
/>
|
||||
<Text>Add a passcode or biometrics lock, or create an account, to require authentication to view this note.</Text>
|
||||
<Button label="Go to Settings" primary={true} fullWidth={true} onPress={onPressGoToSettings} />
|
||||
<Button label="View" fullWidth={true} last={true} onPress={onPressView} />
|
||||
</Container>
|
||||
)
|
||||
|
||||
@@ -19,13 +19,7 @@ import THEME_DARK_JSON from './Themes/blue-dark.json'
|
||||
import THEME_BLUE_JSON from './Themes/blue.json'
|
||||
import THEME_RED_JSON from './Themes/red.json'
|
||||
import { MobileThemeVariables } from './Themes/styled-components'
|
||||
import {
|
||||
DARK_CONTENT,
|
||||
getColorLuminosity,
|
||||
keyboardColorForTheme,
|
||||
LIGHT_CONTENT,
|
||||
statusBarColorForTheme,
|
||||
} from './Utils'
|
||||
import { DARK_CONTENT, getColorLuminosity, keyboardColorForTheme, LIGHT_CONTENT, statusBarColorForTheme } from './Utils'
|
||||
|
||||
const LIGHT_THEME_KEY = 'lightThemeKey'
|
||||
const DARK_THEME_KEY = 'darkThemeKey'
|
||||
@@ -243,10 +237,7 @@ export class ThemeService {
|
||||
}
|
||||
|
||||
public async getThemeForMode(mode: 'light' | 'dark') {
|
||||
return this.application?.getValue(
|
||||
mode === 'dark' ? DARK_THEME_KEY : LIGHT_THEME_KEY,
|
||||
StorageValueModes.Nonwrapped
|
||||
)
|
||||
return this.application?.getValue(mode === 'dark' ? DARK_THEME_KEY : LIGHT_THEME_KEY, StorageValueModes.Nonwrapped)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,8 +251,7 @@ export class ThemeService {
|
||||
}
|
||||
|
||||
private setDefaultTheme() {
|
||||
const defaultThemeId =
|
||||
this.getColorScheme() === 'dark' ? SystemThemeTint.Dark : SystemThemeTint.Blue
|
||||
const defaultThemeId = this.getColorScheme() === 'dark' ? SystemThemeTint.Dark : SystemThemeTint.Blue
|
||||
|
||||
this.setActiveTheme(defaultThemeId)
|
||||
}
|
||||
@@ -321,9 +311,7 @@ export class ThemeService {
|
||||
...theme.mobileContent.variables,
|
||||
...baseVariables,
|
||||
}
|
||||
const luminosity =
|
||||
theme.mobileContent.luminosity ||
|
||||
getColorLuminosity(variables.stylekitContrastBackgroundColor)
|
||||
const luminosity = theme.mobileContent.luminosity || getColorLuminosity(variables.stylekitContrastBackgroundColor)
|
||||
return new MobileTheme(
|
||||
theme.payload.copy({
|
||||
content: {
|
||||
@@ -372,9 +360,7 @@ export class ThemeService {
|
||||
if (Platform.Version <= 22) {
|
||||
StatusBar.setBackgroundColor('#000000')
|
||||
} else {
|
||||
StatusBar.setBackgroundColor(
|
||||
theme.mobileContent.variables.stylekitContrastBackgroundColor
|
||||
)
|
||||
StatusBar.setBackgroundColor(theme.mobileContent.variables.stylekitContrastBackgroundColor)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -476,8 +462,7 @@ export class ThemeService {
|
||||
}
|
||||
|
||||
private async loadCachedThemes() {
|
||||
const rawValue =
|
||||
(await this.application!.getValue(CACHED_THEMES_KEY, StorageValueModes.Nonwrapped)) || []
|
||||
const rawValue = (await this.application!.getValue(CACHED_THEMES_KEY, StorageValueModes.Nonwrapped)) || []
|
||||
|
||||
const themes = (rawValue as DecryptedTransferPayload<ComponentContent>[]).map(rawPayload => {
|
||||
const payload = new DecryptedPayload<ComponentContent>(rawPayload)
|
||||
|
||||
Reference in New Issue
Block a user