Notifications: Use notifications natively.

This commit is contained in:
lain 2020-06-25 16:06:17 +02:00
parent 7d5c3e5db0
commit 145b4e1e52
8 changed files with 76 additions and 109 deletions

View file

@ -22,7 +22,7 @@ const FollowRequestCard = {
this.$store.dispatch('updateNotification', { this.$store.dispatch('updateNotification', {
id: notifId, id: notifId,
updater: notification => { updater: notification => {
notification.redux.type = 'follow' notification.type = 'follow'
} }
}) })
}, },

View file

@ -31,7 +31,7 @@ const Notification = {
return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames) return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
}, },
getUser (notification) { getUser (notification) {
return this.$store.state.users.usersObject[notification.redux.account.id] return this.$store.state.users.usersObject[notification.account.id]
}, },
toggleMute () { toggleMute () {
this.unmuted = !this.unmuted this.unmuted = !this.unmuted
@ -39,39 +39,39 @@ const Notification = {
approveUser () { approveUser () {
this.$store.state.api.backendInteractor.approveUser({ id: this.user.id }) this.$store.state.api.backendInteractor.approveUser({ id: this.user.id })
this.$store.dispatch('removeFollowRequest', this.user) this.$store.dispatch('removeFollowRequest', this.user)
this.$store.dispatch('markSingleNotificationAsSeen', { id: this.notification.redux.id }) this.$store.dispatch('markSingleNotificationAsSeen', { id: this.notification.id })
this.$store.dispatch('updateNotification', { this.$store.dispatch('updateNotification', {
id: this.notification.redux.id, id: this.notification.id,
updater: notification => { updater: notification => {
notification.redux.type = 'follow' notification.type = 'follow'
} }
}) })
}, },
denyUser () { denyUser () {
this.$store.state.api.backendInteractor.denyUser({ id: this.user.id }) this.$store.state.api.backendInteractor.denyUser({ id: this.user.id })
.then(() => { .then(() => {
this.$store.dispatch('dismissNotificationLocal', { id: this.notification.redux.id }) this.$store.dispatch('dismissNotificationLocal', { id: this.notification.id })
this.$store.dispatch('removeFollowRequest', this.user) this.$store.dispatch('removeFollowRequest', this.user)
}) })
} }
}, },
computed: { computed: {
userClass () { userClass () {
return highlightClass(this.notification.redux.account) return highlightClass(this.notification.account)
}, },
userStyle () { userStyle () {
const highlight = this.$store.getters.mergedConfig.highlight const highlight = this.$store.getters.mergedConfig.highlight
const user = this.notification.redux.account const user = this.notification.account
return highlightStyle(highlight[user.screen_name]) return highlightStyle(highlight[user.screen_name])
}, },
user () { user () {
return this.$store.getters.findUser(this.notification.redux.account.id) return this.$store.getters.findUser(this.notification.account.id)
}, },
userProfileLink () { userProfileLink () {
return this.generateUserProfileLink(this.user) return this.generateUserProfileLink(this.user)
}, },
targetUser () { targetUser () {
return this.$store.getters.findUser(this.notification.redux.target.id) return this.$store.getters.findUser(this.notification.target.id)
}, },
targetUserProfileLink () { targetUserProfileLink () {
return this.generateUserProfileLink(this.targetUser) return this.generateUserProfileLink(this.targetUser)
@ -80,7 +80,7 @@ const Notification = {
return this.$store.getters.relationship(this.user.id).muting return this.$store.getters.relationship(this.user.id).muting
}, },
isStatusNotification () { isStatusNotification () {
return (this.notification.redux.type) return (this.notification.type)
} }
} }
} }

View file

