fix: ENS name issues

- don't display identicon rings for contacts with an ENS name
- prefer the at-form (@foo-user) whenever possible, and don't display their
  username or pubkey unless they are locally given a nickname
- show compressed keys everywhere instead of the regular ones

Fixes: #7319
Fixes: #7515
This commit is contained in:
Lukáš Tinkl 2022-09-23 00:18:15 +02:00 committed by Lukáš Tinkl
parent 54c73b0be7
commit a209d39881
22 changed files with 94 additions and 51 deletions

View File

@ -23,6 +23,8 @@ Column {
property Component popupMenu property Component popupMenu
property var isEnsVerified: function(pubKey) { return false }
signal chatItemSelected(string categoryId, string id) signal chatItemSelected(string categoryId, string id)
signal chatItemUnmuted(string id) signal chatItemUnmuted(string id)
signal chatItemReordered(string id, int from, int to) signal chatItemReordered(string id, int from, int to)
@ -122,8 +124,8 @@ Column {
asset.color: !!model.color ? model.color : Theme.palette.userCustomizationColors[model.colorId] asset.color: !!model.color ? model.color : Theme.palette.userCustomizationColors[model.colorId]
asset.isImage: model.icon.includes("data") asset.isImage: model.icon.includes("data")
asset.name: model.icon asset.name: model.icon
ringSettings.ringSpecModel: model.colorHash ringSettings.ringSpecModel: type === StatusChatListItem.Type.OneToOneChat && root.isEnsVerified(chatId) ? undefined : model.colorHash
onlineStatus: model.onlineStatus onlineStatus: !!model.onlineStatus ? model.onlineStatus : StatusChatListItem.OnlineStatus.Inactive
sensor.cursorShape: dragSensor.cursorShape sensor.cursorShape: dragSensor.cursorShape

View File

@ -87,7 +87,7 @@ StatusListItem {
id: d id: d
// Subtitle composition: // Subtitle composition:
function composeSubtitile() { function composeSubtitle() {
var compose = "" var compose = ""
if(root.userName !== "" && root.nickName !== "") if(root.userName !== "" && root.nickName !== "")
compose = "(" + root.userName + ")" compose = "(" + root.userName + ")"
@ -104,21 +104,25 @@ StatusListItem {
// Short keychat composition: // Short keychat composition:
function composeShortKeyChat(pubKey) { function composeShortKeyChat(pubKey) {
if (!pubKey)
return ""
return pubKey.substring(0, 5) + "..." + pubKey.substring(pubKey.length - 3) return pubKey.substring(0, 5) + "..." + pubKey.substring(pubKey.length - 3)
} }
} }
// root object settings: // root object settings:
title: (root.nickName === "") ? root.userName : root.nickName title: root.nickName || root.userName
statusListItemTitleIcons.sourceComponent: StatusContactVerificationIcons { statusListItemTitleIcons.sourceComponent: StatusContactVerificationIcons {
isContact: root.isContact isContact: root.isContact
trustIndicator: { trustIndicator: {
if (root.isVerified) return StatusContactVerificationIcons.TrustedType.Verified if (root.isVerified)
else if (root.isUntrustworthy) return StatusContactVerificationIcons.TrustedType.Untrustworthy return StatusContactVerificationIcons.TrustedType.Verified
if (root.isUntrustworthy)
return StatusContactVerificationIcons.TrustedType.Untrustworthy
return StatusContactVerificationIcons.TrustedType.None return StatusContactVerificationIcons.TrustedType.None
} }
} }
subTitle: d.composeSubtitile() subTitle: d.composeSubtitle()
statusListItemSubTitle.font.pixelSize: 10 statusListItemSubTitle.font.pixelSize: 10
statusListItemIcon.badge.visible: true statusListItemIcon.badge.visible: true
statusListItemIcon.badge.color: root.status === 1 ? Theme.palette.successColor1 : Theme.palette.baseColor1 // FIXME statusListItemIcon.badge.color: root.status === 1 ? Theme.palette.successColor1 : Theme.palette.baseColor1 // FIXME
@ -130,6 +134,8 @@ StatusListItem {
leftPadding: 8 leftPadding: 8
asset.width: 32 asset.width: 32
asset.height: 32 asset.height: 32
asset.charactersLen: 2
asset.letterSize: asset._twoLettersSize
statusListItemIcon.anchors.verticalCenter: sensor.verticalCenter statusListItemIcon.anchors.verticalCenter: sensor.verticalCenter
statusListItemIcon.anchors.top: undefined statusListItemIcon.anchors.top: undefined
statusListItemIcon.badge.border.width: 2 statusListItemIcon.badge.border.width: 2

View File

@ -35,16 +35,13 @@ Item {
RowLayout { RowLayout {
id: layout id: layout
spacing: 4 spacing: 4
TextEdit { StatusBaseText {
id: primaryDisplayName id: primaryDisplayName
Layout.alignment: Qt.AlignBottom verticalAlignment: Text.AlignVCenter
font.family: Theme.palette.baseFont.name Layout.bottomMargin: 2 // offset for the underline to stay vertically centered
font.weight: Font.Medium font.weight: Font.Medium
font.pixelSize: 15
font.underline: mouseArea.containsMouse font.underline: mouseArea.containsMouse
readOnly: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
selectByMouse: true
color: Theme.palette.primaryColor1 color: Theme.palette.primaryColor1
text: root.amISender ? qsTr("You") : root.sender.displayName text: root.amISender ? qsTr("You") : root.sender.displayName
MouseArea { MouseArea {
@ -61,53 +58,55 @@ Item {
} }
StatusBaseText { StatusBaseText {
id: messageOriginInfo id: messageOriginInfo
Layout.alignment: Qt.AlignVCenter verticalAlignment: Text.AlignVCenter
visible: root.messageOriginInfo !== "" visible: text
color: Theme.palette.baseColor1 color: Theme.palette.baseColor1
font.pixelSize: 10 font.pixelSize: 10
text: root.messageOriginInfo text: root.messageOriginInfo
} }
StatusContactVerificationIcons { StatusContactVerificationIcons {
id: verificationIcons
visible: !root.amISender visible: !root.amISender
isContact: root.isContact isContact: root.isContact
trustIndicator: root.trustIndicator trustIndicator: root.trustIndicator
} }
StatusBaseText { StatusBaseText {
id: secondaryDisplayName id: secondaryDisplayName
Layout.alignment: Qt.AlignVCenter verticalAlignment: Text.AlignVCenter
visible: !root.amISender && !!root.sender.secondaryName visible: !root.amISender && !!root.sender.secondaryName
color: Theme.palette.baseColor1 color: Theme.palette.baseColor1
font.pixelSize: 10 font.pixelSize: 10
text: `(${root.sender.secondaryName})` text: `(${root.sender.secondaryName})`
} }
StatusBaseText { StatusBaseText {
Layout.alignment: Qt.AlignVCenter verticalAlignment: Text.AlignVCenter
visible: secondaryDisplayName.visible visible: secondaryDisplayName.visible && tertiaryDetailText.visible
font.pixelSize: 10 font.pixelSize: 10
color: Theme.palette.baseColor1 color: Theme.palette.baseColor1
text: "•" text: "•"
} }
StatusBaseText { StatusBaseText {
id: tertiaryDetailText id: tertiaryDetailText
visible: !root.amISender && root.messageOriginInfo === "" verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignVCenter visible: !root.amISender && root.messageOriginInfo === "" && text
font.pixelSize: 10 font.pixelSize: 10
elide: Text.ElideMiddle elide: Text.ElideMiddle
color: Theme.palette.baseColor1 color: Theme.palette.baseColor1
text: Utils.elideText(tertiaryDetail, 5, 3) text: root.tertiaryDetail ? Utils.elideText(root.tertiaryDetail, 5, 3) : ""
} }
StatusBaseText { StatusBaseText {
Layout.alignment: Qt.AlignVCenter verticalAlignment: Text.AlignVCenter
visible: tertiaryDetailText.visible visible: verificationIcons.width <= 0 || secondaryDisplayName.visible || root.amISender || tertiaryDetailText.visible
font.pixelSize: 10 font.pixelSize: 10
color: Theme.palette.baseColor1 color: Theme.palette.baseColor1
text: "•" text: "•"
} }
StatusTimeStampLabel { StatusTimeStampLabel {
verticalAlignment: Text.AlignVCenter
id: timestampText id: timestampText
} }
StatusBaseText { StatusBaseText {
Layout.alignment: Qt.AlignVCenter verticalAlignment: Text.AlignVCenter
color: Theme.palette.dangerColor1 color: Theme.palette.dangerColor1
font.pixelSize: 12 font.pixelSize: 12
text: root.resendText text: root.resendText

View File

@ -144,7 +144,9 @@ Item {
Connections { Connections {
target: root.settings target: root.settings
onRingSpecModelChanged: requestPaint() function onRingSpecModelChanged() {
requestPaint()
}
} }
} }
} }

View File

@ -10,8 +10,6 @@ import shared.panels 1.0
import shared.status 1.0 import shared.status 1.0
import utils 1.0 import utils 1.0
import "../controls"
import SortFilterProxyModel 0.2 import SortFilterProxyModel 0.2
Item { Item {
@ -74,8 +72,8 @@ Item {
delegate: StatusMemberListItem { delegate: StatusMemberListItem {
width: ListView.view.width width: ListView.view.width
nickName: model.localNickname nickName: model.localNickname
userName: model.displayName !== "" ? model.displayName : model.alias userName: !!model.ensName ? "@" + Utils.removeStatusEns(model.ensName) : model.displayName !== "" ? model.displayName : model.alias
pubKey: Utils.getCompressedPk(model.pubKey) pubKey: !!model.ensName ? "" : Utils.getCompressedPk(model.pubKey)
isContact: model.isContact isContact: model.isContact
isVerified: model.isVerified isVerified: model.isVerified
isUntrustworthy: model.isUntrustworthy isUntrustworthy: model.isUntrustworthy
@ -95,7 +93,7 @@ Item {
asset.isLetterIdenticon: (asset.name === "") asset.isLetterIdenticon: (asset.name === "")
asset.color: Utils.colorForColorId(model.colorId) asset.color: Utils.colorForColorId(model.colorId)
status: model.onlineStatus status: model.onlineStatus
ringSettings.ringSpecModel: Utils.getColorHashAsJson(model.pubKey) // FIXME: use model.colorHash ringSettings.ringSpecModel: !!model.ensName ? undefined : Utils.getColorHashAsJson(model.pubKey, true) // FIXME: use model.colorHash
onClicked: { onClicked: {
if (mouse.button === Qt.RightButton) { if (mouse.button === Qt.RightButton) {
// Set parent, X & Y positions for the messageContextMenu // Set parent, X & Y positions for the messageContextMenu

View File

@ -82,9 +82,7 @@ SettingsPageLayout {
if (root.membersModel.count === 0) { if (root.membersModel.count === 0) {
return qsTr("No members to search") return qsTr("No members to search")
} else { } else {
return qsTr("Search %1's %2 member%3").arg(root.communityName) return qsTr("Search %1's %n member(s)", "", root.membersModel.count).arg(root.communityName)
.arg(root.membersModel.count)
.arg(root.membersModel.count > 1 ? "s" : "")
} }
} }
panelType: CommunityMembersTabPanel.TabType.AllMembers panelType: CommunityMembersTabPanel.TabType.AllMembers

View File

@ -42,7 +42,7 @@ Item {
StatusInput { StatusInput {
id: memberSearch id: memberSearch
Layout.preferredWidth: 350 Layout.preferredWidth: 400
Layout.leftMargin: 12 Layout.leftMargin: 12
maximumHeight: 36 maximumHeight: 36
topPadding: 0 topPadding: 0
@ -126,7 +126,7 @@ Item {
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
color: "transparent" color: "transparent"
pubKey: Utils.getElidedCompressedPk(model.pubKey) pubKey: model.ensName ? "" : Utils.getElidedCompressedPk(model.pubKey)
nickName: model.localNickname nickName: model.localNickname
userName: model.displayName userName: model.displayName
status: model.onlineStatus status: model.onlineStatus
@ -136,7 +136,7 @@ Item {
asset.isLetterIdenticon: !model.icon asset.isLetterIdenticon: !model.icon
asset.width: 40 asset.width: 40
asset.height: 40 asset.height: 40
ringSettings.ringSpecModel: Utils.getColorHashAsJson(model.pubKey) ringSettings.ringSpecModel: !!model.ensName ? undefined : Utils.getColorHashAsJson(model.pubKey, true)
statusListItemIcon.badge.visible: (root.panelType === CommunityMembersTabPanel.TabType.AllMembers) statusListItemIcon.badge.visible: (root.panelType === CommunityMembersTabPanel.TabType.AllMembers)
onClicked: root.userProfileClicked(model.pubKey) onClicked: root.userProfileClicked(model.pubKey)

View File

@ -252,7 +252,19 @@ RowLayout {
StatusChatInfoButton { StatusChatInfoButton {
objectName: "chatInfoBtnInHeader" objectName: "chatInfoBtnInHeader"
title: chatContentModule? chatContentModule.chatDetails.name : "" title: {
const module = root.rootStore.currentChatContentModule()
if(!module)
return ""
if (module.chatDetails.type === Constants.chatType.oneToOne) {
const d = Utils.getContactDetailsAsJson(module.chatDetails.id)
if (!!d.displayName)
return d.displayName
}
return module.chatDetails.name
}
subTitle: { subTitle: {
if(!chatContentModule) if(!chatContentModule)
return "" return ""

View File

@ -158,6 +158,7 @@ Item {
} }
highlightItem: !root.store.openCreateChat highlightItem: !root.store.openCreateChat
isEnsVerified: function(pubKey) { return Utils.isEnsVerified(pubKey) }
onChatItemSelected: { onChatItemSelected: {
Global.closeCreateChatView() Global.closeCreateChatView()
root.chatSectionModule.setActiveItem(id, "") root.chatSectionModule.setActiveItem(id, "")

View File

@ -9,7 +9,8 @@ StatusListItem {
subTitle: community.amISectionAdmin ? qsTr("Admin") : qsTr("Member") subTitle: community.amISectionAdmin ? qsTr("Admin") : qsTr("Member")
asset.name: !!community.image ? community.image : community.name asset.name: !!community.image ? community.image : community.name
asset.isImage: asset.name.includes("data") asset.isImage: asset.name.includes("data")
asset.letterSize: 14
asset.isLetterIdenticon: !community.image asset.isLetterIdenticon: !community.image
asset.color: community.color asset.color: community.color
asset.width: 40
asset.height: 40
} }

View File

@ -50,18 +50,27 @@ StatusListItem {
signal rejectionRemoved(string publicKey) signal rejectionRemoved(string publicKey)
signal textClicked(string publicKey) signal textClicked(string publicKey)
subTitle: Utils.getElidedCompressedPk(root.publicKey) readonly property var d: Utils.getContactDetailsAsJson(root.publicKey)
subTitle: {
if (d.ensVerified) {
if (d.localNickname)
return '@' + Utils.removeStatusEns(d.name)
return ""
}
return Utils.getElidedCompressedPk(root.publicKey)
}
asset.width: 40 asset.width: 40
asset.height: 40 asset.height: 40
asset.color: Utils.colorForPubkey(root.publicKey) asset.color: Utils.colorForPubkey(root.publicKey)
asset.letterSize: Math.max(4, root.asset.width / 2.4) asset.letterSize: asset._twoLettersSize
asset.charactersLen: 2 asset.charactersLen: 2
asset.name: root.iconSource asset.name: root.iconSource
asset.isImage: asset.name.includes("data") asset.isImage: asset.name.includes("data")
asset.isLetterIdenticon: root.iconSource.toString() === "" asset.isLetterIdenticon: root.iconSource.toString() === ""
ringSettings { ringSettings {
ringSpecModel: root.name.startsWith('@') ? undefined : Utils.getColorHashAsJson(root.publicKey) ringSpecModel: Utils.getColorHashAsJson(root.publicKey)
ringPxSize: Math.max(asset.width / 24.0) ringPxSize: Math.max(asset.width / 24.0)
} }

View File

@ -361,7 +361,7 @@ Item {
identicon.asset.height: height identicon.asset.height: height
identicon.asset.charactersLen: 2 identicon.asset.charactersLen: 2
identicon.asset.color: Utils.colorForPubkey(appMain.rootStore.userProfileInst.pubKey) identicon.asset.color: Utils.colorForPubkey(appMain.rootStore.userProfileInst.pubKey)
identicon.ringSettings.ringSpecModel: Utils.getColorHashAsJson(appMain.rootStore.userProfileInst.pubKey) identicon.ringSettings.ringSpecModel: appMain.rootStore.userProfileInst.ensName ? undefined : Utils.getColorHashAsJson(appMain.rootStore.userProfileInst.pubKey, true)
badge.visible: true badge.visible: true
badge.anchors { badge.anchors {

View File

@ -26,6 +26,7 @@ Item {
property int trustStatus property int trustStatus
property bool isContact: false property bool isContact: false
property bool isCurrentUser property bool isCurrentUser
property bool userIsEnsVerified
property int imageSize: ProfileHeader.ImageSize.Compact property int imageSize: ProfileHeader.ImageSize.Compact
property bool displayNameVisible: true property bool displayNameVisible: true
@ -80,6 +81,7 @@ Item {
interactive: false interactive: false
imageWidth: d.getSize(36, 80, 160) imageWidth: d.getSize(36, 80, 160)
imageHeight: imageWidth imageHeight: imageWidth
showRing: !root.userIsEnsVerified
} }
StatusRoundButton { StatusRoundButton {

View File

@ -14,8 +14,9 @@ StatusMemberListItem {
id: root id: root
readonly property string _pubKey: model.pubKey // expose uncompressed pubkey readonly property string _pubKey: model.pubKey // expose uncompressed pubkey
readonly property bool hasEnsName: Utils.isEnsVerified(model.pubKey)
pubKey: Utils.getCompressedPk(model.pubKey) pubKey: hasEnsName ? "" : Utils.getCompressedPk(model.pubKey)
nickName: model.localNickname nickName: model.localNickname
userName: model.displayName userName: model.displayName
isVerified: model.isVerified isVerified: model.isVerified
@ -27,6 +28,6 @@ StatusMemberListItem {
asset.isLetterIdenticon: (asset.name === "") asset.isLetterIdenticon: (asset.name === "")
status: model.onlineStatus status: model.onlineStatus
statusListItemIcon.badge.border.color: sensor.containsMouse ? Theme.palette.baseColor2 : Theme.palette.baseColor4 statusListItemIcon.badge.border.color: sensor.containsMouse ? Theme.palette.baseColor2 : Theme.palette.baseColor4
ringSettings.ringSpecModel: Utils.getColorHashAsJson(model.pubKey) ringSettings.ringSpecModel: hasEnsName ? undefined : Utils.getColorHashAsJson(model.pubKey, true)
color: (sensor.containsMouse || highlighted) ? Theme.palette.baseColor2 : "transparent" color: (sensor.containsMouse || highlighted) ? Theme.palette.baseColor2 : "transparent"
} }

View File

@ -462,6 +462,7 @@ StatusDialog {
userPublicKey: popup.userPublicKey userPublicKey: popup.userPublicKey
userDisplayName: popup.userDisplayName userDisplayName: popup.userDisplayName
userIcon: popup.userIcon userIcon: popup.userIcon
userIsEnsVerified: popup.userIsEnsVerified
onAccepted: popup.contactsStore.sendContactRequest(userPublicKey, message) onAccepted: popup.contactsStore.sendContactRequest(userPublicKey, message)
onClosed: popup.close() onClosed: popup.close()
} }

View File

@ -17,6 +17,7 @@ StatusModal {
property string userPublicKey: "" property string userPublicKey: ""
property string userDisplayName: "" property string userDisplayName: ""
property string userIcon: "" property string userIcon: ""
property bool userIsEnsVerified
signal accepted(string message) signal accepted(string message)
@ -42,6 +43,7 @@ StatusModal {
displayName: root.userDisplayName displayName: root.userDisplayName
pubkey: root.userPublicKey pubkey: root.userPublicKey
icon: root.userIcon icon: root.userIcon
userIsEnsVerified: root.userIsEnsVerified
displayNameVisible: true displayNameVisible: true
pubkeyVisible: true pubkeyVisible: true

View File

@ -23,6 +23,7 @@ StatusPopupMenu {
displayName: root.store.userProfileInst.name displayName: root.store.userProfileInst.name
pubkey: root.store.userProfileInst.pubKey pubkey: root.store.userProfileInst.pubKey
icon: root.store.userProfileInst.icon icon: root.store.userProfileInst.icon
userIsEnsVerified: !!root.store.userProfileInst.ensName
} }
StatusMenuSeparator { StatusMenuSeparator {

View File

@ -60,7 +60,7 @@ Item {
asset.width: 40 asset.width: 40
asset.height: 40 asset.height: 40
asset.color: Utils.colorForColorId(model.colorId) asset.color: Utils.colorForColorId(model.colorId)
ringSettings.ringSpecModel: Utils.getColorHashAsJson(model.pubKey) ringSettings.ringSpecModel: model.ensName ? undefined : Utils.getColorHashAsJson(model.pubKey, true)
statusListItemIcon.badge.border.color: Theme.palette.baseColor4 statusListItemIcon.badge.border.color: Theme.palette.baseColor4
statusListItemIcon.badge.implicitHeight: 14 // 10 px + 2 px * 2 borders statusListItemIcon.badge.implicitHeight: 14 // 10 px + 2 px * 2 borders
statusListItemIcon.badge.implicitWidth: 14 // 10 px + 2 px * 2 borders statusListItemIcon.badge.implicitWidth: 14 // 10 px + 2 px * 2 borders

View File

@ -173,6 +173,7 @@ Rectangle {
isContact: root.isContact isContact: root.isContact
store: root.profileStore store: root.profileStore
isCurrentUser: root.isCurrentUser isCurrentUser: root.isCurrentUser
userIsEnsVerified: root.userIsEnsVerified
displayNameVisible: false displayNameVisible: false
displayNamePlusIconsVisible: true displayNamePlusIconsVisible: true

View File

@ -195,6 +195,7 @@ StatusPopupMenu {
: Constants.trustStatus.unknown : Constants.trustStatus.unknown
isContact: root.isContact isContact: root.isContact
isCurrentUser: root.isMe isCurrentUser: root.isMe
userIsEnsVerified: !!d.contactDetails && d.contactDetails.ensVerified
} }
Item { Item {

View File

@ -212,7 +212,6 @@ Loader {
// } // }
// } // }
height: implicitHeight
z: (typeof chatLogView === "undefined") ? 1 : (chatLogView.count - index) z: (typeof chatLogView === "undefined") ? 1 : (chatLogView.count - index)
sourceComponent: { sourceComponent: {
@ -562,7 +561,7 @@ Loader {
} }
amISender: root.amISender amISender: root.amISender
sender.id: root.senderId sender.id: root.senderIsEnsVerified ? "" : Utils.getCompressedPk(root.senderId)
sender.displayName: root.senderDisplayName sender.displayName: root.senderDisplayName
sender.secondaryName: root.senderOptionalName sender.secondaryName: root.senderOptionalName
sender.isEnsVerified: root.senderIsEnsVerified sender.isEnsVerified: root.senderIsEnsVerified

View File

@ -562,6 +562,12 @@ QtObject {
} }
} }
function isEnsVerified(publicKey) {
if (!publicKey)
return false
return getContactDetailsAsJson(publicKey).ensVerified
}
function getEmojiHashAsJson(publicKey) { function getEmojiHashAsJson(publicKey) {
if (publicKey === "") { if (publicKey === "") {
return "" return ""
@ -570,10 +576,11 @@ QtObject {
return JSON.parse(jsonObj) return JSON.parse(jsonObj)
} }
function getColorHashAsJson(publicKey) { function getColorHashAsJson(publicKey, force=false) {
if (publicKey === "") { if (publicKey === "")
return "" return
} if (!force && isEnsVerified(publicKey))
return
let jsonObj = globalUtils.getColorHashAsJson(publicKey) let jsonObj = globalUtils.getColorHashAsJson(publicKey)
return JSON.parse(jsonObj) return JSON.parse(jsonObj)
} }