Merge branch 'notifications-thru-sw' into 'develop'

Notifications improvements.

See merge request pleroma/pleroma-fe!1873
This commit is contained in:
HJ 2023-12-13 22:20:59 +00:00
commit 2b41c1cfe8
48 changed files with 771 additions and 385 deletions

View file

@ -14,7 +14,8 @@ import {
faBell,
faBars,
faArrowUp,
faMinus
faMinus,
faCheckDouble
} from '@fortawesome/free-solid-svg-icons'
library.add(
@ -22,7 +23,8 @@ library.add(
faBell,
faBars,
faArrowUp,
faMinus
faMinus,
faCheckDouble
)
const MobileNav = {
@ -55,6 +57,12 @@ const MobileNav = {
unseenNotificationsCount () {
return this.unseenNotifications.length + countExtraNotifications(this.$store)
},
unseenCount () {
return this.unseenNotifications.length
},
unseenCountBadgeText () {
return `${this.unseenCount ? this.unseenCount : ''}`
},
hideSitename () { return this.$store.state.instance.hideSitename },
sitename () { return this.$store.state.instance.name },
isChat () {
@ -67,6 +75,9 @@ const MobileNav = {
shouldConfirmLogout () {
return this.$store.getters.mergedConfig.modalOnLogout
},
closingDrawerMarksAsSeen () {
return this.$store.getters.mergedConfig.closingDrawerMarksAsSeen
},
...mapGetters(['unreadChatCount'])
},
methods: {
@ -81,7 +92,7 @@ const MobileNav = {
// make sure to mark notifs seen only when the notifs were open and not
// from close-calls.
this.notificationsOpen = false
if (markRead) {
if (markRead && this.closingDrawerMarksAsSeen) {
this.markNotificationsAsSeen()
}
}
@ -117,7 +128,6 @@ const MobileNav = {
this.hideConfirmLogout()
},
markNotificationsAsSeen () {
// this.$refs.notifications.markAsSeen()
this.$store.dispatch('markNotificationsAsSeen')
},
onScroll ({ target: { scrollTop, clientHeight, scrollHeight } }) {

View file

@ -50,7 +50,13 @@
@touchmove.stop="notificationsTouchMove"
>
<div class="mobile-notifications-header">
<span class="title">{{ $t('notifications.notifications') }}</span>
<span class="title">
{{ $t('notifications.notifications') }}
<span
v-if="unseenCountBadgeText"
class="badge badge-notification unseen-count"
>{{ unseenCountBadgeText }}</span>
</span>
<span class="spacer" />
<button
v-if="notificationsAtTop"
@ -66,6 +72,17 @@
/>
</FALayers>
</button>
<button
v-if="!closingDrawerMarksAsSeen"
class="button-unstyled mobile-nav-button"
:title="$t('nav.mobile_notifications_mark_as_seen')"
@click.stop.prevent="markNotificationsAsSeen()"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="check-double"
/>
</button>
<button
class="button-unstyled mobile-nav-button"
:title="$t('nav.mobile_notifications_close')"

View file

@ -50,6 +50,7 @@ const Notification = {
}
},
props: ['notification'],
emits: ['interacted'],
components: {
StatusContent,
UserAvatar,
@ -72,6 +73,9 @@ const Notification = {
getUser (notification) {
return this.$store.state.users.usersObject[notification.from_profile.id]
},
interacted () {
this.$emit('interacted')
},
toggleMute () {
this.unmuted = !this.unmuted
},
@ -95,6 +99,7 @@ const Notification = {
}
},
doApprove () {
this.$emit('interacted')
this.$store.state.api.backendInteractor.approveUser({ id: this.user.id })
this.$store.dispatch('removeFollowRequest', this.user)
this.$store.dispatch('markSingleNotificationAsSeen', { id: this.notification.id })
@ -114,6 +119,7 @@ const Notification = {
}
},
doDeny () {
this.$emit('interacted')
this.$store.state.api.backendInteractor.denyUser({ id: this.user.id })
.then(() => {
this.$store.dispatch('dismissNotificationLocal', { id: this.notification.id })

View file

@ -6,6 +6,7 @@
class="Notification"
:compact="true"
:statusoid="notification.status"
@interacted="interacted"
/>
</article>
<article v-else>
@ -248,7 +249,7 @@
<StatusContent
:class="{ faint: !statusExpanded }"
:compact="!statusExpanded"
:status="notification.action"
:status="notification.status"
/>
</template>
</div>

View file

@ -8,7 +8,8 @@ import {
notificationsFromStore,
filteredNotificationsFromStore,
unseenNotificationsFromStore,
countExtraNotifications
countExtraNotifications,
ACTIONABLE_NOTIFICATION_TYPES
} from '../../services/notification_utils/notification_utils.js'
import FaviconService from '../../services/favicon_service/favicon_service.js'
import { library } from '@fortawesome/fontawesome-svg-core'
@ -65,13 +66,20 @@ const Notifications = {
return notificationsFromStore(this.$store)
},
error () {
return this.$store.state.statuses.notifications.error
return this.$store.state.notifications.error
},
unseenNotifications () {
return unseenNotificationsFromStore(this.$store)
},
filteredNotifications () {
return filteredNotificationsFromStore(this.$store, this.filterMode)
if (this.unseenAtTop) {
return [
...filteredNotificationsFromStore(this.$store).filter(n => this.shouldShowUnseen(n)),
...filteredNotificationsFromStore(this.$store).filter(n => !this.shouldShowUnseen(n))
]
} else {
return filteredNotificationsFromStore(this.$store, this.filterMode)
}
},
unseenCountBadgeText () {
return `${this.unseenCount ? this.unseenCount : ''}${this.extraNotificationsCount ? '*' : ''}`
@ -79,6 +87,7 @@ const Notifications = {
unseenCount () {
return this.unseenNotifications.length
},
ignoreInactionableSeen () { return this.$store.getters.mergedConfig.ignoreInactionableSeen },
extraNotificationsCount () {
return countExtraNotifications(this.$store)
},
@ -86,7 +95,7 @@ const Notifications = {
return this.unseenNotifications.length + (this.unreadChatCount) + this.unreadAnnouncementCount
},
loading () {
return this.$store.state.statuses.notifications.loading
return this.$store.state.notifications.loading
},
noHeading () {
const { layoutType } = this.$store.state.interface
@ -108,6 +117,7 @@ const Notifications = {
return this.filteredNotifications.slice(0, this.unseenCount + this.seenToDisplayCount)
},
noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders },
unseenAtTop () { return this.$store.getters.mergedConfig.unseenAtTop },
showExtraNotifications () {
return !this.noExtra
},
@ -154,11 +164,28 @@ const Notifications = {
scrollToTop () {
const scrollable = this.scrollerRef
scrollable.scrollTo({ top: this.$refs.root.offsetTop })
// this.$refs.root.scrollIntoView({ behavior: 'smooth', block: 'start' })
},
updateScrollPosition () {
this.showScrollTop = this.$refs.root.offsetTop < this.scrollerRef.scrollTop
},
shouldShowUnseen (notification) {
if (notification.seen) return false
const actionable = ACTIONABLE_NOTIFICATION_TYPES.has(notification.type)
return this.ignoreInactionableSeen ? actionable : true
},
/* "Interacted" really refers to "actionable" notifications that require user input,
* everything else (likes/repeats/reacts) cannot be acted and therefore we just clear
* the "seen" status upon any clicks on them
*/
notificationClicked (notification) {
const { id } = notification
this.$store.dispatch('notificationClicked', { id })
},
notificationInteracted (notification) {
const { id } = notification
this.$store.dispatch('markSingleNotificationAsSeen', { id })
},
markAsSeen () {
this.$store.dispatch('markNotificationsAsSeen')
this.seenToDisplayCount = DEFAULT_SEEN_TO_DISPLAY_COUNT

View file

@ -66,10 +66,14 @@
:key="notification.id"
role="listitem"
class="notification"
:class="{unseen: !minimalMode && !notification.seen}"
:class="{unseen: !minimalMode && shouldShowUnseen(notification)}"
@click="e => notificationClicked(notification)"
>
<div class="notification-overlay" />
<notification :notification="notification" />
<notification
:notification="notification"
@interacted="e => notificationInteracted(notification)"
/>
</div>
</div>
<div class="panel-footer">

View file

@ -52,7 +52,6 @@ const QuickViewSettings = {
get () { return this.mergedConfig.mentionLinkShowAvatar },
set () {
const value = !this.showUserAvatars
console.log(value)
this.$store.dispatch('setOption', { name: 'mentionLinkShowAvatar', value })
}
},

View file

@ -16,7 +16,6 @@ const Report = {
},
computed: {
report () {
console.log(this.$store.state.reports.reports[this.reportId] || {})
return this.$store.state.reports.reports[this.reportId] || {}
},
state: {

View file

@ -3,6 +3,10 @@
.settings-modal {
overflow: hidden;
h4 {
margin-bottom: 0.5em;
}
.setting-list,
.option-list {
list-style-type: none;
@ -15,6 +19,14 @@
.suboptions {
margin-top: 0.3em;
}
&.two-column {
column-count: 2;
> li {
break-inside: avoid;
}
}
}
.setting-description {

View file

@ -16,6 +16,10 @@ const NotificationsTab = {
user () {
return this.$store.state.users.currentUser
},
canReceiveReports () {
if (!this.user) { return false }
return this.user.privileges.includes('reports_manage_reports')
},
...SharedComputedObject()
},
methods: {

View file

@ -1,5 +1,30 @@
<template>
<div :label="$t('settings.notifications')">
<div class="setting-item">
<h2>{{ $t('settings.notification_setting_annoyance') }}</h2>
<ul class="setting-list">
<li>
<BooleanSetting path="closingDrawerMarksAsSeen">
{{ $t('settings.notification_setting_drawer_marks_as_seen') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="ignoreInactionableSeen">
{{ $t('settings.notification_setting_ignore_inactionable_seen') }}
</BooleanSetting>
<div>
<small>
{{ $t('settings.notification_setting_ignore_inactionable_seen_tip') }}
</small>
</div>
</li>
<li>
<BooleanSetting path="unseenAtTop" expert="1">
{{ $t('settings.notification_setting_unseen_at_top') }}
</BooleanSetting>
</li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('settings.notification_setting_filters') }}</h2>
<ul class="setting-list">
@ -11,43 +36,144 @@
{{ $t('settings.notification_setting_block_from_strangers') }}
</BooleanSetting>
</li>
<li class="select-multiple">
<span class="label">{{ $t('settings.notification_visibility') }}</span>
<ul class="option-list">
<li>
<h3> {{ $t('settings.notification_visibility') }}</h3>
<p v-if="expertLevel > 0">{{ $t('settings.notification_setting_filters_chrome_push') }}</p>
<ul class="setting-list two-column">
<li>
<BooleanSetting path="notificationVisibility.likes">
{{ $t('settings.notification_visibility_likes') }}
</BooleanSetting>
<h4> {{ $t('settings.notification_visibility_mentions') }}</h4>
<ul class="setting-list">
<li>
<BooleanSetting path="notificationVisibility.mentions">
{{ $t('settings.notification_visibility_in_column') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationNative.mentions">
{{ $t('settings.notification_visibility_native_notifications') }}
</BooleanSetting>
</li>
</ul>
</li>
<li>
<BooleanSetting path="notificationVisibility.repeats">
{{ $t('settings.notification_visibility_repeats') }}
</BooleanSetting>
<h4> {{ $t('settings.notification_visibility_likes') }}</h4>
<ul class="setting-list">
<li>
<BooleanSetting path="notificationVisibility.likes">
{{ $t('settings.notification_visibility_in_column') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationNative.likes">
{{ $t('settings.notification_visibility_native_notifications') }}
</BooleanSetting>
</li>
</ul>
</li>
<li>
<BooleanSetting path="notificationVisibility.follows">
{{ $t('settings.notification_visibility_follows') }}
</BooleanSetting>
<h4> {{ $t('settings.notification_visibility_repeats') }}</h4>
<ul class="setting-list">
<li>
<BooleanSetting path="notificationVisibility.repeats">
{{ $t('settings.notification_visibility_in_column') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationNative.repeats">
{{ $t('settings.notification_visibility_native_notifications') }}
</BooleanSetting>
</li>
</ul>
</li>
<li>
<BooleanSetting path="notificationVisibility.mentions">
{{ $t('settings.notification_visibility_mentions') }}
</BooleanSetting>
<h4> {{ $t('settings.notification_visibility_emoji_reactions') }}</h4>
<ul class="setting-list">
<li>
<BooleanSetting path="notificationVisibility.emojiReactions">
{{ $t('settings.notification_visibility_in_column') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationNative.emojiReactions">
{{ $t('settings.notification_visibility_native_notifications') }}
</BooleanSetting>
</li>
</ul>
</li>
<li>
<BooleanSetting path="notificationVisibility.moves">
{{ $t('settings.notification_visibility_moves') }}
</BooleanSetting>
<h4> {{ $t('settings.notification_visibility_follows') }}</h4>
<ul class="setting-list">
<li>
<BooleanSetting path="notificationVisibility.follows">
{{ $t('settings.notification_visibility_in_column') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationNative.follows">
{{ $t('settings.notification_visibility_native_notifications') }}
</BooleanSetting>
</li>
</ul>
</li>
<li>
<BooleanSetting path="notificationVisibility.emojiReactions">
{{ $t('settings.notification_visibility_emoji_reactions') }}
</BooleanSetting>
<h4> {{ $t('settings.notification_visibility_follow_requests') }}</h4>
<ul class="setting-list">
<li>
<BooleanSetting path="notificationVisibility.followRequest">
{{ $t('settings.notification_visibility_in_column') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationNative.followRequest">
{{ $t('settings.notification_visibility_native_notifications') }}
</BooleanSetting>
</li>
</ul>
</li>
<li>
<BooleanSetting path="notificationVisibility.polls">
{{ $t('settings.notification_visibility_polls') }}
</BooleanSetting>
<h4> {{ $t('settings.notification_visibility_moves') }}</h4>
<ul class="setting-list">
<li>
<BooleanSetting path="notificationVisibility.moves">
{{ $t('settings.notification_visibility_in_column') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationNative.moves">
{{ $t('settings.notification_visibility_native_notifications') }}
</BooleanSetting>
</li>
</ul>
</li>
<li>
<h4> {{ $t('settings.notification_visibility_polls') }}</h4>
<ul class="setting-list">
<li>
<BooleanSetting path="notificationVisibility.polls">
{{ $t('settings.notification_visibility_in_column') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationNative.polls">
{{ $t('settings.notification_visibility_native_notifications') }}
</BooleanSetting>
</li>
</ul>
</li>
<li v-if="canReceiveReports">
<h4> {{ $t('settings.notification_visibility_reports') }}</h4>
<ul class="setting-list">
<li>
<BooleanSetting path="notificationVisibility.reports">
{{ $t('settings.notification_visibility_in_column') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationNative.reports">
{{ $t('settings.notification_visibility_native_notifications') }}
</BooleanSetting>
</li>
</ul>
</li>
</ul>
</li>
@ -108,6 +234,21 @@
>
{{ $t('settings.enable_web_push_notifications') }}
</BooleanSetting>
<ul class="setting-list suboptions">
<li>
<BooleanSetting
path="webPushAlwaysShowNotifications"
:disabled="!mergedConfig.webPushNotifications"
>
{{ $t('settings.enable_web_push_always_show') }}
</BooleanSetting>
<div :class="{ faint: !mergedConfig.webPushNotifications }">
<small>
{{ $t('settings.enable_web_push_always_show_tip') }}
</small>
</div>
</li>
</ul>
</li>
<li>
<BooleanSetting

View file

@ -755,7 +755,6 @@ export default {
selected () {
this.selectedTheme = Object.entries(this.availableStyles).find(([k, s]) => {
if (Array.isArray(s)) {
console.log(s[0] === this.selected, this.selected)
return s[0] === this.selected
} else {
return s.name === this.selected

View file

@ -154,6 +154,7 @@ const Status = {
'controlledSetMediaPlaying',
'dive'
],
emits: ['interacted'],
data () {
return {
uncontrolledReplying: false,
@ -442,9 +443,11 @@ const Status = {
this.error = error
},
clearError () {
this.$emit('interacted')
this.error = undefined
},
toggleReplying () {
this.$emit('interacted')
controlledOrUncontrolledToggle(this, 'replying')
},
gotoOriginal (id) {

View file

@ -531,14 +531,17 @@
:visibility="status.visibility"
:logged-in="loggedIn"
:status="status"
@click="$emit('interacted')"
/>
<favorite-button
:logged-in="loggedIn"
:status="status"
@click="$emit('interacted')"
/>
<ReactButton
v-if="loggedIn"
:status="status"
@click="$emit('interacted')"
/>
<extra-buttons
:status="status"