From 5afbe0e3939655385231a1f93accbb2bf828076f Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Tue, 16 Apr 2024 17:47:17 +0900 Subject: [PATCH] feat(vmimi-relay/frontend): virtual kemomimi relay social timeline --- locales/index.d.ts | 4 ++++ locales/ja-JP.yml | 1 + .../frontend/src/components/MkTimeline.vue | 15 ++++++++++++- packages/frontend/src/pages/timeline.vue | 22 ++++++++++++------- packages/frontend/src/store.ts | 2 +- packages/frontend/src/ui/deck/deck-store.ts | 2 +- packages/frontend/src/ui/deck/tl-column.vue | 7 ++++-- 7 files changed, 40 insertions(+), 13 deletions(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index a51d35437a66..a164ff919a9d 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -8573,6 +8573,10 @@ export interface Locale extends ILocale { * ぶいみみリレー */ "vmimiRelay": string; + /** + * ぶいみみリレーソーシャル + */ + "vmimiRelaySocial": string; }; "_play": { /** diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 61f2db9f831e..874f368564f6 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2263,6 +2263,7 @@ _timelines: social: "ソーシャル" global: "グローバル" vmimiRelay: "ぶいみみリレー" + vmimiRelaySocial: "ぶいみみリレーソーシャル" _play: new: "Playの作成" diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue index a1c1ea234118..f8e7c41f77bf 100644 --- a/packages/frontend/src/components/MkTimeline.vue +++ b/packages/frontend/src/components/MkTimeline.vue @@ -29,7 +29,7 @@ import { defaultStore } from '@/store.js'; import { Paging } from '@/components/MkPagination.vue'; const props = withDefaults(defineProps<{ - src: 'home' | 'local' | 'social' | 'global' | 'vmimi-relay' | 'mentions' | 'directs' | 'list' | 'antenna' | 'channel' | 'role'; + src: 'home' | 'local' | 'social' | 'global' | 'vmimi-relay' | 'vmimi-relay-social' | 'mentions' | 'directs' | 'list' | 'antenna' | 'channel' | 'role'; list?: string; antenna?: string; channel?: string; @@ -127,6 +127,12 @@ function connectChannel() { withFiles: props.onlyFiles ? true : undefined, withReplies: props.withReplies, }); + } else if (props.src === 'vmimi-relay-social') { + connection = stream.useChannel('vmimiRelayHybridTimeline', { + withRenotes: props.withRenotes, + withFiles: props.onlyFiles ? true : undefined, + withReplies: props.withReplies, + }); } else if (props.src === 'mentions') { connection = stream.useChannel('main'); connection.on('mention', prepend); @@ -206,6 +212,13 @@ function updatePaginationQuery() { withFiles: props.onlyFiles ? true : undefined, withReplies: props.withReplies, }; + } else if (props.src === 'vmimi-relay-social') { + endpoint = 'notes/vmimi-relay-hybrid-timeline'; + query = { + withRenotes: props.withRenotes, + withFiles: props.onlyFiles ? true : undefined, + withReplies: props.withReplies, + }; } else if (props.src === 'mentions') { endpoint = 'notes/mentions'; query = null; diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index df8142e46c2f..2bffbb3c94cd 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -57,6 +57,7 @@ import { miLocalStorage } from '@/local-storage.js'; provide('shouldOmitHeaderTitle', true); const isLocalTimelineAvailable = ($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable); +const isVmimiRelayTimelineAvailable = ($i == null && instance.policies.vrtlAvailable) || ($i != null && $i.policies.vrtlAvailable); const isGlobalTimelineAvailable = ($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable); const keymap = { 't': focus, @@ -67,7 +68,7 @@ const rootEl = shallowRef(); const queue = ref(0); const srcWhenNotSignin = ref<'local' | 'global'>(isLocalTimelineAvailable ? 'local' : 'global'); -const src = computed<'home' | 'local' | 'social' | 'global' | 'vmimi-relay' | `list:${string}`>({ +const src = computed<'home' | 'local' | 'social' | 'global' | 'vmimi-relay' | 'vmimi-relay-social' | `list:${string}`>({ get: () => ($i ? defaultStore.reactiveState.tl.value.src : srcWhenNotSignin.value), set: (x) => saveSrc(x), }); @@ -82,7 +83,7 @@ const localSocialTLFilterSwitchStore = ref<'withReplies' | 'onlyFiles' | false>( const withReplies = computed({ get: () => { if (!$i) return false; - if (['local', 'social', 'vmimi-relay'].includes(src.value) && localSocialTLFilterSwitchStore.value === 'onlyFiles') { + if (['local', 'social', 'vmimi-relay', 'vmimi-relay-social'].includes(src.value) && localSocialTLFilterSwitchStore.value === 'onlyFiles') { return false; } else { return defaultStore.reactiveState.tl.value.filter.withReplies; @@ -92,7 +93,7 @@ const withReplies = computed({ }); const onlyFiles = computed({ get: () => { - if (['local', 'social', 'vmimi-relay'].includes(src.value) && localSocialTLFilterSwitchStore.value === 'withReplies') { + if (['local', 'social', 'vmimi-relay', 'vmimi-relay-social'].includes(src.value) && localSocialTLFilterSwitchStore.value === 'withReplies') { return false; } else { return defaultStore.reactiveState.tl.value.filter.onlyFiles; @@ -199,7 +200,7 @@ async function chooseChannel(ev: MouseEvent): Promise { os.popupMenu(items, ev.currentTarget ?? ev.target); } -function saveSrc(newSrc: 'home' | 'local' | 'social' | 'global' | 'vmimi-relay' | `list:${string}`): void { +function saveSrc(newSrc: 'home' | 'local' | 'social' | 'global' | 'vmimi-relay' | 'vmimi-relay-social' | `list:${string}`): void { const out = deepMerge({ src: newSrc }, defaultStore.state.tl); if (newSrc.startsWith('userList:')) { @@ -250,7 +251,7 @@ const headerActions = computed(() => { type: 'switch', text: i18n.ts.showRenotes, ref: withRenotes, - }, src.value === 'local' || src.value === 'social' || src.value === 'vmimi-relay' ? { + }, src.value === 'local' || src.value === 'social' || src.value === 'vmimi-relay' || src.value === 'vmimi-relay-social' ? { type: 'switch', text: i18n.ts.showRepliesToOthersInTimeline, ref: withReplies, @@ -263,7 +264,7 @@ const headerActions = computed(() => { type: 'switch', text: i18n.ts.fileAttachedOnly, ref: onlyFiles, - disabled: src.value === 'local' || src.value === 'social' || src.value === 'vmimi-relay' ? withReplies : false, + disabled: src.value === 'local' || src.value === 'social' || src.value === 'vmimi-relay' || src.value === 'vmimi-relay-social' ? withReplies : false, }], ev.currentTarget ?? ev.target); }, }, @@ -305,11 +306,16 @@ const headerTabs = computed(() => [...(defaultStore.reactiveState.pinnedUserList title: i18n.ts._timelines.global, icon: 'ti ti-whirl', iconOnly: true, -}, { +}] : []), ...(isVmimiRelayTimelineAvailable ? [{ key: 'vmimi-relay', title: i18n.ts._timelines.vmimiRelay, icon: 'ti ti-circles-relation', iconOnly: true, +}, { + key: 'vmimi-relay-social', + title: i18n.ts._timelines.vmimiRelaySocial, + icon: 'ti ti-topology-full', + iconOnly: true, }] : []), { icon: 'ti ti-list', title: i18n.ts.lists, @@ -344,7 +350,7 @@ const headerTabsWhenNotLogin = computed(() => [ definePageMetadata(() => ({ title: i18n.ts.timeline, - icon: src.value === 'local' ? 'ti ti-planet' : src.value === 'social' ? 'ti ti-universe' : src.value === 'global' ? 'ti ti-whirl' : src.value === 'vmimi-relay' ? 'ti ti-circles-relation' : 'ti ti-home', + icon: src.value === 'local' ? 'ti ti-planet' : src.value === 'social' ? 'ti ti-universe' : src.value === 'global' ? 'ti ti-whirl' : src.value === 'vmimi-relay' ? 'ti ti-circles-relation': src.value === 'vmimi-relay-social' ? 'ti ti-topology-full' : 'ti ti-home', })); diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 516fc296a18a..bb8c91e3372b 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -184,7 +184,7 @@ export const defaultStore = markRaw(new Storage('base', { tl: { where: 'deviceAccount', default: { - src: 'home' as 'home' | 'local' | 'social' | 'global' | 'vmimi-relay' | `list:${string}`, + src: 'home' as 'home' | 'local' | 'social' | 'global' | 'vmimi-relay' | 'vmimi-relay-social' | `list:${string}`, userList: null as Misskey.entities.UserList | null, filter: { withReplies: true, diff --git a/packages/frontend/src/ui/deck/deck-store.ts b/packages/frontend/src/ui/deck/deck-store.ts index a41b5ecb28c5..bb61e754feac 100644 --- a/packages/frontend/src/ui/deck/deck-store.ts +++ b/packages/frontend/src/ui/deck/deck-store.ts @@ -29,7 +29,7 @@ export type Column = { channelId?: string; roleId?: string; excludeTypes?: typeof notificationTypes[number][]; - tl?: 'home' | 'local' | 'social' | 'global' | 'vmimi-relay'; + tl?: 'home' | 'local' | 'social' | 'global' | 'vmimi-relay' | 'vmimi-relay-social'; withRenotes?: boolean; withReplies?: boolean; onlyFiles?: boolean; diff --git a/packages/frontend/src/ui/deck/tl-column.vue b/packages/frontend/src/ui/deck/tl-column.vue index 0090f4fd694f..a930a8c2dcef 100644 --- a/packages/frontend/src/ui/deck/tl-column.vue +++ b/packages/frontend/src/ui/deck/tl-column.vue @@ -11,6 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only + {{ column.name }} @@ -98,6 +99,8 @@ async function setType() { value: 'global' as const, text: i18n.ts._timelines.global, }, { value: 'vmimi-relay' as const, text: i18n.ts._timelines.vmimiRelay, + }, { + value: 'vmimi-relay-social' as const, text: i18n.ts._timelines.vmimiRelaySocial, }], }); if (canceled) { @@ -119,7 +122,7 @@ const menu = [{ type: 'switch', text: i18n.ts.showRenotes, ref: withRenotes, -}, props.column.tl === 'local' || props.column.tl === 'social' || props.column.tl === 'vmimi-relay' ? { +}, props.column.tl === 'local' || props.column.tl === 'social' || props.column.tl === 'vmimi-relay-social' || props.column.tl === 'vmimi-relay' ? { type: 'switch', text: i18n.ts.showRepliesToOthersInTimeline, ref: withReplies, @@ -128,7 +131,7 @@ const menu = [{ type: 'switch', text: i18n.ts.fileAttachedOnly, ref: onlyFiles, - disabled: props.column.tl === 'local' || props.column.tl === 'social' ? withReplies : false, + disabled: props.column.tl === 'local' || props.column.tl === 'social' || props.column.tl === 'vmimi-relay-social' || props.column.tl === 'vmimi-relay' ? withReplies : false, }];