summaryrefslogtreecommitdiff
path: root/packages/frontend/src/preferences/manager.ts
diff options
context:
space:
mode:
authormisskey-release-bot[bot] <157398866+misskey-release-bot[bot]@users.noreply.github.com>2026-03-05 10:56:50 +0000
committerGitHub <noreply@github.com>2026-03-05 10:56:50 +0000
commitfe3dd8edb5f30104cd0a7ed755eb254feda2922d (patch)
treeaf6cf5fa4ca75302ac2de5db742cead00bc13d21 /packages/frontend/src/preferences/manager.ts
parentMerge pull request #16998 from misskey-dev/develop (diff)
parentRelease: 2026.3.0 (diff)
downloadmisskey-fe3dd8edb5f30104cd0a7ed755eb254feda2922d.tar.gz
misskey-fe3dd8edb5f30104cd0a7ed755eb254feda2922d.tar.bz2
misskey-fe3dd8edb5f30104cd0a7ed755eb254feda2922d.zip
Merge pull request #17217 from misskey-dev/develop
Release: 2026.3.0
Diffstat (limited to 'packages/frontend/src/preferences/manager.ts')
-rw-r--r--packages/frontend/src/preferences/manager.ts80
1 files changed, 42 insertions, 38 deletions
diff --git a/packages/frontend/src/preferences/manager.ts b/packages/frontend/src/preferences/manager.ts
index 13ba0000e4..7f3949f81b 100644
--- a/packages/frontend/src/preferences/manager.ts
+++ b/packages/frontend/src/preferences/manager.ts
@@ -3,11 +3,11 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { computed, onUnmounted, ref, watch } from 'vue';
+import { customRef, ref, watch, onScopeDispose } from 'vue';
import { EventEmitter } from 'eventemitter3';
import { host, version } from '@@/js/config.js';
import { PREF_DEF } from './def.js';
-import type { Ref, WritableComputedRef } from 'vue';
+import type { Ref } from 'vue';
import type { MenuItem } from '@/types/menu.js';
import { genId } from '@/utility/id.js';
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
@@ -81,7 +81,7 @@ export type PreferencesProfile = {
};
export type PossiblyNonNormalizedPreferencesProfile = Omit<PreferencesProfile, 'preferences'> & {
- preferences: Record<string, any>;
+ preferences: Record<string, [scope: Scope, value: any, meta: ValueMeta][]>;
};
export type StorageProvider = {
@@ -112,17 +112,17 @@ type PreferencesManagerEvents = {
export function definePreferences<T extends Record<string, unknown>>(x: {
[K in keyof T]: PreferencesDefinitionRecord<T[K]>
}): {
- [K in keyof T]: PreferencesDefinitionRecord<T[K]>
- } {
+ [K in keyof T]: PreferencesDefinitionRecord<T[K]>
+} {
return x;
}
export function getInitialPrefValue<K extends keyof PREF>(k: K): ValueOf<K> {
- const _default = PREF_DEF[k as string].default;
+ const _default = PREF_DEF[k].default;
if (typeof _default === 'function') { // factory
- return _default();
+ return _default() as ValueOf<K>;
} else {
- return _default;
+ return _default as unknown as ValueOf<K>;
}
}
@@ -146,7 +146,7 @@ function createEmptyProfile(): PossiblyNonNormalizedPreferencesProfile {
}
function normalizePreferences(preferences: PossiblyNonNormalizedPreferencesProfile['preferences'], account: { id: string } | null): PreferencesProfile['preferences'] {
- const data = {} as PreferencesProfile['preferences'];
+ const data = {} as Record<string, [scope: Scope, value: any, meta: ValueMeta][]>;
for (const key in PREF_DEF) {
const records = preferences[key];
if (records == null || records.length === 0) {
@@ -183,7 +183,7 @@ function normalizePreferences(preferences: PossiblyNonNormalizedPreferencesProfi
}
}
- return data;
+ return data as PreferencesProfile['preferences'];
}
// TODO: PreferencesManagerForGuest のような非ログイン専用のクラスを分離すればthis.currentAccountのnullチェックやaccountがnullであるスコープのレコード挿入などが不要になり綺麗になるかもしれない
@@ -223,9 +223,10 @@ export class PreferencesManager extends EventEmitter<PreferencesManagerEvents> {
const states = this.genStates();
+ // apply states
for (const key in states) {
- this.s[key] = states[key];
- this.r[key] = ref(this.s[key]);
+ (this.s[key as keyof PREF] as any) = states[key as keyof PREF];
+ (this.r[key as keyof PREF] as Ref<any>) = ref(this.s[key as keyof PREF]);
}
// normalizeの結果変わっていたら保存
@@ -299,36 +300,39 @@ export class PreferencesManager extends EventEmitter<PreferencesManagerEvents> {
* 特定のキーの、簡易的なcomputed refを作ります
* 主にvue上で設定コントロールのmodelとして使う用
*/
- public model<K extends keyof PREF, V extends ValueOf<K> = ValueOf<K>>(
+ public model<K extends keyof PREF, V = ValueOf<K>>(
+ key: K,
+ ): Ref<V>;
+ public model<K extends keyof PREF, V extends Exclude<any, ValueOf<K>>>(
+ key: K,
+ getter: (v: ValueOf<K>) => V,
+ setter: (v: V) => ValueOf<K>,
+ ): Ref<V>;
+
+ public model<K extends keyof PREF, V>(
key: K,
getter?: (v: ValueOf<K>) => V,
setter?: (v: V) => ValueOf<K>,
- ): WritableComputedRef<V> {
- const valueRef = ref(this.s[key]);
-
- const stop = watch(this.r[key], val => {
- valueRef.value = val;
- });
+ ): Ref<V> {
+ return customRef<V>((track, trigger) => {
+ const watchStop = watch(this.r[key], () => {
+ trigger();
+ });
- // NOTE: vueコンポーネント内で呼ばれない限りは、onUnmounted は無意味なのでメモリリークする
- onUnmounted(() => {
- stop();
- });
+ onScopeDispose(() => {
+ watchStop();
+ }, true);
- // TODO: VueのcustomRef使うと良い感じになるかも
- return computed({
- get: () => {
- if (getter) {
- return getter(valueRef.value);
- } else {
- return valueRef.value;
- }
- },
- set: (value) => {
- const val = setter ? setter(value) : value;
- this.commit(key, val);
- valueRef.value = val;
- },
+ return {
+ get: () => {
+ track();
+ return (getter != null ? getter(this.s[key]) : this.s[key]) as V;
+ },
+ set: (value) => {
+ const val = setter != null ? setter(value) : value;
+ this.commit(key, val as ValueOf<K>);
+ },
+ };
});
}
@@ -460,7 +464,7 @@ export class PreferencesManager extends EventEmitter<PreferencesManagerEvents> {
let mergedValue: ValueOf<K> | undefined = undefined; // null と区別したいため
try {
if (merge != null) mergedValue = merge(local, remote);
- } catch (err) {
+ } catch (_) {
// nop
}
const { canceled, result: choice } = await os.select({