feat: contact verification request and trust status

feat: contact verification

fix: add remove identity verified btn

fix: add toast message

feat: received verification request model


feat: finish identity verification flow

Fixes #4784
This commit is contained in:
Jonathan Rainville 2022-06-28 14:11:18 -04:00
parent 5d4aba62e3
commit 1e7c648300
66 changed files with 1827 additions and 214 deletions

View File

@ -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

View File

@ -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*(

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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):

View File

@ -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)

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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]) =

View File

@ -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) =

View File

@ -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) =

View File

@ -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()

View File

@ -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 =

View File

@ -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, "")
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)

View File

@ -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")

View File

@ -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)

View File

@ -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)
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)

View File

@ -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 == ""):

View File

@ -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}
]"""

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -135,6 +135,7 @@ StatusAppTwoPanelLayout {
messagingStore: profileView.store.messagingStore
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.messaging)
contactsStore: profileView.store.contactsStore
contentWidth: d.contentWidth
}

View File

@ -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

View File

@ -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) ||

View File

@ -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 ""
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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)
}
}
}

View File

@ -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

View File

@ -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)
}

View File

@ -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 {

View File

@ -0,0 +1,5 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.5 8C0.5 3.58172 4.08172 0 8.5 0C12.9183 0 16.5 3.58172 16.5 8C16.5 12.4183 12.9183 16 8.5 16C4.08172 16 0.5 12.4183 0.5 8Z" fill="#4360DF"/>
<path d="M8.49984 7.5C9.74248 7.5 10.7498 6.49264 10.7498 5.25C10.7498 4.00736 9.74248 3 8.49984 3C7.2572 3 6.24984 4.00736 6.24984 5.25C6.24984 6.49264 7.2572 7.5 8.49984 7.5Z" fill="white"/>
<path d="M4.62326 12.0101C5.06378 10.2798 6.63236 9 8.49984 9C10.3673 9 11.9359 10.2798 12.3764 12.0101C12.5127 12.5453 12.0521 13 11.4998 13H5.49984C4.94755 13 4.48701 12.5453 4.62326 12.0101Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 659 B

View File

@ -0,0 +1,4 @@
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="5" cy="5" r="5" fill="#FF2D55"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.78125 7.65625C5.78125 8.08772 5.43147 8.4375 5 8.4375C4.56853 8.4375 4.21875 8.08772 4.21875 7.65625C4.21875 7.22478 4.56853 6.875 5 6.875C5.43147 6.875 5.78125 7.22478 5.78125 7.65625ZM5 1.875C4.65482 1.875 4.375 2.15482 4.375 2.5V5.3125C4.375 5.65768 4.65482 5.9375 5 5.9375C5.34518 5.9375 5.625 5.65768 5.625 5.3125V2.5C5.625 2.15482 5.34518 1.875 5 1.875Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 576 B

View File

@ -0,0 +1,4 @@
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="5" cy="5" r="5" fill="#4360DF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.21097 5.79222L6.73854 3.25573C6.91216 3.08149 7.19307 3.0809 7.36869 3.25713C7.54308 3.43214 7.54399 3.71498 7.37008 3.8895L4.52534 6.74428C4.43901 6.83091 4.32615 6.87462 4.2129 6.875C4.09629 6.87412 3.98311 6.8311 3.89811 6.7458L2.6292 5.47241C2.45641 5.29901 2.4565 5.01779 2.63211 4.84156C2.8065 4.66655 3.09029 4.66758 3.26074 4.83864L4.21097 5.79222Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 573 B

View File

@ -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)
}
}
}
/*##^##

View File

@ -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

View File

@ -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 "";
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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()
}
]
}

View File

@ -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)
}
}
}
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -640,7 +640,9 @@ QtObject {
isBlocked: false,
requestReceived: false,
isSyncing: false,
removed: false
removed: false,
trustStatus: Constants.trustStatus.unknown,
verificationStatus: Constants.verificationStatus.unverified
}
}
}

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 7ad0057003d968423b7ee482502cbf0e0b6716d4
Subproject commit 0322ac497bf9e4852b99780f4ff08377a8c3f267