Remove unread timeline and fix scroll position in notifications

This commit is contained in:
AkiraFukushima 2021-07-25 21:51:51 +09:00
parent 143849424e
commit 24e2a80236
No known key found for this signature in database
GPG Key ID: B6E51BAC4DE1A957
5 changed files with 37 additions and 71 deletions

View File

@ -192,8 +192,7 @@ let state = (): NotificationsState => {
return { return {
lazyLoading: false, lazyLoading: false,
heading: true, heading: true,
notifications: [], notifications: []
unreadNotifications: []
} }
} }
@ -253,8 +252,7 @@ describe('Notifications', () => {
return { return {
lazyLoading: false, lazyLoading: false,
heading: true, heading: true,
notifications: [notification1], notifications: [notification1]
unreadNotifications: []
} }
} }
}) })

View File

@ -179,7 +179,7 @@ describe('TimelineSpace/Contents/Home', () => {
showReplies: true showReplies: true
} }
}) })
it('should not update unreadTimeline', () => { it('should not update timeline', () => {
Home.mutations![MUTATION_TYPES.APPEND_TIMELINE](state, status2) Home.mutations![MUTATION_TYPES.APPEND_TIMELINE](state, status2)
expect(state.timeline).toEqual([status2, status1]) expect(state.timeline).toEqual([status2, status1])
}) })

View File

@ -175,8 +175,7 @@ describe('TimelineSpace/Contents/Notifications', () => {
state = { state = {
lazyLoading: false, lazyLoading: false,
heading: true, heading: true,
notifications: [notification2, notification1], notifications: [notification2, notification1]
unreadNotifications: []
} }
}) })
describe('message is not reblogged', () => { describe('message is not reblogged', () => {
@ -200,14 +199,12 @@ describe('TimelineSpace/Contents/Notifications', () => {
state = { state = {
lazyLoading: false, lazyLoading: false,
heading: true, heading: true,
notifications: [notification1], notifications: [notification1]
unreadNotifications: []
} }
}) })
it('should update timeline', () => { it('should update timeline', () => {
Notifications.mutations![MUTATION_TYPES.APPEND_NOTIFICATIONS](state, notification2) Notifications.mutations![MUTATION_TYPES.APPEND_NOTIFICATIONS](state, notification2)
expect(state.notifications).toEqual([notification2, notification1]) expect(state.notifications).toEqual([notification2, notification1])
expect(state.unreadNotifications).toEqual([])
}) })
}) })
@ -216,14 +213,12 @@ describe('TimelineSpace/Contents/Notifications', () => {
state = { state = {
lazyLoading: false, lazyLoading: false,
heading: true, heading: true,
notifications: [notification2, notification1], notifications: [notification2, notification1]
unreadNotifications: []
} }
}) })
it('should not update timeline', () => { it('should not update timeline', () => {
Notifications.mutations![MUTATION_TYPES.APPEND_NOTIFICATIONS](state, notification2) Notifications.mutations![MUTATION_TYPES.APPEND_NOTIFICATIONS](state, notification2)
expect(state.notifications).toEqual([notification2, notification1]) expect(state.notifications).toEqual([notification2, notification1])
expect(state.unreadNotifications).toEqual([])
}) })
}) })
}) })
@ -234,14 +229,12 @@ describe('TimelineSpace/Contents/Notifications', () => {
state = { state = {
lazyLoading: false, lazyLoading: false,
heading: false, heading: false,
notifications: [notification1], notifications: [notification1]
unreadNotifications: []
} }
}) })
it('should update unreadTimeline', () => { it('should update timeline', () => {
Notifications.mutations![MUTATION_TYPES.APPEND_NOTIFICATIONS](state, notification2) Notifications.mutations![MUTATION_TYPES.APPEND_NOTIFICATIONS](state, notification2)
expect(state.notifications).toEqual([notification1]) expect(state.notifications).toEqual([notification2, notification1])
expect(state.unreadNotifications).toEqual([notification2])
}) })
}) })
describe('duplicated status', () => { describe('duplicated status', () => {
@ -249,14 +242,12 @@ describe('TimelineSpace/Contents/Notifications', () => {
state = { state = {
lazyLoading: false, lazyLoading: false,
heading: false, heading: false,
notifications: [notification1], notifications: [notification2, notification1]
unreadNotifications: [notification2]
} }
}) })
it('should not update unreadTimeline', () => { it('should not update timeline', () => {
Notifications.mutations![MUTATION_TYPES.APPEND_NOTIFICATIONS](state, notification2) Notifications.mutations![MUTATION_TYPES.APPEND_NOTIFICATIONS](state, notification2)
expect(state.notifications).toEqual([notification1]) expect(state.notifications).toEqual([notification2, notification1])
expect(state.unreadNotifications).toEqual([notification2])
}) })
}) })
}) })

