diff --git a/src/app/core/signals/remote_signals/messages.nim b/src/app/core/signals/remote_signals/messages.nim
index 534829ad59..8811997f5c 100644
--- a/src/app/core/signals/remote_signals/messages.nim
+++ b/src/app/core/signals/remote_signals/messages.nim
@@ -28,6 +28,7 @@ type MessageSignal* = ref object of Signal
currentStatus*: seq[StatusUpdateDto]
settings*: seq[SettingsFieldDto]
clearedHistories*: seq[ClearedHistoryDto]
+ verificationRequests*: seq[VerificationRequest]
proc fromEvent*(T: type MessageSignal, event: JsonNode): MessageSignal =
var signal:MessageSignal = MessageSignal()
@@ -103,5 +104,9 @@ proc fromEvent*(T: type MessageSignal, event: JsonNode): MessageSignal =
for jsonSettingsField in event["event"]["settings"]:
signal.settings.add(jsonSettingsField.toSettingsFieldDto())
+ if event["event"]{"verificationRequests"} != nil:
+ for jsonVerificationRequest in event["event"]["verificationRequests"]:
+ signal.verificationRequests.add(jsonVerificationRequest.toVerificationRequest())
+
result = signal
diff --git a/src/app/modules/main/activity_center/module.nim b/src/app/modules/main/activity_center/module.nim
index 5fb36df937..bc566d85a2 100644
--- a/src/app/modules/main/activity_center/module.nim
+++ b/src/app/modules/main/activity_center/module.nim
@@ -92,7 +92,8 @@ proc createMessageItemFromDto(self: Module, message: MessageDto, chatDetails: Ch
message.sticker.pack,
message.links,
newTransactionParametersItem("","","","","","",-1,""),
- message.mentionedUsersPks
+ message.mentionedUsersPks,
+ contactDetails.details.trustStatus
))
method convertToItems*(
diff --git a/src/app/modules/main/chat_section/base_item.nim b/src/app/modules/main/chat_section/base_item.nim
index c21e090a18..6c8cbc42f0 100644
--- a/src/app/modules/main/chat_section/base_item.nim
+++ b/src/app/modules/main/chat_section/base_item.nim
@@ -1,4 +1,5 @@
import sequtils, sugar
+import ../../../../app_service/service/contacts/dto/contacts
import ../../shared_models/[color_hash_item, color_hash_model]
@@ -22,10 +23,13 @@ type
position: int
categoryId: string
highlight: bool
+ trustStatus: TrustStatus
proc setup*(self: BaseItem, id, name, icon: string, color, emoji, description: string,
- `type`: int, amIChatAdmin: bool, hasUnreadMessages: bool, notificationsCount: int, muted, blocked, active: bool,
- position: int, categoryId: string = "", colorId: int = 0, colorHash: seq[ColorHashSegment] = @[], highlight: bool = false) =
+ `type`: int, amIChatAdmin: bool, hasUnreadMessages: bool, notificationsCount: int, muted,
+ blocked, active: bool, position: int, categoryId: string = "", colorId: int = 0,
+ colorHash: seq[ColorHashSegment] = @[], highlight: bool = false,
+ trustStatus: TrustStatus = TrustStatus.Unknown) =
self.id = id
self.name = name
self.amIChatAdmin = amIChatAdmin
@@ -45,13 +49,16 @@ proc setup*(self: BaseItem, id, name, icon: string, color, emoji, description: s
self.position = position
self.categoryId = categoryId
self.highlight = highlight
+ self.trustStatus = trustStatus
proc initBaseItem*(id, name, icon: string, color, emoji, description: string, `type`: int,
amIChatAdmin: bool, hasUnreadMessages: bool, notificationsCount: int, muted, blocked, active: bool,
- position: int, categoryId: string = "", colorId: int = 0, colorHash: seq[ColorHashSegment] = @[], highlight: bool = false): BaseItem =
+ position: int, categoryId: string = "", colorId: int = 0, colorHash: seq[ColorHashSegment] = @[],
+ highlight: bool = false, trustStatus: TrustStatus = TrustStatus.Unknown): BaseItem =
result = BaseItem()
result.setup(id, name, icon, color, emoji, description, `type`, amIChatAdmin,
- hasUnreadMessages, notificationsCount, muted, blocked, active, position, categoryId, colorId, colorHash, highlight)
+ hasUnreadMessages, notificationsCount, muted, blocked, active, position, categoryId, colorId,
+ colorHash, highlight, trustStatus)
proc delete*(self: BaseItem) =
discard
@@ -148,3 +155,9 @@ method highlight*(self: BaseItem): bool {.inline base.} =
method `highlight=`*(self: var BaseItem, value: bool) {.inline base.} =
self.highlight = value
+
+method trustStatus*(self: BaseItem): TrustStatus {.inline base.} =
+ self.trustStatus
+
+method `trustStatus=`*(self: var BaseItem, value: TrustStatus) {.inline base.} =
+ self.trustStatus = value
diff --git a/src/app/modules/main/chat_section/chat_content/chat_details.nim b/src/app/modules/main/chat_section/chat_content/chat_details.nim
index 7fed85846d..edccd08539 100644
--- a/src/app/modules/main/chat_section/chat_content/chat_details.nim
+++ b/src/app/modules/main/chat_section/chat_content/chat_details.nim
@@ -1,5 +1,6 @@
import NimQml
+
QtObject:
type ChatDetails* = ref object of QObject
# fixed props
@@ -17,6 +18,7 @@ QtObject:
notificationsCount: int
muted: bool
position: int
+ isUntrustworthy: bool
isMutualContact: bool
proc delete*(self: ChatDetails) =
@@ -29,7 +31,7 @@ QtObject:
proc setChatDetails*(self: ChatDetails, id: string, `type`: int, belongsToCommunity,
isUsersListAvailable: bool, name, icon: string, color, description,
emoji: string, hasUnreadMessages: bool, notificationsCount: int, muted: bool, position: int,
- isMutualContact: bool = false) =
+ isUntrustworthy: bool, isMutualContact: bool = false) =
self.id = id
self.`type` = `type`
self.belongsToCommunity = belongsToCommunity
@@ -43,6 +45,7 @@ QtObject:
self.notificationsCount = notificationsCount
self.muted = muted
self.position = position
+ self.isUntrustworthy = isUntrustworthy
self.isMutualContact = isMutualContact
proc getId(self: ChatDetails): string {.slot.} =
@@ -174,3 +177,14 @@ QtObject:
proc setIsMutualContact*(self: ChatDetails, value: bool) = # this is not a slot
self.isMutualContact = value
self.isMutualContactChanged()
+
+ proc isUntrustworthyChanged(self: ChatDetails) {.signal.}
+ proc getIsUntrustworthy(self: ChatDetails): bool {.slot.} =
+ return self.isUntrustworthy
+ QtProperty[bool] isUntrustworthy:
+ read = getIsUntrustworthy
+ notify = isUntrustworthyChanged
+
+ proc setIsUntrustworthy*(self: ChatDetails, value: bool) = # this is not a slot
+ self.isUntrustworthy = value
+ self.isUntrustworthyChanged()
\ No newline at end of file
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 40674036e3..b96aac0dec 100644
--- a/src/app/modules/main/chat_section/chat_content/controller.nim
+++ b/src/app/modules/main/chat_section/chat_content/controller.nim
@@ -106,6 +106,18 @@ proc init*(self: Controller) =
var args = ContactArgs(e)
self.delegate.onContactDetailsUpdated(args.contactId)
+ self.events.on(SIGNAL_CONTACT_UNTRUSTWORTHY) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.onContactDetailsUpdated(args.publicKey)
+
+ self.events.on(SIGNAL_CONTACT_TRUSTED) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.onContactDetailsUpdated(args.publicKey)
+
+ self.events.on(SIGNAL_REMOVED_TRUST_STATUS) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.onContactDetailsUpdated(args.publicKey)
+
self.events.on(SIGNAL_CONTACT_UPDATED) do(e: Args):
var args = ContactArgs(e)
self.delegate.onContactDetailsUpdated(args.contactId)
diff --git a/src/app/modules/main/chat_section/chat_content/messages/controller.nim b/src/app/modules/main/chat_section/chat_content/messages/controller.nim
index a633bb5eb1..4f9de560b1 100644
--- a/src/app/modules/main/chat_section/chat_content/messages/controller.nim
+++ b/src/app/modules/main/chat_section/chat_content/messages/controller.nim
@@ -111,6 +111,18 @@ proc init*(self: Controller) =
var args = ContactArgs(e)
self.delegate.updateContactDetails(args.contactId)
+ self.events.on(SIGNAL_CONTACT_UNTRUSTWORTHY) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.updateContactDetails(args.publicKey)
+
+ self.events.on(SIGNAL_CONTACT_TRUSTED) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.updateContactDetails(args.publicKey)
+
+ self.events.on(SIGNAL_REMOVED_TRUST_STATUS) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.updateContactDetails(args.publicKey)
+
self.events.on(SIGNAL_CONTACT_UPDATED) do(e: Args):
var args = ContactArgs(e)
self.delegate.updateContactDetails(args.contactId)
diff --git a/src/app/modules/main/chat_section/chat_content/messages/module.nim b/src/app/modules/main/chat_section/chat_content/messages/module.nim
index 1ce73f53f1..2e15916cb7 100644
--- a/src/app/modules/main/chat_section/chat_content/messages/module.nim
+++ b/src/app/modules/main/chat_section/chat_content/messages/module.nim
@@ -8,6 +8,7 @@ import ../../../../shared_models/message_reaction_item
import ../../../../shared_models/message_transaction_parameters_item
import ../../../../../global/global_singleton
import ../../../../../core/eventemitter
+import ../../../../../../app_service/service/contacts/dto/contacts
import ../../../../../../app_service/service/contacts/service as contact_service
import ../../../../../../app_service/service/community/service as community_service
import ../../../../../../app_service/service/chat/service as chat_service
@@ -92,7 +93,8 @@ proc createFetchMoreMessagesItem(self: Module): Item =
stickerPack = -1,
@[],
newTransactionParametersItem("","","","","","",-1,""),
- @[]
+ @[],
+ TrustStatus.Unknown
)
proc createChatIdentifierItem(self: Module): Item =
@@ -128,7 +130,8 @@ proc createChatIdentifierItem(self: Module): Item =
stickerPack = -1,
@[],
newTransactionParametersItem("","","","","","",-1,""),
- @[]
+ @[],
+ TrustStatus.Unknown
)
proc checkIfMessageLoadedAndScrollToItIfItIs(self: Module): bool =
@@ -198,8 +201,9 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se
m.transactionParameters.transactionHash,
m.transactionParameters.commandState,
m.transactionParameters.signature),
- m.mentionedUsersPks()
- )
+ m.mentionedUsersPks(),
+ sender.details.trustStatus,
+ )
for r in reactions:
if(r.messageId == m.id):
@@ -285,7 +289,8 @@ method messageAdded*(self: Module, message: MessageDto) =
message.transactionParameters.transactionHash,
message.transactionParameters.commandState,
message.transactionParameters.signature),
- message.mentionedUsersPks
+ message.mentionedUsersPks,
+ sender.details.trustStatus,
)
self.view.model().insertItemBasedOnTimestamp(item)
@@ -398,6 +403,7 @@ method updateContactDetails*(self: Module, contactId: string) =
item.senderLocalName = updatedContact.details.localNickname
item.senderIcon = updatedContact.icon
item.senderIsAdded = updatedContact.details.added
+ item.senderTrustStatus = updatedContact.details.trustStatus
if(item.messageContainsMentions):
let (m, _, err) = self.controller.getMessageDetails(item.id)
if(err.len == 0):
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 842236ba8e..090fc8e432 100644
--- a/src/app/modules/main/chat_section/chat_content/module.nim
+++ b/src/app/modules/main/chat_section/chat_content/module.nim
@@ -76,17 +76,20 @@ method load*(self: Module) =
var chatName = chatDto.name
var chatImage = chatDto.icon
var isMutualContact = false
+ var trustStatus = TrustStatus.Unknown
if(chatDto.chatType == ChatType.OneToOne):
let contactDto = self.controller.getContactById(self.controller.getMyChatId())
chatName = contactDto.userNameOrAlias()
isMutualContact = contactDto.isMutualContact
+ trustStatus = contactDto.trustStatus
if(contactDto.image.thumbnail.len > 0):
chatImage = contactDto.image.thumbnail
self.view.load(chatDto.id, chatDto.chatType.int, self.controller.belongsToCommunity(),
self.controller.isUsersListAvailable(), chatName, chatImage,
chatDto.color, chatDto.description, chatDto.emoji, hasNotification, notificationsCount,
- chatDto.muted, chatDto.position, isMutualContact)
+ chatDto.muted, chatDto.position, isUntrustworthy = trustStatus == TrustStatus.Untrustworthy,
+ isMutualContact)
self.inputAreaModule.load()
self.messagesModule.load()
@@ -188,7 +191,8 @@ proc buildPinnedMessageItem(self: Module, messageId: string, actionInitiatedBy:
m.transactionParameters.transactionHash,
m.transactionParameters.commandState,
m.transactionParameters.signature),
- m.mentionedUsersPks
+ m.mentionedUsersPks,
+ contactDetails.details.trustStatus,
)
item.pinned = true
item.pinnedBy = actionInitiatedBy
@@ -317,6 +321,7 @@ method onContactDetailsUpdated*(self: Module, contactId: string) =
item.senderDisplayName = updatedContact.displayName
item.senderLocalName = updatedContact.details.localNickname
item.senderIcon = updatedContact.icon
+ item.senderTrustStatus = updatedContact.details.trustStatus
if(item.messageContainsMentions):
let (m, _, err) = self.controller.getMessageDetails(item.id)
if(err.len == 0):
@@ -325,6 +330,7 @@ method onContactDetailsUpdated*(self: Module, contactId: string) =
if(self.controller.getMyChatId() == contactId):
self.view.updateChatDetailsNameAndIcon(updatedContact.displayName, updatedContact.icon)
+ self.view.updateTrustStatus(updatedContact.details.trustStatus == TrustStatus.Untrustworthy)
method onNotificationsUpdated*(self: Module, hasUnreadMessages: bool, notificationCount: int) =
self.view.updateChatDetailsNotifications(hasUnreadMessages, notificationCount)
@@ -345,3 +351,6 @@ method onMutualContactChanged*(self: Module) =
let contactDto = self.controller.getContactById(self.controller.getMyChatId())
let isMutualContact = contactDto.isMutualContact
self.view.onMutualContactChanged(isMutualContact)
+
+method contactTrustStatusChanged*(self: Module, publicKey: string, isUntrustworthy: bool) =
+ self.view.updateTrustStatus(isUntrustworthy)
diff --git a/src/app/modules/main/chat_section/chat_content/users/controller.nim b/src/app/modules/main/chat_section/chat_content/users/controller.nim
index cceed6361e..5837c12e9d 100644
--- a/src/app/modules/main/chat_section/chat_content/users/controller.nim
+++ b/src/app/modules/main/chat_section/chat_content/users/controller.nim
@@ -91,6 +91,18 @@ proc init*(self: Controller) =
# Events only for the user list, so not needed in public and one to one chats
if(self.isUsersListAvailable):
+ self.events.on(SIGNAL_CONTACT_UNTRUSTWORTHY) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.contactUpdated(args.publicKey)
+
+ self.events.on(SIGNAL_CONTACT_TRUSTED) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.contactUpdated(args.publicKey)
+
+ self.events.on(SIGNAL_REMOVED_TRUST_STATUS) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.contactUpdated(args.publicKey)
+
self.events.on(SIGNAL_CONTACTS_STATUS_UPDATED) do(e: Args):
let args = ContactsStatusUpdatedArgs(e)
self.delegate.contactsStatusUpdated(args.statusUpdates)
diff --git a/src/app/modules/main/chat_section/chat_content/users/module.nim b/src/app/modules/main/chat_section/chat_content/users/module.nim
index 3260abd1f4..bb956681ac 100644
--- a/src/app/modules/main/chat_section/chat_content/users/module.nim
+++ b/src/app/modules/main/chat_section/chat_content/users/module.nim
@@ -7,6 +7,7 @@ import ../../../../../global/global_singleton
import ../../../../../core/eventemitter
import ../../../../../../app_service/common/conversion
import ../../../../../../app_service/common/types
+import ../../../../../../app_service/service/contacts/dto/contacts
import ../../../../../../app_service/service/contacts/service as contact_service
import ../../../../../../app_service/service/chat/service as chat_service
import ../../../../../../app_service/service/community/service as community_service
@@ -81,6 +82,7 @@ method onNewMessagesLoaded*(self: Module, messages: seq[MessageDto]) =
icon = contactDetails.icon,
onlineStatus = status,
isContact = contactDetails.details.added,
+ isUntrustworthy = contactDetails.details.trustStatus == TrustStatus.Untrustworthy,
)
)
@@ -108,6 +110,7 @@ method contactUpdated*(self: Module, publicKey: string) =
alias = contactDetails.details.alias,
icon = contactDetails.icon,
isContact = contactDetails.details.added, #FIXME
+ isUntrustworthy = contactDetails.details.trustStatus == TrustStatus.Untrustworthy,
)
method loggedInUserImageChanged*(self: Module) =
@@ -148,8 +151,9 @@ method addChatMember*(self: Module, member: ChatMember) =
onlineStatus = status,
isContact = contactDetails.details.added, #FIXME
isAdmin = member.admin,
- joined = member.joined)
- )
+ joined = member.joined,
+ isUntrustworthy = contactDetails.details.trustStatus == TrustStatus.Untrustworthy
+ ))
method onChatMembersAdded*(self: Module, ids: seq[string]) =
for id in ids:
@@ -184,7 +188,9 @@ method onChatMemberUpdated*(self: Module, publicKey: string, admin: bool, joined
icon = contactDetails.icon,
isContact = contactDetails.details.added,
isAdmin = admin,
- joined = joined)
+ joined = joined,
+ isUntrustworthy = contactDetails.details.trustStatus == TrustStatus.Untrustworthy,
+ )
method getMembersPublicKeys*(self: Module): string =
let publicKeys = self.controller.getMembersPublicKeys()
diff --git a/src/app/modules/main/chat_section/chat_content/view.nim b/src/app/modules/main/chat_section/chat_content/view.nim
index c3ec185d4d..0b03fecdfb 100644
--- a/src/app/modules/main/chat_section/chat_content/view.nim
+++ b/src/app/modules/main/chat_section/chat_content/view.nim
@@ -1,5 +1,7 @@
import NimQml
import ../../../shared_models/message_model as pinned_msg_model
+import ../../../../../app_service/service/contacts/dto/contacts as contacts_dto
+
import io_interface
import chat_details
@@ -32,9 +34,11 @@ QtObject:
proc load*(self: View, id: string, `type`: int, belongsToCommunity, isUsersListAvailable: bool,
name, icon: string, color, description, emoji: string, hasUnreadMessages: bool,
- notificationsCount: int, muted: bool, position: int, isMutualContact: bool) =
- self.chatDetails.setChatDetails(id, `type`, belongsToCommunity, isUsersListAvailable, name, icon,
- color, description, emoji, hasUnreadMessages, notificationsCount, muted, position, isMutualContact)
+ notificationsCount: int, muted: bool, position: int, isUntrustworthy: bool,
+ isMutualContact: bool) =
+ self.chatDetails.setChatDetails(id, `type`, belongsToCommunity, isUsersListAvailable, name,
+ icon, color, description, emoji, hasUnreadMessages, notificationsCount, muted, position,
+ isUntrustworthy, isMutualContact)
self.delegate.viewDidLoad()
self.chatDetailsChanged()
@@ -95,6 +99,9 @@ QtObject:
self.chatDetails.setName(name)
self.chatDetails.setIcon(icon)
+ proc updateTrustStatus*(self: View, isUntrustworthy: bool) =
+ self.chatDetails.setIsUntrustworthy(isUntrustworthy)
+
proc updateChatDetailsNotifications*(self: View, hasUnreadMessages: bool, notificationCount: int) =
self.chatDetails.setHasUnreadMessages(hasUnreadMessages)
self.chatDetails.setNotificationCount(notificationCount)
diff --git a/src/app/modules/main/chat_section/controller.nim b/src/app/modules/main/chat_section/controller.nim
index 1661e673d8..ed36010977 100644
--- a/src/app/modules/main/chat_section/controller.nim
+++ b/src/app/modules/main/chat_section/controller.nim
@@ -180,6 +180,18 @@ proc init*(self: Controller) =
var args = ContactArgs(e)
self.delegate.onContactDetailsUpdated(args.contactId)
+ self.events.on(SIGNAL_CONTACT_UNTRUSTWORTHY) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.onContactDetailsUpdated(args.publicKey)
+
+ self.events.on(SIGNAL_CONTACT_TRUSTED) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.onContactDetailsUpdated(args.publicKey)
+
+ self.events.on(SIGNAL_REMOVED_TRUST_STATUS) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.onContactDetailsUpdated(args.publicKey)
+
self.events.on(SIGNAL_CHAT_RENAMED) do(e: Args):
var args = ChatRenameArgs(e)
self.delegate.onChatRenamed(args.id, args.newName)
diff --git a/src/app/modules/main/chat_section/item.nim b/src/app/modules/main/chat_section/item.nim
index 61120b3244..7e52d5f23f 100644
--- a/src/app/modules/main/chat_section/item.nim
+++ b/src/app/modules/main/chat_section/item.nim
@@ -39,6 +39,7 @@ proc `$`*(self: Item): string =
position: {self.position},
categoryId: {self.categoryId},
highlight: {self.highlight},
+ trustStatus: {self.trustStatus},
subItems:[
{$self.subItems}
]"""
@@ -60,7 +61,8 @@ proc toJsonNode*(self: Item): JsonNode =
"active": self.active,
"position": self.position,
"categoryId": self.categoryId,
- "highlight": self.highlight
+ "highlight": self.highlight,
+ "trustStatus": self.trustStatus,
}
proc appendSubItems*(self: Item, items: seq[SubItem]) =
diff --git a/src/app/modules/main/chat_section/model.nim b/src/app/modules/main/chat_section/model.nim
index bb72ce6c38..d7219d9330 100644
--- a/src/app/modules/main/chat_section/model.nim
+++ b/src/app/modules/main/chat_section/model.nim
@@ -1,5 +1,6 @@
import NimQml, Tables, strutils, strformat, json, algorithm
from ../../../../app_service/service/chat/dto/chat import ChatType
+from ../../../../app_service/service/contacts/dto/contacts import TrustStatus
import item, sub_item, base_item, sub_model
type
@@ -24,6 +25,7 @@ type
IsCategory
CategoryId
Highlight
+ TrustStatus
QtObject:
type
@@ -91,7 +93,8 @@ QtObject:
ModelRole.SubItems.int:"subItems",
ModelRole.IsCategory.int:"isCategory",
ModelRole.CategoryId.int:"categoryId",
- ModelRole.Highlight.int:"highlight"
+ ModelRole.Highlight.int:"highlight",
+ ModelRole.TrustStatus.int:"trustStatus",
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
@@ -145,6 +148,8 @@ QtObject:
result = newQVariant(item.categoryId)
of ModelRole.Highlight:
result = newQVariant(item.highlight)
+ of ModelRole.TrustStatus:
+ result = newQVariant(item.trustStatus.int)
proc appendItem*(self: Model, item: Item) =
let parentModelIndex = newQModelIndex()
@@ -257,14 +262,16 @@ QtObject:
if self.items[i].subItems.blockUnblockItemById(id, blocked):
return
- proc updateItemDetails*(self: Model, id, name, icon: string) =
+ proc updateItemDetails*(self: Model, id, name, icon: string, trustStatus: TrustStatus) =
## This updates only first level items, it doesn't update subitems, since subitems cannot have custom icon.
for i in 0 ..< self.items.len:
if(self.items[i].id == id):
self.items[i].BaseItem.name = name
self.items[i].BaseItem.icon = icon
+ self.items[i].BaseItem.trustStatus = trustStatus
let index = self.createIndex(i, 0, nil)
- self.dataChanged(index, index, @[ModelRole.Name.int, ModelRole.Icon.int])
+ self.dataChanged(index, index, @[ModelRole.Name.int, ModelRole.Icon.int,
+ ModelRole.TrustStatus.int])
return
proc renameItem*(self: Model, id: string, name: string) =
diff --git a/src/app/modules/main/chat_section/module.nim b/src/app/modules/main/chat_section/module.nim
index 9201c255b1..ee2a15d81e 100644
--- a/src/app/modules/main/chat_section/module.nim
+++ b/src/app/modules/main/chat_section/module.nim
@@ -21,6 +21,7 @@ import ../../../../app_service/service/message/service as message_service
import ../../../../app_service/service/mailservers/service as mailservers_service
import ../../../../app_service/service/gif/service as gif_service
import ../../../../app_service/service/visual_identity/service as visual_identity
+import ../../../../app_service/service/contacts/dto/contacts as contacts_dto
export io_interface
@@ -210,7 +211,7 @@ proc createItemFromPublicKey(self: Module, publicKey: string): UserItem =
isContact = contactDetails.details.isMutualContact(),
isVerified = contactDetails.details.isContactVerified(),
isUntrustworthy = contactDetails.details.isContactUntrustworthy(),
- isBlocked = contactDetails.details.isBlocked()
+ isBlocked = contactDetails.details.isBlocked(),
)
proc initContactRequestsModel(self: Module) =
@@ -650,7 +651,8 @@ method onContactDetailsUpdated*(self: Module, publicKey: string) =
let chatName = contactDetails.displayName
let chatImage = contactDetails.icon
- self.view.chatsModel().updateItemDetails(publicKey, chatName, chatImage)
+ let trustStatus = contactDetails.details.trustStatus
+ self.view.chatsModel().updateItemDetails(publicKey, chatName, chatImage, trustStatus)
method onNewMessagesReceived*(self: Module, sectionIdMsgBelongsTo: string, chatIdMsgBelongsTo: string,
chatTypeMsgBelongsTo: ChatType, unviewedMessagesCount: int, unviewedMentionsCount: int, message: MessageDto) =
diff --git a/src/app/modules/main/controller.nim b/src/app/modules/main/controller.nim
index 81d73e2864..c1e0907c55 100644
--- a/src/app/modules/main/controller.nim
+++ b/src/app/modules/main/controller.nim
@@ -174,6 +174,18 @@ proc init*(self: Controller) =
var args = ContactArgs(e)
self.delegate.contactUpdated(args.contactId)
+ self.events.on(SIGNAL_CONTACT_UNTRUSTWORTHY) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.contactUpdated(args.publicKey)
+
+ self.events.on(SIGNAL_CONTACT_TRUSTED) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.contactUpdated(args.publicKey)
+
+ self.events.on(SIGNAL_REMOVED_TRUST_STATUS) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.contactUpdated(args.publicKey)
+
self.events.on(SIGNAL_MNEMONIC_REMOVAL) do(e: Args):
self.delegate.mnemonicBackedUp()
diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim
index 1b858b3e31..a74ee4daf6 100644
--- a/src/app/modules/main/module.nim
+++ b/src/app/modules/main/module.nim
@@ -21,6 +21,7 @@ import activity_center/module as activity_center_module
import communities/module as communities_module
import node_section/module as node_section_module
import networks/module as networks_module
+import ../../../app_service/service/contacts/dto/contacts
import ../../../app_service/service/keychain/service as keychain_service
import ../../../app_service/service/chat/service as chat_service
@@ -692,7 +693,10 @@ method getContactDetailsAsJson*[T](self: Module[T], publicKey: string): string =
"isBlocked":contact.blocked,
"requestReceived":contact.hasAddedUs,
"isSyncing":contact.isSyncing,
- "removed":contact.removed
+ "removed":contact.removed,
+ "trustStatus": contact.trustStatus.int,
+ "verificationStatus": contact.verificationStatus.int,
+ "hasAddedUs": contact.hasAddedUs
}
return $jsonObj
@@ -736,6 +740,7 @@ method contactUpdated*[T](self: Module[T], publicKey: string) =
contactDetails.details.localNickname,
contactDetails.details.alias,
contactDetails.icon,
+ isUntrustworthy = contactDetails.details.isContactUntrustworthy(),
)
method calculateProfileSectionHasNotification*[T](self: Module[T]): bool =
diff --git a/src/app/modules/main/profile_section/contacts/controller.nim b/src/app/modules/main/profile_section/contacts/controller.nim
index 9c68d9ea4e..05cd02a5da 100644
--- a/src/app/modules/main/profile_section/contacts/controller.nim
+++ b/src/app/modules/main/profile_section/contacts/controller.nim
@@ -49,10 +49,38 @@ proc init*(self: Controller) =
var args = ContactArgs(e)
self.delegate.contactNicknameChanged(args.contactId)
+ self.events.on(SIGNAL_CONTACT_UNTRUSTWORTHY) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.contactTrustStatusChanged(args.publicKey, args.isUntrustworthy)
+
+ self.events.on(SIGNAL_CONTACT_TRUSTED) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.contactTrustStatusChanged(args.publicKey, args.isUntrustworthy)
+
+ self.events.on(SIGNAL_REMOVED_TRUST_STATUS) do(e: Args):
+ var args = TrustArgs(e)
+ self.delegate.contactTrustStatusChanged(args.publicKey, args.isUntrustworthy)
+
self.events.on(SIGNAL_CONTACT_UPDATED) do(e: Args):
var args = ContactArgs(e)
self.delegate.contactUpdated(args.contactId)
+ self.events.on(SIGNAL_CONTACT_VERIFICATION_DECLINED) do(e: Args):
+ var args = ContactArgs(e)
+ self.delegate.onVerificationRequestDeclined(args.contactId)
+
+ self.events.on(SIGNAL_CONTACT_VERIFICATION_ADDED) do(e: Args):
+ var args = VerificationRequestArgs(e)
+ self.delegate.onVerificationRequestUpdatedOrAdded(args.verificationRequest)
+
+ self.events.on(SIGNAL_CONTACT_VERIFICATION_UPDATED) do(e: Args):
+ var args = VerificationRequestArgs(e)
+ self.delegate.onVerificationRequestUpdatedOrAdded(args.verificationRequest)
+
+ self.events.on(SIGNAL_CONTACT_VERIFICATION_ACCEPTED) do(e: Args):
+ var args = VerificationRequestArgs(e)
+ self.delegate.onVerificationRequestUpdatedOrAdded(args.verificationRequest)
+
proc getContacts*(self: Controller, group: ContactsGroup): seq[ContactsDto] =
return self.contactsService.getContactsByGroup(group)
@@ -88,4 +116,40 @@ proc removeContactRequestRejection*(self: Controller, publicKey: string) =
self.contactsService.removeContactRequestRejection(publicKey)
proc switchToOrCreateOneToOneChat*(self: Controller, chatId: string) =
- self.chatService.switchToOrCreateOneToOneChat(chatId, "")
\ No newline at end of file
+ self.chatService.switchToOrCreateOneToOneChat(chatId, "")
+
+proc markUntrustworthy*(self: Controller, publicKey: string) =
+ self.contactsService.markUntrustworthy(publicKey)
+
+proc removeTrustStatus*(self: Controller, publicKey: string) =
+ self.contactsService.removeTrustStatus(publicKey)
+
+proc getVerificationRequestSentTo*(self: Controller, publicKey: string): VerificationRequest =
+ self.contactsService.getVerificationRequestSentTo(publicKey)
+
+proc getVerificationRequestFrom*(self: Controller, publicKey: string): VerificationRequest =
+ self.contactsService.getVerificationRequestFrom(publicKey)
+
+proc sendVerificationRequest*(self: Controller, publicKey: string, challenge: string) =
+ self.contactsService.sendVerificationRequest(publicKey, challenge)
+
+proc cancelVerificationRequest*(self: Controller, publicKey: string) =
+ self.contactsService.cancelVerificationRequest(publicKey)
+
+proc verifiedTrusted*(self: Controller, publicKey: string) =
+ self.contactsService.verifiedTrusted(publicKey)
+
+proc verifiedUntrustworthy*(self: Controller, publicKey: string) =
+ self.contactsService.verifiedUntrustworthy(publicKey)
+
+proc acceptVerificationRequest*(self: Controller, publicKey: string, response: string) =
+ self.contactsService.acceptVerificationRequest(publicKey, response)
+
+proc declineVerificationRequest*(self: Controller, publicKey: string) =
+ self.contactsService.declineVerificationRequest(publicKey)
+
+proc getReceivedVerificationRequests*(self: Controller): seq[VerificationRequest] =
+ self.contactsService.getReceivedVerificationRequests()
+
+proc hasReceivedVerificationRequestFrom*(self: Controller, fromId: string): bool =
+ self.contactsService.hasReceivedVerificationRequestFrom(fromId)
diff --git a/src/app/modules/main/profile_section/contacts/io_interface.nim b/src/app/modules/main/profile_section/contacts/io_interface.nim
index c0f44de98f..2c2efb68a7 100644
--- a/src/app/modules/main/profile_section/contacts/io_interface.nim
+++ b/src/app/modules/main/profile_section/contacts/io_interface.nim
@@ -1,4 +1,5 @@
import NimQml
+import ../../../../../app_service/service/contacts/dto/contacts as contacts
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
@@ -69,8 +70,53 @@ method contactRemoved*(self: AccessInterface, publicKey: string) {.base.} =
method contactNicknameChanged*(self: AccessInterface, publicKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
+method contactTrustStatusChanged*(self: AccessInterface, publicKey: string, isUntrustworthy: bool) {.base.} =
+ raise newException(ValueError, "No implementation available")
+
method contactUpdated*(self: AccessInterface, publicKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
+method markUntrustworthy*(self: AccessInterface, publicKey: string): void {.base.} =
+ raise newException(ValueError, "No implementation available")
+
+method removeTrustStatus*(self: AccessInterface, publicKey: string): void {.base.} =
+ raise newException(ValueError, "No implementation available")
+
+method getSentVerificationDetailsAsJson*(self: AccessInterface, publicKey: string): string =
+ raise newException(ValueError, "No implementation available")
+
+method getVerificationDetailsFromAsJson*(self: AccessInterface, publicKey: string): string =
+ raise newException(ValueError, "No implementation available")
+
+method sendVerificationRequest*(self: AccessInterface, publicKey: string, challenge: string) =
+ raise newException(ValueError, "No implementation available")
+
+method cancelVerificationRequest*(self: AccessInterface, publicKey: string) =
+ raise newException(ValueError, "No implementation available")
+
+method verifiedTrusted*(self: AccessInterface, publicKey: string): void {.base.} =
+ raise newException(ValueError, "No implementation available")
+
+method verifiedUntrustworthy*(self: AccessInterface, publicKey: string): void {.base.} =
+ raise newException(ValueError, "No implementation available")
+
+method declineVerificationRequest*(self: AccessInterface, publicKey: string): void {.base.} =
+ raise newException(ValueError, "No implementation available")
+
+method acceptVerificationRequest*(self: AccessInterface, publicKey: string, response: string): void {.base.} =
+ raise newException(ValueError, "No implementation available")
+
method contactRequestRejectionRemoved*(self: AccessInterface, publicKey: string) {.base.} =
+ raise newException(ValueError, "No implementation available")
+
+method getReceivedVerificationRequests*(self: AccessInterface): seq[VerificationRequest] {.base.} =
+ raise newException(ValueError, "No implementation available")
+
+method hasReceivedVerificationRequestFrom*(self: AccessInterface, fromId: string): bool {.base.} =
+ raise newException(ValueError, "No implementation available")
+
+method onVerificationRequestDeclined*(self: AccessInterface, publicKey: string) {.base.} =
+ raise newException(ValueError, "No implementation available")
+
+method onVerificationRequestUpdatedOrAdded*(self: AccessInterface, VerificationRequest: VerificationRequest) {.base.} =
raise newException(ValueError, "No implementation available")
\ No newline at end of file
diff --git a/src/app/modules/main/profile_section/contacts/module.nim b/src/app/modules/main/profile_section/contacts/module.nim
index 6f4e9ad1a7..3c2abd40cb 100644
--- a/src/app/modules/main/profile_section/contacts/module.nim
+++ b/src/app/modules/main/profile_section/contacts/module.nim
@@ -1,12 +1,13 @@
import NimQml, chronicles
-import io_interface, view, controller
+import io_interface, view, controller, json
import ../../../shared_models/user_item
import ../../../shared_models/user_model
import ../io_interface as delegate_interface
import ../../../../global/global_singleton
import ../../../../core/eventemitter
+import ../../../../../app_service/service/contacts/dto/contacts as contacts_dto
import ../../../../../app_service/service/contacts/service as contacts_service
import ../../../../../app_service/service/chat/service as chat_service
@@ -76,6 +77,16 @@ method viewDidLoad*(self: Module) =
# Temporary commented until we provide appropriate flags on the `status-go` side to cover all sections.
# self.buildModel(self.view.receivedButRejectedContactRequestsModel(), ContactsGroup.IncomingRejectedContactRequests)
# self.buildModel(self.view.sentButRejectedContactRequestsModel(), ContactsGroup.IncomingRejectedContactRequests)
+
+ let receivedVerificationRequests = self.controller.getReceivedVerificationRequests()
+ var receivedVerificationRequestItems: seq[UserItem] = @[]
+ for receivedVerificationRequest in receivedVerificationRequests:
+ if receivedVerificationRequest.status == VerificationStatus.Verifying or
+ receivedVerificationRequest.status == VerificationStatus.Verified:
+ let contactItem = self.createItemFromPublicKey(receivedVerificationRequest.fromID)
+ contactItem.incomingVerificationStatus = VerificationRequestStatus(receivedVerificationRequest.status)
+ receivedVerificationRequestItems.add(contactItem)
+ self.view.receivedContactRequestsModel().addItems(receivedVerificationRequestItems)
self.moduleLoaded = true
self.delegate.contactsModuleDidLoad()
@@ -172,3 +183,86 @@ method contactNicknameChanged*(self: Module, publicKey: string) =
# self.view.receivedButRejectedContactRequestsModel().updateName(publicKey, name)
# self.view.sentButRejectedContactRequestsModel().updateName(publicKey, name)
self.view.blockedContactsModel().updateName(publicKey, name)
+
+method contactTrustStatusChanged*(self: Module, publicKey: string, isUntrustworthy: bool) =
+ self.view.myMutualContactsModel().updateTrustStatus(publicKey, isUntrustworthy)
+ self.view.blockedContactsModel().updateTrustStatus(publicKey, isUntrustworthy)
+
+method markUntrustworthy*(self: Module, publicKey: string): void =
+ self.controller.markUntrustworthy(publicKey)
+
+method removeTrustStatus*(self: Module, publicKey: string): void =
+ self.controller.removeTrustStatus(publicKey)
+
+method getSentVerificationDetailsAsJson*(self: Module, publicKey: string): string =
+ let verificationRequest = self.controller.getVerificationRequestSentTo(publicKey)
+ let (name, image, largeImage) = self.controller.getContactNameAndImage(publicKey)
+ let jsonObj = %* {
+ "challenge": verificationRequest.challenge,
+ "response": verificationRequest.response,
+ "requestedAt": verificationRequest.requestedAt,
+ "requestStatus": verificationRequest.status.int,
+ "repliedAt": verificationRequest.repliedAt,
+ "icon": image,
+ "largeImage": largeImage,
+ "displayName": name
+ }
+ return $jsonObj
+
+method getVerificationDetailsFromAsJson*(self: Module, publicKey: string): string =
+ let verificationRequest = self.controller.getVerificationRequestFrom(publicKey)
+ let (name, image, largeImage) = self.controller.getContactNameAndImage(publicKey)
+ let jsonObj = %* {
+ "from": verificationRequest.fromId,
+ "challenge": verificationRequest.challenge,
+ "response": verificationRequest.response,
+ "requestedAt": verificationRequest.requestedAt,
+ "requestStatus": verificationRequest.status.int,
+ "repliedAt": verificationRequest.repliedAt,
+ "icon": image,
+ "largeImage": largeImage,
+ "displayName": name
+ }
+ return $jsonObj
+
+method sendVerificationRequest*(self: Module, publicKey: string, challenge: string) =
+ self.controller.sendVerificationRequest(publicKey, challenge)
+
+method cancelVerificationRequest*(self: Module, publicKey: string) =
+ self.controller.cancelVerificationRequest(publicKey)
+
+method verifiedTrusted*(self: Module, publicKey: string) =
+ self.controller.verifiedTrusted(publicKey)
+
+method verifiedUntrustworthy*(self: Module, publicKey: string) =
+ self.controller.verifiedUntrustworthy(publicKey)
+
+method declineVerificationRequest*(self: Module, publicKey: string) =
+ self.controller.declineVerificationRequest(publicKey)
+
+method acceptVerificationRequest*(self: Module, publicKey: string, response: string) =
+ self.controller.acceptVerificationRequest(publicKey, response)
+
+method getReceivedVerificationRequests*(self: Module): seq[VerificationRequest] =
+ self.controller.getReceivedVerificationRequests()
+
+method hasReceivedVerificationRequestFrom*(self: Module, fromId: string): bool =
+ result = self.controller.hasReceivedVerificationRequestFrom(fromId)
+
+method onVerificationRequestDeclined*(self: Module, publicKey: string) =
+ self.view.receivedContactRequestsModel.removeItemById(publicKey)
+
+method onVerificationRequestUpdatedOrAdded*(self: Module, request: VerificationRequest) =
+ let item = self.createItemFromPublicKey(request.fromID)
+ item.incomingVerificationStatus = VerificationRequestStatus(request.status)
+ if (self.view.receivedContactRequestsModel.containsItemWithPubKey(request.fromID)):
+ if request.status != VerificationStatus.Verifying and
+ request.status != VerificationStatus.Verified:
+ self.view.receivedContactRequestsModel.removeItemById(request.fromID)
+ return
+ self.view.receivedContactRequestsModel.updateIncomingRequestStatus(
+ item.pubKey,
+ item.incomingVerificationStatus
+ )
+ return
+ self.view.receivedContactRequestsModel.addItem(item)
\ No newline at end of file
diff --git a/src/app/modules/main/profile_section/contacts/view.nim b/src/app/modules/main/profile_section/contacts/view.nim
index 2979f5cd06..f37e4f6500 100644
--- a/src/app/modules/main/profile_section/contacts/view.nim
+++ b/src/app/modules/main/profile_section/contacts/view.nim
@@ -33,8 +33,8 @@ QtObject:
# Temporary commented until we provide appropriate flags on the `status-go` side to cover all sections.
# self.receivedButRejectedContactRequestsModel.delete
# self.receivedButRejectedContactRequestsModelVariant.delete
- # self.sentButRejectedContactRequestsModel.delete
# self.sentButRejectedContactRequestsModelVariant.delete
+ # self.sentButRejectedContactRequestsModel.delete
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
@@ -150,5 +150,37 @@ QtObject:
proc removeContact*(self: View, publicKey: string) {.slot.} =
self.delegate.removeContact(publicKey)
+ proc markUntrustworthy*(self: View, publicKey: string) {.slot.} =
+ self.delegate.markUntrustworthy(publicKey)
+
+ proc removeTrustStatus*(self: View, publicKey: string) {.slot.} =
+ self.delegate.removeTrustStatus(publicKey)
+
proc removeContactRequestRejection*(self: View, publicKey: string) {.slot.} =
- self.delegate.removeContactRequestRejection(publicKey)
\ No newline at end of file
+ self.delegate.removeContactRequestRejection(publicKey)
+ proc getSentVerificationDetailsAsJson(self: View, publicKey: string): string {.slot.} =
+ return self.delegate.getSentVerificationDetailsAsJson(publicKey)
+
+ proc getVerificationDetailsFromAsJson(self: View, publicKey: string): string {.slot.} =
+ return self.delegate.getVerificationDetailsFromAsJson(publicKey)
+
+ proc sendVerificationRequest*(self: View, publicKey: string, challenge: string) {.slot.} =
+ self.delegate.sendVerificationRequest(publicKey, challenge)
+
+ proc cancelVerificationRequest*(self: View, publicKey: string) {.slot.} =
+ self.delegate.cancelVerificationRequest(publicKey)
+
+ proc verifiedTrusted*(self: View, publicKey: string) {.slot.} =
+ self.delegate.verifiedTrusted(publicKey)
+
+ proc verifiedUntrustworthy*(self: View, publicKey: string) {.slot.} =
+ self.delegate.verifiedUntrustworthy(publicKey)
+
+ proc declineVerificationRequest*(self: View, publicKey: string) {.slot.} =
+ self.delegate.declineVerificationRequest(publicKey)
+
+ proc acceptVerificationRequest*(self: View, publicKey: string, response: string) {.slot.} =
+ self.delegate.acceptVerificationRequest(publicKey, response)
+
+ proc hasReceivedVerificationRequestFrom*(self: View, fromId: string): bool {.slot.} =
+ result = self.delegate.hasReceivedVerificationRequestFrom(fromId)
\ No newline at end of file
diff --git a/src/app/modules/shared_models/active_section.nim b/src/app/modules/shared_models/active_section.nim
index e69f4179a5..489b20eee5 100644
--- a/src/app/modules/shared_models/active_section.nim
+++ b/src/app/modules/shared_models/active_section.nim
@@ -1,5 +1,6 @@
import NimQml
import section_item
+import ../../../app_service/service/contacts/dto/contacts
QtObject:
type ActiveSection* = ref object of QObject
@@ -182,8 +183,8 @@ QtObject:
localNickname: string,
alias: string,
image: string,
- ) =
- self.item.updateMember(pubkey, name, ensName, localNickname, alias, image)
+ isUntrustworthy: bool) =
+ self.item.updateMember(pubkey, name, ensName, localNickname, alias, image, isUntrustworthy)
proc pendingRequestsToJoin(self: ActiveSection): QVariant {.slot.} =
if (self.item.id == ""):
diff --git a/src/app/modules/shared_models/member_item.nim b/src/app/modules/shared_models/member_item.nim
index 46cf75f632..5310a00678 100644
--- a/src/app/modules/shared_models/member_item.nim
+++ b/src/app/modules/shared_models/member_item.nim
@@ -24,8 +24,8 @@ proc initMemberItem*(
isUntrustworthy: bool = false,
isBlocked: bool = false,
contactRequest: ContactRequest = ContactRequest.None,
- incomingVerification: VerificationRequest = VerificationRequest.None,
- outcomingVerification: VerificationRequest = VerificationRequest.None,
+ incomingVerificationStatus: VerificationRequestStatus = VerificationRequestStatus.None,
+ outgoingVerificationStatus: VerificationRequestStatus = VerificationRequestStatus.None,
isAdmin: bool = false,
joined: bool = false,
): MemberItem =
@@ -47,8 +47,8 @@ proc initMemberItem*(
isUntrustworthy = isUntrustworthy,
isBlocked = isBlocked,
contactRequest = contactRequest,
- incomingVerification = incomingVerification,
- outcomingVerification = outcomingVerification
+ incomingVerificationStatus = incomingVerificationStatus,
+ outgoingVerificationStatus = outgoingVerificationStatus
)
proc `$`*(self: MemberItem): string =
@@ -67,8 +67,8 @@ proc `$`*(self: MemberItem): string =
isUntrustworthy: {self.isUntrustworthy},
isBlocked: {self.isBlocked},
contactRequest: {$self.contactRequest.int},
- incomingVerification: {$self.incomingVerification.int},
- outcomingVerification: {$self.outcomingVerification.int},
+ incomingVerificationStatus: {$self.incomingVerificationStatus.int},
+ outgoingVerificationStatus: {$self.outgoingVerificationStatus.int},
isAdmin: {self.isAdmin},
joined: {self.joined}
]"""
diff --git a/src/app/modules/shared_models/member_model.nim b/src/app/modules/shared_models/member_model.nim
index f63f078d7c..013bc87f72 100644
--- a/src/app/modules/shared_models/member_model.nim
+++ b/src/app/modules/shared_models/member_model.nim
@@ -2,6 +2,7 @@ import NimQml, Tables, strformat, sequtils, sugar
# TODO: use generics to remove duplication between user_model and member_model
+import ../../../app_service/service/contacts/dto/contacts
import member_item
type
@@ -20,8 +21,8 @@ type
IsUntrustworthy
IsBlocked
ContactRequest
- IncomingVerification
- OutcomingVerification
+ IncomingVerificationStatus
+ OutgoingVerificationStatus
IsAdmin
Joined
@@ -81,8 +82,8 @@ QtObject:
ModelRole.IsUntrustworthy.int: "isUntrustworthy",
ModelRole.IsBlocked.int: "isBlocked",
ModelRole.ContactRequest.int: "contactRequest",
- ModelRole.IncomingVerification.int: "incomingVerification",
- ModelRole.OutcomingVerification.int: "outcomingVerification",
+ ModelRole.IncomingVerificationStatus.int: "incomingVerificationStatus",
+ ModelRole.OutgoingVerificationStatus.int: "outgoingVerificationStatus",
ModelRole.IsAdmin.int: "isAdmin",
ModelRole.Joined.int: "joined",
}.toTable
@@ -126,10 +127,10 @@ QtObject:
result = newQVariant(item.isBlocked)
of ModelRole.ContactRequest:
result = newQVariant(item.contactRequest.int)
- of ModelRole.IncomingVerification:
- result = newQVariant(item.incomingVerification.int)
- of ModelRole.OutcomingVerification:
- result = newQVariant(item.outcomingVerification.int)
+ of ModelRole.IncomingVerificationStatus:
+ result = newQVariant(item.incomingVerificationStatus.int)
+ of ModelRole.OutgoingVerificationStatus:
+ result = newQVariant(item.outgoingVerificationStatus.int)
of ModelRole.IsAdmin:
result = newQVariant(item.isAdmin)
of ModelRole.Joined:
@@ -213,7 +214,8 @@ QtObject:
icon: string,
isContact: bool = false,
isAdmin: bool = false,
- joined: bool = false
+ joined: bool = false,
+ isUntrustworthy: bool = false,
) =
let ind = self.findIndexForMessageId(pubKey)
if(ind == -1):
@@ -227,6 +229,7 @@ QtObject:
self.items[ind].isContact = isContact
self.items[ind].isAdmin = isAdmin
self.items[ind].joined = joined
+ self.items[ind].isUntrustworthy = isUntrustworthy
let index = self.createIndex(ind, 0, nil)
self.dataChanged(index, index, @[
@@ -238,6 +241,7 @@ QtObject:
ModelRole.IsContact.int,
ModelRole.IsAdmin.int,
ModelRole.Joined.int,
+ ModelRole.IsUntrustworthy.int,
])
proc setOnlineStatus*(self: Model, pubKey: string,
diff --git a/src/app/modules/shared_models/message_item.nim b/src/app/modules/shared_models/message_item.nim
index 852f2163be..a6ada2e800 100644
--- a/src/app/modules/shared_models/message_item.nim
+++ b/src/app/modules/shared_models/message_item.nim
@@ -1,5 +1,6 @@
import json, strformat
import ../../../app_service/common/types
+import ../../../app_service/service/contacts/dto/contacts
export types.ContentType
import message_reaction_model, message_reaction_item, message_transaction_parameters_item
@@ -35,6 +36,7 @@ type
links: seq[string]
transactionParameters: TransactionParametersItem
mentionedUsersPks: seq[string]
+ senderTrustStatus: TrustStatus
proc initItem*(
id,
@@ -59,6 +61,7 @@ proc initItem*(
links: seq[string],
transactionParameters: TransactionParametersItem,
mentionedUsersPks: seq[string],
+ senderTrustStatus: TrustStatus
): Item =
result = Item()
result.id = id
@@ -89,6 +92,7 @@ proc initItem*(
result.mentionedUsersPks = mentionedUsersPks
result.gapFrom = 0
result.gapTo = 0
+ result.senderTrustStatus = senderTrustStatus
proc `$`*(self: Item): string =
result = fmt"""Item(
@@ -115,6 +119,7 @@ proc `$`*(self: Item): string =
links:{$self.links},
transactionParameters:{$self.transactionParameters},
mentionedUsersPks:{$self.mentionedUsersPks},
+ senderTrustStatus:{$self.senderTrustStatus},
)"""
proc id*(self: Item): string {.inline.} =
@@ -156,6 +161,12 @@ proc senderIsAdded*(self: Item): bool {.inline.} =
proc `senderIsAdded=`*(self: Item, value: bool) {.inline.} =
self.senderIsAdded = value
+proc senderTrustStatus*(self: Item): TrustStatus {.inline.} =
+ self.senderTrustStatus
+
+proc `senderTrustStatus=`*(self: Item, value: TrustStatus) {.inline.} =
+ self.senderTrustStatus = value
+
proc outgoingStatus*(self: Item): string {.inline.} =
self.outgoingStatus
diff --git a/src/app/modules/shared_models/message_item_qobject.nim b/src/app/modules/shared_models/message_item_qobject.nim
index e9eb569348..cda1eb89d0 100644
--- a/src/app/modules/shared_models/message_item_qobject.nim
+++ b/src/app/modules/shared_models/message_item_qobject.nim
@@ -34,6 +34,13 @@ QtObject:
QtProperty[string] pinnedBy:
read = pinnedBy
+ proc senderTrustStatus*(self: MessageItem): int {.slot.} =
+ let trustStatus = ?.self.messageItem.senderTrustStatus
+ return trustStatus.int
+
+ QtProperty[int] senderTrustStatus:
+ read = senderTrustStatus
+
proc senderDisplayName*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.senderDisplayName
QtProperty[string] senderDisplayName:
read = senderDisplayName
diff --git a/src/app/modules/shared_models/message_model.nim b/src/app/modules/shared_models/message_model.nim
index ed92f709d0..3a00f7d6f2 100644
--- a/src/app/modules/shared_models/message_model.nim
+++ b/src/app/modules/shared_models/message_model.nim
@@ -36,6 +36,7 @@ type
Links
TransactionParameters
MentionedUsersPks
+ SenderTrustStatus
QtObject:
type
@@ -108,7 +109,8 @@ QtObject:
ModelRole.IsEdited.int: "isEdited",
ModelRole.Links.int: "links",
ModelRole.TransactionParameters.int: "transactionParameters",
- ModelRole.MentionedUsersPks.int: "mentionedUsersPks"
+ ModelRole.MentionedUsersPks.int: "mentionedUsersPks",
+ ModelRole.SenderTrustStatus.int: "senderTrustStatus"
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
@@ -136,6 +138,8 @@ QtObject:
result = newQVariant(item.senderId)
of ModelRole.SenderDisplayName:
result = newQVariant(item.senderDisplayName)
+ of ModelRole.SenderTrustStatus:
+ result = newQVariant(item.senderTrustStatus.int)
of ModelRole.SenderLocalName:
result = newQVariant(item.senderLocalName)
of ModelRole.SenderIcon:
@@ -365,7 +369,8 @@ QtObject:
var roles: seq[int]
if(self.items[i].senderId == contactId):
- roles = @[ModelRole.SenderDisplayName.int, ModelRole.SenderLocalName.int, ModelRole.SenderIcon.int, ModelRole.SenderIsAdded.int]
+ roles = @[ModelRole.SenderDisplayName.int, ModelRole.SenderLocalName.int,
+ ModelRole.SenderIcon.int, ModelRole.SenderIsAdded.int, ModelRole.SenderTrustStatus.int]
if(self.items[i].pinnedBy == contactId):
roles.add(ModelRole.PinnedBy.int)
if(self.items[i].messageContainsMentions):
diff --git a/src/app/modules/shared_models/section_item.nim b/src/app/modules/shared_models/section_item.nim
index e3c7f9678e..82eb6868dc 100644
--- a/src/app/modules/shared_models/section_item.nim
+++ b/src/app/modules/shared_models/section_item.nim
@@ -238,8 +238,9 @@ proc updateMember*(
ensName: string,
nickname: string,
alias: string,
- image: string) =
- self.membersModel.updateItem(pubkey, name, ensName, nickname, alias, image)
+ image: string,
+ isUntrustworthy: bool) =
+ self.membersModel.updateItem(pubkey, name, ensName, nickname, alias, image, isUntrustworthy)
proc pendingRequestsToJoin*(self: SectionItem): PendingRequestModel {.inline.} =
self.pendingRequestsToJoinModel
diff --git a/src/app/modules/shared_models/user_item.nim b/src/app/modules/shared_models/user_item.nim
index ed4ca64dde..034981b054 100644
--- a/src/app/modules/shared_models/user_item.nim
+++ b/src/app/modules/shared_models/user_item.nim
@@ -10,13 +10,16 @@ type
None = 0
IncomingPending
IncomingRejected
- OutcomingPending
- OutcomingRejected
+ OutgoingPending
+ OutgoingRejected
- VerificationRequest* {.pure.} = enum
+ VerificationRequestStatus* {.pure.} = enum
None = 0
Pending
Answered
+ Declined
+ Canceled
+ Trusted
type
UserItem* = ref object of RootObj
@@ -34,8 +37,8 @@ type
isUntrustworthy: bool
isBlocked: bool
contactRequest: ContactRequest
- incomingVerification: VerificationRequest
- outcomingVerification: VerificationRequest
+ incomingVerificationStatus: VerificationRequestStatus
+ outgoingVerificationStatus: VerificationRequestStatus
proc setup*(self: UserItem,
pubKey: string,
@@ -52,8 +55,9 @@ proc setup*(self: UserItem,
isUntrustworthy: bool,
isBlocked: bool,
contactRequest: ContactRequest,
- incomingVerification: VerificationRequest,
- outcomingVerification: VerificationRequest) =
+ incomingVerificationStatus: VerificationRequestStatus,
+ outgoingVerificationStatus: VerificationRequestStatus,
+ ) =
self.pubKey = pubKey
self.displayName = displayName
self.ensName = ensName
@@ -68,28 +72,28 @@ proc setup*(self: UserItem,
self.isUntrustworthy = isUntrustworthy
self.isBlocked = isBlocked
self.contactRequest = contactRequest
- self.incomingVerification = incomingVerification
- self.outcomingVerification = outcomingVerification
+ self.incomingVerificationStatus = incomingVerificationStatus
+ self.outgoingVerificationStatus = outgoingVerificationStatus
# FIXME: remove defaults
proc initUserItem*(
- pubKey: string,
- displayName: string,
- ensName: string = "",
- localNickname: string = "",
- alias: string = "",
- icon: string,
- colorId: int = 0,
- colorHash: string = "",
- onlineStatus: OnlineStatus = OnlineStatus.Inactive,
- isContact: bool,
- isVerified: bool,
- isUntrustworthy: bool,
- isBlocked: bool,
- contactRequest: ContactRequest = ContactRequest.None,
- incomingVerification: VerificationRequest = VerificationRequest.None,
- outcomingVerification: VerificationRequest = VerificationRequest.None
-): UserItem =
+ pubKey: string,
+ displayName: string,
+ ensName: string = "",
+ localNickname: string = "",
+ alias: string = "",
+ icon: string,
+ colorId: int = 0,
+ colorHash: string = "",
+ onlineStatus: OnlineStatus = OnlineStatus.Inactive,
+ isContact: bool,
+ isVerified: bool,
+ isUntrustworthy: bool,
+ isBlocked: bool,
+ contactRequest: ContactRequest = ContactRequest.None,
+ incomingVerificationStatus: VerificationRequestStatus = VerificationRequestStatus.None,
+ outgoingVerificationStatus: VerificationRequestStatus = VerificationRequestStatus.None,
+ ): UserItem =
result = UserItem()
result.setup(
pubKey = pubKey,
@@ -106,8 +110,8 @@ proc initUserItem*(
isUntrustworthy = isUntrustworthy,
isBlocked = isBlocked,
contactRequest = contactRequest,
- incomingVerification = incomingVerification,
- outcomingVerification = outcomingVerification)
+ incomingVerificationStatus = incomingVerificationStatus,
+ outgoingVerificationStatus = outgoingVerificationStatus)
proc toOnlineStatus*(statusType: StatusType): OnlineStatus =
if(statusType == StatusType.AlwaysOnline or statusType == StatusType.Automatic):
@@ -131,8 +135,8 @@ proc `$`*(self: UserItem): string =
isUntrustworthy: {self.isUntrustworthy},
isBlocked: {self.isBlocked},
contactRequest: {$self.contactRequest.int},
- incomingVerification: {$self.incomingVerification.int},
- outcomingVerification: {$self.outcomingVerification.int},
+ incomingVerificationStatus: {$self.incomingVerificationStatus.int},
+ outgoingVerificationStatus: {$self.outgoingVerificationStatus.int},
]"""
proc pubKey*(self: UserItem): string {.inline.} =
@@ -216,14 +220,14 @@ proc contactRequest*(self: UserItem): ContactRequest {.inline.} =
proc `contactRequest=`*(self: UserItem, value: ContactRequest) {.inline.} =
self.contactRequest = value
-proc incomingVerification*(self: UserItem): VerificationRequest {.inline.} =
- self.incomingVerification
+proc incomingVerificationStatus*(self: UserItem): VerificationRequestStatus {.inline.} =
+ self.incomingVerificationStatus
-proc `incomingVerification=`*(self: UserItem, value: VerificationRequest) {.inline.} =
- self.incomingVerification = value
+proc `incomingVerificationStatus=`*(self: UserItem, value: VerificationRequestStatus) {.inline.} =
+ self.incomingVerificationStatus = value
-proc outcomingVerification*(self: UserItem): VerificationRequest {.inline.} =
- self.outcomingVerification
+proc outgoingVerificationStatus*(self: UserItem): VerificationRequestStatus {.inline.} =
+ self.outgoingVerificationStatus
-proc `outcomingVerification=`*(self: UserItem, value: VerificationRequest) {.inline.} =
- self.outcomingVerification = value
+proc `outgoingVerificationStatus=`*(self: UserItem, value: VerificationRequestStatus) {.inline.} =
+ self.outgoingVerificationStatus = value
diff --git a/src/app/modules/shared_models/user_model.nim b/src/app/modules/shared_models/user_model.nim
index 8126a20b8d..59ef993433 100644
--- a/src/app/modules/shared_models/user_model.nim
+++ b/src/app/modules/shared_models/user_model.nim
@@ -1,5 +1,4 @@
import NimQml, Tables, strformat, sequtils, sugar
-
import user_item
type
@@ -18,8 +17,8 @@ type
IsUntrustworthy
IsBlocked
ContactRequest
- IncomingVerification
- OutcomingVerification
+ IncomingVerificationStatus
+ OutgoingVerificationStatus
QtObject:
type
@@ -75,8 +74,8 @@ QtObject:
ModelRole.IsUntrustworthy.int: "isUntrustworthy",
ModelRole.IsBlocked.int: "isBlocked",
ModelRole.ContactRequest.int: "contactRequest",
- ModelRole.IncomingVerification.int: "incomingVerification",
- ModelRole.OutcomingVerification.int: "outcomingVerification",
+ ModelRole.IncomingVerificationStatus.int: "incomingVerificationStatus",
+ ModelRole.OutgoingVerificationStatus.int: "outgoingVerificationStatus",
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
@@ -118,10 +117,10 @@ QtObject:
result = newQVariant(item.isBlocked)
of ModelRole.ContactRequest:
result = newQVariant(item.contactRequest.int)
- of ModelRole.IncomingVerification:
- result = newQVariant(item.incomingVerification.int)
- of ModelRole.OutcomingVerification:
- result = newQVariant(item.outcomingVerification.int)
+ of ModelRole.IncomingVerificationStatus:
+ result = newQVariant(item.incomingVerificationStatus.int)
+ of ModelRole.OutgoingVerificationStatus:
+ result = newQVariant(item.outgoingVerificationStatus.int)
proc addItems*(self: Model, items: seq[UserItem]) =
if(items.len == 0):
@@ -163,8 +162,7 @@ QtObject:
self.items = @[]
self.endResetModel()
-# TODO: rename to `findIndexForMessagePubkey`
- proc findIndexForMessageId(self: Model, pubKey: string): int =
+ proc findIndexByPubKey(self: Model, pubKey: string): int =
for i in 0 ..< self.items.len:
if(self.items[i].pubKey == pubKey):
return i
@@ -182,11 +180,11 @@ QtObject:
# TODO: rename to `containsItem`
proc isContactWithIdAdded*(self: Model, id: string): bool =
- return self.findIndexForMessageId(id) != -1
+ return self.findIndexByPubKey(id) != -1
proc setName*(self: Model, pubKey: string, displayName: string,
ensName: string, localNickname: string) =
- let ind = self.findIndexForMessageId(pubKey)
+ let ind = self.findIndexByPubKey(pubKey)
if(ind == -1):
return
@@ -202,7 +200,7 @@ QtObject:
])
proc setIcon*(self: Model, pubKey: string, icon: string) =
- let ind = self.findIndexForMessageId(pubKey)
+ let ind = self.findIndexByPubKey(pubKey)
if(ind == -1):
return
@@ -218,9 +216,10 @@ QtObject:
ensName: string,
localNickname: string,
alias: string,
- icon: string
+ icon: string,
+ isUntrustworthy: bool = false,
) =
- let ind = self.findIndexForMessageId(pubKey)
+ let ind = self.findIndexByPubKey(pubKey)
if(ind == -1):
return
@@ -228,7 +227,7 @@ QtObject:
self.items[ind].ensName = ensName
self.items[ind].localNickname = localNickname
self.items[ind].alias = alias
- self.items[ind].icon = icon
+ self.items[ind].isUntrustworthy = isUntrustworthy
let index = self.createIndex(ind, 0, nil)
self.dataChanged(index, index, @[
@@ -237,6 +236,7 @@ QtObject:
ModelRole.LocalNickname.int,
ModelRole.Alias.int,
ModelRole.Icon.int,
+ ModelRole.IsUntrustworthy.int,
])
proc updateName*(
@@ -244,7 +244,7 @@ QtObject:
pubKey: string,
displayName: string
) =
- let ind = self.findIndexForMessageId(pubKey)
+ let ind = self.findIndexByPubKey(pubKey)
if(ind == -1):
return
@@ -254,10 +254,36 @@ QtObject:
self.dataChanged(index, index, @[
ModelRole.DisplayName.int
])
+
+ proc updateIncomingRequestStatus*(
+ self: Model,
+ pubKey: string,
+ requestStatus: VerificationRequestStatus
+ ) =
+ let ind = self.findIndexByPubKey(pubKey)
+ if(ind == -1):
+ return
+
+ self.items[ind].incomingVerificationStatus = requestStatus
+
+ let index = self.createIndex(ind, 0, nil)
+ self.dataChanged(index, index, @[
+ ModelRole.IncomingVerificationStatus.int
+ ])
+
+ proc updateTrustStatus*(self: Model, pubKey: string, isUntrustworthy: bool) =
+ let ind = self.findIndexByPubKey(pubKey)
+ if(ind == -1):
+ return
+
+ let first = self.createIndex(ind, 0, nil)
+ let last = self.createIndex(ind, 0, nil)
+ self.items[ind].isUntrustworthy = isUntrustworthy
+ self.dataChanged(first, last, @[ModelRole.IsUntrustworthy.int])
proc setOnlineStatus*(self: Model, pubKey: string,
onlineStatus: OnlineStatus) =
- let ind = self.findIndexForMessageId(pubKey)
+ let ind = self.findIndexByPubKey(pubKey)
if(ind == -1):
return
@@ -271,7 +297,7 @@ QtObject:
# TODO: rename me to removeItemByPubkey
proc removeItemById*(self: Model, pubKey: string) =
- let ind = self.findIndexForMessageId(pubKey)
+ let ind = self.findIndexByPubKey(pubKey)
if(ind == -1):
return
@@ -280,3 +306,6 @@ QtObject:
# TODO: rename me to getItemsAsPubkeys
proc getItemIds*(self: Model): seq[string] =
return self.items.map(i => i.pubKey)
+
+ proc containsItemWithPubKey*(self: Model, pubKey: string): bool =
+ return self.findIndexByPubKey(pubKey) != -1
\ No newline at end of file
diff --git a/src/app_service/service/contacts/dto/contacts.nim b/src/app_service/service/contacts/dto/contacts.nim
index 5be676f86c..ea5cb4017c 100644
--- a/src/app_service/service/contacts/dto/contacts.nim
+++ b/src/app_service/service/contacts/dto/contacts.nim
@@ -10,6 +10,28 @@ type
thumbnail*: string
large*: string
+type TrustStatus* {.pure.}= enum
+ Unknown = 0,
+ Trusted = 1,
+ Untrustworthy = 2
+
+type VerificationStatus* {.pure.}= enum
+ Unverified = 0
+ Verifying = 1
+ Verified = 2
+ Declined = 3
+ Canceled = 4
+ Trusted = 5
+
+type VerificationRequest* = object
+ fromID*: string
+ toID*: string
+ challenge*: string
+ requestedAt*: int64
+ response*: string
+ repliedAt*: int64
+ status*: VerificationStatus
+
type ContactsDto* = object
id*: string
name*: string
@@ -25,6 +47,8 @@ type ContactsDto* = object
hasAddedUs*: bool
isSyncing*: bool
removed*: bool
+ trustStatus*: TrustStatus
+ verificationStatus*: VerificationStatus
proc `$`(self: Images): string =
result = fmt"""Images(
@@ -45,11 +69,13 @@ proc `$`*(self: ContactsDto): string =
image:[
{$self.image}
],
- added:{self.added}
- blocked:{self.blocked}
- hasAddedUs:{self.hasAddedUs}
- isSyncing:{self.isSyncing}
- removed:{self.removed}
+ added:{self.added},
+ blocked:{self.blocked},
+ hasAddedUs:{self.hasAddedUs},
+ isSyncing:{self.isSyncing},
+ removed:{self.removed},
+ trustStatus:{self.trustStatus},
+ verificationStatus:{self.verificationStatus},
)"""
proc toImages(jsonObj: JsonNode): Images =
@@ -63,6 +89,28 @@ proc toImages(jsonObj: JsonNode): Images =
if(jsonObj.getProp("thumbnail", thumbnailObj)):
discard thumbnailObj.getProp("uri", result.thumbnail)
+proc toTrustStatus*(value: int): TrustStatus =
+ result = TrustStatus.Unknown
+ if value >= ord(low(TrustStatus)) or value <= ord(high(TrustStatus)):
+ result = TrustStatus(value)
+
+proc toVerificationStatus*(value: int): VerificationStatus =
+ result = VerificationStatus.Unverified
+ if value >= ord(low(VerificationStatus)) or value <= ord(high(VerificationStatus)):
+ result = VerificationStatus(value)
+
+proc toVerificationRequest*(jsonObj: JsonNode): VerificationRequest =
+ result = VerificationRequest()
+ discard jsonObj.getProp("from", result.fromID)
+ discard jsonObj.getProp("to", result.toID)
+ discard jsonObj.getProp("challenge", result.challenge)
+ discard jsonObj.getProp("response", result.response)
+ discard jsonObj.getProp("requested_at", result.requestedAt)
+ discard jsonObj.getProp("replied_at", result.repliedAt)
+ var verificationStatusInt: int
+ discard jsonObj.getProp("verification_status", verificationStatusInt)
+ result.status = verificationStatusInt.toVerificationStatus()
+
proc toContactsDto*(jsonObj: JsonNode): ContactsDto =
result = ContactsDto()
discard jsonObj.getProp("id", result.id)
@@ -73,6 +121,15 @@ proc toContactsDto*(jsonObj: JsonNode): ContactsDto =
discard jsonObj.getProp("lastUpdated", result.lastUpdated)
discard jsonObj.getProp("lastUpdatedLocally", result.lastUpdatedLocally)
discard jsonObj.getProp("localNickname", result.localNickname)
+
+ result.trustStatus = TrustStatus.Unknown
+ var trustStatusInt: int
+ discard jsonObj.getProp("trustStatus", trustStatusInt)
+ result.trustStatus = trustStatusInt.toTrustStatus()
+
+ var verificationStatusInt: int
+ discard jsonObj.getProp("verificationStatus", verificationStatusInt)
+ result.verificationStatus = verificationStatusInt.toVerificationStatus()
var imageObj: JsonNode
if(jsonObj.getProp("images", imageObj)):
@@ -122,13 +179,14 @@ proc isMutualContact*(self: ContactsDto): bool =
# But for now we consider that contact is mutual contact if I added him and he added me.
return self.hasAddedUs and self.added and not self.removed and not self.blocked
+proc trustStatus*(self: ContactsDto): TrustStatus =
+ result = self.trustStatus
+
proc isContactVerified*(self: ContactsDto): bool =
- # TODO not implemented in `status-go` yet
- return false
+ return self.verificationStatus == VerificationStatus.Verified
proc isContactUntrustworthy*(self: ContactsDto): bool =
- # TODO not implemented in `status-go` yet
- return false
+ return self.trustStatus == TrustStatus.Untrustworthy
proc isContactMarked*(self: ContactsDto): bool =
return self.isContactVerified() or self.isContactUntrustworthy()
\ No newline at end of file
diff --git a/src/app_service/service/contacts/service.nim b/src/app_service/service/contacts/service.nim
index 1b20efe6d6..d4896801ea 100644
--- a/src/app_service/service/contacts/service.nim
+++ b/src/app_service/service/contacts/service.nim
@@ -1,4 +1,4 @@
-import NimQml, Tables, json, sequtils, strformat, chronicles, strutils, times, sugar
+import NimQml, Tables, json, sequtils, strformat, chronicles, strutils, times, sugar, std/times
import ../../../app/global/global_singleton
import ../../../app/core/signals/types
@@ -27,6 +27,10 @@ type
ContactArgs* = ref object of Args
contactId*: string
+ TrustArgs* = ref object of Args
+ publicKey*: string
+ isUntrustworthy*: bool
+
ResolvedContactArgs* = ref object of Args
pubkey*: string
address*: string
@@ -36,6 +40,9 @@ type
ContactsStatusUpdatedArgs* = ref object of Args
statusUpdates*: seq[StatusUpdateDto]
+ VerificationRequestArgs* = ref object of Args
+ verificationRequest*: VerificationRequest
+
# Local Constants:
const CheckStatusIntervalInMilliseconds = 5000 # 5 seconds, this is timeout how often do we check for user status.
const FiveMinsOnlineLimitInSeconds = int(5 * 60) # 5 minutes
@@ -52,6 +59,16 @@ const SIGNAL_CONTACT_NICKNAME_CHANGED* = "contactNicknameChanged"
const SIGNAL_CONTACTS_STATUS_UPDATED* = "contactsStatusUpdated"
const SIGNAL_CONTACT_UPDATED* = "contactUpdated"
const SIGNAL_LOGGEDIN_USER_IMAGE_CHANGED* = "loggedInUserImageChanged"
+const SIGNAL_REMOVED_TRUST_STATUS* = "removedTrustStatus"
+const SIGNAL_CONTACT_UNTRUSTWORTHY* = "contactUntrustworthy"
+const SIGNAL_CONTACT_TRUSTED* = "contactTrusted"
+const SIGNAL_CONTACT_VERIFIED* = "contactVerified"
+const SIGNAL_CONTACT_VERIFICATION_SENT* = "contactVerificationRequestSent"
+const SIGNAL_CONTACT_VERIFICATION_CANCELLED* = "contactVerificationRequestCancelled"
+const SIGNAL_CONTACT_VERIFICATION_DECLINED* = "contactVerificationRequestDeclined"
+const SIGNAL_CONTACT_VERIFICATION_ACCEPTED* = "contactVerificationRequestAccepted"
+const SIGNAL_CONTACT_VERIFICATION_ADDED* = "contactVerificationRequestAdded"
+const SIGNAL_CONTACT_VERIFICATION_UPDATED* = "contactVerificationRequestUpdated"
type
ContactsGroup* {.pure.} = enum
@@ -69,6 +86,7 @@ QtObject:
networkService: network_service.Service
contacts: Table[string, ContactsDto] # [contact_id, ContactsDto]
contactsStatus: Table[string, StatusUpdateDto] # [contact_id, StatusUpdateDto]
+ receivedIdentityRequests: Table[string, VerificationRequest] # [from_id, VerificationRequest]
events: EventEmitter
closingApp: bool
imageServerUrl: string
@@ -77,11 +95,13 @@ QtObject:
proc getContactById*(self: Service, id: string): ContactsDto
proc saveContact(self: Service, contact: ContactsDto)
proc startCheckingContactStatuses(self: Service)
+ proc fetchReceivedVerificationRequests*(self: Service) : seq[VerificationRequest]
proc delete*(self: Service) =
self.closingApp = true
self.contacts.clear
self.contactsStatus.clear
+ self.receivedIdentityRequests.clear
self.QObject.delete
proc newService*(
@@ -96,6 +116,8 @@ QtObject:
result.networkService = networkService
result.threadpool = threadpool
result.contacts = initTable[string, ContactsDto]()
+ result.contactsStatus = initTable[string, StatusUpdateDto]()
+ result.receivedIdentityRequests = initTable[string, VerificationRequest]()
proc addContact(self: Service, contact: ContactsDto) =
# Private proc, used for adding contacts only.
@@ -111,9 +133,13 @@ QtObject:
for contact in contacts:
self.addContact(contact)
+ # Identity verifications
+ for request in self.fetchReceivedVerificationRequests():
+ self.receivedIdentityRequests[request.fromId] = request
+
except Exception as e:
let errDesription = e.msg
- error "error: ", errDesription
+ error "error fetching contacts: ", errDesription
return
proc doConnect(self: Service) =
@@ -140,6 +166,31 @@ QtObject:
let data = ContactArgs(contactId: c.id)
self.events.emit(SIGNAL_CONTACT_UPDATED, data)
+ let myPubKey = singletonInstance.userProfile.getPubKey()
+ if(receivedData.verificationRequests.len > 0):
+ for request in receivedData.verificationRequests:
+ if request.fromId == myPubKey:
+ # TODO handle reacting to my own request later
+ continue
+
+ let data = VerificationRequestArgs(verificationRequest: request)
+ let alreadyContains = self.receivedIdentityRequests.contains(request.fromId)
+ self.receivedIdentityRequests[request.fromId] = request
+
+ if alreadyContains:
+ self.events.emit(SIGNAL_CONTACT_VERIFICATION_UPDATED, data)
+
+ if request.status == VerificationStatus.Trusted:
+ if self.contacts.hasKey(request.fromId):
+ self.contacts[request.fromId].trustStatus = TrustStatus.Trusted
+ self.contacts[request.fromId].verificationStatus = VerificationStatus.Trusted
+
+ self.events.emit(SIGNAL_CONTACT_TRUSTED,
+ TrustArgs(publicKey: request.fromId, isUntrustworthy: false))
+ self.events.emit(SIGNAL_CONTACT_VERIFIED, ContactArgs(contactId: request.fromId))
+ else:
+ self.events.emit(SIGNAL_CONTACT_VERIFICATION_ADDED, data)
+
proc setImageServerUrl(self: Service) =
try:
let response = status_contacts.getImageServerURL()
@@ -222,6 +273,15 @@ QtObject:
return
return status_accounts.generateAlias(publicKey).result.getStr
+ proc getTrustStatus*(self: Service, publicKey: string): TrustStatus =
+ try:
+ let t = status_contacts.getTrustStatus(publicKey).result.getInt
+ return t.toTrustStatus()
+ except Exception as e:
+ let errDesription = e.msg
+ error "error: ", errDesription
+ return TrustStatus.Unknown
+
proc getContactById*(self: Service, id: string): ContactsDto =
if(id == singletonInstance.userProfile.getPubKey()):
# If we try to get the contact details of ourselves, just return our own info
@@ -235,7 +295,8 @@ QtObject:
image: Images(
thumbnail: singletonInstance.userProfile.getThumbnailImage(),
large: singletonInstance.userProfile.getLargeImage()
- )
+ ),
+ trustStatus: TrustStatus.Trusted
)
## Returns contact details based on passed id (public key)
@@ -256,13 +317,15 @@ QtObject:
return
let alias = self.generateAlias(id)
+ let trustStatus = self.getTrustStatus(id)
result = ContactsDto(
id: id,
alias: alias,
ensVerified: false,
added: false,
blocked: false,
- hasAddedUs: false
+ hasAddedUs: false,
+ trustStatus: trustStatus
)
self.addContact(result)
@@ -390,6 +453,7 @@ QtObject:
proc removeContact*(self: Service, publicKey: string) =
var contact = self.getContactById(publicKey)
contact.removed = true
+ contact.added = false
let response = status_contacts.removeContact(contact.id)
if(not response.error.isNil):
@@ -465,3 +529,164 @@ QtObject:
result.icon = icon
result.isCurrentUser = pubKey == singletonInstance.userProfile.getPubKey()
result.details = self.getContactById(pubKey)
+
+ proc markUntrustworthy*(self: Service, publicKey: string) =
+ let response = status_contacts.markUntrustworthy(publicKey)
+ if(not response.error.isNil):
+ let msg = response.error.message
+ error "error marking as untrustworthy ", msg
+ return
+
+ if self.contacts.hasKey(publicKey):
+ self.contacts[publicKey].trustStatus = TrustStatus.Untrustworthy
+
+ self.events.emit(SIGNAL_CONTACT_UNTRUSTWORTHY,
+ TrustArgs(publicKey: publicKey, isUntrustworthy: true))
+
+ proc verifiedTrusted*(self: Service, publicKey: string) =
+ let response = status_contacts.verifiedTrusted(publicKey)
+ if(not response.error.isNil):
+ let msg = response.error.message
+ error "error confirming identity ", msg
+ return
+
+ if self.contacts.hasKey(publicKey):
+ self.contacts[publicKey].trustStatus = TrustStatus.Trusted
+ self.contacts[publicKey].verificationStatus = VerificationStatus.Trusted
+
+ self.events.emit(SIGNAL_CONTACT_TRUSTED,
+ TrustArgs(publicKey: publicKey, isUntrustworthy: false))
+ self.events.emit(SIGNAL_CONTACT_VERIFIED, ContactArgs(contactId: publicKey))
+
+ proc verifiedUntrustworthy*(self: Service, publicKey: string) =
+ let response = status_contacts.verifiedUntrustworthy(publicKey)
+ if(not response.error.isNil):
+ let msg = response.error.message
+ error "error confirming identity ", msg
+ return
+
+ if self.contacts.hasKey(publicKey):
+ self.contacts[publicKey].trustStatus = TrustStatus.Untrustworthy
+ self.contacts[publicKey].verificationStatus = VerificationStatus.Verified
+
+ self.events.emit(SIGNAL_CONTACT_UNTRUSTWORTHY,
+ TrustArgs(publicKey: publicKey, isUntrustworthy: true))
+ self.events.emit(SIGNAL_CONTACT_VERIFIED, ContactArgs(contactId: publicKey))
+
+ proc removeTrustStatus*(self: Service, publicKey: string) =
+ let response = status_contacts.removeTrustStatus(publicKey)
+ if(not response.error.isNil):
+ let msg = response.error.message
+ error "error removing trust status", msg
+ return
+
+ if self.contacts.hasKey(publicKey):
+ self.contacts[publicKey].trustStatus = TrustStatus.Unknown
+ if self.contacts[publicKey].verificationStatus == VerificationStatus.Verified:
+ self.contacts[publicKey].verificationStatus = VerificationStatus.Unverified
+
+ self.events.emit(SIGNAL_REMOVED_TRUST_STATUS,
+ TrustArgs(publicKey: publicKey, isUntrustworthy: false))
+
+ proc getVerificationRequestSentTo*(self: Service, publicKey: string): VerificationRequest =
+ try:
+ let response = status_contacts.getVerificationRequestSentTo(publicKey)
+ return response.result.toVerificationRequest()
+ except Exception as e:
+ let errDesription = e.msg
+ error "error obtaining verification request", errDesription
+ return
+
+ proc getVerificationRequestFrom*(self: Service, publicKey: string): VerificationRequest =
+ try:
+ if (self.receivedIdentityRequests.contains(publicKey)):
+ return self.receivedIdentityRequests[publicKey]
+
+ let response = status_contacts.getVerificationRequestFrom(publicKey)
+ result = response.result.toVerificationRequest()
+ self.receivedIdentityRequests[publicKey] = result
+ except Exception as e:
+ let errDesription = e.msg
+ error "error obtaining verification request", errDesription
+
+ proc fetchReceivedVerificationRequests*(self: Service): seq[VerificationRequest] =
+ try:
+ let response = status_contacts.getReceivedVerificationRequests()
+
+ for request in response.result:
+ result.add(request.toVerificationRequest())
+ except Exception as e:
+ let errDesription = e.msg
+ error "error obtaining verification requests", errDesription
+
+ proc getReceivedVerificationRequests*(self: Service): seq[VerificationRequest] =
+ result = toSeq(self.receivedIdentityRequests.values)
+
+ proc hasReceivedVerificationRequestFrom*(self: Service, fromId: string): bool =
+ result = self.receivedIdentityRequests.contains(fromId)
+
+ proc sendVerificationRequest*(self: Service, publicKey: string, challenge: string) =
+ try:
+ let response = status_contacts.sendVerificationRequest(publicKey, challenge)
+ if(not response.error.isNil):
+ let msg = response.error.message
+ error "error sending contact verification request", msg
+ return
+
+ var contact = self.getContactById(publicKey)
+ contact.verificationStatus = VerificationStatus.Verifying
+ self.saveContact(contact)
+
+ self.events.emit(SIGNAL_CONTACT_VERIFICATION_SENT, ContactArgs(contactId: publicKey))
+ except Exception as e:
+ error "Error sending verification request", msg = e.msg
+
+ proc cancelVerificationRequest*(self: Service, publicKey: string) =
+ try:
+ let response = status_contacts.cancelVerificationRequest(publicKey)
+ if(not response.error.isNil):
+ let msg = response.error.message
+ error "error sending contact verification request", msg
+ return
+
+ var contact = self.getContactById(publicKey)
+ contact.verificationStatus = VerificationStatus.Unverified
+ self.saveContact(contact)
+
+ self.events.emit(SIGNAL_CONTACT_VERIFICATION_CANCELLED, ContactArgs(contactId: publicKey))
+ except Exception as e:
+ error "Error canceling verification request", msg = e.msg
+
+ proc acceptVerificationRequest*(self: Service, publicKey: string, responseText: string) =
+ try:
+ let response = status_contacts.acceptVerificationRequest(publicKey, responseText)
+ if(not response.error.isNil):
+ let msg = response.error.message
+ raise newException(RpcException, msg)
+
+ var request = self.receivedIdentityRequests[publicKey]
+ request.status = VerificationStatus.Verified
+ request.response = responseText
+ request.repliedAt = getTime().toUnix * 1000
+ self.receivedIdentityRequests[publicKey] = request
+
+ self.events.emit(SIGNAL_CONTACT_VERIFICATION_ACCEPTED,
+ VerificationRequestArgs(verificationRequest: request))
+ except Exception as e:
+ error "error accepting contact verification request", msg=e.msg
+
+ proc declineVerificationRequest*(self: Service, publicKey: string) =
+ try:
+ let response = status_contacts.declineVerificationRequest(publicKey)
+ if(not response.error.isNil):
+ let msg = response.error.message
+ raise newException(RpcException, msg)
+
+ var request = self.receivedIdentityRequests[publicKey]
+ request.status = VerificationStatus.Declined
+ self.receivedIdentityRequests[publicKey] = request
+
+ self.events.emit(SIGNAL_CONTACT_VERIFICATION_DECLINED, ContactArgs(contactId: publicKey))
+ except Exception as e:
+ error "error declining contact verification request", msg=e.msg
+
\ No newline at end of file
diff --git a/src/backend/contacts.nim b/src/backend/contacts.nim
index 8c4db60fab..1dc22ff0cb 100644
--- a/src/backend/contacts.nim
+++ b/src/backend/contacts.nim
@@ -54,3 +54,51 @@ proc sendContactUpdate*(publicKey, ensName, thumbnail: string): RpcResponse[Json
proc getImageServerURL*(): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* []
result = callPrivateRPC("imageServerURL".prefix, payload)
+
+proc markUntrustworthy*(pubkey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
+ let payload = %* [pubkey]
+ result = callPrivateRPC("markAsUntrustworthy".prefix, payload)
+
+proc verifiedTrusted*(pubkey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
+ let payload = %* [pubkey]
+ result = callPrivateRPC("verifiedTrusted".prefix, payload)
+
+proc verifiedUntrustworthy*(pubkey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
+ let payload = %* [pubkey]
+ result = callPrivateRPC("verifiedUntrustworthy".prefix, payload)
+
+proc removeTrustStatus*(pubkey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
+ let payload = %* [pubkey]
+ result = callPrivateRPC("removeTrustStatus".prefix, payload)
+
+proc getTrustStatus*(pubkey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
+ let payload = %* [pubkey]
+ result = callPrivateRPC("getTrustStatus".prefix, payload)
+
+proc sendVerificationRequest*(pubkey: string, challenge: string): RpcResponse[JsonNode] {.raises: [Exception].} =
+ let payload = %* [pubkey, challenge]
+ result = callPrivateRPC("sendContactVerificationRequest".prefix, payload)
+
+proc acceptVerificationRequest*(pubkey: string, response: string): RpcResponse[JsonNode] {.raises: [Exception].} =
+ let payload = %* [pubkey, response]
+ result = callPrivateRPC("acceptContactVerificationRequest".prefix, payload)
+
+proc declineVerificationRequest*(pubkey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
+ let payload = %* [pubkey]
+ result = callPrivateRPC("declineContactVerificationRequest".prefix, payload)
+
+proc getVerificationRequestSentTo*(pubkey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
+ let payload = %* [pubkey]
+ result = callPrivateRPC("getVerificationRequestSentTo".prefix, payload)
+
+proc getVerificationRequestFrom*(pubkey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
+ let payload = %* [pubkey]
+ result = callPrivateRPC("getVerificationRequestFrom".prefix, payload)
+
+proc getReceivedVerificationRequests*(): RpcResponse[JsonNode] {.raises: [Exception].} =
+ let payload = %* []
+ result = callPrivateRPC("getReceivedVerificationRequests".prefix, payload)
+
+proc cancelVerificationRequest*(pubkey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
+ let payload = %* [pubkey]
+ result = callPrivateRPC("cancelVerificationRequest".prefix, payload)
diff --git a/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml b/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml
index 6b6feec1e8..33bc243974 100644
--- a/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml
+++ b/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml
@@ -129,6 +129,7 @@ ModalPopup {
pinnedMessage: model.pinned
messagePinnedBy: model.pinnedBy
reactionsModel: model.reactions
+ senderTrustStatus: model.senderTrustStatus
linkUrls: model.links
isInPinnedPopup: true
transactionParams: model.transactionParameters
diff --git a/ui/app/AppLayouts/Chat/views/ActivityCenterMessageComponentView.qml b/ui/app/AppLayouts/Chat/views/ActivityCenterMessageComponentView.qml
index 88b248f83a..3d53c77b14 100644
--- a/ui/app/AppLayouts/Chat/views/ActivityCenterMessageComponentView.qml
+++ b/ui/app/AppLayouts/Chat/views/ActivityCenterMessageComponentView.qml
@@ -135,6 +135,7 @@ Item {
messageTimestamp: model.timestamp
messageOutgoingStatus: model.message.outgoingStatus
messageContentType: model.message.contentType
+ senderTrustStatus: model.message.senderTrustStatus
activityCenterMessage: true
read: model.read
onImageClicked: Global.openImagePopup(image, root.messageContextMenu)
diff --git a/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml b/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml
index 9247b72376..72a47c4bb8 100644
--- a/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml
+++ b/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml
@@ -303,6 +303,7 @@ Item {
messageTimestamp: model.timestamp
messageOutgoingStatus: model.outgoingStatus
messageContentType: model.contentType
+ senderTrustStatus: model.senderTrustStatus
pinnedMessage: model.pinned
messagePinnedBy: model.pinnedBy
reactionsModel: model.reactions
diff --git a/ui/app/AppLayouts/Profile/ProfileLayout.qml b/ui/app/AppLayouts/Profile/ProfileLayout.qml
index 9b41f7fcb4..735409f570 100644
--- a/ui/app/AppLayouts/Profile/ProfileLayout.qml
+++ b/ui/app/AppLayouts/Profile/ProfileLayout.qml
@@ -135,6 +135,7 @@ StatusAppTwoPanelLayout {
messagingStore: profileView.store.messagingStore
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.messaging)
+ contactsStore: profileView.store.contactsStore
contentWidth: d.contentWidth
}
diff --git a/ui/app/AppLayouts/Profile/panels/ContactPanel.qml b/ui/app/AppLayouts/Profile/panels/ContactPanel.qml
index 8ef9bd7763..494bff5968 100644
--- a/ui/app/AppLayouts/Profile/panels/ContactPanel.qml
+++ b/ui/app/AppLayouts/Profile/panels/ContactPanel.qml
@@ -31,6 +31,7 @@ StatusListItem {
property bool isBlocked: false
property bool isVerified: false
property bool isUntrustworthy: false
+ property int verificationRequestStatus: 0
property string searchStr: ""
@@ -44,12 +45,24 @@ StatusListItem {
signal openProfilePopup(string publicKey)
signal openChangeNicknamePopup(string publicKey)
signal sendMessageActionTriggered(string publicKey)
+ signal showVerificationRequest(string publicKey)
signal contactRequestAccepted(string publicKey)
signal contactRequestRejected(string publicKey)
signal rejectionRemoved(string publicKey)
signal textClicked(string publicKey)
components: [
+ StatusFlatButton {
+ visible: verificationRequestStatus === Constants.verificationStatus.verifying ||
+ verificationRequestStatus === Constants.verificationStatus.verified
+ width: visible ? implicitWidth : 0
+ height: visible ? implicitHeight : 0
+ text: verificationRequestStatus === Constants.verificationStatus.verifying ?
+ qsTr("Respond to ID Request") :
+ qsTr("See ID Request")
+ size: StatusBaseButton.Size.Small
+ onClicked: container.showVerificationRequest(container.publicKey)
+ },
StatusFlatRoundButton {
visible: showSendMessageButton
width: visible ? 32 : 0
diff --git a/ui/app/AppLayouts/Profile/panels/ContactsListPanel.qml b/ui/app/AppLayouts/Profile/panels/ContactsListPanel.qml
index 736c52c0e9..faec97c03f 100644
--- a/ui/app/AppLayouts/Profile/panels/ContactsListPanel.qml
+++ b/ui/app/AppLayouts/Profile/panels/ContactsListPanel.qml
@@ -27,6 +27,7 @@ Item {
signal contactClicked(string publicKey)
signal openProfilePopup(string publicKey)
signal sendMessageActionTriggered(string publicKey)
+ signal showVerificationRequest(string publicKey)
signal openChangeNicknamePopup(string publicKey)
signal contactRequestAccepted(string publicKey)
signal contactRequestRejected(string publicKey)
@@ -115,19 +116,20 @@ Item {
isBlocked: model.isBlocked
isVerified: model.isVerified
isUntrustworthy: model.isUntrustworthy
+ verificationRequestStatus: model.incomingVerificationStatus
searchStr: contactListRoot.searchString
showSendMessageButton: model.isContact
showRejectContactRequestButton: {
- if (contactListRoot.panelUsage === Constants.contactsPanelUsage.receivedContactRequest) {
+ if (contactListRoot.panelUsage === Constants.contactsPanelUsage.receivedContactRequest && !model.verificationRequestStatus) {
return true
}
return false
}
showAcceptContactRequestButton: {
- if (contactListRoot.panelUsage === Constants.contactsPanelUsage.receivedContactRequest) {
+ if (contactListRoot.panelUsage === Constants.contactsPanelUsage.receivedContactRequest && !model.verificationRequestStatus) {
return true
}
@@ -162,6 +164,7 @@ Item {
onContactRequestRejected: contactListRoot.contactRequestRejected(publicKey)
onRejectionRemoved: contactListRoot.rejectionRemoved(publicKey)
onTextClicked: contactListRoot.textClicked(publicKey)
+ onShowVerificationRequest: contactListRoot.showVerificationRequest(publicKey)
visible: searchString === "" ||
panelDelegate.name.toLowerCase().includes(lowerCaseSearchString) ||
diff --git a/ui/app/AppLayouts/Profile/panels/MenuPanel.qml b/ui/app/AppLayouts/Profile/panels/MenuPanel.qml
index e1ea7e0ac2..b82f385c58 100644
--- a/ui/app/AppLayouts/Profile/panels/MenuPanel.qml
+++ b/ui/app/AppLayouts/Profile/panels/MenuPanel.qml
@@ -11,7 +11,7 @@ Column {
spacing: 4
property var privacyStore
- property var messagingStore
+ property var contactsStore
property alias mainMenuItems: mainMenuItems.model
property alias settingsMenuItems: settingsMenuItems.model
property alias extraMenuItems: extraMenuItems.model
@@ -71,7 +71,7 @@ Column {
badge.value: {
switch (model.subsection) {
case Constants.settingsSubsection.messaging:
- return root.messagingStore.contactRequestsModel.count
+ return root.contactsStore.receivedContactRequestsModel.count
default: return ""
}
}
diff --git a/ui/app/AppLayouts/Profile/stores/ContactsStore.qml b/ui/app/AppLayouts/Profile/stores/ContactsStore.qml
index f1008f1521..78f452eddd 100644
--- a/ui/app/AppLayouts/Profile/stores/ContactsStore.qml
+++ b/ui/app/AppLayouts/Profile/stores/ContactsStore.qml
@@ -80,4 +80,50 @@ QtObject {
function removeContactRequestRejection(pubKey) {
root.contactsModule.removeContactRequestRejection(pubKey)
}
+
+ function markUntrustworthy(pubKey) {
+ root.contactsModule.markUntrustworthy(pubKey)
+ }
+
+ function removeTrustStatus(pubKey) {
+ root.contactsModule.removeTrustStatus(pubKey)
+ }
+
+ function sendVerificationRequest(pubKey, challenge) {
+ root.contactsModule.sendVerificationRequest(pubKey, challenge);
+ }
+
+ function cancelVerificationRequest(pubKey) {
+ root.contactsModule.cancelVerificationRequest(pubKey);
+ }
+
+ function declineVerificationRequest(pubKey) {
+ root.contactsModule.declineVerificationRequest(pubKey);
+ }
+
+ function acceptVerificationRequest(pubKey, response) {
+ root.contactsModule.acceptVerificationRequest(pubKey, response);
+ }
+
+ function getVerificationDetailsFromAsJson(pubKey) {
+ let resp = root.contactsModule.getVerificationDetailsFromAsJson(pubKey);
+ return JSON.parse(resp);
+ }
+
+ function getSentVerificationDetailsAsJson(pubKey) {
+ let resp = root.contactsModule.getSentVerificationDetailsAsJson(pubKey);
+ return JSON.parse(resp);
+ }
+
+ function hasReceivedVerificationRequestFrom(pubKey) {
+ return root.contactsModule.hasReceivedVerificationRequestFrom(pubKey);
+ }
+
+ function verifiedTrusted(pubKey) {
+ root.contactsModule.verifiedTrusted(pubKey);
+ }
+
+ function verifiedUntrustworthy(pubKey) {
+ root.contactsModule.verifiedUntrustworthy(pubKey);
+ }
}
diff --git a/ui/app/AppLayouts/Profile/stores/MessagingStore.qml b/ui/app/AppLayouts/Profile/stores/MessagingStore.qml
index 189bf99868..67b8dabbbd 100644
--- a/ui/app/AppLayouts/Profile/stores/MessagingStore.qml
+++ b/ui/app/AppLayouts/Profile/stores/MessagingStore.qml
@@ -10,11 +10,6 @@ QtObject {
property int profilePicturesVisibility: privacyModule.profilePicturesVisibility
property int profilePicturesShowTo: privacyModule.profilePicturesShowTo
- // TODO move contact requests back to the contacts module since we need them in the Profile
- // also, having them in the chat section creates some waste, since no community has it
- property var chatSectionModule: mainModule.getChatSectionModule()
- property var contactRequestsModel: chatSectionModule.contactRequestsModel
-
property var mailservers: syncModule.model
property bool useMailservers: syncModule.useMailservers
diff --git a/ui/app/AppLayouts/Profile/views/ContactsView.qml b/ui/app/AppLayouts/Profile/views/ContactsView.qml
index d356a6b27f..6134e9a9bb 100644
--- a/ui/app/AppLayouts/Profile/views/ContactsView.qml
+++ b/ui/app/AppLayouts/Profile/views/ContactsView.qml
@@ -17,8 +17,6 @@ import shared.controls 1.0
import "../stores"
import "../panels"
import "../popups"
-// TODO remove this import when the ContactRequestPanel is moved to the the Profile completely
-import "../../Chat/panels"
SettingsContentBase {
id: root
@@ -181,6 +179,23 @@ SettingsContentBase {
onContactRequestRejected: {
root.contactsStore.rejectContactRequest(publicKey)
}
+
+ onShowVerificationRequest: {
+ try {
+ let request = root.contactsStore.getVerificationDetailsFromAsJson(publicKey)
+ Global.openPopup(contactVerificationRequestPopupComponent, {
+ senderPublicKey: request.from,
+ senderDisplayName: request.displayName,
+ senderIcon: request.icon,
+ challengeText: request.challenge,
+ responseText: request.response,
+ messageTimestamp: request.requestedAt,
+ responseTimestamp: request.repliedAt
+ })
+ } catch (e) {
+ console.error("Error getting or parsing verification data", e)
+ }
+ }
}
ContactsListPanel {
@@ -304,6 +319,18 @@ SettingsContentBase {
root.contactsStore.removeContact(removeContactConfirmationDialog.value);
}
removeContactConfirmationDialog.close()
+ }
+ }
+
+ Component {
+ id: contactVerificationRequestPopupComponent
+ ContactVerificationRequestPopup {
+ onResponseSent: {
+ root.contactsStore.acceptVerificationRequest(senderPublicKey, response)
+ }
+ onVerificationRefused: {
+ root.contactsStore.declineVerificationRequest(senderPublicKey)
+ }
}
}
diff --git a/ui/app/AppLayouts/Profile/views/LeftTabView.qml b/ui/app/AppLayouts/Profile/views/LeftTabView.qml
index 45eb81cc03..379dec4000 100644
--- a/ui/app/AppLayouts/Profile/views/LeftTabView.qml
+++ b/ui/app/AppLayouts/Profile/views/LeftTabView.qml
@@ -38,7 +38,7 @@ Item {
MenuPanel {
id: profileMenu
privacyStore: store.privacyStore
- messagingStore: store.messagingStore
+ contactsStore: store.contactsStore
mainMenuItems: store.mainMenuItems
settingsMenuItems: store.settingsMenuItems
extraMenuItems: store.extraMenuItems
diff --git a/ui/app/AppLayouts/Profile/views/MessagingView.qml b/ui/app/AppLayouts/Profile/views/MessagingView.qml
index 65c34113fe..07bfd5afbd 100644
--- a/ui/app/AppLayouts/Profile/views/MessagingView.qml
+++ b/ui/app/AppLayouts/Profile/views/MessagingView.qml
@@ -24,6 +24,7 @@ SettingsContentBase {
id: root
property MessagingStore messagingStore
+ property ContactsStore contactsStore
ColumnLayout {
id: generalColumn
@@ -214,7 +215,7 @@ SettingsContentBase {
StatusContactRequestsIndicatorListItem {
Layout.fillWidth: true
title: qsTr("Contacts, Requests, and Blocked Users")
- requestsCount: root.messagingStore.contactRequestsModel.count
+ requestsCount: root.contactsStore.receivedContactRequestsModel.count
sensor.onClicked: Global.changeAppSectionBySectionType(Constants.appSection.profile,
Constants.settingsSubsection.contacts)
}
diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml
index 89f202adbd..b57be18920 100644
--- a/ui/app/mainui/AppMain.qml
+++ b/ui/app/mainui/AppMain.qml
@@ -107,6 +107,10 @@ Item {
onDisplayToastMessage: {
appMain.rootStore.mainModuleInst.displayEphemeralNotification(title, subTitle, icon, loading, ephNotifType, url);
}
+ onOpenEditDisplayNamePopup: {
+ var popup = displayNamePopupComponent.createObject(appMain)
+ popup.open()
+ }
}
function changeAppSectionBySectionId(sectionId) {
@@ -151,6 +155,13 @@ Item {
privacyStore: appMain.rootStore.profileSectionStore.privacyStore
}
+ property Component displayNamePopupComponent: DisplayNamePopup {
+ profileStore: appMain.rootStore.profileSectionStore.profileStore
+ onClosed: {
+ destroy()
+ }
+ }
+
Component {
id: downloadPageComponent
DownloadPage {
diff --git a/ui/imports/assets/icons/contact.svg b/ui/imports/assets/icons/contact.svg
new file mode 100644
index 0000000000..10a8c22721
--- /dev/null
+++ b/ui/imports/assets/icons/contact.svg
@@ -0,0 +1,5 @@
+
diff --git a/ui/imports/assets/icons/untrustworthy.svg b/ui/imports/assets/icons/untrustworthy.svg
new file mode 100644
index 0000000000..2c50e489de
--- /dev/null
+++ b/ui/imports/assets/icons/untrustworthy.svg
@@ -0,0 +1,4 @@
+
diff --git a/ui/imports/assets/icons/verified.svg b/ui/imports/assets/icons/verified.svg
new file mode 100644
index 0000000000..4eb91e85f1
--- /dev/null
+++ b/ui/imports/assets/icons/verified.svg
@@ -0,0 +1,4 @@
+
diff --git a/ui/imports/shared/controls/Input.qml b/ui/imports/shared/controls/Input.qml
index 45c8617040..85eaec2a1d 100644
--- a/ui/imports/shared/controls/Input.qml
+++ b/ui/imports/shared/controls/Input.qml
@@ -125,12 +125,7 @@ Item {
anchors.fill: parent
acceptedButtons: Qt.RightButton | Qt.LeftButton
onClicked: {
- if((mouse.button === Qt.RightButton) && inputValue.canPaste) {
- rightClickContextMenu.popup()
- }
- else {
- inputValue.forceActiveFocus(Qt.MouseFocusReason)
- }
+ inputValue.forceActiveFocus(Qt.MouseFocusReason)
}
}
}
@@ -183,9 +178,7 @@ Item {
if (inputBox.copyToClipboard) {
RootStore.copyToClipboard(inputBox.textToCopy ? inputBox.textToCopy : inputValue.text)
} else {
- if (inputValue.canPaste) {
- inputValue.paste()
- }
+ inputValue.paste()
}
copyBtn.copied = true
@@ -211,22 +204,6 @@ Item {
color: validationErrorColor
wrapMode: TextEdit.Wrap
}
-
- StatusPopupMenu {
- id: rightClickContextMenu
-
- StatusMenuItem {
- enabled: inputValue.canPaste
- text: qsTrId("Paste")
- onTriggered: {
- inputValue.paste()
- }
- }
-
- onClosed: {
- inputValue.forceActiveFocus(Qt.MouseFocusReason)
- }
- }
}
/*##^##
diff --git a/ui/imports/shared/controls/chat/ProfileHeader.qml b/ui/imports/shared/controls/chat/ProfileHeader.qml
index dc6421b60d..cf7fc322ff 100644
--- a/ui/imports/shared/controls/chat/ProfileHeader.qml
+++ b/ui/imports/shared/controls/chat/ProfileHeader.qml
@@ -18,18 +18,24 @@ Item {
Big
}
+ property var store
property string displayName
property string pubkey
property string icon
+ property int trustStatus
+ property bool isContact: false
property int imageSize: ProfileHeader.ImageSize.Compact
property bool displayNameVisible: true
+ property bool displayNamePlusIconsVisible: false
property bool pubkeyVisible: true
+ property bool pubkeyVisibleWithCopy: false
property bool emojiHashVisible: true
property bool editImageButtonVisible: false
readonly property bool compact: root.imageSize == ProfileHeader.ImageSize.Compact
signal clicked()
+ signal editClicked()
height: visible ? contentContainer.height : 0
implicitHeight: contentContainer.implicitHeight
@@ -108,9 +114,56 @@ Item {
}
}
+ Row {
+ width: 380
+ spacing: Style.current.halfPadding
+ Layout.alignment: Qt.AlignHCenter
+ visible: root.displayNamePlusIconsVisible
+ StyledText {
+ text: root.displayName
+ font {
+ weight: Font.Medium
+ pixelSize: Style.current.primaryTextFontSize
+ }
+ }
+
+ Loader {
+ sourceComponent: SVGImage {
+ height: 16
+ width: 16
+ source: Style.svg("contact")
+ }
+ active: isContact
+ }
+
+ Loader {
+ sourceComponent: VerificationLabel {
+ id: trustStatus
+ trustStatus: root.trustStatus
+ height: 16
+ width: 16
+ }
+ active: root.trustStatus !== Constants.trustStatus.unknown
+ }
+
+ SVGImage {
+ height: 16
+ width: 16
+ source: Style.svg("edit-message")
+ MouseArea {
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ acceptedButtons: Qt.LeftButton
+ onClicked: {
+ root.editClicked()
+ }
+ }
+ }
+
+ }
+
StyledText {
Layout.fillWidth: true
-
visible: root.pubkeyVisible
text: Utils.getElidedCompressedPk(pubkey)
@@ -120,6 +173,31 @@ Item {
color: Style.current.secondaryText
}
+ Row {
+ width: 380
+ Layout.alignment: Qt.AlignHCenter
+ visible: root.pubkeyVisibleWithCopy
+ StyledText {
+ id: txtChatKey
+ text: qsTr("Chatkey:%1...").arg(pubkey.substring(0, 32))
+ horizontalAlignment: Text.AlignHCenter
+ font.pixelSize: Style.current.primaryTextFontSize
+ color: Style.current.secondaryText
+ width: 360
+ }
+
+
+ CopyToClipBoardButton {
+ id: copyBtn
+ width: 20
+ height: 20
+ color: Style.current.transparent
+ textToCopy: pubkey
+ store: root.store
+ }
+
+ }
+
EmojiHash {
id: emojiHash
Layout.alignment: Qt.AlignHCenter
diff --git a/ui/imports/shared/controls/chat/VerificationLabel.qml b/ui/imports/shared/controls/chat/VerificationLabel.qml
new file mode 100644
index 0000000000..00f1b22a9b
--- /dev/null
+++ b/ui/imports/shared/controls/chat/VerificationLabel.qml
@@ -0,0 +1,25 @@
+import QtQuick 2.3
+import shared.controls 1.0
+import shared 1.0
+import shared.panels 1.0
+
+import utils 1.0
+
+SVGImage {
+ id: root
+ width: 10
+ height: 10
+
+ property int trustStatus: Constants.trustStatus.unknown
+
+ source: {
+ switch(trustStatus) {
+ case Constants.trustStatus.trusted:
+ return Style.svg("verified");
+ case Constants.trustStatus.untrustworthy:
+ return Style.svg("untrustworthy");
+ default:
+ return "";
+ }
+ }
+}
\ No newline at end of file
diff --git a/ui/imports/shared/controls/chat/qmldir b/ui/imports/shared/controls/chat/qmldir
index 08a4866415..0b873cd121 100644
--- a/ui/imports/shared/controls/chat/qmldir
+++ b/ui/imports/shared/controls/chat/qmldir
@@ -13,3 +13,4 @@ GasSelectorButton 1.0 GasSelectorButton.qml
MessageBorder 1.0 MessageBorder.qml
EmojiReaction 1.0 EmojiReaction.qml
ProfileHeader 1.0 ProfileHeader.qml
+VerificationLabel 1.0 VerificationLabel.qml
diff --git a/ui/imports/shared/panels/Separator.qml b/ui/imports/shared/panels/Separator.qml
index 10355f4b88..277956258a 100644
--- a/ui/imports/shared/panels/Separator.qml
+++ b/ui/imports/shared/panels/Separator.qml
@@ -6,7 +6,8 @@ Item {
id: root
property color color: Style.current.separator
width: parent.width
- height: root.visible ? 1 : 0
+ implicitHeight: 1
+ height: root.visible ? implicitHeight : 0
anchors.topMargin: Style.current.padding
Rectangle {
id: separator
diff --git a/ui/imports/shared/popups/ContactVerificationRequestPopup.qml b/ui/imports/shared/popups/ContactVerificationRequestPopup.qml
new file mode 100644
index 0000000000..ccea785787
--- /dev/null
+++ b/ui/imports/shared/popups/ContactVerificationRequestPopup.qml
@@ -0,0 +1,151 @@
+import QtQuick 2.13
+import QtQuick.Controls 2.13
+import QtQuick.Dialogs 1.3
+
+import utils 1.0
+
+import StatusQ.Core 0.1
+import StatusQ.Core.Theme 0.1
+import StatusQ.Controls 0.1
+import StatusQ.Popups 0.1
+
+import shared.controls 1.0
+import shared.views.chat 1.0
+
+StatusModal {
+ id: root
+
+ property string senderPublicKey: ""
+ property string senderDisplayName: ""
+ property string senderIcon: ""
+ property string challengeText: ""
+ property string responseText: ""
+ property string messageTimestamp: ""
+ property string responseTimestamp: ""
+
+ signal verificationRefused(string senderPublicKey)
+ signal responseSent(string senderPublicKey, string response)
+
+ header.title: qsTr("%1 is asking you to verify your identity").arg(root.senderDisplayName)
+
+ x: Math.round(((parent ? parent.width : 0) - width) / 2)
+ y: Math.round(((parent ? parent.height : 0) - height) / 2)
+
+ width: 480
+ height: 230 + verificationMessage.height + verificationResponse.height
+
+ onOpened: {
+ verificationResponse.input.edit.forceActiveFocus(Qt.MouseFocusReason)
+ }
+ onClosed: {
+ root.destroy();
+ }
+
+ contentItem: Item {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.leftMargin: Style.current.padding
+ anchors.rightMargin: Style.current.padding
+
+ StatusBaseText {
+ id: description
+ width: parent.width
+ color: Theme.palette.directColor1
+ wrapMode: Text.WordWrap
+ anchors.top: parent.top
+ anchors.topMargin: Style.current.padding
+ text: qsTr("%1 would like to verify your identity. Answer the question to prove your identity to %2")
+ .arg(root.senderDisplayName).arg(root.senderDisplayName)
+ font.pixelSize: 15
+ }
+
+ MessageView {
+ id: verificationMessage
+ anchors.top: description.bottom
+ anchors.topMargin: Style.current.padding
+ isMessage: true
+ shouldRepeatHeader: true
+ messageTimestamp: root.messageTimestamp
+ senderDisplayName: root.senderDisplayName
+ senderIcon: root.senderIcon
+ message: root.challengeText
+ messageContentType: Constants.messageContentType.messageType
+ placeholderMessage: true
+ }
+
+ StatusInput {
+ id: verificationResponse
+ visible: !responseText
+ anchors.top: verificationMessage.bottom
+ anchors.topMargin: 5
+ input.multiline: true
+ input.placeholderText: qsTr("Provide answer to verification request from this contact.")
+ input.implicitHeight: 152
+ width: parent.width
+ input.verticalAlignment: TextEdit.AlignTop
+ leftPadding: 0
+ rightPadding: 0
+ charLimit: 280
+ }
+
+ MessageView {
+ id: responseMessage
+ visible: !!root.responseText
+ anchors.top: verificationMessage.bottom
+ isMessage: true
+ shouldRepeatHeader: true
+ messageTimestamp: root.responseTimestamp
+ senderDisplayName: userProfile.name
+ senderIcon: userProfile.icon
+ message: root.responseText
+ messageContentType: Constants.messageContentType.messageType
+ placeholderMessage: true
+ }
+
+ StatusBaseText {
+ id: responseSent
+ visible: !!root.responseText
+ width: parent.width
+ color: Theme.palette.baseColor1
+ wrapMode: Text.WordWrap
+ anchors.top: responseMessage.bottom
+ anchors.topMargin: 58
+ text: qsTr("You're answer has been sent to %1.").arg(root.senderDisplayName)
+ font.pixelSize: 13
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+
+ rightButtons: [
+ StatusButton {
+ visible: !root.responseText
+ text: qsTr("Refuse Verification")
+ onClicked: {
+ root.verificationRefused(root.senderPublicKey)
+ root.close();
+ }
+ },
+ StatusButton {
+ text: qsTr("Send Answer")
+ visible: !root.responseText
+ enabled: verificationResponse.text !== ""
+ onClicked: {
+ root.responseSent(root.senderPublicKey, Utils.escapeHtml(verificationResponse.text))
+ root.responseText = verificationResponse.text
+ root.responseTimestamp = Date.now()
+ }
+ },
+ StatusFlatButton {
+ visible: root.responseText
+ text: qsTr("Change answer")
+ onClicked: {
+ root.responseText = ""
+ }
+ },
+ StatusButton {
+ visible: root.responseText
+ text: qsTr("Close")
+ onClicked: root.close()
+ }
+ ]
+}
diff --git a/ui/app/AppLayouts/Profile/views/DisplayNamePopup.qml b/ui/imports/shared/popups/DisplayNamePopup.qml
similarity index 100%
rename from ui/app/AppLayouts/Profile/views/DisplayNamePopup.qml
rename to ui/imports/shared/popups/DisplayNamePopup.qml
diff --git a/ui/imports/shared/popups/ProfilePopup.qml b/ui/imports/shared/popups/ProfilePopup.qml
index 6d3a8f1c00..a8595e7cb3 100644
--- a/ui/imports/shared/popups/ProfilePopup.qml
+++ b/ui/imports/shared/popups/ProfilePopup.qml
@@ -9,6 +9,7 @@ import shared.popups 1.0
import shared.stores 1.0
import shared.views 1.0 as SharedViews
import shared.controls.chat 1.0
+import shared.panels 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
@@ -30,11 +31,40 @@ StatusModal {
property string userNickname: ""
property string userEnsName: ""
property string userIcon: ""
+ property int userTrustStatus: Constants.trustStatus.unknown
+ property int verificationStatus: Constants.verificationStatus.unverified
+ property string text: ""
+ property string challenge: ""
+ property string response: ""
property bool userIsEnsVerified: false
property bool userIsBlocked: false
+ property bool userIsUntrustworthy: false
+ property bool userTrustIsUnknown: false
property bool isCurrentUser: false
property bool isAddedContact: false
+ property bool isMutualContact: false
+ property bool isVerificationSent: false
+ property bool isVerified: false
+ property bool isTrusted: false
+ property bool hasReceivedVerificationRequest: false
+
+ property bool showRemoveVerified: false
+ property bool showVerifyIdentitySection: false
+ property bool showVerificationPendingSection: false
+ property bool showIdentityVerified: false
+ property bool showIdentityVerifiedUntrustworthy: false
+
+ property string verificationChallenge: ""
+ property string verificationResponse: ""
+ property string verificationResponseDisplayName: ""
+ property string verificationResponseIcon: ""
+ property string verificationRequestedAt: ""
+ property string verificationRepliedAt: ""
+
+ signal blockButtonClicked(name: string, address: string)
+ signal unblockButtonClicked(name: string, address: string)
+ signal removeButtonClicked(address: string)
signal contactUnblocked(publicKey: string)
signal contactBlocked(publicKey: string)
@@ -51,6 +81,32 @@ StatusModal {
userIsEnsVerified = contactDetails.ensVerified;
userIsBlocked = contactDetails.isBlocked;
isAddedContact = contactDetails.isContact;
+ isMutualContact = contactDetails.isContact && contactDetails.hasAddedUs
+ userTrustStatus = contactDetails.trustStatus
+ userTrustIsUnknown = contactDetails.trustStatus === Constants.trustStatus.unknown
+ userIsUntrustworthy = contactDetails.trustStatus === Constants.trustStatus.untrustworthy
+ verificationStatus = contactDetails.verificationStatus
+ isVerificationSent = verificationStatus !== Constants.verificationStatus.unverified
+
+ if (isMutualContact && popup.contactsStore.hasReceivedVerificationRequestFrom(publicKey)) {
+ popup.hasReceivedVerificationRequest = true
+ }
+
+ if(isMutualContact && isVerificationSent) {
+ let verificationDetails = popup.contactsStore.getSentVerificationDetailsAsJson(publicKey);
+
+ verificationStatus = verificationDetails.requestStatus;
+ verificationChallenge = verificationDetails.challenge;
+ verificationResponse = verificationDetails.response;
+ verificationResponseDisplayName = verificationDetails.displayName;
+ verificationResponseIcon = verificationDetails.icon;
+ verificationRequestedAt = verificationDetails.requestedAt;
+ verificationRepliedAt = verificationDetails.repliedAt;
+ }
+ isTrusted = verificationStatus === Constants.verificationStatus.trusted
+ isVerified = verificationStatus === Constants.verificationStatus.verified
+
+ text = ""; // this is most likely unneeded
isCurrentUser = popup.profileStore.pubkey === publicKey;
showFooter = !isCurrentUser;
@@ -79,19 +135,19 @@ StatusModal {
profileView.unblockContactConfirmationDialog.open();
}
- header.title: userDisplayName + qsTr("'s Profile")
+ width: 700
+
+ header.title: {
+ if(showVerifyIdentitySection || showVerificationPendingSection){
+ return qsTr("Verify %1's Identity").arg(userIsEnsVerified ? userName : userDisplayName)
+ }
+ return qsTr("%1's Profile").arg(userIsEnsVerified ? userName : userDisplayName)
+ }
header.subTitle: userIsEnsVerified ? userName : Utils.getElidedCompressedPk(userPublicKey)
header.subTitleElide: Text.ElideMiddle
padding: 8
- QtObject {
- id: d
-
- readonly property int contentSpacing: 5
- readonly property int contentMargins: 16
- }
-
- headerActionButton: StatusFlatRoundButton {
+ headerActionButton: StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Secondary
width: 32
height: 32
@@ -120,6 +176,33 @@ StatusModal {
isAddedContact: popup.isAddedContact
isCurrentUser: popup.isCurrentUser
+ isMutualContact: popup.isMutualContact
+ isVerificationSent: popup.isVerificationSent
+ isVerified: popup.isVerified
+ isTrusted: popup.isTrusted
+ hasReceivedVerificationRequest: popup.hasReceivedVerificationRequest
+
+ userTrustStatus: popup.userTrustStatus
+ verificationStatus: popup.verificationStatus
+
+ showVerifyIdentitySection: popup.showVerifyIdentitySection
+ showVerificationPendingSection: popup.showVerificationPendingSection
+ showIdentityVerified: popup.showIdentityVerified
+ showIdentityVerifiedUntrustworthy: popup.showIdentityVerifiedUntrustworthy
+
+ challenge: popup.challenge
+ response: popup.response
+
+ userIsUntrustworthy: popup.userIsUntrustworthy
+ userTrustIsUnknown: popup.userTrustIsUnknown
+
+ verificationChallenge: popup.verificationChallenge
+ verificationResponse: popup.verificationResponse
+ verificationResponseDisplayName: popup.verificationResponseDisplayName
+ verificationResponseIcon: popup.verificationResponseIcon
+ verificationRequestedAt: popup.verificationRequestedAt
+ verificationRepliedAt: popup.verificationRepliedAt
+
onContactUnblocked: {
popup.close()
popup.contactUnblocked(publicKey)
@@ -149,7 +232,6 @@ StatusModal {
id: sendContactRequestModal
anchors.centerIn: parent
width: popup.width
- height: popup.height
visible: false
header.title: qsTr("Send Contact Request to") + " " + userDisplayName
userPublicKey: popup.userPublicKey
@@ -158,6 +240,17 @@ StatusModal {
onAccepted: popup.contactsStore.sendContactRequest(userPublicKey, message)
onClosed: popup.close()
}
+
+ leftButtons:[
+ StatusButton {
+ text: qsTr("Cancel verification")
+ visible: !isVerified && isMutualContact && isVerificationSent && showVerificationPendingSection
+ onClicked: {
+ popup.contactsStore.cancelVerificationRequest(userPublicKey);
+ popup.close()
+ }
+ }
+ ]
rightButtons: [
StatusFlatButton {
@@ -165,11 +258,12 @@ StatusModal {
qsTr("Unblock User") :
qsTr("Block User")
type: StatusBaseButton.Type.Danger
+ visible: !isAddedContact
onClicked: userIsBlocked ? unblockUser() : blockUser()
},
StatusFlatButton {
- visible: !userIsBlocked && isAddedContact
+ visible: !showRemoveVerified && !showIdentityVerified && !showVerifyIdentitySection && !showVerificationPendingSection && !userIsBlocked && isAddedContact
type: StatusBaseButton.Type.Danger
text: qsTr('Remove Contact')
onClicked: {
@@ -182,6 +276,160 @@ StatusModal {
text: qsTr("Send Contact Request")
visible: !userIsBlocked && !isAddedContact
onClicked: sendContactRequestModal.open()
+ },
+
+ StatusButton {
+ text: qsTr("Mark Untrustworthy")
+ visible: !showIdentityVerifiedUntrustworthy && !showIdentityVerified && !showVerifyIdentitySection && userTrustIsUnknown
+ enabled: !showVerificationPendingSection || verificationResponse !== ""
+ type: StatusBaseButton.Type.Danger
+ onClicked: {
+ if (showVerificationPendingSection) {
+ popup.showIdentityVerified = false;
+ popup.showIdentityVerifiedUntrustworthy = true;
+ popup.showVerificationPendingSection = false;
+ popup.showVerifyIdentitySection = false;
+ profileView.stepsListModel.setProperty(2, "stepCompleted", true);
+ popup.contactsStore.verifiedUntrustworthy(userPublicKey);
+ } else {
+ popup.contactsStore.markUntrustworthy(userPublicKey);
+ popup.close();
+ }
+ }
+ },
+
+ StatusButton {
+ text: qsTr("Remove 'Identity Verified' status")
+ visible: isTrusted && !showIdentityVerified && !showRemoveVerified
+ type: StatusBaseButton.Type.Danger
+ onClicked: {
+ showRemoveVerified = true
+ }
+ },
+
+ StatusButton {
+ text: qsTr("No")
+ visible: showRemoveVerified
+ type: StatusBaseButton.Type.Danger
+ onClicked: {
+ showRemoveVerified = false
+ }
+ },
+
+ StatusButton {
+ text: qsTr("Yes")
+ visible: showRemoveVerified
+ onClicked: {
+ popup.contactsStore.removeTrustStatus(userPublicKey);
+ popup.close();
+ }
+ },
+
+ StatusButton {
+ text: qsTr("Remove Untrustworthy Mark")
+ visible: userIsUntrustworthy
+ onClicked: {
+ popup.contactsStore.removeTrustStatus(userPublicKey);
+ popup.close();
+ }
+ },
+
+ StatusButton {
+ text: qsTr("Verify Identity")
+ visible: !showIdentityVerifiedUntrustworthy && !showIdentityVerified &&
+ !showVerifyIdentitySection && isMutualContact && !isVerificationSent
+ && !hasReceivedVerificationRequest
+ onClicked: {
+ popup.showVerifyIdentitySection = true
+ }
+ },
+
+ StatusButton {
+ text: qsTr("Verify Identity pending...")
+ visible: (!showIdentityVerifiedUntrustworthy && !showIdentityVerified && !isTrusted
+ && isMutualContact && isVerificationSent && !showVerificationPendingSection) ||
+ (hasReceivedVerificationRequest && !isTrusted)
+ onClicked: {
+ if (hasReceivedVerificationRequest) {
+ try {
+ let request = popup.contactsStore.getVerificationDetailsFromAsJson(popup.userPublicKey)
+ Global.openPopup(contactVerificationRequestPopupComponent, {
+ senderPublicKey: request.from,
+ senderDisplayName: request.displayName,
+ senderIcon: request.icon,
+ challengeText: request.challenge,
+ responseText: request.response,
+ messageTimestamp: request.requestedAt,
+ responseTimestamp: request.repliedAt
+ })
+ } catch (e) {
+ console.error("Error getting or parsing verification data", e)
+ }
+ } else {
+ popup.showVerificationPendingSection = true
+ profileView.wizardAnimation.running = true
+ }
+ }
+ },
+
+
+ StatusButton {
+ text: qsTr("Send verification request")
+ visible: showVerifyIdentitySection && isMutualContact && !isVerificationSent
+ onClicked: {
+ popup.contactsStore.sendVerificationRequest(userPublicKey, Utils.escapeHtml(profileView.challengeTxt.input.text));
+ profileView.stepsListModel.setProperty(1, "stepCompleted", true);
+ Global.displayToastMessage(qsTr("Verification request sent"),
+ "",
+ "checkmark-circle",
+ false,
+ Constants.ephemeralNotificationType.normal,
+ "");
+ popup.close();
+ }
+ },
+
+ StatusButton {
+ text: qsTr("Confirm Identity")
+ visible: isMutualContact && isVerificationSent && !isTrusted && showVerificationPendingSection
+ enabled: verificationChallenge !== "" && verificationResponse !== ""
+ onClicked: {
+ popup.showIdentityVerified = true;
+ popup.showIdentityVerifiedUntrustworthy = false;
+ popup.showVerificationPendingSection = false;
+ popup.showVerifyIdentitySection = false;
+ profileView.stepsListModel.setProperty(2, "stepCompleted", true);
+ popup.contactsStore.verifiedTrusted(userPublicKey);
+ popup.isTrusted = true
+ }
+ },
+
+ StatusButton {
+ visible: showIdentityVerified || showIdentityVerifiedUntrustworthy
+ text: qsTr("Rename")
+ onClicked: {
+ nicknamePopup.open()
+ }
+ },
+
+ StatusButton {
+ visible: showIdentityVerified || showIdentityVerifiedUntrustworthy
+ text: qsTr("Close")
+ onClicked: {
+ popup.close();
+ }
}
]
+
+ Component {
+ id: contactVerificationRequestPopupComponent
+ ContactVerificationRequestPopup {
+ onResponseSent: {
+ popup.contactsStore.acceptVerificationRequest(senderPublicKey, response)
+ }
+ onVerificationRefused: {
+ popup.contactsStore.declineVerificationRequest(senderPublicKey)
+ }
+ }
+ }
}
diff --git a/ui/imports/shared/popups/SendContactRequestModal.qml b/ui/imports/shared/popups/SendContactRequestModal.qml
index 5a586bb329..553021d873 100644
--- a/ui/imports/shared/popups/SendContactRequestModal.qml
+++ b/ui/imports/shared/popups/SendContactRequestModal.qml
@@ -71,7 +71,7 @@ StatusModal {
enabled: messageInput.valid
text: qsTr("Send Contact Request")
onClicked: {
- root.accepted(messageInput.text);
+ root.accepted(Utils.escapeHtml(messageInput.text));
root.close();
}
}
diff --git a/ui/imports/shared/popups/qmldir b/ui/imports/shared/popups/qmldir
index d5f38e46e9..a3ed9ea506 100644
--- a/ui/imports/shared/popups/qmldir
+++ b/ui/imports/shared/popups/qmldir
@@ -3,6 +3,7 @@ BlockContactConfirmationDialog 1.0 BlockContactConfirmationDialog.qml
SettingsDirtyToastMessage 1.0 SettingsDirtyToastMessage.qml
ConfirmationDialog 1.0 ConfirmationDialog.qml
CommunityIntroDialog 1.0 CommunityIntroDialog.qml
+ContactVerificationRequestPopup 1.0 ContactVerificationRequestPopup.qml
DownloadModal 1.0 DownloadModal.qml
DownloadPage 1.0 DownloadPage.qml
ImageCropperModal 1.0 ImageCropperModal.qml
@@ -20,3 +21,4 @@ SelectAccountModal 1.0 SelectAccountModal.qml
ProfilePopup 1.0 ProfilePopup.qml
ImageCropWorkflow 1.0 ImageCropWorkflow.qml
ImportCommunityPopup 1.0 ImportCommunityPopup.qml
+DisplayNamePopup 1.0 DisplayNamePopup.qml
diff --git a/ui/imports/shared/views/ProfileView.qml b/ui/imports/shared/views/ProfileView.qml
index 1cf8a30e57..f9a2121c46 100644
--- a/ui/imports/shared/views/ProfileView.qml
+++ b/ui/imports/shared/views/ProfileView.qml
@@ -7,7 +7,9 @@ import utils 1.0
import shared 1.0
import shared.popups 1.0
import shared.stores 1.0
+import shared.views.chat 1.0
import shared.controls.chat 1.0
+import shared.panels 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
@@ -36,10 +38,42 @@ Rectangle {
property bool isCurrentUser: profileStore.pubkey === userPublicKey
property bool isAddedContact: false
+ property int userTrustStatus: Constants.trustStatus.unknown
+ property int verificationStatus: Constants.verificationStatus.unverified
+
+ property string challenge: ""
+ property string response: ""
+
+ property bool userIsUntrustworthy: false
+ property bool userTrustIsUnknown: false
+ property bool isMutualContact: false
+ property bool isVerificationSent: false
+ property bool isVerified: false
+ property bool isTrusted: false
+ property bool hasReceivedVerificationRequest: false
+
+ property bool showRemoveVerified: false
+ property bool showVerifyIdentitySection: false
+ property bool showVerificationPendingSection: false
+ property bool showIdentityVerified: false
+ property bool showIdentityVerifiedUntrustworthy: false
+
+ property string verificationChallenge: ""
+ property string verificationResponse: ""
+ property string verificationResponseDisplayName: ""
+ property string verificationResponseIcon: ""
+ property string verificationRequestedAt: ""
+ property string verificationRepliedAt: ""
+
readonly property alias qrCodePopup: qrCodePopup
readonly property alias unblockContactConfirmationDialog: unblockContactConfirmationDialog
readonly property alias blockContactConfirmationDialog: blockContactConfirmationDialog
readonly property alias removeContactConfirmationDialog: removeContactConfirmationDialog
+ readonly property alias wizardAnimation: wizardAnimation
+ readonly property alias challengeTxt: challengeTxt
+ readonly property alias stepsListModel: stepsListModel
+
+ readonly property int animationDuration: 500
signal contactUnblocked(publicKey: string)
signal contactBlocked(publicKey: string)
@@ -59,13 +93,66 @@ Rectangle {
readonly property int subTitleElide: Text.ElideMiddle
}
+ SequentialAnimation {
+ id: wizardAnimation
+ ScriptAction {
+ id: step1
+ property int loadingTime: 0
+ Behavior on loadingTime { NumberAnimation { duration: animationDuration }}
+ onLoadingTimeChanged: {
+ if (isVerificationSent) {
+ stepsListModel.setProperty(1, "loadingTime", step1.loadingTime);
+ }
+ }
+ script: {
+ step1.loadingTime = animationDuration;
+ stepsListModel.setProperty(0, "loadingTime", step1.loadingTime);
+
+ if (isVerificationSent) {
+ stepsListModel.setProperty(0, "stepCompleted", true);
+ }
+ }
+ }
+ PauseAnimation {
+ duration: animationDuration + 100
+ }
+ ScriptAction {
+ id: step2
+ property int loadingTime: 0
+ Behavior on loadingTime { NumberAnimation { duration: animationDuration } }
+ onLoadingTimeChanged: {
+ if (isVerificationSent && !!verificationResponse) {
+ stepsListModel.setProperty(2, "loadingTime", step2.loadingTime);
+ }
+ }
+ script: {
+ if (isVerificationSent && !!verificationChallenge) {
+ step2.loadingTime = animationDuration;
+ if (isVerificationSent && !!verificationResponse) {
+ stepsListModel.setProperty(1, "stepCompleted", true);
+ }
+ }
+ }
+ }
+ PauseAnimation {
+ duration: animationDuration + 100
+ }
+ ScriptAction {
+ script: {
+ if (verificationStatus === Constants.verificationStatus.trusted) {
+ stepsListModel.setProperty(2, "stepCompleted", true);
+ }
+ }
+ }
+ }
+
ColumnLayout {
id: modalContent
anchors.fill: parent
Item {
Layout.fillWidth: true
- implicitHeight: 16
+ implicitHeight: 32
}
ProfileHeader {
@@ -74,11 +161,23 @@ Rectangle {
displayName: root.userDisplayName
pubkey: root.userPublicKey
icon: root.isCurrentUser ? root.profileStore.icon : root.userIcon
+ trustStatus: root.userTrustStatus
+ isContact: root.isAddedContact
+ store: root.profileStore
displayNameVisible: false
+ displayNamePlusIconsVisible: true
+ pubkeyVisibleWithCopy: true
pubkeyVisible: false
imageSize: ProfileHeader.ImageSize.Middle
editImageButtonVisible: root.isCurrentUser
+ onEditClicked: {
+ if(!isCurrentUser){
+ nicknamePopup.open()
+ } else {
+ Global.openEditDisplayNamePopup()
+ }
+ }
}
StatusBanner {
@@ -88,26 +187,9 @@ Rectangle {
statusText: qsTr("Blocked")
}
- Item {
- Layout.fillWidth: true
- implicitHeight: 16
- }
-
- StatusDescriptionListItem {
- Layout.fillWidth: true
- title: root.userIsEnsVerified ? qsTr("ENS username") : qsTr("Username")
- subTitle: root.userIsEnsVerified ? root.userEnsName : root.userName
- tooltip.text: qsTr("Copied to clipboard")
- tooltip.timeout: 1000
- icon.name: "copy"
- iconButton.onClicked: {
- globalUtils.copyToClipboard(subTitle)
- tooltip.open();
- }
- }
-
StatusDescriptionListItem {
Layout.fillWidth: true
+ visible: !showVerifyIdentitySection && !showVerificationPendingSection && !showIdentityVerified
title: qsTr("Chat key")
subTitle: Utils.getCompressedPk(root.userPublicKey)
subTitleComponent.elide: Text.ElideMiddle
@@ -124,6 +206,7 @@ Rectangle {
StatusDescriptionListItem {
Layout.fillWidth: true
+ visible: !showVerifyIdentitySection && !showVerificationPendingSection && !showIdentityVerified
title: qsTr("Share Profile URL")
subTitle: {
let user = ""
@@ -154,22 +237,164 @@ Rectangle {
}
}
- StatusDescriptionListItem {
- Layout.fillWidth: true
- visible: !isCurrentUser
- title: qsTr("Chat settings")
- subTitle: qsTr("Nickname")
- value: userNickname ? userNickname : qsTr("None")
- sensor.enabled: true
- sensor.onClicked: {
- nicknamePopup.open()
- }
+ ListModel {
+ id: stepsListModel
+ ListElement {description:"Send Request"; loadingTime: 0; stepCompleted: false}
+ ListElement {description:"Receive Response"; loadingTime: 0; stepCompleted: false}
+ ListElement {description:"Confirm Identity"; loadingTime: 0; stepCompleted: false}
+ }
+
+ StatusWizardStepper {
+ id: wizardStepper
+ maxDuration: animationDuration
+ visible: showVerifyIdentitySection || showVerificationPendingSection || showIdentityVerified || showIdentityVerifiedUntrustworthy
+ width: parent.width
+ stepsModel: stepsListModel
+ }
+
+ Separator {
+ visible: wizardStepper.visible
+ implicitHeight: 32
+ }
+
+ StatusBaseText {
+ id: confirmLbl
+ visible: showIdentityVerified
+ text: qsTr("You have confirmed %1's identity. From now on this verification emblem will always be displayed alongside %1's nickname.").arg(userIsEnsVerified ? userEnsName : userDisplayName)
+ font.pixelSize: Style.current.additionalTextSize
+ horizontalAlignment : Text.AlignHCenter
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredWidth: 363
+ wrapMode: Text.WordWrap
+ color: Theme.palette.baseColor1
+ }
+
+ StatusBaseText {
+ id: confirmUntrustworthyLbl
+ visible: showIdentityVerifiedUntrustworthy
+ text: qsTr("You have marked %1 as Untrustworthy. From now on this Untrustworthy emblem will always be displayed alongside %1's nickname.").arg(userIsEnsVerified ? userEnsName : userDisplayName)
+ font.pixelSize: Style.current.additionalTextSize
+ horizontalAlignment : Text.AlignHCenter
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredWidth: 363
+ wrapMode: Text.WordWrap
+ color: Theme.palette.baseColor1
}
Item {
+ visible: checkboxIcon.visible || dangerIcon.visible
+ Layout.fillWidth: true
+ implicitHeight: visible ? 16 : 0
+ }
+
+ StatusRoundIcon {
+ id: checkboxIcon
+ visible: confirmLbl.visible
+ icon.name: "checkbox"
+ icon.width: 16
+ icon.height: 16
+ icon.color: Theme.palette.white
+ Layout.alignment: Qt.AlignHCenter
+ color: Theme.palette.primaryColor1
+ width: 32
+ height: 32
+ }
+
+ StatusDescriptionListItem {
+ Layout.fillWidth: true
+ visible: !showVerifyIdentitySection && !showVerificationPendingSection && !showIdentityVerified
+ title: root.userIsEnsVerified ? qsTr("ENS username") : qsTr("Username")
+ subTitle: root.userIsEnsVerified ? root.userEnsName : root.userName
+ tooltip.text: qsTr("Copied to clipboard")
+ tooltip.timeout: 1000
+ icon.name: "copy"
+ iconButton.onClicked: {
+ globalUtils.copyToClipboard(subTitle)
+ tooltip.open();
+ }
+ }
+
+ StatusRoundIcon {
+ id: dangerIcon
+ visible: confirmUntrustworthyLbl.visible
+ icon.name: "tiny/subtract"
+ icon.width: 5
+ icon.height: 21
+ icon.color: Theme.palette.white
+ Layout.alignment: Qt.AlignHCenter
+ color: Theme.palette.dangerColor1
+ width: 32
+ height: 32
+ }
+
+ Item {
+ visible: checkboxIcon.visible || dangerIcon.visible
+ height: visible ? 16 : 0
+ Layout.fillWidth: true
+ }
+
+ StatusInput {
+ id: challengeTxt
+ visible: showVerifyIdentitySection
+ charLimit: 280
+ input.text: root.challenge
+ Layout.fillWidth: true
+ Layout.rightMargin: d.contentMargins
+ Layout.leftMargin: d.contentMargins
+ input.multiline: true
+ input.implicitHeight: 152
+ input.placeholderText: qsTr("Ask a question that only the real %1 will be able to answer e.g. a question about a shared experience, or ask Mark to enter a code or phrase you have sent to them via a different communication channel (phone, post, etc...).").arg(userIsEnsVerified ? userEnsName : userDisplayName)
+ }
+
+ MessageView {
+ id: challengeMessage
+ visible: root.showVerificationPendingSection
+ Layout.fillWidth: true
+ isMessage: true
+ shouldRepeatHeader: true
+ messageTimestamp: root.verificationRequestedAt
+ senderDisplayName: userProfile.name
+ senderIcon: userProfile.icon
+ message: root.verificationChallenge
+ messageContentType: Constants.messageContentType.messageType
+ placeholderMessage: true
+ }
+
+ MessageView {
+ id: responseMessage
+ visible: root.showVerificationPendingSection && !!root.verificationResponse
+ width: parent.width
+ isMessage: true
+ shouldRepeatHeader: true
+ messageTimestamp: root.verificationRepliedAt
+ senderDisplayName: root.verificationResponseDisplayName
+ senderIcon: root.verificationResponseIcon
+ message: root.verificationResponse
+ messageContentType: Constants.messageContentType.messageType
+ placeholderMessage: true
+ }
+
+ Item {
+ visible: waitingForText.visible
+ height: 32
+ Layout.fillWidth: true
+ }
+
+ StatusBaseText {
+ id: waitingForText
+ visible: showVerificationPendingSection && !verificationResponse
+ text: qsTr("Waiting for %1's response...").arg(userIsEnsVerified ? userEnsName : userDisplayName)
+ font.pixelSize: Style.current.additionalTextSize
+ horizontalAlignment : Text.AlignHCenter
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredWidth: 363
+ wrapMode: Text.WordWrap
+ color: Theme.palette.baseColor1
+ }
+
+ Item {
+ height: 32
Layout.fillWidth: true
- visible: !isCurrentUser
- implicitHeight: 16
}
}
diff --git a/ui/imports/shared/views/chat/CompactMessageView.qml b/ui/imports/shared/views/chat/CompactMessageView.qml
index 163c6f4a95..446fea0b34 100644
--- a/ui/imports/shared/views/chat/CompactMessageView.qml
+++ b/ui/imports/shared/views/chat/CompactMessageView.qml
@@ -28,6 +28,7 @@ Item {
property int contentType
property bool isChatBlocked: false
property bool isActiveChannel: false
+ property int senderTrustStatus
property int chatHorizontalPadding: Style.current.halfPadding
property int chatVerticalPadding: 7
@@ -72,8 +73,9 @@ Item {
+ (dateGroupLbl.visible ? dateGroupLbl.height + dateGroupLbl.anchors.topMargin : 0)
Connections {
- target: !!root.messageStore && root.messageStore.messageModule? root.messageStore.messageModule : null
- enabled: responseTo !== ""
+ target: !!root.messageStore && root.messageStore.messageModule ?
+ root.messageStore.messageModule : null
+ enabled: !!root.messageStore && !!root.messageStore.messageModule && responseTo !== ""
onRefreshAMessageUserRespondedTo: {
if(msgId === messageId)
chatReply.resetOriginalMessage()
@@ -383,11 +385,21 @@ Item {
}
}
+ VerificationLabel {
+ id: trustStatus
+ anchors.left: chatName.right
+ anchors.leftMargin: 4
+ anchors.bottom: chatName.bottom
+ anchors.bottomMargin: 4
+ visible: !root.amISender && chatName.visible
+ trustStatus: senderTrustStatus
+ }
+
ChatTimePanel {
id: chatTime
visible: !editModeOn && headerRepeatCondition
anchors.verticalCenter: chatName.verticalCenter
- anchors.left: chatName.right
+ anchors.left: trustStatus.right
anchors.leftMargin: 4
color: Style.current.secondaryText
timestamp: messageTimestamp
diff --git a/ui/imports/shared/views/chat/MessageView.qml b/ui/imports/shared/views/chat/MessageView.qml
index 2ef719c304..cbc2af5bd9 100644
--- a/ui/imports/shared/views/chat/MessageView.qml
+++ b/ui/imports/shared/views/chat/MessageView.qml
@@ -41,6 +41,7 @@ Column {
property string senderIcon: ""
property bool amISender: false
property bool senderIsAdded: false
+ property int senderTrustStatus: Constants.trustStatus.unknown
readonly property string senderIconToShow: {
if ((!senderIsAdded &&
Global.privacyModuleInst.profilePicturesVisibility !==
@@ -340,6 +341,7 @@ Column {
isChatBlocked: root.isChatBlocked
isActiveChannel: root.isActiveChannel
emojiPopup: root.emojiPopup
+ senderTrustStatus: root.senderTrustStatus
communityId: root.communityId
stickersLoaded: root.stickersLoaded
@@ -353,7 +355,7 @@ Column {
linkUrls: root.linkUrls
isInPinnedPopup: root.isInPinnedPopup
pinnedMessage: root.pinnedMessage
- canPin: messageStore.getNumberOfPinnedMessages() < Constants.maxNumberOfPins
+ canPin: !!messageStore && messageStore.getNumberOfPinnedMessages() < Constants.maxNumberOfPins
transactionParams: root.transactionParams
diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml
index c72421838b..fbe1f812d1 100644
--- a/ui/imports/utils/Constants.qml
+++ b/ui/imports/utils/Constants.qml
@@ -100,12 +100,21 @@ QtObject {
readonly property int noOne: 3
}
- readonly property QtObject contactVerificationState: QtObject {
- readonly property int notMarked: 0
- readonly property int verified: 1
+ readonly property QtObject trustStatus: QtObject {
+ readonly property int unknown: 0
+ readonly property int trusted: 1
readonly property int untrustworthy: 2
}
+ readonly property QtObject verificationStatus: QtObject {
+ readonly property int unverified: 0
+ readonly property int verifying: 1
+ readonly property int verified: 2
+ readonly property int declined: 3
+ readonly property int canceled: 4
+ readonly property int trusted: 5
+ }
+
readonly property QtObject contactsPanelUsage: QtObject {
readonly property int unknownPosition: -1
readonly property int mutualContacts: 0
diff --git a/ui/imports/utils/Global.qml b/ui/imports/utils/Global.qml
index a1f2300502..ff32b5a76e 100644
--- a/ui/imports/utils/Global.qml
+++ b/ui/imports/utils/Global.qml
@@ -28,6 +28,7 @@ QtObject {
signal openProfilePopupRequested(string publicKey, var parentPopup, string state)
signal openChangeProfilePicPopup()
signal displayToastMessage(string title, string subTitle, string icon, bool loading, int ephNotifType, string url)
+ signal openEditDisplayNamePopup()
function openProfilePopup(publicKey, parentPopup, state = "") {
openProfilePopupRequested(publicKey, parentPopup, state);
diff --git a/ui/imports/utils/Utils.qml b/ui/imports/utils/Utils.qml
index fad3d327b3..d0b42745e0 100644
--- a/ui/imports/utils/Utils.qml
+++ b/ui/imports/utils/Utils.qml
@@ -640,7 +640,9 @@ QtObject {
isBlocked: false,
requestReceived: false,
isSyncing: false,
- removed: false
+ removed: false,
+ trustStatus: Constants.trustStatus.unknown,
+ verificationStatus: Constants.verificationStatus.unverified
}
}
}
diff --git a/vendor/status-go b/vendor/status-go
index 7ad0057003..0322ac497b 160000
--- a/vendor/status-go
+++ b/vendor/status-go
@@ -1 +1 @@
-Subproject commit 7ad0057003d968423b7ee482502cbf0e0b6716d4
+Subproject commit 0322ac497bf9e4852b99780f4ff08377a8c3f267