diff options
| author | anatawa12 <anatawa12@icloud.com> | 2023-11-23 18:56:20 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-23 18:56:20 +0900 |
| commit | 864827f788cd1671a4db2ebc159c1c8ab031b7ad (patch) | |
| tree | 689fa67a1f438cc3410446cd893397d91c2d6725 /packages/frontend/src | |
| parent | 絵文字のオートコンプリート強化の対応 (#12365) (diff) | |
| download | misskey-864827f788cd1671a4db2ebc159c1c8ab031b7ad.tar.gz misskey-864827f788cd1671a4db2ebc159c1c8ab031b7ad.tar.bz2 misskey-864827f788cd1671a4db2ebc159c1c8ab031b7ad.zip | |
Hard mute (#12376)
* feat(backend,misskey-js): hard mute storage in backend
* fix(backend,misskey-js): mute word record type
* chore(frontend): generalize XWordMute
* feat(frontend): configure hard mute
* feat(frontend): hard mute notes on the timelines
* lint(backend,frontend): fix lint failure
* chore(misskey-js): update api.md
* fix(backend): test failure
* chore(frontend): check word mute for reply
* chore: limit hard mute count
Diffstat (limited to 'packages/frontend/src')
5 files changed, 43 insertions, 18 deletions
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index e300ef88a5..6349df2e30 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template> <div - v-if="!muted" + v-if="!hardMuted && !muted" v-show="!isDeleted" ref="el" v-hotkey="keymap" @@ -133,7 +133,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </article> </div> -<div v-else :class="$style.muted" @click="muted = false"> +<div v-else-if="!hardMuted" :class="$style.muted" @click="muted = false"> <I18n :src="i18n.ts.userSaysSomething" tag="small"> <template #name> <MkA v-user-preview="appearNote.userId" :to="userPage(appearNote.user)"> @@ -183,6 +183,7 @@ const props = withDefaults(defineProps<{ note: Misskey.entities.Note; pinned?: boolean; mock?: boolean; + withHardMute?: boolean; }>(), { mock: false, }); @@ -239,13 +240,23 @@ const urls = $computed(() => parsed ? extractUrlFromMfm(parsed) : null); const isLong = shouldCollapsed(appearNote, urls ?? []); const collapsed = ref(appearNote.cw == null && isLong); const isDeleted = ref(false); -const muted = ref($i ? checkWordMute(appearNote, $i, $i.mutedWords) : false); +const muted = ref(checkMute(appearNote, $i?.mutedWords)); +const hardMuted = ref(props.withHardMute && checkMute(appearNote, $i?.hardMutedWords)); const translation = ref<any>(null); const translating = ref(false); const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.user.instance); const canRenote = computed(() => ['public', 'home'].includes(appearNote.visibility) || (appearNote.visibility === 'followers' && appearNote.userId === $i.id)); let renoteCollapsed = $ref(defaultStore.state.collapseRenotes && isRenote && (($i && ($i.id === note.userId || $i.id === appearNote.userId)) || (appearNote.myReaction != null))); +function checkMute(note: Misskey.entities.Note, mutedWords: Array<string | string[]> | undefined | null): boolean { + if (mutedWords == null) return false; + + if (checkWordMute(note, $i, mutedWords)) return true; + if (note.reply && checkWordMute(note.reply, $i, mutedWords)) return true; + if (note.renote && checkWordMute(note.renote, $i, mutedWords)) return true; + return false; +} + const keymap = { 'r': () => reply(true), 'e|a|plus': () => react(true), diff --git a/packages/frontend/src/components/MkNotes.vue b/packages/frontend/src/components/MkNotes.vue index 89fd504dcc..7af31074db 100644 --- a/packages/frontend/src/components/MkNotes.vue +++ b/packages/frontend/src/components/MkNotes.vue @@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only :ad="true" :class="$style.notes" > - <MkNote :key="note._featuredId_ || note._prId_ || note.id" :class="$style.note" :note="note"/> + <MkNote :key="note._featuredId_ || note._prId_ || note.id" :class="$style.note" :note="note" :withHardMute="true"/> </MkDateSeparatedList> </div> </template> diff --git a/packages/frontend/src/components/MkNotifications.vue b/packages/frontend/src/components/MkNotifications.vue index 0c817bd64c..7b072fa492 100644 --- a/packages/frontend/src/components/MkNotifications.vue +++ b/packages/frontend/src/components/MkNotifications.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template #default="{ items: notifications }"> <MkDateSeparatedList v-slot="{ item: notification }" :class="$style.list" :items="notifications" :noGap="true"> - <MkNote v-if="['reply', 'quote', 'mention'].includes(notification.type)" :key="notification.id" :note="notification.note"/> + <MkNote v-if="['reply', 'quote', 'mention'].includes(notification.type)" :key="notification.id" :note="notification.note" :withHardMute="true"/> <XNotification v-else :key="notification.id" :notification="notification" :withTime="true" :full="true" class="_panel"/> </MkDateSeparatedList> </template> diff --git a/packages/frontend/src/pages/settings/mute-block.vue b/packages/frontend/src/pages/settings/mute-block.vue index c6cbd424ec..4883ca0df4 100644 --- a/packages/frontend/src/pages/settings/mute-block.vue +++ b/packages/frontend/src/pages/settings/mute-block.vue @@ -9,7 +9,14 @@ SPDX-License-Identifier: AGPL-3.0-only <template #icon><i class="ti ti-message-off"></i></template> <template #label>{{ i18n.ts.wordMute }}</template> - <XWordMute/> + <XWordMute :muted="$i!.mutedWords" @save="saveMutedWords"/> + </MkFolder> + + <MkFolder> + <template #icon><i class="ti ti-message-off"></i></template> + <template #label>{{ i18n.ts.hardWordMute }}</template> + + <XWordMute :muted="$i!.hardMutedWords" @save="saveHardMutedWords"/> </MkFolder> <MkFolder> @@ -129,6 +136,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js'; import MkUserCardMini from '@/components/MkUserCardMini.vue'; import * as os from '@/os.js'; import { infoImageUrl } from '@/instance.js'; +import { $i } from '@/account.js'; import MkFolder from '@/components/MkFolder.vue'; const renoteMutingPagination = { @@ -207,6 +215,14 @@ async function toggleBlockItem(item) { } } +async function saveMutedWords(mutedWords: (string | string[])[]) { + await os.api('i/update', { mutedWords }); +} + +async function saveHardMutedWords(hardMutedWords: (string | string[])[]) { + await os.api('i/update', { hardMutedWords }); +} + const headerActions = $computed(() => []); const headerTabs = $computed(() => []); diff --git a/packages/frontend/src/pages/settings/mute-block.word-mute.vue b/packages/frontend/src/pages/settings/mute-block.word-mute.vue index 25a836ea55..7328967c51 100644 --- a/packages/frontend/src/pages/settings/mute-block.word-mute.vue +++ b/packages/frontend/src/pages/settings/mute-block.word-mute.vue @@ -18,16 +18,17 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, watch } from 'vue'; import MkTextarea from '@/components/MkTextarea.vue'; -import MkKeyValue from '@/components/MkKeyValue.vue'; import MkButton from '@/components/MkButton.vue'; -import MkInfo from '@/components/MkInfo.vue'; -import MkTab from '@/components/MkTab.vue'; import * as os from '@/os.js'; -import number from '@/filters/number.js'; -import { defaultStore } from '@/store.js'; -import { $i } from '@/account.js'; import { i18n } from '@/i18n.js'; -import { definePageMetadata } from '@/scripts/page-metadata.js'; + +const props = defineProps<{ + muted: (string[] | string)[]; +}>(); + +const emit = defineEmits<{ + (ev: 'save', value: (string[] | string)[]): void; +}>(); const render = (mutedWords) => mutedWords.map(x => { if (Array.isArray(x)) { @@ -37,8 +38,7 @@ const render = (mutedWords) => mutedWords.map(x => { } }).join('\n'); -const tab = ref('soft'); -const mutedWords = ref(render($i!.mutedWords)); +const mutedWords = ref(render(props.muted)); const changed = ref(false); watch(mutedWords, () => { @@ -85,9 +85,7 @@ async function save() { return; } - await os.api('i/update', { - mutedWords: parsed, - }); + emit('save', parsed); changed.value = false; } |