@ -1,8 +1,8 @@
<template> <template>
<status <status
v-if="notification.redux.type === 'mention'" v-if="notification.type === 'mention'"
:compact="true" :compact="true"
:statusoid="notification.redux.status" :statusoid="notification.status"
/> />
<div v-else> <div v-else>
<div <div
@ -11,7 +11,7 @@
> >
<small> <small>
<router-link :to="userProfileLink"> <router-link :to="userProfileLink">
{{ notification.redux.account.redux.acct }} {{ notification.account.redux.acct }}
</router-link> </router-link>
</small> </small>
<a <a
@ -28,13 +28,13 @@
> >
<a <a
class="avatar-container" class="avatar-container"
:href="notification.redux.account.redux.url" :href="notification.account.redux.url"
@click.stop.prevent.capture="toggleUserExpanded" @click.stop.prevent.capture="toggleUserExpanded"
> >
<UserAvatar <UserAvatar
:compact="true" :compact="true"
:better-shadow="betterShadow" :better-shadow="betterShadow"
:user="notification.redux.account" :user="notification.account"
/> />
</a> </a>
<div class="notification-right"> <div class="notification-right">
@ -48,44 +48,44 @@
<div class="name-and-action"> <div class="name-and-action">
<!-- eslint-disable vue/no-v-html --> <!-- eslint-disable vue/no-v-html -->
<bdi <bdi
v-if="!!notification.redux.account.name_html" v-if="!!notification.account.name_html"
class="username" class="username"
:title="'@'+notification.redux.account.screen_name" :title="'@'+notification.account.screen_name"
v-html="notification.redux.account.name_html" v-html="notification.account.name_html"
/> />
<!-- eslint-enable vue/no-v-html --> <!-- eslint-enable vue/no-v-html -->
<span <span
v-else v-else
class="username" class="username"
:title="'@'+notification.redux.account.redux.acct" :title="'@'+notification.account.redux.acct"
>{{ notification.redux.account.display_name }}</span> >{{ notification.account.display_name }}</span>
<span v-if="notification.redux.type === 'favourite'"> <span v-if="notification.type === 'favourite'">
<i class="fa icon-star lit" /> <i class="fa icon-star lit" />
<small>{{ $t('notifications.favorited_you') }}</small> <small>{{ $t('notifications.favorited_you') }}</small>
</span> </span>
<span v-if="notification.redux.type === 'reblog'"> <span v-if="notification.type === 'reblog'">
<i <i
class="fa icon-retweet lit" class="fa icon-retweet lit"
:title="$t('tool_tip.repeat')" :title="$t('tool_tip.repeat')"
/> />
<small>{{ $t('notifications.repeated_you') }}</small> <small>{{ $t('notifications.repeated_you') }}</small>
</span> </span>
<span v-if="notification.redux.type === 'follow'"> <span v-if="notification.type === 'follow'">
<i class="fa icon-user-plus lit" /> <i class="fa icon-user-plus lit" />
<small>{{ $t('notifications.followed_you') }}</small> <small>{{ $t('notifications.followed_you') }}</small>
</span> </span>
<span v-if="notification.redux.type === 'follow_request'"> <span v-if="notification.type === 'follow_request'">
<i class="fa icon-user lit" /> <i class="fa icon-user lit" />
<small>{{ $t('notifications.follow_request') }}</small> <small>{{ $t('notifications.follow_request') }}</small>
</span> </span>
<span v-if="notification.redux.type === 'move'"> <span v-if="notification.type === 'move'">
<i class="fa icon-arrow-curved lit" /> <i class="fa icon-arrow-curved lit" />
<small>{{ $t('notifications.migrated_to') }}</small> <small>{{ $t('notifications.migrated_to') }}</small>
</span> </span>
<span v-if="notification.redux.type === 'pleroma:emoji_reaction'"> <span v-if="notification.type === 'pleroma:emoji_reaction'">
<small> <small>
<i18n path="notifications.reacted_with"> <i18n path="notifications.reacted_with">
<span class="emoji-reaction-emoji">{{ notification.redux.emoji }}</span> <span class="emoji-reaction-emoji">{{ notification.emoji }}</span>
</i18n> </i18n>
</small> </small>
</span> </span>
@ -95,12 +95,12 @@
class="timeago" class="timeago"
> >
<router-link <router-link
v-if="notification.redux.status" v-if="notification.status"
:to="{ name: 'conversation', params: { id: notification.redux.status.id } }" :to="{ name: 'conversation', params: { id: notification.status.id } }"
class="faint-link" class="faint-link"
> >
<Timeago <Timeago
:time="notification.redux.created_at" :time="notification.created_at"
:auto-update="240" :auto-update="240"
/> />
</router-link> </router-link>
@ -111,7 +111,7 @@
> >
<span class="faint"> <span class="faint">
<Timeago <Timeago
:time="notification.redux.created_at" :time="notification.created_at"
:auto-update="240" :auto-update="240"
/> />
</span> </span>
@ -123,17 +123,17 @@
><i class="button-icon icon-eye-off" /></a> ><i class="button-icon icon-eye-off" /></a>
</span> </span>
<div <div
v-if="notification.redux.type === 'follow' || notification.redux.type === 'follow_request'" v-if="notification.type === 'follow' || notification.type === 'follow_request'"
class="follow-text" class="follow-text"
> >
<router-link <router-link
:to="userProfileLink" :to="userProfileLink"
class="follow-name" class="follow-name"
> >
@{{ notification.redux.account.redux.acct }} @{{ notification.account.redux.acct }}
</router-link> </router-link>
<div <div
v-if="notification.redux.type === 'follow_request'" v-if="notification.type === 'follow_request'"
style="white-space: nowrap;" style="white-space: nowrap;"
> >
<i <i
@ -149,17 +149,17 @@
</div> </div>
</div> </div>
<div <div
v-else-if="notification.redux.type === 'move'" v-else-if="notification.type === 'move'"
class="move-text" class="move-text"
> >
<router-link :to="targetUserProfileLink"> <router-link :to="targetUserProfileLink">
@{{ notification.redux.target.redux.acct }} @{{ notification.target.redux.acct }}
</router-link> </router-link>
</div> </div>
<template v-else> <template v-else>
<status-content <status-content
class="faint" class="faint"
:status="notification.redux.status" :status="notification.status"
/> />
</template> </template>
</div> </div>

