fix: Fixes issue where lock screen would not use previously active theme (#2372)
This commit is contained in:
@@ -6,7 +6,7 @@ import { WebApplication } from '@/Application/WebApplication'
|
||||
import {
|
||||
UIFeature,
|
||||
EditorFeatureDescription,
|
||||
FeatureIdentifier,
|
||||
NativeFeatureIdentifier,
|
||||
IframeComponentFeatureDescription,
|
||||
NoteMutator,
|
||||
NoteType,
|
||||
@@ -100,7 +100,7 @@ const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
|
||||
|
||||
setCurrentFeature(application.componentManager.editorForNote(note))
|
||||
|
||||
if (uiFeature.featureIdentifier === FeatureIdentifier.PlainEditor) {
|
||||
if (uiFeature.featureIdentifier === NativeFeatureIdentifier.TYPES.PlainEditor) {
|
||||
reloadFont(application.getPreference(PrefKey.EditorMonospaceEnabled))
|
||||
}
|
||||
},
|
||||
@@ -211,7 +211,7 @@ const ChangeEditorMenu: FunctionComponent<ChangeEditorMenuProps> = ({
|
||||
|
||||
return (
|
||||
<MenuRadioButtonItem
|
||||
key={menuItem.uiFeature.uniqueIdentifier}
|
||||
key={menuItem.uiFeature.uniqueIdentifier.value}
|
||||
onClick={onClickEditorItem}
|
||||
className={'flex-row-reversed py-2'}
|
||||
checked={isSelected(menuItem)}
|
||||
|
||||
@@ -141,7 +141,7 @@ const ChangeEditorMultipleMenu = ({ application, notes, setDisableClickOutside }
|
||||
}
|
||||
return (
|
||||
<MenuItem
|
||||
key={item.uiFeature.uniqueIdentifier}
|
||||
key={item.uiFeature.uniqueIdentifier.value}
|
||||
onClick={onClickEditorItem}
|
||||
className={'flex-row-reversed py-2'}
|
||||
>
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
ApplicationEvent,
|
||||
ContentType,
|
||||
DecryptedItem,
|
||||
FeatureIdentifier,
|
||||
NativeFeatureIdentifier,
|
||||
FeatureStatus,
|
||||
NoteContent,
|
||||
NoteType,
|
||||
@@ -61,7 +61,10 @@ const ClipperView = ({
|
||||
|
||||
const [user, setUser] = useState(() => application.getUser())
|
||||
const [isEntitledToExtension, setIsEntitled] = useState(
|
||||
() => application.features.getFeatureStatus(FeatureIdentifier.Extension) === FeatureStatus.Entitled,
|
||||
() =>
|
||||
application.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.Clipper).getValue(),
|
||||
) === FeatureStatus.Entitled,
|
||||
)
|
||||
const isEntitledRef = useStateRef(isEntitledToExtension)
|
||||
const hasSubscription = application.hasValidFirstPartySubscription()
|
||||
@@ -72,10 +75,18 @@ const ClipperView = ({
|
||||
case ApplicationEvent.SignedOut:
|
||||
case ApplicationEvent.UserRolesChanged:
|
||||
setUser(application.getUser())
|
||||
setIsEntitled(application.features.getFeatureStatus(FeatureIdentifier.Extension) === FeatureStatus.Entitled)
|
||||
setIsEntitled(
|
||||
application.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.Clipper).getValue(),
|
||||
) === FeatureStatus.Entitled,
|
||||
)
|
||||
break
|
||||
case ApplicationEvent.FeaturesAvailabilityChanged:
|
||||
setIsEntitled(application.features.getFeatureStatus(FeatureIdentifier.Extension) === FeatureStatus.Entitled)
|
||||
setIsEntitled(
|
||||
application.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.Clipper).getValue(),
|
||||
) === FeatureStatus.Entitled,
|
||||
)
|
||||
break
|
||||
}
|
||||
})
|
||||
@@ -212,7 +223,7 @@ const ClipperView = ({
|
||||
const note = application.items.createTemplateItem<NoteContent, SNNote>(ContentType.TYPES.Note, {
|
||||
title: clipPayload.title,
|
||||
text: editorStateJSON,
|
||||
editorIdentifier: FeatureIdentifier.SuperEditor,
|
||||
editorIdentifier: NativeFeatureIdentifier.TYPES.SuperEditor,
|
||||
noteType: NoteType.Super,
|
||||
references: [],
|
||||
})
|
||||
|
||||
@@ -168,7 +168,7 @@ const IframeFeatureView: FunctionComponent<Props> = ({ onLoad, componentViewer,
|
||||
const unregisterDesktopObserver = application
|
||||
.getDesktopService()
|
||||
?.registerUpdateObserver((updatedComponent: ComponentInterface) => {
|
||||
if (updatedComponent.uuid === uiFeature.uniqueIdentifier) {
|
||||
if (updatedComponent.uuid === uiFeature.uniqueIdentifier.value) {
|
||||
requestReload?.(componentViewer)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import {
|
||||
FeatureIdentifier,
|
||||
NativeFeatureIdentifier,
|
||||
NewNoteTitleFormat,
|
||||
PrefKey,
|
||||
EditorIdentifier,
|
||||
TagPreferences,
|
||||
isSmartView,
|
||||
isSystemView,
|
||||
SystemViewId,
|
||||
PrefDefaults,
|
||||
FeatureStatus,
|
||||
Uuid,
|
||||
} from '@standardnotes/snjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { ChangeEventHandler, FunctionComponent, useCallback, useEffect, useRef, useState } from 'react'
|
||||
@@ -17,6 +17,11 @@ import { DropdownItem } from '@/Components/Dropdown/DropdownItem'
|
||||
import { WebApplication } from '@/Application/WebApplication'
|
||||
import { AnyTag } from '@/Controllers/Navigation/AnyTagType'
|
||||
import { PreferenceMode } from './PreferenceMode'
|
||||
import { EditorOption, getDropdownItemsForAllEditors } from '@/Utils/DropdownItemsForEditors'
|
||||
import { classNames } from '@standardnotes/utils'
|
||||
import { NoteTitleFormatOptions } from './NoteTitleFormatOptions'
|
||||
import { usePremiumModal } from '@/Hooks/usePremiumModal'
|
||||
|
||||
import dayjs from 'dayjs'
|
||||
import dayjsAdvancedFormat from 'dayjs/plugin/advancedFormat'
|
||||
import dayjsUTC from 'dayjs/plugin/utc'
|
||||
@@ -24,11 +29,6 @@ import dayjsTimezone from 'dayjs/plugin/timezone'
|
||||
dayjs.extend(dayjsAdvancedFormat)
|
||||
dayjs.extend(dayjsUTC)
|
||||
dayjs.extend(dayjsTimezone)
|
||||
import { EditorOption, getDropdownItemsForAllEditors } from '@/Utils/DropdownItemsForEditors'
|
||||
import { classNames } from '@standardnotes/utils'
|
||||
import { NoteTitleFormatOptions } from './NoteTitleFormatOptions'
|
||||
|
||||
import { usePremiumModal } from '@/Hooks/usePremiumModal'
|
||||
|
||||
const PrefChangeDebounceTimeInMs = 25
|
||||
|
||||
@@ -57,8 +57,8 @@ const NewNotePreferences: FunctionComponent<Props> = ({
|
||||
: selectedTag.preferences
|
||||
|
||||
const [editorItems, setEditorItems] = useState<DropdownItem[]>([])
|
||||
const [defaultEditorIdentifier, setDefaultEditorIdentifier] = useState<EditorIdentifier>(
|
||||
FeatureIdentifier.PlainEditor,
|
||||
const [defaultEditorIdentifier, setDefaultEditorIdentifier] = useState<string>(
|
||||
NativeFeatureIdentifier.TYPES.PlainEditor,
|
||||
)
|
||||
const [newNoteTitleFormat, setNewNoteTitleFormat] = useState<NewNoteTitleFormat>(
|
||||
NewNoteTitleFormat.CurrentDateAndTime,
|
||||
@@ -121,14 +121,19 @@ const NewNotePreferences: FunctionComponent<Props> = ({
|
||||
|
||||
const selectEditorForNewNoteDefault = useCallback(
|
||||
(value: EditorOption['value']) => {
|
||||
if (application.features.getFeatureStatus(value) !== FeatureStatus.Entitled) {
|
||||
const uuid = Uuid.create(value)
|
||||
const feature = NativeFeatureIdentifier.create(value)
|
||||
if (
|
||||
application.features.getFeatureStatus(!uuid.isFailed() ? uuid.getValue() : feature.getValue()) !==
|
||||
FeatureStatus.Entitled
|
||||
) {
|
||||
const editorItem = editorItems.find((item) => item.value === value)
|
||||
if (editorItem) {
|
||||
premiumModal.activate(editorItem.label)
|
||||
}
|
||||
return
|
||||
}
|
||||
setDefaultEditorIdentifier(value as FeatureIdentifier)
|
||||
setDefaultEditorIdentifier(value)
|
||||
|
||||
if (mode === 'global') {
|
||||
void application.setPreference(PrefKey.DefaultEditorIdentifier, value)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { WebApplication } from '@/Application/WebApplication'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
import {
|
||||
MutatorService,
|
||||
SNComponentManager,
|
||||
SNComponent,
|
||||
SNTag,
|
||||
@@ -11,7 +10,7 @@ import {
|
||||
ItemManagerInterface,
|
||||
MutatorClientInterface,
|
||||
} from '@standardnotes/snjs'
|
||||
import { FeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { NativeFeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { NoteViewController } from './NoteViewController'
|
||||
|
||||
describe('note view controller', () => {
|
||||
@@ -40,7 +39,9 @@ describe('note view controller', () => {
|
||||
})
|
||||
|
||||
it('should create notes with plaintext note type', async () => {
|
||||
application.componentManager.getDefaultEditorIdentifier = jest.fn().mockReturnValue(FeatureIdentifier.PlainEditor)
|
||||
application.componentManager.getDefaultEditorIdentifier = jest
|
||||
.fn()
|
||||
.mockReturnValue(NativeFeatureIdentifier.TYPES.PlainEditor)
|
||||
|
||||
const controller = new NoteViewController(application)
|
||||
await controller.initialize()
|
||||
@@ -55,13 +56,13 @@ describe('note view controller', () => {
|
||||
it('should create notes with markdown note type', async () => {
|
||||
application.items.getDisplayableComponents = jest.fn().mockReturnValue([
|
||||
{
|
||||
identifier: FeatureIdentifier.MarkdownProEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.MarkdownProEditor,
|
||||
} as SNComponent,
|
||||
])
|
||||
|
||||
application.componentManager.getDefaultEditorIdentifier = jest
|
||||
.fn()
|
||||
.mockReturnValue(FeatureIdentifier.MarkdownProEditor)
|
||||
.mockReturnValue(NativeFeatureIdentifier.TYPES.MarkdownProEditor)
|
||||
|
||||
const controller = new NoteViewController(application)
|
||||
await controller.initialize()
|
||||
@@ -74,7 +75,9 @@ describe('note view controller', () => {
|
||||
})
|
||||
|
||||
it('should add tag to note if default tag is set', async () => {
|
||||
application.componentManager.getDefaultEditorIdentifier = jest.fn().mockReturnValue(FeatureIdentifier.PlainEditor)
|
||||
application.componentManager.getDefaultEditorIdentifier = jest
|
||||
.fn()
|
||||
.mockReturnValue(NativeFeatureIdentifier.TYPES.PlainEditor)
|
||||
|
||||
const tag = {
|
||||
uuid: 'tag-uuid',
|
||||
|
||||
@@ -8,7 +8,7 @@ import { ElementIds } from '@/Constants/ElementIDs'
|
||||
import { StringDeleteNote, STRING_DELETE_LOCKED_ATTEMPT, STRING_DELETE_PLACEHOLDER_ATTEMPT } from '@/Constants/Strings'
|
||||
import { log, LoggingDomain } from '@/Logging'
|
||||
import { debounce, isDesktopApplication, isMobileScreen } from '@/Utils'
|
||||
import { classNames, pluralize } from '@standardnotes/utils'
|
||||
import { classNames, compareArrayReferences, pluralize } from '@standardnotes/utils'
|
||||
import {
|
||||
ApplicationEvent,
|
||||
ComponentArea,
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
EditorLineWidth,
|
||||
IframeComponentFeatureDescription,
|
||||
isUIFeatureAnIframeFeature,
|
||||
isPayloadSourceInternalChange,
|
||||
isPayloadSourceRetrieved,
|
||||
NoteType,
|
||||
PayloadEmitSource,
|
||||
@@ -94,7 +93,6 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
|
||||
onEditorComponentLoad?: () => void
|
||||
|
||||
private removeTrashKeyObserver?: () => void
|
||||
private removeComponentStreamObserver?: () => void
|
||||
private removeNoteStreamObserver?: () => void
|
||||
private removeComponentManagerObserver?: () => void
|
||||
private removeInnerNoteObserver?: () => void
|
||||
@@ -144,9 +142,6 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
|
||||
super.deinit()
|
||||
;(this.controller as unknown) = undefined
|
||||
|
||||
this.removeComponentStreamObserver?.()
|
||||
;(this.removeComponentStreamObserver as unknown) = undefined
|
||||
|
||||
this.removeNoteStreamObserver?.()
|
||||
;(this.removeNoteStreamObserver as unknown) = undefined
|
||||
|
||||
@@ -187,14 +182,19 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
|
||||
}
|
||||
|
||||
override shouldComponentUpdate(_nextProps: Readonly<NoteViewProps>, nextState: Readonly<State>): boolean {
|
||||
const complexObjects: (keyof State)[] = ['availableStackComponents', 'stackComponentViewers']
|
||||
for (const key of Object.keys(nextState) as (keyof State)[]) {
|
||||
if (complexObjects.includes(key)) {
|
||||
continue
|
||||
}
|
||||
const prevValue = this.state[key]
|
||||
const nextValue = nextState[key]
|
||||
|
||||
if (Array.isArray(prevValue) && Array.isArray(nextValue)) {
|
||||
const areEqual = compareArrayReferences<unknown>(prevValue, nextValue)
|
||||
if (!areEqual) {
|
||||
log(LoggingDomain.NoteView, 'Rendering due to array state change', key, prevValue, nextValue)
|
||||
return true
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (prevValue !== nextValue) {
|
||||
log(LoggingDomain.NoteView, 'Rendering due to state change', key, prevValue, nextValue)
|
||||
return true
|
||||
@@ -340,7 +340,8 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
|
||||
|
||||
switch (eventName) {
|
||||
case ApplicationEvent.PreferencesChanged:
|
||||
this.reloadPreferences().catch(console.error)
|
||||
void this.reloadPreferences()
|
||||
void this.reloadStackComponents()
|
||||
break
|
||||
case ApplicationEvent.HighLatencySync:
|
||||
this.setState({ syncTakingTooLong: true })
|
||||
@@ -428,23 +429,6 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
|
||||
}
|
||||
|
||||
streamItems() {
|
||||
this.removeComponentStreamObserver = this.application.streamItems(
|
||||
ContentType.TYPES.Component,
|
||||
async ({ source }) => {
|
||||
log(LoggingDomain.NoteView, 'On component stream observer', PayloadEmitSource[source])
|
||||
if (isPayloadSourceInternalChange(source) || source === PayloadEmitSource.InitialObserverRegistrationPush) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.note) {
|
||||
return
|
||||
}
|
||||
|
||||
await this.reloadStackComponents()
|
||||
this.debounceReloadEditorComponent()
|
||||
},
|
||||
)
|
||||
|
||||
this.removeNoteStreamObserver = this.application.streamItems<SNNote>(ContentType.TYPES.Note, async () => {
|
||||
if (!this.note) {
|
||||
return
|
||||
@@ -740,25 +724,22 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
|
||||
|
||||
async reloadStackComponents() {
|
||||
log(LoggingDomain.NoteView, 'Reload stack components')
|
||||
const stackComponents = sortAlphabetically(
|
||||
const enabledComponents = sortAlphabetically(
|
||||
this.application.componentManager
|
||||
.thirdPartyComponentsForArea(ComponentArea.EditorStack)
|
||||
.filter((component) => this.application.componentManager.isComponentActive(component)),
|
||||
)
|
||||
const enabledComponents = stackComponents.filter((component) => {
|
||||
return component.isExplicitlyEnabledForItem(this.note.uuid)
|
||||
})
|
||||
|
||||
const needsNewViewer = enabledComponents.filter((component) => {
|
||||
const hasExistingViewer = this.state.stackComponentViewers.find(
|
||||
(viewer) => viewer.componentUniqueIdentifier === component.uuid,
|
||||
(viewer) => viewer.componentUniqueIdentifier.value === component.uuid,
|
||||
)
|
||||
return !hasExistingViewer
|
||||
})
|
||||
|
||||
const needsDestroyViewer = this.state.stackComponentViewers.filter((viewer) => {
|
||||
const viewerComponentExistsInEnabledComponents = enabledComponents.find((component) => {
|
||||
return component.uuid === viewer.componentUniqueIdentifier
|
||||
return component.uuid === viewer.componentUniqueIdentifier.value
|
||||
})
|
||||
return !viewerComponentExistsInEnabledComponents
|
||||
})
|
||||
@@ -779,13 +760,15 @@ class NoteView extends AbstractComponent<NoteViewProps, State> {
|
||||
this.application.componentManager.destroyComponentViewer(viewer)
|
||||
}
|
||||
this.setState({
|
||||
availableStackComponents: stackComponents,
|
||||
availableStackComponents: enabledComponents,
|
||||
stackComponentViewers: newViewers,
|
||||
})
|
||||
}
|
||||
|
||||
stackComponentExpanded = (component: ComponentInterface): boolean => {
|
||||
return !!this.state.stackComponentViewers.find((viewer) => viewer.componentUniqueIdentifier === component.uuid)
|
||||
return !!this.state.stackComponentViewers.find(
|
||||
(viewer) => viewer.componentUniqueIdentifier.value === component.uuid,
|
||||
)
|
||||
}
|
||||
|
||||
toggleStackComponent = async (component: ComponentInterface) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
FeatureIdentifier,
|
||||
NativeFeatureIdentifier,
|
||||
FeatureStatus,
|
||||
MuteMarketingEmailsOption,
|
||||
MuteSignInEmailsOption,
|
||||
@@ -28,7 +28,9 @@ const Email: FunctionComponent<Props> = ({ application }: Props) => {
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
const isMuteSignInEmailsFeatureAvailable =
|
||||
application.features.getFeatureStatus(FeatureIdentifier.SignInAlerts) === FeatureStatus.Entitled
|
||||
application.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.SignInAlerts).getValue(),
|
||||
) === FeatureStatus.Entitled
|
||||
|
||||
const updateSetting = async (settingName: SettingName, payload: string): Promise<boolean> => {
|
||||
try {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FeatureStatus, FeatureIdentifier } from '@standardnotes/snjs'
|
||||
import { FeatureStatus, NativeFeatureIdentifier } from '@standardnotes/snjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent, useState } from 'react'
|
||||
|
||||
@@ -29,8 +29,9 @@ const SubscriptionSharing: FunctionComponent<Props> = ({ application, viewContro
|
||||
const isReadOnlySession = application.sessions.isCurrentSessionReadOnly()
|
||||
|
||||
const isSubscriptionSharingFeatureAvailable =
|
||||
application.features.getFeatureStatus(FeatureIdentifier.SubscriptionSharing) === FeatureStatus.Entitled &&
|
||||
!isReadOnlySession
|
||||
application.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.SubscriptionSharing).getValue(),
|
||||
) === FeatureStatus.Entitled && !isReadOnlySession
|
||||
|
||||
const closeInviteDialog = () => setIsInviteDialogOpen(false)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { usePremiumModal } from '@/Hooks/usePremiumModal'
|
||||
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||
import Switch from '@/Components/Switch/Switch'
|
||||
import { WebApplication } from '@/Application/WebApplication'
|
||||
import { FeatureIdentifier, PrefKey, FeatureStatus, naturalSort, PrefDefaults } from '@standardnotes/snjs'
|
||||
import { PrefKey, FeatureStatus, naturalSort, PrefDefaults } from '@standardnotes/snjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { FunctionComponent, useEffect, useState } from 'react'
|
||||
import { Subtitle, Title, Text } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
@@ -50,7 +50,7 @@ const Appearance: FunctionComponent<Props> = ({ application }) => {
|
||||
label: theme.displayName as string,
|
||||
value: theme.featureIdentifier,
|
||||
icon:
|
||||
application.features.getFeatureStatus(theme.featureIdentifier) !== FeatureStatus.Entitled
|
||||
application.features.getFeatureStatus(theme.uniqueIdentifier) !== FeatureStatus.Entitled
|
||||
? PremiumFeatureIconName
|
||||
: undefined,
|
||||
}
|
||||
@@ -72,14 +72,10 @@ const Appearance: FunctionComponent<Props> = ({ application }) => {
|
||||
const toggleUseDeviceSettings = () => {
|
||||
application.setPreference(PrefKey.UseSystemColorScheme, !useDeviceSettings).catch(console.error)
|
||||
if (!application.getPreference(PrefKey.AutoLightThemeIdentifier)) {
|
||||
application
|
||||
.setPreference(PrefKey.AutoLightThemeIdentifier, autoLightTheme as FeatureIdentifier)
|
||||
.catch(console.error)
|
||||
application.setPreference(PrefKey.AutoLightThemeIdentifier, autoLightTheme).catch(console.error)
|
||||
}
|
||||
if (!application.getPreference(PrefKey.AutoDarkThemeIdentifier)) {
|
||||
application
|
||||
.setPreference(PrefKey.AutoDarkThemeIdentifier, autoDarkTheme as FeatureIdentifier)
|
||||
.catch(console.error)
|
||||
application.setPreference(PrefKey.AutoDarkThemeIdentifier, autoDarkTheme).catch(console.error)
|
||||
}
|
||||
setUseDeviceSettings(!useDeviceSettings)
|
||||
}
|
||||
@@ -90,7 +86,7 @@ const Appearance: FunctionComponent<Props> = ({ application }) => {
|
||||
premiumModal.activate(`${item.label} theme`)
|
||||
return
|
||||
}
|
||||
application.setPreference(PrefKey.AutoLightThemeIdentifier, value as FeatureIdentifier).catch(console.error)
|
||||
application.setPreference(PrefKey.AutoLightThemeIdentifier, value).catch(console.error)
|
||||
setAutoLightTheme(value)
|
||||
}
|
||||
|
||||
@@ -100,7 +96,7 @@ const Appearance: FunctionComponent<Props> = ({ application }) => {
|
||||
premiumModal.activate(`${item.label} theme`)
|
||||
return
|
||||
}
|
||||
application.setPreference(PrefKey.AutoDarkThemeIdentifier, value as FeatureIdentifier).catch(console.error)
|
||||
application.setPreference(PrefKey.AutoDarkThemeIdentifier, value).catch(console.error)
|
||||
setAutoDarkTheme(value)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Text, Title } from '@/Components/Preferences/PreferencesComponents/Cont
|
||||
import { WebApplication } from '@/Application/WebApplication'
|
||||
import {
|
||||
ApplicationEvent,
|
||||
FeatureIdentifier,
|
||||
NativeFeatureIdentifier,
|
||||
FeatureStatus,
|
||||
FindNativeFeature,
|
||||
PrefKey,
|
||||
@@ -17,7 +17,7 @@ import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||
import { MutuallyExclusiveMediaQueryBreakpoints, useMediaQuery } from '@/Hooks/useMediaQuery'
|
||||
|
||||
type ExperimentalFeatureItem = {
|
||||
identifier: FeatureIdentifier
|
||||
identifier: string
|
||||
name: string
|
||||
description: string
|
||||
isEnabled: boolean
|
||||
@@ -55,7 +55,9 @@ const LabsPane: FunctionComponent<Props> = ({ application }) => {
|
||||
name: feature?.name ?? featureIdentifier,
|
||||
description: feature?.description ?? '',
|
||||
isEnabled: application.features.isExperimentalFeatureEnabled(featureIdentifier),
|
||||
isEntitled: application.features.getFeatureStatus(featureIdentifier) === FeatureStatus.Entitled,
|
||||
isEntitled:
|
||||
application.features.getFeatureStatus(NativeFeatureIdentifier.create(featureIdentifier).getValue()) ===
|
||||
FeatureStatus.Entitled,
|
||||
}
|
||||
})
|
||||
setExperimentalFeatures(experimentalFeatures)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FeatureIdentifier, FeatureStatus } from '@standardnotes/snjs'
|
||||
import { NativeFeatureIdentifier, FeatureStatus } from '@standardnotes/snjs'
|
||||
|
||||
import { WebApplication } from '@/Application/WebApplication'
|
||||
import { ViewControllerManager } from '@/Controllers/ViewControllerManager'
|
||||
@@ -24,8 +24,9 @@ const Security: FunctionComponent<SecurityProps> = (props) => {
|
||||
const isNativeMobileWeb = props.application.isNativeMobileWeb()
|
||||
|
||||
const isU2FFeatureAvailable =
|
||||
props.application.features.getFeatureStatus(FeatureIdentifier.UniversalSecondFactor) === FeatureStatus.Entitled &&
|
||||
props.userProvider.getUser() !== undefined
|
||||
props.application.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.UniversalSecondFactor).getValue(),
|
||||
) === FeatureStatus.Entitled && props.userProvider.getUser() !== undefined
|
||||
|
||||
return (
|
||||
<PreferencesPane>
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
ComponentInterface,
|
||||
UIFeature,
|
||||
ContentType,
|
||||
FeatureIdentifier,
|
||||
NativeFeatureIdentifier,
|
||||
PreferencesServiceEvent,
|
||||
ThemeFeatureDescription,
|
||||
} from '@standardnotes/snjs'
|
||||
@@ -54,7 +54,7 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ quickSettingsMenuCont
|
||||
(component) =>
|
||||
!component.isTheme() &&
|
||||
[ComponentArea.EditorStack].includes(component.area) &&
|
||||
component.identifier !== FeatureIdentifier.DeprecatedFoldersComponent,
|
||||
component.identifier !== NativeFeatureIdentifier.TYPES.DeprecatedFoldersComponent,
|
||||
)
|
||||
|
||||
setEditorStackComponents(toggleableComponents)
|
||||
@@ -100,7 +100,7 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ quickSettingsMenuCont
|
||||
|
||||
const toggleEditorStackComponent = useCallback(
|
||||
(component: ComponentInterface) => {
|
||||
application.componentManager.toggleComponent(component).catch(console.error)
|
||||
void application.componentManager.toggleComponent(component)
|
||||
},
|
||||
[application],
|
||||
)
|
||||
@@ -141,7 +141,7 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ quickSettingsMenuCont
|
||||
Default
|
||||
</MenuRadioButtonItem>
|
||||
{themes.map((theme) => (
|
||||
<ThemesMenuButton uiFeature={theme} key={theme.uniqueIdentifier} />
|
||||
<ThemesMenuButton uiFeature={theme} key={theme.uniqueIdentifier.value} />
|
||||
))}
|
||||
<HorizontalSeparator classes="my-2" />
|
||||
<FocusModeSwitch
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { UIFeature, FeatureIdentifier, FeatureStatus, ThemeFeatureDescription } from '@standardnotes/snjs'
|
||||
import { UIFeature, NativeFeatureIdentifier, FeatureStatus, ThemeFeatureDescription } from '@standardnotes/snjs'
|
||||
import { FunctionComponent, MouseEventHandler, useCallback, useMemo } from 'react'
|
||||
import Icon from '@/Components/Icon/Icon'
|
||||
import { usePremiumModal } from '@/Hooks/usePremiumModal'
|
||||
@@ -26,8 +26,8 @@ const ThemesMenuButton: FunctionComponent<Props> = ({ uiFeature }) => {
|
||||
[application, uiFeature.featureIdentifier],
|
||||
)
|
||||
const isEntitledToTheme = useMemo(
|
||||
() => application.features.getFeatureStatus(uiFeature.featureIdentifier) === FeatureStatus.Entitled,
|
||||
[application, uiFeature.featureIdentifier],
|
||||
() => application.features.getFeatureStatus(uiFeature.uniqueIdentifier) === FeatureStatus.Entitled,
|
||||
[application, uiFeature.uniqueIdentifier],
|
||||
)
|
||||
const canActivateTheme = useMemo(() => isEntitledToTheme || isThirdPartyTheme, [isEntitledToTheme, isThirdPartyTheme])
|
||||
|
||||
@@ -55,10 +55,10 @@ const ThemesMenuButton: FunctionComponent<Props> = ({ uiFeature }) => {
|
||||
)
|
||||
|
||||
const isMobile = application.isNativeMobileWeb() || isMobileScreen()
|
||||
const shouldHideButton = uiFeature.featureIdentifier === FeatureIdentifier.DynamicTheme && isMobile
|
||||
const shouldHideButton = uiFeature.featureIdentifier === NativeFeatureIdentifier.TYPES.DynamicTheme && isMobile
|
||||
|
||||
const darkThemeShortcut = useMemo(() => {
|
||||
if (uiFeature.featureIdentifier === FeatureIdentifier.DarkTheme) {
|
||||
if (uiFeature.featureIdentifier === NativeFeatureIdentifier.TYPES.DarkTheme) {
|
||||
return commandService.keyboardShortcutForCommand(TOGGLE_DARK_MODE_COMMAND)
|
||||
}
|
||||
}, [commandService, uiFeature.featureIdentifier])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FeatureIdentifier } from '@standardnotes/features'
|
||||
import { NativeFeatureIdentifier } from '@standardnotes/features'
|
||||
import { NoteType, PredicateCompoundOperator, PredicateJsonForm } from '@standardnotes/snjs'
|
||||
import { makeObservable, observable, action } from 'mobx'
|
||||
import { PredicateKeypath, PredicateKeypathTypes } from './PredicateKeypaths'
|
||||
@@ -59,7 +59,7 @@ export class CompoundPredicateBuilderController {
|
||||
this.setPredicate(index, { value: Object.values(NoteType)[0] })
|
||||
break
|
||||
case 'editorIdentifier':
|
||||
this.setPredicate(index, { value: FeatureIdentifier.PlainEditor })
|
||||
this.setPredicate(index, { value: NativeFeatureIdentifier.TYPES.PlainEditor })
|
||||
break
|
||||
case 'date':
|
||||
this.setPredicate(index, { value: '1.days.ago' })
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
isPayloadSourceRetrieved,
|
||||
PrefKey,
|
||||
PrefDefaults,
|
||||
FeatureIdentifier,
|
||||
NativeFeatureIdentifier,
|
||||
FeatureStatus,
|
||||
GetSuperNoteFeature,
|
||||
} from '@standardnotes/snjs'
|
||||
@@ -76,7 +76,12 @@ export const SuperEditor: FunctionComponent<Props> = ({
|
||||
|
||||
useEffect(() => {
|
||||
setFeatureStatus(
|
||||
application.features.getFeatureStatus(FeatureIdentifier.SuperEditor, { inContextOfItem: note.current }),
|
||||
application.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.SuperEditor).getValue(),
|
||||
{
|
||||
inContextOfItem: note.current,
|
||||
},
|
||||
),
|
||||
)
|
||||
}, [application.features])
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { PremiumFeatureModalType } from '@/Components/PremiumFeaturesModal/Premi
|
||||
import { destroyAllObjectProperties } from '@/Utils'
|
||||
import {
|
||||
ApplicationEvent,
|
||||
FeatureIdentifier,
|
||||
NativeFeatureIdentifier,
|
||||
FeatureStatus,
|
||||
InternalEventBusInterface,
|
||||
InternalEventInterface,
|
||||
@@ -100,19 +100,25 @@ export class FeaturesController extends AbstractViewController {
|
||||
}
|
||||
|
||||
private isEntitledToFiles(): boolean {
|
||||
const status = this.application.features.getFeatureStatus(FeatureIdentifier.Files)
|
||||
const status = this.application.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.Files).getValue(),
|
||||
)
|
||||
|
||||
return status === FeatureStatus.Entitled
|
||||
}
|
||||
|
||||
private isEntitledToFolders(): boolean {
|
||||
const status = this.application.features.getFeatureStatus(FeatureIdentifier.TagNesting)
|
||||
const status = this.application.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.TagNesting).getValue(),
|
||||
)
|
||||
|
||||
return status === FeatureStatus.Entitled
|
||||
}
|
||||
|
||||
private isEntitledToSmartViews(): boolean {
|
||||
const status = this.application.features.getFeatureStatus(FeatureIdentifier.SmartFilters)
|
||||
const status = this.application.features.getFeatureStatus(
|
||||
NativeFeatureIdentifier.create(NativeFeatureIdentifier.TYPES.SmartFilters).getValue(),
|
||||
)
|
||||
|
||||
return status === FeatureStatus.Entitled
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import { FeatureIdentifier } from '@standardnotes/snjs'
|
||||
import { ComponentArea, FindNativeFeature, GetIframeAndNativeEditors } from '@standardnotes/features'
|
||||
import {
|
||||
ComponentArea,
|
||||
FindNativeFeature,
|
||||
GetIframeAndNativeEditors,
|
||||
NativeFeatureIdentifier,
|
||||
} from '@standardnotes/features'
|
||||
import { getIconAndTintForNoteType } from './Items/Icons/getIconAndTintForNoteType'
|
||||
import { DropdownItem } from '@/Components/Dropdown/DropdownItem'
|
||||
import { WebApplicationInterface } from '@standardnotes/ui-services'
|
||||
|
||||
export type EditorOption = DropdownItem & {
|
||||
value: FeatureIdentifier
|
||||
value: string
|
||||
isLabs?: boolean
|
||||
}
|
||||
|
||||
@@ -19,6 +23,7 @@ export function getDropdownItemsForAllEditors(application: WebApplicationInterfa
|
||||
return {
|
||||
label: editor.name,
|
||||
value: editor.identifier,
|
||||
id: NativeFeatureIdentifier.create(editor.identifier).getValue(),
|
||||
...(iconType ? { icon: iconType } : null),
|
||||
...(tint ? { iconClassName: `text-accessory-tint-${tint}` } : null),
|
||||
}
|
||||
@@ -30,12 +35,11 @@ export function getDropdownItemsForAllEditors(application: WebApplicationInterfa
|
||||
.thirdPartyComponentsForArea(ComponentArea.Editor)
|
||||
.filter((component) => FindNativeFeature(component.identifier) === undefined)
|
||||
.map((editor): EditorOption => {
|
||||
const identifier = editor.package_info.identifier
|
||||
const [iconType, tint] = getIconAndTintForNoteType(editor.noteType)
|
||||
|
||||
return {
|
||||
label: editor.displayName,
|
||||
value: identifier,
|
||||
value: editor.uuid,
|
||||
...(iconType ? { icon: iconType } : null),
|
||||
...(tint ? { iconClassName: `text-accessory-tint-${tint}` } : null),
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { UIFeature, FeatureIdentifier, ThemeFeatureDescription } from '@standardnotes/snjs'
|
||||
import { UIFeature, NativeFeatureIdentifier, ThemeFeatureDescription } from '@standardnotes/snjs'
|
||||
|
||||
const isDarkModeTheme = (theme: UIFeature<ThemeFeatureDescription>) =>
|
||||
theme.featureIdentifier === FeatureIdentifier.DarkTheme
|
||||
theme.featureIdentifier === NativeFeatureIdentifier.TYPES.DarkTheme
|
||||
|
||||
export const sortThemes = (a: UIFeature<ThemeFeatureDescription>, b: UIFeature<ThemeFeatureDescription>) => {
|
||||
const aIsLayerable = a.layerable
|
||||
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
GetSuperNoteFeature,
|
||||
UIFeature,
|
||||
IframeComponentFeatureDescription,
|
||||
Uuid,
|
||||
NativeFeatureIdentifier,
|
||||
} from '@standardnotes/snjs'
|
||||
import { EditorMenuGroup } from '@/Components/NotesOptions/EditorMenuGroup'
|
||||
import { EditorMenuItem } from '@/Components/NotesOptions/EditorMenuItem'
|
||||
@@ -29,7 +31,9 @@ const insertNativeEditorsInMap = (map: NoteTypeToEditorRowsMap, application: Web
|
||||
|
||||
const noteType = editorFeature.note_type
|
||||
map[noteType].push({
|
||||
isEntitled: application.features.getFeatureStatus(editorFeature.identifier) === FeatureStatus.Entitled,
|
||||
isEntitled:
|
||||
application.features.getFeatureStatus(NativeFeatureIdentifier.create(editorFeature.identifier).getValue()) ===
|
||||
FeatureStatus.Entitled,
|
||||
uiFeature: new UIFeature(editorFeature),
|
||||
})
|
||||
}
|
||||
@@ -52,7 +56,7 @@ const insertInstalledComponentsInMap = (map: NoteTypeToEditorRowsMap, applicatio
|
||||
|
||||
const editorItem: EditorMenuItem = {
|
||||
uiFeature: new UIFeature<IframeComponentFeatureDescription>(editor),
|
||||
isEntitled: application.features.getFeatureStatus(editor.identifier) === FeatureStatus.Entitled,
|
||||
isEntitled: application.features.getFeatureStatus(Uuid.create(editor.uuid).getValue()) === FeatureStatus.Entitled,
|
||||
}
|
||||
|
||||
map[noteType].push(editorItem)
|
||||
|
||||
Reference in New Issue
Block a user