diff --git a/src/components/font_control/font_control.js b/src/components/font_control/font_control.js index d7c5aa225..d1f3390cc 100644 --- a/src/components/font_control/font_control.js +++ b/src/components/font_control/font_control.js @@ -21,7 +21,14 @@ export default { Popover, LocalSettingIndicator, }, - props: ['name', 'label', 'modelValue', 'fallback', 'options', 'no-inherit'], + props: [ + 'name', + 'label', + 'modelValue', + 'fallback', + 'options', + 'no-inherit', + ], mounted() { useInterfaceStore().queryLocalFonts() }, diff --git a/src/components/settings_modal/helpers/list_setting.js b/src/components/settings_modal/helpers/list_setting.js index 232ea123f..c1d504cd5 100644 --- a/src/components/settings_modal/helpers/list_setting.js +++ b/src/components/settings_modal/helpers/list_setting.js @@ -1,8 +1,6 @@ import Checkbox from 'src/components/checkbox/checkbox.vue' import Setting from './setting.js' -import { useSyncConfigStore } from 'src/stores/sync_config.js' - export default { ...Setting, data() { @@ -45,7 +43,7 @@ export default { if (this.forceNew) return true if (!this.allowNew) return false - const isExpert = useSyncConfigStore().mergedConfig.expertLevel > 0 + const isExpert = this.$store.state.config.expertLevel > 0 const hasBuiltins = this.builtinEntries.length > 0 if (hasBuiltins) { diff --git a/src/components/settings_modal/settings_modal.js b/src/components/settings_modal/settings_modal.js index a99067f36..25c508bef 100644 --- a/src/components/settings_modal/settings_modal.js +++ b/src/components/settings_modal/settings_modal.js @@ -9,10 +9,6 @@ import PanelLoading from 'src/components/panel_loading/panel_loading.vue' import Popover from '../popover/popover.vue' import { useInterfaceStore } from 'src/stores/interface.js' -import { - LOCAL_ONLY_KEYS, - useLocalConfigStore, -} from 'src/stores/local_config.js' import { useSyncConfigStore } from 'src/stores/sync_config.js' import { @@ -141,34 +137,7 @@ const SettingsModal = { }, onImport(data) { if (data) { - Object.entries(data).forEach(([path, value]) => { - if (LOCAL_ONLY_KEYS.has(path)) { - useLocalConfigStore().set({ path, value }) - } else { - if (path.startsWith('muteFilters')) { - Object.keys( - useSyncConfigStore().mergedConfig.muteFilters, - ).forEach((key) => { - useSyncConfigStore().unsetPreference({ - path: `simple.${path}.${key}`, - }) - }) - - Object.entries(value).forEach(([key, filter]) => { - useSyncConfigStore().setPreference({ - path: `simple.${path}.${key}`, - value: filter, - }) - }) - } else { - useSyncConfigStore().setPreference({ - path: `simple.${path}`, - value, - }) - } - } - }) - useSyncConfigStore().pushSyncConfig() + this.$store.dispatch('loadSettings', data) } }, restore() { @@ -181,7 +150,7 @@ const SettingsModal = { this.dataThemeExporter.exportData() }, generateExport(theme = false) { - const config = useSyncConfigStore().mergedConfigWithoutDefaults + const { config } = this.$store.state let sample = config if (!theme) { const ignoreList = new Set([ @@ -190,9 +159,7 @@ const SettingsModal = { 'colors', ]) sample = Object.fromEntries( - Object.entries(sample).filter( - ([key, value]) => !ignoreList.has(key) && value !== undefined, - ), + Object.entries(sample).filter(([key]) => !ignoreList.has(key)), ) } const clone = cloneDeep(sample) diff --git a/src/components/settings_modal/settings_modal_user_content.js b/src/components/settings_modal/settings_modal_user_content.js index 6c33b4fa6..ddee812ca 100644 --- a/src/components/settings_modal/settings_modal_user_content.js +++ b/src/components/settings_modal/settings_modal_user_content.js @@ -16,7 +16,6 @@ import SecurityTab from './tabs/security_tab/security_tab.vue' import StyleTab from './tabs/style_tab/style_tab.vue' import { useInterfaceStore } from 'src/stores/interface.js' -import { useSyncConfigStore } from 'src/stores/sync_config.js' import { library } from '@fortawesome/fontawesome-svg-core' import { @@ -84,7 +83,7 @@ const SettingsModalContent = { return useInterfaceStore().settingsModalState === 'visible' }, expertLevel() { - return useSyncConfigStore().mergedConfig.expertLevel + return this.$store.state.config.expertLevel }, }, data() { diff --git a/src/components/settings_modal/tabs/clutter_tab.js b/src/components/settings_modal/tabs/clutter_tab.js index 85749ab3f..510425e2d 100644 --- a/src/components/settings_modal/tabs/clutter_tab.js +++ b/src/components/settings_modal/tabs/clutter_tab.js @@ -38,6 +38,55 @@ const ClutterTab = { Object.entries(store.prefsStorage.simple.muteFilters), muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters, }), + onMuteDefaultActionLv1: { + get() { + const value = this.$store.state.config.onMuteDefaultAction + if (value === 'ask' || value === 'forever') { + return value + } else { + return 'temporarily' + } + }, + set(value) { + let realValue = value + if (value !== 'ask' && value !== 'forever') { + realValue = '14d' + } + useSyncConfigStore().setSimplePrefAndSave({ + path: 'onMuteDefaultAction', + value: realValue, + }) + }, + }, + onBlockDefaultActionLv1: { + get() { + const value = this.$store.state.config.onBlockDefaultAction + if (value === 'ask' || value === 'forever') { + return value + } else { + return 'temporarily' + } + }, + set(value) { + let realValue = value + if (value !== 'ask' && value !== 'forever') { + realValue = '14d' + } + useSyncConfigStore().setSimplePrefAndSave({ + path: 'onBlockDefaultAction', + value: realValue, + }) + }, + }, + muteFiltersDraft() { + return Object.entries(this.muteFiltersDraftObject) + }, + muteFiltersExpired() { + const now = Date.now() + return Object.entries(this.muteFiltersDraftObject).filter( + ([, { expires }]) => expires != null && expires <= now, + ) + }, }, methods: { ...mapActions(useSyncConfigStore, [ diff --git a/src/components/settings_modal/tabs/clutter_tab.vue b/src/components/settings_modal/tabs/clutter_tab.vue index 533cd85c6..8ae416ff8 100644 --- a/src/components/settings_modal/tabs/clutter_tab.vue +++ b/src/components/settings_modal/tabs/clutter_tab.vue @@ -83,7 +83,9 @@
  • - + {{ $t('settings.hide_shoutbox') }}
  • diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js index 3598de757..facc6073f 100644 --- a/src/components/settings_modal/tabs/filtering_tab.js +++ b/src/components/settings_modal/tabs/filtering_tab.js @@ -93,12 +93,14 @@ const FilteringTab = { computed: { ...SharedComputedObject(), ...mapState(useSyncConfigStore, { + muteFilters: (store) => + Object.entries(store.prefsStorage.simple.muteFilters), muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters, }), ...mapState(useInstanceCapabilitiesStore, ['blockExpiration']), onMuteDefaultActionLv1: { get() { - const value = useSyncConfigStore().mergedConfig.onMuteDefaultAction + const value = this.$store.state.config.onMuteDefaultAction if (value === 'ask' || value === 'forever') { return value } else { @@ -118,7 +120,7 @@ const FilteringTab = { }, onBlockDefaultActionLv1: { get() { - const value = useSyncConfigStore().mergedConfig.onBlockDefaultAction + const value = this.$store.state.config.onBlockDefaultAction if (value === 'ask' || value === 'forever') { return value } else { @@ -149,7 +151,7 @@ const FilteringTab = { methods: { ...mapActions(useSyncConfigStore, [ 'setPreference', - 'setSimplePrefAndSave', + 'setPrefAndSave', 'unsetPreference', 'unsetPrefAndSave', 'pushSyncConfig', @@ -258,12 +260,6 @@ const FilteringTab = { replyVisibility() { this.$store.dispatch('queueFlushAll') }, - muteFiltersObject() { - console.log('UPDATE') - this.muteFiltersDraftObject = cloneDeep( - useSyncConfigStore().prefsStorage.simple.muteFilters, - ) - }, }, } diff --git a/src/components/settings_modal/tabs/posts_tab.vue b/src/components/settings_modal/tabs/posts_tab.vue index 444f96392..d14475fc3 100644 --- a/src/components/settings_modal/tabs/posts_tab.vue +++ b/src/components/settings_modal/tabs/posts_tab.vue @@ -101,7 +101,6 @@ {{ $t('settings.mention_link_display') }} @@ -172,10 +171,7 @@
  • - + {{ $t('settings.nsfw_clickthrough') }}
      @@ -183,7 +179,6 @@ {{ $t('settings.preload_images') }} @@ -193,7 +188,6 @@ {{ $t('settings.use_one_click_nsfw') }} diff --git a/src/i18n/en.json b/src/i18n/en.json index 0165af240..70c099932 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -381,7 +381,6 @@ "select_all": "Select all" }, "settings": { - "invalid_settings_imported": "Error importing settings", "add_language": "Add fallback language", "remove_language": "Remove", "primary_language": "Primary language:", diff --git a/src/main.js b/src/main.js index ceb8c0878..a4269b4a7 100644 --- a/src/main.js +++ b/src/main.js @@ -41,7 +41,7 @@ const i18n = createI18n({ messages.setLanguage(i18n.global, currentLocale) const persistedStateOptions = { - paths: ['users.lastLoginName', 'oauth'], + paths: ['syncConfig.cache', 'config', 'users.lastLoginName', 'oauth'], } ;(async () => { diff --git a/src/modules/default_config_state.js b/src/modules/default_config_state.js index a391e9b21..fbfaf08a3 100644 --- a/src/modules/default_config_state.js +++ b/src/modules/default_config_state.js @@ -49,6 +49,8 @@ export const instanceDefaultConfig = { hideScrobbles: false, hideScrobblesAfter: '2d', maxThumbnails: 16, + hideNsfw: true, + preloadImage: true, loopVideo: true, loopVideoSilentOnly: true, /// This is not the streaming API configuration, but rather an option @@ -119,6 +121,7 @@ export const instanceDefaultConfig = { modalMobileCenter: false, playVideosInModal: false, + useOneClickNsfw: false, useContainFit: true, disableStickyHeaders: false, showScrollbars: false, @@ -162,9 +165,6 @@ export const instanceDefaultConfig = { export const defaultConfigLocal = { hideAttachments: false, hideAttachmentsInConv: false, - hideNsfw: true, - useOneClickNsfw: false, - preloadImage: true, postContentType: 'text/plain', sidebarRight: false, sidebarColumnWidth: '25rem', @@ -191,12 +191,9 @@ export const makeUndefined = (c) => export const defaultState = { // Set these to undefined so it does not interfere with default settings check ...makeUndefined(instanceDefaultConfig), - ...makeUndefined(defaultConfigLocal), - // If there are any configurations that does not make sense to - // have instance-wide default, put it here and explain why. - // # Special processing - // ## Theme stuff + // Special processing + // Theme stuff theme: undefined, // Very old theme store, stores preset name, still in use // V1 @@ -223,4 +220,15 @@ export const defaultState = { monospace: undefined, }, }, + + // Special handling: These fields are not of a primitive type, and + // might cause problems with current code because it specifically checks + // them in state.config (not getters.mergedConfig). + + // Specifically, muteWords is now deprecated in favour of a server-side configuration. + muteWords: [], + highlight: {}, + + // If there are any configurations that does not make sense to + // have instance-wide default, put it here and explain why. } diff --git a/src/modules/old_default_config_state.js b/src/modules/old_default_config_state.js index dc15e1c24..e53cafe29 100644 --- a/src/modules/old_default_config_state.js +++ b/src/modules/old_default_config_state.js @@ -18,6 +18,8 @@ export const defaultConfigSync = { hideScrobbles: false, hideScrobblesAfter: '2d', maxThumbnails: 16, + hideNsfw: true, + preloadImage: true, loopVideo: true, loopVideoSilentOnly: true, /// This is not the streaming API configuration, but rather an option @@ -91,6 +93,7 @@ export const defaultConfigSync = { modalMobileCenter: false, playVideosInModal: false, + useOneClickNsfw: false, useContainFit: true, disableStickyHeaders: false, showScrollbars: false, @@ -166,9 +169,6 @@ export const defaultConfigSync = { export const defaultConfigLocal = { hideAttachments: false, hideAttachmentsInConv: false, - hideNsfw: true, - useOneClickNsfw: false, - preloadImage: true, sidebarColumnWidth: '25rem', contentColumnWidth: '45rem', notifsColumnWidth: '25rem', @@ -182,4 +182,6 @@ export const defaultConfigLocal = { mentionLinkDisplay: 'short', imageCompression: true, alwaysUseJpeg: false, + imageCompression: true, + alwaysUseJpeg: false, } diff --git a/src/stores/local_config.js b/src/stores/local_config.js index 3611b559e..117be393d 100644 --- a/src/stores/local_config.js +++ b/src/stores/local_config.js @@ -6,8 +6,6 @@ import { useInstanceStore } from 'src/stores/instance' import { defaultState as configDefaultState } from 'src/modules/default_config_state' -export const LOCAL_ONLY_KEYS = new Set(Object.keys(configDefaultState)) - export const defaultState = { prefsStorage: { ...configDefaultState, @@ -34,7 +32,7 @@ export const useLocalConfigStore = defineStore('local_config', { unset({ path, value }) { set(this.prefsStorage, path, undefined) }, - clearLocalConfig() { + clearSyncConfig() { const blankState = { ...cloneDeep(defaultState) } Object.keys(this).forEach((k) => { this.prefsStorage[k] = blankState[k] diff --git a/src/stores/sync_config.js b/src/stores/sync_config.js index 996f32979..e43356e8e 100644 --- a/src/stores/sync_config.js +++ b/src/stores/sync_config.js @@ -18,21 +18,14 @@ import { toRaw } from 'vue' import { CURRENT_UPDATE_COUNTER } from 'src/components/update_notification/update_notification.js' import { useInstanceStore } from 'src/stores/instance.js' -import { - LOCAL_ONLY_KEYS, - useLocalConfigStore, -} from 'src/stores/local_config.js' +import { useLocalConfigStore } from 'src/stores/local_config.js' import { storage } from 'src/lib/storage.js' -import { - defaultState as configDefaultState, - defaultConfigLocal, - instanceDefaultConfig, -} from 'src/modules/default_config_state.js' +import { defaultState as configDefaultState } from 'src/modules/default_config_state.js' import { defaultConfigSync } from 'src/modules/old_default_config_state.js' export const VERSION = 2 -export const NEW_USER_DATE = new Date('2026-03-16') // date of writing this, basically +export const NEW_USER_DATE = new Date('2022-08-04') // date of writing this, basically export const COMMAND_TRIM_FLAGS = 1000 export const COMMAND_TRIM_FLAGS_AND_RESET = 1001 @@ -56,7 +49,6 @@ export const defaultState = { dontShowUpdateNotifs: false, collapseNav: false, muteFilters: {}, - ...configDefaultState, }, collections: { @@ -623,14 +615,14 @@ export const useSyncConfigStore = defineStore('sync_config', { let dirty = false console.debug('Migrating from old config') - const vuexState = (await storage.getItem('vuex-lz')) ?? {} - vuexState.config = vuexState.config ?? {} + const vuexState = await storage.getItem('vuex-lz') + const { config } = vuexState - const migratedEntries = new Set(vuexState.config._syncMigration ?? []) + const migratedEntries = new Set(config._syncMigration ?? []) console.debug(`Already migrated Values: ${[...migratedEntries].join()}`) Object.entries(defaultConfigSync).forEach(([key, value]) => { - const oldValue = vuexState.config[key] + const oldValue = config[key] const defaultValue = value const present = oldValue !== undefined @@ -638,13 +630,12 @@ export const useSyncConfigStore = defineStore('sync_config', { const different = !isEqual(oldValue, defaultValue) if (present && !migrated && different) { - console.debug(`Migrating config ${key}: ${oldValue}`) + console.debug(`Migrating config ${key}: ${oldValue}`,) this.setPreference({ path: `simple.${key}`, oldValue }) migratedEntries.add(key) needUpload = true } }) - vuexState.config._syncMigration = [...migratedEntries] storage.setItem('vuex-lz', vuexState) @@ -725,28 +716,9 @@ export const useSyncConfigStore = defineStore('sync_config', { const localPrefs = useLocalConfigStore().prefsStorage const tempPrefs = useLocalConfigStore().tempStorage const result = Object.fromEntries( - Object.entries(state.prefsStorage.simple).map(([k, value]) => [ + Object.entries(state.prefsStorage.simple).map(([k, v]) => [ k, - LOCAL_ONLY_KEYS.has(k) - ? (tempPrefs[k] ?? - localPrefs[k] ?? - instancePrefs[k] ?? - defaultConfigLocal[k]) - : (tempPrefs[k] ?? - localPrefs[k] ?? - value ?? - instancePrefs[k] ?? - instanceDefaultConfig[k]), - ]), - ) - return result - }, - mergedConfigWithoutDefaults: (state) => { - const localPrefs = useLocalConfigStore().prefsStorage - const result = Object.fromEntries( - Object.entries(state.prefsStorage.simple).map(([k, value]) => [ - k, - LOCAL_ONLY_KEYS.has(k) ? localPrefs[k] : value, + tempPrefs[k] ?? localPrefs[k] ?? v ?? instancePrefs[k], ]), ) return result diff --git a/src/stores/user_highlight.js b/src/stores/user_highlight.js index ae2bd4d4c..c8868921a 100644 --- a/src/stores/user_highlight.js +++ b/src/stores/user_highlight.js @@ -278,10 +278,8 @@ export const useUserHighlightStore = defineStore('user_highlight', { const userNew = userData.created_at > NEW_USER_DATE let dirty = false - const vuexState = (await storage.getItem('vuex-lz')) ?? {} - vuexState.config = vuexState.config ?? {} - const highlight = vuexState.config.highlight ?? {} - + const vuexState = await storage.getItem('vuex-lz') + const { highlight } = vuexState.config Object.entries(highlight).forEach(([user, value]) => { if ((highlight[user]._migrated || 0) < 1) { dirty = true diff --git a/src/sw.js b/src/sw.js index bfe35d3c5..e3225c91d 100644 --- a/src/sw.js +++ b/src/sw.js @@ -34,14 +34,14 @@ function getWindowClients() { } const setSettings = async () => { - const piniaState = await storage.getItem('pinia-local-sync_config') - const locale = piniaState.prefsStorage.simple.interfaceLanguage || 'en' + const vuexState = await storage.getItem('vuex-lz') + const locale = vuexState.config.interfaceLanguage || 'en' i18n.locale = locale const notificationsNativeArray = Object.entries( - piniaState.prefsStorage.simple.notificationNative, + vuexState.config.notificationNative, ) state.webPushAlwaysShowNotifications = - piniaState.prefsStorage.simple.webPushAlwaysShowNotifications + vuexState.config.webPushAlwaysShowNotifications state.allowedNotificationTypes = new Set( notificationsNativeArray