feat: Themes and appeareance settings are now local to your device and not synced (#2847)
This commit is contained in:
@@ -27,10 +27,10 @@ export const PrefDefaults = {
|
|||||||
[PrefKey.NotesHideDate]: false,
|
[PrefKey.NotesHideDate]: false,
|
||||||
[PrefKey.NotesHideTags]: false,
|
[PrefKey.NotesHideTags]: false,
|
||||||
[PrefKey.NotesHideEditorIcon]: false,
|
[PrefKey.NotesHideEditorIcon]: false,
|
||||||
[PrefKey.UseSystemColorScheme]: false,
|
[PrefKey.DEPRECATED_UseSystemColorScheme]: false,
|
||||||
[PrefKey.UseTranslucentUI]: true,
|
[PrefKey.DEPRECATED_UseTranslucentUI]: true,
|
||||||
[PrefKey.AutoLightThemeIdentifier]: 'Default',
|
[PrefKey.DEPRECATED_AutoLightThemeIdentifier]: 'Default',
|
||||||
[PrefKey.AutoDarkThemeIdentifier]: NativeFeatureIdentifier.TYPES.DarkTheme,
|
[PrefKey.DEPRECATED_AutoDarkThemeIdentifier]: NativeFeatureIdentifier.TYPES.DarkTheme,
|
||||||
[PrefKey.NoteAddToParentFolders]: true,
|
[PrefKey.NoteAddToParentFolders]: true,
|
||||||
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat.CurrentDateAndTime,
|
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat.CurrentDateAndTime,
|
||||||
[PrefKey.CustomNoteTitleFormat]: 'YYYY-MM-DD [at] hh:mm A',
|
[PrefKey.CustomNoteTitleFormat]: 'YYYY-MM-DD [at] hh:mm A',
|
||||||
@@ -46,7 +46,7 @@ export const PrefDefaults = {
|
|||||||
[PrefKey.SystemViewPreferences]: {},
|
[PrefKey.SystemViewPreferences]: {},
|
||||||
[PrefKey.AuthenticatorNames]: '',
|
[PrefKey.AuthenticatorNames]: '',
|
||||||
[PrefKey.ComponentPreferences]: {},
|
[PrefKey.ComponentPreferences]: {},
|
||||||
[PrefKey.ActiveThemes]: [],
|
[PrefKey.DEPRECATED_ActiveThemes]: [],
|
||||||
[PrefKey.ActiveComponents]: [],
|
[PrefKey.ActiveComponents]: [],
|
||||||
[PrefKey.AlwaysShowSuperToolbar]: true,
|
[PrefKey.AlwaysShowSuperToolbar]: true,
|
||||||
[PrefKey.AddImportsToTag]: true,
|
[PrefKey.AddImportsToTag]: true,
|
||||||
|
|||||||
@@ -28,10 +28,6 @@ export enum PrefKey {
|
|||||||
NotesHideDate = 'hideDate',
|
NotesHideDate = 'hideDate',
|
||||||
NotesHideTags = 'hideTags',
|
NotesHideTags = 'hideTags',
|
||||||
NotesHideEditorIcon = 'hideEditorIcon',
|
NotesHideEditorIcon = 'hideEditorIcon',
|
||||||
UseSystemColorScheme = 'useSystemColorScheme',
|
|
||||||
UseTranslucentUI = 'useTranslucentUI',
|
|
||||||
AutoLightThemeIdentifier = 'autoLightThemeIdentifier',
|
|
||||||
AutoDarkThemeIdentifier = 'autoDarkThemeIdentifier',
|
|
||||||
NoteAddToParentFolders = 'noteAddToParentFolders',
|
NoteAddToParentFolders = 'noteAddToParentFolders',
|
||||||
NewNoteTitleFormat = 'newNoteTitleFormat',
|
NewNoteTitleFormat = 'newNoteTitleFormat',
|
||||||
CustomNoteTitleFormat = 'customNoteTitleFormat',
|
CustomNoteTitleFormat = 'customNoteTitleFormat',
|
||||||
@@ -47,12 +43,16 @@ export enum PrefKey {
|
|||||||
AuthenticatorNames = 'authenticatorNames',
|
AuthenticatorNames = 'authenticatorNames',
|
||||||
PaneGesturesEnabled = 'paneGesturesEnabled',
|
PaneGesturesEnabled = 'paneGesturesEnabled',
|
||||||
ComponentPreferences = 'componentPreferences',
|
ComponentPreferences = 'componentPreferences',
|
||||||
ActiveThemes = 'activeThemes',
|
|
||||||
ActiveComponents = 'activeComponents',
|
ActiveComponents = 'activeComponents',
|
||||||
AlwaysShowSuperToolbar = 'alwaysShowSuperToolbar',
|
AlwaysShowSuperToolbar = 'alwaysShowSuperToolbar',
|
||||||
AddImportsToTag = 'addImportsToTag',
|
AddImportsToTag = 'addImportsToTag',
|
||||||
AlwaysCreateNewTagForImports = 'alwaysCreateNewTagForImports',
|
AlwaysCreateNewTagForImports = 'alwaysCreateNewTagForImports',
|
||||||
ExistingTagForImports = 'existingTagForImports',
|
ExistingTagForImports = 'existingTagForImports',
|
||||||
|
DEPRECATED_ActiveThemes = 'activeThemes',
|
||||||
|
DEPRECATED_UseSystemColorScheme = 'useSystemColorScheme',
|
||||||
|
DEPRECATED_UseTranslucentUI = 'useTranslucentUI',
|
||||||
|
DEPRECATED_AutoLightThemeIdentifier = 'autoLightThemeIdentifier',
|
||||||
|
DEPRECATED_AutoDarkThemeIdentifier = 'autoDarkThemeIdentifier',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PrefValue = {
|
export type PrefValue = {
|
||||||
@@ -73,10 +73,11 @@ export type PrefValue = {
|
|||||||
[PrefKey.NotesHideDate]: boolean
|
[PrefKey.NotesHideDate]: boolean
|
||||||
[PrefKey.NotesHideTags]: boolean
|
[PrefKey.NotesHideTags]: boolean
|
||||||
[PrefKey.NotesHideEditorIcon]: boolean
|
[PrefKey.NotesHideEditorIcon]: boolean
|
||||||
[PrefKey.UseSystemColorScheme]: boolean
|
[PrefKey.DEPRECATED_ActiveThemes]: string[]
|
||||||
[PrefKey.UseTranslucentUI]: boolean
|
[PrefKey.DEPRECATED_UseSystemColorScheme]: boolean
|
||||||
[PrefKey.AutoLightThemeIdentifier]: string
|
[PrefKey.DEPRECATED_UseTranslucentUI]: boolean
|
||||||
[PrefKey.AutoDarkThemeIdentifier]: string
|
[PrefKey.DEPRECATED_AutoLightThemeIdentifier]: string
|
||||||
|
[PrefKey.DEPRECATED_AutoDarkThemeIdentifier]: string
|
||||||
[PrefKey.NoteAddToParentFolders]: boolean
|
[PrefKey.NoteAddToParentFolders]: boolean
|
||||||
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat
|
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat
|
||||||
[PrefKey.CustomNoteTitleFormat]: string
|
[PrefKey.CustomNoteTitleFormat]: string
|
||||||
@@ -95,7 +96,6 @@ export type PrefValue = {
|
|||||||
[PrefKey.AuthenticatorNames]: string
|
[PrefKey.AuthenticatorNames]: string
|
||||||
[PrefKey.PaneGesturesEnabled]: boolean
|
[PrefKey.PaneGesturesEnabled]: boolean
|
||||||
[PrefKey.ComponentPreferences]: AllComponentPreferences
|
[PrefKey.ComponentPreferences]: AllComponentPreferences
|
||||||
[PrefKey.ActiveThemes]: string[]
|
|
||||||
[PrefKey.ActiveComponents]: string[]
|
[PrefKey.ActiveComponents]: string[]
|
||||||
[PrefKey.AlwaysShowSuperToolbar]: boolean
|
[PrefKey.AlwaysShowSuperToolbar]: boolean
|
||||||
[PrefKey.AddImportsToTag]: boolean
|
[PrefKey.AddImportsToTag]: boolean
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ export enum ApplicationEvent {
|
|||||||
/** When StorageService is ready (but NOT yet decrypted) to start servicing read/write requests */
|
/** When StorageService is ready (but NOT yet decrypted) to start servicing read/write requests */
|
||||||
StorageReady = 'Application:StorageReady',
|
StorageReady = 'Application:StorageReady',
|
||||||
PreferencesChanged = 'Application:PreferencesChanged',
|
PreferencesChanged = 'Application:PreferencesChanged',
|
||||||
|
LocalPreferencesChanged = 'Application:LocalPreferencesChanged',
|
||||||
UnprotectedSessionBegan = 'Application:UnprotectedSessionBegan',
|
UnprotectedSessionBegan = 'Application:UnprotectedSessionBegan',
|
||||||
UserRolesChanged = 'Application:UserRolesChanged',
|
UserRolesChanged = 'Application:UserRolesChanged',
|
||||||
FeaturesAvailabilityChanged = 'Application:FeaturesAvailabilityChanged',
|
FeaturesAvailabilityChanged = 'Application:FeaturesAvailabilityChanged',
|
||||||
|
|||||||
15
packages/services/src/Domain/Preferences/LocalPrefKey.ts
Normal file
15
packages/services/src/Domain/Preferences/LocalPrefKey.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
export enum LocalPrefKey {
|
||||||
|
ActiveThemes = 'activeThemes',
|
||||||
|
UseSystemColorScheme = 'useSystemColorScheme',
|
||||||
|
UseTranslucentUI = 'useTranslucentUI',
|
||||||
|
AutoLightThemeIdentifier = 'autoLightThemeIdentifier',
|
||||||
|
AutoDarkThemeIdentifier = 'autoDarkThemeIdentifier',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LocalPrefValue = {
|
||||||
|
[LocalPrefKey.ActiveThemes]: string[]
|
||||||
|
[LocalPrefKey.UseSystemColorScheme]: boolean
|
||||||
|
[LocalPrefKey.UseTranslucentUI]: boolean
|
||||||
|
[LocalPrefKey.AutoLightThemeIdentifier]: string
|
||||||
|
[LocalPrefKey.AutoDarkThemeIdentifier]: string
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import { PrefKey, PrefValue } from '@standardnotes/models'
|
import { PrefKey, PrefValue } from '@standardnotes/models'
|
||||||
import { AbstractService } from '../Service/AbstractService'
|
import { AbstractService } from '../Service/AbstractService'
|
||||||
|
import { LocalPrefKey, LocalPrefValue } from './LocalPrefKey'
|
||||||
|
|
||||||
export enum PreferencesServiceEvent {
|
export enum PreferencesServiceEvent {
|
||||||
|
LocalPreferencesChanged = 'LocalPreferencesChanged',
|
||||||
PreferencesChanged = 'PreferencesChanged',
|
PreferencesChanged = 'PreferencesChanged',
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10,7 +12,15 @@ export interface PreferenceServiceInterface extends AbstractService<PreferencesS
|
|||||||
getValue<K extends PrefKey>(key: K, defaultValue?: PrefValue[K]): PrefValue[K] | undefined
|
getValue<K extends PrefKey>(key: K, defaultValue?: PrefValue[K]): PrefValue[K] | undefined
|
||||||
getValue<K extends PrefKey>(key: K, defaultValue: PrefValue[K] | undefined): PrefValue[K] | undefined
|
getValue<K extends PrefKey>(key: K, defaultValue: PrefValue[K] | undefined): PrefValue[K] | undefined
|
||||||
|
|
||||||
|
getLocalValue<K extends LocalPrefKey>(key: K, defaultValue: LocalPrefValue[K]): LocalPrefValue[K]
|
||||||
|
getLocalValue<K extends LocalPrefKey>(key: K, defaultValue?: LocalPrefValue[K]): LocalPrefValue[K] | undefined
|
||||||
|
getLocalValue<K extends LocalPrefKey>(
|
||||||
|
key: K,
|
||||||
|
defaultValue: LocalPrefValue[K] | undefined,
|
||||||
|
): LocalPrefValue[K] | undefined
|
||||||
|
|
||||||
setValue<K extends PrefKey>(key: K, value: PrefValue[K]): Promise<void>
|
setValue<K extends PrefKey>(key: K, value: PrefValue[K]): Promise<void>
|
||||||
/** Set value without triggering sync or event notifications */
|
/** Set value without triggering sync or event notifications */
|
||||||
setValueDetached<K extends PrefKey>(key: K, value: PrefValue[K]): Promise<void>
|
setValueDetached<K extends PrefKey>(key: K, value: PrefValue[K]): Promise<void>
|
||||||
|
setLocalValue<K extends LocalPrefKey>(key: K, value: LocalPrefValue[K]): void
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export enum StorageKey {
|
|||||||
FileBackupsLocation = 'file_backups_location',
|
FileBackupsLocation = 'file_backups_location',
|
||||||
VaultSelectionOptions = 'vault_selection_options',
|
VaultSelectionOptions = 'vault_selection_options',
|
||||||
Subscription = 'subscription',
|
Subscription = 'subscription',
|
||||||
|
LocalPreferences = 'local_preferences',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum NonwrappedStorageKey {
|
export enum NonwrappedStorageKey {
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ export * from './KeySystem/KeySystemKeyManager'
|
|||||||
export * from './Mfa/MfaServiceInterface'
|
export * from './Mfa/MfaServiceInterface'
|
||||||
export * from './Mutator/MutatorClientInterface'
|
export * from './Mutator/MutatorClientInterface'
|
||||||
export * from './Payloads/PayloadManagerInterface'
|
export * from './Payloads/PayloadManagerInterface'
|
||||||
|
export * from './Preferences/LocalPrefKey'
|
||||||
export * from './Preferences/PreferenceId'
|
export * from './Preferences/PreferenceId'
|
||||||
export * from './Preferences/PreferenceServiceInterface'
|
export * from './Preferences/PreferenceServiceInterface'
|
||||||
export * from './Protection/MobileUnlockTiming'
|
export * from './Protection/MobileUnlockTiming'
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ import {
|
|||||||
CreateDecryptedBackupFile,
|
CreateDecryptedBackupFile,
|
||||||
CreateEncryptedBackupFile,
|
CreateEncryptedBackupFile,
|
||||||
WebSocketsService,
|
WebSocketsService,
|
||||||
|
PreferencesServiceEvent,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import {
|
import {
|
||||||
SNNote,
|
SNNote,
|
||||||
@@ -326,8 +327,12 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
|||||||
|
|
||||||
const preferencesService = this.dependencies.get<PreferencesService>(TYPES.PreferencesService)
|
const preferencesService = this.dependencies.get<PreferencesService>(TYPES.PreferencesService)
|
||||||
this.serviceObservers.push(
|
this.serviceObservers.push(
|
||||||
preferencesService.addEventObserver(() => {
|
preferencesService.addEventObserver((event) => {
|
||||||
void this.notifyEvent(ApplicationEvent.PreferencesChanged)
|
if (event === PreferencesServiceEvent.PreferencesChanged) {
|
||||||
|
void this.notifyEvent(ApplicationEvent.PreferencesChanged)
|
||||||
|
} else if (event === PreferencesServiceEvent.LocalPreferencesChanged) {
|
||||||
|
void this.notifyEvent(ApplicationEvent.LocalPreferencesChanged)
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ import {
|
|||||||
DesignateSurvivor,
|
DesignateSurvivor,
|
||||||
SyncBackoffService,
|
SyncBackoffService,
|
||||||
SyncBackoffServiceInterface,
|
SyncBackoffServiceInterface,
|
||||||
|
StorageServiceInterface,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { ItemManager } from '../../Services/Items/ItemManager'
|
import { ItemManager } from '../../Services/Items/ItemManager'
|
||||||
import { PayloadManager } from '../../Services/Payloads/PayloadManager'
|
import { PayloadManager } from '../../Services/Payloads/PayloadManager'
|
||||||
@@ -1282,6 +1283,7 @@ export class Dependencies {
|
|||||||
this.get<ItemManager>(TYPES.ItemManager),
|
this.get<ItemManager>(TYPES.ItemManager),
|
||||||
this.get<MutatorService>(TYPES.MutatorService),
|
this.get<MutatorService>(TYPES.MutatorService),
|
||||||
this.get<SyncService>(TYPES.SyncService),
|
this.get<SyncService>(TYPES.SyncService),
|
||||||
|
this.get<StorageServiceInterface>(TYPES.DiskStorageService),
|
||||||
this.get<InternalEventBus>(TYPES.InternalEventBus),
|
this.get<InternalEventBus>(TYPES.InternalEventBus),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export class Migration2_202_1 extends Migration {
|
|||||||
const activeThemes = allActiveitems.filter((component) => component.isTheme())
|
const activeThemes = allActiveitems.filter((component) => component.isTheme())
|
||||||
const activeComponents = allActiveitems.filter((component) => !component.isTheme())
|
const activeComponents = allActiveitems.filter((component) => !component.isTheme())
|
||||||
|
|
||||||
await this.services.preferences.setValueDetached(PrefKey.ActiveThemes, Uuids(activeThemes))
|
await this.services.preferences.setValueDetached(PrefKey.DEPRECATED_ActiveThemes, Uuids(activeThemes))
|
||||||
await this.services.preferences.setValueDetached(PrefKey.ActiveComponents, Uuids(activeComponents))
|
await this.services.preferences.setValueDetached(PrefKey.ActiveComponents, Uuids(activeComponents))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
55
packages/snjs/lib/Migrations/Versions/2_208_0.ts
Normal file
55
packages/snjs/lib/Migrations/Versions/2_208_0.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { LocalPrefKey, ApplicationStage } from '@standardnotes/services'
|
||||||
|
import { Migration } from '@Lib/Migrations/Migration'
|
||||||
|
import { PrefDefaults, PrefKey } from '@standardnotes/models'
|
||||||
|
|
||||||
|
export class Migration2_208_0 extends Migration {
|
||||||
|
static override version(): string {
|
||||||
|
return '2.208.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
protected registerStageHandlers(): void {
|
||||||
|
this.registerStageHandler(ApplicationStage.FullSyncCompleted_13, async () => {
|
||||||
|
await this.migrateSyncedPreferencesToLocal()
|
||||||
|
|
||||||
|
this.markDone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private async migrateSyncedPreferencesToLocal(): Promise<void> {
|
||||||
|
this.services.preferences.setLocalValue(
|
||||||
|
LocalPrefKey.ActiveThemes,
|
||||||
|
this.services.preferences.getValue(
|
||||||
|
PrefKey.DEPRECATED_ActiveThemes,
|
||||||
|
PrefDefaults[PrefKey.DEPRECATED_ActiveThemes],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
this.services.preferences.setLocalValue(
|
||||||
|
LocalPrefKey.UseSystemColorScheme,
|
||||||
|
this.services.preferences.getValue(
|
||||||
|
PrefKey.DEPRECATED_UseSystemColorScheme,
|
||||||
|
PrefDefaults[PrefKey.DEPRECATED_UseSystemColorScheme],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
this.services.preferences.setLocalValue(
|
||||||
|
LocalPrefKey.AutoLightThemeIdentifier,
|
||||||
|
this.services.preferences.getValue(
|
||||||
|
PrefKey.DEPRECATED_AutoLightThemeIdentifier,
|
||||||
|
PrefDefaults[PrefKey.DEPRECATED_AutoLightThemeIdentifier],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
this.services.preferences.setLocalValue(
|
||||||
|
LocalPrefKey.AutoDarkThemeIdentifier,
|
||||||
|
this.services.preferences.getValue(
|
||||||
|
PrefKey.DEPRECATED_AutoDarkThemeIdentifier,
|
||||||
|
PrefDefaults[PrefKey.DEPRECATED_AutoDarkThemeIdentifier],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
this.services.preferences.setLocalValue(
|
||||||
|
LocalPrefKey.UseTranslucentUI,
|
||||||
|
this.services.preferences.getValue(
|
||||||
|
PrefKey.DEPRECATED_UseTranslucentUI,
|
||||||
|
PrefDefaults[PrefKey.DEPRECATED_UseTranslucentUI],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import { Migration2_42_0 } from './2_42_0'
|
|||||||
import { Migration2_167_6 } from './2_167_6'
|
import { Migration2_167_6 } from './2_167_6'
|
||||||
import { Migration2_168_6 } from './2_168_6'
|
import { Migration2_168_6 } from './2_168_6'
|
||||||
import { Migration2_202_1 } from './2_202_1'
|
import { Migration2_202_1 } from './2_202_1'
|
||||||
|
import { Migration2_208_0 } from './2_208_0'
|
||||||
|
|
||||||
export const MigrationClasses = [
|
export const MigrationClasses = [
|
||||||
Migration2_0_15,
|
Migration2_0_15,
|
||||||
@@ -16,6 +17,7 @@ export const MigrationClasses = [
|
|||||||
Migration2_167_6,
|
Migration2_167_6,
|
||||||
Migration2_168_6,
|
Migration2_168_6,
|
||||||
Migration2_202_1,
|
Migration2_202_1,
|
||||||
|
Migration2_208_0,
|
||||||
]
|
]
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@@ -27,4 +29,5 @@ export {
|
|||||||
Migration2_167_6,
|
Migration2_167_6,
|
||||||
Migration2_168_6,
|
Migration2_168_6,
|
||||||
Migration2_202_1,
|
Migration2_202_1,
|
||||||
|
Migration2_208_0,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import {
|
|||||||
ItemManagerInterface,
|
ItemManagerInterface,
|
||||||
SyncServiceInterface,
|
SyncServiceInterface,
|
||||||
FeatureStatus,
|
FeatureStatus,
|
||||||
|
LocalPrefKey,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { GetFeatureUrl } from './UseCase/GetFeatureUrl'
|
import { GetFeatureUrl } from './UseCase/GetFeatureUrl'
|
||||||
import { ComponentManagerEventData } from './ComponentManagerEventData'
|
import { ComponentManagerEventData } from './ComponentManagerEventData'
|
||||||
@@ -393,7 +394,7 @@ export class ComponentManager
|
|||||||
this.logger.info('Toggling theme', uiFeature.uniqueIdentifier)
|
this.logger.info('Toggling theme', uiFeature.uniqueIdentifier)
|
||||||
|
|
||||||
if (this.isThemeActive(uiFeature)) {
|
if (this.isThemeActive(uiFeature)) {
|
||||||
await this.removeActiveTheme(uiFeature)
|
this.removeActiveTheme(uiFeature)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,7 +404,7 @@ export class ComponentManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Activate current before deactivating others, so as not to flicker */
|
/* Activate current before deactivating others, so as not to flicker */
|
||||||
await this.addActiveTheme(uiFeature)
|
this.addActiveTheme(uiFeature)
|
||||||
|
|
||||||
/* Deactive currently active theme(s) if new theme is not layerable */
|
/* Deactive currently active theme(s) if new theme is not layerable */
|
||||||
if (!uiFeature.layerable) {
|
if (!uiFeature.layerable) {
|
||||||
@@ -416,7 +417,7 @@ export class ComponentManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!candidate.layerable) {
|
if (!candidate.layerable) {
|
||||||
await this.removeActiveTheme(candidate)
|
this.removeActiveTheme(candidate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -453,7 +454,7 @@ export class ComponentManager
|
|||||||
const features: NativeFeatureIdentifier[] = []
|
const features: NativeFeatureIdentifier[] = []
|
||||||
const uuids: Uuid[] = []
|
const uuids: Uuid[] = []
|
||||||
|
|
||||||
const strings = this.preferences.getValue(PrefKey.ActiveThemes, undefined) ?? []
|
const strings = this.preferences.getLocalValue(LocalPrefKey.ActiveThemes, [])
|
||||||
for (const string of strings) {
|
for (const string of strings) {
|
||||||
const nativeIdentifier = NativeFeatureIdentifier.create(string)
|
const nativeIdentifier = NativeFeatureIdentifier.create(string)
|
||||||
if (!nativeIdentifier.isFailed()) {
|
if (!nativeIdentifier.isFailed()) {
|
||||||
@@ -534,24 +535,24 @@ export class ComponentManager
|
|||||||
return preferences[preferencesLookupKey]
|
return preferences[preferencesLookupKey]
|
||||||
}
|
}
|
||||||
|
|
||||||
async addActiveTheme(theme: UIFeature<ThemeFeatureDescription>): Promise<void> {
|
addActiveTheme(theme: UIFeature<ThemeFeatureDescription>) {
|
||||||
const activeThemes = (this.preferences.getValue(PrefKey.ActiveThemes, undefined) ?? []).slice()
|
const activeThemes = this.preferences.getLocalValue(LocalPrefKey.ActiveThemes, []).slice()
|
||||||
|
|
||||||
activeThemes.push(theme.uniqueIdentifier.value)
|
activeThemes.push(theme.uniqueIdentifier.value)
|
||||||
|
|
||||||
await this.preferences.setValue(PrefKey.ActiveThemes, activeThemes)
|
this.preferences.setLocalValue(LocalPrefKey.ActiveThemes, activeThemes)
|
||||||
}
|
}
|
||||||
|
|
||||||
async replaceActiveTheme(theme: UIFeature<ThemeFeatureDescription>): Promise<void> {
|
replaceActiveTheme(theme: UIFeature<ThemeFeatureDescription>) {
|
||||||
await this.preferences.setValue(PrefKey.ActiveThemes, [theme.uniqueIdentifier.value])
|
this.preferences.setLocalValue(LocalPrefKey.ActiveThemes, [theme.uniqueIdentifier.value])
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeActiveTheme(theme: UIFeature<ThemeFeatureDescription>): Promise<void> {
|
removeActiveTheme(theme: UIFeature<ThemeFeatureDescription>) {
|
||||||
const activeThemes = this.preferences.getValue(PrefKey.ActiveThemes, undefined) ?? []
|
const activeThemes = this.preferences.getLocalValue(LocalPrefKey.ActiveThemes, [])
|
||||||
|
|
||||||
const filteredThemes = activeThemes.filter((activeTheme) => activeTheme !== theme.uniqueIdentifier.value)
|
const filteredThemes = activeThemes.filter((activeTheme) => activeTheme !== theme.uniqueIdentifier.value)
|
||||||
|
|
||||||
await this.preferences.setValue(PrefKey.ActiveThemes, filteredThemes)
|
this.preferences.setLocalValue(LocalPrefKey.ActiveThemes, filteredThemes)
|
||||||
}
|
}
|
||||||
|
|
||||||
isThemeActive(theme: UIFeature<ThemeFeatureDescription>): boolean {
|
isThemeActive(theme: UIFeature<ThemeFeatureDescription>): boolean {
|
||||||
@@ -559,13 +560,13 @@ export class ComponentManager
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeThemes = this.preferences.getValue(PrefKey.ActiveThemes, undefined) ?? []
|
const activeThemes = this.preferences.getLocalValue(LocalPrefKey.ActiveThemes, [])
|
||||||
|
|
||||||
return activeThemes.includes(theme.uniqueIdentifier.value)
|
return activeThemes.includes(theme.uniqueIdentifier.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
async addActiveComponent(component: ComponentInterface): Promise<void> {
|
async addActiveComponent(component: ComponentInterface): Promise<void> {
|
||||||
const activeComponents = (this.preferences.getValue(PrefKey.ActiveComponents, undefined) ?? []).slice()
|
const activeComponents = this.preferences.getValue(PrefKey.ActiveComponents, []).slice()
|
||||||
|
|
||||||
activeComponents.push(component.uuid)
|
activeComponents.push(component.uuid)
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ import {
|
|||||||
InternalEventInterface,
|
InternalEventInterface,
|
||||||
ApplicationEvent,
|
ApplicationEvent,
|
||||||
ApplicationStageChangedEventPayload,
|
ApplicationStageChangedEventPayload,
|
||||||
|
StorageServiceInterface,
|
||||||
|
StorageKey,
|
||||||
|
LocalPrefKey,
|
||||||
|
LocalPrefValue,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { ContentType } from '@standardnotes/domain-core'
|
import { ContentType } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
@@ -24,6 +28,7 @@ export class PreferencesService
|
|||||||
private shouldReload = true
|
private shouldReload = true
|
||||||
private reloading = false
|
private reloading = false
|
||||||
private preferences?: SNUserPrefs
|
private preferences?: SNUserPrefs
|
||||||
|
private localPreferences: { [key in LocalPrefKey]?: LocalPrefValue[key] } = {}
|
||||||
private removeItemObserver?: () => void
|
private removeItemObserver?: () => void
|
||||||
private removeSyncObserver?: () => void
|
private removeSyncObserver?: () => void
|
||||||
|
|
||||||
@@ -32,6 +37,7 @@ export class PreferencesService
|
|||||||
items: ItemManager,
|
items: ItemManager,
|
||||||
private mutator: MutatorClientInterface,
|
private mutator: MutatorClientInterface,
|
||||||
private sync: SyncService,
|
private sync: SyncService,
|
||||||
|
private storage: StorageServiceInterface,
|
||||||
protected override internalEventBus: InternalEventBusInterface,
|
protected override internalEventBus: InternalEventBusInterface,
|
||||||
) {
|
) {
|
||||||
super(internalEventBus)
|
super(internalEventBus)
|
||||||
@@ -69,16 +75,36 @@ export class PreferencesService
|
|||||||
if (this.preferences) {
|
if (this.preferences) {
|
||||||
void this.notifyEvent(PreferencesServiceEvent.PreferencesChanged)
|
void this.notifyEvent(PreferencesServiceEvent.PreferencesChanged)
|
||||||
}
|
}
|
||||||
|
} else if (stage === ApplicationStage.StorageDecrypted_09) {
|
||||||
|
this.localPreferences = this.storage.getValue(StorageKey.LocalPreferences) ?? {}
|
||||||
|
void this.notifyEvent(PreferencesServiceEvent.LocalPreferencesChanged)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLocalValue<K extends LocalPrefKey>(
|
||||||
|
key: K,
|
||||||
|
defaultValue: LocalPrefValue[K] | undefined,
|
||||||
|
): LocalPrefValue[K] | undefined
|
||||||
|
getLocalValue<K extends LocalPrefKey>(key: K, defaultValue: LocalPrefValue[K]): LocalPrefValue[K]
|
||||||
|
getLocalValue<K extends LocalPrefKey>(key: K, defaultValue?: LocalPrefValue[K]): LocalPrefValue[K] | undefined {
|
||||||
|
return this.localPreferences[key] ?? defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
getValue<K extends PrefKey>(key: K, defaultValue: PrefValue[K] | undefined): PrefValue[K] | undefined
|
getValue<K extends PrefKey>(key: K, defaultValue: PrefValue[K] | undefined): PrefValue[K] | undefined
|
||||||
getValue<K extends PrefKey>(key: K, defaultValue: PrefValue[K]): PrefValue[K]
|
getValue<K extends PrefKey>(key: K, defaultValue: PrefValue[K]): PrefValue[K]
|
||||||
getValue<K extends PrefKey>(key: K, defaultValue?: PrefValue[K]): PrefValue[K] | undefined {
|
getValue<K extends PrefKey>(key: K, defaultValue?: PrefValue[K]): PrefValue[K] | undefined {
|
||||||
return this.preferences?.getPref(key) ?? defaultValue
|
return this.preferences?.getPref(key) ?? defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setLocalValue<K extends LocalPrefKey>(key: K, value: LocalPrefValue[K]): void {
|
||||||
|
this.localPreferences[key] = value
|
||||||
|
|
||||||
|
this.storage.setValue(StorageKey.LocalPreferences, this.localPreferences)
|
||||||
|
|
||||||
|
void this.notifyEvent(PreferencesServiceEvent.LocalPreferencesChanged)
|
||||||
|
}
|
||||||
|
|
||||||
async setValue<K extends PrefKey>(key: K, value: PrefValue[K]): Promise<void> {
|
async setValue<K extends PrefKey>(key: K, value: PrefValue[K]): Promise<void> {
|
||||||
await this.setValueDetached(key, value)
|
await this.setValueDetached(key, value)
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import {
|
|||||||
UIFeature,
|
UIFeature,
|
||||||
CreateDecryptedLocalStorageContextPayload,
|
CreateDecryptedLocalStorageContextPayload,
|
||||||
LocalStorageDecryptedContextualPayload,
|
LocalStorageDecryptedContextualPayload,
|
||||||
PrefKey,
|
|
||||||
PrefDefaults,
|
PrefDefaults,
|
||||||
ComponentInterface,
|
ComponentInterface,
|
||||||
} from '@standardnotes/models'
|
} from '@standardnotes/models'
|
||||||
@@ -12,8 +11,8 @@ import {
|
|||||||
StorageValueModes,
|
StorageValueModes,
|
||||||
FeatureStatus,
|
FeatureStatus,
|
||||||
PreferenceServiceInterface,
|
PreferenceServiceInterface,
|
||||||
PreferencesServiceEvent,
|
|
||||||
ComponentManagerInterface,
|
ComponentManagerInterface,
|
||||||
|
LocalPrefKey,
|
||||||
} from '@standardnotes/services'
|
} from '@standardnotes/services'
|
||||||
import { NativeFeatureIdentifier, FindNativeTheme, ThemeFeatureDescription } from '@standardnotes/features'
|
import { NativeFeatureIdentifier, FindNativeTheme, ThemeFeatureDescription } from '@standardnotes/features'
|
||||||
import { WebApplicationInterface } from '../WebApplication/WebApplicationInterface'
|
import { WebApplicationInterface } from '../WebApplication/WebApplicationInterface'
|
||||||
@@ -75,56 +74,6 @@ export class ThemeManager extends AbstractUIService {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.eventDisposers.push(
|
|
||||||
this.preferences.addEventObserver(async (event) => {
|
|
||||||
if (event !== PreferencesServiceEvent.PreferencesChanged) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.toggleTranslucentUIColors()
|
|
||||||
|
|
||||||
let hasChange = false
|
|
||||||
|
|
||||||
const { features, uuids } = this.components.getActiveThemesIdentifiers()
|
|
||||||
|
|
||||||
const featuresList = new ActiveThemeList(this.application.items, features)
|
|
||||||
const uuidsList = new ActiveThemeList(this.application.items, uuids)
|
|
||||||
|
|
||||||
for (const active of this.themesActiveInTheUI.getList()) {
|
|
||||||
if (!featuresList.has(active) && !uuidsList.has(active)) {
|
|
||||||
this.deactivateThemeInTheUI(active)
|
|
||||||
hasChange = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const feature of features) {
|
|
||||||
if (!this.themesActiveInTheUI.has(feature)) {
|
|
||||||
const theme = FindNativeTheme(feature.value)
|
|
||||||
if (theme) {
|
|
||||||
const uiFeature = new UIFeature<ThemeFeatureDescription>(theme)
|
|
||||||
this.activateTheme(uiFeature)
|
|
||||||
hasChange = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const uuid of uuids) {
|
|
||||||
if (!this.themesActiveInTheUI.has(uuid)) {
|
|
||||||
const theme = this.application.items.findItem<ComponentInterface>(uuid.value)
|
|
||||||
if (theme) {
|
|
||||||
const uiFeature = new UIFeature<ThemeFeatureDescription>(theme)
|
|
||||||
this.activateTheme(uiFeature)
|
|
||||||
hasChange = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasChange) {
|
|
||||||
this.cacheThemeState().catch(console.error)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override async onAppEvent(event: ApplicationEvent) {
|
override async onAppEvent(event: ApplicationEvent) {
|
||||||
@@ -154,15 +103,15 @@ export class ThemeManager extends AbstractUIService {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case ApplicationEvent.PreferencesChanged: {
|
case ApplicationEvent.LocalPreferencesChanged: {
|
||||||
void this.handlePreferencesChangeEvent()
|
void this.handleLocalPreferencesChangeEvent()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleMobileColorSchemeChangeEvent() {
|
async handleMobileColorSchemeChangeEvent() {
|
||||||
const useDeviceThemeSettings = this.application.getPreference(PrefKey.UseSystemColorScheme, false)
|
const useDeviceThemeSettings = this.preferences.getLocalValue(LocalPrefKey.UseSystemColorScheme, false)
|
||||||
|
|
||||||
if (useDeviceThemeSettings) {
|
if (useDeviceThemeSettings) {
|
||||||
const prefersDarkColorScheme = (await this.application.mobileDevice.getColorScheme()) === 'dark'
|
const prefersDarkColorScheme = (await this.application.mobileDevice.getColorScheme()) === 'dark'
|
||||||
@@ -170,10 +119,54 @@ export class ThemeManager extends AbstractUIService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handlePreferencesChangeEvent() {
|
private handleThemeStateChange() {
|
||||||
|
let hasChange = false
|
||||||
|
|
||||||
|
const { features, uuids } = this.components.getActiveThemesIdentifiers()
|
||||||
|
|
||||||
|
const featuresList = new ActiveThemeList(this.application.items, features)
|
||||||
|
const uuidsList = new ActiveThemeList(this.application.items, uuids)
|
||||||
|
|
||||||
|
for (const active of this.themesActiveInTheUI.getList()) {
|
||||||
|
if (!featuresList.has(active) && !uuidsList.has(active)) {
|
||||||
|
this.deactivateThemeInTheUI(active)
|
||||||
|
hasChange = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const feature of features) {
|
||||||
|
if (!this.themesActiveInTheUI.has(feature)) {
|
||||||
|
const theme = FindNativeTheme(feature.value)
|
||||||
|
if (theme) {
|
||||||
|
const uiFeature = new UIFeature<ThemeFeatureDescription>(theme)
|
||||||
|
this.activateTheme(uiFeature)
|
||||||
|
hasChange = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const uuid of uuids) {
|
||||||
|
if (!this.themesActiveInTheUI.has(uuid)) {
|
||||||
|
const theme = this.application.items.findItem<ComponentInterface>(uuid.value)
|
||||||
|
if (theme) {
|
||||||
|
const uiFeature = new UIFeature<ThemeFeatureDescription>(theme)
|
||||||
|
this.activateTheme(uiFeature)
|
||||||
|
hasChange = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasChange) {
|
||||||
|
this.cacheThemeState().catch(console.error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleLocalPreferencesChangeEvent() {
|
||||||
|
this.handleThemeStateChange()
|
||||||
|
|
||||||
this.toggleTranslucentUIColors()
|
this.toggleTranslucentUIColors()
|
||||||
|
|
||||||
const useDeviceThemeSettings = this.application.getPreference(PrefKey.UseSystemColorScheme, false)
|
const useDeviceThemeSettings = this.preferences.getLocalValue(LocalPrefKey.UseSystemColorScheme, false)
|
||||||
|
|
||||||
const hasPreferenceChanged = useDeviceThemeSettings !== this.lastUseDeviceThemeSettings
|
const hasPreferenceChanged = useDeviceThemeSettings !== this.lastUseDeviceThemeSettings
|
||||||
|
|
||||||
@@ -218,7 +211,7 @@ export class ThemeManager extends AbstractUIService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private colorSchemeEventHandler(event: MediaQueryListEvent) {
|
private colorSchemeEventHandler(event: MediaQueryListEvent) {
|
||||||
const shouldChangeTheme = this.application.getPreference(PrefKey.UseSystemColorScheme, false)
|
const shouldChangeTheme = this.preferences.getLocalValue(LocalPrefKey.UseSystemColorScheme, false)
|
||||||
|
|
||||||
if (shouldChangeTheme) {
|
if (shouldChangeTheme) {
|
||||||
this.setThemeAsPerColorScheme(event.matches)
|
this.setThemeAsPerColorScheme(event.matches)
|
||||||
@@ -226,10 +219,14 @@ export class ThemeManager extends AbstractUIService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setThemeAsPerColorScheme(prefersDarkColorScheme: boolean) {
|
private setThemeAsPerColorScheme(prefersDarkColorScheme: boolean) {
|
||||||
const preference = prefersDarkColorScheme ? PrefKey.AutoDarkThemeIdentifier : PrefKey.AutoLightThemeIdentifier
|
const preference = prefersDarkColorScheme
|
||||||
|
? LocalPrefKey.AutoDarkThemeIdentifier
|
||||||
|
: LocalPrefKey.AutoLightThemeIdentifier
|
||||||
|
|
||||||
const preferenceDefault =
|
const preferenceDefault =
|
||||||
preference === PrefKey.AutoDarkThemeIdentifier ? NativeFeatureIdentifier.TYPES.DarkTheme : DefaultThemeIdentifier
|
preference === LocalPrefKey.AutoDarkThemeIdentifier
|
||||||
|
? NativeFeatureIdentifier.TYPES.DarkTheme
|
||||||
|
: DefaultThemeIdentifier
|
||||||
|
|
||||||
const usecase = new GetAllThemesUseCase(this.application.items)
|
const usecase = new GetAllThemesUseCase(this.application.items)
|
||||||
const { thirdParty, native } = usecase.execute({ excludeLayerable: false })
|
const { thirdParty, native } = usecase.execute({ excludeLayerable: false })
|
||||||
@@ -237,7 +234,7 @@ export class ThemeManager extends AbstractUIService {
|
|||||||
|
|
||||||
const activeTheme = themes.find((theme) => this.components.isThemeActive(theme) && !theme.layerable)
|
const activeTheme = themes.find((theme) => this.components.isThemeActive(theme) && !theme.layerable)
|
||||||
|
|
||||||
const themeIdentifier = this.preferences.getValue(preference, preferenceDefault)
|
const themeIdentifier = this.preferences.getLocalValue(preference, preferenceDefault)
|
||||||
|
|
||||||
const toggleActiveTheme = () => {
|
const toggleActiveTheme = () => {
|
||||||
if (activeTheme) {
|
if (activeTheme) {
|
||||||
@@ -337,7 +334,7 @@ export class ThemeManager extends AbstractUIService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private shouldUseTranslucentUI() {
|
private shouldUseTranslucentUI() {
|
||||||
return this.application.getPreference(PrefKey.UseTranslucentUI, PrefDefaults[PrefKey.UseTranslucentUI])
|
return this.preferences.getLocalValue(LocalPrefKey.UseTranslucentUI, PrefDefaults[LocalPrefKey.UseTranslucentUI])
|
||||||
}
|
}
|
||||||
|
|
||||||
private toggleTranslucentUIColors() {
|
private toggleTranslucentUIColors() {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { usePremiumModal } from '@/Hooks/usePremiumModal'
|
|||||||
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
import HorizontalSeparator from '@/Components/Shared/HorizontalSeparator'
|
||||||
import Switch from '@/Components/Switch/Switch'
|
import Switch from '@/Components/Switch/Switch'
|
||||||
import { WebApplication } from '@/Application/WebApplication'
|
import { WebApplication } from '@/Application/WebApplication'
|
||||||
import { PrefKey, FeatureStatus, naturalSort, PrefDefaults } from '@standardnotes/snjs'
|
import { FeatureStatus, naturalSort, LocalPrefKey } from '@standardnotes/snjs'
|
||||||
import { observer } from 'mobx-react-lite'
|
import { observer } from 'mobx-react-lite'
|
||||||
import { FunctionComponent, useEffect, useState } from 'react'
|
import { FunctionComponent, useEffect, useState } from 'react'
|
||||||
import { Subtitle, Title, Text } from '@/Components/Preferences/PreferencesComponents/Content'
|
import { Subtitle, Title, Text } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||||
@@ -14,7 +14,7 @@ import PreferencesSegment from '../PreferencesComponents/PreferencesSegment'
|
|||||||
import { PremiumFeatureIconName } from '@/Components/Icon/PremiumFeatureIcon'
|
import { PremiumFeatureIconName } from '@/Components/Icon/PremiumFeatureIcon'
|
||||||
import EditorAppearance from './Appearance/EditorAppearance'
|
import EditorAppearance from './Appearance/EditorAppearance'
|
||||||
import { GetAllThemesUseCase } from '@standardnotes/ui-services'
|
import { GetAllThemesUseCase } from '@standardnotes/ui-services'
|
||||||
import usePreference from '@/Hooks/usePreference'
|
import { useLocalPreference } from '@/Hooks/usePreference'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
application: WebApplication
|
application: WebApplication
|
||||||
@@ -24,19 +24,14 @@ const Appearance: FunctionComponent<Props> = ({ application }) => {
|
|||||||
const premiumModal = usePremiumModal()
|
const premiumModal = usePremiumModal()
|
||||||
|
|
||||||
const [themeItems, setThemeItems] = useState<DropdownItem[]>([])
|
const [themeItems, setThemeItems] = useState<DropdownItem[]>([])
|
||||||
const [autoLightTheme, setAutoLightTheme] = useState<string>(() =>
|
|
||||||
application.getPreference(PrefKey.AutoLightThemeIdentifier, PrefDefaults[PrefKey.AutoLightThemeIdentifier]),
|
|
||||||
)
|
|
||||||
const [autoDarkTheme, setAutoDarkTheme] = useState<string>(() =>
|
|
||||||
application.getPreference(PrefKey.AutoDarkThemeIdentifier, PrefDefaults[PrefKey.AutoDarkThemeIdentifier]),
|
|
||||||
)
|
|
||||||
const [useDeviceSettings, setUseDeviceSettings] = useState(() =>
|
|
||||||
application.getPreference(PrefKey.UseSystemColorScheme, PrefDefaults[PrefKey.UseSystemColorScheme]),
|
|
||||||
)
|
|
||||||
|
|
||||||
const useTranslucentUI = usePreference(PrefKey.UseTranslucentUI)
|
const [autoLightTheme, setAutoLightTheme] = useLocalPreference(LocalPrefKey.AutoLightThemeIdentifier)
|
||||||
|
const [autoDarkTheme, setAutoDarkTheme] = useLocalPreference(LocalPrefKey.AutoDarkThemeIdentifier)
|
||||||
|
const [useDeviceSettings, setUseDeviceSettings] = useLocalPreference(LocalPrefKey.UseSystemColorScheme)
|
||||||
|
|
||||||
|
const [useTranslucentUI, setUseTranslucentUI] = useLocalPreference(LocalPrefKey.UseTranslucentUI)
|
||||||
const toggleTranslucentUI = () => {
|
const toggleTranslucentUI = () => {
|
||||||
application.setPreference(PrefKey.UseTranslucentUI, !useTranslucentUI).catch(console.error)
|
setUseTranslucentUI(!useTranslucentUI)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -76,12 +71,12 @@ const Appearance: FunctionComponent<Props> = ({ application }) => {
|
|||||||
}, [application])
|
}, [application])
|
||||||
|
|
||||||
const toggleUseDeviceSettings = () => {
|
const toggleUseDeviceSettings = () => {
|
||||||
application.setPreference(PrefKey.UseSystemColorScheme, !useDeviceSettings).catch(console.error)
|
setUseDeviceSettings(!useDeviceSettings)
|
||||||
if (!application.getPreference(PrefKey.AutoLightThemeIdentifier)) {
|
if (!application.preferences.getLocalValue(LocalPrefKey.AutoLightThemeIdentifier)) {
|
||||||
application.setPreference(PrefKey.AutoLightThemeIdentifier, autoLightTheme).catch(console.error)
|
setAutoLightTheme(autoLightTheme)
|
||||||
}
|
}
|
||||||
if (!application.getPreference(PrefKey.AutoDarkThemeIdentifier)) {
|
if (!application.preferences.getLocalValue(LocalPrefKey.AutoDarkThemeIdentifier)) {
|
||||||
application.setPreference(PrefKey.AutoDarkThemeIdentifier, autoDarkTheme).catch(console.error)
|
setAutoDarkTheme(autoDarkTheme)
|
||||||
}
|
}
|
||||||
setUseDeviceSettings(!useDeviceSettings)
|
setUseDeviceSettings(!useDeviceSettings)
|
||||||
}
|
}
|
||||||
@@ -92,7 +87,6 @@ const Appearance: FunctionComponent<Props> = ({ application }) => {
|
|||||||
premiumModal.activate(`${item.label} theme`)
|
premiumModal.activate(`${item.label} theme`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
application.setPreference(PrefKey.AutoLightThemeIdentifier, value).catch(console.error)
|
|
||||||
setAutoLightTheme(value)
|
setAutoLightTheme(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +96,6 @@ const Appearance: FunctionComponent<Props> = ({ application }) => {
|
|||||||
premiumModal.activate(`${item.label} theme`)
|
premiumModal.activate(`${item.label} theme`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
application.setPreference(PrefKey.AutoDarkThemeIdentifier, value).catch(console.error)
|
|
||||||
setAutoDarkTheme(value)
|
setAutoDarkTheme(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ const QuickSettingsMenu: FunctionComponent<MenuProps> = ({ closeMenu }) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return application.preferences.addEventObserver((event) => {
|
return application.preferences.addEventObserver((event) => {
|
||||||
if (event === PreferencesServiceEvent.PreferencesChanged) {
|
if (event === PreferencesServiceEvent.LocalPreferencesChanged) {
|
||||||
reloadThemes()
|
reloadThemes()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,29 @@
|
|||||||
import { useApplication } from '@/Components/ApplicationProvider'
|
import { useApplication } from '@/Components/ApplicationProvider'
|
||||||
import { ApplicationEvent, PrefKey, PrefDefaults } from '@standardnotes/snjs'
|
import { ApplicationEvent, PrefKey, PrefDefaults, LocalPrefKey, LocalPrefValue } from '@standardnotes/snjs'
|
||||||
import { useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
export function useLocalPreference<Key extends LocalPrefKey>(preference: Key) {
|
||||||
|
const application = useApplication()
|
||||||
|
|
||||||
|
const [value, setValue] = useState(application.preferences.getLocalValue(preference, PrefDefaults[preference]))
|
||||||
|
|
||||||
|
const setNewValue = useCallback(
|
||||||
|
(newValue: LocalPrefValue[Key]) => {
|
||||||
|
application.preferences.setLocalValue(preference, newValue)
|
||||||
|
},
|
||||||
|
[application, preference],
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return application.addEventObserver(async () => {
|
||||||
|
const latestValue = application.preferences.getLocalValue(preference, PrefDefaults[preference])
|
||||||
|
|
||||||
|
setValue(latestValue)
|
||||||
|
}, ApplicationEvent.LocalPreferencesChanged)
|
||||||
|
}, [application, preference])
|
||||||
|
|
||||||
|
return [value, setNewValue] as const
|
||||||
|
}
|
||||||
|
|
||||||
export default function usePreference<Key extends PrefKey>(preference: Key) {
|
export default function usePreference<Key extends PrefKey>(preference: Key) {
|
||||||
const application = useApplication()
|
const application = useApplication()
|
||||||
|
|||||||
Reference in New Issue
Block a user