Merge branch 'develop' into upstream/2025.5.0
This commit is contained in:
commit
3ebf9c4a71
317 changed files with 6144 additions and 2603 deletions
|
|
@ -10,11 +10,12 @@ import type { SoundType } from '@/utility/sound.js';
|
|||
import type { Plugin } from '@/plugin.js';
|
||||
import type { DeviceKind } from '@/utility/device-kind.js';
|
||||
import type { DeckProfile } from '@/deck.js';
|
||||
import type { PreferencesDefinition } from './manager.js';
|
||||
import type { Pref, PreferencesDefinition } from './manager.js';
|
||||
import type { FollowingFeedState } from '@/types/following-feed.js';
|
||||
import { DEFAULT_DEVICE_KIND } from '@/utility/device-kind.js';
|
||||
import { searchEngineMap } from '@/utility/search-engine-map.js';
|
||||
import { defaultFollowingFeedState } from '@/types/following-feed.js';
|
||||
import { miLocalStorage } from '@/local-storage';
|
||||
|
||||
/** サウンド設定 */
|
||||
export type SoundStore = {
|
||||
|
|
@ -120,7 +121,7 @@ export const PREF_DEF = {
|
|||
default: false,
|
||||
},
|
||||
keepCw: {
|
||||
default: true,
|
||||
default: true as boolean | 'prepend-re',
|
||||
},
|
||||
rememberNoteVisibility: {
|
||||
default: false,
|
||||
|
|
@ -480,4 +481,84 @@ export const PREF_DEF = {
|
|||
default: true,
|
||||
},
|
||||
//#endregion
|
||||
|
||||
//#region hybrid options
|
||||
// These exist in preferences, but may have a legacy value in local storage.
|
||||
// Some parts of the system may still reference the legacy storage so both need to stay in sync!
|
||||
// Null means "fall back to existing value from localStorage"
|
||||
// For all of these preferences, "null" means fall back to existing value in localStorage.
|
||||
fontSize: {
|
||||
default: '0',
|
||||
needsReload: true,
|
||||
onSet: fontSize => {
|
||||
if (fontSize !== '0') {
|
||||
miLocalStorage.setItem('fontSize', fontSize);
|
||||
} else {
|
||||
miLocalStorage.removeItem('fontSize');
|
||||
}
|
||||
},
|
||||
} as Pref<'0' | '1' | '2' | '3'>,
|
||||
useSystemFont: {
|
||||
default: false,
|
||||
needsReload: true,
|
||||
onSet: useSystemFont => {
|
||||
if (useSystemFont) {
|
||||
miLocalStorage.setItem('useSystemFont', 't');
|
||||
} else {
|
||||
miLocalStorage.removeItem('useSystemFont');
|
||||
}
|
||||
},
|
||||
} as Pref<boolean>,
|
||||
cornerRadius: {
|
||||
default: 'sharkey',
|
||||
needsReload: true,
|
||||
onSet: cornerRadius => {
|
||||
if (cornerRadius === 'sharkey') {
|
||||
miLocalStorage.removeItem('cornerRadius');
|
||||
} else {
|
||||
miLocalStorage.setItem('cornerRadius', cornerRadius);
|
||||
}
|
||||
},
|
||||
} as Pref<'misskey' | 'sharkey'>,
|
||||
lang: {
|
||||
default: 'en-US',
|
||||
needsReload: true,
|
||||
onSet: lang => {
|
||||
miLocalStorage.setItem('lang', lang);
|
||||
miLocalStorage.removeItem('locale');
|
||||
miLocalStorage.removeItem('localeVersion');
|
||||
},
|
||||
} as Pref<string>,
|
||||
customCss: {
|
||||
default: '',
|
||||
needsReload: true,
|
||||
onSet: customCss => {
|
||||
if (customCss) {
|
||||
miLocalStorage.setItem('customCss', customCss);
|
||||
} else {
|
||||
miLocalStorage.removeItem('customCss');
|
||||
}
|
||||
},
|
||||
} as Pref<string>,
|
||||
neverShowDonationInfo: {
|
||||
default: false,
|
||||
onSet: neverShowDonationInfo => {
|
||||
if (neverShowDonationInfo) {
|
||||
miLocalStorage.setItem('neverShowDonationInfo', 'true');
|
||||
} else {
|
||||
miLocalStorage.removeItem('neverShowDonationInfo');
|
||||
}
|
||||
},
|
||||
} as Pref<boolean>,
|
||||
neverShowLocalOnlyInfo: {
|
||||
default: false,
|
||||
onSet: neverShowLocalOnlyInfo => {
|
||||
if (neverShowLocalOnlyInfo) {
|
||||
miLocalStorage.setItem('neverShowLocalOnlyInfo', 'true');
|
||||
} else {
|
||||
miLocalStorage.removeItem('neverShowLocalOnlyInfo');
|
||||
}
|
||||
},
|
||||
} as Pref<boolean>,
|
||||
//#endregion
|
||||
} satisfies PreferencesDefinition;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { computed, onUnmounted, ref, watch } from 'vue';
|
||||
import { computed, nextTick, onUnmounted, ref, watch } from 'vue';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { host, version } from '@@/js/config.js';
|
||||
import { PREF_DEF } from './def.js';
|
||||
|
|
@ -14,6 +14,7 @@ import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
|||
import { i18n } from '@/i18n.js';
|
||||
import * as os from '@/os.js';
|
||||
import { deepEqual } from '@/utility/deep-equal.js';
|
||||
import { reloadAsk } from '@/utility/reload-ask';
|
||||
|
||||
// NOTE: 明示的な設定値のひとつとして null もあり得るため、設定が存在しないかどうかを判定する目的で null で比較したり ?? を使ってはいけない
|
||||
|
||||
|
|
@ -84,16 +85,29 @@ export type StorageProvider = {
|
|||
cloudSet: <K extends keyof PREF>(ctx: { key: K; scope: Scope; value: ValueOf<K>; }) => Promise<void>;
|
||||
};
|
||||
|
||||
export type PreferencesDefinition = Record<string, {
|
||||
default: any;
|
||||
export type Pref<T> = {
|
||||
default: T;
|
||||
accountDependent?: boolean;
|
||||
serverDependent?: boolean;
|
||||
}>;
|
||||
needsReload?: boolean;
|
||||
onSet?: (value: T) => void;
|
||||
};
|
||||
|
||||
export type PreferencesDefinition = Record<string, Pref<any> | undefined>;
|
||||
|
||||
export class PreferencesManager {
|
||||
private storageProvider: StorageProvider;
|
||||
public profile: PreferencesProfile;
|
||||
public cloudReady: Promise<void>;
|
||||
private enableReload = true;
|
||||
|
||||
public suppressReload() {
|
||||
this.enableReload = false;
|
||||
}
|
||||
|
||||
public allowReload() {
|
||||
this.enableReload = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* static / state の略 (static が予約語のため)
|
||||
|
|
@ -126,11 +140,11 @@ export class PreferencesManager {
|
|||
}
|
||||
|
||||
private isAccountDependentKey<K extends keyof PREF>(key: K): boolean {
|
||||
return (PREF_DEF as PreferencesDefinition)[key].accountDependent === true;
|
||||
return (PREF_DEF as PreferencesDefinition)[key]?.accountDependent === true;
|
||||
}
|
||||
|
||||
private isServerDependentKey<K extends keyof PREF>(key: K): boolean {
|
||||
return (PREF_DEF as PreferencesDefinition)[key].serverDependent === true;
|
||||
return (PREF_DEF as PreferencesDefinition)[key]?.serverDependent === true;
|
||||
}
|
||||
|
||||
private rewriteRawState<K extends keyof PREF>(key: K, value: ValueOf<K>) {
|
||||
|
|
@ -142,14 +156,28 @@ export class PreferencesManager {
|
|||
const v = JSON.parse(JSON.stringify(value)); // deep copy 兼 vueのプロキシ解除
|
||||
|
||||
if (deepEqual(this.s[key], v)) {
|
||||
if (_DEV_) console.log('(skip) prefer:commit', key, v);
|
||||
if (_DEV_) console.debug('(skip) prefer:commit', key, v);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_DEV_) console.log('prefer:commit', key, v);
|
||||
if (_DEV_) console.debug('prefer:commit', key, v);
|
||||
|
||||
this.rewriteRawState(key, v);
|
||||
|
||||
const pref = (PREF_DEF as PreferencesDefinition)[key];
|
||||
if (pref) {
|
||||
// Call custom setter
|
||||
if (pref.onSet) {
|
||||
pref.onSet(v);
|
||||
}
|
||||
|
||||
// Prompt to reload the frontend
|
||||
if (pref.needsReload && this.enableReload) {
|
||||
// noinspection JSIgnoredPromiseFromCall
|
||||
nextTick(() => reloadAsk({ unison: true }));
|
||||
}
|
||||
}
|
||||
|
||||
const record = this.getMatchedRecordOf(key);
|
||||
|
||||
if (parseScope(record[0]).account == null && this.isAccountDependentKey(key)) {
|
||||
|
|
@ -250,13 +278,13 @@ export class PreferencesManager {
|
|||
if (!deepEqual(cloudValue, record[1])) {
|
||||
this.rewriteRawState(key, cloudValue);
|
||||
record[1] = cloudValue;
|
||||
if (_DEV_) console.log('cloud fetched', key, cloudValue);
|
||||
if (_DEV_) console.debug('cloud fetched', key, cloudValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.save();
|
||||
if (_DEV_) console.log('cloud fetch completed');
|
||||
if (_DEV_) console.debug('cloud fetch completed');
|
||||
}
|
||||
|
||||
public static newProfile(): PreferencesProfile {
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ export async function restoreFromCloudBackup() {
|
|||
key: select.result,
|
||||
});
|
||||
|
||||
if (_DEV_) console.log(profile);
|
||||
if (_DEV_) console.debug(profile);
|
||||
|
||||
miLocalStorage.setItem('preferences', JSON.stringify(profile));
|
||||
miLocalStorage.setItem('hidePreferencesRestoreSuggestion', 'true');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue