1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-05-02 02:45:55 +02:00

Compare commits

...

2 Commits

Author SHA1 Message Date
syuilo
7f9180e045 Merge branch 'develop' into lowpowermode 2025-08-01 15:20:01 +09:00
syuilo
e8b5aa5c2f wip 2025-07-30 13:52:52 +09:00
5 changed files with 539 additions and 486 deletions

8
locales/index.d.ts vendored
View File

@@ -5493,6 +5493,10 @@ export interface Locale extends ILocale {
* 低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。 * 低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。
*/ */
"defaultImageCompressionLevel_description": string; "defaultImageCompressionLevel_description": string;
/**
* 低電力モード
*/
"lowPowerMode": string;
/** /**
* 分 * 分
*/ */
@@ -5807,6 +5811,10 @@ export interface Locale extends ILocale {
* UIのアニメーション * UIのアニメーション
*/ */
"uiAnimations": string; "uiAnimations": string;
/**
* アニメーション画像を再生
*/
"playAnimatedImages": string;
/** /**
* ナビゲーションバーに副ボタンを表示 * ナビゲーションバーに副ボタンを表示
*/ */

View File

@@ -1368,6 +1368,7 @@ redisplayAllTips: "全ての「ヒントとコツ」を再表示"
hideAllTips: "全ての「ヒントとコツ」を非表示" hideAllTips: "全ての「ヒントとコツ」を非表示"
defaultImageCompressionLevel: "デフォルトの画像圧縮度" defaultImageCompressionLevel: "デフォルトの画像圧縮度"
defaultImageCompressionLevel_description: "低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。" defaultImageCompressionLevel_description: "低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。"
lowPowerMode: "低電力モード"
inMinutes: "分" inMinutes: "分"
inDays: "日" inDays: "日"
@@ -1453,6 +1454,7 @@ _settings:
useStickyIcons: "アイコンをスクロールに追従させる" useStickyIcons: "アイコンをスクロールに追従させる"
enableHighQualityImagePlaceholders: "高品質な画像のプレースホルダを表示" enableHighQualityImagePlaceholders: "高品質な画像のプレースホルダを表示"
uiAnimations: "UIのアニメーション" uiAnimations: "UIのアニメーション"
playAnimatedImages: "アニメーション画像を再生"
showNavbarSubButtons: "ナビゲーションバーに副ボタンを表示" showNavbarSubButtons: "ナビゲーションバーに副ボタンを表示"
ifOn: "オンのとき" ifOn: "オンのとき"
ifOff: "オフのとき" ifOff: "オフのとき"

View File

@@ -567,50 +567,73 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #icon><SearchIcon><i class="ti ti-battery-vertical-eco"></i></SearchIcon></template> <template #icon><SearchIcon><i class="ti ti-battery-vertical-eco"></i></SearchIcon></template>
<div class="_gaps_s"> <div class="_gaps_s">
<SearchMarker :keywords="['animation', 'motion', 'reduce']"> <SearchMarker :keywords="['lowpowermode', 'battery', 'eco', 'save']">
<MkPreferenceContainer k="animation"> <MkPreferenceContainer k="lowPowerMode">
<MkSwitch :modelValue="!reduceAnimation" @update:modelValue="v => reduceAnimation = !v"> <MkSwitch v-model="lowPowerMode">
<template #label><SearchLabel>{{ i18n.ts._settings.uiAnimations }}</SearchLabel></template> <template #label><SearchLabel>{{ i18n.ts.lowPowerMode }}</SearchLabel></template>
<template #caption><SearchKeyword>{{ i18n.ts.turnOffToImprovePerformance }}</SearchKeyword></template>
</MkSwitch> </MkSwitch>
</MkPreferenceContainer> </MkPreferenceContainer>
</SearchMarker> </SearchMarker>
<SearchMarker :keywords="['blur']"> <hr>
<MkPreferenceContainer k="useBlurEffect">
<MkSwitch v-model="useBlurEffect">
<template #label><SearchLabel>{{ i18n.ts.useBlurEffect }}</SearchLabel></template>
<template #caption><SearchKeyword>{{ i18n.ts.turnOffToImprovePerformance }}</SearchKeyword></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['blur', 'modal']"> <MkDisableSection :disabled="lowPowerMode">
<MkPreferenceContainer k="useBlurEffectForModal"> <div class="_gaps_s">
<MkSwitch v-model="useBlurEffectForModal"> <SearchMarker :keywords="['animation', 'image', 'gif']">
<template #label><SearchLabel>{{ i18n.ts.useBlurEffectForModal }}</SearchLabel></template> <MkPreferenceContainer k="disableShowingAnimatedImages">
<template #caption><SearchKeyword>{{ i18n.ts.turnOffToImprovePerformance }}</SearchKeyword></template> <MkSwitch :modelValue="!disableShowingAnimatedImages" @update:modelValue="v => disableShowingAnimatedImages = !v">
</MkSwitch> <template #label><SearchLabel>{{ i18n.ts._settings.playAnimatedImages }}</SearchLabel></template>
</MkPreferenceContainer> <template #caption><SearchKeyword>{{ i18n.ts.turnOffToImprovePerformance }}</SearchKeyword></template>
</SearchMarker> </MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['blurhash', 'image', 'photo', 'picture', 'thumbnail', 'placeholder']"> <SearchMarker :keywords="['animation', 'motion', 'reduce']">
<MkPreferenceContainer k="enableHighQualityImagePlaceholders"> <MkPreferenceContainer k="animation">
<MkSwitch v-model="enableHighQualityImagePlaceholders"> <MkSwitch :modelValue="!reduceAnimation" @update:modelValue="v => reduceAnimation = !v">
<template #label><SearchLabel>{{ i18n.ts._settings.enableHighQualityImagePlaceholders }}</SearchLabel></template> <template #label><SearchLabel>{{ i18n.ts._settings.uiAnimations }}</SearchLabel></template>
<template #caption><SearchKeyword>{{ i18n.ts.turnOffToImprovePerformance }}</SearchKeyword></template> <template #caption><SearchKeyword>{{ i18n.ts.turnOffToImprovePerformance }}</SearchKeyword></template>
</MkSwitch> </MkSwitch>
</MkPreferenceContainer> </MkPreferenceContainer>
</SearchMarker> </SearchMarker>
<SearchMarker :keywords="['sticky']"> <SearchMarker :keywords="['blur']">
<MkPreferenceContainer k="useStickyIcons"> <MkPreferenceContainer k="useBlurEffect">
<MkSwitch v-model="useStickyIcons"> <MkSwitch v-model="useBlurEffect">
<template #label><SearchLabel>{{ i18n.ts._settings.useStickyIcons }}</SearchLabel></template> <template #label><SearchLabel>{{ i18n.ts.useBlurEffect }}</SearchLabel></template>
<template #caption><SearchKeyword>{{ i18n.ts.turnOffToImprovePerformance }}</SearchKeyword></template> <template #caption><SearchKeyword>{{ i18n.ts.turnOffToImprovePerformance }}</SearchKeyword></template>
</MkSwitch> </MkSwitch>
</MkPreferenceContainer> </MkPreferenceContainer>
</SearchMarker> </SearchMarker>
<SearchMarker :keywords="['blur', 'modal']">
<MkPreferenceContainer k="useBlurEffectForModal">
<MkSwitch v-model="useBlurEffectForModal">
<template #label><SearchLabel>{{ i18n.ts.useBlurEffectForModal }}</SearchLabel></template>
<template #caption><SearchKeyword>{{ i18n.ts.turnOffToImprovePerformance }}</SearchKeyword></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['blurhash', 'image', 'photo', 'picture', 'thumbnail', 'placeholder']">
<MkPreferenceContainer k="enableHighQualityImagePlaceholders">
<MkSwitch v-model="enableHighQualityImagePlaceholders">
<template #label><SearchLabel>{{ i18n.ts._settings.enableHighQualityImagePlaceholders }}</SearchLabel></template>
<template #caption><SearchKeyword>{{ i18n.ts.turnOffToImprovePerformance }}</SearchKeyword></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['sticky']">
<MkPreferenceContainer k="useStickyIcons">
<MkSwitch v-model="useStickyIcons">
<template #label><SearchLabel>{{ i18n.ts._settings.useStickyIcons }}</SearchLabel></template>
<template #caption><SearchKeyword>{{ i18n.ts.turnOffToImprovePerformance }}</SearchKeyword></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
</div>
</MkDisableSection>
<MkInfo> <MkInfo>
<div class="_gaps_s"> <div class="_gaps_s">
@@ -871,6 +894,7 @@ const useNativeUiForVideoAudioPlayer = prefer.model('useNativeUiForVideoAudioPla
const contextMenu = prefer.model('contextMenu'); const contextMenu = prefer.model('contextMenu');
const menuStyle = prefer.model('menuStyle'); const menuStyle = prefer.model('menuStyle');
const makeEveryTextElementsSelectable = prefer.model('makeEveryTextElementsSelectable'); const makeEveryTextElementsSelectable = prefer.model('makeEveryTextElementsSelectable');
const lowPowerMode = prefer.model('lowPowerMode');
const fontSize = ref(miLocalStorage.getItem('fontSize')); const fontSize = ref(miLocalStorage.getItem('fontSize'));
const useSystemFont = ref(miLocalStorage.getItem('useSystemFont') != null); const useSystemFont = ref(miLocalStorage.getItem('useSystemFont') != null);
@@ -928,6 +952,7 @@ watch([
enablePullToRefresh, enablePullToRefresh,
reduceAnimation, reduceAnimation,
showAvailableReactionsFirstInNote, showAvailableReactionsFirstInNote,
lowPowerMode,
], async () => { ], async () => {
await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true }); await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true });
}); });

