diff --git a/locales/en-US.yml b/locales/en-US.yml index e19f1585a8..d580e324bf 100755 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -2824,3 +2824,6 @@ _contextMenu: app: "Application" appWithShift: "Application with shift key" native: "Native" +_reactionChecksMuting: + title: "Check mutings when get reactions" + caption: "Check mutings when get reactions, but cache does not work and may increase traffic" diff --git a/locales/index.d.ts b/locales/index.d.ts index 27bcf5b53d..ef516b0a28 100755 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -10895,6 +10895,16 @@ export interface Locale extends ILocale { */ "native": string; }; + "_reactionChecksMuting": { + /** + * リアクションでミュートを考慮する + */ + "title": string; + /** + * リアクションがミュートを考慮しますが、キャッシュが効かず通信量が増えることがあります。 + */ + "caption": string; + }; } declare const locales: { [lang: string]: Locale; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 3728ec45d3..61d679ef14 100755 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2899,3 +2899,7 @@ _contextMenu: app: "アプリケーション" appWithShift: "Shiftキーでアプリケーション" native: "ブラウザのUI" + +_reactionChecksMuting: + title: "リアクションでミュートを考慮する" + caption: "リアクションがミュートを考慮しますが、キャッシュが効かず通信量が増えることがあります。" diff --git a/packages/backend/src/server/api/endpoints/notes/reactions.ts b/packages/backend/src/server/api/endpoints/notes/reactions.ts index 7e334df93e..57aff1a1d5 100755 --- a/packages/backend/src/server/api/endpoints/notes/reactions.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions.ts @@ -4,13 +4,12 @@ */ import { Inject, Injectable } from '@nestjs/common'; -import { Brackets, type FindOptionsWhere } from 'typeorm'; import type { NoteReactionsRepository } from '@/models/_.js'; -import type { MiNoteReaction } from '@/models/NoteReaction.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { NoteReactionEntityService } from '@/core/entities/NoteReactionEntityService.js'; import { DI } from '@/di-symbols.js'; import { QueryService } from '@/core/QueryService.js'; +import { CacheService } from '@/core/CacheService.js'; export const meta = { tags: ['notes', 'reactions'], @@ -59,6 +58,7 @@ export default class extends Endpoint { // eslint- private noteReactionEntityService: NoteReactionEntityService, private queryService: QueryService, + private cacheService: CacheService, ) { super(meta, paramDef, async (ps, me) => { const query = this.queryService.makePaginationQuery(this.noteReactionsRepository.createQueryBuilder('reaction'), ps.sinceId, ps.untilId) @@ -66,6 +66,15 @@ export default class extends Endpoint { // eslint- .leftJoinAndSelect('reaction.user', 'user') .leftJoinAndSelect('reaction.note', 'note'); + if (me != null) { + const [userIdsWhoMeMuting, userIdsWhoBlockingMe] = await Promise.all([ + this.cacheService.userMutingsCache.get(me.id), + this.cacheService.userBlockedCache.get(me.id), + ]); + + query.andWhere('reaction.userId NOT IN (:...userIds)', { userIds: Array.from(userIdsWhoMeMuting ?? []).concat(Array.from(userIdsWhoBlockingMe ?? [])) }); + } + if (ps.type) { // ローカルリアクションはホスト名が . とされているが // DB 上ではそうではないので、必要に応じて変換 diff --git a/packages/frontend/src/components/MkReactionsViewer.details.vue b/packages/frontend/src/components/MkReactionsViewer.details.vue index 60118fadd2..aa5cbb73a0 100755 --- a/packages/frontend/src/components/MkReactionsViewer.details.vue +++ b/packages/frontend/src/components/MkReactionsViewer.details.vue @@ -15,6 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only +
{{ i18n.ts.noUsers }}
+{{ count - 10 }}
@@ -26,6 +27,7 @@ import { } from 'vue'; import MkTooltip from './MkTooltip.vue'; import MkReactionIcon from '@/components/MkReactionIcon.vue'; import { getEmojiName } from '@/scripts/emojilist.js'; +import { i18n } from '@/i18n'; defineProps<{ showing: boolean; diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue index 6506035f8f..3688801791 100755 --- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue +++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue @@ -36,6 +36,8 @@ import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.j import { customEmojisMap } from '@/custom-emojis.js'; import { getUnicodeEmoji } from '@/scripts/emojilist.js'; +const reactionChecksMuting = computed(defaultStore.makeGetterSetter('reactionChecksMuting')); + const props = defineProps<{ reaction: string; count: number; @@ -146,7 +148,9 @@ onMounted(() => { if (!mock) { useTooltip(buttonEl, async (showing) => { - const reactions = await misskeyApiGet('notes/reactions', { + const useGet = !reactionChecksMuting.value; + const apiCall = useGet ? misskeyApiGet : misskeyApi; + const reactions = await apiCall('notes/reactions', { noteId: props.note.id, type: props.reaction, limit: 10, @@ -154,12 +158,13 @@ if (!mock) { }); const users = reactions.map(x => x.user); + const count = users.length; const { dispose } = os.popup(XDetails, { showing, reaction: props.reaction, users, - count: props.count, + count, targetElement: buttonEl.value, }, { closed: () => dispose(), diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 637c1b24b9..599285d9af 100755 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -235,6 +235,11 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.enableHorizontalSwipe }} {{ i18n.ts.alwaysConfirmFollow }} {{ i18n.ts.confirmWhenRevealingSensitiveMedia }} + + + {{ i18n.ts._reactionChecksMuting.title }}{{ i18n.ts.originalFeature }} + + @@ -435,6 +440,8 @@ const useNativeUIForVideoAudioPlayer = computed(defaultStore.makeGetterSetter('u const alwaysConfirmFollow = computed(defaultStore.makeGetterSetter('alwaysConfirmFollow')); const confirmWhenRevealingSensitiveMedia = computed(defaultStore.makeGetterSetter('confirmWhenRevealingSensitiveMedia')); const contextMenu = computed(defaultStore.makeGetterSetter('contextMenu')); +const searchEngine = computed(defaultStore.makeGetterSetter('searchEngine')); +const reactionChecksMuting = computed(defaultStore.makeGetterSetter('reactionChecksMuting')); watch(lang, () => { miLocalStorage.setItem('lang', lang.value as string); diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index dd155190aa..e2c839939f 100755 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -532,10 +532,10 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: false, }, - contextMenu: { + contextMenu: { where: 'device', default: 'app' as 'app' | 'appWithShift' | 'native', - }, + }, sound_masterVolume: { where: 'device', @@ -565,6 +565,14 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: { type: 'syuilo/bubble2', volume: 1 } as SoundStore, }, + searchEngine: { + where: 'device', + default: 'https://google.com/search?q=', + }, + reactionChecksMuting: { + where: 'device', + default: true, + }, })); // TODO: 他のタブと永続化されたstateを同期