feat: Allow changing per-view display preferences for system views (#2120)
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { CollectionSortProperty } from '../../Runtime/Collection/CollectionSort'
|
||||
import { EditorIdentifier, FeatureIdentifier } from '@standardnotes/features'
|
||||
import { SystemViewId } from '../SmartView'
|
||||
import { TagPreferences } from '../Tag'
|
||||
|
||||
export enum PrefKey {
|
||||
TagsPanelWidth = 'tagsPanelWidth',
|
||||
@@ -40,6 +42,7 @@ export enum PrefKey {
|
||||
DarkMode = 'darkMode',
|
||||
DefaultEditorIdentifier = 'defaultEditorIdentifier',
|
||||
MomentsDefaultTagUuid = 'momentsDefaultTagUuid',
|
||||
SystemViewPreferences = 'systemViewPreferences',
|
||||
}
|
||||
|
||||
export enum NewNoteTitleFormat {
|
||||
@@ -105,4 +108,5 @@ export type PrefValue = {
|
||||
[PrefKey.DarkMode]: boolean
|
||||
[PrefKey.DefaultEditorIdentifier]: EditorIdentifier
|
||||
[PrefKey.MomentsDefaultTagUuid]: string | undefined
|
||||
[PrefKey.SystemViewPreferences]: Partial<Record<SystemViewId, TagPreferences>>
|
||||
}
|
||||
|
||||
@@ -35,11 +35,14 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
||||
selectedTag,
|
||||
}) => {
|
||||
const isSystemTag = isSmartView(selectedTag) && isSystemView(selectedTag)
|
||||
const [currentMode, setCurrentMode] = useState<PreferenceMode>(selectedTag.preferences ? 'tag' : 'global')
|
||||
const selectedTagPreferences = isSystemTag
|
||||
? application.getPreference(PrefKey.SystemViewPreferences)?.[selectedTag.uuid as SystemViewId]
|
||||
: selectedTag.preferences
|
||||
const [currentMode, setCurrentMode] = useState<PreferenceMode>(selectedTagPreferences ? 'tag' : 'global')
|
||||
const [preferences, setPreferences] = useState<TagPreferences>({})
|
||||
const hasSubscription = application.hasValidSubscription()
|
||||
const controlsDisabled = currentMode === 'tag' && !hasSubscription
|
||||
const isDailyEntry = selectedTag.preferences?.entryMode === 'daily'
|
||||
const isDailyEntry = selectedTagPreferences?.entryMode === 'daily'
|
||||
|
||||
const reloadPreferences = useCallback(() => {
|
||||
const globalValues: TagPreferences = {
|
||||
@@ -71,24 +74,59 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
||||
} else {
|
||||
setPreferences({
|
||||
...globalValues,
|
||||
...selectedTag.preferences,
|
||||
...selectedTagPreferences,
|
||||
})
|
||||
}
|
||||
}, [currentMode, setPreferences, selectedTag, application])
|
||||
}, [application, currentMode, selectedTagPreferences])
|
||||
|
||||
useEffect(() => {
|
||||
reloadPreferences()
|
||||
}, [reloadPreferences])
|
||||
|
||||
const changeGlobalPreferences = useCallback(
|
||||
async (properties: Partial<TagPreferences>) => {
|
||||
for (const key of Object.keys(properties)) {
|
||||
const value = properties[key as keyof TagPreferences]
|
||||
await application.setPreference(key as PrefKey, value).catch(console.error)
|
||||
|
||||
reloadPreferences()
|
||||
}
|
||||
},
|
||||
[application, reloadPreferences],
|
||||
)
|
||||
|
||||
const changeSystemViewPreferences = useCallback(
|
||||
async (properties: Partial<TagPreferences>) => {
|
||||
if (!selectedTag) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isSystemTag) {
|
||||
return
|
||||
}
|
||||
|
||||
const systemViewPreferences = application.getPreference(PrefKey.SystemViewPreferences) || {}
|
||||
const systemViewPreferencesForTag = systemViewPreferences[selectedTag.uuid as SystemViewId] || {}
|
||||
|
||||
await application.setPreference(PrefKey.SystemViewPreferences, {
|
||||
...systemViewPreferences,
|
||||
[selectedTag.uuid as SystemViewId]: {
|
||||
...systemViewPreferencesForTag,
|
||||
...properties,
|
||||
},
|
||||
})
|
||||
|
||||
reloadPreferences()
|
||||
},
|
||||
[application, isSystemTag, reloadPreferences, selectedTag],
|
||||
)
|
||||
|
||||
const changePreferences = useCallback(
|
||||
async (properties: Partial<TagPreferences>) => {
|
||||
if (currentMode === 'global') {
|
||||
for (const key of Object.keys(properties)) {
|
||||
const value = properties[key as keyof TagPreferences]
|
||||
await application.setPreference(key as PrefKey, value).catch(console.error)
|
||||
|
||||
reloadPreferences()
|
||||
}
|
||||
await changeGlobalPreferences(properties)
|
||||
} else if (isSystemTag) {
|
||||
await changeSystemViewPreferences(properties)
|
||||
} else {
|
||||
await application.mutator.changeAndSaveItem<TagMutator>(selectedTag, (mutator) => {
|
||||
mutator.preferences = {
|
||||
@@ -98,14 +136,23 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
||||
})
|
||||
}
|
||||
},
|
||||
[reloadPreferences, application, currentMode, selectedTag],
|
||||
[currentMode, isSystemTag, changeGlobalPreferences, changeSystemViewPreferences, application.mutator, selectedTag],
|
||||
)
|
||||
|
||||
const resetTagPreferences = useCallback(() => {
|
||||
const resetTagPreferences = useCallback(async () => {
|
||||
if (isSystemTag) {
|
||||
await application.setPreference(PrefKey.SystemViewPreferences, {
|
||||
...application.getPreference(PrefKey.SystemViewPreferences),
|
||||
[selectedTag.uuid as SystemViewId]: undefined,
|
||||
})
|
||||
reloadPreferences()
|
||||
return
|
||||
}
|
||||
|
||||
void application.mutator.changeAndSaveItem<TagMutator>(selectedTag, (mutator) => {
|
||||
mutator.preferences = undefined
|
||||
})
|
||||
}, [application, selectedTag])
|
||||
}, [application, isSystemTag, reloadPreferences, selectedTag])
|
||||
|
||||
const toggleSortReverse = useCallback(() => {
|
||||
void changePreferences({ sortReverse: !preferences.sortReverse })
|
||||
@@ -212,7 +259,7 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
||||
<div className={classNames('mt-1.5 flex w-full justify-between px-3', !controlsDisabled && 'mb-3')}>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<TabButton label="Global" mode="global" />
|
||||
{!isSystemTag && <TabButton label={selectedTag.title} icon={selectedTag.iconString} mode="tag" />}
|
||||
<TabButton label={selectedTag.title} icon={selectedTag.iconString} mode="tag" />
|
||||
</div>
|
||||
{currentMode === 'tag' && (
|
||||
<button className="text-base lg:text-sm" onClick={resetTagPreferences}>
|
||||
@@ -363,7 +410,7 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
||||
</>
|
||||
)}
|
||||
|
||||
{currentMode === 'tag' && DailyEntryModeEnabled && (
|
||||
{currentMode === 'tag' && !isSystemTag && DailyEntryModeEnabled && (
|
||||
<>
|
||||
<MenuItemSeparator />
|
||||
<MenuSwitchButtonItem
|
||||
@@ -385,7 +432,7 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
|
||||
</>
|
||||
)}
|
||||
|
||||
{!shouldHideNonApplicableOptions && (
|
||||
{!shouldHideNonApplicableOptions && (!isSystemTag || currentMode === 'global') && (
|
||||
<>
|
||||
<MenuItemSeparator />
|
||||
<NewNotePreferences
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
import { FeatureIdentifier, NewNoteTitleFormat, PrefKey, EditorIdentifier, TagPreferences } from '@standardnotes/snjs'
|
||||
import {
|
||||
FeatureIdentifier,
|
||||
NewNoteTitleFormat,
|
||||
PrefKey,
|
||||
EditorIdentifier,
|
||||
TagPreferences,
|
||||
isSmartView,
|
||||
isSystemView,
|
||||
SystemViewId,
|
||||
} from '@standardnotes/snjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { ChangeEventHandler, FunctionComponent, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { PrefDefaults } from '@/Constants/PrefDefaults'
|
||||
@@ -31,6 +40,11 @@ const NewNotePreferences: FunctionComponent<Props> = ({
|
||||
changePreferencesCallback,
|
||||
disabled,
|
||||
}: Props) => {
|
||||
const isSystemTag = isSmartView(selectedTag) && isSystemView(selectedTag)
|
||||
const selectedTagPreferences = isSystemTag
|
||||
? application.getPreference(PrefKey.SystemViewPreferences)?.[selectedTag.uuid as SystemViewId]
|
||||
: selectedTag.preferences
|
||||
|
||||
const [editorItems, setEditorItems] = useState<DropdownItem[]>([])
|
||||
const [defaultEditorIdentifier, setDefaultEditorIdentifier] = useState<EditorIdentifier>(
|
||||
FeatureIdentifier.PlainEditor,
|
||||
@@ -45,15 +59,15 @@ const NewNotePreferences: FunctionComponent<Props> = ({
|
||||
}, [application])
|
||||
|
||||
const reloadPreferences = useCallback(() => {
|
||||
if (mode === 'tag' && selectedTag.preferences?.editorIdentifier) {
|
||||
setDefaultEditorIdentifier(selectedTag.preferences?.editorIdentifier)
|
||||
if (mode === 'tag' && selectedTagPreferences?.editorIdentifier) {
|
||||
setDefaultEditorIdentifier(selectedTagPreferences?.editorIdentifier)
|
||||
} else {
|
||||
const globalDefault = getGlobalEditorDefaultIdentifier()
|
||||
setDefaultEditorIdentifier(globalDefault)
|
||||
}
|
||||
|
||||
if (mode === 'tag' && selectedTag.preferences?.newNoteTitleFormat) {
|
||||
setNewNoteTitleFormat(selectedTag.preferences?.newNoteTitleFormat)
|
||||
if (mode === 'tag' && selectedTagPreferences?.newNoteTitleFormat) {
|
||||
setNewNoteTitleFormat(selectedTagPreferences?.newNoteTitleFormat)
|
||||
} else {
|
||||
setNewNoteTitleFormat(
|
||||
application.getPreference(PrefKey.NewNoteTitleFormat, PrefDefaults[PrefKey.NewNoteTitleFormat]),
|
||||
@@ -61,22 +75,21 @@ const NewNotePreferences: FunctionComponent<Props> = ({
|
||||
}
|
||||
}, [
|
||||
mode,
|
||||
selectedTag,
|
||||
application,
|
||||
selectedTagPreferences?.editorIdentifier,
|
||||
selectedTagPreferences?.newNoteTitleFormat,
|
||||
getGlobalEditorDefaultIdentifier,
|
||||
setDefaultEditorIdentifier,
|
||||
setNewNoteTitleFormat,
|
||||
application,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
if (mode === 'tag' && selectedTag.preferences?.customNoteTitleFormat) {
|
||||
setCustomNoteTitleFormat(selectedTag.preferences?.customNoteTitleFormat)
|
||||
if (mode === 'tag' && selectedTagPreferences?.customNoteTitleFormat) {
|
||||
setCustomNoteTitleFormat(selectedTagPreferences?.customNoteTitleFormat)
|
||||
} else {
|
||||
setCustomNoteTitleFormat(
|
||||
application.getPreference(PrefKey.CustomNoteTitleFormat, PrefDefaults[PrefKey.CustomNoteTitleFormat]),
|
||||
)
|
||||
}
|
||||
}, [application, mode, selectedTag])
|
||||
}, [application, mode, selectedTag, selectedTagPreferences?.customNoteTitleFormat])
|
||||
|
||||
useEffect(() => {
|
||||
void reloadPreferences()
|
||||
|
||||
@@ -20,6 +20,8 @@ import {
|
||||
useBoolean,
|
||||
isTag,
|
||||
isFile,
|
||||
isSmartView,
|
||||
isSystemView,
|
||||
} from '@standardnotes/snjs'
|
||||
import { action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'
|
||||
import { WebApplication } from '../../Application/Application'
|
||||
@@ -502,10 +504,14 @@ export class ItemListController extends AbstractViewController implements Intern
|
||||
const newDisplayOptions = {} as DisplayOptions
|
||||
const newWebDisplayOptions = {} as WebDisplayOptions
|
||||
const selectedTag = this.navigationController.selected
|
||||
const isSystemTag = selectedTag && isSmartView(selectedTag) && isSystemView(selectedTag)
|
||||
const selectedTagPreferences = isSystemTag
|
||||
? this.application.getPreference(PrefKey.SystemViewPreferences)?.[selectedTag.uuid as SystemViewId]
|
||||
: selectedTag?.preferences
|
||||
|
||||
const currentSortBy = this.displayOptions.sortBy
|
||||
let sortBy =
|
||||
selectedTag?.preferences?.sortBy ||
|
||||
selectedTagPreferences?.sortBy ||
|
||||
this.application.getPreference(PrefKey.SortNotesBy, PrefDefaults[PrefKey.SortNotesBy])
|
||||
if (sortBy === CollectionSort.UpdatedAt || (sortBy as string) === 'client_updated_at') {
|
||||
sortBy = CollectionSort.UpdatedAt
|
||||
@@ -515,49 +521,49 @@ export class ItemListController extends AbstractViewController implements Intern
|
||||
const currentSortDirection = this.displayOptions.sortDirection
|
||||
newDisplayOptions.sortDirection =
|
||||
useBoolean(
|
||||
selectedTag?.preferences?.sortReverse,
|
||||
selectedTagPreferences?.sortReverse,
|
||||
this.application.getPreference(PrefKey.SortNotesReverse, PrefDefaults[PrefKey.SortNotesReverse]),
|
||||
) === false
|
||||
? 'dsc'
|
||||
: 'asc'
|
||||
|
||||
newDisplayOptions.includeArchived = useBoolean(
|
||||
selectedTag?.preferences?.showArchived,
|
||||
selectedTagPreferences?.showArchived,
|
||||
this.application.getPreference(PrefKey.NotesShowArchived, PrefDefaults[PrefKey.NotesShowArchived]),
|
||||
)
|
||||
|
||||
newDisplayOptions.includeTrashed = useBoolean(
|
||||
selectedTag?.preferences?.showTrashed,
|
||||
selectedTagPreferences?.showTrashed,
|
||||
this.application.getPreference(PrefKey.NotesShowTrashed, PrefDefaults[PrefKey.NotesShowTrashed]),
|
||||
)
|
||||
|
||||
newDisplayOptions.includePinned = !useBoolean(
|
||||
selectedTag?.preferences?.hidePinned,
|
||||
selectedTagPreferences?.hidePinned,
|
||||
this.application.getPreference(PrefKey.NotesHidePinned, PrefDefaults[PrefKey.NotesHidePinned]),
|
||||
)
|
||||
|
||||
newDisplayOptions.includeProtected = !useBoolean(
|
||||
selectedTag?.preferences?.hideProtected,
|
||||
selectedTagPreferences?.hideProtected,
|
||||
this.application.getPreference(PrefKey.NotesHideProtected, PrefDefaults[PrefKey.NotesHideProtected]),
|
||||
)
|
||||
|
||||
newWebDisplayOptions.hideNotePreview = useBoolean(
|
||||
selectedTag?.preferences?.hideNotePreview,
|
||||
selectedTagPreferences?.hideNotePreview,
|
||||
this.application.getPreference(PrefKey.NotesHideNotePreview, PrefDefaults[PrefKey.NotesHideNotePreview]),
|
||||
)
|
||||
|
||||
newWebDisplayOptions.hideDate = useBoolean(
|
||||
selectedTag?.preferences?.hideDate,
|
||||
selectedTagPreferences?.hideDate,
|
||||
this.application.getPreference(PrefKey.NotesHideDate, PrefDefaults[PrefKey.NotesHideDate]),
|
||||
)
|
||||
|
||||
newWebDisplayOptions.hideTags = useBoolean(
|
||||
selectedTag?.preferences?.hideTags,
|
||||
selectedTagPreferences?.hideTags,
|
||||
this.application.getPreference(PrefKey.NotesHideTags, PrefDefaults[PrefKey.NotesHideTags]),
|
||||
)
|
||||
|
||||
newWebDisplayOptions.hideEditorIcon = useBoolean(
|
||||
selectedTag?.preferences?.hideEditorIcon,
|
||||
selectedTagPreferences?.hideEditorIcon,
|
||||
this.application.getPreference(PrefKey.NotesHideEditorIcon, PrefDefaults[PrefKey.NotesHideEditorIcon]),
|
||||
)
|
||||
|
||||
@@ -621,8 +627,14 @@ export class ItemListController extends AbstractViewController implements Intern
|
||||
return this.noteFilterText
|
||||
}
|
||||
|
||||
const selectedTag = this.navigationController.selected
|
||||
const isSystemTag = selectedTag && isSmartView(selectedTag) && isSystemView(selectedTag)
|
||||
const selectedTagPreferences = isSystemTag
|
||||
? this.application.getPreference(PrefKey.SystemViewPreferences)?.[selectedTag.uuid as SystemViewId]
|
||||
: selectedTag?.preferences
|
||||
|
||||
const titleFormat =
|
||||
this.navigationController.selected?.preferences?.newNoteTitleFormat ||
|
||||
selectedTagPreferences?.newNoteTitleFormat ||
|
||||
this.application.getPreference(PrefKey.NewNoteTitleFormat, PrefDefaults[PrefKey.NewNoteTitleFormat])
|
||||
|
||||
if (titleFormat === NewNoteTitleFormat.CurrentNoteCount) {
|
||||
|
||||
Reference in New Issue
Block a user