feat: Allow changing per-view display preferences for system views (#2120)

This commit is contained in:
Aman Harwara
2022-12-27 23:33:08 +05:30
committed by GitHub
parent 771758fcd4
commit dc33aef660
4 changed files with 115 additions and 39 deletions

View File

@@ -1,5 +1,7 @@
import { CollectionSortProperty } from '../../Runtime/Collection/CollectionSort' import { CollectionSortProperty } from '../../Runtime/Collection/CollectionSort'
import { EditorIdentifier, FeatureIdentifier } from '@standardnotes/features' import { EditorIdentifier, FeatureIdentifier } from '@standardnotes/features'
import { SystemViewId } from '../SmartView'
import { TagPreferences } from '../Tag'
export enum PrefKey { export enum PrefKey {
TagsPanelWidth = 'tagsPanelWidth', TagsPanelWidth = 'tagsPanelWidth',
@@ -40,6 +42,7 @@ export enum PrefKey {
DarkMode = 'darkMode', DarkMode = 'darkMode',
DefaultEditorIdentifier = 'defaultEditorIdentifier', DefaultEditorIdentifier = 'defaultEditorIdentifier',
MomentsDefaultTagUuid = 'momentsDefaultTagUuid', MomentsDefaultTagUuid = 'momentsDefaultTagUuid',
SystemViewPreferences = 'systemViewPreferences',
} }
export enum NewNoteTitleFormat { export enum NewNoteTitleFormat {
@@ -105,4 +108,5 @@ export type PrefValue = {
[PrefKey.DarkMode]: boolean [PrefKey.DarkMode]: boolean
[PrefKey.DefaultEditorIdentifier]: EditorIdentifier [PrefKey.DefaultEditorIdentifier]: EditorIdentifier
[PrefKey.MomentsDefaultTagUuid]: string | undefined [PrefKey.MomentsDefaultTagUuid]: string | undefined
[PrefKey.SystemViewPreferences]: Partial<Record<SystemViewId, TagPreferences>>
} }

View File

@@ -35,11 +35,14 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
selectedTag, selectedTag,
}) => { }) => {
const isSystemTag = isSmartView(selectedTag) && isSystemView(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 [preferences, setPreferences] = useState<TagPreferences>({})
const hasSubscription = application.hasValidSubscription() const hasSubscription = application.hasValidSubscription()
const controlsDisabled = currentMode === 'tag' && !hasSubscription const controlsDisabled = currentMode === 'tag' && !hasSubscription
const isDailyEntry = selectedTag.preferences?.entryMode === 'daily' const isDailyEntry = selectedTagPreferences?.entryMode === 'daily'
const reloadPreferences = useCallback(() => { const reloadPreferences = useCallback(() => {
const globalValues: TagPreferences = { const globalValues: TagPreferences = {
@@ -71,24 +74,59 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
} else { } else {
setPreferences({ setPreferences({
...globalValues, ...globalValues,
...selectedTag.preferences, ...selectedTagPreferences,
}) })
} }
}, [currentMode, setPreferences, selectedTag, application]) }, [application, currentMode, selectedTagPreferences])
useEffect(() => { useEffect(() => {
reloadPreferences() reloadPreferences()
}, [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( const changePreferences = useCallback(
async (properties: Partial<TagPreferences>) => { async (properties: Partial<TagPreferences>) => {
if (currentMode === 'global') { if (currentMode === 'global') {
for (const key of Object.keys(properties)) { await changeGlobalPreferences(properties)
const value = properties[key as keyof TagPreferences] } else if (isSystemTag) {
await application.setPreference(key as PrefKey, value).catch(console.error) await changeSystemViewPreferences(properties)
reloadPreferences()
}
} else { } else {
await application.mutator.changeAndSaveItem<TagMutator>(selectedTag, (mutator) => { await application.mutator.changeAndSaveItem<TagMutator>(selectedTag, (mutator) => {
mutator.preferences = { 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) => { void application.mutator.changeAndSaveItem<TagMutator>(selectedTag, (mutator) => {
mutator.preferences = undefined mutator.preferences = undefined
}) })
}, [application, selectedTag]) }, [application, isSystemTag, reloadPreferences, selectedTag])
const toggleSortReverse = useCallback(() => { const toggleSortReverse = useCallback(() => {
void changePreferences({ sortReverse: !preferences.sortReverse }) 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={classNames('mt-1.5 flex w-full justify-between px-3', !controlsDisabled && 'mb-3')}>
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<TabButton label="Global" mode="global" /> <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> </div>
{currentMode === 'tag' && ( {currentMode === 'tag' && (
<button className="text-base lg:text-sm" onClick={resetTagPreferences}> <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 /> <MenuItemSeparator />
<MenuSwitchButtonItem <MenuSwitchButtonItem
@@ -385,7 +432,7 @@ const DisplayOptionsMenu: FunctionComponent<DisplayOptionsMenuProps> = ({
</> </>
)} )}
{!shouldHideNonApplicableOptions && ( {!shouldHideNonApplicableOptions && (!isSystemTag || currentMode === 'global') && (
<> <>
<MenuItemSeparator /> <MenuItemSeparator />
<NewNotePreferences <NewNotePreferences

View File

@@ -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 { observer } from 'mobx-react-lite'
import { ChangeEventHandler, FunctionComponent, useCallback, useEffect, useRef, useState } from 'react' import { ChangeEventHandler, FunctionComponent, useCallback, useEffect, useRef, useState } from 'react'
import { PrefDefaults } from '@/Constants/PrefDefaults' import { PrefDefaults } from '@/Constants/PrefDefaults'
@@ -31,6 +40,11 @@ const NewNotePreferences: FunctionComponent<Props> = ({
changePreferencesCallback, changePreferencesCallback,
disabled, disabled,
}: Props) => { }: 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 [editorItems, setEditorItems] = useState<DropdownItem[]>([])
const [defaultEditorIdentifier, setDefaultEditorIdentifier] = useState<EditorIdentifier>( const [defaultEditorIdentifier, setDefaultEditorIdentifier] = useState<EditorIdentifier>(
FeatureIdentifier.PlainEditor, FeatureIdentifier.PlainEditor,
@@ -45,15 +59,15 @@ const NewNotePreferences: FunctionComponent<Props> = ({
}, [application]) }, [application])
const reloadPreferences = useCallback(() => { const reloadPreferences = useCallback(() => {
if (mode === 'tag' && selectedTag.preferences?.editorIdentifier) { if (mode === 'tag' && selectedTagPreferences?.editorIdentifier) {
setDefaultEditorIdentifier(selectedTag.preferences?.editorIdentifier) setDefaultEditorIdentifier(selectedTagPreferences?.editorIdentifier)
} else { } else {
const globalDefault = getGlobalEditorDefaultIdentifier() const globalDefault = getGlobalEditorDefaultIdentifier()
setDefaultEditorIdentifier(globalDefault) setDefaultEditorIdentifier(globalDefault)
} }
if (mode === 'tag' && selectedTag.preferences?.newNoteTitleFormat) { if (mode === 'tag' && selectedTagPreferences?.newNoteTitleFormat) {
setNewNoteTitleFormat(selectedTag.preferences?.newNoteTitleFormat) setNewNoteTitleFormat(selectedTagPreferences?.newNoteTitleFormat)
} else { } else {
setNewNoteTitleFormat( setNewNoteTitleFormat(
application.getPreference(PrefKey.NewNoteTitleFormat, PrefDefaults[PrefKey.NewNoteTitleFormat]), application.getPreference(PrefKey.NewNoteTitleFormat, PrefDefaults[PrefKey.NewNoteTitleFormat]),
@@ -61,22 +75,21 @@ const NewNotePreferences: FunctionComponent<Props> = ({
} }
}, [ }, [
mode, mode,
selectedTag, selectedTagPreferences?.editorIdentifier,
application, selectedTagPreferences?.newNoteTitleFormat,
getGlobalEditorDefaultIdentifier, getGlobalEditorDefaultIdentifier,
setDefaultEditorIdentifier, application,
setNewNoteTitleFormat,
]) ])
useEffect(() => { useEffect(() => {
if (mode === 'tag' && selectedTag.preferences?.customNoteTitleFormat) { if (mode === 'tag' && selectedTagPreferences?.customNoteTitleFormat) {
setCustomNoteTitleFormat(selectedTag.preferences?.customNoteTitleFormat) setCustomNoteTitleFormat(selectedTagPreferences?.customNoteTitleFormat)
} else { } else {
setCustomNoteTitleFormat( setCustomNoteTitleFormat(
application.getPreference(PrefKey.CustomNoteTitleFormat, PrefDefaults[PrefKey.CustomNoteTitleFormat]), application.getPreference(PrefKey.CustomNoteTitleFormat, PrefDefaults[PrefKey.CustomNoteTitleFormat]),
) )
} }
}, [application, mode, selectedTag]) }, [application, mode, selectedTag, selectedTagPreferences?.customNoteTitleFormat])
useEffect(() => { useEffect(() => {
void reloadPreferences() void reloadPreferences()

View File

@@ -20,6 +20,8 @@ import {
useBoolean, useBoolean,
isTag, isTag,
isFile, isFile,
isSmartView,
isSystemView,
} from '@standardnotes/snjs' } from '@standardnotes/snjs'
import { action, computed, makeObservable, observable, reaction, runInAction } from 'mobx' import { action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'
import { WebApplication } from '../../Application/Application' import { WebApplication } from '../../Application/Application'
@@ -502,10 +504,14 @@ export class ItemListController extends AbstractViewController implements Intern
const newDisplayOptions = {} as DisplayOptions const newDisplayOptions = {} as DisplayOptions
const newWebDisplayOptions = {} as WebDisplayOptions const newWebDisplayOptions = {} as WebDisplayOptions
const selectedTag = this.navigationController.selected 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 const currentSortBy = this.displayOptions.sortBy
let sortBy = let sortBy =
selectedTag?.preferences?.sortBy || selectedTagPreferences?.sortBy ||
this.application.getPreference(PrefKey.SortNotesBy, PrefDefaults[PrefKey.SortNotesBy]) this.application.getPreference(PrefKey.SortNotesBy, PrefDefaults[PrefKey.SortNotesBy])
if (sortBy === CollectionSort.UpdatedAt || (sortBy as string) === 'client_updated_at') { if (sortBy === CollectionSort.UpdatedAt || (sortBy as string) === 'client_updated_at') {
sortBy = CollectionSort.UpdatedAt sortBy = CollectionSort.UpdatedAt
@@ -515,49 +521,49 @@ export class ItemListController extends AbstractViewController implements Intern
const currentSortDirection = this.displayOptions.sortDirection const currentSortDirection = this.displayOptions.sortDirection
newDisplayOptions.sortDirection = newDisplayOptions.sortDirection =
useBoolean( useBoolean(
selectedTag?.preferences?.sortReverse, selectedTagPreferences?.sortReverse,
this.application.getPreference(PrefKey.SortNotesReverse, PrefDefaults[PrefKey.SortNotesReverse]), this.application.getPreference(PrefKey.SortNotesReverse, PrefDefaults[PrefKey.SortNotesReverse]),
) === false ) === false
? 'dsc' ? 'dsc'
: 'asc' : 'asc'
newDisplayOptions.includeArchived = useBoolean( newDisplayOptions.includeArchived = useBoolean(
selectedTag?.preferences?.showArchived, selectedTagPreferences?.showArchived,
this.application.getPreference(PrefKey.NotesShowArchived, PrefDefaults[PrefKey.NotesShowArchived]), this.application.getPreference(PrefKey.NotesShowArchived, PrefDefaults[PrefKey.NotesShowArchived]),
) )
newDisplayOptions.includeTrashed = useBoolean( newDisplayOptions.includeTrashed = useBoolean(
selectedTag?.preferences?.showTrashed, selectedTagPreferences?.showTrashed,
this.application.getPreference(PrefKey.NotesShowTrashed, PrefDefaults[PrefKey.NotesShowTrashed]), this.application.getPreference(PrefKey.NotesShowTrashed, PrefDefaults[PrefKey.NotesShowTrashed]),
) )
newDisplayOptions.includePinned = !useBoolean( newDisplayOptions.includePinned = !useBoolean(
selectedTag?.preferences?.hidePinned, selectedTagPreferences?.hidePinned,
this.application.getPreference(PrefKey.NotesHidePinned, PrefDefaults[PrefKey.NotesHidePinned]), this.application.getPreference(PrefKey.NotesHidePinned, PrefDefaults[PrefKey.NotesHidePinned]),
) )
newDisplayOptions.includeProtected = !useBoolean( newDisplayOptions.includeProtected = !useBoolean(
selectedTag?.preferences?.hideProtected, selectedTagPreferences?.hideProtected,
this.application.getPreference(PrefKey.NotesHideProtected, PrefDefaults[PrefKey.NotesHideProtected]), this.application.getPreference(PrefKey.NotesHideProtected, PrefDefaults[PrefKey.NotesHideProtected]),
) )
newWebDisplayOptions.hideNotePreview = useBoolean( newWebDisplayOptions.hideNotePreview = useBoolean(
selectedTag?.preferences?.hideNotePreview, selectedTagPreferences?.hideNotePreview,
this.application.getPreference(PrefKey.NotesHideNotePreview, PrefDefaults[PrefKey.NotesHideNotePreview]), this.application.getPreference(PrefKey.NotesHideNotePreview, PrefDefaults[PrefKey.NotesHideNotePreview]),
) )
newWebDisplayOptions.hideDate = useBoolean( newWebDisplayOptions.hideDate = useBoolean(
selectedTag?.preferences?.hideDate, selectedTagPreferences?.hideDate,
this.application.getPreference(PrefKey.NotesHideDate, PrefDefaults[PrefKey.NotesHideDate]), this.application.getPreference(PrefKey.NotesHideDate, PrefDefaults[PrefKey.NotesHideDate]),
) )
newWebDisplayOptions.hideTags = useBoolean( newWebDisplayOptions.hideTags = useBoolean(
selectedTag?.preferences?.hideTags, selectedTagPreferences?.hideTags,
this.application.getPreference(PrefKey.NotesHideTags, PrefDefaults[PrefKey.NotesHideTags]), this.application.getPreference(PrefKey.NotesHideTags, PrefDefaults[PrefKey.NotesHideTags]),
) )
newWebDisplayOptions.hideEditorIcon = useBoolean( newWebDisplayOptions.hideEditorIcon = useBoolean(
selectedTag?.preferences?.hideEditorIcon, selectedTagPreferences?.hideEditorIcon,
this.application.getPreference(PrefKey.NotesHideEditorIcon, PrefDefaults[PrefKey.NotesHideEditorIcon]), this.application.getPreference(PrefKey.NotesHideEditorIcon, PrefDefaults[PrefKey.NotesHideEditorIcon]),
) )
@@ -621,8 +627,14 @@ export class ItemListController extends AbstractViewController implements Intern
return this.noteFilterText 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 = const titleFormat =
this.navigationController.selected?.preferences?.newNoteTitleFormat || selectedTagPreferences?.newNoteTitleFormat ||
this.application.getPreference(PrefKey.NewNoteTitleFormat, PrefDefaults[PrefKey.NewNoteTitleFormat]) this.application.getPreference(PrefKey.NewNoteTitleFormat, PrefDefaults[PrefKey.NewNoteTitleFormat])
if (titleFormat === NewNoteTitleFormat.CurrentNoteCount) { if (titleFormat === NewNoteTitleFormat.CurrentNoteCount) {