Skip to content

Commit

Permalink
feat(ActivityCenter): load new notifications on scroll to bottom (#12712
Browse files Browse the repository at this point in the history
)

Close #9637
  • Loading branch information
MishkaRogachev committed Nov 15, 2023
1 parent b315d8b commit 53d19b0
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 36 deletions.
30 changes: 17 additions & 13 deletions src/app/modules/main/activity_center/controller.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)

Expand All @@ -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)
Expand Down
47 changes: 30 additions & 17 deletions src/app/modules/main/activity_center/model.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
3 changes: 1 addition & 2 deletions src/app/modules/main/activity_center/module.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
4 changes: 2 additions & 2 deletions src/app/modules/main/activity_center/view.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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.} =
Expand Down Expand Up @@ -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)
Expand Down
13 changes: 13 additions & 0 deletions ui/app/mainui/activitycenter/popups/ActivityCenterPopup.qml
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -79,6 +89,7 @@ Popup {

StatusListView {
id: listView

anchors.left: parent.left
anchors.right: parent.right
anchors.top: activityCenterTopBar.bottom
Expand All @@ -88,6 +99,8 @@ Popup {

model: root.activityCenterStore.activityCenterNotifications

onContentYChanged: d.loadMoreNotificationsIfScrollBelowThreshold()

delegate: Loader {
width: listView.availableWidth

Expand Down
4 changes: 4 additions & 0 deletions ui/app/mainui/activitycenter/stores/ActivityCenterStore.qml
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,8 @@ QtObject {
function setActivityCenterReadType(readType) {
root.activityCenterModuleInst.setActivityCenterReadType(readType)
}

function fetchActivityCenterNotifications() {
root.activityCenterModuleInst.fetchActivityCenterNotifications()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) : ""
Expand Down

0 comments on commit 53d19b0

Please sign in to comment.