Skip to content

Commit

Permalink
Feat(Frontend): リアクションミュートを実装
Browse files Browse the repository at this point in the history
  • Loading branch information
mattyatea committed Jul 18, 2024
1 parent db94657 commit 17312d1
Show file tree
Hide file tree
Showing 15 changed files with 1,693 additions and 283 deletions.
4 changes: 4 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,10 @@ export interface Locale extends ILocale {
* リノートのミュートを解除
*/
"renoteUnmute": string;
/**
* リアクションのミュート
*/
"mutedReactions": string;
/**
* ブロック
*/
Expand Down
1 change: 1 addition & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ mute: "ミュート"
unmute: "ミュート解除"
renoteMute: "リノートをミュート"
renoteUnmute: "リノートのミュートを解除"
mutedReactions: "リアクションのミュート"
block: "ブロック"
unblock: "ブロック解除"
suspend: "凍結"
Expand Down
12 changes: 12 additions & 0 deletions packages/backend/migration/1721320100254-reactionMute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export class ReactionMute1721320100254 {
name = 'ReactionMute1721320100254'

async up(queryRunner) {

await queryRunner.query(`ALTER TABLE "user_profile" ADD "mutedReactions" jsonb NOT NULL DEFAULT '[]'`);
}

async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "mutedReactions"`);
}
}
1 change: 1 addition & 0 deletions packages/backend/src/core/entities/UserEntityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,7 @@ export class UserEntityService implements OnModuleInit {
mutedWords: profile!.mutedWords,
hardMutedWords: profile!.hardMutedWords,
mutedInstances: profile!.mutedInstances,
mutedReactions: profile!.mutedReactions,
mutingNotificationTypes: [], // 後方互換性のため
notificationRecieveConfig: profile!.notificationRecieveConfig,
emailNotificationTypes: profile!.emailNotificationTypes,
Expand Down
5 changes: 5 additions & 0 deletions packages/backend/src/models/UserProfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,11 @@ export class MiUserProfile {
})
public mutedInstances: string[];

@Column('jsonb', {
default: [],
})
public mutedReactions: (string[] | string)[];

Check failure on line 241 in packages/backend/src/models/UserProfile.ts

View workflow job for this annotation

GitHub Actions / lint (backend)

Multiple spaces found before '('

@Column('jsonb', {
default: {},
})
Expand Down
7 changes: 7 additions & 0 deletions packages/backend/src/server/api/endpoints/i/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export const paramDef = {
pinnedPageId: { type: 'string', format: 'misskey:id', nullable: true },
mutedWords: muteWords,
hardMutedWords: muteWords,
mutedReactions: muteWords,
mutedInstances: { type: 'array', items: {
type: 'string',
} },
Expand Down Expand Up @@ -311,6 +312,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
validateMuteWordRegex(ps.hardMutedWords);
profileUpdates.hardMutedWords = ps.hardMutedWords;
}
if (ps.mutedReactions !== undefined) {
policies ??= await this.roleService.getUserPolicies(user.id);
checkMuteWordCount(ps.mutedReactions, policies.wordMuteLimit);
validateMuteWordRegex(ps.mutedReactions);
profileUpdates.mutedReactions = ps.mutedReactions;
}
if (ps.mutedInstances !== undefined) profileUpdates.mutedInstances = ps.mutedInstances;
if (ps.notificationRecieveConfig !== undefined) profileUpdates.notificationRecieveConfig = ps.notificationRecieveConfig;
if (typeof ps.isLocked === 'boolean') updates.isLocked = ps.isLocked;
Expand Down
21 changes: 17 additions & 4 deletions packages/frontend/src/components/MkReactionsViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import * as Misskey from 'misskey-js';
import { inject, watch, ref } from 'vue';
import XReaction from '@/components/MkReactionsViewer.reaction.vue';
import { defaultStore } from '@/store.js';
import { $i } from '@/account.js';

const props = withDefaults(defineProps<{
note: Misskey.entities.Note & {
Expand All @@ -46,6 +47,7 @@ if (props.note.myReaction && !Object.keys(reactions.value).includes(props.note.m
reactions.value[props.note.myReaction] = props.note.reactions[props.note.myReaction];
}


function onMockToggleReaction(emoji: string, count: number) {
if (!mock) return;

Expand All @@ -54,7 +56,13 @@ function onMockToggleReaction(emoji: string, count: number) {

emit('mockUpdateMyReaction', emoji, (count - reactions.value[i][1]));
}
if ($i && reactions.value){

reactions.value = reactions.value.filter(([reactionType]) =>{
if (reactionType === props.note.myReaction) return true;
if (!($i.mutedReactions.flat()).includes(reactionType)) return true;
} );
}
watch([() => props.note.reactions, () => props.maxNumber], ([newSource, maxNumber]) => {
let newReactions: [string, number][] = [];
hasMoreReactions.value = Object.keys(newSource).length > maxNumber;
Expand All @@ -65,7 +73,6 @@ watch([() => props.note.reactions, () => props.maxNumber], ([newSource, maxNumbe
newReactions.push(reactions.value[i]);
}
}

const newReactionsNames = newReactions.map(([x]) => x);
newReactions = [
...newReactions,
Expand All @@ -76,11 +83,17 @@ watch([() => props.note.reactions, () => props.maxNumber], ([newSource, maxNumbe

newReactions = newReactions.slice(0, props.maxNumber);

if (props.note. myReaction && !newReactions.map(([x]) => x).includes(props.note.myReaction)) {
if (props.note.myReaction && !newReactions.map(([x]) => x).includes(props.note.myReaction)) {
newReactions.push([props.note.myReaction, newSource[props.note.myReaction]]);
}

reactions.value = newReactions;
if ($i){
reactions.value = newReactions.filter(([reactionType]) =>{
if (reactionType === props.note.myReaction) return true;
if (!($i.mutedReactions.flat()).includes(reactionType)) return true;
} );
} else {
reactions.value = newReactions;
}
}, { immediate: true, deep: true });
</script>

Expand Down
10 changes: 10 additions & 0 deletions packages/frontend/src/pages/settings/mute-block.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<XWordMute :muted="$i.hardMutedWords" @save="saveHardMutedWords"/>
</MkFolder>

<MkFolder>
<template #icon><i class="ti ti-message-off"></i></template>
<template #label>{{ i18n.ts.mutedReactions }}</template>

<XWordMute :notCaption="true" :muted="$i.mutedReactions" @save="saveMutedReactions"/>
</MkFolder>

<MkFolder>
<template #icon><i class="ti ti-planet-off"></i></template>
<template #label>{{ i18n.ts.instanceMute }}</template>
Expand Down Expand Up @@ -225,6 +232,9 @@ async function saveMutedWords(mutedWords: (string | string[])[]) {
async function saveHardMutedWords(hardMutedWords: (string | string[])[]) {
await misskeyApi('i/update', { hardMutedWords });
}
async function saveMutedReactions(mutedReactions: (string | string[])[]) {
await misskeyApi('i/update', { mutedReactions });
}

const headerActions = computed(() => []);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div>
<MkTextarea v-model="mutedWords">
<span>{{ i18n.ts._wordMute.muteWords }}</span>
<template #caption>{{ i18n.ts._wordMute.muteWordsDescription }}<br>{{ i18n.ts._wordMute.muteWordsDescription2 }}</template>
<template v-if="!notCaption" #caption>{{ i18n.ts._wordMute.muteWordsDescription }}<br>{{ i18n.ts._wordMute.muteWordsDescription2 }}</template>
</MkTextarea>
</div>
<MkButton primary inline :disabled="!changed" @click="save()"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
Expand All @@ -24,6 +24,7 @@ import { i18n } from '@/i18n.js';

const props = defineProps<{
muted: (string[] | string)[];
notCaption?: boolean;
}>();

const emit = defineEmits<{
Expand Down
Loading

0 comments on commit 17312d1

Please sign in to comment.