View file

@ -33,9 +33,9 @@
<div class="panel-body"> <div class="panel-body">
<div <div
v-for="notification in notificationsToDisplay" v-for="notification in notificationsToDisplay"
:key="notification.redux.id" :key="notification.id"
class="notification" class="notification"
:class="{&quot;unseen&quot;: !minimalMode && !notification.redux.pleroma.is_seen}" :class="{&quot;unseen&quot;: !minimalMode && !notification.pleroma.is_seen}"
> >
<div class="notification-overlay" /> <div class="notification-overlay" />
<notification :notification="notification" /> <notification :notification="notification" />

View file

@ -311,35 +311,35 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters }) => { const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters }) => {
each(notifications, (notification) => { each(notifications, (notification) => {
if (isStatusNotification(notification.redux.type)) { if (isStatusNotification(notification.type)) {
notification.redux.status = notification.redux.status && addStatusToGlobalStorage(state, notification.redux.status).item notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item
} }
if (notification.redux.type === 'pleroma:emoji_reaction') { if (notification.type === 'pleroma:emoji_reaction') {
dispatch('fetchEmojiReactionsBy', notification.redux.status.id) dispatch('fetchEmojiReactionsBy', notification.status.id)
} }
// Only add a new notification if we don't have one for the same action // Only add a new notification if we don't have one for the same action
if (!state.notifications.idStore.hasOwnProperty(notification.redux.id)) { if (!state.notifications.idStore.hasOwnProperty(notification.id)) {
state.notifications.maxId = notification.redux.id > state.notifications.maxId state.notifications.maxId = notification.id > state.notifications.maxId
? notification.redux.id ? notification.id
: state.notifications.maxId : state.notifications.maxId
state.notifications.minId = notification.redux.id < state.notifications.minId state.notifications.minId = notification.id < state.notifications.minId
? notification.redux.id ? notification.id
: state.notifications.minId : state.notifications.minId
state.notifications.data.push(notification) state.notifications.data.push(notification)
state.notifications.idStore[notification.redux.id] = notification state.notifications.idStore[notification.id] = notification
if ('Notification' in window && window.Notification.permission === 'granted') { if ('Notification' in window && window.Notification.permission === 'granted') {
const notifObj = prepareNotificationObject(notification, rootGetters.i18n) const notifObj = prepareNotificationObject(notification, rootGetters.i18n)
const reasonsToMuteNotif = ( const reasonsToMuteNotif = (
notification.redux.pleroma.is_seen || notification.pleroma.is_seen ||
state.notifications.desktopNotificationSilence || state.notifications.desktopNotificationSilence ||
!visibleNotificationTypes.includes(notification.redux.type) || !visibleNotificationTypes.includes(notification.type) ||
( (
notification.redux.type === 'mention' && status && ( notification.type === 'mention' && status && (
status.muted || status.muted ||
muteWordHits(status, rootGetters.mergedConfig.muteWords).length === 0 muteWordHits(status, rootGetters.mergedConfig.muteWords).length === 0
) )
@ -352,8 +352,8 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
setTimeout(desktopNotification.close.bind(desktopNotification), 5000) setTimeout(desktopNotification.close.bind(desktopNotification), 5000)
} }
} }
} else if (notification.redux.pleroma.is_seen) { } else if (notification.pleroma.is_seen) {
state.notifications.idStore[notification.redux.id].pleroma.is_seen = true state.notifications.idStore[notification.id].pleroma.is_seen = true
} }
}) })
} }
@ -486,12 +486,12 @@ export const mutations = {
}, },
markNotificationsAsSeen (state) { markNotificationsAsSeen (state) {
each(state.notifications.data, (notification) => { each(state.notifications.data, (notification) => {
notification.redux.pleroma.is_seen = true notification.pleroma.is_seen = true
}) })
}, },
markSingleNotificationAsSeen (state, { id }) { markSingleNotificationAsSeen (state, { id }) {
const notification = find(state.notifications.data, n => n.id === id) const notification = find(state.notifications.data, n => n.id === id)
if (notification) notification.redux.pleroma.is_seen = true if (notification) notification.pleroma.is_seen = true
}, },
dismissNotification (state, { id }) { dismissNotification (state, { id }) {
state.notifications.data = state.notifications.data.filter(n => n.id !== id) state.notifications.data = state.notifications.data.filter(n => n.id !== id)

View file

@ -206,8 +206,7 @@ export const mutations = {
status.user = state.usersObject[status.user.id] status.user = state.usersObject[status.user.id]
}, },
setUserForNotification (state, notification) { setUserForNotification (state, notification) {
notification.from_profile = state.usersObject[notification.from_profile.id] notification.account = state.usersObject[notification.account.id]
notification.redux.account = state.usersObject[notification.redux.account.id]
}, },
setColor (state, { user: { id }, highlighted }) { setColor (state, { user: { id }, highlighted }) {
const user = state.usersObject[id] const user = state.usersObject[id]
@ -410,7 +409,7 @@ const users = {
}) })
}, },
addNewNotifications (store, { notifications }) { addNewNotifications (store, { notifications }) {
const users = map(notifications, 'from_profile') const users = map(notifications, 'account')
const targetUsers = map(notifications, 'target').filter(_ => _) const targetUsers = map(notifications, 'target').filter(_ => _)
const notificationIds = notifications.map(_ => _.id) const notificationIds = notifications.map(_ => _.id)
store.commit('addNewUsers', users) store.commit('addNewUsers', users)

View file

@ -329,44 +329,12 @@ export const parseStatus = (data) => {
} }
export const parseNotification = (data) => { export const parseNotification = (data) => {
const mastoDict = { const redux = data
'favourite': 'like', redux.account = parseUser(data.account)
'reblog': 'repeat' redux.status = isStatusNotification(data.type) ? parseStatus(data.status) : null
} redux.target = data.type !== 'move' ? null : parseUser(data.target)
const masto = !data.hasOwnProperty('ntype')
const output = {}
if (masto) { return redux
output.type = mastoDict[data.type] || data.type
output.seen = data.pleroma.is_seen
output.status = isStatusNotification(output.type) ? parseStatus(data.status) : null
output.action = output.status // TODO: Refactor, this is unneeded
output.target = output.type !== 'move'
? null
: parseUser(data.target)
output.from_profile = parseUser(data.account)
output.emoji = data.emoji
} else {
const parsedNotice = parseStatus(data.notice)
output.type = data.ntype
output.seen = Boolean(data.is_seen)
output.status = output.type === 'like'
? parseStatus(data.notice.favorited_status)
: parsedNotice
output.action = parsedNotice
output.from_profile = parseUser(data.from_profile)
}
output.created_at = new Date(data.created_at)
output.id = parseInt(data.id)
output.redux = data
output.redux.account = parseUser(data.account)
output.redux.status = isStatusNotification(data.type) ? parseStatus(data.status) : null
output.redux.target = output.type !== 'move' ? null : parseUser(data.target)
console.log(output.redux.pleroma.is_seen)
return output
} }
const isNsfw = (status) => { const isNsfw = (status) => {

View file

@ -35,25 +35,25 @@ const sortById = (a, b) => {
export const filteredNotificationsFromStore = (store, types) => { export const filteredNotificationsFromStore = (store, types) => {
// map is just to clone the array since sort mutates it and it causes some issues // map is just to clone the array since sort mutates it and it causes some issues
let sortedNotifications = notificationsFromStore(store).map(_ => _).sort(sortById) let sortedNotifications = notificationsFromStore(store).map(_ => _).sort(sortById)
sortedNotifications = sortBy(sortedNotifications, 'seen') sortedNotifications = sortBy(sortedNotifications, 'pleroma.is_seen')
return sortedNotifications.filter( return sortedNotifications.filter(
(notification) => (types || visibleTypes(store.state)).includes(notification.redux.type) (notification) => (types || visibleTypes(store.state)).includes(notification.type)
) )
} }
export const unseenNotificationsFromStore = store => export const unseenNotificationsFromStore = store =>
filter(filteredNotificationsFromStore(store), ({ seen }) => !seen) filter(filteredNotificationsFromStore(store), ({ pleroma }) => !pleroma.is_seen)
export const prepareNotificationObject = (notification, i18n) => { export const prepareNotificationObject = (notification, i18n) => {
const notifObj = { const notifObj = {
tag: notification.redux.id tag: notification.id
} }
const status = notification.redux.status const status = notification.status
const title = notification.redux.account.name const title = notification.account.name
notifObj.title = title notifObj.title = title
notifObj.icon = notification.redux.account.profile_image_url notifObj.icon = notification.account.profile_image_url
let i18nString let i18nString
switch (notification.redux.type) { switch (notification.type) {
case 'favourite': case 'favourite':
i18nString = 'favorited_you' i18nString = 'favorited_you'
break break
@ -71,12 +71,12 @@ export const prepareNotificationObject = (notification, i18n) => {
break break
} }
if (notification.redux.type === 'pleroma:emoji_reaction') { if (notification.type === 'pleroma:emoji_reaction') {
notifObj.body = i18n.t('notifications.reacted_with', [notification.redux.emoji]) notifObj.body = i18n.t('notifications.reacted_with', [notification.emoji])
} else if (i18nString) { } else if (i18nString) {
notifObj.body = i18n.t('notifications.' + i18nString) notifObj.body = i18n.t('notifications.' + i18nString)
} else if (isStatusNotification(notification.redux.type)) { } else if (isStatusNotification(notification.type)) {
notifObj.body = notification.redux.status.text notifObj.body = notification.status.text
} }
// Shows first attached non-nsfw image, if any. Should add configuration for this somehow... // Shows first attached non-nsfw image, if any. Should add configuration for this somehow...