From b697ca05adc5c48d4e1a468c485774f9a8ccdce5 Mon Sep 17 00:00:00 2001 From: FruitRiin Date: Mon, 1 Sep 2025 14:25:40 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=81=E3=83=A3=E3=83=B3=E3=83=8D=E3=83=AB?= =?UTF-8?q?=E6=97=A2=E8=AA=AD=E3=81=AE=E5=90=8C=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/boot/main-boot.ts | 3 +++ .../src/components/MkChannelPreview.vue | 2 +- packages/frontend/src/local-storage.ts | 3 ++- packages/frontend/src/pages/channel.vue | 18 +++++++++++-- packages/frontend/src/pages/timeline.vue | 2 +- packages/frontend/src/registry-item.ts | 25 +++++++++++++++++++ 6 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 packages/frontend/src/registry-item.ts diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index 18817d3f79..86d5779346 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -29,6 +29,7 @@ import { prefer } from '@/preferences.js'; import { updateCurrentAccountPartial } from '@/accounts.js'; import { migrateOldSettings } from '@/pref-migrate.js'; import { unisonReload } from '@/utility/unison-reload.js'; +import { miRegistoryItem } from '@/registry-item.js'; export async function mainBoot() { const { isClientUpdated, lastVersion } = await common(async () => { @@ -285,6 +286,8 @@ export async function mainBoot() { // } //} //miLocalStorage.setItem('lastUsed', Date.now().toString()); + const channelLastReadedAt = await miRegistoryItem.get('channelsLastReadedAt'); + miLocalStorage.setItemAsJson('channelsLastReadedAt', channelLastReadedAt); const latestDonationInfoShownAt = miLocalStorage.getItem('latestDonationInfoShownAt'); const neverShowDonationInfo = miLocalStorage.getItem('neverShowDonationInfo'); diff --git a/packages/frontend/src/components/MkChannelPreview.vue b/packages/frontend/src/components/MkChannelPreview.vue index f79989d882..c6f5d08299 100644 --- a/packages/frontend/src/components/MkChannelPreview.vue +++ b/packages/frontend/src/components/MkChannelPreview.vue @@ -56,7 +56,7 @@ const props = defineProps<{ }>(); const getLastReadedAt = (): number | null => { - return miLocalStorage.getItemAsJson(`channelLastReadedAt:${props.channel.id}`) ?? null; + return miLocalStorage.getItemAsJson('channelsLastReadedAt')[props.channel.id] ?? null; }; const lastReadedAt = ref(getLastReadedAt()); diff --git a/packages/frontend/src/local-storage.ts b/packages/frontend/src/local-storage.ts index 687983bcdb..a3cae571ec 100644 --- a/packages/frontend/src/local-storage.ts +++ b/packages/frontend/src/local-storage.ts @@ -39,7 +39,8 @@ export type Keys = ( `aiscript:${string}` | 'lastEmojisFetchedAt' | // DEPRECATED, stored in indexeddb (13.9.0~) 'emojis' | // DEPRECATED, stored in indexeddb (13.9.0~); - `channelLastReadedAt:${string}` | + `channelLastReadedAt:${string}` | // DEPRECATED, stored channelsLastReadedAt and registry + 'channelsLastReadedAt' | `idbfallback::${string}` ); diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue index 9e1608f24d..ed4b8ba695 100644 --- a/packages/frontend/src/pages/channel.vue +++ b/packages/frontend/src/pages/channel.vue @@ -98,6 +98,7 @@ import { notesSearchAvailable } from '@/utility/check-permissions.js'; import { miLocalStorage } from '@/local-storage.js'; import { useRouter } from '@/router.js'; import { Paginator } from '@/utility/paginator.js'; +import { miRegistoryItem } from '@/registry-item'; const router = useRouter(); @@ -139,15 +140,28 @@ watch(() => props.channelId, async () => { } if ((favorited.value || channel.value.isFollowing) && channel.value.lastNotedAt) { - const lastReadedAt: number = miLocalStorage.getItemAsJson(`channelLastReadedAt:${channel.value.id}`) ?? 0; + const lastReadedAt = miLocalStorage.getItemAsJson('channelsLastReadedAt')[channel.value.id] ?? undefined; const lastNotedAt = Date.parse(channel.value.lastNotedAt); + if (!lastReadedAt) { + saveLastReadedAt(); + return; + } + if (lastNotedAt > lastReadedAt) { - miLocalStorage.setItemAsJson(`channelLastReadedAt:${channel.value.id}`, lastNotedAt); + saveLastReadedAt(); } } }, { immediate: true }); +async function saveLastReadedAt() { + if (!channel.value) return; + const tmp = await miRegistoryItem.get('channelsLastReadedAt'); + tmp[channel.value.id] = Date.now(); + await miRegistoryItem.set('channelsLastReadedAt', tmp); + miLocalStorage.setItemAsJson('channelsLastReadedAt', tmp); +} + function edit() { router.push('/channels/:channelId/edit', { params: { diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index f72549df07..e47f7e18c6 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -148,7 +148,7 @@ async function chooseChannel(ev: MouseEvent): Promise { const channels = await favoritedChannelsCache.fetch(); const items: (MenuItem | undefined)[] = [ ...channels.map(channel => { - const lastReadedAt = miLocalStorage.getItemAsJson(`channelLastReadedAt:${channel.id}`) ?? null; + const lastReadedAt = miLocalStorage.getItemAsJson('channelsLastReadedAt')[channel.id] ?? null; const hasUnreadNote = (lastReadedAt && channel.lastNotedAt) ? Date.parse(channel.lastNotedAt) > lastReadedAt : !!(!lastReadedAt && channel.lastNotedAt); return { diff --git a/packages/frontend/src/registry-item.ts b/packages/frontend/src/registry-item.ts new file mode 100644 index 0000000000..9b1a8ff546 --- /dev/null +++ b/packages/frontend/src/registry-item.ts @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { misskeyApi } from '@/utility/misskey-api.js'; + +export type Keys = + 'channelsLastReadedAt' | // DEPRECATED, stored registory(2025.1.xxx) + 'somethingElse'; + +export const miRegistoryItem = { + async get(key: Keys) { + try { + return JSON.parse(await misskeyApi('i/registry/get', { scope: ['client'], key })); + } catch (err) { + if (err.code === 'NO_SUCH_KEY') return {}; + throw err; + } + }, + async set(key: Keys, payload) { + await misskeyApi('i/registry/set', { scope: ['client'], key, value: JSON.stringify(payload) }); + }, +}; +