fix minor bugs, preliminary support for status mention previews
This commit is contained in:
commit
cebf4989e7
|
@ -8,6 +8,7 @@
|
|||
>
|
||||
<UserAvatar
|
||||
:user="user"
|
||||
no-popover="true"
|
||||
class="avatar-small"
|
||||
/>
|
||||
</router-link>
|
||||
|
|
|
@ -18,6 +18,8 @@ const Popover = {
|
|||
// Takes a x/y object and tells how many pixels to offset from
|
||||
// anchor point on either axis
|
||||
offset: Object,
|
||||
// Takes an element to use for positioning over this.$el
|
||||
offsetElement: null,
|
||||
// Additional styles you may want for the popover container
|
||||
popoverClass: String,
|
||||
// Time in milliseconds until the popup appears, default is 100ms
|
||||
|
@ -47,7 +49,9 @@ const Popover = {
|
|||
// Popover will be anchored around this element, trigger ref is the container, so
|
||||
// its children are what are inside the slot. Expect only one slot="trigger".
|
||||
const anchorEl = (this.$refs.trigger && this.$refs.trigger.children[0]) || this.$el
|
||||
const screenBox = anchorEl.getBoundingClientRect()
|
||||
const positionElement = this.offsetElement ? this.offsetElement : anchorEl
|
||||
const screenBox = positionElement.getBoundingClientRect()
|
||||
console.log(positionElement, screenBox)
|
||||
// Screen position of the origin point for popover
|
||||
const origin = { x: screenBox.left + screenBox.width * 0.5, y: screenBox.top }
|
||||
const content = this.$refs.content
|
||||
|
@ -99,11 +103,11 @@ const Popover = {
|
|||
|
||||
const yOffset = (this.offset && this.offset.y) || 0
|
||||
const translateY = usingTop
|
||||
? -anchorEl.offsetHeight - yOffset - content.offsetHeight
|
||||
? -positionElement.offsetHeight - yOffset - content.offsetHeight
|
||||
: yOffset
|
||||
|
||||
const xOffset = (this.offset && this.offset.x) || 0
|
||||
const translateX = (anchorEl.offsetWidth * 0.5) - content.offsetWidth * 0.5 + horizOffset + xOffset
|
||||
const translateX = (positionElement.offsetWidth * 0.5) - content.offsetWidth * 0.5 + horizOffset + xOffset
|
||||
|
||||
// Note, separate translateX and translateY avoids blurry text on chromium,
|
||||
// single translate or translate3d resulted in blurry text.
|
||||
|
|
|
@ -74,7 +74,10 @@
|
|||
:user="statusoid.user"
|
||||
/>
|
||||
<div class="media-body faint">
|
||||
<span class="user-name">
|
||||
<span
|
||||
class="user-name"
|
||||
:title="retweeter"
|
||||
>
|
||||
<UserPopover :user-id="statusoid.user.id">
|
||||
<router-link
|
||||
v-if="retweeterHtml"
|
||||
|
@ -86,6 +89,7 @@
|
|||
:to="retweeterProfileLink"
|
||||
>{{ retweeter }}</router-link>
|
||||
</UserPopover>
|
||||
|
||||
</span>
|
||||
<i
|
||||
class="fa icon-retweet retweeted"
|
||||
|
@ -123,11 +127,13 @@
|
|||
<h4
|
||||
v-if="status.user.name_html"
|
||||
class="user-name"
|
||||
:title="status.user.name"
|
||||
v-html="status.user.name_html"
|
||||
/>
|
||||
<h4
|
||||
v-else
|
||||
class="user-name"
|
||||
:title="status.user.name"
|
||||
>
|
||||
{{ status.user.name }}
|
||||
</h4>
|
||||
|
@ -137,11 +143,17 @@
|
|||
>
|
||||
<router-link
|
||||
class="account-name"
|
||||
:title="status.user.screen_name"
|
||||
:to="userProfileLink"
|
||||
>
|
||||
{{ status.user.screen_name }}
|
||||
</router-link>
|
||||
</UserPopover>
|
||||
<img
|
||||
v-if="!!(status.user && status.user.favicon)"
|
||||
class="status-favicon"
|
||||
:src="status.user.favicon"
|
||||
>
|
||||
</div>
|
||||
|
||||
<span class="heading-right">
|
||||
|
@ -225,8 +237,9 @@
|
|||
:user-id="status.in_reply_to_user_id"
|
||||
>
|
||||
<router-link
|
||||
:to="replyProfileLink"
|
||||
class="reply-to-accountname"
|
||||
:title="replyToName"
|
||||
:to="replyProfileLink"
|
||||
>
|
||||
{{ replyToName }}
|
||||
</router-link>
|
||||
|
@ -434,6 +447,12 @@ $status-margin: 0.75em;
|
|||
}
|
||||
}
|
||||
|
||||
.status-favicon {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
margin-right: 0.4em;
|
||||
}
|
||||
|
||||
.media-heading {
|
||||
padding: 0;
|
||||
vertical-align: bottom;
|
||||
|
|
|
@ -2,6 +2,7 @@ import Attachment from '../attachment/attachment.vue'
|
|||
import Poll from '../poll/poll.vue'
|
||||
import Gallery from '../gallery/gallery.vue'
|
||||
import LinkPreview from '../link-preview/link-preview.vue'
|
||||
import UserPopover from '../user_popover/user_popover.vue'
|
||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||
import fileType from 'src/services/file_type/file_type.service'
|
||||
import { processHtml } from 'src/services/tiny_post_html_processor/tiny_post_html_processor.service.js'
|
||||
|
@ -10,6 +11,13 @@ import { mapGetters, mapState } from 'vuex'
|
|||
|
||||
const StatusContent = {
|
||||
name: 'StatusContent',
|
||||
components: {
|
||||
Attachment,
|
||||
Poll,
|
||||
Gallery,
|
||||
LinkPreview,
|
||||
UserPopover
|
||||
},
|
||||
props: [
|
||||
'status',
|
||||
'focused',
|
||||
|
@ -22,7 +30,9 @@ const StatusContent = {
|
|||
showingTall: this.fullContent || (this.inConversation && this.focused),
|
||||
showingLongSubject: false,
|
||||
// not as computed because it sets the initial state which will be changed later
|
||||
expandingSubject: !this.$store.getters.mergedConfig.collapseMessageWithSubject
|
||||
expandingSubject: !this.$store.getters.mergedConfig.collapseMessageWithSubject,
|
||||
focusedUserId: null,
|
||||
focusedUserElement: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -142,12 +152,6 @@ const StatusContent = {
|
|||
currentUser: state => state.users.currentUser
|
||||
})
|
||||
},
|
||||
components: {
|
||||
Attachment,
|
||||
Poll,
|
||||
Gallery,
|
||||
LinkPreview
|
||||
},
|
||||
methods: {
|
||||
linkClicked (event) {
|
||||
const target = event.target.closest('.status-content a')
|
||||
|
@ -175,6 +179,22 @@ const StatusContent = {
|
|||
window.open(target.href, '_blank')
|
||||
}
|
||||
},
|
||||
linkHover (event) {
|
||||
const target = event.target.closest('.status-content a')
|
||||
this.focusedUserId = null
|
||||
if (target) {
|
||||
if (target.className.match(/mention/)) {
|
||||
const href = target.href
|
||||
const attn = this.status.attentions.find(attn => mentionMatchesUrl(attn, href))
|
||||
if (attn) {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
this.focusedUserId = attn.id
|
||||
this.focusedUserElement = target
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
toggleShowMore () {
|
||||
if (this.mightHideBecauseTall) {
|
||||
this.showingTall = !this.showingTall
|
||||
|
|
|
@ -28,63 +28,68 @@
|
|||
{{ $t("status.show_full_subject") }}
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
:class="{'tall-status': hideTallStatus}"
|
||||
class="status-content-wrapper"
|
||||
<UserPopover
|
||||
:user-id="focusedUserId"
|
||||
>
|
||||
<a
|
||||
v-if="hideTallStatus"
|
||||
class="tall-status-hider"
|
||||
:class="{ 'tall-status-hider_focused': focused }"
|
||||
href="#"
|
||||
@click.prevent="toggleShowMore"
|
||||
>
|
||||
{{ $t("general.show_more") }}
|
||||
</a>
|
||||
<div
|
||||
v-if="!hideSubjectStatus"
|
||||
:class="{ 'single-line': singleLine }"
|
||||
class="status-content media-body"
|
||||
@click.prevent="linkClicked"
|
||||
v-html="postBodyHtml"
|
||||
/>
|
||||
<a
|
||||
v-if="hideSubjectStatus"
|
||||
href="#"
|
||||
class="cw-status-hider"
|
||||
@click.prevent="toggleShowMore"
|
||||
:class="{'tall-status': hideTallStatus}"
|
||||
class="status-content-wrapper"
|
||||
>
|
||||
{{ $t("status.show_content") }}
|
||||
<span
|
||||
v-if="attachmentTypes.includes('image')"
|
||||
class="icon-picture"
|
||||
<a
|
||||
v-if="hideTallStatus"
|
||||
class="tall-status-hider"
|
||||
:class="{ 'tall-status-hider_focused': focused }"
|
||||
href="#"
|
||||
@click.prevent="toggleShowMore"
|
||||
>
|
||||
{{ $t("general.show_more") }}
|
||||
</a>
|
||||
<div
|
||||
v-if="!hideSubjectStatus"
|
||||
:class="{ 'single-line': singleLine }"
|
||||
class="status-content media-body"
|
||||
@click.prevent="linkClicked"
|
||||
@mouseover="linkHover"
|
||||
v-html="postBodyHtml"
|
||||
/>
|
||||
<span
|
||||
v-if="attachmentTypes.includes('video')"
|
||||
class="icon-video"
|
||||
/>
|
||||
<span
|
||||
v-if="attachmentTypes.includes('audio')"
|
||||
class="icon-music"
|
||||
/>
|
||||
<span
|
||||
v-if="attachmentTypes.includes('unknown')"
|
||||
class="icon-doc"
|
||||
/>
|
||||
<span
|
||||
v-if="status.card"
|
||||
class="icon-link"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
v-if="showingMore && !fullContent"
|
||||
href="#"
|
||||
class="status-unhider"
|
||||
@click.prevent="toggleShowMore"
|
||||
>
|
||||
{{ tallStatus ? $t("general.show_less") : $t("status.hide_content") }}
|
||||
</a>
|
||||
</div>
|
||||
<a
|
||||
v-if="hideSubjectStatus"
|
||||
href="#"
|
||||
class="cw-status-hider"
|
||||
@click.prevent="toggleShowMore"
|
||||
>
|
||||
{{ $t("status.show_content") }}
|
||||
<span
|
||||
v-if="attachmentTypes.includes('image')"
|
||||
class="icon-picture"
|
||||
/>
|
||||
<span
|
||||
v-if="attachmentTypes.includes('video')"
|
||||
class="icon-video"
|
||||
/>
|
||||
<span
|
||||
v-if="attachmentTypes.includes('audio')"
|
||||
class="icon-music"
|
||||
/>
|
||||
<span
|
||||
v-if="attachmentTypes.includes('unknown')"
|
||||
class="icon-doc"
|
||||
/>
|
||||
<span
|
||||
v-if="status.card"
|
||||
class="icon-link"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
v-if="showingMore && !fullContent"
|
||||
href="#"
|
||||
class="status-unhider"
|
||||
@click.prevent="toggleShowMore"
|
||||
>
|
||||
{{ tallStatus ? $t("general.show_less") : $t("status.hide_content") }}
|
||||
</a>
|
||||
</div>
|
||||
</UserPopover>
|
||||
|
||||
<div v-if="status.poll && status.poll.options">
|
||||
<poll :base-poll="status.poll" />
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
<div class="bottom-line">
|
||||
<router-link
|
||||
class="user-screen-name"
|
||||
:title="user.screen_name"
|
||||
:to="userProfileLink(user)"
|
||||
>
|
||||
@{{ user.screen_name }}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
const UserPopover = {
|
||||
name: 'UserPopover',
|
||||
props: [
|
||||
'userId'
|
||||
'userId',
|
||||
'focusedElement'
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<template>
|
||||
<Popover
|
||||
v-if="userId"
|
||||
class="user-popover-container"
|
||||
trigger="hover"
|
||||
popover-class="user-popover"
|
||||
:bound-to="{ x: 'container' }"
|
||||
:delay="200"
|
||||
:offset-element="focusedElement"
|
||||
@show="enter"
|
||||
>
|
||||
<template slot="trigger">
|
||||
|
@ -34,6 +36,12 @@
|
|||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
<div
|
||||
v-else
|
||||
class="user-popover-container"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./user_popover.js" ></script>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
|
||||
import { WSConnectionStatus } from '../services/api/api.service.js'
|
||||
import { maybeShowChatNotification } from '../services/chat_utils/chat_utils.js'
|
||||
import { Socket } from 'phoenix'
|
||||
|
||||
const api = {
|
||||
|
@ -77,6 +78,7 @@ const api = {
|
|||
messages: [message.chatUpdate.lastMessage]
|
||||
})
|
||||
dispatch('updateChat', { chat: message.chatUpdate })
|
||||
maybeShowChatNotification(store, message.chatUpdate)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -2,6 +2,7 @@ import Vue from 'vue'
|
|||
import { find, omitBy, orderBy, sumBy } from 'lodash'
|
||||
import chatService from '../services/chat_service/chat_service.js'
|
||||
import { parseChat, parseChatMessage } from '../services/entity_normalizer/entity_normalizer.service.js'
|
||||
import { maybeShowChatNotification } from '../services/chat_utils/chat_utils.js'
|
||||
|
||||
const emptyChatList = () => ({
|
||||
data: [],
|
||||
|
@ -59,8 +60,12 @@ const chats = {
|
|||
return chats
|
||||
})
|
||||
},
|
||||
addNewChats ({ rootState, commit, dispatch, rootGetters }, { chats }) {
|
||||
commit('addNewChats', { dispatch, chats, rootGetters })
|
||||
addNewChats (store, { chats }) {
|
||||
const { commit, dispatch, rootGetters } = store
|
||||
const newChatMessageSideEffects = (chat) => {
|
||||
maybeShowChatNotification(store, chat)
|
||||
}
|
||||
commit('addNewChats', { dispatch, chats, rootGetters, newChatMessageSideEffects })
|
||||
},
|
||||
updateChat ({ commit }, { chat }) {
|
||||
commit('updateChat', { chat })
|
||||
|
@ -130,13 +135,17 @@ const chats = {
|
|||
setCurrentChatId (state, { chatId }) {
|
||||
state.currentChatId = chatId
|
||||
},
|
||||
addNewChats (state, { _dispatch, chats, _rootGetters }) {
|
||||
addNewChats (state, { chats, newChatMessageSideEffects }) {
|
||||
chats.forEach((updatedChat) => {
|
||||
const chat = getChatById(state, updatedChat.id)
|
||||
|
||||
if (chat) {
|
||||
const isNewMessage = (chat.lastMessage && chat.lastMessage.id) !== (updatedChat.lastMessage && updatedChat.lastMessage.id)
|
||||
chat.lastMessage = updatedChat.lastMessage
|
||||
chat.unread = updatedChat.unread
|
||||
if (isNewMessage && chat.unread) {
|
||||
newChatMessageSideEffects(updatedChat)
|
||||
}
|
||||
} else {
|
||||
state.chatList.data.push(updatedChat)
|
||||
Vue.set(state.chatList.idStore, updatedChat.id, updatedChat)
|
||||
|
|
|
@ -13,9 +13,8 @@ import {
|
|||
omitBy
|
||||
} from 'lodash'
|
||||
import { set } from 'vue'
|
||||
import { isStatusNotification, prepareNotificationObject } from '../services/notification_utils/notification_utils.js'
|
||||
import { isStatusNotification, maybeShowNotification } from '../services/notification_utils/notification_utils.js'
|
||||
import apiService from '../services/api/api.service.js'
|
||||
import { muteWordHits } from '../services/status_parser/status_parser.js'
|
||||
|
||||
const emptyTl = (userId = 0) => ({
|
||||
statuses: [],
|
||||
|
@ -77,17 +76,6 @@ export const prepareStatus = (status) => {
|
|||
return status
|
||||
}
|
||||
|
||||
const visibleNotificationTypes = (rootState) => {
|
||||
return [
|
||||
rootState.config.notificationVisibility.likes && 'like',
|
||||
rootState.config.notificationVisibility.mentions && 'mention',
|
||||
rootState.config.notificationVisibility.repeats && 'repeat',
|
||||
rootState.config.notificationVisibility.follows && 'follow',
|
||||
rootState.config.notificationVisibility.moves && 'move',
|
||||
rootState.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reactions'
|
||||
].filter(_ => _)
|
||||
}
|
||||
|
||||
const mergeOrAdd = (arr, obj, item) => {
|
||||
const oldItem = obj[item.id]
|
||||
|
||||
|
@ -325,7 +313,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
|
|||
}
|
||||
}
|
||||
|
||||
const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters }) => {
|
||||
const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters, newNotificationSideEffects }) => {
|
||||
each(notifications, (notification) => {
|
||||
if (isStatusNotification(notification.type)) {
|
||||
notification.action = addStatusToGlobalStorage(state, notification.action).item
|
||||
|
@ -348,27 +336,7 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
|
|||
state.notifications.data.push(notification)
|
||||
state.notifications.idStore[notification.id] = notification
|
||||
|
||||
if ('Notification' in window && window.Notification.permission === 'granted') {
|
||||
const notifObj = prepareNotificationObject(notification, rootGetters.i18n)
|
||||
|
||||
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(notifObj.title, notifObj)
|
||||
// Chrome is known for not closing notifications automatically
|
||||
// according to MDN, anyway.
|
||||
setTimeout(desktopNotification.close.bind(desktopNotification), 5000)
|
||||
}
|
||||
}
|
||||
newNotificationSideEffects(notification)
|
||||
} else if (notification.seen) {
|
||||
state.notifications.idStore[notification.id].seen = true
|
||||
}
|
||||
|
@ -609,8 +577,13 @@ const statuses = {
|
|||
addNewStatuses ({ rootState, commit }, { statuses, showImmediately = false, timeline = false, noIdUpdate = false, userId, pagination }) {
|
||||
commit('addNewStatuses', { statuses, showImmediately, timeline, noIdUpdate, user: rootState.users.currentUser, userId, pagination })
|
||||
},
|
||||
addNewNotifications ({ rootState, commit, dispatch, rootGetters }, { notifications, older }) {
|
||||
commit('addNewNotifications', { visibleNotificationTypes: visibleNotificationTypes(rootState), dispatch, notifications, older, rootGetters })
|
||||
addNewNotifications (store, { notifications, older }) {
|
||||
const { commit, dispatch, rootGetters } = store
|
||||
|
||||
const newNotificationSideEffects = (notification) => {
|
||||
maybeShowNotification(store, notification)
|
||||
}
|
||||
commit('addNewNotifications', { dispatch, notifications, older, rootGetters, newNotificationSideEffects })
|
||||
},
|
||||
setError ({ rootState, commit }, { value }) {
|
||||
commit('setError', { value })
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import { showDesktopNotification } from '../desktop_notification_utils/desktop_notification_utils.js'
|
||||
|
||||
export const maybeShowChatNotification = (store, chat) => {
|
||||
if (!chat.lastMessage) return
|
||||
if (store.rootState.chats.currentChatId === chat.id && !document.hidden) return
|
||||
|
||||
const opts = {
|
||||
tag: chat.lastMessage.id,
|
||||
title: chat.account.name,
|
||||
icon: chat.account.profile_image_url,
|
||||
body: chat.lastMessage.content
|
||||
}
|
||||
|
||||
if (chat.lastMessage.attachment && chat.lastMessage.attachment.type === 'image') {
|
||||
opts.image = chat.lastMessage.attachment.preview_url
|
||||
}
|
||||
|
||||
showDesktopNotification(store.rootState, opts)
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
export const showDesktopNotification = (rootState, desktopNotificationOpts) => {
|
||||
if (!('Notification' in window && window.Notification.permission === 'granted')) return
|
||||
if (rootState.statuses.notifications.desktopNotificationSilence) { return }
|
||||
|
||||
const desktopNotification = new window.Notification(desktopNotificationOpts.title, desktopNotificationOpts)
|
||||
// Chrome is known for not closing notifications automatically
|
||||
// according to MDN, anyway.
|
||||
setTimeout(desktopNotification.close.bind(desktopNotification), 5000)
|
||||
}
|
|
@ -79,6 +79,7 @@ export const parseUser = (data) => {
|
|||
const relationship = data.pleroma.relationship
|
||||
|
||||
output.background_image = data.pleroma.background_image
|
||||
output.favicon = data.pleroma.favicon
|
||||
output.token = data.pleroma.chat_token
|
||||
|
||||
if (relationship) {
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
import { filter, sortBy, includes } from 'lodash'
|
||||
import { muteWordHits } from '../status_parser/status_parser.js'
|
||||
import { showDesktopNotification } from '../desktop_notification_utils/desktop_notification_utils.js'
|
||||
|
||||
export const notificationsFromStore = store => store.state.statuses.notifications.data
|
||||
|
||||
export const visibleTypes = store => ([
|
||||
store.state.config.notificationVisibility.likes && 'like',
|
||||
store.state.config.notificationVisibility.mentions && 'mention',
|
||||
store.state.config.notificationVisibility.repeats && 'repeat',
|
||||
store.state.config.notificationVisibility.follows && 'follow',
|
||||
store.state.config.notificationVisibility.followRequest && 'follow_request',
|
||||
store.state.config.notificationVisibility.moves && 'move',
|
||||
store.state.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction'
|
||||
].filter(_ => _))
|
||||
export const visibleTypes = store => {
|
||||
const rootState = store.rootState || store.state
|
||||
|
||||
return ([
|
||||
rootState.config.notificationVisibility.likes && 'like',
|
||||
rootState.config.notificationVisibility.mentions && 'mention',
|
||||
rootState.config.notificationVisibility.repeats && 'repeat',
|
||||
rootState.config.notificationVisibility.follows && 'follow',
|
||||
rootState.config.notificationVisibility.followRequest && 'follow_request',
|
||||
rootState.config.notificationVisibility.moves && 'move',
|
||||
rootState.config.notificationVisibility.emojiReactions && 'pleroma:emoji_reaction'
|
||||
].filter(_ => _))
|
||||
}
|
||||
|
||||
const statusNotifications = ['like', 'mention', 'repeat', 'pleroma:emoji_reaction']
|
||||
|
||||
|
@ -32,6 +38,22 @@ const sortById = (a, b) => {
|
|||
}
|
||||
}
|
||||
|
||||
const isMutedNotification = (store, notification) => {
|
||||
if (!notification.status) return
|
||||
return notification.status.muted || muteWordHits(notification.status, store.rootGetters.mergedConfig.muteWords).length > 0
|
||||
}
|
||||
|
||||
export const maybeShowNotification = (store, notification) => {
|
||||
const rootState = store.rootState || store.state
|
||||
|
||||
if (notification.seen) return
|
||||
if (!visibleTypes(store).includes(notification.type)) return
|
||||
if (notification.type === 'mention' && isMutedNotification(store, notification)) return
|
||||
|
||||
const notificationObject = prepareNotificationObject(notification, store.rootGetters.i18n)
|
||||
showDesktopNotification(rootState, notificationObject)
|
||||
}
|
||||
|
||||
export const filteredNotificationsFromStore = (store, types) => {
|
||||
// map is just to clone the array since sort mutates it and it causes some issues
|
||||
let sortedNotifications = notificationsFromStore(store).map(_ => _).sort(sortById)
|
||||
|
|
|
@ -35,7 +35,7 @@ const fetchAndUpdate = ({ store, credentials, older = false }) => {
|
|||
const notifications = timelineData.data
|
||||
const readNotifsIds = notifications.filter(n => n.seen).map(n => n.id)
|
||||
const numUnseenNotifs = notifications.length - readNotifsIds.length
|
||||
if (numUnseenNotifs > 0) {
|
||||
if (numUnseenNotifs > 0 && readNotifsIds.length > 0) {
|
||||
args['since'] = Math.max(...readNotifsIds)
|
||||
fetchNotifications({ store, args, older })
|
||||
}
|
||||
|
|
|
@ -43,7 +43,9 @@ const fetchAndUpdate = ({
|
|||
args['userId'] = userId
|
||||
args['tag'] = tag
|
||||
args['withMuted'] = !hideMutedPosts
|
||||
if (loggedIn) args['replyVisibility'] = replyVisibility
|
||||
if (loggedIn && ['friends', 'public', 'publicAndExternal'].includes(timeline)) {
|
||||
args['replyVisibility'] = replyVisibility
|
||||
}
|
||||
|
||||
const numStatusesBeforeFetch = timelineData.statuses.length
|
||||
|
||||
|
|
Loading…
Reference in New Issue