diff --git a/locales/index.d.ts b/locales/index.d.ts index b65bfe4e67..a529d5ef7a 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -5717,6 +5717,22 @@ export interface Locale extends ILocale { * デバイス間でインストールしたテーマを同期 */ "enableSyncThemesBetweenDevices": string; + /** + * サーバーと接続を確立し、リアルタイムでコンテンツを更新します。通信量とバッテリーの消費が多くなる場合があります。 + */ + "realtimeMode_description": string; + /** + * コンテンツの取得頻度 + */ + "contentsUpdateFrequency": string; + /** + * 高いほどリアルタイムにコンテンツが更新されますが、パフォーマンスが低下し、通信量とバッテリーの消費が多くなります。 + */ + "contentsUpdateFrequency_description": string; + /** + * リアルタイムモードがオンのときは、この設定に関わらずリアルタイムでコンテンツが更新されます。 + */ + "contentsUpdateFrequency_description2": string; "_chat": { /** * 送信者の名前を表示 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index f9fa456a77..1ba9cc7ea0 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1429,6 +1429,10 @@ _settings: ifOn: "オンのとき" ifOff: "オフのとき" enableSyncThemesBetweenDevices: "デバイス間でインストールしたテーマを同期" + realtimeMode_description: "サーバーと接続を確立し、リアルタイムでコンテンツを更新します。通信量とバッテリーの消費が多くなる場合があります。" + contentsUpdateFrequency: "コンテンツの取得頻度" + contentsUpdateFrequency_description: "高いほどリアルタイムにコンテンツが更新されますが、パフォーマンスが低下し、通信量とバッテリーの消費が多くなります。" + contentsUpdateFrequency_description2: "リアルタイムモードがオンのときは、この設定に関わらずリアルタイムでコンテンツが更新されます。" _chat: showSenderName: "送信者の名前を表示" diff --git a/packages/frontend/src/components/MkNotifications.vue b/packages/frontend/src/components/MkNotifications.vue index e7f42ce497..6b646e6b95 100644 --- a/packages/frontend/src/components/MkNotifications.vue +++ b/packages/frontend/src/components/MkNotifications.vue @@ -78,7 +78,12 @@ const paginator = usePagination({ }, }); -const POLLING_INTERVAL = 1000 * 15; +const MIN_POLLING_INTERVAL = 1000 * 10; +const POLLING_INTERVAL = + prefer.s.pollingInterval === 1 ? MIN_POLLING_INTERVAL : + prefer.s.pollingInterval === 2 ? MIN_POLLING_INTERVAL * 1.5 : + prefer.s.pollingInterval === 3 ? MIN_POLLING_INTERVAL * 1.5 * 1.5 : + MIN_POLLING_INTERVAL; if (!store.s.realtimeMode) { useInterval(async () => { diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue index 9b28573712..d5f8becca7 100644 --- a/packages/frontend/src/components/MkTimeline.vue +++ b/packages/frontend/src/components/MkTimeline.vue @@ -109,7 +109,12 @@ type TimelineQueryType = { let adInsertionCounter = 0; -const POLLING_INTERVAL = 1000 * 15; +const MIN_POLLING_INTERVAL = 1000 * 10; +const POLLING_INTERVAL = + prefer.s.pollingInterval === 1 ? MIN_POLLING_INTERVAL : + prefer.s.pollingInterval === 2 ? MIN_POLLING_INTERVAL * 1.5 : + prefer.s.pollingInterval === 3 ? MIN_POLLING_INTERVAL * 1.5 * 1.5 : + MIN_POLLING_INTERVAL; if (!store.s.realtimeMode) { useInterval(async () => { diff --git a/packages/frontend/src/pages/settings/preferences.vue b/packages/frontend/src/pages/settings/preferences.vue index acdb9bb5a1..8480ff4ddb 100644 --- a/packages/frontend/src/pages/settings/preferences.vue +++ b/packages/frontend/src/pages/settings/preferences.vue @@ -41,6 +41,24 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + + + + + + + + + + + + + + +
@@ -717,7 +735,7 @@ import MkRadios from '@/components/MkRadios.vue'; import MkRange from '@/components/MkRange.vue'; import MkFolder from '@/components/MkFolder.vue'; import MkButton from '@/components/MkButton.vue'; -import FormSection from '@/components/form/section.vue'; +import MkDisableSection from '@/components/MkDisableSection.vue'; import FormLink from '@/components/form/link.vue'; import MkLink from '@/components/MkLink.vue'; import MkInfo from '@/components/MkInfo.vue'; @@ -740,8 +758,10 @@ const $i = ensureSignin(); const lang = ref(miLocalStorage.getItem('lang')); const dataSaver = ref(prefer.s.dataSaver); +const realtimeMode = computed(store.makeGetterSetter('realtimeMode')); const overridedDeviceKind = prefer.model('overridedDeviceKind'); +const pollingInterval = prefer.model('pollingInterval'); const showTitlebar = prefer.model('showTitlebar'); const keepCw = prefer.model('keepCw'); const serverDisconnectedBehavior = prefer.model('serverDisconnectedBehavior'); @@ -824,6 +844,8 @@ watch(useSystemFont, () => { watch([ hemisphere, lang, + realtimeMode, + pollingInterval, enableInfiniteScroll, showNoteActionsOnlyHover, overridedDeviceKind, diff --git a/packages/frontend/src/preferences/def.ts b/packages/frontend/src/preferences/def.ts index 9a644128b8..3f678154f0 100644 --- a/packages/frontend/src/preferences/def.ts +++ b/packages/frontend/src/preferences/def.ts @@ -241,6 +241,12 @@ export const PREF_DEF = { numberOfPageCache: { default: 3, }, + pollingInterval: { + // 1 ... 低 + // 2 ... 中 + // 3 ... 高 + default: 2, + }, showNoteActionsOnlyHover: { default: false, }, diff --git a/packages/frontend/src/use/use-note-capture.ts b/packages/frontend/src/use/use-note-capture.ts index 910e9e96d2..d11ab52ab6 100644 --- a/packages/frontend/src/use/use-note-capture.ts +++ b/packages/frontend/src/use/use-note-capture.ts @@ -11,6 +11,7 @@ import { useStream } from '@/stream.js'; import { $i } from '@/i.js'; import { store } from '@/store.js'; import { misskeyApi } from '@/utility/misskey-api.js'; +import { prefer } from '@/preferences.js'; export const noteEvents = new EventEmitter<{ [ev: `reacted:${string}`]: (ctx: { userId: Misskey.entities.User['id']; reaction: string; emoji?: { name: string; url: string; }; }) => void; @@ -59,7 +60,12 @@ function pollingDequeue(note: Pick) { } const CAPTURE_MAX = 30; -const POLLING_INTERVAL = 1000 * 15; +const MIN_POLLING_INTERVAL = 1000 * 10; +const POLLING_INTERVAL = + prefer.s.pollingInterval === 1 ? MIN_POLLING_INTERVAL : + prefer.s.pollingInterval === 2 ? MIN_POLLING_INTERVAL * 1.5 : + prefer.s.pollingInterval === 3 ? MIN_POLLING_INTERVAL * 1.5 * 1.5 : + MIN_POLLING_INTERVAL; window.setInterval(() => { const ids = [...pollingQueue.entries()] diff --git a/packages/frontend/src/use/use-pagination.ts b/packages/frontend/src/use/use-pagination.ts index 12ce2a7f7d..3193e263fd 100644 --- a/packages/frontend/src/use/use-pagination.ts +++ b/packages/frontend/src/use/use-pagination.ts @@ -64,6 +64,7 @@ export function usePagination(props: { async function init(): Promise { items.value = []; + queue.value = []; fetching.value = true; const params = props.ctx.params ? isRef(props.ctx.params) ? props.ctx.params.value : props.ctx.params : {}; await misskeyApi(props.ctx.endpoint, {