diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c1db768e..dc9c082bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ChangeLog 10.81.0 ---------- * 動画のサムネイルを作成するように +* 個別に投稿のウォッチ/ウォッチ解除をできるように * リモートの外部サービス認証情報を表示するように * public の Renote/Reply/Quote先 が public以外 だったら、public => homeに * ユーザーページから管理者/モデレーターがアカウントのサイレンス/凍結をできるように diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index fd325f13c..24eac18c3 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -374,6 +374,8 @@ common/views/components/note-menu.vue: copy-link: "リンクをコピー" favorite: "お気に入り" unfavorite: "お気に入り解除" + watch: "ウォッチ" + unwatch: "ウォッチ解除" pin: "ピン留め" unpin: "ピン留め解除" delete: "削除" diff --git a/src/client/app/common/views/components/note-menu.vue b/src/client/app/common/views/components/note-menu.vue index ecea08b75..b83d5c325 100644 --- a/src/client/app/common/views/components/note-menu.vue +++ b/src/client/app/common/views/components/note-menu.vue @@ -10,14 +10,15 @@ import i18n from '../../../i18n'; import { url } from '../../../config'; import copyToClipboard from '../../../common/scripts/copy-to-clipboard'; import { concat, intersperse } from '../../../../../prelude/array'; -import { faCopy } from '@fortawesome/free-regular-svg-icons'; +import { faCopy, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons'; export default Vue.extend({ i18n: i18n('common/views/components/note-menu.vue'), props: ['note', 'source'], data() { return { - isFavorited: false + isFavorited: false, + isWatching: false }; }, computed: { @@ -55,6 +56,15 @@ export default Vue.extend({ text: this.$t('favorite'), action: this.favorite }, + this.note.userId != this.$store.state.i.id ? this.isWatching ? { + icon: faEyeSlash, + text: this.$t('unwatch'), + action: this.unwatch + } : { + icon: faEye, + text: this.$t('watch'), + action: this.watch + } : undefined, this.note.userId == this.$store.state.i.id ? (this.$store.state.i.pinnedNoteIds || []).includes(this.note.id) ? { icon: 'thumbtack', text: this.$t('unpin'), @@ -78,6 +88,7 @@ export default Vue.extend({ noteId: this.note.id }).then(state => { this.isFavorited = state.isFavorited; + this.isWatching = state.isWatching; }); }, @@ -166,6 +177,30 @@ export default Vue.extend({ }); }, + watch() { + this.$root.api('notes/watching/create', { + noteId: this.note.id + }).then(() => { + this.$root.dialog({ + type: 'success', + splash: true + }); + this.destroyDom(); + }); + }, + + unwatch() { + this.$root.api('notes/watching/delete', { + noteId: this.note.id + }).then(() => { + this.$root.dialog({ + type: 'success', + splash: true + }); + this.destroyDom(); + }); + }, + closed() { this.$nextTick(() => { this.destroyDom(); diff --git a/src/server/api/endpoints/notes/state.ts b/src/server/api/endpoints/notes/state.ts index d8adc48c9..e9db12ead 100644 --- a/src/server/api/endpoints/notes/state.ts +++ b/src/server/api/endpoints/notes/state.ts @@ -1,6 +1,7 @@ import $ from 'cafy'; import ID, { transform } from '../../../../misc/cafy-id'; import define from '../../define'; import Favorite from '../../../../models/favorite'; +import NoteWatching from '../../../../models/note-watching'; export const meta = { stability: 'stable', @@ -25,14 +26,23 @@ export const meta = { }; export default define(meta, (ps, user) => new Promise(async (res, rej) => { - const favorite = await Favorite.count({ - userId: user._id, - noteId: ps.noteId - }, { - limit: 1 - }); + const [favorite, watching] = await Promise.all([ + Favorite.count({ + userId: user._id, + noteId: ps.noteId + }, { + limit: 1 + }), + NoteWatching.count({ + userId: user._id, + noteId: ps.noteId + }, { + limit: 1 + }) + ]); res({ - isFavorited: favorite !== 0 + isFavorited: favorite !== 0, + isWatching: watching !== 0 }); }));