feat(@desktop/activityCenter): show notification about invite to group chat from non our mutual contact (#14415)

This commit is contained in:
Mykhailo Prakhov 2024-04-12 18:28:28 +02:00 committed by GitHub
parent 3843b53cc0
commit 55dd8e3065
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 219 additions and 22 deletions

View File

@ -165,7 +165,6 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
# Services
result.generalService = general_service.newService(statusFoundation.events, statusFoundation.threadpool)
result.activityCenterService = activity_center_service.newService(statusFoundation.events, statusFoundation.threadpool)
result.keycardService = keycard_service.newService(statusFoundation.events, statusFoundation.threadpool)
result.nodeConfigurationService = node_configuration_service.newService(statusFoundation.fleetConfiguration,
result.settingsService, statusFoundation.events)
@ -177,6 +176,7 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
statusFoundation.events, statusFoundation.threadpool, result.networkService, result.settingsService
)
result.chatService = chat_service.newService(statusFoundation.events, statusFoundation.threadpool, result.contactsService)
result.activityCenterService = activity_center_service.newService(statusFoundation.events, statusFoundation.threadpool, result.chatService)
result.tokenService = token_service.newService(
statusFoundation.events, statusFoundation.threadpool, result.networkService, result.settingsService
)

View File

@ -76,6 +76,14 @@ proc init*(self: Controller) =
if (evArgs.notificationIds.len > 0):
self.delegate.removeActivityCenterNotifications(evArgs.notificationIds)
self.events.on(activity_center_service.SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_ACCEPTED) do(e: Args):
var evArgs = ActivityCenterNotificationIdArgs(e)
self.delegate.acceptActivityCenterNotificationDone(evArgs.notificationId)
self.events.on(activity_center_service.SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_DISMISSED) do(e: Args):
var evArgs = ActivityCenterNotificationIdArgs(e)
self.delegate.dismissActivityCenterNotificationDone(evArgs.notificationId)
proc hasMoreToShow*(self: Controller): bool =
return self.activityCenterService.hasMoreToShow()
@ -109,6 +117,12 @@ proc markActivityCenterNotificationUnread*(self: Controller,notificationId: stri
proc markAsSeenActivityCenterNotifications*(self: Controller) =
self.activityCenterService.markAsSeenActivityCenterNotifications()
proc acceptActivityCenterNotification*(self: Controller,notificationId: string) =
self.activityCenterService.acceptActivityCenterNotification(notificationId)
proc dismissActivityCenterNotification*(self: Controller,notificationId: string) =
self.activityCenterService.dismissActivityCenterNotification(notificationId)
proc replacePubKeysWithDisplayNames*(self: Controller, message: string): string =
return self.messageService.replacePubKeysWithDisplayNames(message)

View File

@ -63,6 +63,18 @@ method markActivityCenterNotificationUnread*(self: AccessInterface, notification
method markAsSeenActivityCenterNotifications*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method acceptActivityCenterNotification*(self: AccessInterface, notificationId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method dismissActivityCenterNotification*(self: AccessInterface, notificationId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method acceptActivityCenterNotificationDone*(self: AccessInterface, notificationId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method dismissActivityCenterNotificationDone*(self: AccessInterface, notificationId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method addActivityCenterNotifications*(self: AccessInterface, activityCenterNotifications: seq[ActivityCenterNotificationDto]) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -126,9 +126,15 @@ proc `read=`*(self: Item, value: bool) =
proc dismissed*(self: Item): bool =
return self.dismissed
proc `dismissed=`*(self: Item, value: bool) =
self.dismissed = value
proc accepted*(self: Item): bool =
return self.accepted
proc `accepted=`*(self: Item, value: bool) =
self.accepted = value
proc messageItem*(self: Item): MessageItem =
return self.messageItem

View File

@ -112,27 +112,55 @@ QtObject:
NotifRoles.TokenData.int: "tokenData"
}.toTable
proc findNotificationIndex(self: Model, notificationId: string): int =
if notificationId.len == 0:
return -1
for i in 0 ..< self.activityCenterNotifications.len:
if self.activityCenterNotifications[i].id == notificationId:
return i
return -1
proc markActivityCenterNotificationUnread*(self: Model, notificationId: string) =
var i = 0
for acnViewItem in self.activityCenterNotifications:
if (acnViewItem.id == notificationId):
acnViewItem.read = false
let i = self.findNotificationIndex(notificationId)
if i == -1:
return
self.activityCenterNotifications[i].read = false
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[NotifRoles.Read.int])
break
i.inc
proc markActivityCenterNotificationRead*(self: Model, notificationId: string) =
var i = 0
for acnViewItem in self.activityCenterNotifications:
if (acnViewItem.id == notificationId):
acnViewItem.read = true
let i = self.findNotificationIndex(notificationId)
if i == -1:
return
self.activityCenterNotifications[i].read = true
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[NotifRoles.Read.int])
break
i.inc
proc activityCenterNotificationAccepted*(self: Model, notificationId: string) =
let i = self.findNotificationIndex(notificationId)
if i == -1:
return
self.activityCenterNotifications[i].read = true
self.activityCenterNotifications[i].accepted = true
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[NotifRoles.Accepted.int, NotifRoles.Read.int])
proc activityCenterNotificationDismissed*(self: Model, notificationId: string) =
let i = self.findNotificationIndex(notificationId)
if i == -1:
return
self.activityCenterNotifications[i].read = true
self.activityCenterNotifications[i].dismissed = true
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[NotifRoles.Dismissed.int, NotifRoles.Read.int])
proc removeNotifications*(self: Model, ids: seq[string]) =
var i = 0

View File

@ -244,6 +244,18 @@ method resetActivityCenterNotifications*(self: Module, activityCenterNotificatio
method markActivityCenterNotificationUnread*(self: Module, notificationId: string) =
self.controller.markActivityCenterNotificationUnread(notificationId)
method acceptActivityCenterNotification*(self: Module, notificationId: string) =
self.controller.acceptActivityCenterNotification(notificationId)
method dismissActivityCenterNotification*(self: Module, notificationId: string) =
self.controller.dismissActivityCenterNotification(notificationId)
method acceptActivityCenterNotificationDone*(self: Module, notificationId: string) =
self.view.acceptActivityCenterNotificationDone(notificationId)
method dismissActivityCenterNotificationDone*(self: Module, notificationId: string) =
self.view.dismissActivityCenterNotificationDone(notificationId)
method markActivityCenterNotificationUnreadDone*(self: Module, notificationIds: seq[string]) =
for notificationId in notificationIds:
self.view.markActivityCenterNotificationUnreadDone(notificationId)

View File

@ -90,6 +90,18 @@ QtObject:
self.delegate.markAsSeenActivityCenterNotifications()
self.hasUnseenActivityCenterNotificationsChanged()
proc acceptActivityCenterNotification(self: View, notificationId: string): void {.slot.} =
self.delegate.acceptActivityCenterNotification(notificationId)
proc dismissActivityCenterNotification(self: View, notificationId: string): void {.slot.} =
self.delegate.dismissActivityCenterNotification(notificationId)
proc acceptActivityCenterNotificationDone*(self: View, notificationId: string) =
self.model.activityCenterNotificationAccepted(notificationId)
proc dismissActivityCenterNotificationDone*(self: View, notificationId: string) =
self.model.activityCenterNotificationDismissed(notificationId)
proc addActivityCenterNotifications*(self: View, activityCenterNotifications: seq[Item]) =
self.model.upsertActivityCenterNotifications(activityCenterNotifications)

View File

@ -100,6 +100,7 @@ proc toActivityCenterNotificationDto*(jsonObj: JsonNode): ActivityCenterNotifica
discard jsonObj.getProp("id", result.id)
discard jsonObj.getProp("chatId", result.chatId)
discard jsonObj.getProp("communityId", result.communityId)
discard jsonObj.getProp("name", result.name)
result.membershipStatus = ActivityCenterMembershipStatus.Idle
var membershipStatusInt: int

View File

@ -13,6 +13,7 @@ import ./dto/notification
import ../../common/activity_center
import ../message/service
import ../message/dto/seen_unseen_messages
import ../chat/service as chat_service
export notification
@ -28,6 +29,9 @@ type
ActivityCenterNotificationIdsArgs* = ref object of Args
notificationIds*: seq[string]
ActivityCenterNotificationIdArgs* = ref object of Args
notificationId*: string
# Signals which may be emitted by this service:
const SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_LOADED* = "activityCenterNotificationsLoaded"
const SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_COUNT_MAY_HAVE_CHANGED* = "activityCenterNotificationsCountMayChanged"
@ -35,6 +39,8 @@ const SIGNAL_ACTIVITY_CENTER_MARK_NOTIFICATIONS_AS_READ* = "activityCenterMarkNo
const SIGNAL_ACTIVITY_CENTER_MARK_NOTIFICATIONS_AS_UNREAD* = "activityCenterMarkNotificationsAsUnread"
const SIGNAL_ACTIVITY_CENTER_MARK_ALL_NOTIFICATIONS_AS_READ* = "activityCenterMarkAllNotificationsAsRead"
const SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_REMOVED* = "activityCenterNotificationsRemoved"
const SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_ACCEPTED* = "activityCenterNotificationsAccepted"
const SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_DISMISSED* = "activityCenterNotificationsDismissed"
const DEFAULT_LIMIT = 20
@ -55,6 +61,7 @@ QtObject:
cursor*: string
activeGroup: ActivityCenterGroup
readType: ActivityCenterReadType
chatService: chat_service.Service
# Forward declaration
proc asyncActivityNotificationLoad*(self: Service)
@ -64,7 +71,8 @@ QtObject:
proc newService*(
events: EventEmitter,
threadpool: ThreadPool
threadpool: ThreadPool,
chatService: chat_service.Service,
): Service =
new(result, delete)
result.QObject.setup
@ -73,6 +81,7 @@ QtObject:
result.cursor = ""
result.activeGroup = ActivityCenterGroup.All
result.readType = ActivityCenterReadType.All
result.chatService = chatService
proc handleNewNotificationsLoaded(self: Service, activityCenterNotifications: seq[ActivityCenterNotificationDto]) =
# For now status-go notify about every notification update regardless active group so we need filter manulay on the desktop side
@ -151,6 +160,7 @@ QtObject:
readType: self.readType.int
)
)
let activityCenterNotificationsTuple = parseActivityCenterNotifications(response.result)
self.cursor = activityCenterNotificationsTuple[0];
@ -231,7 +241,10 @@ QtObject:
proc markActivityCenterNotificationUnread*(self: Service, notificationId: string) =
try:
let notificationIds = @[notificationId]
discard backend.markActivityCenterNotificationsUnread(notificationIds)
let response = backend.markActivityCenterNotificationsUnread(notificationIds)
if response.error != nil:
raise newException(RpcException, response.error.message)
self.events.emit(SIGNAL_ACTIVITY_CENTER_MARK_NOTIFICATIONS_AS_UNREAD, ActivityCenterNotificationIdsArgs(notificationIds: notificationIds))
except Exception as e:
error "Error marking as unread", msg = e.msg
@ -273,7 +286,10 @@ QtObject:
proc deleteActivityCenterNotifications*(self: Service, notificationIds: seq[string]): string =
try:
discard backend.deleteActivityCenterNotifications(notificationIds)
let response = backend.deleteActivityCenterNotifications(notificationIds)
if response.error != nil:
raise newException(RpcException, response.error.message)
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_REMOVED, ActivityCenterNotificationIdsArgs(notificationIds: notificationIds))
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_COUNT_MAY_HAVE_CHANGED, Args())
except Exception as e:
@ -285,3 +301,34 @@ QtObject:
for acNotification in acNotifications:
if acNotification.notificationType == notificationType and acNotification.communityId == communityId:
return acNotification
proc acceptActivityCenterNotification*(self: Service, notificationId: string) =
try:
let notificationIds = @[notificationId]
let response = backend.acceptActivityCenterNotifications(notificationIds)
if response.error != nil:
raise newException(RpcException, response.error.message)
if response.result.kind != JNull:
if response.result.contains("chats"):
for jsonChat in response.result["chats"]:
let chat = toChatDto(jsonChat)
self.chatService.updateOrAddChat(chat)
self.events.emit(SIGNAL_CHAT_UPDATE, ChatUpdateArgs(chats: @[chat]))
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_ACCEPTED, ActivityCenterNotificationIdArgs(notificationId: notificationId))
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_COUNT_MAY_HAVE_CHANGED, Args())
except Exception as e:
error "Error accepting activity center notification", msg = e.msg
proc dismissActivityCenterNotification*(self: Service, notificationId: string) =
try:
let notificationIds = @[notificationId]
let response = backend.dismissActivityCenterNotifications(notificationIds)
if response.error != nil:
raise newException(RpcException, response.error.message)
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_DISMISSED, ActivityCenterNotificationIdArgs(notificationId: notificationId))
self.events.emit(SIGNAL_ACTIVITY_CENTER_NOTIFICATIONS_COUNT_MAY_HAVE_CHANGED, Args())
except Exception as e:
error "Error dismissing activity center notification", msg = e.msg

