diff --git a/src/app/boot/app_controller.nim b/src/app/boot/app_controller.nim index 5d3de1d28c..6fff428b51 100644 --- a/src/app/boot/app_controller.nim +++ b/src/app/boot/app_controller.nim @@ -27,6 +27,7 @@ import ../../app_service/service/stickers/service as stickers_service import ../../app_service/service/about/service as about_service import ../../app_service/service/node_configuration/service as node_configuration_service import ../../app_service/service/network/service as network_service +import ../../app_service/service/activity_center/service as activity_center_service import ../modules/startup/module as startup_module import ../modules/main/module as main_module @@ -89,6 +90,7 @@ type stickersService: stickers_service.Service aboutService: about_service.Service networkService: network_service.Service + activityCenterService: activity_center_service.Service languageService: language_service.Service mnemonicService: mnemonic_service.Service privacyService: privacy_service.Service @@ -140,6 +142,7 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController = result.chatService = chat_service.newService(statusFoundation.status.events, result.contactsService) result.communityService = community_service.newService(result.chatService) result.messageService = message_service.newService(statusFoundation.status.events, statusFoundation.threadpool) + result.activityCenterService = activity_center_service.newService(statusFoundation.status.events, statusFoundation.threadpool, result.chatService) result.tokenService = token_service.newService(statusFoundation.status.events, statusFoundation.threadpool, result.settingsService) result.collectibleService = collectible_service.newService(result.settingsService) @@ -196,7 +199,8 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController = result.mnemonicService, result.privacyService, result.providerService, - result.stickersService + result.stickersService, + result.activityCenterService ) # Do connections @@ -226,6 +230,7 @@ proc delete*(self: AppController) = self.walletAccountService.delete self.aboutService.delete self.networkService.delete + self.activityCenterService.delete self.dappPermissionsService.delete self.providerService.delete self.ensService.delete @@ -270,6 +275,7 @@ proc load(self: AppController) = self.languageService.init() self.stickersService.init() self.networkService.init() + self.activityCenterService.init() let pubKey = self.settingsService.getPublicKey() singletonInstance.localAccountSensitiveSettings.setFileName(pubKey) diff --git a/src/app/core/signals/remote_signals/messages.nim b/src/app/core/signals/remote_signals/messages.nim index 4fbb979c81..5e16f58b60 100644 --- a/src/app/core/signals/remote_signals/messages.nim +++ b/src/app/core/signals/remote_signals/messages.nim @@ -9,6 +9,7 @@ import status/types/community as old_community import ../../../../app_service/service/message/dto/[message, pinned_message, reaction] import ../../../../app_service/service/chat/dto/[chat] import ../../../../app_service/service/community/dto/[community] +import ../../../../app_service/service/activity_center/dto/[notification] import ../../../../app_service/service/contacts/dto/[contacts, status_update] type MessageSignal* = ref object of Signal @@ -20,7 +21,7 @@ type MessageSignal* = ref object of Signal emojiReactions*: seq[ReactionDto] communities*: seq[CommunityDto] membershipRequests*: seq[old_community.CommunityMembershipRequest] - activityCenterNotification*: seq[ActivityCenterNotification] + activityCenterNotifications*: seq[ActivityCenterNotificationDto] statusUpdates*: seq[StatusUpdateDto] deletedMessages*: seq[RemovedMessage] @@ -70,7 +71,7 @@ proc fromEvent*(T: type MessageSignal, event: JsonNode): MessageSignal = if event["event"]{"activityCenterNotifications"} != nil: for jsonNotification in event["event"]["activityCenterNotifications"]: - signal.activityCenterNotification.add(jsonNotification.toActivityCenterNotification()) + signal.activityCenterNotifications.add(jsonNotification.toActivityCenterNotificationDto()) if event["event"]{"pinMessages"} != nil: discard diff --git a/src/app/modules/main/activity_center/controller.nim b/src/app/modules/main/activity_center/controller.nim new file mode 100644 index 0000000000..57e925a635 --- /dev/null +++ b/src/app/modules/main/activity_center/controller.nim @@ -0,0 +1,105 @@ +import Tables, stint +import eventemitter +import ./controller_interface +import ./io_interface + +import ../../../../app/core/signals/types +import ../../../../app_service/service/activity_center/service as activity_center_service +import ../../../../app_service/service/contacts/service as contacts_service +import ../../../../app_service/service/chat/service as chat_service + +export controller_interface + +type + Controller*[T: controller_interface.DelegateInterface] = ref object of controller_interface.AccessInterface + delegate: io_interface.AccessInterface + events: EventEmitter + activityCenterService: activity_center_service.Service + contactsService: contacts_service.Service + +proc newController*[T]( + delegate: io_interface.AccessInterface, + events: EventEmitter, + activityCenterService: activity_center_service.Service, + contactsService: contacts_service.Service + ): Controller[T] = + result = Controller[T]() + result.delegate = delegate + result.events = events + result.activityCenterService = activityCenterService + result.contactsService = contactsService + +method delete*[T](self: Controller[T]) = + discard + +method init*[T](self: Controller[T]) = + self.events.on(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_LOADED) do(e: Args): + let args = ActivityCenterNotificationsArgs(e) + self.delegate.pushActivityCenterNotifications(args.activityCenterNotifications) + + self.events.on(chat_service.SIGNAL_CHAT_UPDATE) do(e: Args): + var evArgs = ChatUpdateArgsNew(e) + if (evArgs.activityCenterNotifications.len > 0): + self.delegate.addActivityCenterNotification(evArgs.activityCenterNotifications) + + self.events.on(activity_center_service.SIGNAL_MARK_NOTIFICATIONS_AS_ACCEPTED) do(e: Args): + var evArgs = MarkAsAcceptedNotificationProperties(e) + self.delegate.acceptActivityCenterNotificationsDone(evArgs.notificationIds) + + self.events.on(activity_center_service.SIGNAL_MARK_NOTIFICATIONS_AS_DISMISSED) do(e: Args): + var evArgs = MarkAsDismissedNotificationProperties(e) + self.delegate.dismissActivityCenterNotificationsDone(evArgs.notificationIds) + + 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 + if (evArgs.notificationIds.len > 0): + self.delegate.markActivityCenterNotificationReadDone(evArgs.notificationIds) + + self.events.on(activity_center_service.SIGNAL_MARK_NOTIFICATIONS_AS_UNREAD) do(e: Args): + var evArgs = MarkAsUnreadNotificationProperties(e) + if (evArgs.notificationIds.len > 0): + self.delegate.markActivityCenterNotificationUnreadDone(evArgs.notificationIds) + + self.events.on(SignalType.Message.event) do(e: Args): + var evArgs = MessageSignal(e) + if (evArgs.activityCenterNotifications.len > 0): + self.delegate.addActivityCenterNotification(evArgs.activityCenterNotifications) + + +method hasMoreToShow*[T](self: Controller[T]): bool = + return self.activityCenterService.hasMoreToShow() + +method unreadActivityCenterNotificationsCount*[T](self: Controller[T]): int = + return self.activityCenterService.unreadActivityCenterNotificationsCount() + +method getContactDetails*[T](self: Controller[T], contactId: string): ContactDetails = + return self.contactsService.getContactDetails(contactId) + +method getActivityCenterNotifications*[T](self: Controller[T]): seq[ActivityCenterNotificationDto] = + return self.activityCenterService.getActivityCenterNotifications() + +method markAllActivityCenterNotificationsRead*[T](self: Controller[T]): string = + return self.activityCenterService.markAllActivityCenterNotificationsRead() + +method markActivityCenterNotificationRead*[T]( + self: Controller[T], + notificationId: string, + markAsReadProps: MarkAsReadNotificationProperties + ): string = + return self.activityCenterService.markActivityCenterNotificationRead(notificationId, markAsReadProps) + +method markActivityCenterNotificationUnread*[T]( + self: Controller[T], + notificationId: string, + markAsUnreadProps: MarkAsUnreadNotificationProperties + ): string = + return self.activityCenterService.markActivityCenterNotificationUnread(notificationId, markAsUnreadProps) + +method acceptActivityCenterNotifications*[T](self: Controller[T], notificationIds: seq[string]): string = + return self.activityCenterService.acceptActivityCenterNotifications(notificationIds) + +method dismissActivityCenterNotifications*[T](self: Controller[T], notificationIds: seq[string]): string = + return self.activityCenterService.dismissActivityCenterNotifications(notificationIds) \ No newline at end of file diff --git a/src/app/modules/main/activity_center/controller_interface.nim b/src/app/modules/main/activity_center/controller_interface.nim new file mode 100644 index 0000000000..71fbd89422 --- /dev/null +++ b/src/app/modules/main/activity_center/controller_interface.nim @@ -0,0 +1,44 @@ +import ../../../../app_service/service/contacts/service as contacts_service +import ../../../../app_service/service/activity_center/service as activity_center_service + +type + AccessInterface* {.pure inheritable.} = ref object of RootObj + ## Abstract class for any input/interaction with this module. + +method delete*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") + +method init*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") + +method hasMoreToShow*(self: AccessInterface): bool {.base.} = + raise newException(ValueError, "No implementation available") + +method unreadActivityCenterNotificationsCount*(self: AccessInterface): int {.base.} = + raise newException(ValueError, "No implementation available") + +method getContactDetails*(self: AccessInterface, contactId: string): ContactDetails {.base.} = + raise newException(ValueError, "No implementation available") + +method getActivityCenterNotifications*(self: AccessInterface): seq[ActivityCenterNotificationDto] {.base.} = + raise newException(ValueError, "No implementation available") + +method markAllActivityCenterNotificationsRead*(self: AccessInterface): string {.base.} = + raise newException(ValueError, "No implementation available") + +method markActivityCenterNotificationRead*(self: AccessInterface, notificationId: string, markAsReadProps: MarkAsReadNotificationProperties): string {.base.} = + raise newException(ValueError, "No implementation available") + +method markActivityCenterNotificationUnread*(self: AccessInterface, notificationId: string, markAsUnreadProps: MarkAsUnreadNotificationProperties): string {.base.} = + raise newException(ValueError, "No implementation available") + +method acceptActivityCenterNotifications*(self: AccessInterface, notificationIds: seq[string]): string {.base.} = + raise newException(ValueError, "No implementation available") + +method dismissActivityCenterNotifications*(self: AccessInterface, notificationIds: seq[string]): string {.base.} = + raise newException(ValueError, "No implementation available") + +type + ## Abstract class (concept) which must be implemented by object/s used in this + ## module. + DelegateInterface* = concept c diff --git a/src/app/modules/main/activity_center/io_interface.nim b/src/app/modules/main/activity_center/io_interface.nim new file mode 100644 index 0000000000..cd02a1a770 --- /dev/null +++ b/src/app/modules/main/activity_center/io_interface.nim @@ -0,0 +1,73 @@ +import Tables, stint +import ./item +import ../../../../app_service/service/activity_center/service as activity_center_service + +type + AccessInterface* {.pure inheritable.} = ref object of RootObj + ## Abstract class for any input/interaction with this module. + +method delete*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") + +method load*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") + +method isLoaded*(self: AccessInterface): bool {.base.} = + raise newException(ValueError, "No implementation available") + +method viewDidLoad*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") + +method hasMoreToShow*(self: AccessInterface): bool {.base.} = + raise newException(ValueError, "No implementation available") + +method unreadActivityCenterNotificationsCount*(self: AccessInterface): int {.base.} = + raise newException(ValueError, "No implementation available") + +method convertToItems*(self: AccessInterface, activityCenterNotifications: seq[ActivityCenterNotificationDto]): seq[Item] {.base.} = + raise newException(ValueError, "No implementation available") + +method getActivityCenterNotifications*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") + +method markAllActivityCenterNotificationsRead*(self: AccessInterface): string {.base.} = + raise newException(ValueError, "No implementation available") + +method markAllActivityCenterNotificationsReadDone*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") + +method dismissActivityCenterNotificationsDone*(self: AccessInterface, notificationIds: seq[string]) {.base.} = + raise newException(ValueError, "No implementation available") + +method markActivityCenterNotificationReadDone*(self: AccessInterface, notificationIds: seq[string]) {.base.} = + raise newException(ValueError, "No implementation available") + +method markActivityCenterNotificationUnreadDone*(self: AccessInterface, notificationIds: seq[string]) {.base.} = + raise newException(ValueError, "No implementation available") + +method acceptActivityCenterNotificationsDone*(self: AccessInterface, notificationIds: seq[string]) {.base.} = + raise newException(ValueError, "No implementation available") + +method markActivityCenterNotificationRead*(self: AccessInterface, notificationId: string, communityId: string, channelId: string, nType: int): string {.base.} = + raise newException(ValueError, "No implementation available") + +method markActivityCenterNotificationUnread*(self: AccessInterface, notificationId: string, communityId: string, channelId: string, nType: int): string {.base.} = + raise newException(ValueError, "No implementation available") + +method pushActivityCenterNotifications*(self: AccessInterface, activityCenterNotifications: seq[ActivityCenterNotificationDto]) {.base.} = + raise newException(ValueError, "No implementation available") + +method addActivityCenterNotification*(self: AccessInterface, activityCenterNotifications: seq[ActivityCenterNotificationDto]) {.base.} = + raise newException(ValueError, "No implementation available") + +method acceptActivityCenterNotifications*(self: AccessInterface, notificationIds: seq[string]): string {.base.} = + raise newException(ValueError, "No implementation available") + +method dismissActivityCenterNotifications*(self: AccessInterface, notificationIds: seq[string]): string {.base.} = + raise newException(ValueError, "No implementation available") + +type + ## Abstract class (concept) which must be implemented by object/s used in this + ## module. + DelegateInterface* = concept c + c.activityCenterDidLoad() diff --git a/src/app/modules/main/activity_center/item.nim b/src/app/modules/main/activity_center/item.nim new file mode 100644 index 0000000000..06917b9422 --- /dev/null +++ b/src/app/modules/main/activity_center/item.nim @@ -0,0 +1,85 @@ +import strformat, stint +import ../../shared_models/message_item_qobject + +type Item* = ref object + id: string # ID is the id of the chat, for public chats it is the name e.g. status, for one-to-one is the hex encoded public key and for group chats is a random uuid appended with the hex encoded pk of the creator of the chat + chatId: string + name: string + author: string + notificationType: int + timestamp: int64 + read: bool + dismissed: bool + accepted: bool + messageItem: MessageItem + +proc initItem*( + id: string, + chatId: string, + name: string, + author: string, + notificationType: int, + timestamp: int64, + read: bool, + dismissed: bool, + accepted: bool, + messageItem: MessageItem +): Item = + result = Item() + result.id = id + result.chatId = chatId + result.name = name + result.author = author + result.notificationType = notificationType + result.timestamp = timestamp + result.read = read + result.dismissed = dismissed + result.accepted = accepted + result.messageItem = messageItem + +proc `$`*(self: Item): string = + result = fmt"""StickerItem( + id: {self.id}, + name: {$self.name}, + chatId: {$self.chatId}, + author: {$self.author}, + notificationType: {$self.notificationType}, + timestamp: {$self.timestamp}, + read: {$self.read}, + dismissed: {$self.dismissed}, + accepted: {$self.accepted}, + # messageItem: {$self.messageItem}, + ]""" + +proc id*(self: Item): string = + return self.id + +proc name*(self: Item): string = + return self.name + +proc author*(self: Item): string = + return self.author + +proc chatId*(self: Item): string = + return self.chatId + +proc notificationType*(self: Item): int = + return self.notificationType + +proc timestamp*(self: Item): int64 = + return self.timestamp + +proc read*(self: Item): bool = + return self.read + +proc `read=`*(self: Item, value: bool) = + self.read = value + +proc dismissed*(self: Item): bool = + return self.dismissed + +proc accepted*(self: Item): bool = + return self.accepted + +proc messageItem*(self: Item): MessageItem = + return self.messageItem diff --git a/src/app/modules/main/activity_center/model.nim b/src/app/modules/main/activity_center/model.nim new file mode 100644 index 0000000000..5959495b95 --- /dev/null +++ b/src/app/modules/main/activity_center/model.nim @@ -0,0 +1,196 @@ +import NimQml, Tables, chronicles, json, sequtils, strformat, strutils +import ./item + +type + NotifRoles {.pure.} = enum + Id = UserRole + 1 + ChatId = UserRole + 2 + Name = UserRole + 3 + NotificationType = UserRole + 4 + Message = UserRole + 5 + Timestamp = UserRole + 6 + Read = UserRole + 7 + Dismissed = UserRole + 8 + Accepted = UserRole + 9 + Author = UserRole + 10 + +QtObject: + type + Model* = ref object of QAbstractListModel + activityCenterNotifications*: seq[Item] + nbUnreadNotifications*: int + + proc setup(self: Model) = self.QAbstractListModel.setup + + proc delete(self: Model) = + self.activityCenterNotifications = @[] + self.QAbstractListModel.delete + + proc newModel*(): Model = + new(result, delete) + result.activityCenterNotifications = @[] + result.setup() + + proc getUnreadNotificationsForChat*(self: Model, chatId: string): seq[string] = + result = @[] + for notification in self.activityCenterNotifications: + if (notification.chatId == chatId and not notification.read): + result.add(notification.id) + + proc unreadCountChanged*(self: Model) {.signal.} + + proc unreadCount*(self: Model): int {.slot.} = + self.nbUnreadNotifications + + QtProperty[int] unreadCount: + read = unreadCount + notify = unreadCountChanged + + proc markAllAsRead*(self: Model) = + self.nbUnreadNotifications = 0 + self.unreadCountChanged() + + for activityCenterNotification in self.activityCenterNotifications: + activityCenterNotification.read = true + + let topLeft = self.createIndex(0, 0, nil) + let bottomRight = self.createIndex(self.activityCenterNotifications.len - 1, 0, nil) + self.dataChanged(topLeft, bottomRight, @[NotifRoles.Read.int]) + + method rowCount*(self: Model, index: QModelIndex = nil): int = self.activityCenterNotifications.len + + method data(self: Model, index: QModelIndex, role: int): QVariant = + if not index.isValid: + return + if index.row < 0 or index.row >= self.activityCenterNotifications.len: + return + + let acitivityNotificationItem = self.activityCenterNotifications[index.row] + let communityItemRole = role.NotifRoles + case communityItemRole: + of NotifRoles.Id: result = newQVariant(acitivityNotificationItem.id) + of NotifRoles.ChatId: result = newQVariant(acitivityNotificationItem.chatId) + of NotifRoles.Name: result = newQVariant(acitivityNotificationItem.name) + of NotifRoles.Author: result = newQVariant(acitivityNotificationItem.author) + of NotifRoles.NotificationType: result = newQVariant(acitivityNotificationItem.notificationType.int) + of NotifRoles.Message: result = newQVariant(acitivityNotificationItem.messageItem) + of NotifRoles.Timestamp: result = newQVariant(acitivityNotificationItem.timestamp) + of NotifRoles.Read: result = newQVariant(acitivityNotificationItem.read.bool) + of NotifRoles.Dismissed: result = newQVariant(acitivityNotificationItem.dismissed.bool) + of NotifRoles.Accepted: result = newQVariant(acitivityNotificationItem.accepted.bool) + + proc getNotificationData(self: Model, index: int, data: string): string {.slot.} = + if index < 0 or index >= self.activityCenterNotifications.len: return ("") + + let notif = self.activityCenterNotifications[index] + case data: + of "id": result = notif.id + of "chatId": result = notif.chatId + of "name": result = notif.name + of "author": result = notif.author + of "notificationType": result = $(notif.notificationType.int) + of "timestamp": result = $(notif.timestamp) + of "read": result = $(notif.read) + of "dismissed": result = $(notif.dismissed) + of "accepted": result = $(notif.accepted) + else: result = ("") + + method roleNames(self: Model): Table[int, string] = + { + NotifRoles.Id.int:"id", + NotifRoles.ChatId.int:"chatId", + NotifRoles.Name.int: "name", + NotifRoles.Author.int: "author", + NotifRoles.NotificationType.int: "notificationType", + NotifRoles.Message.int: "message", + NotifRoles.Timestamp.int: "timestamp", + NotifRoles.Read.int: "read", + NotifRoles.Dismissed.int: "dismissed", + NotifRoles.Accepted.int: "accepted" + }.toTable + + proc reduceUnreadCount(self: Model, numberNotifs: int) = + self.nbUnreadNotifications = self.nbUnreadNotifications - numberNotifs + if (self.nbUnreadNotifications < 0): + self.nbUnreadNotifications = 0 + self.unreadCountChanged() + + proc markActivityCenterNotificationUnread*(self: Model, notificationId: string) = + self.nbUnreadNotifications = self.nbUnreadNotifications + 1 + self.unreadCountChanged() + + var i = 0 + for acnViewItem in self.activityCenterNotifications: + if (acnViewItem.id == notificationId): + acnViewItem.read = false + let index = self.createIndex(i, 0, nil) + self.dataChanged(index, index, @[NotifRoles.Read.int]) + break + i.inc + + proc markActivityCenterNotificationRead*(self: Model, notificationId: string) = + self.nbUnreadNotifications = self.nbUnreadNotifications - 1 + if (self.nbUnreadNotifications < 0): + self.nbUnreadNotifications = 0 + self.unreadCountChanged() + + var i = 0 + for acnViewItem in self.activityCenterNotifications: + if (acnViewItem.id == notificationId): + acnViewItem.read = true + let index = self.createIndex(i, 0, nil) + self.dataChanged(index, index, @[NotifRoles.Read.int]) + break + i.inc + + proc removeNotifications*(self: Model, ids: seq[string]) = + var i = 0 + var indexesToDelete: seq[int] = @[] + for activityCenterNotification in self.activityCenterNotifications: + for id in ids: + if (activityCenterNotification.id == id): + indexesToDelete.add(i) + break + i = i + 1 + + i = 0 + for index in indexesToDelete: + let indexUpdated = index - i + self.beginRemoveRows(newQModelIndex(), indexUpdated, indexUpdated) + self.activityCenterNotifications.delete(indexUpdated) + self.endRemoveRows() + i = i + 1 + + self.reduceUnreadCount(ids.len) + + proc setNewData*(self: Model, activityCenterNotifications: seq[Item]) = + self.beginResetModel() + self.activityCenterNotifications = activityCenterNotifications + self.endResetModel() + + proc addActivityNotificationItemToList*(self: Model, activityCenterNotification: Item, addToCount: bool = true) = + self.beginInsertRows(newQModelIndex(), self.activityCenterNotifications.len, self.activityCenterNotifications.len) + + self.activityCenterNotifications.add(activityCenterNotification) + + self.endInsertRows() + + if (addToCount and not activityCenterNotification.read): + self.nbUnreadNotifications = self.nbUnreadNotifications + 1 + + proc updateUnreadCount*(self: Model, count: int) = + self.nbUnreadNotifications = count + self.unreadCountChanged() + + proc addActivityNotificationItemsToList*(self: Model, activityCenterNotifications: seq[Item]) = + if (self.activityCenterNotifications.len == 0): + self.setNewData(activityCenterNotifications) + else: + for activityCenterNotification in activityCenterNotifications: + var found = false + for notif in self.activityCenterNotifications: + if activityCenterNotification.id == notif.id: + found = true + break + if found: continue + self.addActivityNotificationItemToList(activityCenterNotification, false) diff --git a/src/app/modules/main/activity_center/module.nim b/src/app/modules/main/activity_center/module.nim new file mode 100644 index 0000000000..8ddbf50fad --- /dev/null +++ b/src/app/modules/main/activity_center/module.nim @@ -0,0 +1,176 @@ +import NimQml, Tables, stint, sugar, sequtils + +import eventemitter +import ./io_interface, ./view, ./controller +import ./item as notification_item +import ../../shared_models/message_item as message_item +import ../../shared_models/message_item_qobject as message_item_qobject +import ../../../global/global_singleton +import ../../../../app_service/service/activity_center/service as activity_center_service +import ../../../../app_service/service/contacts/service as contacts_service + +export io_interface + +type + Module* [T: io_interface.DelegateInterface] = ref object of io_interface.AccessInterface + delegate: T + controller: controller.AccessInterface + view: View + viewVariant: QVariant + moduleLoaded: bool + +proc newModule*[T]( + delegate: T, + events: EventEmitter, + activityCenterService: activity_center_service.Service, + contactsService: contacts_service.Service + ): Module[T] = + result = Module[T]() + result.delegate = delegate + result.view = newView(result) + result.viewVariant = newQVariant(result.view) + result.controller = controller.newController[Module[T]]( + result, + events, + activityCenterService, + contactsService + ) + result.moduleLoaded = false + +method delete*[T](self: Module[T]) = + self.view.delete + +method load*[T](self: Module[T]) = + singletonInstance.engine.setRootContextProperty("activityCenterModule", self.viewVariant) + self.controller.init() + self.view.load() + +method isLoaded*[T](self: Module[T]): bool = + return self.moduleLoaded + +method viewDidLoad*[T](self: Module[T]) = + self.moduleLoaded = true + self.delegate.activityCenterDidLoad() + +method hasMoreToShow*[T](self: Module[T]): bool = + self.controller.hasMoreToShow() + +method unreadActivityCenterNotificationsCount*[T](self: Module[T]): int = + self.controller.unreadActivityCenterNotificationsCount() + +method convertToItems*[T]( + self: Module[T], + activityCenterNotifications: seq[ActivityCenterNotificationDto] + ): seq[notification_item.Item] = + result = activityCenterNotifications.map( + proc(n: ActivityCenterNotificationDto): Item = + var messageItem = MessageItem() + if (n.message.id == ""): + # If there is a message in the Notification, transfer it to a MessageItem (QObject) + let contactDetails = self.controller.getContactDetails(n.message.`from`) + messageItem = message_item_qobject.newMessageItem(initItem( + n.message.id, + n.message.responseTo, + n.message.`from`, + contactDetails.displayName, + contactDetails.localNickname, + contactDetails.icon, + contactDetails.isIconIdenticon, + contactDetails.isCurrentUser, + n.message.outgoingStatus, + n.message.text, + n.message.image, + n.message.seen, + n.message.timestamp, + ContentType(n.message.contentType), + n.message.messageType + )) + + return notification_item.initItem( + n.id, + n.chatId, + n.name, + n.author, + n.notificationType.int, + n.timestamp, + n.read, + n.dismissed, + n.accepted, + messageItem + ) + ) + +method getActivityCenterNotifications*[T](self: Module[T]): seq[notification_item.Item] = + let activityCenterNotifications = self.controller.getActivityCenterNotifications() + self.view.pushActivityCenterNotifications(self.convertToItems(activityCenterNotifications)) + +method markAllActivityCenterNotificationsRead*[T](self: Module[T]): string = + self.controller.markAllActivityCenterNotificationsRead() + +method markAllActivityCenterNotificationsReadDone*[T](self: Module[T]): string = + self.view.markAllActivityCenterNotificationsReadDone() + +method markActivityCenterNotificationRead*[T]( + self: Module[T], + notificationId: string, + communityId: string, + channelId: string, + nType: int + ): string = + let notificationType = ActivityCenterNotificationType(nType) + let markAsReadProps = MarkAsReadNotificationProperties( + notificationIds: @[notificationId], + communityId: communityId, + channelId: channelId, + notificationTypes: @[notificationType] + ) + result = self.controller.markActivityCenterNotificationRead(notificationId, markAsReadProps) + +method markActivityCenterNotificationReadDone*[T](self: Module[T], notificationIds: seq[string]) = + for notificationId in notificationIds: + self.view.markActivityCenterNotificationReadDone(notificationId) + +method pushActivityCenterNotifications*[T]( + self: Module[T], + activityCenterNotifications: seq[ActivityCenterNotificationDto] + ) = + self.view.pushActivityCenterNotifications(self.convertToItems(activityCenterNotifications)) + +method addActivityCenterNotification*[T]( + self: Module[T], + activityCenterNotifications: seq[ActivityCenterNotificationDto] + ) = + self.view.addActivityCenterNotification(self.convertToItems(activityCenterNotifications)) + +method markActivityCenterNotificationUnread*[T]( + self: Module[T], + notificationId: string, + communityId: string, + channelId: string, + nType: int + ): string = + let notificationType = ActivityCenterNotificationType(nType) + let markAsUnreadProps = MarkAsUnreadNotificationProperties( + notificationIds: @[notificationId], + communityId: communityId, + channelId: channelId, + notificationTypes: @[notificationType] + ) + + result = self.controller.markActivityCenterNotificationUnread(notificationId, markAsUnreadProps) + +method markActivityCenterNotificationUnreadDone*[T](self: Module[T], notificationIds: seq[string]) = + for notificationId in notificationIds: + self.view.markActivityCenterNotificationUnreadDone(notificationId) + +method acceptActivityCenterNotificationsDone*[T](self: Module[T], notificationIds: seq[string]) = + self.view.acceptActivityCenterNotificationsDone(notificationIds) + +method acceptActivityCenterNotifications*[T](self: Module[T], notificationIds: seq[string]): string = + self.controller.acceptActivityCenterNotifications(notificationIds) + +method dismissActivityCenterNotificationsDone*[T](self: Module[T], notificationIds: seq[string]) = + self.view.dismissActivityCenterNotificationsDone(notificationIds) + +method dismissActivityCenterNotifications*[T](self: Module[T], notificationIds: seq[string]): string = + self.controller.dismissActivityCenterNotifications(notificationIds) diff --git a/src/app/modules/main/activity_center/view.nim b/src/app/modules/main/activity_center/view.nim new file mode 100644 index 0000000000..6d8fa4bbbc --- /dev/null +++ b/src/app/modules/main/activity_center/view.nim @@ -0,0 +1,128 @@ +import NimQml, json, strutils, json_serialization, sequtils, strformat +import ../../../../app_service/service/activity_center/service as activity_center_service + +import ./model +import ./io_interface, ./item + +QtObject: + type + View* = ref object of QObject + delegate: io_interface.AccessInterface + model: Model + modelVariant: QVariant + + proc delete*(self: View) = + self.QObject.delete + + proc newView*(delegate: io_interface.AccessInterface): View = + new(result, delete) + result.QObject.setup + result.delegate = delegate + result.model = newModel() + result.modelVariant = newQVariant(result.model) + + proc load*(self: View) = + self.delegate.viewDidLoad() + + proc activityNotificationsChanged*(self: View) {.signal.} + + proc getModel(self: View): QVariant {.slot.} = + return newQVariant(self.modelVariant) + + QtProperty[QVariant] model: + read = getModel + notify = activityNotificationsChanged + + proc hasMoreToShowChanged*(self: View) {.signal.} + + proc hasMoreToShow*(self: View): bool {.slot.} = + self.delegate.hasMoreToShow() + + QtProperty[bool] hasMoreToShow: + read = hasMoreToShow + notify = hasMoreToShowChanged + + proc pushActivityCenterNotifications*(self:View, activityCenterNotifications: seq[Item]) = + self.model.addActivityNotificationItemsToList(activityCenterNotifications) + self.activityNotificationsChanged() + self.hasMoreToShowChanged() + + let count = self.delegate.unreadActivityCenterNotificationsCount() + self.model.updateUnreadCount(count) + + proc loadMoreNotifications(self: View) {.slot.} = + self.delegate.getActivityCenterNotifications() + + proc markAllActivityCenterNotificationsRead(self: View): string {.slot.} = + result = self.delegate.markAllActivityCenterNotificationsRead() + + proc markAllActivityCenterNotificationsReadDone*(self: View) {.slot.} = + self.model.markAllAsRead() + + proc markActivityCenterNotificationRead( + self: View, + notificationId: string, + communityId: string, + channelId: string, + nType: int + ): void {.slot.} = + discard self.delegate.markActivityCenterNotificationRead(notificationId, communityId, channelId, nType) + + proc markActivityCenterNotificationReadDone*(self: View, notificationId: string) = + self.model.markActivityCenterNotificationRead(notificationId) + + proc markActivityCenterNotificationUnreadDone*(self: View, notificationId: string) = + self.model.markActivityCenterNotificationUnread(notificationId) + + proc markAllChatMentionsAsRead*(self: View, communityId: string, chatId: string) = + let notifsIds = self.model.getUnreadNotificationsForChat(chatId) + for notifId in notifsIds: + # TODO change the 3 to the real type + self.markActivityCenterNotificationRead(notifId, communityId, chatId, ActivityCenterNotificationType.Mention.int) + + proc markActivityCenterNotificationUnread( + self: View, + notificationId: string, + communityId: string, + channelId: string, + nType: int + ): void {.slot.} = + discard self.delegate.markActivityCenterNotificationUnread( + notificationId, + communityId, + channelId, + nType + ) + + proc acceptActivityCenterNotifications(self: View, idsJson: string): string {.slot.} = + let ids = map(parseJson(idsJson).getElems(), proc(x:JsonNode):string = x.getStr()) + + result = self.delegate.acceptActivityCenterNotifications(ids) + + proc acceptActivityCenterNotificationsDone*(self: View, notificationIds: seq[string]) = + self.model.removeNotifications(notificationIds) + + proc acceptActivityCenterNotification(self: View, id: string): string {.slot.} = + self.acceptActivityCenterNotifications(fmt"[""{id}""]") + + proc dismissActivityCenterNotifications(self: View, idsJson: string): string {.slot.} = + let ids = map(parseJson(idsJson).getElems(), proc(x:JsonNode):string = x.getStr()) + + result = self.delegate.dismissActivityCenterNotifications(ids) + + proc dismissActivityCenterNotification(self: View, id: string): string {.slot.} = + self.dismissActivityCenterNotifications(fmt"[""{id}""]") + + proc dismissActivityCenterNotificationsDone*(self: View, notificationIds: seq[string]) = + self.model.removeNotifications(notificationIds) + + proc addActivityCenterNotification*(self: View, activityCenterNotifications: seq[Item]) = + for activityCenterNotification in activityCenterNotifications: + # TODO this should be handled by the chat or community module + # if self.channelView.activeChannel.id == activityCenterNotification.chatId: + # activityCenterNotification.read = true + # let communityId = self.status.chat.getCommunityIdForChat(activityCenterNotification.chatId) + # if communityId != "": + # self.communities.joinedCommunityList.decrementMentions(communityId, activityCenterNotification.chatId) + self.model.addActivityNotificationItemToList(activityCenterNotification) + self.activityNotificationsChanged() diff --git a/src/app/modules/main/chat_section/chat_content/controller.nim b/src/app/modules/main/chat_section/chat_content/controller.nim index 58cb183c4b..84287588c4 100644 --- a/src/app/modules/main/chat_section/chat_content/controller.nim +++ b/src/app/modules/main/chat_section/chat_content/controller.nim @@ -103,4 +103,7 @@ method unmuteChat*(self: Controller) = self.chatService.unmuteChat(self.chatId) method getContactById*(self: Controller, contactId: string): ContactsDto = - return self.contactService.getContactById(contactId) \ No newline at end of file + return self.contactService.getContactById(contactId) + +method getContactDetails*(self: Controller, contactId: string): ContactDetails = + return self.contactService.getContactDetails(contactId) \ No newline at end of file diff --git a/src/app/modules/main/chat_section/chat_content/controller_interface.nim b/src/app/modules/main/chat_section/chat_content/controller_interface.nim index 3ace881ee4..d1c9b28ec4 100644 --- a/src/app/modules/main/chat_section/chat_content/controller_interface.nim +++ b/src/app/modules/main/chat_section/chat_content/controller_interface.nim @@ -1,6 +1,7 @@ import ../../../../../app_service/service/contacts/dto/[contacts] import ../../../../../app_service/service/message/dto/[message, reaction] import ../../../../../app_service/service/chat/dto/[chat] +import ../../../../../app_service/service/contacts/service type AccessInterface* {.pure inheritable.} = ref object of RootObj @@ -42,4 +43,7 @@ method unmuteChat*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") method getContactById*(self: AccessInterface, contactId: string): ContactsDto {.base.} = + raise newException(ValueError, "No implementation available") + +method getContactDetails*(self: AccessInterface, contactId: string): ContactDetails {.base.} = raise newException(ValueError, "No implementation available") \ No newline at end of file diff --git a/src/app/modules/main/chat_section/chat_content/module.nim b/src/app/modules/main/chat_section/chat_content/module.nim index 6a357f197a..c899e46b98 100644 --- a/src/app/modules/main/chat_section/chat_content/module.nim +++ b/src/app/modules/main/chat_section/chat_content/module.nim @@ -128,18 +128,25 @@ proc buildPinnedMessageItem(self: Module, messageId: string, item: var pinned_ms if(err.len > 0): return false - let sender = self.controller.getContactById(m.`from`) - let senderDisplayName = sender.userNameOrAlias() - let amISender = m.`from` == singletonInstance.userProfile.getPubKey() - var senderIcon = sender.identicon - var isSenderIconIdenticon = sender.identicon.len > 0 - if(sender.image.thumbnail.len > 0): - senderIcon = sender.image.thumbnail - isSenderIconIdenticon = false + let contactDetails = self.controller.getContactDetails(m.`from`) - var item = initItem(m.id, m.responseTo, m.`from`, senderDisplayName, sender.localNickname, senderIcon, - isSenderIconIdenticon, amISender, m.outgoingStatus, m.text, m.image, m.seen, m.timestamp, m.contentType.ContentType, - m.messageType) + var item = initItem( + m.id, + m.responseTo, + m.`from`, + contactDetails.displayName, + contactDetails.localNickname, + contactDetails.icon, + contactDetails.isIconIdenticon, + contactDetails.isCurrentUser, + m.outgoingStatus, + m.text, + m.image, + m.seen, + m.timestamp, + m.contentType.ContentType, + m.messageType + ) item.pinned = true for r in reactions: diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim index ae9bd3d6a4..e5b0efd0b6 100644 --- a/src/app/modules/main/module.nim +++ b/src/app/modules/main/module.nim @@ -10,6 +10,7 @@ import browser_section/module as browser_section_module import profile_section/module as profile_section_module import app_search/module as app_search_module import stickers/module as stickers_module +import activity_center/module as activity_center_module import ../../../app_service/service/keychain/service as keychain_service import ../../../app_service/service/chat/service as chat_service @@ -31,6 +32,7 @@ import ../../../app_service/service/language/service as language_service import ../../../app_service/service/mnemonic/service as mnemonic_service import ../../../app_service/service/privacy/service as privacy_service import ../../../app_service/service/stickers/service as stickers_service +import ../../../app_service/service/activity_center/service as activity_center_service import eventemitter @@ -48,6 +50,7 @@ type browserSectionModule: browser_section_module.AccessInterface profileSectionModule: profile_section_module.AccessInterface stickersModule: stickers_module.AccessInterface + activityCenterModule: activity_center_module.AccessInterface appSearchModule: app_search_module.AccessInterface moduleLoaded: bool @@ -73,7 +76,8 @@ proc newModule*[T]( mnemonicService: mnemonic_service.ServiceInterface, privacyService: privacy_service.ServiceInterface, providerService: provider_service.ServiceInterface, - stickersService: stickers_service.Service + stickersService: stickers_service.Service, + activityCenterService: activity_center_service.Service ): Module[T] = result = Module[T]() result.delegate = delegate @@ -94,6 +98,7 @@ proc newModule*[T]( result.profileSectionModule = profile_section_module.newModule(result, events, accountsService, settingsService, profileService, contactsService, aboutService, languageService, mnemonicService, privacyService) result.stickersModule = stickers_module.newModule(result, events, stickersService) + result.activityCenterModule = activity_center_module.newModule(result, events, activityCenterService, contactsService) result.appSearchModule = app_search_module.newModule(result, events, contactsService, chatService, communityService, messageService) @@ -101,6 +106,7 @@ method delete*[T](self: Module[T]) = self.chatSectionModule.delete self.profileSectionModule.delete self.stickersModule.delete + self.activityCenterModule.delete for cModule in self.communitySectionsModule.values: cModule.delete self.communitySectionsModule.clear @@ -213,6 +219,7 @@ method load*[T]( # self.nodeManagementSectionModule.load() self.profileSectionModule.load() self.stickersModule.load() + self.activityCenterModule.load() self.appSearchModule.load() # Set active section on app start @@ -241,6 +248,9 @@ proc checkIfModuleDidLoad [T](self: Module[T]) = if(not self.stickersModule.isLoaded()): return + if(not self.activityCenterModule.isLoaded()): + return + if(not self.appSearchModule.isLoaded()): return @@ -259,6 +269,9 @@ method appSearchDidLoad*[T](self: Module[T]) = proc stickersDidLoad*[T](self: Module[T]) = self.checkIfModuleDidLoad() +proc activityCenterDidLoad*[T](self: Module[T]) = + self.checkIfModuleDidLoad() + proc walletSectionDidLoad*[T](self: Module[T]) = self.checkIfModuleDidLoad() diff --git a/src/app/modules/shared_models/contact_item.nim b/src/app/modules/shared_models/contact_item.nim new file mode 100644 index 0000000000..1b5204aba4 --- /dev/null +++ b/src/app/modules/shared_models/contact_item.nim @@ -0,0 +1,102 @@ +import Tables, json + +type + ImageItem* = object + thumbnail*: string + large*: string + +proc initImageItem*( + thumbnail: string, + large: string + ): ImageItem = + result = ImageItem() + result.thumbnail = thumbnail + result.large = large + +proc thumbnail*(self: ImageItem): string {.inline.} = + self.thumbnail + +proc large*(self: ImageItem): string {.inline.} = + self.large + +type + Item* = ref object + id: string + name: string + ensVerified: bool + alias: string + identicon: string + lastUpdated: int64 + lastUpdatedLocally: int64 + localNickname: string + image: ImageItem + added: bool + blocked: bool + isSyncing: bool + hasAddedUs: bool + removed: bool + +proc initItem*( + id: string, + name: string, + ensVerified: bool, + alias: string, + identicon: string, + lastUpdated: int64, + lastUpdatedLocally: int64, + image: ImageItem, + added: bool, + blocked: bool, + isSyncing: bool, + hasAddedUs: bool, + removed: bool + ): Item = + result = Item() + result.id = id + result.name = name + result.ensVerified = ensVerified + result.alias = alias + result.lastUpdated = lastUpdated + result.lastUpdatedLocally = lastUpdatedLocally + result.image = image + result.added = added + result.blocked = blocked + result.isSyncing = isSyncing + result.hasAddedUs = hasAddedUs + result.removed = removed + +proc id*(self: Item): string {.inline.} = + self.id + +proc name*(self: Item): string {.inline.} = + self.name + +proc ensVerified*(self: Item): bool {.inline.} = + self.ensVerified + +proc alias*(self: Item): string {.inline.} = + self.alias + +proc lastUpdated*(self: Item): int64 {.inline.} = + self.lastUpdated + +proc lastUpdatedLocally*(self: Item): int64 {.inline.} = + self.lastUpdatedLocally + +proc image*(self: Item): ImageItem {.inline.} = + self.image + +proc added*(self: Item): bool {.inline.} = + self.added + +proc blocked*(self: Item): bool {.inline.} = + self.blocked + +proc isSyncing*(self: Item): bool {.inline.} = + self.isSyncing + +proc hasAddedUs*(self: Item): bool {.inline.} = + self.hasAddedUs + +proc removed*(self: Item): bool {.inline.} = + self.removed diff --git a/src/app/modules/shared_models/message_item.nim b/src/app/modules/shared_models/message_item.nim index 6fa99761ef..0f6e186ef6 100644 --- a/src/app/modules/shared_models/message_item.nim +++ b/src/app/modules/shared_models/message_item.nim @@ -66,6 +66,27 @@ proc initItem*(id, responseToMessageWithId, senderId, senderDisplayName, senderL result.messageType = messageType result.pinned = false +proc `$`*(self: Item): string = + result = fmt"""Item( + id: {$self.id}, + responseToMessageWithId: {self.responseToMessageWithId}, + senderId: {self.senderId}, + senderDisplayName: {$self.senderDisplayName}, + senderLocalName: {self.senderLocalName}, + amISender: {$self.amISender}, + isSenderIconIdenticon: {$self.isSenderIconIdenticon}, + seen: {$self.seen}, + outgoingStatus:{$self.outgoingStatus}, + messageText:{self.messageText}, + messageImage:{self.messageImage}, + timestamp:{$self.timestamp}, + contentType:{$self.contentType.int}, + messageType:{$self.messageType}, + chatTypeThisMessageBelongsTo:{self.chatTypeThisMessageBelongsTo}, + chatColorThisMessageBelongsTo:{self.chatColorThisMessageBelongsTo}, + pinned:{$self.pinned} + )""" + proc id*(self: Item): string {.inline.} = self.id @@ -99,6 +120,12 @@ proc messageText*(self: Item): string {.inline.} = proc messageImage*(self: Item): string {.inline.} = self.messageImage +proc stickerPack*(self: Item): int {.inline.} = + self.stickerPack + +proc stickerHash*(self: Item): string {.inline.} = + self.stickerHash + proc seen*(self: Item): bool {.inline.} = self.seen @@ -192,21 +219,6 @@ proc getCountsForReactions*(self: Item): seq[JsonNode] = result.add(%* {"emojiId": k, "counts": v.len}) -proc `$`*(self: Item): string = - result = fmt"""MessageItem( - id: {self.id}, - responseToMessageWithId: {self.responseToMessageWithId}, - senderId: {self.senderId}, - senderDisplayName: {self.senderDisplayName}, - senderLocalName: {self.senderLocalName}, - timestamp: {self.timestamp}, - contentType: {self.contentType.int}, - messageType:{self.messageType}, - chatTypeThisMessageBelongsTo:{self.chatTypeThisMessageBelongsTo}, - chatColorThisMessageBelongsTo:{self.chatColorThisMessageBelongsTo}, - pinned:{self.pinned} - ]""" - proc toJsonNode*(self: Item): JsonNode = result = %* { "id": self.id, diff --git a/src/app/modules/shared_models/message_item_qobject.nim b/src/app/modules/shared_models/message_item_qobject.nim new file mode 100644 index 0000000000..538f4d9d87 --- /dev/null +++ b/src/app/modules/shared_models/message_item_qobject.nim @@ -0,0 +1,111 @@ +import NimQml, std/wrapnils +import ./message_item + +QtObject: + type MessageItem* = ref object of QObject + messageItem*: message_item.Item + + proc setup(self: MessageItem) = + self.QObject.setup + + proc delete*(self: MessageItem) = + self.QObject.delete + + proc newMessageItem*(message: message_item.Item): MessageItem = + new(result, delete) + result.messageItem = message + result.setup + + proc `$`*(self: MessageItem): string = + result = $self.messageItem + + proc setMessageItem*(self: MessageItem, messageItem: message_item.Item) = + self.messageItem = messageItem + + proc responseToMessageWithId*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.responseToMessageWithId + QtProperty[string] responseToMessageWithId: + read = responseToMessageWithId + + proc senderId*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.senderId + QtProperty[string] senderId: + read = senderId + + proc senderDisplayName*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.senderDisplayName + QtProperty[string] senderDisplayName: + read = senderDisplayName + + proc senderLocalName*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.senderLocalName + QtProperty[string] senderLocalName: + read = senderLocalName + + proc amISender*(self: MessageItem): bool {.slot.} = result = ?.self.messageItem.amISender + QtProperty[bool] amISender: + read = amISender + + proc senderIcon*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.senderIcon + QtProperty[string] senderIcon: + read = senderIcon + + proc isSenderIconIdenticon*(self: MessageItem): bool {.slot.} = result = ?.self.messageItem.isSenderIconIdenticon + QtProperty[bool] isSenderIconIdenticon: + read = isSenderIconIdenticon + + proc seen*(self: MessageItem): bool {.slot.} = result = ?.self.messageItem.seen + QtProperty[bool] seen: + read = seen + + proc outgoingStatus*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.outgoingStatus + QtProperty[string] outgoingStatus: + read = outgoingStatus + + proc messageText*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.messageText + QtProperty[string] messageText: + read = messageText + + proc messageImage*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.messageImage + QtProperty[string] messageImage: + read = messageImage + + proc stickerHash*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.stickerHash + QtProperty[string] stickerHash: + read = stickerHash + + proc stickerPack*(self: MessageItem): int {.slot.} = result = ?.self.messageItem.stickerPack + QtProperty[int] stickerPack: + read = stickerPack + + # Convert to int + # proc gapFrom*(self: MessageItem): int64 {.slot.} = result = ?.self.messageItem.gapFrom + # QtProperty[int64] gapFrom: + # read = gapFrom + + # proc gapTo*(self: MessageItem): int64 {.slot.} = result = ?.self.messageItem.gapTo + # QtProperty[int64] gapTo: + # read = gapTo + + # proc timestamp*(self: MessageItem): int64 {.slot.} = result = ?.self.messageItem.timestamp + # QtProperty[int64] timestamp: + # read = timestamp + + proc contentType*(self: MessageItem): int {.slot.} = + if (self.messageItem.isNil): return 0 + result = self.messageItem.contentType.int + QtProperty[int] contentType: + read = contentType + + proc messageType*(self: MessageItem): int {.slot.} = result = ?.self.messageItem.messageType + QtProperty[int] messageType: + read = messageType + + # TODO find a way to pass reactions since they are not basic types (might need to be a Model) + # proc reactions*(self: MessageItem): int {.slot.} = result = ?.self.messageItem.reactions + # QtProperty[int] reactions: + # read = reactions + + # proc reactionIds*(self: MessageItem): int {.slot.} = result = ?.self.messageItem.reactionIds + # QtProperty[int] reactionIds: + # read = reactionIds + + proc pinned*(self: MessageItem): bool {.slot.} = result = ?.self.messageItem.pinned + QtProperty[int] bool: + read = bool \ No newline at end of file diff --git a/src/app_service/service/activity_center/async_tasks.nim b/src/app_service/service/activity_center/async_tasks.nim new file mode 100644 index 0000000000..887f92ad22 --- /dev/null +++ b/src/app_service/service/activity_center/async_tasks.nim @@ -0,0 +1,16 @@ +include ../../common/json_utils +include ../../../app/core/tasks/common + +type + AsyncActivityNotificationLoadTaskArg = ref object of QObjectTaskArg + cursor: string + limit: int + +const asyncActivityNotificationLoadTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[AsyncActivityNotificationLoadTaskArg](argEncoded) + let activityNotificationsCallResult = status_activity_center.rpcActivityCenterNotifications(newJString(arg.cursor), arg.limit) + + let responseJson = %*{ + "activityNotifications": activityNotificationsCallResult.result + } + arg.finish(responseJson) diff --git a/src/app_service/service/activity_center/dto/notification.nim b/src/app_service/service/activity_center/dto/notification.nim new file mode 100644 index 0000000000..01961b54a8 --- /dev/null +++ b/src/app_service/service/activity_center/dto/notification.nim @@ -0,0 +1,72 @@ +{.used.} + +import json, strformat, strutils, stint, json_serialization +import ../../message/dto/message + +include ../../../common/json_utils +include ../../../common/utils + +type ActivityCenterNotificationType* {.pure.}= enum + Unknown = 0, + NewOneToOne = 1, + NewPrivateGroupChat = 2, + Mention = 3 + Reply = 4 + +type ActivityCenterNotificationDto* = ref object of RootObj + id*: string # ID is the id of the chat, for public chats it is the name e.g. status, for one-to-one is the hex encoded public key and for group chats is a random uuid appended with the hex encoded pk of the creator of the chat + chatId*: string + name*: string + author*: string + notificationType*: ActivityCenterNotificationType + message*: MessageDto + timestamp*: int64 + read*: bool + dismissed*: bool + accepted*: bool + +proc `$`*(self: ActivityCenterNotificationDto): string = + result = fmt"""ActivityCenterNotificationDto( + id: {$self.id}, + chatId: {self.chatId}, + author: {self.author}, + notificationType: {$self.notificationType.int}, + timestamp: {self.timestamp}, + read: {$self.read}, + dismissed: {$self.dismissed}, + accepted: {$self.accepted}, + message:{self.message} + )""" + +proc toActivityCenterNotificationDto*(jsonObj: JsonNode): ActivityCenterNotificationDto = + result = ActivityCenterNotificationDto() + discard jsonObj.getProp("id", result.id) + discard jsonObj.getProp("chatId", result.chatId) + discard jsonObj.getProp("author", result.author) + + result.notificationType = ActivityCenterNotificationType.Unknown + var notificationTypeInt: int + if (jsonObj.getProp("notificationType", notificationTypeInt) and + (notificationTypeInt >= ord(low(ActivityCenterNotificationType)) or + notificationTypeInt <= ord(high(ActivityCenterNotificationType)))): + result.notificationType = ActivityCenterNotificationType(notificationTypeInt) + + discard jsonObj.getProp("timestamp", result.timestamp) + discard jsonObj.getProp("read", result.read) + discard jsonObj.getProp("dismissed", result.dismissed) + discard jsonObj.getProp("accepted", result.accepted) + + if jsonObj.contains("message") and jsonObj{"message"}.kind != JNull: + result.message = jsonObj{"message"}.toMessageDto() + elif result.notificationType == ActivityCenterNotificationType.NewOneToOne and + jsonObj.contains("lastMessage") and jsonObj{"lastMessage"}.kind != JNull: + result.message = jsonObj{"lastMessage"}.toMessageDto() + + +proc parseActivityCenterNotifications*(rpcResult: JsonNode): (string, seq[ActivityCenterNotificationDto]) = + var notifs: seq[ActivityCenterNotificationDto] = @[] + if rpcResult{"notifications"}.kind != JNull: + for jsonMsg in rpcResult["notifications"]: + notifs.add(jsonMsg.toActivityCenterNotificationDto()) + return (rpcResult{"cursor"}.getStr, notifs) + diff --git a/src/app_service/service/activity_center/service.nim b/src/app_service/service/activity_center/service.nim new file mode 100644 index 0000000000..dda3093c96 --- /dev/null +++ b/src/app_service/service/activity_center/service.nim @@ -0,0 +1,195 @@ +import NimQml, json, sequtils, chronicles, strutils, strutils, stint + +import eventemitter +import ../../../app/core/[main] +import ../../../app/core/tasks/[qt, threadpool] + +import web3/ethtypes, web3/conversions, stew/byteutils, nimcrypto, json_serialization, chronicles +import json, tables, json_serialization + +import ../chat/service as chat_service + +import status/statusgo_backend_new/activity_center as status_activity_center +import status/statusgo_backend_new/response_type +import ./dto/notification + +export notification + +include async_tasks + +logScope: + topics = "activity-center-service" + +type + ActivityCenterNotificationsArgs* = ref object of Args + activityCenterNotifications*: seq[ActivityCenterNotificationDto] + + MarkAsAcceptedNotificationProperties* = ref object of Args + notificationIds*: seq[string] + + MarkAsDismissedNotificationProperties* = ref object of Args + notificationIds*: seq[string] + + MarkAsReadNotificationProperties* = ref object of Args + isAll*: bool + notificationIds*: seq[string] + communityId*: string + channelId*: string + notificationTypes*: seq[ActivityCenterNotificationType] + + MarkAsUnreadNotificationProperties* = ref object of Args + notificationIds*: seq[string] + communityId*: string + channelId*: string + notificationTypes*: seq[ActivityCenterNotificationType] + +# Signals which may be emitted by this service: +# TODO remove new when refactor is done +const SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_LOADED* = "activityCenterNotificationsLoaded-new" +const SIGNAL_MARK_NOTIFICATIONS_AS_READ* = "markNotificationsAsRead-new" +const SIGNAL_MARK_NOTIFICATIONS_AS_UNREAD* = "markNotificationsAsUnread-new" +const SIGNAL_MARK_NOTIFICATIONS_AS_ACCEPTED* = "markNotificationsAsAccepted" +const SIGNAL_MARK_NOTIFICATIONS_AS_DISMISSED* = "markNotificationsAsDismissed" + +const DEFAULT_LIMIT = 20 + + +QtObject: + type Service* = ref object of QObject + threadpool: ThreadPool + events: EventEmitter + chatService: chat_service.Service + cursor*: string + + # Forward declaration + proc asyncActivityNotificationLoad*(self: Service) + + proc delete*(self: Service) = + self.QObject.delete + + proc newService*( + events: EventEmitter, + threadpool: ThreadPool, + chatService: chat_service.Service + ): Service = + new(result, delete) + result.QObject.setup + result.events = events + result.threadpool = threadpool + result.chatService = chatService + + proc init*(self: Service) = + self.asyncActivityNotificationLoad() + + proc hasMoreToShow*(self: Service): bool = + return self.cursor != "" + + proc asyncActivityNotificationLoad*(self: Service) = + let arg = AsyncActivityNotificationLoadTaskArg( + tptr: cast[ByteAddress](asyncActivityNotificationLoadTask), + vptr: cast[ByteAddress](self.vptr), + slot: "asyncActivityNotificationLoaded", + cursor: "", + limit: DEFAULT_LIMIT + ) + self.threadpool.start(arg) + + proc getActivityCenterNotifications*(self: Service): seq[ActivityCenterNotificationDto] = + if(self.cursor == ""): return + + var cursorVal: JsonNode + + if self.cursor == "": + cursorVal = newJNull() + else: + cursorVal = newJString(self.cursor) + + let callResult = status_activity_center.rpcActivityCenterNotifications(cursorVal, DEFAULT_LIMIT) + let activityCenterNotificationsTuple = parseActivityCenterNotifications(callResult.result) + + self.cursor = activityCenterNotificationsTuple[0]; + + result = activityCenterNotificationsTuple[1] + + proc markActivityCenterNotificationRead*( + self: Service, + notificationId: string, + markAsReadProps: MarkAsReadNotificationProperties + ): string = + try: + discard status_activity_center.markActivityCenterNotificationsRead(@[notificationId]) + self.events.emit(SIGNAL_MARK_NOTIFICATIONS_AS_READ, markAsReadProps) + except Exception as e: + error "Error marking as read", msg = e.msg + result = e.msg + + proc unreadActivityCenterNotificationsCount*(self: Service): int = + try: + let response = status_activity_center.unreadActivityCenterNotificationsCount() + + if response.result.kind != JNull: + return response.result.getInt + except Exception as e: + error "Error getting unread acitvity center unread count", msg = e.msg + + proc markActivityCenterNotificationUnread*( + self: Service, + notificationId: string, + markAsUnreadProps: MarkAsUnreadNotificationProperties + ): string = + try: + discard status_activity_center.markActivityCenterNotificationsUnread(@[notificationId]) + self.events.emit(SIGNAL_MARK_NOTIFICATIONS_AS_UNREAD, markAsUnreadProps) + except Exception as e: + error "Error marking as unread", msg = e.msg + result = e.msg + + proc markAllActivityCenterNotificationsRead*(self: Service, initialLoad: bool = true):string = + try: + discard status_activity_center.markAllActivityCenterNotificationsRead() + # This proc should accept ActivityCenterNotificationType in order to clear all notifications + # per type, that's why we have this part here. If we add all types to notificationsType that + # means that we need to clear all notifications for all types. + var types : seq[ActivityCenterNotificationType] + for t in ActivityCenterNotificationType: + types.add(t) + + self.events.emit(SIGNAL_MARK_NOTIFICATIONS_AS_READ, + MarkAsReadNotificationProperties(notificationTypes: types, isAll: true)) + except Exception as e: + error "Error marking all as read", msg = e.msg + result = e.msg + + proc asyncActivityNotificationLoaded*(self: Service, rpcResponse: string) {.slot.} = + let rpcResponseObj = rpcResponse.parseJson + + if(rpcResponseObj["activityNotifications"].kind != JNull): + let activityCenterNotificationsTuple = parseActivityCenterNotifications(rpcResponseObj["activityNotifications"]) + + self.cursor = activityCenterNotificationsTuple[0] + + self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_LOADED, + ActivityCenterNotificationsArgs(activityCenterNotifications: activityCenterNotificationsTuple[1])) + + proc acceptActivityCenterNotifications*(self: Service, notificationIds: seq[string]): string = + try: + let response = status_activity_center.acceptActivityCenterNotifications(notificationIds) + + let (chats, messages) = self.chatService.parseChatResponse2(response) + self.events.emit(chat_service.SIGNAL_CHAT_UPDATE, + ChatUpdateArgsNew(messages: messages, chats: chats)) + + except Exception as e: + error "Error marking as accepted", msg = e.msg + result = e.msg + + proc dismissActivityCenterNotifications*(self: Service, notificationIds: seq[string]): string = + try: + discard status_activity_center.dismissActivityCenterNotifications(notificationIds) + self.events.emit(SIGNAL_MARK_NOTIFICATIONS_AS_DISMISSED, + MarkAsDismissedNotificationProperties(notificationIds: notificationIds)) + except Exception as e: + error "Error marking as dismissed", msg = e.msg + result = e.msg + + diff --git a/src/app_service/service/chat/service.nim b/src/app_service/service/chat/service.nim index 2be54586a5..063c5fef06 100644 --- a/src/app_service/service/chat/service.nim +++ b/src/app_service/service/chat/service.nim @@ -2,6 +2,7 @@ import NimQml, Tables, json, sequtils, strformat, chronicles, os import ./dto/chat as chat_dto import ../message/dto/message as message_dto +import ../activity_center/dto/notification as notification_dto import ../contacts/service as contact_service import status/statusgo_backend_new/chat as status_chat import status/statusgo_backend_new/chatCommands as status_chat_commands @@ -34,7 +35,7 @@ type # emojiReactions*: seq[Reaction] # communities*: seq[Community] # communityMembershipRequests*: seq[CommunityMembershipRequest] - # activityCenterNotifications*: seq[ActivityCenterNotification] + activityCenterNotifications*: seq[ActivityCenterNotificationDto] # statusUpdates*: seq[StatusUpdate] # deletedMessages*: seq[RemovedMessage] diff --git a/src/app_service/service/contacts/service.nim b/src/app_service/service/contacts/service.nim index f4c1cba773..9bc6368e81 100644 --- a/src/app_service/service/contacts/service.nim +++ b/src/app_service/service/contacts/service.nim @@ -36,6 +36,13 @@ type ContactsStatusUpdatedArgs* = ref object of Args statusUpdates*: seq[StatusUpdateDto] + ContactDetails* = ref object of RootObj + displayName*: string + localNickname*: string + icon*: string + isIconIdenticon*: bool + isCurrentUser*: bool + # Local Constants: const CheckStatusIntervalInMilliseconds = 5000 # 5 seconds, this is timeout how often do we check for user status. const OnlineLimitInSeconds = int(5.5 * 60) # 5.5 minutes @@ -341,3 +348,15 @@ QtObject: timeoutInMilliseconds: CheckStatusIntervalInMilliseconds ) self.threadpool.start(arg) + + proc getContactDetails*(self: Service, pubKey: string): ContactDetails = + result = ContactDetails() + let contact = self.getContactById(pubKey) + result.displayName = contact.userNameOrAlias() + result.isCurrentUser = pubKey == singletonInstance.userProfile.getPubKey() + result.icon = contact.identicon + result.isIconIdenticon = contact.identicon.len > 0 + if(contact.image.thumbnail.len > 0): + result.icon = contact.image.thumbnail + result.isIconIdenticon = false + diff --git a/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/ActivityCenterTopBar.qml b/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/ActivityCenterTopBar.qml deleted file mode 100644 index e7629d3373..0000000000 --- a/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/ActivityCenterTopBar.qml +++ /dev/null @@ -1,141 +0,0 @@ -import QtQuick 2.13 -import QtQuick.Controls 2.13 - -import utils 1.0 -import "../../../../../shared" -import "../../../../../shared/popups" -import "../../../../../shared/panels" -import "../../../../../shared/status" -import ".." - -Item { - width: parent.width - height: 64 - - Row { - id: filterButtons - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: Style.current.padding - height: allBtn.height - spacing: Style.current.padding - - StatusButton { - id: allBtn - //% "All" - text: qsTrId("all") - type: "secondary" - size: "small" - highlighted: activityCenter.currentFilter === ActivityCenter.Filter.All - onClicked: activityCenter.currentFilter = ActivityCenter.Filter.All - } - - StatusButton { - id: mentionsBtn - //% "Mentions" - text: qsTrId("mentions") - type: "secondary" - enabled: hasMentions - size: "small" - highlighted: activityCenter.currentFilter === ActivityCenter.Filter.Mentions - onClicked: activityCenter.currentFilter = ActivityCenter.Filter.Mentions - } - - StatusButton { - id: repliesbtn - //% "Replies" - text: qsTrId("replies") - enabled: hasReplies - type: "secondary" - size: "small" - highlighted: activityCenter.currentFilter === ActivityCenter.Filter.Replies - onClicked: activityCenter.currentFilter = ActivityCenter.Filter.Replies - } - -// StatusButton { -// id: contactRequestsBtn -// //% "Contact requests" -// text: qsTrId("contact-requests") -// enabled: hasContactRequests -// type: "secondary" -// size: "small" -// highlighted: activityCenter.currentFilter === ActivityCenter.Filter.ContactRequests -// onClicked: activityCenter.currentFilter = ActivityCenter.Filter.ContactRequests -// } - } - - Row { - id: otherButtons - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - anchors.rightMargin: Style.current.padding - height: markAllReadBtn.height - spacing: Style.current.padding - - StatusIconButton { - id: markAllReadBtn - icon.name: "double-check" - iconColor: Style.current.primary - icon.width: 24 - icon.height: 24 - width: 32 - height: 32 - onClicked: { - // Not Refactored Yet -// errorText.text = chatsModel.activityNotificationList.markAllActivityCenterNotificationsRead() - } - - StatusToolTip { - visible: markAllReadBtn.hovered - //% "Mark all as Read" - text: qsTrId("mark-all-as-read") - } - } - - StatusContextMenuButton { - id: moreActionsBtn - onClicked: moreActionsMenu.open() - - // TODO: replace with StatusPopupMenu - PopupMenu { - id: moreActionsMenu - x: moreActionsBtn.width - moreActionsMenu.width - y: moreActionsBtn.height + 4 - - Action { - icon.source: hideReadNotifications ? Style.svg("eye") : Style.svg("eye-barred") - icon.width: 16 - icon.height: 16 - text: hideReadNotifications ? - //% "Show read notifications" - qsTrId("show-read-notifications") : - //% "Hide read notifications" - qsTrId("hide-read-notifications") - onTriggered: hideReadNotifications = !hideReadNotifications - } - Action { - icon.source: Style.svg("bell") - icon.width: 16 - icon.height: 16 - //% "Notification settings" - text: qsTrId("chat-notification-preferences") - onTriggered: { - activityCenter.close() - Global.changeAppSectionBySectionType(Constants.appSection.profile) - // TODO: replace with shared store constant - // Profile/RootStore.notifications_id - profileLayoutContainer.changeProfileSection(7) - } - } - } - } - } - - StyledText { - id: errorText - visible: !!text - anchors.top: filterButtons.bottom - anchors.topMargin: Style.current.smallPadding - color: Style.current.danger - } -} diff --git a/ui/app/AppLayouts/Chat/popups/ActivityCenterPopup.qml b/ui/app/AppLayouts/Chat/popups/ActivityCenterPopup.qml index ea2ed4cec7..fe9409e432 100644 --- a/ui/app/AppLayouts/Chat/popups/ActivityCenterPopup.qml +++ b/ui/app/AppLayouts/Chat/popups/ActivityCenterPopup.qml @@ -81,8 +81,7 @@ Popup { profileLayoutContainer.changeProfileSection(7) } onMarkAllReadClicked: { - // Not Refactored Yet -// errorText = activityCenter.store.chatsModelInst.activityNotificationList.markAllActivityCenterNotificationsRead() + errorText = activityCenter.store.activityCenterModuleInst.markAllActivityCenterNotificationsRead() } } @@ -146,9 +145,7 @@ Popup { function(left, right) { return left.timestamp > right.timestamp } ] - // Not Refactored Yet - model: [] -// model: activityCenter.store.chatsModelInst.activityNotificationList + model: activityCenter.store.activityCenterList delegate: Item { id: notificationDelegate @@ -186,9 +183,7 @@ Popup { } return -1; } - // Not Refactored Yet - property string previousNotificationTimestamp: "" -// property string previousNotificationTimestamp: notificationDelegate.idx === 0 ? "" : chatsModel.activityNotificationList.getNotificationData(previousNotificationIndex, "timestamp") + property string previousNotificationTimestamp: notificationDelegate.idx === 0 ? "" : activityCenter.store.activityCenterList.getNotificationData(previousNotificationIndex, "timestamp") onPreviousNotificationTimestampChanged: { activityCenter.store.messageStore.prevMsgTimestamp = previousNotificationTimestamp; } @@ -227,8 +222,7 @@ Popup { } Item { - // Not Refactored Yet -// visible: activityCenter.store.chatsModelInst.activityNotificationList.hasMoreToShow + visible: activityCenter.store.activityCenterModuleInst.hasMoreToShow width: parent.width height: visible ? showMoreBtn.height + showMoreBtn.anchors.topMargin : 0 StatusButton { @@ -238,8 +232,7 @@ Popup { anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top anchors.topMargin: Style.current.smallPadding - // Not Refactored Yet -// onClicked: activityCenter.store.chatsModelInst.activityNotificationList.loadMoreNotifications() + onClicked: activityCenter.store.activityCenterModuleInst.loadMoreNotifications() } } } diff --git a/ui/app/AppLayouts/Chat/stores/RootStore.qml b/ui/app/AppLayouts/Chat/stores/RootStore.qml index b4080ddd89..797c8b8127 100644 --- a/ui/app/AppLayouts/Chat/stores/RootStore.qml +++ b/ui/app/AppLayouts/Chat/stores/RootStore.qml @@ -17,6 +17,8 @@ QtObject { // Not Refactored Yet // property var profileModelInst: profileModel property var profileModuleInst: profileModule + property var activityCenterModuleInst: activityCenterModule + property var activityCenterList: activityCenterModuleInst.model property var userProfileInst: userProfile diff --git a/ui/app/AppLayouts/Chat/views/ActivityCenterGroupRequest.qml b/ui/app/AppLayouts/Chat/views/ActivityCenterGroupRequest.qml index 9fd26d9d72..c783dbe99a 100644 --- a/ui/app/AppLayouts/Chat/views/ActivityCenterGroupRequest.qml +++ b/ui/app/AppLayouts/Chat/views/ActivityCenterGroupRequest.qml @@ -155,10 +155,8 @@ Item { anchors.right: parent.right anchors.rightMargin: Style.current.halfPadding anchors.verticalCenter: parent.verticalCenter - // Not Refactored Yet -// onAcceptClicked: root.store.chatsModelInst.activityNotificationList.acceptActivityCenterNotification(model.id) - // Not Refactored Yet -// onDeclineClicked: root.store.chatsModelInst.activityNotificationList.dismissActivityCenterNotification(model.id) + onAcceptClicked: root.store.activityCenterModuleInst.acceptActivityCenterNotification(model.id) + onDeclineClicked: root.store.activityCenterModuleInst.dismissActivityCenterNotification(model.id) onProfileClicked: groupRequestContent.openProfile() onBlockClicked: { // Not Refactored Yet @@ -171,10 +169,9 @@ Item { BlockContactConfirmationDialog { id: blockContactConfirmationDialog onBlockButtonClicked: { - // Not Refactored Yet -// root.store.profileModuleInst.blockContact(blockContactConfirmationDialog.contactAddress) -// root.store.chatsModelInst.activityNotificationList.dismissActivityCenterNotification(model.id) -// blockContactConfirmationDialog.close() + root.store.profileModuleInst.blockContact(blockContactConfirmationDialog.contactAddress) + root.store.activityCenterModuleInst.dismissActivityCenterNotification(model.id) + blockContactConfirmationDialog.close() } } } diff --git a/ui/app/AppLayouts/Chat/views/ActivityCenterMessageComponentView.qml b/ui/app/AppLayouts/Chat/views/ActivityCenterMessageComponentView.qml index 5d14e8ae3c..a109a9af44 100644 --- a/ui/app/AppLayouts/Chat/views/ActivityCenterMessageComponentView.qml +++ b/ui/app/AppLayouts/Chat/views/ActivityCenterMessageComponentView.qml @@ -58,11 +58,10 @@ Item { tooltip.x: -tooltip.width - Style.current.padding tooltip.y: markReadBtn.height / 2 - height / 2 + 4 onClicked: { - // Not Refactored Yet -// if (!model.read) { -// return root.store.chatsModelInst.activityNotificationList.markActivityCenterNotificationRead(model.id, model.message.communityId, model.message.chatId, model.notificationType) -// } -// return root.store.chatsModelInst.activityNotificationList.markActivityCenterNotificationUnread(model.id, model.message.communityId, model.message.chatId, model.notificationType) + if (!model.read) { + return root.store.activityCenterModuleInst.markActivityCenterNotificationRead(model.id, model.message.communityId, model.message.chatId, model.notificationType) + } + return root.store.activityCenterModuleInst.markActivityCenterNotificationUnread(model.id, model.message.communityId, model.message.chatId, model.notificationType) } } } @@ -77,13 +76,12 @@ Item { // const setActiveChannel = root.store.chatsModelInst.channelView.setActiveChannel // const chatId = model.message.chatId // const messageId = model.message.messageId -// root.store.profileModuleInst.addContact(model.author) + root.store.activityCenterModuleInst.acceptActivityCenterNotification(model.id) // root.store.chatsModelInst.activityNotificationList.acceptActivityCenterNotification(model.id) // setActiveChannel(chatId) // positionAtMessage(messageId) } - // Not Refactored Yet -// onDeclineClicked: root.store.chatsModelInst.activityNotificationList.dismissActivityCenterNotification(model.id) + onDeclineClicked: root.store.activityCenterModuleInst.dismissActivityCenterNotification(model.id) onProfileClicked: root.openProfile() onBlockClicked: { // Not Refactored Yet @@ -98,8 +96,8 @@ Item { onBlockButtonClicked: { // Not Refactored Yet // root.store.profileModuleInst.blockContact(blockContactConfirmationDialog.contactAddress) -// root.store.chatsModelInst.activityNotificationList.dismissActivityCenterNotification(model.id) -// blockContactConfirmationDialog.close() + root.store.activityCenterModuleInst.dismissActivityCenterNotification(model.id) + blockContactConfirmationDialog.close() } } }