aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/components/status/status.vue24
-rw-r--r--src/components/user_card/user_card.vue1
-rw-r--r--src/modules/api.js2
-rw-r--r--src/modules/chats.js15
-rw-r--r--src/modules/statuses.js47
-rw-r--r--src/services/chat_utils/chat_utils.js19
-rw-r--r--src/services/desktop_notification_utils/desktop_notification_utils.js9
-rw-r--r--src/services/entity_normalizer/entity_normalizer.service.js1
-rw-r--r--src/services/notification_utils/notification_utils.js40
-rw-r--r--src/services/notifications_fetcher/notifications_fetcher.service.js2
-rw-r--r--src/services/timeline_fetcher/timeline_fetcher.service.js4
11 files changed, 111 insertions, 53 deletions
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 4764f467..e1e56ec9 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -72,7 +72,10 @@
:user="statusoid.user"
/>
<div class="media-body faint">
- <span class="user-name">
+ <span
+ class="user-name"
+ :title="retweeter"
+ >
<router-link
v-if="retweeterHtml"
:to="retweeterProfileLink"
@@ -129,20 +132,28 @@
<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>
<router-link
class="account-name"
+ :title="status.user.screen_name"
:to="userProfileLink"
>
{{ status.user.screen_name }}
</router-link>
+ <img
+ class="status-favicon"
+ v-if="!!(status.user && status.user.favicon)"
+ :src="status.user.favicon"
+ >
</div>
<span class="heading-right">
@@ -222,7 +233,10 @@
>
<span class="reply-to-text">{{ $t('status.reply_to') }}</span>
</span>
- <router-link :to="replyProfileLink">
+ <router-link
+ :title="replyToName"
+ :to="replyProfileLink"
+ >
{{ replyToName }}
</router-link>
<span
@@ -434,6 +448,12 @@ $status-margin: 0.75em;
}
}
+ .status-favicon {
+ height: 18px;
+ width: 18px;
+ margin-right: 0.4em;
+ }
+
.media-heading {
padding: 0;
vertical-align: bottom;
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index 9529d7f6..75db5db1 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -66,6 +66,7 @@
<div class="bottom-line">
<router-link
class="user-screen-name"
+ :title="user.screen_name"
:to="userProfileLink(user)"
>
@{{ user.screen_name }}
diff --git a/src/modules/api.js b/src/modules/api.js
index 68402602..5e213f0d 100644
--- a/src/modules/api.js
+++ b/src/modules/api.js
@@ -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)
}
}
)
diff --git a/src/modules/chats.js b/src/modules/chats.js
index 228d6256..c7609018 100644
--- a/src/modules/chats.js
+++ b/src/modules/chats.js
@@ -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)
diff --git a/src/modules/statuses.js b/src/modules/statuses.js
index 64f5b587..e108b2a7 100644
--- a/src/modules/statuses.js
+++ b/src/modules/statuses.js
@@ -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 })
diff --git a/src/services/chat_utils/chat_utils.js b/src/services/chat_utils/chat_utils.js
new file mode 100644
index 00000000..ab898ced
--- /dev/null
+++ b/src/services/chat_utils/chat_utils.js
@@ -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)
+}
diff --git a/src/services/desktop_notification_utils/desktop_notification_utils.js b/src/services/desktop_notification_utils/desktop_notification_utils.js
new file mode 100644
index 00000000..b84a1f75
--- /dev/null
+++ b/src/services/desktop_notification_utils/desktop_notification_utils.js
@@ -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)
+}
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index 7ea8a16c..c1bf8535 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -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) {
diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js
index 5cc19215..d912d19f 100644
--- a/src/services/notification_utils/notification_utils.js
+++ b/src/services/notification_utils/notification_utils.js
@@ -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)
diff --git a/src/services/notifications_fetcher/notifications_fetcher.service.js b/src/services/notifications_fetcher/notifications_fetcher.service.js
index d282074a..80be02ca 100644
--- a/src/services/notifications_fetcher/notifications_fetcher.service.js
+++ b/src/services/notifications_fetcher/notifications_fetcher.service.js
@@ -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 })
}
diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js
index 214294eb..d0cddf84 100644
--- a/src/services/timeline_fetcher/timeline_fetcher.service.js
+++ b/src/services/timeline_fetcher/timeline_fetcher.service.js
@@ -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