👀 format (packages/frontend/src/store.ts)

This commit is contained in:
ひでまる 2025-01-29 10:45:40 +09:00
parent 0b9035c9fc
commit 312232e990

View file

@ -3,31 +3,31 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import { markRaw, ref } from 'vue'; import { markRaw, ref } from "vue";
import * as Misskey from 'misskey-js'; import * as Misskey from "misskey-js";
import { hemisphere } from '@@/js/intl-const.js'; import { hemisphere } from "@@/js/intl-const.js";
import lightTheme from '@@/themes/l-cherry.json5'; import lightTheme from "@@/themes/l-cherry.json5";
import darkTheme from '@@/themes/d-ice.json5'; import darkTheme from "@@/themes/d-ice.json5";
import { searchEngineMap } from './scripts/search-engine-map.js'; import { searchEngineMap } from "./scripts/search-engine-map.js";
import type { SoundType } from '@/scripts/sound.js'; import type { SoundType } from "@/scripts/sound.js";
import { DEFAULT_DEVICE_KIND, type DeviceKind } from '@/scripts/device-kind.js'; import { DEFAULT_DEVICE_KIND, type DeviceKind } from "@/scripts/device-kind.js";
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from "@/local-storage.js";
import { defaultFollowingFeedState } from '@/scripts/following-feed-utils.js'; import { defaultFollowingFeedState } from "@/scripts/following-feed-utils.js";
import { Storage } from '@/pizzax.js'; import { Storage } from "@/pizzax.js";
import type { Ast } from '@syuilo/aiscript'; import type { Ast } from "@syuilo/aiscript";
interface PostFormAction { interface PostFormAction {
title: string, title: string;
handler: <T>(form: T, update: (key: unknown, value: unknown) => void) => void; handler: <T>(form: T, update: (key: unknown, value: unknown) => void) => void;
} }
interface UserAction { interface UserAction {
title: string, title: string;
handler: (user: Misskey.entities.UserDetailed) => void; handler: (user: Misskey.entities.UserDetailed) => void;
} }
interface NoteAction { interface NoteAction {
title: string, title: string;
handler: (note: Misskey.entities.Note) => void; handler: (note: Misskey.entities.Note) => void;
} }
@ -44,11 +44,13 @@ interface PageViewInterruptor {
} }
/** サウンド設定 */ /** サウンド設定 */
export type SoundStore = { export type SoundStore =
type: Exclude<SoundType, '_driveFile_'>; | {
type: Exclude<SoundType, "_driveFile_">;
volume: number; volume: number;
} | { }
type: '_driveFile_'; | {
type: "_driveFile_";
/** ドライブのファイルID */ /** ドライブのファイルID */
fileId: string; fileId: string;
@ -57,7 +59,7 @@ export type SoundStore = {
fileUrl: string; fileUrl: string;
volume: number; volume: number;
} };
export const postFormActions: PostFormAction[] = []; export const postFormActions: PostFormAction[] = [];
export const userActions: UserAction[] = []; export const userActions: UserAction[] = [];
@ -68,13 +70,14 @@ export const pageViewInterruptors: PageViewInterruptor[] = [];
// TODO: それぞれいちいちwhereとかdefaultというキーを付けなきゃいけないの冗長なのでなんとかする(ただ型定義が面倒になりそう) // TODO: それぞれいちいちwhereとかdefaultというキーを付けなきゃいけないの冗長なのでなんとかする(ただ型定義が面倒になりそう)
// あと、現行の定義の仕方なら「whereが何であるかに関わらずキー名の重複不可」という制約を付けられるメリットもあるからそのメリットを引き継ぐ方法も考えないといけない // あと、現行の定義の仕方なら「whereが何であるかに関わらずキー名の重複不可」という制約を付けられるメリットもあるからそのメリットを引き継ぐ方法も考えないといけない
export const defaultStore = markRaw(new Storage('base', { export const defaultStore = markRaw(
new Storage("base", {
accountSetupWizard: { accountSetupWizard: {
where: 'account', where: "account",
default: 0, default: 0,
}, },
timelineTutorials: { timelineTutorials: {
where: 'account', where: "account",
default: { default: {
home: false, home: false,
local: false, local: false,
@ -83,146 +86,151 @@ export const defaultStore = markRaw(new Storage('base', {
}, },
}, },
abusesTutorial: { abusesTutorial: {
where: 'account', where: "account",
default: false, default: false,
}, },
keepCw: { keepCw: {
where: 'account', where: "account",
default: true, default: true,
}, },
showFullAcct: { showFullAcct: {
where: 'account', where: "account",
default: false, default: false,
}, },
collapseRenotes: { collapseRenotes: {
where: 'account', where: "account",
default: false, default: false,
}, },
collapseNotesRepliedTo: { collapseNotesRepliedTo: {
where: 'account', where: "account",
default: false, default: false,
}, },
collapseFiles: { collapseFiles: {
where: 'account', where: "account",
default: false, default: false,
}, },
uncollapseCW: { uncollapseCW: {
where: 'account', where: "account",
default: false, default: false,
}, },
expandLongNote: { expandLongNote: {
where: 'device', where: "device",
default: false, default: false,
}, },
rememberNoteVisibility: { rememberNoteVisibility: {
where: 'account', where: "account",
default: false, default: false,
}, },
defaultNoteVisibility: { defaultNoteVisibility: {
where: 'account', where: "account",
default: 'public' as (typeof Misskey.noteVisibilities)[number], default: "public" as (typeof Misskey.noteVisibilities)[number],
}, },
defaultNoteLocalOnly: { defaultNoteLocalOnly: {
where: 'account', where: "account",
default: false, default: false,
}, },
uploadFolder: { uploadFolder: {
where: 'account', where: "account",
default: null as string | null, default: null as string | null,
}, },
pastedFileName: { pastedFileName: {
where: 'account', where: "account",
default: 'yyyy-MM-dd HH-mm-ss [{{number}}]', default: "yyyy-MM-dd HH-mm-ss [{{number}}]",
}, },
keepOriginalUploading: { keepOriginalUploading: {
where: 'account', where: "account",
default: false, default: false,
}, },
memo: { memo: {
where: 'account', where: "account",
default: null, default: null,
}, },
reactions: { reactions: {
where: 'account', where: "account",
default: ['👍', '❤️', '😆', '🤔', '😮', '🎉', '💢', '😥', '😇', '🍮'], default: ["👍", "❤", "😆", "🤔", "😮", "🎉", "💢", "😥", "😇", "🍮"],
}, },
pinnedEmojis: { pinnedEmojis: {
where: 'account', where: "account",
default: [], default: [],
}, },
reactionAcceptance: { reactionAcceptance: {
where: 'account', where: "account",
default: 'nonSensitiveOnly' as 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null, default: "nonSensitiveOnly" as
| "likeOnly"
| "likeOnlyForRemote"
| "nonSensitiveOnly"
| "nonSensitiveOnlyForLocalLikeOnlyForRemote"
| null,
}, },
like: { like: {
where: 'account', where: "account",
default: null as string | null, default: null as string | null,
}, },
mutedAds: { mutedAds: {
where: 'account', where: "account",
default: [] as string[], default: [] as string[],
}, },
autoloadConversation: { autoloadConversation: {
where: 'account', where: "account",
default: true, default: true,
}, },
showVisibilitySelectorOnBoost: { showVisibilitySelectorOnBoost: {
where: 'account', where: "account",
default: true, default: true,
}, },
visibilityOnBoost: { visibilityOnBoost: {
where: 'account', where: "account",
default: 'public' as 'public' | 'home' | 'followers', default: "public" as "public" | "home" | "followers",
}, },
trustedDomains: { trustedDomains: {
where: 'account', where: "account",
default: [] as string[], default: [] as string[],
}, },
warnExternalUrl: { warnExternalUrl: {
where: 'account', where: "account",
default: true, default: true,
}, },
menu: { menu: {
where: 'deviceAccount', where: "deviceAccount",
default: [ default: [
'notifications', "notifications",
'explore', "explore",
'followRequests', "followRequests",
'-', "-",
'announcements', "announcements",
'search', "search",
'-', "-",
'favorites', "favorites",
'drive', "drive",
'achievements', "achievements",
], ],
}, },
visibility: { visibility: {
where: 'deviceAccount', where: "deviceAccount",
default: 'public' as (typeof Misskey.noteVisibilities)[number], default: "public" as (typeof Misskey.noteVisibilities)[number],
}, },
localOnly: { localOnly: {
where: 'deviceAccount', where: "deviceAccount",
default: false, default: false,
}, },
showPreview: { showPreview: {
where: 'device', where: "device",
default: false, default: false,
}, },
statusbars: { statusbars: {
where: 'deviceAccount', where: "deviceAccount",
default: [] as { default: [] as {
name: string; name: string;
id: string; id: string;
type: string; type: string;
size: 'verySmall' | 'small' | 'medium' | 'large' | 'veryLarge'; size: "verySmall" | "small" | "medium" | "large" | "veryLarge";
black: boolean; black: boolean;
props: Record<string, any>; props: Record<string, any>;
}[], }[],
}, },
widgets: { widgets: {
where: 'account', where: "account",
default: [] as { default: [] as {
name: string; name: string;
id: string; id: string;
@ -231,9 +239,15 @@ export const defaultStore = markRaw(new Storage('base', {
}[], }[],
}, },
tl: { tl: {
where: 'deviceAccount', where: "deviceAccount",
default: { default: {
src: 'home' as 'home' | 'local' | 'social' | 'global' | 'bubble' | `list:${string}`, src: "home" as
| "home"
| "local"
| "social"
| "global"
| "bubble"
| `list:${string}`,
userList: null as Misskey.entities.UserList | null, userList: null as Misskey.entities.UserList | null,
filter: { filter: {
withReplies: true, withReplies: true,
@ -245,272 +259,276 @@ export const defaultStore = markRaw(new Storage('base', {
}, },
}, },
pinnedUserLists: { pinnedUserLists: {
where: 'deviceAccount', where: "deviceAccount",
default: [] as Misskey.entities.UserList[], default: [] as Misskey.entities.UserList[],
}, },
followingFeed: { followingFeed: {
where: 'account', where: "account",
default: defaultFollowingFeedState, default: defaultFollowingFeedState,
}, },
overridedDeviceKind: { overridedDeviceKind: {
where: 'device', where: "device",
default: null as DeviceKind | null, default: null as DeviceKind | null,
}, },
serverDisconnectedBehavior: { serverDisconnectedBehavior: {
where: 'device', where: "device",
default: 'disabled' as 'quiet' | 'dialog' | 'disabled', default: "disabled" as "quiet" | "dialog" | "disabled",
}, },
nsfw: { nsfw: {
where: 'device', where: "device",
default: 'respect' as 'respect' | 'force' | 'ignore', default: "respect" as "respect" | "force" | "ignore",
}, },
highlightSensitiveMedia: { highlightSensitiveMedia: {
where: 'device', where: "device",
default: false, default: false,
}, },
animation: { animation: {
where: 'device', where: "device",
default: !window.matchMedia('(prefers-reduced-motion)').matches, default: !window.matchMedia("(prefers-reduced-motion)").matches,
}, },
animatedMfm: { animatedMfm: {
where: 'device', where: "device",
default: !window.matchMedia('(prefers-reduced-motion)').matches, default: !window.matchMedia("(prefers-reduced-motion)").matches,
}, },
advancedMfm: { advancedMfm: {
where: 'device', where: "device",
default: true, default: true,
}, },
showReactionsCount: { showReactionsCount: {
where: 'device', where: "device",
default: false, default: false,
}, },
enableQuickAddMfmFunction: { enableQuickAddMfmFunction: {
where: 'device', where: "device",
default: false, default: false,
}, },
loadRawImages: { loadRawImages: {
where: 'device', where: "device",
default: false, default: false,
}, },
warnMissingAltText: { warnMissingAltText: {
where: 'device', where: "device",
default: true, default: true,
}, },
enableFaviconNotificationDot: { enableFaviconNotificationDot: {
where: 'device', where: "device",
default: true, default: true,
}, },
imageNewTab: { imageNewTab: {
where: 'device', where: "device",
default: false, default: false,
}, },
disableShowingAnimatedImages: { disableShowingAnimatedImages: {
where: 'device', where: "device",
default: window.matchMedia('(prefers-reduced-motion)').matches, default: window.matchMedia("(prefers-reduced-motion)").matches,
}, },
disableCatSpeak: { disableCatSpeak: {
where: 'account', where: "account",
default: false, default: false,
}, },
emojiStyle: { emojiStyle: {
where: 'device', where: "device",
default: 'twemoji', // twemoji / fluentEmoji / native default: "twemoji", // twemoji / fluentEmoji / native
}, },
menuStyle: { menuStyle: {
where: 'device', where: "device",
default: 'auto' as 'auto' | 'popup' | 'drawer', default: "auto" as "auto" | "popup" | "drawer",
}, },
useBlurEffectForModal: { useBlurEffectForModal: {
where: 'device', where: "device",
default: DEFAULT_DEVICE_KIND === 'desktop', default: DEFAULT_DEVICE_KIND === "desktop",
}, },
useBlurEffect: { useBlurEffect: {
where: 'device', where: "device",
default: DEFAULT_DEVICE_KIND === 'desktop', default: DEFAULT_DEVICE_KIND === "desktop",
}, },
showFixedPostForm: { showFixedPostForm: {
where: 'device', where: "device",
default: false, default: false,
}, },
showFixedPostFormInChannel: { showFixedPostFormInChannel: {
where: 'device', where: "device",
default: false, default: false,
}, },
showTickerOnReplies: { showTickerOnReplies: {
where: 'device', where: "device",
default: false, default: false,
}, },
searchEngine: { searchEngine: {
where: 'account', where: "account",
default: Object.keys(searchEngineMap)[0], default: Object.keys(searchEngineMap)[0],
}, },
noteDesign: { noteDesign: {
where: 'device', where: "device",
default: 'sharkey' as 'sharkey' | 'misskey', default: "sharkey" as "sharkey" | "misskey",
}, },
enableInfiniteScroll: { enableInfiniteScroll: {
where: 'device', where: "device",
default: true, default: true,
}, },
useReactionPickerForContextMenu: { useReactionPickerForContextMenu: {
where: 'device', where: "device",
default: false, default: false,
}, },
showGapBetweenNotesInTimeline: { showGapBetweenNotesInTimeline: {
where: 'device', where: "device",
default: false, default: false,
}, },
darkMode: { darkMode: {
where: 'device', where: "device",
default: false, default: false,
}, },
instanceTicker: { instanceTicker: {
where: 'device', where: "device",
default: 'remote' as 'none' | 'remote' | 'always', default: "remote" as "none" | "remote" | "always",
}, },
emojiPickerScale: { emojiPickerScale: {
where: 'device', where: "device",
default: 1, default: 1,
}, },
emojiPickerWidth: { emojiPickerWidth: {
where: 'device', where: "device",
default: 1, default: 1,
}, },
emojiPickerHeight: { emojiPickerHeight: {
where: 'device', where: "device",
default: 2, default: 2,
}, },
emojiPickerStyle: { emojiPickerStyle: {
where: 'device', where: "device",
default: 'auto' as 'auto' | 'popup' | 'drawer', default: "auto" as "auto" | "popup" | "drawer",
}, },
recentlyUsedEmojis: { recentlyUsedEmojis: {
where: 'device', where: "device",
default: [] as string[], default: [] as string[],
}, },
recentlyUsedUsers: { recentlyUsedUsers: {
where: 'device', where: "device",
default: [] as string[], default: [] as string[],
}, },
defaultSideView: { defaultSideView: {
where: 'device', where: "device",
default: false, default: false,
}, },
menuDisplay: { menuDisplay: {
where: 'device', where: "device",
default: 'sideFull' as 'sideFull' | 'sideIcon' | 'top', default: "sideFull" as "sideFull" | "sideIcon" | "top",
}, },
reportError: { reportError: {
where: 'device', where: "device",
default: false, default: false,
}, },
squareAvatars: { squareAvatars: {
where: 'device', where: "device",
default: true, default: true,
}, },
showAvatarDecorations: { showAvatarDecorations: {
where: 'device', where: "device",
default: true, default: true,
}, },
postFormWithHashtags: { postFormWithHashtags: {
where: 'device', where: "device",
default: false, default: false,
}, },
postFormHashtags: { postFormHashtags: {
where: 'device', where: "device",
default: '', default: "",
}, },
themeInitial: { themeInitial: {
where: 'device', where: "device",
default: true, default: true,
}, },
numberOfPageCache: { numberOfPageCache: {
where: 'device', where: "device",
default: 3, default: 3,
}, },
numberOfReplies: { numberOfReplies: {
where: 'device', where: "device",
default: 5, default: 5,
}, },
showNoteActionsOnlyHover: { showNoteActionsOnlyHover: {
where: 'device', where: "device",
default: false, default: false,
}, },
showClipButtonInNoteFooter: { showClipButtonInNoteFooter: {
where: 'device', where: "device",
default: false, default: false,
}, },
reactionsDisplaySize: { reactionsDisplaySize: {
where: 'device', where: "device",
default: 'medium' as 'small' | 'medium' | 'large', default: "medium" as "small" | "medium" | "large",
}, },
limitWidthOfReaction: { limitWidthOfReaction: {
where: 'device', where: "device",
default: true, default: true,
}, },
forceShowAds: { forceShowAds: {
where: 'device', where: "device",
default: false, default: false,
}, },
oneko: { oneko: {
where: 'device', where: "device",
default: false, default: false,
}, },
clickToOpen: { clickToOpen: {
where: 'device', where: "device",
default: true, default: true,
}, },
aiChanMode: { aiChanMode: {
where: 'device', where: "device",
default: false, default: false,
}, },
devMode: { devMode: {
where: 'device', where: "device",
default: false, default: false,
}, },
mediaListWithOneImageAppearance: { mediaListWithOneImageAppearance: {
where: 'device', where: "device",
default: 'expand' as 'expand' | '16_9' | '1_1' | '2_3', default: "expand" as "expand" | "16_9" | "1_1" | "2_3",
}, },
notificationPosition: { notificationPosition: {
where: 'device', where: "device",
default: 'rightBottom' as 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom', default: "rightBottom" as
| "leftTop"
| "leftBottom"
| "rightTop"
| "rightBottom",
}, },
notificationStackAxis: { notificationStackAxis: {
where: 'device', where: "device",
default: 'horizontal' as 'vertical' | 'horizontal', default: "horizontal" as "vertical" | "horizontal",
}, },
notificationClickable: { notificationClickable: {
where: 'device', where: "device",
default: false, default: false,
}, },
enableCondensedLine: { enableCondensedLine: {
where: 'device', where: "device",
default: true, default: true,
}, },
additionalUnicodeEmojiIndexes: { additionalUnicodeEmojiIndexes: {
where: 'device', where: "device",
default: {} as Record<string, Record<string, string[]>>, default: {} as Record<string, Record<string, string[]>>,
}, },
keepScreenOn: { keepScreenOn: {
where: 'device', where: "device",
default: false, default: false,
}, },
defaultWithReplies: { defaultWithReplies: {
where: 'account', where: "account",
default: false, default: false,
}, },
disableStreamingTimeline: { disableStreamingTimeline: {
where: 'device', where: "device",
default: false, default: false,
}, },
useGroupedNotifications: { useGroupedNotifications: {
where: 'device', where: "device",
default: true, default: true,
}, },
dataSaver: { dataSaver: {
where: 'device', where: "device",
default: { default: {
media: false, media: false,
avatar: false, avatar: false,
@ -519,82 +537,83 @@ export const defaultStore = markRaw(new Storage('base', {
} as Record<string, boolean>, } as Record<string, boolean>,
}, },
enableSeasonalScreenEffect: { enableSeasonalScreenEffect: {
where: 'device', where: "device",
default: false, default: false,
}, },
dropAndFusion: { dropAndFusion: {
where: 'device', where: "device",
default: { default: {
bgmVolume: 0.25, bgmVolume: 0.25,
sfxVolume: 1, sfxVolume: 1,
}, },
}, },
hemisphere: { hemisphere: {
where: 'device', where: "device",
default: hemisphere as 'N' | 'S', default: hemisphere as "N" | "S",
}, },
enableHorizontalSwipe: { enableHorizontalSwipe: {
where: 'device', where: "device",
default: true, default: true,
}, },
useNativeUIForVideoAudioPlayer: { useNativeUIForVideoAudioPlayer: {
where: 'device', where: "device",
default: false, default: false,
}, },
keepOriginalFilename: { keepOriginalFilename: {
where: 'device', where: "device",
default: true, default: true,
}, },
alwaysConfirmFollow: { alwaysConfirmFollow: {
where: 'device', where: "device",
default: true, default: true,
}, },
confirmWhenRevealingSensitiveMedia: { confirmWhenRevealingSensitiveMedia: {
where: 'device', where: "device",
default: false, default: false,
}, },
contextMenu: { contextMenu: {
where: 'device', where: "device",
default: 'app' as 'app' | 'appWithShift' | 'native', default: "app" as "app" | "appWithShift" | "native",
}, },
skipNoteRender: { skipNoteRender: {
where: 'device', where: "device",
default: true, default: true,
}, },
sound_masterVolume: { sound_masterVolume: {
where: 'device', where: "device",
default: 0.3, default: 0.3,
}, },
sound_notUseSound: { sound_notUseSound: {
where: 'device', where: "device",
default: false, default: false,
}, },
sound_useSoundOnlyWhenActive: { sound_useSoundOnlyWhenActive: {
where: 'device', where: "device",
default: false, default: false,
}, },
sound_note: { sound_note: {
where: 'device', where: "device",
default: { type: 'syuilo/n-aec', volume: 0 } as SoundStore, default: { type: "syuilo/n-aec", volume: 0 } as SoundStore,
}, },
sound_noteMy: { sound_noteMy: {
where: 'device', where: "device",
default: { type: 'syuilo/n-cea-4va', volume: 1 } as SoundStore, default: { type: "syuilo/n-cea-4va", volume: 1 } as SoundStore,
}, },
sound_notification: { sound_notification: {
where: 'device', where: "device",
default: { type: 'syuilo/n-ea', volume: 1 } as SoundStore, default: { type: "syuilo/n-ea", volume: 1 } as SoundStore,
}, },
sound_reaction: { sound_reaction: {
where: 'device', where: "device",
default: { type: 'syuilo/bubble2', volume: 1 } as SoundStore, default: { type: "syuilo/bubble2", volume: 1 } as SoundStore,
}, },
})); }),
);
// TODO: 他のタブと永続化されたstateを同期 // TODO: 他のタブと永続化されたstateを同期
const PREFIX = 'miux:' as const; const PREFIX = "miux:" as const;
export type Plugin = { export type Plugin = {
id: string; id: string;
@ -630,7 +649,9 @@ export class ColdDeviceStorage {
public static watchers: Watcher[] = []; public static watchers: Watcher[] = [];
public static get<T extends keyof typeof ColdDeviceStorage.default>(key: T): typeof ColdDeviceStorage.default[T] { public static get<T extends keyof typeof ColdDeviceStorage.default>(
key: T,
): (typeof ColdDeviceStorage.default)[T] {
// TODO: indexedDBにする // TODO: indexedDBにする
// ただしその際はnullチェックではなくキー存在チェックにしないとダメ // ただしその際はnullチェックではなくキー存在チェックにしないとダメ
// (indexedDBはnullを保存できるため、ユーザーが意図してnullを格納した可能性がある) // (indexedDBはnullを保存できるため、ユーザーが意図してnullを格納した可能性がある)
@ -643,7 +664,9 @@ export class ColdDeviceStorage {
} }
public static getAll(): Partial<typeof this.default> { public static getAll(): Partial<typeof this.default> {
return (Object.keys(this.default) as (keyof typeof this.default)[]).reduce<Partial<typeof this.default>>((acc, key) => { return (Object.keys(this.default) as (keyof typeof this.default)[]).reduce<
Partial<typeof this.default>
>((acc, key) => {
const value = localStorage.getItem(PREFIX + key); const value = localStorage.getItem(PREFIX + key);
if (value != null) { if (value != null) {
acc[key] = JSON.parse(value); acc[key] = JSON.parse(value);
@ -652,7 +675,10 @@ export class ColdDeviceStorage {
}, {}); }, {});
} }
public static set<T extends keyof typeof ColdDeviceStorage.default>(key: T, value: typeof ColdDeviceStorage.default[T]): void { public static set<T extends keyof typeof ColdDeviceStorage.default>(
key: T,
value: (typeof ColdDeviceStorage.default)[T],
): void {
// 呼び出し側のバグ等で undefined が来ることがある // 呼び出し側のバグ等で undefined が来ることがある
// undefined を文字列として miLocalStorage に入れると参照する際の JSON.parse でコケて不具合の元になるため無視 // undefined を文字列として miLocalStorage に入れると参照する際の JSON.parse でコケて不具合の元になるため無視
@ -677,7 +703,7 @@ export class ColdDeviceStorage {
const v = ColdDeviceStorage.get(key); const v = ColdDeviceStorage.get(key);
const r = ref(v); const r = ref(v);
// TODO: このままではwatcherがリークするので開放する方法を考える // TODO: このままではwatcherがリークするので開放する方法を考える
this.watch(key, v => { this.watch(key, (v) => {
r.value = v; r.value = v;
}); });
return r; return r;
@ -687,14 +713,16 @@ export class ColdDeviceStorage {
* getter/setterを作ります * getter/setterを作ります
* vue場で設定コントロールのmodelとして使う用 * vue場で設定コントロールのmodelとして使う用
*/ */
public static makeGetterSetter<K extends keyof typeof ColdDeviceStorage.default>(key: K) { public static makeGetterSetter<
K extends keyof typeof ColdDeviceStorage.default,
>(key: K) {
// TODO: VueのcustomRef使うと良い感じになるかも // TODO: VueのcustomRef使うと良い感じになるかも
const valueRef = ColdDeviceStorage.ref(key); const valueRef = ColdDeviceStorage.ref(key);
return { return {
get: () => { get: () => {
return valueRef.value; return valueRef.value;
}, },
set: (value: typeof ColdDeviceStorage.default[K]) => { set: (value: (typeof ColdDeviceStorage.default)[K]) => {
const val = value; const val = value;
ColdDeviceStorage.set(key, val); ColdDeviceStorage.set(key, val);
}, },