View File

@@ -35,464 +35,472 @@ export type SoundStore = {
// NOTE: デフォルト値は他の設定の状態に依存してはならない(依存していた場合、ユーザーがその設定項目単体で「初期値にリセット」した場合不具合の原因になる) // NOTE: デフォルト値は他の設定の状態に依存してはならない(依存していた場合、ユーザーがその設定項目単体で「初期値にリセット」した場合不具合の原因になる)
export const PREF_DEF = definePreferences({ export const PREF_DEF = definePreferences({
accounts: { states: {
default: [] as [host: string, user: { accounts: {
id: string; default: [] as [host: string, user: {
username: string; id: string;
}][], username: string;
}, }][],
pinnedUserLists: {
accountDependent: true,
default: [] as Misskey.entities.UserList[],
},
uploadFolder: {
accountDependent: true,
default: null as string | null,
},
widgets: {
accountDependent: true,
default: () => [{
name: 'calendar',
id: genId(), place: 'right', data: {},
}, {
name: 'notifications',
id: genId(), place: 'right', data: {},
}, {
name: 'trends',
id: genId(), place: 'right', data: {},
}] as {
name: string;
id: string;
place: string | null;
data: Record<string, any>;
}[],
},
'deck.profile': {
accountDependent: true,
default: null as string | null,
},
'deck.profiles': {
accountDependent: true,
default: [] as DeckProfile[],
},
emojiPalettes: {
serverDependent: true,
default: () => [{
id: genId(),
name: '',
emojis: ['👍', '❤️', '😆', '🤔', '😮', '🎉', '💢', '😥', '😇', '🍮'],
}] as {
id: string;
name: string;
emojis: string[];
}[],
mergeStrategy: (a, b) => {
const mergedItems = [] as typeof a;
for (const x of a.concat(b)) {
const sameIdItem = mergedItems.find(y => y.id === x.id);
if (sameIdItem != null) {
if (deepEqual(x, sameIdItem)) { // 完全な重複は無視
continue;
} else { // IDは同じなのに内容が違う場合はマージ不可とする
throw new Error();
}
} else {
mergedItems.push(x);
}
}
return mergedItems;
}, },
},
emojiPaletteForReaction: {
serverDependent: true,
default: null as string | null,
},
emojiPaletteForMain: {
serverDependent: true,
default: null as string | null,
},
overridedDeviceKind: { pinnedUserLists: {
default: null as DeviceKind | null, accountDependent: true,
}, default: [] as Misskey.entities.UserList[],
themes: {
default: [] as Theme[],
mergeStrategy: (a, b) => {
const mergedItems = [] as typeof a;
for (const x of a.concat(b)) {
const sameIdItem = mergedItems.find(y => y.id === x.id);
if (sameIdItem != null) {
if (deepEqual(x, sameIdItem)) { // 完全な重複は無視
continue;
} else { // IDは同じなのに内容が違う場合はマージ不可とする
throw new Error();
}
} else {
mergedItems.push(x);
}
}
return mergedItems;
}, },
}, uploadFolder: {
lightTheme: { accountDependent: true,
default: null as Theme | null, default: null as string | null,
}, },
darkTheme: { widgets: {
default: null as Theme | null, accountDependent: true,
}, default: () => [{
syncDeviceDarkMode: { name: 'calendar',
default: true, id: genId(), place: 'right', data: {},
}, }, {
defaultNoteVisibility: { name: 'notifications',
default: 'public' as (typeof Misskey.noteVisibilities)[number], id: genId(), place: 'right', data: {},
}, }, {
defaultNoteLocalOnly: { name: 'trends',
default: false, id: genId(), place: 'right', data: {},
}, }] as {
keepCw: { name: string;
default: true, id: string;
}, place: string | null;
rememberNoteVisibility: { data: Record<string, any>;
default: false, }[],
}, },
reportError: { 'deck.profile': {
default: false, accountDependent: true,
}, default: null as string | null,
collapseRenotes: { },
default: true, 'deck.profiles': {
}, accountDependent: true,
menu: { default: [] as DeckProfile[],
default: [ },
'notifications',
'clips', emojiPalettes: {
'drive', serverDependent: true,
'followRequests', default: () => [{
'chat', id: genId(),
'-', name: '',
'explore', emojis: ['👍', '❤️', '😆', '🤔', '😮', '🎉', '💢', '😥', '😇', '🍮'],
'announcements', }] as {
'channels', id: string;
'search', name: string;
'-', emojis: string[];
'ui', }[],
], mergeStrategy: (a, b) => {
}, const mergedItems = [] as typeof a;
statusbars: { for (const x of a.concat(b)) {
default: [] as { const sameIdItem = mergedItems.find(y => y.id === x.id);
name: string; if (sameIdItem != null) {
id: string; if (deepEqual(x, sameIdItem)) { // 完全な重複は無視
type: string; continue;
size: 'verySmall' | 'small' | 'medium' | 'large' | 'veryLarge'; } else { // IDは同じなのに内容が違う場合はマージ不可とする
black: boolean; throw new Error();
props: Record<string, any>; }
}[], } else {
}, mergedItems.push(x);
serverDisconnectedBehavior: { }
default: 'quiet' as 'quiet' | 'reload' | 'dialog', }
}, return mergedItems;
nsfw: { },
default: 'respect' as 'respect' | 'force' | 'ignore', },
}, emojiPaletteForReaction: {
highlightSensitiveMedia: { serverDependent: true,
default: false, default: null as string | null,
}, },
animation: { emojiPaletteForMain: {
default: !window.matchMedia('(prefers-reduced-motion)').matches, serverDependent: true,
}, default: null as string | null,
animatedMfm: { },
default: !window.matchMedia('(prefers-reduced-motion)').matches,
}, overridedDeviceKind: {
advancedMfm: { default: null as DeviceKind | null,
default: true, },
}, themes: {
showReactionsCount: { default: [] as Theme[],
default: false, mergeStrategy: (a, b) => {
}, const mergedItems = [] as typeof a;
enableQuickAddMfmFunction: { for (const x of a.concat(b)) {
default: false, const sameIdItem = mergedItems.find(y => y.id === x.id);
}, if (sameIdItem != null) {
loadRawImages: { if (deepEqual(x, sameIdItem)) { // 完全な重複は無視
default: false, continue;
}, } else { // IDは同じなのに内容が違う場合はマージ不可とする
imageNewTab: { throw new Error();
default: false, }
}, } else {
disableShowingAnimatedImages: { mergedItems.push(x);
default: window.matchMedia('(prefers-reduced-motion)').matches, }
}, }
emojiStyle: { return mergedItems;
default: 'twemoji', // twemoji / fluentEmoji / native },
}, },
menuStyle: { lightTheme: {
default: 'auto' as 'auto' | 'popup' | 'drawer', default: null as Theme | null,
}, },
useBlurEffectForModal: { darkTheme: {
default: true, default: null as Theme | null,
}, },
useBlurEffect: { syncDeviceDarkMode: {
default: true, default: true,
}, },
useStickyIcons: { defaultNoteVisibility: {
default: true, default: 'public' as (typeof Misskey.noteVisibilities)[number],
}, },
enableHighQualityImagePlaceholders: { defaultNoteLocalOnly: {
default: true, default: false,
}, },
showFixedPostForm: { keepCw: {
default: false, default: true,
}, },
showFixedPostFormInChannel: { rememberNoteVisibility: {
default: false, default: false,
}, },
enableInfiniteScroll: { reportError: {
default: true, default: false,
}, },
useReactionPickerForContextMenu: { collapseRenotes: {
default: false, default: true,
}, },
instanceTicker: { menu: {
default: 'remote' as 'none' | 'remote' | 'always', default: [
}, 'notifications',
emojiPickerScale: { 'clips',
default: 2, 'drive',
}, 'followRequests',
emojiPickerWidth: { 'chat',
default: 2, '-',
}, 'explore',
emojiPickerHeight: { 'announcements',
default: 3, 'channels',
}, 'search',
emojiPickerStyle: { '-',
default: 'auto' as 'auto' | 'popup' | 'drawer', 'ui',
}, ],
squareAvatars: { },
default: false, statusbars: {
}, default: [] as {
showAvatarDecorations: { name: string;
default: true, id: string;
}, type: string;
numberOfPageCache: { size: 'verySmall' | 'small' | 'medium' | 'large' | 'veryLarge';
default: 3, black: boolean;
}, props: Record<string, any>;
pollingInterval: { }[],
},
serverDisconnectedBehavior: {
default: 'quiet' as 'quiet' | 'reload' | 'dialog',
},
nsfw: {
default: 'respect' as 'respect' | 'force' | 'ignore',
},
highlightSensitiveMedia: {
default: false,
},
animation: {
default: !window.matchMedia('(prefers-reduced-motion)').matches,
},
animatedMfm: {
default: !window.matchMedia('(prefers-reduced-motion)').matches,
},
advancedMfm: {
default: true,
},
showReactionsCount: {
default: false,
},
enableQuickAddMfmFunction: {
default: false,
},
loadRawImages: {
default: false,
},
imageNewTab: {
default: false,
},
disableShowingAnimatedImages: {
default: window.matchMedia('(prefers-reduced-motion)').matches,
},
emojiStyle: {
default: 'twemoji', // twemoji / fluentEmoji / native
},
menuStyle: {
default: 'auto' as 'auto' | 'popup' | 'drawer',
},
useBlurEffectForModal: {
default: true,
},
useBlurEffect: {
default: true,
},
useStickyIcons: {
default: true,
},
enableHighQualityImagePlaceholders: {
default: true,
},
showFixedPostForm: {
default: false,
},
showFixedPostFormInChannel: {
default: false,
},
enableInfiniteScroll: {
default: true,
},
useReactionPickerForContextMenu: {
default: false,
},
instanceTicker: {
default: 'remote' as 'none' | 'remote' | 'always',
},
emojiPickerScale: {
default: 2,
},
emojiPickerWidth: {
default: 2,
},
emojiPickerHeight: {
default: 3,
},
emojiPickerStyle: {
default: 'auto' as 'auto' | 'popup' | 'drawer',
},
squareAvatars: {
default: false,
},
showAvatarDecorations: {
default: true,
},
numberOfPageCache: {
default: 3,
},
pollingInterval: {
// 1 ... 低 // 1 ... 低
// 2 ... 中 // 2 ... 中
// 3 ... 高 // 3 ... 高
default: 2, default: 2,
},
showNoteActionsOnlyHover: {
default: false,
},
showClipButtonInNoteFooter: {
default: false,
},
reactionsDisplaySize: {
default: 'medium' as 'small' | 'medium' | 'large',
},
limitWidthOfReaction: {
default: true,
},
forceShowAds: {
default: false,
},
aiChanMode: {
default: false,
},
devMode: {
default: false,
},
mediaListWithOneImageAppearance: {
default: 'expand' as 'expand' | '16_9' | '1_1' | '2_3',
},
notificationPosition: {
default: 'rightBottom' as 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom',
},
notificationStackAxis: {
default: 'horizontal' as 'vertical' | 'horizontal',
},
enableCondensedLine: {
default: true,
},
keepScreenOn: {
default: false,
},
useGroupedNotifications: {
default: true,
},
dataSaver: {
default: {
media: false,
avatar: false,
urlPreviewThumbnail: false,
disableUrlPreview: false,
code: false,
} satisfies Record<string, boolean>,
},
hemisphere: {
default: hemisphere as 'N' | 'S',
},
enableSeasonalScreenEffect: {
default: false,
},
enableHorizontalSwipe: {
default: false,
},
enablePullToRefresh: {
default: true,
},
useNativeUiForVideoAudioPlayer: {
default: false,
},
keepOriginalFilename: {
default: true,
},
alwaysConfirmFollow: {
default: true,
},
confirmWhenRevealingSensitiveMedia: {
default: false,
},
contextMenu: {
default: 'app' as 'app' | 'appWithShift' | 'native',
},
skipNoteRender: {
default: true,
},
showSoftWordMutedWord: {
default: false,
},
confirmOnReact: {
default: false,
},
defaultFollowWithReplies: {
default: false,
},
makeEveryTextElementsSelectable: {
default: DEFAULT_DEVICE_KIND === 'desktop',
},
showNavbarSubButtons: {
default: true,
},
showTitlebar: {
default: false,
},
showAvailableReactionsFirstInNote: {
default: false,
},
plugins: {
default: [] as Plugin[],
mergeStrategy: (a, b) => {
const sameIdExists = a.some(x => b.some(y => x.installId === y.installId));
if (sameIdExists) throw new Error();
const sameNameExists = a.some(x => b.some(y => x.name === y.name));
if (sameNameExists) throw new Error();
return a.concat(b);
}, },
}, showNoteActionsOnlyHover: {
mutingEmojis: { default: false,
default: [] as string[],
mergeStrategy: (a, b) => {
return [...new Set(a.concat(b))];
}, },
}, showClipButtonInNoteFooter: {
watermarkPresets: { default: false,
accountDependent: true, },
default: [] as WatermarkPreset[], reactionsDisplaySize: {
mergeStrategy: (a, b) => { default: 'medium' as 'small' | 'medium' | 'large',
const mergedItems = [] as typeof a; },
for (const x of a.concat(b)) { limitWidthOfReaction: {
const sameIdItem = mergedItems.find(y => y.id === x.id); default: true,
if (sameIdItem != null) { },
if (deepEqual(x, sameIdItem)) { // 完全な重複は無視 forceShowAds: {
continue; default: false,
} else { // IDは同じなのに内容が違う場合はマージ不可とする },
throw new Error(); aiChanMode: {
default: false,
},
devMode: {
default: false,
},
mediaListWithOneImageAppearance: {
default: 'expand' as 'expand' | '16_9' | '1_1' | '2_3',
},
notificationPosition: {
default: 'rightBottom' as 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom',
},
notificationStackAxis: {
default: 'horizontal' as 'vertical' | 'horizontal',
},
enableCondensedLine: {
default: true,
},
keepScreenOn: {
default: false,
},
useGroupedNotifications: {
default: true,
},
dataSaver: {
default: {
media: false,
avatar: false,
urlPreviewThumbnail: false,
disableUrlPreview: false,
code: false,
} satisfies Record<string, boolean>,
},
hemisphere: {
default: hemisphere as 'N' | 'S',
},
enableSeasonalScreenEffect: {
default: false,
},
enableHorizontalSwipe: {
default: false,
},
enablePullToRefresh: {
default: true,
},
useNativeUiForVideoAudioPlayer: {
default: false,
},
keepOriginalFilename: {
default: true,
},
alwaysConfirmFollow: {
default: true,
},
confirmWhenRevealingSensitiveMedia: {
default: false,
},
contextMenu: {
default: 'app' as 'app' | 'appWithShift' | 'native',
},
skipNoteRender: {
default: true,
},
showSoftWordMutedWord: {
default: false,
},
confirmOnReact: {
default: false,
},
defaultFollowWithReplies: {
default: false,
},
makeEveryTextElementsSelectable: {
default: DEFAULT_DEVICE_KIND === 'desktop',
},
showNavbarSubButtons: {
default: true,
},
showTitlebar: {
default: false,
},
showAvailableReactionsFirstInNote: {
default: false,
},
plugins: {
default: [] as Plugin[],
mergeStrategy: (a, b) => {
const sameIdExists = a.some(x => b.some(y => x.installId === y.installId));
if (sameIdExists) throw new Error();
const sameNameExists = a.some(x => b.some(y => x.name === y.name));
if (sameNameExists) throw new Error();
return a.concat(b);
},
},
mutingEmojis: {
default: [] as string[],
mergeStrategy: (a, b) => {
return [...new Set(a.concat(b))];
},
},
watermarkPresets: {
accountDependent: true,
default: [] as WatermarkPreset[],
mergeStrategy: (a, b) => {
const mergedItems = [] as typeof a;
for (const x of a.concat(b)) {
const sameIdItem = mergedItems.find(y => y.id === x.id);
if (sameIdItem != null) {
if (deepEqual(x, sameIdItem)) { // 完全な重複は無視
continue;
} else { // IDは同じなのに内容が違う場合はマージ不可とする
throw new Error();
}
} else {
mergedItems.push(x);
} }
} else {
mergedItems.push(x);
} }
} return mergedItems;
return mergedItems; },
},
defaultWatermarkPresetId: {
accountDependent: true,
default: null as WatermarkPreset['id'] | null,
},
defaultImageCompressionLevel: {
default: 2 as 0 | 1 | 2 | 3,
},
lowPowerMode: {
default: false,
},
'sound.masterVolume': {
default: 0.5,
},
'sound.notUseSound': {
default: false,
},
'sound.useSoundOnlyWhenActive': {
default: false,
},
'sound.on.note': {
default: { type: 'syuilo/n-aec', volume: 1 } as SoundStore,
},
'sound.on.noteMy': {
default: { type: 'syuilo/n-cea-4va', volume: 1 } as SoundStore,
},
'sound.on.notification': {
default: { type: 'syuilo/n-ea', volume: 1 } as SoundStore,
},
'sound.on.reaction': {
default: { type: 'syuilo/bubble2', volume: 1 } as SoundStore,
},
'sound.on.chatMessage': {
default: { type: 'syuilo/waon', volume: 1 } as SoundStore,
},
'deck.alwaysShowMainColumn': {
default: true,
},
'deck.navWindow': {
default: true,
},
'deck.useSimpleUiForNonRootPages': {
default: true,
},
'deck.columnAlign': {
default: 'center' as 'left' | 'right' | 'center',
},
'deck.columnGap': {
default: 6,
},
'deck.menuPosition': {
default: 'bottom' as 'right' | 'bottom',
},
'deck.navbarPosition': {
default: 'left' as 'left' | 'top' | 'bottom',
},
'deck.wallpaper': {
default: null as string | null,
},
'chat.showSenderName': {
default: false,
},
'chat.sendOnEnter': {
default: false,
},
'game.dropAndFusion': {
default: {
bgmVolume: 0.25,
sfxVolume: 1,
},
},
'experimental.stackingRouterView': {
default: false,
},
'experimental.enableFolderPageView': {
default: false,
}, },
}, },
defaultWatermarkPresetId: { computed: {
accountDependent: true, disableShowingAnimatedImages: (s) => s.disableShowingAnimatedImages || s.lowPowerMode,
default: null as WatermarkPreset['id'] | null,
},
defaultImageCompressionLevel: {
default: 2 as 0 | 1 | 2 | 3,
},
'sound.masterVolume': {
default: 0.5,
},
'sound.notUseSound': {
default: false,
},
'sound.useSoundOnlyWhenActive': {
default: false,
},
'sound.on.note': {
default: { type: 'syuilo/n-aec', volume: 1 } as SoundStore,
},
'sound.on.noteMy': {
default: { type: 'syuilo/n-cea-4va', volume: 1 } as SoundStore,
},
'sound.on.notification': {
default: { type: 'syuilo/n-ea', volume: 1 } as SoundStore,
},
'sound.on.reaction': {
default: { type: 'syuilo/bubble2', volume: 1 } as SoundStore,
},
'sound.on.chatMessage': {
default: { type: 'syuilo/waon', volume: 1 } as SoundStore,
},
'deck.alwaysShowMainColumn': {
default: true,
},
'deck.navWindow': {
default: true,
},
'deck.useSimpleUiForNonRootPages': {
default: true,
},
'deck.columnAlign': {
default: 'center' as 'left' | 'right' | 'center',
},
'deck.columnGap': {
default: 6,
},
'deck.menuPosition': {
default: 'bottom' as 'right' | 'bottom',
},
'deck.navbarPosition': {
default: 'left' as 'left' | 'top' | 'bottom',
},
'deck.wallpaper': {
default: null as string | null,
},
'chat.showSenderName': {
default: false,
},
'chat.sendOnEnter': {
default: false,
},
'game.dropAndFusion': {
default: {
bgmVolume: 0.25,
sfxVolume: 1,
},
},
'experimental.stackingRouterView': {
default: false,
},
'experimental.enableFolderPageView': {
default: false,
}, },
}); });

View File

@@ -101,9 +101,19 @@ type PreferencesDefinitionRecord<Default, T = Default extends (...args: any) =>
export type PreferencesDefinition = Record<string, PreferencesDefinitionRecord<any>>; export type PreferencesDefinition = Record<string, PreferencesDefinitionRecord<any>>;
export function definePreferences<T extends Record<string, unknown>>(x: { export function definePreferences<T extends Record<string, unknown>>(x: {
[K in keyof T]: PreferencesDefinitionRecord<T[K]> states: {
[K in keyof T]: PreferencesDefinitionRecord<T[K]>;
};
computed: {
[K in keyof T]: PreferencesDefinitionRecord<T[K]>;
};
}): { }): {
[K in keyof T]: PreferencesDefinitionRecord<T[K]> states: {
[K in keyof T]: PreferencesDefinitionRecord<T[K]>;
};
computed: {
[K in keyof T]: PreferencesDefinitionRecord<T[K]>;
};
} { } {
return x; return x;
} }