feat(ActivityCenter): load new notifications on scroll to bottom (#12712)

Close #9637
This commit is contained in:
Mikhail Rogachev 2023-11-15 15:29:03 +04:00 committed by GitHub
parent b315d8b9b8
commit 53d19b0e5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 69 additions and 36 deletions

View File

@ -54,6 +54,7 @@ proc init*(self: Controller) =
self.events.on(activity_center_service.SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_LOADED) do(e: Args):
let args = ActivityCenterNotificationsArgs(e)
self.delegate.addActivityCenterNotifications(args.activityCenterNotifications)
self.updateActivityGroupCounters()
self.events.on(activity_center_service.SIGNAL_MARK_NOTIFICATIONS_AS_ACCEPTED) do(e: Args):
var evArgs = MarkAsAcceptedNotificationProperties(e)
@ -66,8 +67,8 @@ proc init*(self: Controller) =
self.events.on(activity_center_service.SIGNAL_MARK_NOTIFICATIONS_AS_READ) do(e: Args):
var evArgs = MarkAsReadNotificationProperties(e)
if (evArgs.isAll):
self.delegate.markAllActivityCenterNotificationsReadDone()
return
self.delegate.markAllActivityCenterNotificationsReadDone()
return
if (evArgs.notificationIds.len > 0):
self.delegate.markActivityCenterNotificationReadDone(evArgs.notificationIds)
@ -87,48 +88,51 @@ proc init*(self: Controller) =
self.delegate.removeActivityCenterNotifications(evArgs.notificationIds)
proc hasMoreToShow*(self: Controller): bool =
return self.activityCenterService.hasMoreToShow()
return self.activityCenterService.hasMoreToShow()
proc unreadActivityCenterNotificationsCount*(self: Controller): int =
return self.activityCenterService.getUnreadActivityCenterNotificationsCount()
return self.activityCenterService.getUnreadActivityCenterNotificationsCount()
proc hasUnseenActivityCenterNotifications*(self: Controller): bool =
return self.activityCenterService.getHasUnseenActivityCenterNotifications()
return self.activityCenterService.getHasUnseenActivityCenterNotifications()
proc getContactDetails*(self: Controller, contactId: string): ContactDetails =
return self.contactsService.getContactDetails(contactId)
return self.contactsService.getContactDetails(contactId)
proc getCommunityById*(self: Controller, communityId: string): CommunityDto =
return self.communityService.getCommunityById(communityId)
proc getActivityCenterNotifications*(self: Controller): seq[ActivityCenterNotificationDto] =
return self.activityCenterService.getActivityCenterNotifications()
return self.activityCenterService.getActivityCenterNotifications()
proc asyncActivityNotificationLoad*(self: Controller) =
self.activityCenterService.asyncActivityNotificationLoad()
proc markAllActivityCenterNotificationsRead*(self: Controller): string =
return self.activityCenterService.markAllActivityCenterNotificationsRead()
return self.activityCenterService.markAllActivityCenterNotificationsRead()
proc markActivityCenterNotificationRead*(
self: Controller,
notificationId: string,
markAsReadProps: MarkAsReadNotificationProperties
): string =
return self.activityCenterService.markActivityCenterNotificationRead(notificationId, markAsReadProps)
return self.activityCenterService.markActivityCenterNotificationRead(notificationId, markAsReadProps)
proc markActivityCenterNotificationUnread*(
self: Controller,
notificationId: string,
markAsUnreadProps: MarkAsUnreadNotificationProperties
): string =
return self.activityCenterService.markActivityCenterNotificationUnread(notificationId, markAsUnreadProps)
return self.activityCenterService.markActivityCenterNotificationUnread(notificationId, markAsUnreadProps)
proc markAsSeenActivityCenterNotifications*(self: Controller) =
self.activityCenterService.markAsSeenActivityCenterNotifications()
self.activityCenterService.markAsSeenActivityCenterNotifications()
proc acceptActivityCenterNotifications*(self: Controller, notificationIds: seq[string]): string =
return self.activityCenterService.acceptActivityCenterNotifications(notificationIds)
return self.activityCenterService.acceptActivityCenterNotifications(notificationIds)
proc dismissActivityCenterNotifications*(self: Controller, notificationIds: seq[string]): string =
return self.activityCenterService.dismissActivityCenterNotifications(notificationIds)
return self.activityCenterService.dismissActivityCenterNotifications(notificationIds)
proc replacePubKeysWithDisplayNames*(self: Controller, message: string): string =
return self.messageService.replacePubKeysWithDisplayNames(message)

View File

@ -156,27 +156,40 @@ QtObject:
self.activityCenterNotifications = activityCenterNotifications
self.endResetModel()
proc addActivityNotificationItemToList*(self: Model, activityCenterNotification: Item, addToCount: bool = true) =
let modelIndex = newQModelIndex()
defer: modelIndex.delete
self.beginInsertRows(modelIndex, 0, 0)
self.activityCenterNotifications.insert(activityCenterNotification, 0)
proc updateActivityCenterNotification*(self: Model, ind: int, newNotification: Item) =
self.activityCenterNotifications[ind] = newNotification
let index = self.createIndex(ind, 0, nil)
defer: index.delete
self.dataChanged(index, index)
proc upsertActivityCenterNotification*(self: Model, newNotification: Item) =
for i, notification in self.activityCenterNotifications:
if newNotification.id == notification.id:
self.updateActivityCenterNotification(i, newNotification)
return
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
var indexToInsert = self.activityCenterNotifications.len
for i, notification in self.activityCenterNotifications:
if newNotification.timestamp > notification.timestamp:
indexToInsert = i
break
self.beginInsertRows(parentModelIndex, indexToInsert, indexToInsert)
self.activityCenterNotifications.insert(newNotification, indexToInsert)
self.endInsertRows()
if self.activityCenterNotifications.len > 1:
let topLeft = self.createIndex(0, 0, nil)
let bottomRight = self.createIndex(1, 0, nil)
defer: topLeft.delete
defer: bottomRight.delete
self.dataChanged(topLeft, bottomRight, @[NotifRoles.Timestamp.int, NotifRoles.PreviousTimestamp.int])
let indexToUpdate = indexToInsert - 2
if indexToUpdate >= 0 and indexToUpdate < self.activityCenterNotifications.len:
let index = self.createIndex(indexToUpdate, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[NotifRoles.PreviousTimestamp.int])
proc addActivityNotificationItemsToList*(self: Model, activityCenterNotifications: seq[Item]) =
proc upsertActivityCenterNotifications*(self: Model, activityCenterNotifications: seq[Item]) =
if self.activityCenterNotifications.len == 0:
self.setNewData(activityCenterNotifications)
else:
for activityCenterNotification in activityCenterNotifications:
for notif in self.activityCenterNotifications:
if activityCenterNotification.id == notif.id:
self.removeNotifications(@[notif.id])
break
self.addActivityNotificationItemToList(activityCenterNotification, false)
self.upsertActivityCenterNotification(activityCenterNotification)

View File

@ -191,8 +191,7 @@ method convertToItems*(
)
method fetchActivityCenterNotifications*(self: Module) =
let activityCenterNotifications = self.controller.getActivityCenterNotifications()
self.view.addActivityCenterNotifications(self.convertToItems(activityCenterNotifications))
self.controller.asyncActivityNotificationLoad()
method markAllActivityCenterNotificationsRead*(self: Module): string =
self.controller.markAllActivityCenterNotificationsRead()

View File

@ -62,7 +62,7 @@ QtObject:
read = hasUnseenActivityCenterNotifications
notify = hasUnseenActivityCenterNotificationsChanged
proc loadMoreNotifications(self: View) {.slot.} =
proc fetchActivityCenterNotifications(self: View) {.slot.} =
self.delegate.fetchActivityCenterNotifications()
proc markAllActivityCenterNotificationsRead(self: View): string {.slot.} =
@ -136,7 +136,7 @@ QtObject:
self.model.removeNotifications(notificationIds)
proc addActivityCenterNotifications*(self: View, activityCenterNotifications: seq[Item]) =
self.model.addActivityNotificationItemsToList(activityCenterNotifications)
self.model.upsertActivityCenterNotifications(activityCenterNotifications)
proc resetActivityCenterNotifications*(self: View, activityCenterNotifications: seq[Item]) =
self.model.setNewData(activityCenterNotifications)

View File

@ -35,6 +35,16 @@ Popup {
modal: true
parent: Overlay.overlay
QtObject {
id: d
readonly property var loadMoreNotificationsIfScrollBelowThreshold: Backpressure.oneInTimeQueued(root, 100, function() {
if (listView.contentY >= listView.contentHeight - listView.height - 1) {
root.activityCenterStore.fetchActivityCenterNotifications()
}
})
}
Overlay.modal: MouseArea { // eat every event behind the popup
hoverEnabled: true
onPressed: (event) => {
@ -79,6 +89,7 @@ Popup {
StatusListView {
id: listView
anchors.left: parent.left
anchors.right: parent.right
anchors.top: activityCenterTopBar.bottom
@ -88,6 +99,8 @@ Popup {
model: root.activityCenterStore.activityCenterNotifications
onContentYChanged: d.loadMoreNotificationsIfScrollBelowThreshold()
delegate: Loader {
width: listView.availableWidth

View File

@ -105,4 +105,8 @@ QtObject {
function setActivityCenterReadType(readType) {
root.activityCenterModuleInst.setActivityCenterReadType(readType)
}
function fetchActivityCenterNotifications() {
root.activityCenterModuleInst.fetchActivityCenterNotifications()
}
}

View File

@ -43,7 +43,7 @@ ActivityNotificationMessage {
}
ctaComponent: MembershipCta {
membershipStatus: notification && notification.membershipStatus ? notification.membershipStatus : ActivityNotification.MembershipStatus.None
membershipStatus: notification && notification.membershipStatus ? notification.membershipStatus : ActivityCenterStore.ActivityCenterMembershipStatus.None
onAcceptRequestToJoinCommunity: root.store.acceptRequestToJoinCommunity(notification.id, notification.communityId)
onDeclineRequestToJoinCommunity: root.store.declineRequestToJoinCommunity(notification.id, notification.communityId)
//TODO: Get backend value. If the membersip is in acceptedPending or declinedPending state, another user can't accept or decline the request

View File

@ -12,7 +12,7 @@ import utils 1.0
ActivityNotificationBase {
id: root
readonly property bool isOutgoingMessage: notification && notification.message && notification.message.amISender
readonly property bool isOutgoingMessage: notification && notification.message && notification.message.amISender || false
readonly property string contactId: notification ? isOutgoingMessage ? notification.chatId : notification.author : ""
readonly property string contactName: contactDetails ? ProfileUtils.displayName(contactDetails.localNickname, contactDetails.name,
contactDetails.displayName, contactDetails.alias) : ""