View File

@ -1,6 +1,5 @@
<template> <template>
<div id="notifications" v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" @shortkey="handleKey"> <div id="notifications" v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" @shortkey="handleKey">
<div class="unread">{{ unread.length > 0 ? unread.length : '' }}</div>
<div v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }" @shortkey="reload()"></div> <div v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }" @shortkey="reload()"></div>
<DynamicScroller :items="handledNotifications" :min-item-size="20" id="scroller" class="scroller" ref="scroller"> <DynamicScroller :items="handledNotifications" :min-item-size="20" id="scroller" class="scroller" ref="scroller">
<template v-slot="{ item, index, active }"> <template v-slot="{ item, index, active }">
@ -31,6 +30,7 @@ import { mapState, mapGetters } from 'vuex'
import Notification from '~/src/renderer/components/organisms/Notification' import Notification from '~/src/renderer/components/organisms/Notification'
import reloadable from '~/src/renderer/components/mixins/reloadable' import reloadable from '~/src/renderer/components/mixins/reloadable'
import { Event } from '~/src/renderer/components/event' import { Event } from '~/src/renderer/components/event'
import { ScrollPosition } from '~/src/renderer/components/utils/scroll'
export default { export default {
name: 'notifications', name: 'notifications',
@ -38,7 +38,8 @@ export default {
mixins: [reloadable], mixins: [reloadable],
data() { data() {
return { return {
focusedId: null focusedId: null,
scroll: null
} }
}, },
computed: { computed: {
@ -49,8 +50,7 @@ export default {
}), }),
...mapState('TimelineSpace/Contents/Notifications', { ...mapState('TimelineSpace/Contents/Notifications', {
lazyLoading: state => state.lazyLoading, lazyLoading: state => state.lazyLoading,
heading: state => state.heading, heading: state => state.heading
unread: state => state.unreadNotifications
}), }),
...mapGetters('TimelineSpace/Contents/Notifications', ['handledNotifications', 'filters']), ...mapGetters('TimelineSpace/Contents/Notifications', ['handledNotifications', 'filters']),
...mapGetters('TimelineSpace/Modals', ['modalOpened']), ...mapGetters('TimelineSpace/Modals', ['modalOpened']),
@ -83,18 +83,30 @@ export default {
if (this.heading && this.handledNotifications.length > 0) { if (this.heading && this.handledNotifications.length > 0) {
this.$store.dispatch('TimelineSpace/Contents/Notifications/saveMarker', this.handledNotifications[0].id) this.$store.dispatch('TimelineSpace/Contents/Notifications/saveMarker', this.handledNotifications[0].id)
} }
const el = document.getElementById('scroller')
this.scroll = new ScrollPosition(el)
this.scroll.prepare()
}, },
beforeUpdate() { beforeUpdate() {
if (this.$store.state.TimelineSpace.SideMenu.unreadNotifications) { if (this.$store.state.TimelineSpace.SideMenu.unreadNotifications && this.heading) {
this.$store.commit('TimelineSpace/SideMenu/changeUnreadNotifications', false) this.$store.commit('TimelineSpace/SideMenu/changeUnreadNotifications', false)
} }
if (!this.heading) {
const el = document.getElementById('scroller')
this.scroll = new ScrollPosition(el)
this.scroll.prepare()
}
},
updated() {
if (this.scroll && !this.heading) {
this.scroll.restore()
}
}, },
beforeDestroy() { beforeDestroy() {
Event.$off('focus-timeline') Event.$off('focus-timeline')
}, },
destroyed() { destroyed() {
this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', true) this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', true)
this.$store.commit('TimelineSpace/Contents/Notifications/mergeNotifications')
this.$store.commit('TimelineSpace/Contents/Notifications/archiveNotifications') this.$store.commit('TimelineSpace/Contents/Notifications/archiveNotifications')
if (document.getElementById('scroller') !== undefined && document.getElementById('scroller') !== null) { if (document.getElementById('scroller') !== undefined && document.getElementById('scroller') !== null) {
document.getElementById('scroller').removeEventListener('scroll', this.onScroll) document.getElementById('scroller').removeEventListener('scroll', this.onScroll)
@ -114,7 +126,6 @@ export default {
this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', false) this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', false)
} else if (newState === null && !this.heading) { } else if (newState === null && !this.heading) {
this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', true) this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', true)
this.$store.commit('TimelineSpace/Contents/Notifications/mergeNotifications')
this.$store.dispatch('TimelineSpace/Contents/Notifications/resetBadge') this.$store.dispatch('TimelineSpace/Contents/Notifications/resetBadge')
} }
}, },
@ -142,16 +153,11 @@ export default {
}) })
}) })
} }
// for unread control
if (event.target.scrollTop > 5 && this.heading) { if (event.target.scrollTop > 10 && this.heading) {
this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', false) this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', false)
} else if (event.target.scrollTop <= 5 && !this.heading) { } else if (event.target.scrollTop <= 10 && !this.heading) {
const currentPos = this.unread.length
if (currentPos === 0) {
this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', true) this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', true)
}
this.$store.commit('TimelineSpace/Contents/Notifications/mergeNotifications')
this.$refs.scroller.scrollToItem(currentPos)
this.$store.dispatch('TimelineSpace/Contents/Notifications/resetBadge') this.$store.dispatch('TimelineSpace/Contents/Notifications/resetBadge')
} }
}, },
@ -214,21 +220,6 @@ export default {
height: 100%; height: 100%;
} }
.unread {
position: fixed;
right: 24px;
top: 48px;
background-color: rgba(0, 0, 0, 0.7);
color: #ffffff;
padding: 4px 8px;
border-radius: 0 0 2px 2px;
z-index: 1;
&:empty {
display: none;
}
}
.loading-card { .loading-card {
height: 60px; height: 60px;
} }

