diff --git a/src/app/modules/main/activity_center/controller.nim b/src/app/modules/main/activity_center/controller.nim index a058c9d903..86c2bb2f09 100644 --- a/src/app/modules/main/activity_center/controller.nim +++ b/src/app/modules/main/activity_center/controller.nim @@ -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) diff --git a/src/app/modules/main/activity_center/model.nim b/src/app/modules/main/activity_center/model.nim index 6757ff0bc5..3ff242ce6b 100644 --- a/src/app/modules/main/activity_center/model.nim +++ b/src/app/modules/main/activity_center/model.nim @@ -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) diff --git a/src/app/modules/main/activity_center/module.nim b/src/app/modules/main/activity_center/module.nim index 8bd152f52c..507b3a7432 100644 --- a/src/app/modules/main/activity_center/module.nim +++ b/src/app/modules/main/activity_center/module.nim @@ -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() diff --git a/src/app/modules/main/activity_center/view.nim b/src/app/modules/main/activity_center/view.nim index faad8b9efd..81e340fec6 100644 --- a/src/app/modules/main/activity_center/view.nim +++ b/src/app/modules/main/activity_center/view.nim @@ -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) diff --git a/ui/app/mainui/activitycenter/popups/ActivityCenterPopup.qml b/ui/app/mainui/activitycenter/popups/ActivityCenterPopup.qml index 76169497c6..18aa40c187 100644 --- a/ui/app/mainui/activitycenter/popups/ActivityCenterPopup.qml +++ b/ui/app/mainui/activitycenter/popups/ActivityCenterPopup.qml @@ -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 diff --git a/ui/app/mainui/activitycenter/stores/ActivityCenterStore.qml b/ui/app/mainui/activitycenter/stores/ActivityCenterStore.qml index 3cb4362017..48b7175b65 100644 --- a/ui/app/mainui/activitycenter/stores/ActivityCenterStore.qml +++ b/ui/app/mainui/activitycenter/stores/ActivityCenterStore.qml @@ -105,4 +105,8 @@ QtObject { function setActivityCenterReadType(readType) { root.activityCenterModuleInst.setActivityCenterReadType(readType) } + + function fetchActivityCenterNotifications() { + root.activityCenterModuleInst.fetchActivityCenterNotifications() + } } diff --git a/ui/app/mainui/activitycenter/views/ActivityNotificationCommunityMembershipRequest.qml b/ui/app/mainui/activitycenter/views/ActivityNotificationCommunityMembershipRequest.qml index 6c88b533ae..39107dcdd5 100644 --- a/ui/app/mainui/activitycenter/views/ActivityNotificationCommunityMembershipRequest.qml +++ b/ui/app/mainui/activitycenter/views/ActivityNotificationCommunityMembershipRequest.qml @@ -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 diff --git a/ui/app/mainui/activitycenter/views/ActivityNotificationMessage.qml b/ui/app/mainui/activitycenter/views/ActivityNotificationMessage.qml index 4924caec9c..6d412c943c 100644 --- a/ui/app/mainui/activitycenter/views/ActivityNotificationMessage.qml +++ b/ui/app/mainui/activitycenter/views/ActivityNotificationMessage.qml @@ -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) : ""