View File

@ -144,6 +144,8 @@ Popup {
return communityBannedNotificationComponent
case ActivityCenterStore.ActivityCenterNotificationType.CommunityUnbanned:
return communityUnbannedNotificationComponent
case ActivityCenterStore.ActivityCenterNotificationType.NewPrivateGroupChat:
return groupChatInvitationNotificationComponent
default:
return null
}
@ -352,4 +354,16 @@ Popup {
}
}
}
Component {
id: groupChatInvitationNotificationComponent
ActivityNotificationUnknownGroupChatInvitation {
filteredIndex: parent.filteredIndex
notification: parent.notification
store: root.store
activityCenterStore: root.activityCenterStore
onCloseActivityCenter: root.close()
}
}
}

View File

@ -110,4 +110,12 @@ QtObject {
function fetchActivityCenterNotifications() {
root.activityCenterModuleInst.fetchActivityCenterNotifications()
}
function acceptActivityCenterNotification(notification) {
root.activityCenterModuleInst.acceptActivityCenterNotification(notification.id)
}
function dismissActivityCenterNotification(notification) {
root.activityCenterModuleInst.dismissActivityCenterNotification(notification.id)
}
}

View File

@ -0,0 +1,43 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import shared 1.0
import shared.panels 1.0
import utils 1.0
import "../controls"
import "../panels"
import "../stores"
ActivityNotificationMessage {
id: root
messageDetails.messageText: qsTr("Invitation to an unknown group")
badgeComponent: ChannelBadge {
property var group: root.store.getChatDetails(notification.chatId)
chatType: notification.chatType
name: notification.name
asset.isImage: asset.name != ""
asset.name: group.icon
asset.emoji: group.emoji
asset.color: group.color
}
ctaComponent: MembershipCta {
membershipStatus: if (notification.accepted)
return ActivityCenterStore.ActivityCenterMembershipStatus.Accepted
else if (notification.dismissed)
return ActivityCenterStore.ActivityCenterMembershipStatus.Declined
else
return ActivityCenterStore.ActivityCenterMembershipStatus.Pending
onAcceptRequestToJoinCommunity: activityCenterStore.acceptActivityCenterNotification(notification)
onDeclineRequestToJoinCommunity: activityCenterStore.dismissActivityCenterNotification(notification)
}
}