View File

@ -10,14 +10,12 @@ export type NotificationsState = {
lazyLoading: boolean lazyLoading: boolean
heading: boolean heading: boolean
notifications: Array<Entity.Notification> notifications: Array<Entity.Notification>
unreadNotifications: Array<Entity.Notification>
} }
const state = (): NotificationsState => ({ const state = (): NotificationsState => ({
lazyLoading: false, lazyLoading: false,
heading: true, heading: true,
notifications: [], notifications: []
unreadNotifications: []
}) })
export const MUTATION_TYPES = { export const MUTATION_TYPES = {
@ -25,7 +23,6 @@ export const MUTATION_TYPES = {
CHANGE_HEADING: 'changeHeading', CHANGE_HEADING: 'changeHeading',
APPEND_NOTIFICATIONS: 'appendNotifications', APPEND_NOTIFICATIONS: 'appendNotifications',
UPDATE_NOTIFICATIONS: 'updateNotifications', UPDATE_NOTIFICATIONS: 'updateNotifications',
MERGE_NOTIFICATIONS: 'mergeNotifications',
INSERT_NOTIFICATIONS: 'insertNotifications', INSERT_NOTIFICATIONS: 'insertNotifications',
UPDATE_TOOT: 'updateToot', UPDATE_TOOT: 'updateToot',
DELETE_TOOT: 'deleteToot', DELETE_TOOT: 'deleteToot',
@ -42,24 +39,13 @@ const mutations: MutationTree<NotificationsState> = {
}, },
[MUTATION_TYPES.APPEND_NOTIFICATIONS]: (state, notification: Entity.Notification) => { [MUTATION_TYPES.APPEND_NOTIFICATIONS]: (state, notification: Entity.Notification) => {
// Reject duplicated status in timeline // Reject duplicated status in timeline
if ( if (!state.notifications.find(item => item.id === notification.id)) {
!state.notifications.find(item => item.id === notification.id) &&
!state.unreadNotifications.find(item => item.id === notification.id)
) {
if (state.heading) {
state.notifications = [notification].concat(state.notifications) state.notifications = [notification].concat(state.notifications)
} else {
state.unreadNotifications = [notification].concat(state.unreadNotifications)
}
} }
}, },
[MUTATION_TYPES.UPDATE_NOTIFICATIONS]: (state, notifications: Array<Entity.Notification>) => { [MUTATION_TYPES.UPDATE_NOTIFICATIONS]: (state, notifications: Array<Entity.Notification>) => {
state.notifications = notifications state.notifications = notifications
}, },
[MUTATION_TYPES.MERGE_NOTIFICATIONS]: state => {
state.notifications = state.unreadNotifications.slice(0, 80).concat(state.notifications)
state.unreadNotifications = []
},
[MUTATION_TYPES.INSERT_NOTIFICATIONS]: (state, notifications: Array<Entity.Notification>) => { [MUTATION_TYPES.INSERT_NOTIFICATIONS]: (state, notifications: Array<Entity.Notification>) => {
state.notifications = state.notifications.concat(notifications) state.notifications = state.notifications.concat(notifications)
}, },