Skip to content

Commit

Permalink
feat(Communities): Improvements for token holders list (#11923)
Browse files Browse the repository at this point in the history
* feat(Communities): Refactor token holder list item to separate file

Close #11858

* feat(Communities): Use contact details for community member info

* feat(Communities): reuse StatusMemberListItem for member token holder

* Review fixes

Co-authored-by: Michał Iskierko <[email protected]>

---------

Co-authored-by: Michał Iskierko <[email protected]>
  • Loading branch information
MishkaRogachev and endulab authored Aug 22, 2023
1 parent 18b1579 commit cc83098
Show file tree
Hide file tree
Showing 16 changed files with 300 additions and 204 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ proc initTokenItem*(
result.remoteDestructedAddresses = remoteDestructedAddresses
result.tokenOwnersModel = newTokenOwnersModel()
result.tokenOwnersModel.setItems(tokenOwners.map(proc(owner: CommunityCollectibleOwner): TokenOwnersItem =
result = initTokenOwnersItem(owner.contactId, owner.name, owner.imageSource, owner.collectibleOwner, remoteDestructedAddresses)
# TODO: provide number of messages here
result = initTokenOwnersItem(owner.contactId, owner.name, owner.imageSource, 0, owner.collectibleOwner, remoteDestructedAddresses)
))

proc `$`*(self: TokenItem): string =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ QtObject:
for i in 0 ..< self.items.len:
if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)):
self.items[i].tokenOwnersModel.setItems(owners.map(proc(owner: CommunityCollectibleOwner): TokenOwnersItem =
result = initTokenOwnersItem(owner.contactId, owner.name, owner.imageSource, owner.collectibleOwner, self.items[i].remoteDestructedAddresses)
# TODO: provide number of messages here
result = initTokenOwnersItem(owner.contactId, owner.name, owner.imageSource, 0, owner.collectibleOwner, self.items[i].remoteDestructedAddresses)
))
let index = self.createIndex(i, 0, nil)
defer: index.delete
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type
contactId*: string
name*: string
imageSource*: string
numberOfMessages*: int
ownerDetails*: CollectibleOwner
amount*: int
remotelyDestructState*: ContractTransactionStatus
Expand All @@ -20,12 +21,14 @@ proc initTokenOwnersItem*(
contactId: string,
name: string,
imageSource: string,
numberOfMessages: int,
ownerDetails: CollectibleOwner,
remoteDestructedAddresses: seq[string]
): TokenOwnersItem =
result.contactId = contactId
result.name = name
result.imageSource = imageSource
result.numberOfMessages = numberOfMessages
result.ownerDetails = ownerDetails
result.remotelyDestructState = remoteDestructTransactionStatus(remoteDestructedAddresses, ownerDetails.address)
for balance in ownerDetails.balances:
Expand All @@ -35,6 +38,7 @@ proc `$`*(self: TokenOwnersItem): string =
result = fmt"""TokenOwnersItem(
contactId: {self.contactId},
name: {self.name},
numberOfMessages: {self.numberOfMessages},
amount: {self.amount},
ownerDetails: {self.ownerDetails}
]"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ type
ModelRole {.pure.} = enum
Name = UserRole + 1
ContactId,
ImageSource
WalletAddress
Amount
ImageSource,
NumberOfMessages,
WalletAddress,
Amount,
RemotelyDestructState

QtObject:
Expand Down Expand Up @@ -48,6 +49,7 @@ QtObject:
ModelRole.Name.int:"name",
ModelRole.ContactId.int:"contactId",
ModelRole.ImageSource.int:"imageSource",
ModelRole.NumberOfMessages.int:"numberOfMessages",
ModelRole.WalletAddress.int:"walletAddress",
ModelRole.Amount.int:"amount",
ModelRole.RemotelyDestructState.int:"remotelyDestructState"
Expand Down Expand Up @@ -76,6 +78,8 @@ QtObject:
result = newQVariant(item.contactId)
of ModelRole.ImageSource:
result = newQVariant(item.imageSource)
of ModelRole.NumberOfMessages:
result = newQVariant(item.numberOfMessages)
of ModelRole.WalletAddress:
result = newQVariant(item.ownerDetails.address)
of ModelRole.Amount:
Expand Down
2 changes: 1 addition & 1 deletion src/app/modules/main/io_interface.nim
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ method getCommunitySectionModule*(self: AccessInterface, communityId: string): Q
method getAppSearchModule*(self: AccessInterface): QVariant {.base.} =
raise newException(ValueError, "No implementation available")

method getContactDetailsAsJson*(self: AccessInterface, publicKey: string, getVerificationRequest: bool): string {.base.} =
method getContactDetailsAsJson*(self: AccessInterface, publicKey: string, getVerificationRequest: bool, getOnlineStatus: bool): string {.base.} =
raise newException(ValueError, "No implementation available")

method isEnsVerified*(self: AccessInterface, publicKey: string): bool {.base.} =
Expand Down
8 changes: 6 additions & 2 deletions src/app/modules/main/module.nim
Original file line number Diff line number Diff line change
Expand Up @@ -988,11 +988,14 @@ method onCommunityMuted*[T](
method getVerificationRequestFrom*[T](self: Module[T], publicKey: string): VerificationRequest =
self.controller.getVerificationRequestFrom(publicKey)

method getContactDetailsAsJson*[T](self: Module[T], publicKey: string, getVerificationRequest: bool): string =
method getContactDetailsAsJson*[T](self: Module[T], publicKey: string, getVerificationRequest: bool, getOnlineStatus: bool): string =
let contact = self.controller.getContact(publicKey)
var requestStatus = 0
if getVerificationRequest:
requestStatus = self.getVerificationRequestFrom(publicKey).status.int
var onlineStatus = OnlineStatus.Inactive
if getOnlineStatus:
onlineStatus = toOnlineStatus(self.controller.getStatusForContactWithId(publicKey).statusType)
let jsonObj = %* {
"displayName": contact.displayName,
"displayIcon": contact.image.thumbnail,
Expand All @@ -1018,7 +1021,8 @@ method getContactDetailsAsJson*[T](self: Module[T], publicKey: string, getVerifi
"incomingVerificationStatus": requestStatus,
"hasAddedUs": contact.hasAddedUs,
"socialLinks": $contact.socialLinks.toJsonNode(),
"bio": contact.bio
"bio": contact.bio,
"onlineStatus": onlineStatus.int
}
return $jsonObj

Expand Down
4 changes: 2 additions & 2 deletions src/app/modules/main/view.nim
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ QtObject:
QtProperty[QVariant] appSearchModule:
read = getAppSearchModule

proc getContactDetailsAsJson(self: View, publicKey: string, getVerificationRequest: bool): string {.slot.} =
return self.delegate.getContactDetailsAsJson(publicKey, getVerificationRequest)
proc getContactDetailsAsJson(self: View, publicKey: string, getVerificationRequest: bool, getOnlineStatus: bool): string {.slot.} =
return self.delegate.getContactDetailsAsJson(publicKey, getVerificationRequest, getOnlineStatus)

proc isEnsVerified(self:View, publicKey: string): bool {.slot.} =
return self.delegate.isEnsVerified(publicKey)
Expand Down
18 changes: 12 additions & 6 deletions storybook/src/Models/TokenHoldersModel.qml
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,57 @@ ListModel {
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
readonly property var data: [
{
contactId: "0x043a7ed0e8752236a4688563652fd0296453cef00a5dcddbe252dc74f72cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486b443ed1012cf04",
name: "chris.eth",
walletAddress: "0xb794f5ea0ba39494ce839613fffba74279579262",
imageSource: image,
amount: 5,
noOfMessages: 3123,
numberOfMessages: 3123,
remotelyDestructState: Constants.ContractTransactionStatus.None
},
{
contactId: "0x043a8ed0e8752236a4688563652fd0296453cef00a5dcddbe252dc74f72cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486b443ed1012cf04",
name: "carmen.eth",
walletAddress: "0xb794f5450ba39494ce839613fffba74279579261",
imageSource: image,
amount: 15,
noOfMessages: 123,
numberOfMessages: 123,
remotelyDestructState: Constants.ContractTransactionStatus.InProgress
},
{
contactId: "0x043a7ed0e9752236a4688563652fd0296453cef00a5dcddbe252dc74f72cc1caa97a2b65e4a1a52d9c30a84c9966beaaaf6b333d659cbdd2e486b443ed1012cf04",
name: "emily.eth",
walletAddress: "0xb794f5ea0ba39494ce839613fffba74279579263",
imageSource: image,
amount: 2,
noOfMessages: 3,
numberOfMessages: 3,
remotelyDestructState: Constants.ContractTransactionStatus.Completed
},
{
contactId: "",
name: "",
walletAddress: "0xb794f5ea0ba394782634hhh3fffba74279579264",
imageSource: "",
amount: 1,
noOfMessages: 0,
numberOfMessages: 0,
remotelyDestructState: Constants.ContractTransactionStatus.Failed
},
{
contactId: "",
name: "",
walletAddress: "0xc794f577990jjjjjewaofherfffba74279579265",
imageSource: "",
amount: 11,
noOfMessages: 0,
numberOfMessages: 0,
remotelyDestructState: Constants.ContractTransactionStatus.None
},
{
contactId: "",
name: "",
walletAddress: "0xd794f5ea009fnrsehggwe7777ffba74279579266",
imageSource: "",
amount: 14,
noOfMessages: 0,
numberOfMessages: 0,
remotelyDestructState: Constants.ContractTransactionStatus.None
}

Expand Down
203 changes: 203 additions & 0 deletions ui/app/AppLayouts/Communities/controls/TokenHolderListItem.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15

import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils

import utils 1.0

/*!
\qmltype TokenHolderListItem
\inherits ItemDelegate
\brief Represents a token holder which can be a community member or a bare wallet address
*/

ItemDelegate {
id: root

property int usernameHeaderWidth: 0
property int noOfMessagesHeaderWidth: 0
property int holdingHeaderWidth: 0
property bool isCurrentItem: false

property bool remotelyDestructInProgress: false
property bool showSeparator: false
property bool isFirstRowAddress: false

property string name
property string contactId
property string walletAddress
property string imageSource
property int numberOfMessages: 0
property int amount: 0

property var contactDetails: null

readonly property string addressElided: StatusQUtils.Utils.elideText(root.walletAddress, 6, 3).replace(
"0x", "0" + String.fromCodePoint(0x00D7))

signal clicked(var mouse)

function updateContactDetails() {
contactDetails = contactId !== "" ? Utils.getContactDetailsAsJson(contactId, false) : null
}

Component.onCompleted: root.updateContactDetails()
onContactIdChanged: root.updateContactDetails()

onRemotelyDestructInProgressChanged: {
if (!remotelyDestructInProgress)
colorAnimation.restart()
}

padding: 0
horizontalPadding: Style.current.padding
topPadding: showSeparator ? Style.current.halfPadding : 0

background: Item {
Rectangle {
anchors.fill: parent
anchors.topMargin: root.topPadding

radius: Style.current.radius
color: root.hovered || root.isCurrentItem ? Theme.palette.baseColor2 : "transparent"
}

Rectangle {
anchors.fill: parent
anchors.topMargin: root.topPadding

radius: Style.current.radius
color: "transparent"

SequentialAnimation on color {
id: colorAnimation

running: false

PropertyAction { value: Theme.palette.primaryColor3 }
PauseAnimation { duration: 1000 }
ColorAnimation { to: "transparent"; duration: 500 }
}
}

Rectangle {
visible: root.showSeparator

anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right

height: 1
color: Theme.palette.baseColor2
}
}

Component {
id: communityMemberContentItem

StatusMemberListItem {
color: "transparent"
leftPadding: 0
rightPadding: 0
sensor.enabled: false
nickName: root.contactDetails.localNickname
userName: ProfileUtils.displayName("", root.contactDetails.ensName, root.contactDetails.displayName, root.contactDetails.alias)
pubKey: root.contactDetails.isEnsVerified ? "" : Utils.getCompressedPk(root.contactId)
isContact: root.contactDetails.isContact
isVerified: root.contactDetails.verificationStatus === Constants.verificationStatus.verified
isUntrustworthy: root.contactDetails.trustStatus == Constants.trustStatus.untrustworthy
isAdmin: root.contactDetails.memberRole === Constants.memberRole.owner
status: root.contactDetails.onlineStatus
asset.name: root.contactDetails.displayIcon
asset.isImage: (asset.name !== "")
asset.isLetterIdenticon: (asset.name === "")
asset.color: Utils.colorForPubkey(root.contactId)
ringSettings.ringSpecModel: Utils.getColorHashAsJson(root.contactId)
}
}

Component {
id: bareAddressContentItem

StatusListItem {
color: "transparent"
leftPadding: 0
rightPadding: 0
sensor.enabled: false
title: root.addressElided
statusListItemIcon.name: "?"
statusListItemSubTitle.font.pixelSize: Theme.asideTextFontSize
statusListItemSubTitle.lineHeightMode: Text.FixedHeight
statusListItemSubTitle.lineHeight: 14
asset.name: root.imageSource
asset.isImage: true
asset.isLetterIdenticon: true
asset.color: Theme.palette.userCustomizationColors[d.red2Color]
}
}

contentItem: Item {
implicitWidth: delegateRow.implicitWidth
implicitHeight: delegateRow.implicitHeight

RowLayout {
id: delegateRow

spacing: Style.current.padding

Loader {
Layout.preferredWidth: root.usernameHeaderWidth
sourceComponent: contactDetails ? communityMemberContentItem : bareAddressContentItem
}

TokenHolderNumberCell {
Layout.preferredWidth: root.noOfMessagesHeaderWidth

text: root.name
? LocaleUtils.numberToLocaleString(root.numberOfMessages)
: "-"
}

RowLayout {
Layout.preferredWidth: root.holdingHeaderWidth
spacing: 4

StatusBaseText {
Layout.fillWidth: true
horizontalAlignment: Qt.AlignRight

text: StatusQUtils.Emoji.fromCodePoint("1f525") // :fire: emoji
font.pixelSize: Style.current.tertiaryTextFontSize
visible: root.remotelyDestructInProgress
color: Theme.palette.directColor1
}

TokenHolderNumberCell {
Layout.alignment: Qt.AlignRight
text: LocaleUtils.numberToLocaleString(root.amount)
}

StatusLoadingIndicator {
Layout.preferredHeight: Theme.primaryTextFontSize
Layout.preferredWidth: Layout.preferredHeight
Layout.leftMargin: 6
visible: root.remotelyDestructInProgress
color: Theme.palette.primaryColor1
}
}
}
}

MouseArea {
anchors.fill: parent

acceptedButtons: Qt.AllButtons
cursorShape: Qt.PointingHandCursor

onClicked: root.clicked(mouse)
}
}
Loading

0 comments on commit cc83098

Please sign in to comment.