Compare commits
13 commits
7bd01ca116
...
c91e52f18f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c91e52f18f | ||
|
|
18bdc84200 | ||
|
|
9676f95cf4 | ||
|
|
713eb828c8 | ||
|
|
7c46ba462f | ||
|
|
4e1d6f704d | ||
|
|
a44b60dbc8 | ||
|
|
b112bf11c2 | ||
|
|
f46575add2 | ||
|
|
a4b02936ac | ||
|
|
d9f03f61ae | ||
|
|
ae36bcbb4e | ||
|
|
82d6b66386 |
11 changed files with 82 additions and 22 deletions
|
|
@ -37,9 +37,7 @@ export const piniaPushNotificationsPlugin = ({ store }) => {
|
||||||
if (store.$id === 'interface') {
|
if (store.$id === 'interface') {
|
||||||
if (actionName === 'setNotificationPermission') {
|
if (actionName === 'setNotificationPermission') {
|
||||||
permissionGranted = args[0] === 'granted'
|
permissionGranted = args[0] === 'granted'
|
||||||
} else if (actionName === 'setLoginStatus') {
|
} else if (actionName !== 'onLogin' && actionName !== 'onLogout') {
|
||||||
user = args[0]
|
|
||||||
} else {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if (store.$id === 'sync_config') {
|
} else if (store.$id === 'sync_config') {
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,11 @@ import { showDesktopNotification } from '../desktop_notification_utils/desktop_n
|
||||||
import { useUsersStore } from 'src/stores/users.js'
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
export const maybeShowChatNotification = (chat) => {
|
export const maybeShowChatNotification = (chat) => {
|
||||||
|
// No messages
|
||||||
if (!chat.lastMessage) return
|
if (!chat.lastMessage) return
|
||||||
|
// No unreads to display
|
||||||
if (chat.unread === 0) return
|
if (chat.unread === 0) return
|
||||||
|
// Don't notify on outgoing message (shouldn't happen with condition above)
|
||||||
if (useUsersStore().currentUser.id === chat.lastMessage.account_id) return
|
if (useUsersStore().currentUser.id === chat.lastMessage.account_id) return
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
|
|
|
||||||
|
|
@ -430,7 +430,7 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
|
||||||
})
|
})
|
||||||
|
|
||||||
resultUserIds.data.forEach((userId) => {
|
resultUserIds.data.forEach((userId) => {
|
||||||
useStatusesStore().wipeUserStatuses(status.user.id)
|
useStatusesStore().wipeUserStatuses(userId)
|
||||||
// Users are technically never deleted, just deactivated
|
// Users are technically never deleted, just deactivated
|
||||||
// so there's no real need to delete them from store.
|
// so there's no real need to delete them from store.
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ export const useChatsStore = defineStore('chats', {
|
||||||
useStreamingStore().addSubscriber(socket)
|
useStreamingStore().addSubscriber(socket)
|
||||||
},
|
},
|
||||||
startFetching() {
|
startFetching() {
|
||||||
this.fetcher = () => promiseInterval(() => this.fetchChats(), 5000)
|
this.fetcher = promiseInterval(() => this.fetchChats(), 5000)
|
||||||
this.fetcher()
|
this.fetchChats()
|
||||||
},
|
},
|
||||||
stopFetching() {
|
stopFetching() {
|
||||||
this.fetcher?.stop()
|
this.fetcher?.stop()
|
||||||
|
|
@ -56,8 +56,6 @@ export const useChatsStore = defineStore('chats', {
|
||||||
},
|
},
|
||||||
resetChats() {
|
resetChats() {
|
||||||
this.data = new Map()
|
this.data = new Map()
|
||||||
this.stopFetching()
|
|
||||||
this.startFetching()
|
|
||||||
},
|
},
|
||||||
addNewChats(result) {
|
addNewChats(result) {
|
||||||
useUsersStore().addNewUsers({
|
useUsersStore().addNewUsers({
|
||||||
|
|
@ -79,13 +77,15 @@ export const useChatsStore = defineStore('chats', {
|
||||||
updateChat(updatedChat) {
|
updateChat(updatedChat) {
|
||||||
const chat = this.data.get(updatedChat.id)
|
const chat = this.data.get(updatedChat.id)
|
||||||
if (chat) {
|
if (chat) {
|
||||||
|
const isNewMessage = chat.lastMessage !== updatedChat.lastMessage
|
||||||
chat.lastMessage = updatedChat.lastMessage
|
chat.lastMessage = updatedChat.lastMessage
|
||||||
chat.unread = updatedChat.unread
|
chat.unread = updatedChat.unread
|
||||||
chat.updated_at = updatedChat.updated_at
|
chat.updated_at = updatedChat.updated_at
|
||||||
|
if (isNewMessage) maybeShowChatNotification(chat)
|
||||||
} else {
|
} else {
|
||||||
this.data.set(updatedChat.id, updatedChat)
|
this.data.set(updatedChat.id, updatedChat)
|
||||||
|
maybeShowChatNotification(updatedChat)
|
||||||
}
|
}
|
||||||
maybeShowChatNotification(chat ?? updatedChat)
|
|
||||||
},
|
},
|
||||||
deleteChat(id) {
|
deleteChat(id) {
|
||||||
this.data.delete(id)
|
this.data.delete(id)
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ const timelineFetcher = (timeline, argument, credentials) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
args.withMuted = !hideMutedPosts
|
args.withMuted = !hideMutedPosts
|
||||||
if (loggedIn && REPLY_VISIBILITY_TIMELINES.has(timeline)) {
|
if (loggedIn && REPLY_VISIBILITY_TIMELINES.has(timeline.name)) {
|
||||||
args.replyVisibility = replyVisibility
|
args.replyVisibility = replyVisibility
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,17 +22,41 @@ import {
|
||||||
import { isStatusNotification } from 'src/services/notification_utils/notification_utils_sw.js'
|
import { isStatusNotification } from 'src/services/notification_utils/notification_utils_sw.js'
|
||||||
|
|
||||||
export const defaultState = () => ({
|
export const defaultState = () => ({
|
||||||
|
// Prevents desktop notification spam on startup
|
||||||
desktopNotificationSilence: true,
|
desktopNotificationSilence: true,
|
||||||
|
|
||||||
|
// Pagination
|
||||||
maxId: '',
|
maxId: '',
|
||||||
minId: '',
|
minId: '',
|
||||||
|
|
||||||
|
// Order
|
||||||
data: [],
|
data: [],
|
||||||
|
|
||||||
|
// TODO: Implement!
|
||||||
|
// Useful for making notification as seen
|
||||||
|
// when interacting with status
|
||||||
statusNotificationRelations: new WeakMap(),
|
statusNotificationRelations: new WeakMap(),
|
||||||
|
|
||||||
|
// ID to Object notification
|
||||||
idStore: new Map(),
|
idStore: new Map(),
|
||||||
statusIdStore: new Set(),
|
|
||||||
|
// Reference to WS subscriber
|
||||||
socket: null,
|
socket: null,
|
||||||
|
|
||||||
|
// Indicates whether notifications receive push updates
|
||||||
streaming: false,
|
streaming: false,
|
||||||
|
|
||||||
|
// Indicates whether notifications are SUPPOSED to be fetching
|
||||||
|
// this is partiualrly useful for when pausing/resuming. I.e.
|
||||||
|
// whether we need to start fetching again if timeline was resumed.
|
||||||
fetching: true,
|
fetching: true,
|
||||||
|
|
||||||
|
// Reference to fetcher, used for polling for new notifications
|
||||||
|
// and manually fetching old notifications
|
||||||
fetcher: null,
|
fetcher: null,
|
||||||
|
|
||||||
|
// Whether notifications fetcher has been paused - it stops fetching
|
||||||
|
// (but still receives pushes!)
|
||||||
paused: false,
|
paused: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,10 @@ export const useReportsStore = defineStore('reports', {
|
||||||
actions: {
|
actions: {
|
||||||
openUserReportingModal({ userId, statusIds = [] }) {
|
openUserReportingModal({ userId, statusIds = [] }) {
|
||||||
const preTickedIds = new Set(statusIds)
|
const preTickedIds = new Set(statusIds)
|
||||||
// There shouldn't be a case where this is undefined
|
// There could be a case (i.e. user is only ever mentioned in someone else's post -> user popover)
|
||||||
const userAllStatusesIds = useStatusesStore().statusesPerUser.get(userId)
|
// where user has no known posts
|
||||||
|
const userAllStatusesIds =
|
||||||
|
useStatusesStore().statusesPerUser.get(userId) ?? new Set()
|
||||||
// Set constructor should take care of duplicated IDs and order,
|
// Set constructor should take care of duplicated IDs and order,
|
||||||
// later duplicated IDs will be dropped in favor of earlier
|
// later duplicated IDs will be dropped in favor of earlier
|
||||||
const sortedIds = new Set([...preTickedIds, ...userAllStatusesIds])
|
const sortedIds = new Set([...preTickedIds, ...userAllStatusesIds])
|
||||||
|
|
|
||||||
|
|
@ -534,7 +534,7 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
|
|
||||||
// For when blocking a user
|
// For when blocking a user
|
||||||
wipeUserStatuses(userId) {
|
wipeUserStatuses(userId) {
|
||||||
const removed = this.statusesPerUser.get(userId)
|
const removed = this.statusesPerUser.get(userId) ?? new Set()
|
||||||
removed.forEach((statusId) => {
|
removed.forEach((statusId) => {
|
||||||
const status = this.allStatuses.get(statusId)
|
const status = this.allStatuses.get(statusId)
|
||||||
this.allStatuses.delete(statusId)
|
this.allStatuses.delete(statusId)
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,49 @@ import { TIMELINE_STREAM_MAP, useStreamingStore } from 'src/stores/streaming.js'
|
||||||
|
|
||||||
const emptyTl = (name, argument = null) => {
|
const emptyTl = (name, argument = null) => {
|
||||||
const result = {
|
const result = {
|
||||||
|
// Name of the timeline. Useful for debugging and logging
|
||||||
name,
|
name,
|
||||||
|
|
||||||
|
// Order of statuses, important for timelines that
|
||||||
|
// have different ordering, i.e. bookmarks and favorites
|
||||||
order: [],
|
order: [],
|
||||||
|
|
||||||
|
// All statuses belonging to the timeline
|
||||||
statusIds: new Set(),
|
statusIds: new Set(),
|
||||||
|
|
||||||
|
// Statuses shown to user
|
||||||
visibleStatusIds: new Set(),
|
visibleStatusIds: new Set(),
|
||||||
|
|
||||||
|
// Number of statuses not shown yet
|
||||||
newStatusCount: 0,
|
newStatusCount: 0,
|
||||||
|
|
||||||
|
// Pagination
|
||||||
maxId: '',
|
maxId: '',
|
||||||
minId: '',
|
minId: '',
|
||||||
|
|
||||||
|
// Indicates whether timeline receives push updates
|
||||||
streaming: false,
|
streaming: false,
|
||||||
|
|
||||||
|
// Indicates whether timeline is SUPPOSED to be fetching
|
||||||
|
// this is partiualrly useful for when pausing/resuming
|
||||||
|
// timeline. I.e. whether we need to start fetching again
|
||||||
|
// if timeline was resumed.
|
||||||
fetching: false,
|
fetching: false,
|
||||||
|
|
||||||
|
// Indicates that in recent poll update we've hit more than or
|
||||||
|
// equal to 20 statuses and most likely missed some statuses
|
||||||
|
// between polls
|
||||||
reloadNeeded: false,
|
reloadNeeded: false,
|
||||||
|
|
||||||
|
// Reference to fetcher, used for polling for new statuses and
|
||||||
|
// manually fetching old statuses
|
||||||
fetcher: null,
|
fetcher: null,
|
||||||
|
|
||||||
|
// Reference to WS subscriber
|
||||||
socket: null,
|
socket: null,
|
||||||
|
|
||||||
|
// Whether the timeline has been paused - it stops fetching
|
||||||
|
// (but still receives pushes!)
|
||||||
paused: false,
|
paused: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,6 +347,14 @@ export const useTimelinesStore = defineStore('timelines', {
|
||||||
reason,
|
reason,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
} else if (timeline.paused) {
|
||||||
|
console.debug(
|
||||||
|
'[Timelines] Deactivating paused timeline',
|
||||||
|
timelineName,
|
||||||
|
'Reason:',
|
||||||
|
reason,
|
||||||
|
)
|
||||||
|
timeline.fetching = false
|
||||||
} else {
|
} else {
|
||||||
timeline.fetcher.stopFetching()
|
timeline.fetcher.stopFetching()
|
||||||
console.debug(
|
console.debug(
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,6 @@ import { promiseInterval } from 'src/services/promise_interval/promise_interval.
|
||||||
export const useUsersStore = defineStore('users', {
|
export const useUsersStore = defineStore('users', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
loggingIn: false,
|
loggingIn: false,
|
||||||
lastLoginName: null,
|
|
||||||
currentUser: null,
|
currentUser: null,
|
||||||
users: new Map(),
|
users: new Map(),
|
||||||
usersByName: new Map(),
|
usersByName: new Map(),
|
||||||
|
|
@ -616,7 +615,6 @@ export const useUsersStore = defineStore('users', {
|
||||||
user.muteIds = new Set()
|
user.muteIds = new Set()
|
||||||
user.domainMutes = new Set()
|
user.domainMutes = new Set()
|
||||||
|
|
||||||
this.lastLoginName = user.screen_name
|
|
||||||
useTimelinesStore().deactivateAll()
|
useTimelinesStore().deactivateAll()
|
||||||
useStatusesStore().resetStatuses()
|
useStatusesStore().resetStatuses()
|
||||||
|
|
||||||
|
|
@ -739,13 +737,13 @@ export const useUsersStore = defineStore('users', {
|
||||||
oauth.clearToken()
|
oauth.clearToken()
|
||||||
|
|
||||||
this.currentUser = null
|
this.currentUser = null
|
||||||
this.lastLoginName = null
|
|
||||||
|
|
||||||
useNotificationsStore().deactivate()
|
useNotificationsStore().deactivate()
|
||||||
|
|
||||||
// Full reset on logout success
|
// Full reset on logout success
|
||||||
useTimelinesStore().deactivateAll()
|
useTimelinesStore().deactivateAll()
|
||||||
useStatusesStore().resetStatuses()
|
useStatusesStore().resetStatuses()
|
||||||
|
useChatsStore().stopFetching()
|
||||||
useChatsStore().resetChats()
|
useChatsStore().resetChats()
|
||||||
|
|
||||||
this.users = new Map()
|
this.users = new Map()
|
||||||
|
|
@ -777,6 +775,7 @@ export const useUsersStore = defineStore('users', {
|
||||||
useAnnouncementsStore().startFetching()
|
useAnnouncementsStore().startFetching()
|
||||||
useListsStore().startFetching()
|
useListsStore().startFetching()
|
||||||
useBookmarkFoldersStore().startFetching()
|
useBookmarkFoldersStore().startFetching()
|
||||||
|
useChatsStore().startFetching()
|
||||||
store?.dispatch('startFetchingFollowRequests')
|
store?.dispatch('startFetchingFollowRequests')
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
|
@ -785,7 +784,4 @@ export const useUsersStore = defineStore('users', {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
persist: {
|
|
||||||
paths: ['lastLoginName'],
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -679,7 +679,6 @@ describe('Users store', () => {
|
||||||
expect(store.usersByName).to.have.length(1)
|
expect(store.usersByName).to.have.length(1)
|
||||||
expect(store.usersByURL).to.have.length(1)
|
expect(store.usersByURL).to.have.length(1)
|
||||||
expect(store.relationships).to.have.length(0)
|
expect(store.relationships).to.have.length(0)
|
||||||
expect(store.lastLoginName).to.eql(userScreenName)
|
|
||||||
spies.forEach((spy, index) => {
|
spies.forEach((spy, index) => {
|
||||||
expect(spy, `Spy ${index} has failed`).to.have.been.called
|
expect(spy, `Spy ${index} has failed`).to.have.been.called
|
||||||
})
|
})
|
||||||
|
|
@ -783,7 +782,6 @@ describe('Users store', () => {
|
||||||
expect(store.loggedIn).to.eql(true)
|
expect(store.loggedIn).to.eql(true)
|
||||||
await store.logout()
|
await store.logout()
|
||||||
expect(store.loggedIn).to.eql(false)
|
expect(store.loggedIn).to.eql(false)
|
||||||
expect(store.lastLoginName).to.eql(null)
|
|
||||||
expect(revokeApi).to.have.been.called
|
expect(revokeApi).to.have.been.called
|
||||||
expect(store.users).to.have.length(0)
|
expect(store.users).to.have.length(0)
|
||||||
expect(store.usersByName).to.have.length(0)
|
expect(store.usersByName).to.have.length(0)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue