forked from AkkomaGang/akkoma-fe
Merge branch 'fix-reprooted-muted-posts' into 'develop'
Fixed some issues with muting See merge request pleroma/pleroma-fe!1120
This commit is contained in:
commit
e47d0f2103
9 changed files with 143 additions and 39 deletions
|
@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
### Changed
|
### Changed
|
||||||
- Removed the use of with_move parameters when fetching notifications
|
- Removed the use of with_move parameters when fetching notifications
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Multiple issues with muted statuses/notifications
|
||||||
|
|
||||||
## [Unreleased patch]
|
## [Unreleased patch]
|
||||||
### Add
|
### Add
|
||||||
- Added private notifications option for push notifications
|
- Added private notifications option for push notifications
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import StatusContent from '../status_content/status_content.vue'
|
||||||
import Status from '../status/status.vue'
|
import Status from '../status/status.vue'
|
||||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||||
import UserCard from '../user_card/user_card.vue'
|
import UserCard from '../user_card/user_card.vue'
|
||||||
|
@ -16,10 +17,11 @@ const Notification = {
|
||||||
},
|
},
|
||||||
props: [ 'notification' ],
|
props: [ 'notification' ],
|
||||||
components: {
|
components: {
|
||||||
Status,
|
StatusContent,
|
||||||
UserAvatar,
|
UserAvatar,
|
||||||
UserCard,
|
UserCard,
|
||||||
Timeago
|
Timeago,
|
||||||
|
Status
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleUserExpanded () {
|
toggleUserExpanded () {
|
||||||
|
|
|
@ -157,11 +157,9 @@
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<status
|
<status-content
|
||||||
class="faint"
|
class="faint"
|
||||||
:compact="true"
|
:status="notification.action"
|
||||||
:statusoid="notification.action"
|
|
||||||
:no-heading="true"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
border-bottom: 1px solid;
|
border-bottom: 1px solid;
|
||||||
border-color: $fallback--border;
|
border-color: $fallback--border;
|
||||||
border-color: var(--border, $fallback--border);
|
border-color: var(--border, $fallback--border);
|
||||||
|
word-wrap: break-word;
|
||||||
|
word-break: break-word;
|
||||||
|
|
||||||
&:hover .animated.avatar {
|
&:hover .animated.avatar {
|
||||||
canvas {
|
canvas {
|
||||||
|
@ -46,10 +48,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.muted {
|
|
||||||
padding: .25em .6em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.non-mention {
|
.non-mention {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
|
@ -12,7 +12,8 @@ import StatusPopover from '../status_popover/status_popover.vue'
|
||||||
import EmojiReactions from '../emoji_reactions/emoji_reactions.vue'
|
import EmojiReactions from '../emoji_reactions/emoji_reactions.vue'
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
|
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
|
||||||
import { filter, unescape, uniqBy } from 'lodash'
|
import { muteWordHits } from '../../services/status_parser/status_parser.js'
|
||||||
|
import { unescape, uniqBy } from 'lodash'
|
||||||
import { mapGetters, mapState } from 'vuex'
|
import { mapGetters, mapState } from 'vuex'
|
||||||
|
|
||||||
const Status = {
|
const Status = {
|
||||||
|
@ -44,6 +45,12 @@ const Status = {
|
||||||
muteWords () {
|
muteWords () {
|
||||||
return this.mergedConfig.muteWords
|
return this.mergedConfig.muteWords
|
||||||
},
|
},
|
||||||
|
showReasonMutedThread () {
|
||||||
|
return (
|
||||||
|
this.status.thread_muted ||
|
||||||
|
(this.status.reblog && this.status.reblog.thread_muted)
|
||||||
|
) && !this.inConversation
|
||||||
|
},
|
||||||
repeaterClass () {
|
repeaterClass () {
|
||||||
const user = this.statusoid.user
|
const user = this.statusoid.user
|
||||||
return highlightClass(user)
|
return highlightClass(user)
|
||||||
|
@ -93,20 +100,42 @@ const Status = {
|
||||||
return !!this.currentUser
|
return !!this.currentUser
|
||||||
},
|
},
|
||||||
muteWordHits () {
|
muteWordHits () {
|
||||||
const statusText = this.status.text.toLowerCase()
|
return muteWordHits(this.status, this.muteWords)
|
||||||
const statusSummary = this.status.summary.toLowerCase()
|
|
||||||
const hits = filter(this.muteWords, (muteWord) => {
|
|
||||||
return statusText.includes(muteWord.toLowerCase()) || statusSummary.includes(muteWord.toLowerCase())
|
|
||||||
})
|
|
||||||
|
|
||||||
return hits
|
|
||||||
},
|
},
|
||||||
muted () {
|
muted () {
|
||||||
const relationship = this.$store.getters.relationship(this.status.user.id)
|
const { status } = this
|
||||||
return !this.unmuted && (
|
const { reblog } = status
|
||||||
(!(this.inProfile && this.status.user.id === this.profileUserId) && relationship.muting) ||
|
const relationship = this.$store.getters.relationship(status.user.id)
|
||||||
(!this.inConversation && this.status.thread_muted) ||
|
const relationshipReblog = reblog && this.$store.getters.relationship(reblog.user.id)
|
||||||
this.muteWordHits.length > 0)
|
const reasonsToMute = (
|
||||||
|
// Post is muted according to BE
|
||||||
|
status.muted ||
|
||||||
|
// Reprööt of a muted post according to BE
|
||||||
|
(reblog && reblog.muted) ||
|
||||||
|
// Muted user
|
||||||
|
relationship.muting ||
|
||||||
|
// Muted user of a reprööt
|
||||||
|
(relationshipReblog && relationshipReblog.muting) ||
|
||||||
|
// Thread is muted
|
||||||
|
status.thread_muted ||
|
||||||
|
// Wordfiltered
|
||||||
|
this.muteWordHits.length > 0
|
||||||
|
)
|
||||||
|
const excusesNotToMute = (
|
||||||
|
(
|
||||||
|
this.inProfile && (
|
||||||
|
// Don't mute user's posts on user timeline (except reblogs)
|
||||||
|
(!reblog && status.user.id === this.profileUserId) ||
|
||||||
|
// Same as above but also allow self-reblogs
|
||||||
|
(reblog && reblog.user.id === this.profileUserId)
|
||||||
|
)
|
||||||
|
) ||
|
||||||
|
// Don't mute statuses in muted conversation when said conversation is opened
|
||||||
|
(this.inConversation && status.thread_muted)
|
||||||
|
// No excuses if post has muted words
|
||||||
|
) && !this.muteWordHits.length > 0
|
||||||
|
|
||||||
|
return !this.unmuted && !excusesNotToMute && reasonsToMute
|
||||||
},
|
},
|
||||||
hideFilteredStatuses () {
|
hideFilteredStatuses () {
|
||||||
return this.mergedConfig.hideFilteredStatuses
|
return this.mergedConfig.hideFilteredStatuses
|
||||||
|
|
|
@ -17,12 +17,33 @@
|
||||||
</div>
|
</div>
|
||||||
<template v-if="muted && !isPreview">
|
<template v-if="muted && !isPreview">
|
||||||
<div class="media status container muted">
|
<div class="media status container muted">
|
||||||
<small>
|
<small class="username">
|
||||||
|
<i
|
||||||
|
v-if="muted && retweet"
|
||||||
|
class="button-icon icon-retweet"
|
||||||
|
/>
|
||||||
<router-link :to="userProfileLink">
|
<router-link :to="userProfileLink">
|
||||||
{{ status.user.screen_name }}
|
{{ status.user.screen_name }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</small>
|
</small>
|
||||||
<small class="muteWords">{{ muteWordHits.join(', ') }}</small>
|
<small
|
||||||
|
v-if="showReasonMutedThread"
|
||||||
|
class="mute-thread"
|
||||||
|
>
|
||||||
|
{{ $t('status.thread_muted') }}
|
||||||
|
</small>
|
||||||
|
<small
|
||||||
|
v-if="showReasonMutedThread && muteWordHits.length > 0"
|
||||||
|
class="mute-thread"
|
||||||
|
>
|
||||||
|
{{ $t('status.thread_muted_and_words') }}
|
||||||
|
</small>
|
||||||
|
<small
|
||||||
|
class="mute-words"
|
||||||
|
:title="muteWordHits.join(', ')"
|
||||||
|
>
|
||||||
|
{{ muteWordHits.join(', ') }}
|
||||||
|
</small>
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="unmute"
|
class="unmute"
|
||||||
|
@ -637,19 +658,48 @@ $status-margin: 0.75em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.muted {
|
.muted {
|
||||||
padding: 0.25em 0.5em;
|
padding: .25em .6em;
|
||||||
button {
|
height: 1.2em;
|
||||||
|
line-height: 1.2em;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
|
||||||
|
.username, .mute-thread, .mute-words {
|
||||||
|
word-wrap: normal;
|
||||||
|
word-break: normal;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username, .mute-words {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
margin-right: .2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mute-thread {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mute-words {
|
||||||
|
flex: 1 0 5em;
|
||||||
|
margin-left: .2em;
|
||||||
|
&::before {
|
||||||
|
content: ' '
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.unmute {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
margin-left: auto;
|
||||||
|
display: block;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.muteWords {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a.unmute {
|
|
||||||
display: block;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-body {
|
.reply-body {
|
||||||
|
|
|
@ -621,7 +621,9 @@
|
||||||
"mute_conversation": "Mute conversation",
|
"mute_conversation": "Mute conversation",
|
||||||
"unmute_conversation": "Unmute conversation",
|
"unmute_conversation": "Unmute conversation",
|
||||||
"status_unavailable": "Status unavailable",
|
"status_unavailable": "Status unavailable",
|
||||||
"copy_link": "Copy link to status"
|
"copy_link": "Copy link to status",
|
||||||
|
"thread_muted": "Thread muted",
|
||||||
|
"thread_muted_and_words": ", has words:"
|
||||||
},
|
},
|
||||||
"user_card": {
|
"user_card": {
|
||||||
"approve": "Approve",
|
"approve": "Approve",
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {
|
||||||
import { set } from 'vue'
|
import { set } from 'vue'
|
||||||
import { isStatusNotification } from '../services/notification_utils/notification_utils.js'
|
import { isStatusNotification } from '../services/notification_utils/notification_utils.js'
|
||||||
import apiService from '../services/api/api.service.js'
|
import apiService from '../services/api/api.service.js'
|
||||||
// import parse from '../services/status_parser/status_parser.js'
|
import { muteWordHits } from '../services/status_parser/status_parser.js'
|
||||||
|
|
||||||
const emptyTl = (userId = 0) => ({
|
const emptyTl = (userId = 0) => ({
|
||||||
statuses: [],
|
statuses: [],
|
||||||
|
@ -381,7 +381,18 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
|
||||||
notifObj.image = status.attachments[0].url
|
notifObj.image = status.attachments[0].url
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!notification.seen && !state.notifications.desktopNotificationSilence && visibleNotificationTypes.includes(notification.type)) {
|
const reasonsToMuteNotif = (
|
||||||
|
notification.seen ||
|
||||||
|
state.notifications.desktopNotificationSilence ||
|
||||||
|
!visibleNotificationTypes.includes(notification.type) ||
|
||||||
|
(
|
||||||
|
notification.type === 'mention' && status && (
|
||||||
|
status.muted ||
|
||||||
|
muteWordHits(status, rootGetters.mergedConfig.muteWords).length === 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (!reasonsToMuteNotif) {
|
||||||
let desktopNotification = new window.Notification(title, notifObj)
|
let desktopNotification = new window.Notification(title, notifObj)
|
||||||
// Chrome is known for not closing notifications automatically
|
// Chrome is known for not closing notifications automatically
|
||||||
// according to MDN, anyway.
|
// according to MDN, anyway.
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { filter } from 'lodash'
|
||||||
import sanitize from 'sanitize-html'
|
import sanitize from 'sanitize-html'
|
||||||
|
|
||||||
export const removeAttachmentLinks = (html) => {
|
export const removeAttachmentLinks = (html) => {
|
||||||
|
@ -12,4 +13,14 @@ export const parse = (html) => {
|
||||||
return removeAttachmentLinks(html)
|
return removeAttachmentLinks(html)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const muteWordHits = (status, muteWords) => {
|
||||||
|
const statusText = status.text.toLowerCase()
|
||||||
|
const statusSummary = status.summary.toLowerCase()
|
||||||
|
const hits = filter(muteWords, (muteWord) => {
|
||||||
|
return statusText.includes(muteWord.toLowerCase()) || statusSummary.includes(muteWord.toLowerCase())
|
||||||
|
})
|
||||||
|
|
||||||
|
return hits
|
||||||
|
}
|
||||||
|
|
||||||
export default parse
|
export default parse
|
||||||
|
|
Loading…
Reference in a new issue