fix(communities): deltas between designs and build for join token gated community flow
This commit: - improves selection of addresses to reveal - keeps the selection state for the popup lifetime - brings higher granularity in terms of signed requests by keypairs - meets new requirements from the latest related Figma - merges edit shared addresses feature and request to join community features into a single component, cause the flow is logically the same, with the only difference that when editing revealed addresses we don't show the community intro screen Fixes at least points 3 and 4 from #13988
This commit is contained in:
parent
ec4e2f3fc8
commit
10a8469b9e
|
@ -224,7 +224,7 @@ method prepareKeypairsForSigning*(self: AccessInterface, communityId: string, en
|
||||||
airdropAddress: string, editMode: bool) {.base.} =
|
airdropAddress: string, editMode: bool) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method signSharedAddressesForAllNonKeycardKeypairs*(self: AccessInterface) {.base.} =
|
method signProfileKeypairAndAllNonKeycardKeypairs*(self: AccessInterface) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
method signSharedAddressesForKeypair*(self: AccessInterface, keyUid: string, pin: string) {.base.} =
|
method signSharedAddressesForKeypair*(self: AccessInterface, keyUid: string, pin: string) {.base.} =
|
||||||
|
|
|
@ -675,7 +675,7 @@ method shareCommunityChannelUrlWithChatKey*(self: Module, communityId: string, c
|
||||||
method shareCommunityChannelUrlWithData*(self: Module, communityId: string, chatId: string): string =
|
method shareCommunityChannelUrlWithData*(self: Module, communityId: string, chatId: string): string =
|
||||||
return self.controller.shareCommunityChannelUrlWithData(communityId, chatId)
|
return self.controller.shareCommunityChannelUrlWithData(communityId, chatId)
|
||||||
|
|
||||||
proc signRevealedAddressesThatBelongToRegularKeypairs(self: Module): bool =
|
proc signRevealedAddressesForNonKeycardKeypairs(self: Module): bool =
|
||||||
var signingParams: seq[SignParamsDto]
|
var signingParams: seq[SignParamsDto]
|
||||||
for address, details in self.joiningCommunityDetails.addressesToShare.pairs:
|
for address, details in self.joiningCommunityDetails.addressesToShare.pairs:
|
||||||
if details.signature.len > 0:
|
if details.signature.len > 0:
|
||||||
|
@ -702,8 +702,24 @@ proc signRevealedAddressesThatBelongToRegularKeypairs(self: Module): bool =
|
||||||
let signatures = self.controller.signCommunityRequests(self.joiningCommunityDetails.communityId, signingParams)
|
let signatures = self.controller.signCommunityRequests(self.joiningCommunityDetails.communityId, signingParams)
|
||||||
for i in 0 ..< len(signingParams):
|
for i in 0 ..< len(signingParams):
|
||||||
self.joiningCommunityDetails.addressesToShare[signingParams[i].address].signature = signatures[i]
|
self.joiningCommunityDetails.addressesToShare[signingParams[i].address].signature = signatures[i]
|
||||||
|
self.view.keypairsSigningModel().setOwnershipVerified(self.joiningCommunityDetails.addressesToShare[signingParams[i].address].keyUid, true)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
proc signRevealedAddressesForNonKeycardKeypairsAndEmitSignal(self: Module) =
|
||||||
|
if self.signRevealedAddressesForNonKeycardKeypairs() and self.joiningCommunityDetails.allSigned():
|
||||||
|
self.view.sendAllSharedAddressesSignedSignal()
|
||||||
|
|
||||||
|
proc anyProfileKeyPairAddressSelectedToBeRevealed(self: Module): bool =
|
||||||
|
let profileKeypair = self.controller.getKeypairByKeyUid(singletonInstance.userProfile.getKeyUid())
|
||||||
|
if profileKeypair.isNil:
|
||||||
|
error "profile keypair not found"
|
||||||
|
return false
|
||||||
|
for acc in profileKeypair.accounts:
|
||||||
|
for addrToReveal in self.joiningCommunityDetails.addressesToShare.keys:
|
||||||
|
if cmpIgnoreCase(addrToReveal, acc.address) == 0:
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
method onUserAuthenticated*(self: Module, pin: string, password: string, keyUid: string) =
|
method onUserAuthenticated*(self: Module, pin: string, password: string, keyUid: string) =
|
||||||
if password == "" and pin == "":
|
if password == "" and pin == "":
|
||||||
info "unsuccesful authentication"
|
info "unsuccesful authentication"
|
||||||
|
@ -712,8 +728,16 @@ method onUserAuthenticated*(self: Module, pin: string, password: string, keyUid:
|
||||||
|
|
||||||
self.joiningCommunityDetails.profilePassword = password
|
self.joiningCommunityDetails.profilePassword = password
|
||||||
self.joiningCommunityDetails.profilePin = pin
|
self.joiningCommunityDetails.profilePin = pin
|
||||||
if self.signRevealedAddressesThatBelongToRegularKeypairs():
|
|
||||||
self.view.sendSharedAddressesForAllNonKeycardKeypairsSignedSignal()
|
# If any profile keypair address selected to be revealed and if the profile is a keycard user, we need to sign the request
|
||||||
|
# for revealed profile addresses first, then using pubic encryption key to sign other non keycard key pairs.
|
||||||
|
# If the profile is not a keycard user, we sign the request for it calling `signRevealedAddressesForNonKeycardKeypairs` function.
|
||||||
|
if keyUid == singletonInstance.userProfile.getKeyUid() and
|
||||||
|
singletonInstance.userProfile.getIsKeycardUser() and
|
||||||
|
self.anyProfileKeyPairAddressSelectedToBeRevealed():
|
||||||
|
self.signSharedAddressesForKeypair(keyUid, pin)
|
||||||
|
return
|
||||||
|
self.signRevealedAddressesForNonKeycardKeypairsAndEmitSignal()
|
||||||
|
|
||||||
method onDataSigned*(self: Module, keyUid: string, path: string, r: string, s: string, v: string, pin: string) =
|
method onDataSigned*(self: Module, keyUid: string, path: string, r: string, s: string, v: string, pin: string) =
|
||||||
if keyUid.len == 0 or path.len == 0 or r.len == 0 or s.len == 0 or v.len == 0 or pin.len == 0:
|
if keyUid.len == 0 or path.len == 0 or r.len == 0 or s.len == 0 or v.len == 0 or pin.len == 0:
|
||||||
|
@ -727,6 +751,11 @@ method onDataSigned*(self: Module, keyUid: string, path: string, r: string, s: s
|
||||||
break
|
break
|
||||||
self.signSharedAddressesForKeypair(keyUid, pin)
|
self.signSharedAddressesForKeypair(keyUid, pin)
|
||||||
|
|
||||||
|
# Only if the signed request is for the profile revealed addresses, we need to try to sign other revealed addresses
|
||||||
|
# for non profile key pairs. If they are already signed or moved to keycard we skip them (handled in signRevealedAddressesForNonKeycardKeypairsAndEmitSignal)
|
||||||
|
if keyUid == singletonInstance.userProfile.getKeyUid():
|
||||||
|
self.signRevealedAddressesForNonKeycardKeypairsAndEmitSignal()
|
||||||
|
|
||||||
method prepareKeypairsForSigning*(self: Module, communityId, ensName: string, addresses: string,
|
method prepareKeypairsForSigning*(self: Module, communityId, ensName: string, addresses: string,
|
||||||
airdropAddress: string, editMode: bool) =
|
airdropAddress: string, editMode: bool) =
|
||||||
var addressesToShare: seq[string]
|
var addressesToShare: seq[string]
|
||||||
|
@ -778,7 +807,7 @@ method prepareKeypairsForSigning*(self: Module, communityId, ensName: string, ad
|
||||||
)
|
)
|
||||||
self.joiningCommunityDetails.addressesToShare[param.address] = details
|
self.joiningCommunityDetails.addressesToShare[param.address] = details
|
||||||
|
|
||||||
method signSharedAddressesForAllNonKeycardKeypairs*(self: Module) =
|
method signProfileKeypairAndAllNonKeycardKeypairs*(self: Module) =
|
||||||
self.controller.authenticate()
|
self.controller.authenticate()
|
||||||
|
|
||||||
# if pin is provided we're signing on a keycard silently
|
# if pin is provided we're signing on a keycard silently
|
||||||
|
@ -796,6 +825,8 @@ method signSharedAddressesForKeypair*(self: Module, keyUid: string, pin: string)
|
||||||
self.controller.runSigningOnKeycard(keyUid, details.path, details.messageToBeSigned, pin)
|
self.controller.runSigningOnKeycard(keyUid, details.path, details.messageToBeSigned, pin)
|
||||||
return
|
return
|
||||||
self.view.keypairsSigningModel().setOwnershipVerified(keyUid, true)
|
self.view.keypairsSigningModel().setOwnershipVerified(keyUid, true)
|
||||||
|
if self.joiningCommunityDetails.allSigned():
|
||||||
|
self.view.sendAllSharedAddressesSignedSignal()
|
||||||
|
|
||||||
method joinCommunityOrEditSharedAddresses*(self: Module) =
|
method joinCommunityOrEditSharedAddresses*(self: Module) =
|
||||||
if not self.joiningCommunityDetails.allSigned():
|
if not self.joiningCommunityDetails.allSigned():
|
||||||
|
|
|
@ -339,8 +339,8 @@ QtObject:
|
||||||
proc prepareTokenModelForCommunity(self: View, communityId: string) {.slot.} =
|
proc prepareTokenModelForCommunity(self: View, communityId: string) {.slot.} =
|
||||||
self.delegate.prepareTokenModelForCommunity(communityId)
|
self.delegate.prepareTokenModelForCommunity(communityId)
|
||||||
|
|
||||||
proc signSharedAddressesForAllNonKeycardKeypairs*(self: View) {.slot.} =
|
proc signProfileKeypairAndAllNonKeycardKeypairs*(self: View) {.slot.} =
|
||||||
self.delegate.signSharedAddressesForAllNonKeycardKeypairs()
|
self.delegate.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
|
|
||||||
proc signSharedAddressesForKeypair*(self: View, keyUid: string) {.slot.} =
|
proc signSharedAddressesForKeypair*(self: View, keyUid: string) {.slot.} =
|
||||||
self.delegate.signSharedAddressesForKeypair(keyUid, pin = "")
|
self.delegate.signSharedAddressesForKeypair(keyUid, pin = "")
|
||||||
|
@ -815,9 +815,9 @@ QtObject:
|
||||||
self.keypairsSigningModel.setItems(items)
|
self.keypairsSigningModel.setItems(items)
|
||||||
self.keypairsSigningModelChanged()
|
self.keypairsSigningModelChanged()
|
||||||
|
|
||||||
proc sharedAddressesForAllNonKeycardKeypairsSigned(self: View) {.signal.}
|
proc allSharedAddressesSigned*(self: View) {.signal.}
|
||||||
proc sendSharedAddressesForAllNonKeycardKeypairsSignedSignal*(self: View) =
|
proc sendAllSharedAddressesSignedSignal*(self: View) =
|
||||||
self.sharedAddressesForAllNonKeycardKeypairsSigned()
|
self.allSharedAddressesSigned()
|
||||||
|
|
||||||
proc promoteSelfToControlNode*(self: View, communityId: string) {.slot.} =
|
proc promoteSelfToControlNode*(self: View, communityId: string) {.slot.} =
|
||||||
self.delegate.promoteSelfToControlNode(communityId)
|
self.delegate.promoteSelfToControlNode(communityId)
|
||||||
|
|
|
@ -120,3 +120,6 @@ method getRpcStats*(self: AccessInterface): string {.base.} =
|
||||||
|
|
||||||
method resetRpcStats*(self: AccessInterface) {.base.} =
|
method resetRpcStats*(self: AccessInterface) {.base.} =
|
||||||
raise newException(ValueError, "No implementation available")
|
raise newException(ValueError, "No implementation available")
|
||||||
|
|
||||||
|
method canProfileProveOwnershipOfProvidedAddresses*(self: AccessInterface, addresses: string): bool {.base.} =
|
||||||
|
raise newException(ValueError, "No implementation available")
|
|
@ -1,4 +1,4 @@
|
||||||
import NimQml, chronicles, sequtils, strutils, sugar
|
import NimQml, json, chronicles, sequtils, strutils, sugar
|
||||||
|
|
||||||
import ./controller, ./view, ./filter
|
import ./controller, ./view, ./filter
|
||||||
import ./io_interface as io_interface
|
import ./io_interface as io_interface
|
||||||
|
@ -471,3 +471,21 @@ method getRpcStats*(self: Module): string =
|
||||||
|
|
||||||
method resetRpcStats*(self: Module) =
|
method resetRpcStats*(self: Module) =
|
||||||
self.view.resetRpcStats()
|
self.view.resetRpcStats()
|
||||||
|
|
||||||
|
method canProfileProveOwnershipOfProvidedAddresses*(self: Module, addresses: string): bool =
|
||||||
|
var addressesForProvingOwnership: seq[string]
|
||||||
|
try:
|
||||||
|
addressesForProvingOwnership = map(parseJson(addresses).getElems(), proc(x:JsonNode):string = x.getStr())
|
||||||
|
except Exception as e:
|
||||||
|
error "Failed to parse addresses for proving ownership: ", msg=e.msg
|
||||||
|
return false
|
||||||
|
|
||||||
|
for address in addressesForProvingOwnership:
|
||||||
|
let keypair = self.controller.getKeypairByAccountAddress(address)
|
||||||
|
if keypair.isNil:
|
||||||
|
return false
|
||||||
|
if keypair.keyUid == singletonInstance.userProfile.getKeyUid():
|
||||||
|
continue
|
||||||
|
if keypair.migratedToKeycard():
|
||||||
|
return false
|
||||||
|
return true
|
|
@ -10,6 +10,7 @@ QtObject:
|
||||||
canSend: bool
|
canSend: bool
|
||||||
|
|
||||||
proc setup*(self: AccountItem,
|
proc setup*(self: AccountItem,
|
||||||
|
keyUid: string,
|
||||||
name: string,
|
name: string,
|
||||||
address: string,
|
address: string,
|
||||||
colorId: string,
|
colorId: string,
|
||||||
|
@ -29,7 +30,7 @@ QtObject:
|
||||||
emoji,
|
emoji,
|
||||||
walletType,
|
walletType,
|
||||||
path = "",
|
path = "",
|
||||||
keyUid = "",
|
keyUid = keyUid,
|
||||||
keycardAccount = false,
|
keycardAccount = false,
|
||||||
position,
|
position,
|
||||||
operability = wa_dto.AccountFullyOperable,
|
operability = wa_dto.AccountFullyOperable,
|
||||||
|
@ -43,6 +44,7 @@ QtObject:
|
||||||
self.QObject.delete
|
self.QObject.delete
|
||||||
|
|
||||||
proc newAccountItem*(
|
proc newAccountItem*(
|
||||||
|
keyUid: string = "",
|
||||||
name: string = "",
|
name: string = "",
|
||||||
address: string = "",
|
address: string = "",
|
||||||
colorId: string = "",
|
colorId: string = "",
|
||||||
|
@ -56,7 +58,7 @@ QtObject:
|
||||||
canSend: bool = true,
|
canSend: bool = true,
|
||||||
): AccountItem =
|
): AccountItem =
|
||||||
new(result, delete)
|
new(result, delete)
|
||||||
result.setup(name, address, colorId, emoji, walletType, currencyBalance, position, areTestNetworksEnabled, prodPreferredChainIds, testPreferredChainIds, canSend)
|
result.setup(keyUid, name, address, colorId, emoji, walletType, currencyBalance, position, areTestNetworksEnabled, prodPreferredChainIds, testPreferredChainIds, canSend)
|
||||||
|
|
||||||
proc `$`*(self: AccountItem): string =
|
proc `$`*(self: AccountItem): string =
|
||||||
result = "WalletSection-Send-Item("
|
result = "WalletSection-Send-Item("
|
||||||
|
|
|
@ -5,13 +5,14 @@ import ../../../shared_models/currency_amount
|
||||||
|
|
||||||
type
|
type
|
||||||
ModelRole {.pure.} = enum
|
ModelRole {.pure.} = enum
|
||||||
Name = UserRole + 1,
|
KeyUid = UserRole + 1
|
||||||
Address,
|
Name
|
||||||
ColorId,
|
Address
|
||||||
WalletType,
|
ColorId
|
||||||
Emoji,
|
WalletType
|
||||||
CurrencyBalance,
|
Emoji
|
||||||
Position,
|
CurrencyBalance
|
||||||
|
Position
|
||||||
PreferredSharingChainIds
|
PreferredSharingChainIds
|
||||||
|
|
||||||
QtObject:
|
QtObject:
|
||||||
|
@ -48,6 +49,7 @@ QtObject:
|
||||||
|
|
||||||
method roleNames(self: AccountsModel): Table[int, string] =
|
method roleNames(self: AccountsModel): Table[int, string] =
|
||||||
{
|
{
|
||||||
|
ModelRole.KeyUid.int: "keyUid",
|
||||||
ModelRole.Name.int:"name",
|
ModelRole.Name.int:"name",
|
||||||
ModelRole.Address.int:"address",
|
ModelRole.Address.int:"address",
|
||||||
ModelRole.ColorId.int:"colorId",
|
ModelRole.ColorId.int:"colorId",
|
||||||
|
@ -75,6 +77,8 @@ QtObject:
|
||||||
let enumRole = role.ModelRole
|
let enumRole = role.ModelRole
|
||||||
|
|
||||||
case enumRole:
|
case enumRole:
|
||||||
|
of ModelRole.KeyUid:
|
||||||
|
result = newQVariant(item.keyUid())
|
||||||
of ModelRole.Name:
|
of ModelRole.Name:
|
||||||
result = newQVariant(item.name())
|
result = newQVariant(item.name())
|
||||||
of ModelRole.Address:
|
of ModelRole.Address:
|
||||||
|
|
|
@ -259,3 +259,6 @@ QtObject:
|
||||||
return self.delegate.getRpcStats()
|
return self.delegate.getRpcStats()
|
||||||
proc resetRpcStats*(self: View) {.slot.} =
|
proc resetRpcStats*(self: View) {.slot.} =
|
||||||
self.delegate.resetRpcStats()
|
self.delegate.resetRpcStats()
|
||||||
|
|
||||||
|
proc canProfileProveOwnershipOfProvidedAddresses*(self: View, addresses: string): bool {.slot.} =
|
||||||
|
return self.delegate.canProfileProveOwnershipOfProvidedAddresses(addresses)
|
|
@ -60,6 +60,7 @@ proc walletAccountToWalletAccountsItem*(w: WalletAccountDto, keycardAccount: boo
|
||||||
proc walletAccountToWalletSendAccountItem*(w: WalletAccountDto, chainIds: seq[int], enabledChainIds: seq[int],
|
proc walletAccountToWalletSendAccountItem*(w: WalletAccountDto, chainIds: seq[int], enabledChainIds: seq[int],
|
||||||
currencyBalance: float64, currencyFormat: CurrencyFormatDto, areTestNetworksEnabled: bool): wallet_send_account_item.AccountItem =
|
currencyBalance: float64, currencyFormat: CurrencyFormatDto, areTestNetworksEnabled: bool): wallet_send_account_item.AccountItem =
|
||||||
return wallet_send_account_item.newAccountItem(
|
return wallet_send_account_item.newAccountItem(
|
||||||
|
w.keyUid,
|
||||||
w.name,
|
w.name,
|
||||||
w.address,
|
w.address,
|
||||||
w.colorId,
|
w.colorId,
|
||||||
|
|
|
@ -122,9 +122,9 @@ StackLayout {
|
||||||
Global.openPopup(communityIntroDialogPopup, {
|
Global.openPopup(communityIntroDialogPopup, {
|
||||||
communityId: joinCommunityView.communityId,
|
communityId: joinCommunityView.communityId,
|
||||||
isInvitationPending: joinCommunityView.isInvitationPending,
|
isInvitationPending: joinCommunityView.isInvitationPending,
|
||||||
name: communityData.name,
|
communityName: communityData.name,
|
||||||
introMessage: communityData.introMessage,
|
introMessage: communityData.introMessage,
|
||||||
imageSrc: communityData.image,
|
communityIcon: communityData.image,
|
||||||
accessType: communityData.access
|
accessType: communityData.access
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -190,9 +190,9 @@ StackLayout {
|
||||||
Global.openPopup(communityIntroDialogPopup, {
|
Global.openPopup(communityIntroDialogPopup, {
|
||||||
communityId: chatView.communityId,
|
communityId: chatView.communityId,
|
||||||
isInvitationPending: root.rootStore.isMyCommunityRequestPending(chatView.communityId),
|
isInvitationPending: root.rootStore.isMyCommunityRequestPending(chatView.communityId),
|
||||||
name: root.sectionItemModel.name,
|
communityName: root.sectionItemModel.name,
|
||||||
introMessage: root.sectionItemModel.introMessage,
|
introMessage: root.sectionItemModel.introMessage,
|
||||||
imageSrc: root.sectionItemModel.image,
|
communityIcon: root.sectionItemModel.image,
|
||||||
accessType: root.sectionItemModel.access
|
accessType: root.sectionItemModel.access
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -272,8 +272,9 @@ StackLayout {
|
||||||
|
|
||||||
property string communityId
|
property string communityId
|
||||||
|
|
||||||
loginType: root.rootStore.loginType
|
|
||||||
walletAccountsModel: WalletStore.RootStore.nonWatchAccounts
|
walletAccountsModel: WalletStore.RootStore.nonWatchAccounts
|
||||||
|
canProfileProveOwnershipOfProvidedAddressesFn: WalletStore.RootStore.canProfileProveOwnershipOfProvidedAddresses
|
||||||
|
|
||||||
walletAssetsModel: walletAssetsStore.groupedAccountAssetsModel
|
walletAssetsModel: walletAssetsStore.groupedAccountAssetsModel
|
||||||
requirementsCheckPending: root.rootStore.requirementsCheckPending
|
requirementsCheckPending: root.rootStore.requirementsCheckPending
|
||||||
permissionsModel: {
|
permissionsModel: {
|
||||||
|
@ -293,8 +294,8 @@ StackLayout {
|
||||||
communityIntroDialog.keypairSigningModel = root.rootStore.communitiesModuleInst.keypairsSigningModel
|
communityIntroDialog.keypairSigningModel = root.rootStore.communitiesModuleInst.keypairsSigningModel
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignSharedAddressesForAllNonKeycardKeypairs: {
|
onSignProfileKeypairAndAllNonKeycardKeypairs: {
|
||||||
root.rootStore.signSharedAddressesForAllNonKeycardKeypairs()
|
root.rootStore.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignSharedAddressesForKeypair: {
|
onSignSharedAddressesForKeypair: {
|
||||||
|
@ -321,9 +322,21 @@ StackLayout {
|
||||||
Connections {
|
Connections {
|
||||||
target: root.rootStore.communitiesModuleInst
|
target: root.rootStore.communitiesModuleInst
|
||||||
|
|
||||||
function onSharedAddressesForAllNonKeycardKeypairsSigned() {
|
function onAllSharedAddressesSigned() {
|
||||||
|
if (communityIntroDialog.profileProvesOwnershipOfSelectedAddresses) {
|
||||||
|
communityIntroDialog.joinCommunity()
|
||||||
|
communityIntroDialog.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (communityIntroDialog.allAddressesToRevealBelongToSingleNonProfileKeypair) {
|
||||||
|
communityIntroDialog.joinCommunity()
|
||||||
|
communityIntroDialog.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!!communityIntroDialog.replaceItem) {
|
if (!!communityIntroDialog.replaceItem) {
|
||||||
communityIntroDialog.replaceLoader.item.sharedAddressesForAllNonKeycardKeypairsSigned()
|
communityIntroDialog.replaceLoader.item.allSigned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -403,8 +403,8 @@ QtObject {
|
||||||
communitiesModuleInst.prepareKeypairsForSigning(communityId, ensName, JSON.stringify(addressesToShare), airdropAddress, editMode)
|
communitiesModuleInst.prepareKeypairsForSigning(communityId, ensName, JSON.stringify(addressesToShare), airdropAddress, editMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
function signSharedAddressesForAllNonKeycardKeypairs() {
|
function signProfileKeypairAndAllNonKeycardKeypairs() {
|
||||||
communitiesModuleInst.signSharedAddressesForAllNonKeycardKeypairs()
|
communitiesModuleInst.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
}
|
}
|
||||||
|
|
||||||
function signSharedAddressesForKeypair(keyUid) {
|
function signSharedAddressesForKeypair(keyUid) {
|
||||||
|
|
|
@ -15,17 +15,16 @@ import utils 1.0
|
||||||
StatusListView {
|
StatusListView {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
required property var selectedSharedAddressesMap // Map[address, [selected, isAirdrop]]
|
||||||
|
|
||||||
property var walletAssetsModel
|
property var walletAssetsModel
|
||||||
property bool hasPermissions
|
property bool hasPermissions
|
||||||
property var uniquePermissionTokenKeys
|
property var uniquePermissionTokenKeys
|
||||||
|
|
||||||
// read/write properties
|
|
||||||
property string selectedAirdropAddress
|
|
||||||
property var selectedSharedAddresses: []
|
|
||||||
|
|
||||||
property var getCurrencyAmount: function (balance, symbol){}
|
property var getCurrencyAmount: function (balance, symbol){}
|
||||||
|
|
||||||
signal addressesChanged()
|
signal toggleAddressSelection(string keyUid, string address)
|
||||||
|
signal airdropAddressSelected (string address)
|
||||||
|
|
||||||
leftMargin: d.absLeftMargin
|
leftMargin: d.absLeftMargin
|
||||||
topMargin: Style.current.padding
|
topMargin: Style.current.padding
|
||||||
|
@ -35,6 +34,8 @@ StatusListView {
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
|
|
||||||
|
readonly property int selectedSharedAddressesCount: root.selectedSharedAddressesMap.size
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
readonly property int absLeftMargin: 12
|
readonly property int absLeftMargin: 12
|
||||||
|
|
||||||
|
@ -46,10 +47,6 @@ StatusListView {
|
||||||
exclusive: false
|
exclusive: false
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectFirstAvailableAirdropAddress() {
|
|
||||||
root.selectedAirdropAddress = ModelUtils.modelToFlatArray(root.model, "address").find(address => selectedSharedAddresses.includes(address))
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTotalBalance(balances, decimals, symbol) {
|
function getTotalBalance(balances, decimals, symbol) {
|
||||||
let totalBalance = 0
|
let totalBalance = 0
|
||||||
for(let i=0; i<balances.count; i++) {
|
for(let i=0; i<balances.count; i++) {
|
||||||
|
@ -143,12 +140,20 @@ StatusListView {
|
||||||
icon.color: hovered ? Theme.palette.primaryColor3 :
|
icon.color: hovered ? Theme.palette.primaryColor3 :
|
||||||
checked ? Theme.palette.primaryColor1 : disabledTextColor
|
checked ? Theme.palette.primaryColor1 : disabledTextColor
|
||||||
checkable: true
|
checkable: true
|
||||||
checked: listItem.address === root.selectedAirdropAddress.toLowerCase()
|
checked: {
|
||||||
enabled: shareAddressCheckbox.checked && root.selectedSharedAddresses.length > 1 // last cannot be unchecked
|
let obj = root.selectedSharedAddressesMap.get(listItem.address)
|
||||||
|
if (!!obj) {
|
||||||
|
return obj.isAirdrop
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
enabled: shareAddressCheckbox.checked && d.selectedSharedAddressesCount > 1 // last cannot be unchecked
|
||||||
visible: shareAddressCheckbox.checked
|
visible: shareAddressCheckbox.checked
|
||||||
opacity: enabled ? 1.0 : 0.3
|
opacity: enabled ? 1.0 : 0.3
|
||||||
onCheckedChanged: if (checked) root.selectedAirdropAddress = listItem.address
|
|
||||||
onToggled: root.addressesChanged()
|
onToggled: {
|
||||||
|
root.airdropAddressSelected(listItem.address)
|
||||||
|
}
|
||||||
|
|
||||||
StatusToolTip {
|
StatusToolTip {
|
||||||
text: qsTr("Use this address for any Community airdrops")
|
text: qsTr("Use this address for any Community airdrops")
|
||||||
|
@ -161,25 +166,11 @@ StatusListView {
|
||||||
ButtonGroup.group: d.addressesGroup
|
ButtonGroup.group: d.addressesGroup
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
checkable: true
|
checkable: true
|
||||||
checked: root.selectedSharedAddresses.some((address) => address.toLowerCase() === listItem.address )
|
checked: root.selectedSharedAddressesMap.has(listItem.address)
|
||||||
enabled: !(root.selectedSharedAddresses.length === 1 && checked) // last cannot be unchecked
|
enabled: !(d.selectedSharedAddressesCount === 1 && checked) // last cannot be unchecked
|
||||||
|
|
||||||
onToggled: {
|
onToggled: {
|
||||||
// handle selected addresses
|
root.toggleAddressSelection(model.keyUid, listItem.address)
|
||||||
const index = root.selectedSharedAddresses.findIndex((address) => address.toLowerCase() === listItem.address)
|
|
||||||
const selectedSharedAddressesCopy = Object.assign([], root.selectedSharedAddresses) // deep copy
|
|
||||||
if (index === -1) {
|
|
||||||
selectedSharedAddressesCopy.push(listItem.address)
|
|
||||||
} else {
|
|
||||||
selectedSharedAddressesCopy.splice(index, 1)
|
|
||||||
}
|
|
||||||
root.selectedSharedAddresses = selectedSharedAddressesCopy
|
|
||||||
|
|
||||||
// switch to next available airdrop address when unchecking
|
|
||||||
if (!checked && listItem.address === root.selectedAirdropAddress.toLowerCase()) {
|
|
||||||
d.selectFirstAvailableAirdropAddress()
|
|
||||||
}
|
|
||||||
|
|
||||||
root.addressesChanged()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -24,13 +24,18 @@ import shared.panels 1.0
|
||||||
Control {
|
Control {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property bool isEditMode
|
required property string componentUid
|
||||||
|
required property bool isEditMode
|
||||||
|
required property var selectedSharedAddressesMap // Map[address, [keyUid, selected, isAirdrop]
|
||||||
|
property var currentSharedAddressesMap // Map[address, [keyUid, selected, isAirdrop]
|
||||||
|
required property int totalNumOfAddressesForSharing
|
||||||
|
required property bool profileProvesOwnershipOfSelectedAddresses
|
||||||
|
required property bool allAddressesToRevealBelongToSingleNonProfileKeypair
|
||||||
|
|
||||||
property bool requirementsCheckPending: false
|
property bool requirementsCheckPending: false
|
||||||
|
|
||||||
required property string communityName
|
required property string communityName
|
||||||
required property string communityIcon
|
required property string communityIcon
|
||||||
property int loginType: Constants.LoginType.Password
|
|
||||||
|
|
||||||
required property var walletAssetsModel
|
required property var walletAssetsModel
|
||||||
required property var walletAccountsModel // name, address, emoji, colorId, assets
|
required property var walletAccountsModel // name, address, emoji, colorId, assets
|
||||||
|
@ -38,52 +43,16 @@ Control {
|
||||||
required property var assetsModel
|
required property var assetsModel
|
||||||
required property var collectiblesModel
|
required property var collectiblesModel
|
||||||
|
|
||||||
readonly property string title: isEditMode ? qsTr("Edit which addresses you share with %1").arg(communityName)
|
readonly property string title: isEditMode ? qsTr("Edit which addresses you share with %1").arg(root.communityName)
|
||||||
: qsTr("Select addresses to share with %1").arg(communityName)
|
: qsTr("Select addresses to share with %1").arg(root.communityName)
|
||||||
|
|
||||||
readonly property var buttons: ObjectModel {
|
readonly property var rightButtons: root.isEditMode? [d.cancelButton, d.saveButton] : [d.shareAddressesButton]
|
||||||
StatusFlatButton {
|
|
||||||
visible: root.isEditMode
|
|
||||||
borderColor: Theme.palette.baseColor2
|
|
||||||
text: qsTr("Cancel")
|
|
||||||
onClicked: root.close()
|
|
||||||
}
|
|
||||||
StatusButton {
|
|
||||||
enabled: d.dirty
|
|
||||||
type: d.lostCommunityPermission || d.lostChannelPermissions ? StatusBaseButton.Type.Danger : StatusBaseButton.Type.Normal
|
|
||||||
visible: root.isEditMode
|
|
||||||
icon.name: type === StatusBaseButton.Type.Normal && d.selectedAddressesDirty?
|
|
||||||
!root.isEditMode? Constants.authenticationIconByType[root.loginType] : ""
|
|
||||||
: ""
|
|
||||||
text: d.lostCommunityPermission ? qsTr("Save changes & leave %1").arg(root.communityName) :
|
|
||||||
d.lostChannelPermissions ? qsTr("Save changes & update my permissions")
|
|
||||||
: qsTr("Prove ownership")
|
|
||||||
onClicked: {
|
|
||||||
root.prepareForSigning(root.selectedAirdropAddress, root.selectedSharedAddresses)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StatusButton {
|
|
||||||
visible: !root.isEditMode
|
|
||||||
text: qsTr("Share selected addresses to join")
|
|
||||||
onClicked: {
|
|
||||||
root.shareSelectedAddressesClicked(root.selectedAirdropAddress, root.selectedSharedAddresses)
|
|
||||||
root.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// NB no more buttons after this, see property `rightButtons` below
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property var rightButtons: [buttons.get(buttons.count-1)] // "magically" used by CommunityIntroDialog StatusStackModal impl
|
|
||||||
|
|
||||||
property var selectedSharedAddresses: []
|
|
||||||
property string selectedAirdropAddress
|
|
||||||
|
|
||||||
property var getCurrencyAmount: function (balance, symbol){}
|
property var getCurrencyAmount: function (balance, symbol){}
|
||||||
|
|
||||||
signal sharedAddressesChanged(string airdropAddress, var sharedAddresses)
|
signal toggleAddressSelection(string keyUid, string address)
|
||||||
signal shareSelectedAddressesClicked(string airdropAddress, var sharedAddresses)
|
signal airdropAddressSelected (string address)
|
||||||
signal prepareForSigning(string airdropAddress, var sharedAddresses)
|
signal shareSelectedAddressesClicked()
|
||||||
|
|
||||||
signal close()
|
signal close()
|
||||||
|
|
||||||
padding: 0
|
padding: 0
|
||||||
|
@ -94,69 +63,108 @@ Control {
|
||||||
|
|
||||||
// internal logic
|
// internal logic
|
||||||
readonly property bool hasPermissions: root.permissionsModel && root.permissionsModel.count
|
readonly property bool hasPermissions: root.permissionsModel && root.permissionsModel.count
|
||||||
|
readonly property int selectedSharedAddressesCount: root.selectedSharedAddressesMap.size
|
||||||
|
|
||||||
// initial state (not bindings, we want a static snapshot of the initial state)
|
readonly property bool dirty: {
|
||||||
property var initialSelectedSharedAddresses: []
|
if (root.currentSharedAddressesMap.size !== root.selectedSharedAddressesMap.size) {
|
||||||
property string initialSelectedAirdropAddress
|
return true
|
||||||
|
}
|
||||||
// dirty state handling
|
for (const [key, value] of root.currentSharedAddressesMap) {
|
||||||
readonly property bool selectedAddressesDirty: !SQInternal.ModelUtils.isSameArray(d.initialSelectedSharedAddresses, root.selectedSharedAddresses)
|
const obj = root.selectedSharedAddressesMap.get(key)
|
||||||
readonly property bool selectedAirdropAddressDirty: root.selectedAirdropAddress !== d.initialSelectedAirdropAddress
|
if (!obj || value.selected !== obj.selected || value.isAirdrop !== obj.isAirdrop) {
|
||||||
readonly property bool dirty: selectedAddressesDirty || selectedAirdropAddressDirty
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// warning states
|
// warning states
|
||||||
readonly property bool lostCommunityPermission: root.isEditMode && permissionsView.lostPermissionToJoin
|
readonly property bool lostCommunityPermission: root.isEditMode && permissionsView.lostPermissionToJoin
|
||||||
readonly property bool lostChannelPermissions: root.isEditMode && permissionsView.lostChannelPermissions
|
readonly property bool lostChannelPermissions: root.isEditMode && permissionsView.lostChannelPermissions
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
readonly property var cancelButton: StatusFlatButton {
|
||||||
// initialize the state
|
visible: root.isEditMode
|
||||||
d.initialSelectedSharedAddresses = root.selectedSharedAddresses.length ? root.selectedSharedAddresses
|
borderColor: Theme.palette.baseColor2
|
||||||
: filteredAccountsModel.count ? ModelUtils.modelToFlatArray(filteredAccountsModel, "address")
|
text: qsTr("Cancel")
|
||||||
: []
|
onClicked: root.close()
|
||||||
d.initialSelectedAirdropAddress = !!root.selectedAirdropAddress ? root.selectedAirdropAddress
|
|
||||||
: d.initialSelectedSharedAddresses.length ? d.initialSelectedSharedAddresses[0] : ""
|
|
||||||
root.selectedSharedAddresses = accountSelector.selectedSharedAddresses
|
|
||||||
root.selectedAirdropAddress = accountSelector.selectedAirdropAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
function setOldSharedAddresses(oldSharedAddresses) {
|
|
||||||
d.initialSelectedSharedAddresses = oldSharedAddresses
|
|
||||||
accountSelector.selectedSharedAddresses = Qt.binding(() => d.initialSelectedSharedAddresses)
|
|
||||||
accountSelector.applyChange()
|
|
||||||
}
|
|
||||||
|
|
||||||
function setOldAirdropAddress(oldAirdropAddress) {
|
|
||||||
d.initialSelectedAirdropAddress = oldAirdropAddress
|
|
||||||
accountSelector.selectedAirdropAddress = Qt.binding(() => d.initialSelectedAirdropAddress)
|
|
||||||
accountSelector.applyChange()
|
|
||||||
}
|
|
||||||
|
|
||||||
SortFilterProxyModel {
|
|
||||||
id: filteredAccountsModel
|
|
||||||
sourceModel: root.walletAccountsModel
|
|
||||||
filters: ValueFilter {
|
|
||||||
roleName: "walletType"
|
|
||||||
value: Constants.watchWalletType
|
|
||||||
inverted: true
|
|
||||||
}
|
}
|
||||||
sorters: [
|
|
||||||
ExpressionSorter {
|
readonly property var saveButton: StatusButton {
|
||||||
function isGenerated(modelData) {
|
enabled: d.dirty
|
||||||
return modelData.walletType === Constants.generatedWalletType
|
type: d.lostCommunityPermission || d.lostChannelPermissions ? StatusBaseButton.Type.Danger : StatusBaseButton.Type.Normal
|
||||||
|
visible: root.isEditMode
|
||||||
|
|
||||||
|
text: {
|
||||||
|
if (d.lostCommunityPermission) {
|
||||||
|
return qsTr("Save changes & leave %1").arg(root.communityName)
|
||||||
|
}
|
||||||
|
if (d.lostChannelPermissions) {
|
||||||
|
return qsTr("Save changes & update my permissions")
|
||||||
|
}
|
||||||
|
if (d.selectedSharedAddressesCount === root.totalNumOfAddressesForSharing) {
|
||||||
|
return qsTr("Reveal all addresses")
|
||||||
|
}
|
||||||
|
return qsTr("Reveal %n address(s)", "", d.selectedSharedAddressesCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.name: {
|
||||||
|
if (!d.lostCommunityPermission
|
||||||
|
&& !d.lostChannelPermissions
|
||||||
|
&& root.profileProvesOwnershipOfSelectedAddresses) {
|
||||||
|
if (userProfile.usingBiometricLogin) {
|
||||||
|
return "touch-id"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userProfile.isKeycardUser) {
|
||||||
|
return "keycard"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "password"
|
||||||
|
}
|
||||||
|
if (root.allAddressesToRevealBelongToSingleNonProfileKeypair) {
|
||||||
|
return "keycard"
|
||||||
}
|
}
|
||||||
|
|
||||||
expression: {
|
return ""
|
||||||
return isGenerated(modelLeft)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
RoleSorter {
|
|
||||||
roleName: "position"
|
|
||||||
},
|
|
||||||
RoleSorter {
|
|
||||||
roleName: "name"
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
|
onClicked: {
|
||||||
|
root.shareSelectedAddressesClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property var shareAddressesButton: StatusButton {
|
||||||
|
visible: !root.isEditMode
|
||||||
|
text: {
|
||||||
|
if (d.selectedSharedAddressesCount === root.totalNumOfAddressesForSharing) {
|
||||||
|
return qsTr("Share all addresses to join")
|
||||||
|
}
|
||||||
|
return qsTr("Share %n address(s) to join", "", d.selectedSharedAddressesCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.name: {
|
||||||
|
if (root.profileProvesOwnershipOfSelectedAddresses) {
|
||||||
|
if (userProfile.usingBiometricLogin) {
|
||||||
|
return "touch-id"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userProfile.isKeycardUser) {
|
||||||
|
return "keycard"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "password"
|
||||||
|
}
|
||||||
|
if (root.allAddressesToRevealBelongToSingleNonProfileKeypair) {
|
||||||
|
return "keycard"
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.shareSelectedAddressesClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
|
@ -184,14 +192,16 @@ Control {
|
||||||
Layout.fillHeight: !hasPermissions
|
Layout.fillHeight: !hasPermissions
|
||||||
model: root.walletAccountsModel
|
model: root.walletAccountsModel
|
||||||
walletAssetsModel: root.walletAssetsModel
|
walletAssetsModel: root.walletAssetsModel
|
||||||
selectedSharedAddresses: d.initialSelectedSharedAddresses
|
selectedSharedAddressesMap: root.selectedSharedAddressesMap
|
||||||
selectedAirdropAddress: d.initialSelectedAirdropAddress
|
|
||||||
onAddressesChanged: accountSelector.applyChange()
|
onToggleAddressSelection: {
|
||||||
function applyChange() {
|
root.toggleAddressSelection(keyUid, address)
|
||||||
root.selectedSharedAddresses = selectedSharedAddresses
|
|
||||||
root.selectedAirdropAddress = selectedAirdropAddress
|
|
||||||
root.sharedAddressesChanged(selectedAirdropAddress, selectedSharedAddresses)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onAirdropAddressSelected: {
|
||||||
|
root.airdropAddressSelected(address)
|
||||||
|
}
|
||||||
|
|
||||||
getCurrencyAmount: function (balance, symbol){
|
getCurrencyAmount: function (balance, symbol){
|
||||||
return root.getCurrencyAmount(balance, symbol)
|
return root.getCurrencyAmount(balance, symbol)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,46 +13,67 @@ import SortFilterProxyModel 0.2
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
required property string componentUid
|
||||||
|
required property bool isEditMode
|
||||||
property var keypairSigningModel
|
property var keypairSigningModel
|
||||||
|
|
||||||
readonly property string title: qsTr("Prove ownership of keypairs")
|
required property var selectedSharedAddressesMap // Map[address, [keyUid, selected, isAirdrop]
|
||||||
|
required property int totalNumOfAddressesForSharing
|
||||||
|
|
||||||
|
required property string communityName
|
||||||
|
readonly property string title: root.isEditMode?
|
||||||
|
qsTr("Save addresses you share with %1").arg(root.communityName)
|
||||||
|
: qsTr("Request to join %1").arg(root.communityName)
|
||||||
readonly property var rightButtons: [d.rightBtn]
|
readonly property var rightButtons: [d.rightBtn]
|
||||||
readonly property bool allSigned: regularKeypairs.visible == d.sharedAddressesForAllNonKeycardKeypairsSigned &&
|
|
||||||
keycardKeypairs.visible == d.allKeycardKeypairsSigned
|
|
||||||
|
|
||||||
signal joinCommunity()
|
signal joinCommunity()
|
||||||
signal signSharedAddressesForAllNonKeycardKeypairs()
|
signal signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
signal signSharedAddressesForKeypair(string keyUid)
|
signal signSharedAddressesForKeypair(string keyUid)
|
||||||
|
|
||||||
function sharedAddressesForAllNonKeycardKeypairsSigned() {
|
function allSigned() {
|
||||||
d.sharedAddressesForAllNonKeycardKeypairsSigned = true
|
d.allSigned = true
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
|
|
||||||
property bool sharedAddressesForAllNonKeycardKeypairsSigned: false
|
readonly property int selectedSharedAddressesCount: root.selectedSharedAddressesMap.size
|
||||||
property bool allKeycardKeypairsSigned: false
|
|
||||||
|
property bool allSigned: false
|
||||||
|
|
||||||
|
readonly property bool anyOfSelectedAddressesToRevealBelongToProfileKeypair: {
|
||||||
|
for (const [key, value] of root.selectedSharedAddressesMap) {
|
||||||
|
if (value.keyUid === userProfile.keyUid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property bool thereAreMoreThanOneNonProfileRegularKeypairs: nonProfileRegularKeypairs.count > 1
|
||||||
|
|
||||||
|
readonly property bool allNonProfileRegularKeypairsSigned: {
|
||||||
|
for (let i = 0; i < nonProfileRegularKeypairs.model.count; ++i) {
|
||||||
|
const item = nonProfileRegularKeypairs.model.get(i)
|
||||||
|
if (!!item && !item.keyPair.ownershipVerified) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
readonly property var rightBtn: StatusButton {
|
readonly property var rightBtn: StatusButton {
|
||||||
enabled: root.allSigned
|
enabled: d.allSigned
|
||||||
text: qsTr("Share your addresses to join")
|
text: {
|
||||||
|
if (d.selectedSharedAddressesCount === root.totalNumOfAddressesForSharing) {
|
||||||
|
return qsTr("Share all addresses to join")
|
||||||
|
}
|
||||||
|
return qsTr("Share %n address(s) to join", "", d.selectedSharedAddressesCount)
|
||||||
|
}
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.joinCommunity()
|
root.joinCommunity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function reEvaluateSignedKeypairs() {
|
|
||||||
let allKeypairsSigned = true
|
|
||||||
for(var i = 0; i< keycardKeypairs.model.count; i++) {
|
|
||||||
if(!keycardKeypairs.model.get(i).keyPair.ownershipVerified) {
|
|
||||||
allKeypairsSigned = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
d.allKeycardKeypairsSigned = allKeypairsSigned
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
@ -61,43 +82,41 @@ ColumnLayout {
|
||||||
|
|
||||||
spacing: Style.current.padding
|
spacing: Style.current.padding
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
Layout.preferredWidth: parent.width
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
text: qsTr("To share %n address(s) with <b>%1</b>, authenticate the associated keypairs...", "", d.selectedSharedAddressesCount).arg(root.communityName)
|
||||||
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
visible: regularKeypairs.visible
|
visible: nonKeycardProfileKeypair.visible
|
||||||
|
|
||||||
StatusBaseText {
|
StatusBaseText {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: qsTr("Keypairs we need an authentication for")
|
text: qsTr("Stored on device")
|
||||||
font.pixelSize: Constants.keycard.general.fontSize2
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
color: Theme.palette.baseColor1
|
color: Theme.palette.baseColor1
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusButton {
|
|
||||||
text: d.sharedAddressesForAllNonKeycardKeypairsSigned? qsTr("Authenticated") : qsTr("Authenticate")
|
|
||||||
enabled: !d.sharedAddressesForAllNonKeycardKeypairsSigned
|
|
||||||
icon.name: userProfile.usingBiometricLogin? "touch-id" : "password"
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
root.signSharedAddressesForAllNonKeycardKeypairs()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusListView {
|
StatusListView {
|
||||||
id: regularKeypairs
|
id: nonKeycardProfileKeypair
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: regularKeypairs.contentHeight
|
Layout.preferredHeight: nonKeycardProfileKeypair.contentHeight
|
||||||
visible: regularKeypairs.model.count > 0
|
visible: nonKeycardProfileKeypair.model.count > 0
|
||||||
spacing: Style.current.padding
|
spacing: Style.current.padding
|
||||||
model: SortFilterProxyModel {
|
model: SortFilterProxyModel {
|
||||||
sourceModel: root.keypairSigningModel
|
sourceModel: root.keypairSigningModel
|
||||||
filters: ExpressionFilter {
|
filters: ExpressionFilter {
|
||||||
expression: !model.keyPair.migratedToKeycard
|
expression: model.keyPair.keyUid === userProfile.keyUid && !userProfile.isKeycardUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delegate: KeyPairItem {
|
delegate: KeyPairItem {
|
||||||
|
id: kpOnDeviceDelegate
|
||||||
width: ListView.view.width
|
width: ListView.view.width
|
||||||
sensor.hoverEnabled: false
|
sensor.hoverEnabled: false
|
||||||
additionalInfoForProfileKeypair: ""
|
additionalInfoForProfileKeypair: ""
|
||||||
|
@ -109,22 +128,80 @@ ColumnLayout {
|
||||||
keyPairImage: model.keyPair.image
|
keyPairImage: model.keyPair.image
|
||||||
keyPairDerivedFrom: model.keyPair.derivedFrom
|
keyPairDerivedFrom: model.keyPair.derivedFrom
|
||||||
keyPairAccounts: model.keyPair.accounts
|
keyPairAccounts: model.keyPair.accounts
|
||||||
|
|
||||||
|
components: [
|
||||||
|
StatusButton {
|
||||||
|
text: qsTr("Authenticate")
|
||||||
|
visible: !model.keyPair.ownershipVerified
|
||||||
|
icon.name: {
|
||||||
|
if (userProfile.usingBiometricLogin) {
|
||||||
|
return "touch-id"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userProfile.isKeycardUser) {
|
||||||
|
return "keycard"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "password"
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
StatusButton {
|
||||||
|
text: qsTr("Authenticated")
|
||||||
|
visible: model.keyPair.ownershipVerified
|
||||||
|
enabled: false
|
||||||
|
normalColor: "transparent"
|
||||||
|
disabledColor: "transparent"
|
||||||
|
disabledTextColor: Theme.palette.successColor1
|
||||||
|
icon.name: "checkmark-circle"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
running: model.keyPair.ownershipVerified
|
||||||
|
PropertyAnimation {
|
||||||
|
target: kpOnDeviceDelegate
|
||||||
|
property: "color"
|
||||||
|
to: Theme.palette.successColor3
|
||||||
|
duration: 500
|
||||||
|
}
|
||||||
|
PropertyAnimation {
|
||||||
|
target: kpOnDeviceDelegate
|
||||||
|
property: "color"
|
||||||
|
to: Theme.palette.baseColor2
|
||||||
|
duration: 1500
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
visible: regularKeypairs.visible && keycardKeypairs.visible
|
visible: nonKeycardProfileKeypair.visible
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: Style.current.xlPadding
|
Layout.preferredHeight: Style.current.xlPadding
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusBaseText {
|
RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
visible: keycardKeypairs.visible
|
visible: keycardKeypairs.visible
|
||||||
text: qsTr("Keypairs that need to be singed using appropriate Keycard")
|
|
||||||
font.pixelSize: Constants.keycard.general.fontSize2
|
StatusBaseText {
|
||||||
color: Theme.palette.baseColor1
|
text: qsTr("Stored on keycard")
|
||||||
wrapMode: Text.WordWrap
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusIcon {
|
||||||
|
Layout.preferredHeight: 20
|
||||||
|
Layout.preferredWidth: 20
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
icon: "keycard"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusListView {
|
StatusListView {
|
||||||
|
@ -140,6 +217,7 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delegate: KeyPairItem {
|
delegate: KeyPairItem {
|
||||||
|
id: kpOnKeycardDelegate
|
||||||
width: ListView.view.width
|
width: ListView.view.width
|
||||||
sensor.hoverEnabled: !model.keyPair.ownershipVerified
|
sensor.hoverEnabled: !model.keyPair.ownershipVerified
|
||||||
additionalInfoForProfileKeypair: ""
|
additionalInfoForProfileKeypair: ""
|
||||||
|
@ -153,28 +231,173 @@ ColumnLayout {
|
||||||
keyPairAccounts: model.keyPair.accounts
|
keyPairAccounts: model.keyPair.accounts
|
||||||
|
|
||||||
components: [
|
components: [
|
||||||
StatusBaseText {
|
StatusButton {
|
||||||
font.weight: Font.Medium
|
text: qsTr("Authenticate")
|
||||||
font.underline: mouseArea.containsMouse
|
visible: !model.keyPair.ownershipVerified
|
||||||
font.pixelSize: Theme.primaryTextFontSize
|
icon.name: "keycard"
|
||||||
color: model.keyPair.ownershipVerified? Theme.palette.baseColor1 : Theme.palette.primaryColor1
|
|
||||||
text: model.keyPair.ownershipVerified? qsTr("Signed") : qsTr("Sign")
|
onClicked: {
|
||||||
MouseArea {
|
if (model.keyPair.keyUid === userProfile.keyUid) {
|
||||||
id: mouseArea
|
root.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
anchors.fill: parent
|
return
|
||||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
||||||
hoverEnabled: !model.keyPair.ownershipVerified
|
|
||||||
enabled: !model.keyPair.ownershipVerified
|
|
||||||
onEnabledChanged: {
|
|
||||||
d.reEvaluateSignedKeypairs()
|
|
||||||
}
|
|
||||||
onClicked: {
|
|
||||||
root.signSharedAddressesForKeypair(model.keyPair.keyUid)
|
|
||||||
}
|
}
|
||||||
|
root.signSharedAddressesForKeypair(model.keyPair.keyUid)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
StatusButton {
|
||||||
|
text: qsTr("Authenticated")
|
||||||
|
visible: model.keyPair.ownershipVerified
|
||||||
|
enabled: false
|
||||||
|
normalColor: "transparent"
|
||||||
|
disabledColor: "transparent"
|
||||||
|
disabledTextColor: Theme.palette.successColor1
|
||||||
|
icon.name: "checkmark-circle"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
running: model.keyPair.ownershipVerified
|
||||||
|
PropertyAnimation {
|
||||||
|
target: kpOnKeycardDelegate
|
||||||
|
property: "color"
|
||||||
|
to: Theme.palette.successColor3
|
||||||
|
duration: 500
|
||||||
|
}
|
||||||
|
PropertyAnimation {
|
||||||
|
target: kpOnKeycardDelegate
|
||||||
|
property: "color"
|
||||||
|
to: Theme.palette.baseColor2
|
||||||
|
duration: 1500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
visible: keycardKeypairs.visible
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: Style.current.xlPadding
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 8
|
||||||
|
visible: nonProfileRegularKeypairs.visible
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
Layout.preferredWidth: !d.anyOfSelectedAddressesToRevealBelongToProfileKeypair &&
|
||||||
|
d.thereAreMoreThanOneNonProfileRegularKeypairs?
|
||||||
|
370
|
||||||
|
: -1
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: !d.anyOfSelectedAddressesToRevealBelongToProfileKeypair &&
|
||||||
|
d.thereAreMoreThanOneNonProfileRegularKeypairs?
|
||||||
|
qsTr("Authenticate via “%1” keypair").arg(userProfile.name)
|
||||||
|
: qsTr("The following keypairs will be authenticated via “%1” keypair").arg(userProfile.name)
|
||||||
|
font.pixelSize: Constants.keycard.general.fontSize2
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
wrapMode: Text.WrapAnywhere
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusButton {
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
text: qsTr("Authenticate")
|
||||||
|
visible: !d.anyOfSelectedAddressesToRevealBelongToProfileKeypair
|
||||||
|
&& d.thereAreMoreThanOneNonProfileRegularKeypairs
|
||||||
|
&& !d.allNonProfileRegularKeypairsSigned
|
||||||
|
icon.name: {
|
||||||
|
if (userProfile.usingBiometricLogin) {
|
||||||
|
return "touch-id"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userProfile.isKeycardUser) {
|
||||||
|
return "keycard"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "password"
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusListView {
|
||||||
|
id: nonProfileRegularKeypairs
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: nonProfileRegularKeypairs.contentHeight
|
||||||
|
visible: nonProfileRegularKeypairs.model.count > 0
|
||||||
|
spacing: Style.current.padding
|
||||||
|
model: SortFilterProxyModel {
|
||||||
|
sourceModel: root.keypairSigningModel
|
||||||
|
filters: ExpressionFilter {
|
||||||
|
expression: !model.keyPair.migratedToKeycard && model.keyPair.keyUid !== userProfile.keyUid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delegate: KeyPairItem {
|
||||||
|
id: dependantKpOnDeviceDelegate
|
||||||
|
width: ListView.view.width
|
||||||
|
sensor.hoverEnabled: false
|
||||||
|
additionalInfoForProfileKeypair: ""
|
||||||
|
|
||||||
|
keyPairType: model.keyPair.pairType
|
||||||
|
keyPairKeyUid: model.keyPair.keyUid
|
||||||
|
keyPairName: model.keyPair.name
|
||||||
|
keyPairIcon: model.keyPair.icon
|
||||||
|
keyPairImage: model.keyPair.image
|
||||||
|
keyPairDerivedFrom: model.keyPair.derivedFrom
|
||||||
|
keyPairAccounts: model.keyPair.accounts
|
||||||
|
|
||||||
|
components: [
|
||||||
|
StatusButton {
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
text: qsTr("Authenticate")
|
||||||
|
visible: !d.anyOfSelectedAddressesToRevealBelongToProfileKeypair
|
||||||
|
&& !d.thereAreMoreThanOneNonProfileRegularKeypairs
|
||||||
|
&& !model.keyPair.ownershipVerified
|
||||||
|
icon.name: {
|
||||||
|
if (userProfile.usingBiometricLogin) {
|
||||||
|
return "touch-id"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userProfile.isKeycardUser) {
|
||||||
|
return "keycard"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "password"
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
StatusButton {
|
||||||
|
text: qsTr("Authenticated")
|
||||||
|
visible: model.keyPair.ownershipVerified
|
||||||
|
enabled: false
|
||||||
|
normalColor: "transparent"
|
||||||
|
disabledColor: "transparent"
|
||||||
|
disabledTextColor: Theme.palette.successColor1
|
||||||
|
icon.name: "checkmark-circle"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
running: model.keyPair.ownershipVerified
|
||||||
|
PropertyAnimation {
|
||||||
|
target: dependantKpOnDeviceDelegate
|
||||||
|
property: "color"
|
||||||
|
to: Theme.palette.successColor3
|
||||||
|
duration: 500
|
||||||
|
}
|
||||||
|
PropertyAnimation {
|
||||||
|
target: dependantKpOnDeviceDelegate
|
||||||
|
property: "color"
|
||||||
|
to: Theme.palette.baseColor2
|
||||||
|
duration: 1500
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,12 @@ import AppLayouts.Communities.panels 1.0
|
||||||
|
|
||||||
import utils 1.0
|
import utils 1.0
|
||||||
|
|
||||||
|
/****************************************************
|
||||||
|
This file is not in use any more.
|
||||||
|
|
||||||
|
TODO: remove it
|
||||||
|
****************************************************/
|
||||||
|
|
||||||
StatusDialog {
|
StatusDialog {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
@ -35,7 +41,7 @@ StatusDialog {
|
||||||
|
|
||||||
signal prepareForSigning(string airdropAddress, var sharedAddresses)
|
signal prepareForSigning(string airdropAddress, var sharedAddresses)
|
||||||
signal editRevealedAddresses()
|
signal editRevealedAddresses()
|
||||||
signal signSharedAddressesForAllNonKeycardKeypairs()
|
signal signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
signal signSharedAddressesForKeypair(string keyUid)
|
signal signSharedAddressesForKeypair(string keyUid)
|
||||||
|
|
||||||
function setOldSharedAddresses(oldSharedAddresses) {
|
function setOldSharedAddresses(oldSharedAddresses) {
|
||||||
|
@ -71,6 +77,8 @@ StatusDialog {
|
||||||
property var oldSharedAddresses
|
property var oldSharedAddresses
|
||||||
property string oldAirdropAddress
|
property string oldAirdropAddress
|
||||||
|
|
||||||
|
property int selectedSharedAddressesCount
|
||||||
|
|
||||||
property var selectAddressesPanelButtons: ObjectModel {}
|
property var selectAddressesPanelButtons: ObjectModel {}
|
||||||
readonly property var signingPanelButtons: ObjectModel {
|
readonly property var signingPanelButtons: ObjectModel {
|
||||||
StatusFlatButton {
|
StatusFlatButton {
|
||||||
|
@ -136,6 +144,7 @@ StatusDialog {
|
||||||
d.displaySigningPanel = true
|
d.displaySigningPanel = true
|
||||||
}
|
}
|
||||||
onSharedAddressesChanged: {
|
onSharedAddressesChanged: {
|
||||||
|
d.selectedSharedAddressesCount = sharedAddresses.length
|
||||||
root.sharedAddressesChanged(airdropAddress, sharedAddresses)
|
root.sharedAddressesChanged(airdropAddress, sharedAddresses)
|
||||||
}
|
}
|
||||||
onClose: root.close()
|
onClose: root.close()
|
||||||
|
@ -147,12 +156,16 @@ StatusDialog {
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: sharedAddressesSigningPanelComponent
|
id: sharedAddressesSigningPanelComponent
|
||||||
SharedAddressesSigningPanel {
|
SharedAddressesSigningPanel {
|
||||||
|
|
||||||
|
totalNumOfAddressesForSharing: root.walletAccountsModel.count
|
||||||
|
numOfSelectedAddressesForSharing: d.selectedSharedAddressesCount
|
||||||
|
|
||||||
|
communityName: root.communityName
|
||||||
keypairSigningModel: root.keypairSigningModel
|
keypairSigningModel: root.keypairSigningModel
|
||||||
|
|
||||||
onSignSharedAddressesForAllNonKeycardKeypairs: {
|
onSignProfileKeypairAndAllNonKeycardKeypairs: {
|
||||||
root.signSharedAddressesForAllNonKeycardKeypairs()
|
root.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignSharedAddressesForKeypair: {
|
onSignSharedAddressesForKeypair: {
|
||||||
|
|
|
@ -536,12 +536,14 @@ Item {
|
||||||
|
|
||||||
isInvitationPending: d.invitationPending
|
isInvitationPending: d.invitationPending
|
||||||
requirementsCheckPending: root.store.requirementsCheckPending
|
requirementsCheckPending: root.store.requirementsCheckPending
|
||||||
name: communityData.name
|
communityName: communityData.name
|
||||||
introMessage: communityData.introMessage
|
introMessage: communityData.introMessage
|
||||||
imageSrc: communityData.image
|
communityIcon: communityData.image
|
||||||
accessType: communityData.access
|
accessType: communityData.access
|
||||||
loginType: root.store.loginType
|
|
||||||
walletAccountsModel: WalletStore.RootStore.nonWatchAccounts
|
walletAccountsModel: WalletStore.RootStore.nonWatchAccounts
|
||||||
|
canProfileProveOwnershipOfProvidedAddressesFn: WalletStore.RootStore.canProfileProveOwnershipOfProvidedAddresses
|
||||||
|
|
||||||
walletAssetsModel: walletAssetsStore.groupedAccountAssetsModel
|
walletAssetsModel: walletAssetsStore.groupedAccountAssetsModel
|
||||||
permissionsModel: {
|
permissionsModel: {
|
||||||
root.store.prepareTokenModelForCommunity(communityData.id)
|
root.store.prepareTokenModelForCommunity(communityData.id)
|
||||||
|
@ -560,8 +562,8 @@ Item {
|
||||||
communityIntroDialog.keypairSigningModel = root.store.communitiesModuleInst.keypairsSigningModel
|
communityIntroDialog.keypairSigningModel = root.store.communitiesModuleInst.keypairsSigningModel
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignSharedAddressesForAllNonKeycardKeypairs: {
|
onSignProfileKeypairAndAllNonKeycardKeypairs: {
|
||||||
root.store.signSharedAddressesForAllNonKeycardKeypairs()
|
root.store.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignSharedAddressesForKeypair: {
|
onSignSharedAddressesForKeypair: {
|
||||||
|
@ -589,9 +591,21 @@ Item {
|
||||||
Connections {
|
Connections {
|
||||||
target: root.store.communitiesModuleInst
|
target: root.store.communitiesModuleInst
|
||||||
|
|
||||||
function onSharedAddressesForAllNonKeycardKeypairsSigned() {
|
function onAllSharedAddressesSigned() {
|
||||||
|
if (communityIntroDialog.profileProvesOwnershipOfSelectedAddresses) {
|
||||||
|
communityIntroDialog.joinCommunity()
|
||||||
|
communityIntroDialog.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (communityIntroDialog.allAddressesToRevealBelongToSingleNonProfileKeypair) {
|
||||||
|
communityIntroDialog.joinCommunity()
|
||||||
|
communityIntroDialog.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!!communityIntroDialog.replaceItem) {
|
if (!!communityIntroDialog.replaceItem) {
|
||||||
communityIntroDialog.replaceLoader.item.sharedAddressesForAllNonKeycardKeypairsSigned()
|
communityIntroDialog.replaceLoader.item.allSigned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,9 +211,9 @@ SettingsContentBase {
|
||||||
Global.openPopup(communityIntroDialogPopup, {
|
Global.openPopup(communityIntroDialogPopup, {
|
||||||
communityId: communityId,
|
communityId: communityId,
|
||||||
isInvitationPending: root.rootStore.isMyCommunityRequestPending(communityId),
|
isInvitationPending: root.rootStore.isMyCommunityRequestPending(communityId),
|
||||||
name: name,
|
communityName: name,
|
||||||
introMessage: introMessage,
|
introMessage: introMessage,
|
||||||
imageSrc: imageSrc,
|
communityIcon: imageSrc,
|
||||||
accessType: accessType
|
accessType: accessType
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -236,8 +236,9 @@ SettingsContentBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loginType: chatStore.loginType
|
|
||||||
walletAccountsModel: WalletStore.RootStore.nonWatchAccounts
|
walletAccountsModel: WalletStore.RootStore.nonWatchAccounts
|
||||||
|
canProfileProveOwnershipOfProvidedAddressesFn: WalletStore.RootStore.canProfileProveOwnershipOfProvidedAddresses
|
||||||
|
|
||||||
walletAssetsModel: walletAssetsStore.groupedAccountAssetsModel
|
walletAssetsModel: walletAssetsStore.groupedAccountAssetsModel
|
||||||
requirementsCheckPending: root.rootStore.requirementsCheckPending
|
requirementsCheckPending: root.rootStore.requirementsCheckPending
|
||||||
permissionsModel: {
|
permissionsModel: {
|
||||||
|
@ -257,8 +258,8 @@ SettingsContentBase {
|
||||||
communityIntroDialog.keypairSigningModel = chatStore.communitiesModuleInst.keypairsSigningModel
|
communityIntroDialog.keypairSigningModel = chatStore.communitiesModuleInst.keypairsSigningModel
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignSharedAddressesForAllNonKeycardKeypairs: {
|
onSignProfileKeypairAndAllNonKeycardKeypairs: {
|
||||||
chatStore.signSharedAddressesForAllNonKeycardKeypairs()
|
chatStore.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignSharedAddressesForKeypair: {
|
onSignSharedAddressesForKeypair: {
|
||||||
|
@ -280,9 +281,21 @@ SettingsContentBase {
|
||||||
Connections {
|
Connections {
|
||||||
target: chatStore.communitiesModuleInst
|
target: chatStore.communitiesModuleInst
|
||||||
|
|
||||||
function onSharedAddressesForAllNonKeycardKeypairsSigned() {
|
function onAllSharedAddressesSigned() {
|
||||||
|
if (communityIntroDialog.profileProvesOwnershipOfSelectedAddresses) {
|
||||||
|
communityIntroDialog.joinCommunity()
|
||||||
|
communityIntroDialog.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (communityIntroDialog.allAddressesToRevealBelongToSingleNonProfileKeypair) {
|
||||||
|
communityIntroDialog.joinCommunity()
|
||||||
|
communityIntroDialog.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!!communityIntroDialog.replaceItem) {
|
if (!!communityIntroDialog.replaceItem) {
|
||||||
communityIntroDialog.replaceLoader.item.sharedAddressesForAllNonKeycardKeypairsSigned()
|
communityIntroDialog.replaceLoader.item.allSigned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,6 +209,10 @@ QtObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function canProfileProveOwnershipOfProvidedAddresses(addresses) {
|
||||||
|
return walletSection.canProfileProveOwnershipOfProvidedAddresses(JSON.stringify(addresses))
|
||||||
|
}
|
||||||
|
|
||||||
function setHideSignPhraseModal(value) {
|
function setHideSignPhraseModal(value) {
|
||||||
localAccountSensitiveSettings.hideSignPhraseModal = value;
|
localAccountSensitiveSettings.hideSignPhraseModal = value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,8 +241,8 @@ QtObject {
|
||||||
communitiesModuleInst.prepareKeypairsForSigning(communityId, ensName, JSON.stringify(addressesToShare), airdropAddress, editMode)
|
communitiesModuleInst.prepareKeypairsForSigning(communityId, ensName, JSON.stringify(addressesToShare), airdropAddress, editMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
function signSharedAddressesForAllNonKeycardKeypairs() {
|
function signProfileKeypairAndAllNonKeycardKeypairs() {
|
||||||
communitiesModuleInst.signSharedAddressesForAllNonKeycardKeypairs()
|
communitiesModuleInst.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
}
|
}
|
||||||
|
|
||||||
function signSharedAddressesForKeypair(keyUid) {
|
function signSharedAddressesForKeypair(keyUid) {
|
||||||
|
|
|
@ -263,9 +263,9 @@ QtObject {
|
||||||
imageSrc, accessType, isInvitationPending) {
|
imageSrc, accessType, isInvitationPending) {
|
||||||
openPopup(communityIntroDialogPopup,
|
openPopup(communityIntroDialogPopup,
|
||||||
{communityId: communityId,
|
{communityId: communityId,
|
||||||
name: name,
|
communityName: name,
|
||||||
introMessage: introMessage,
|
introMessage: introMessage,
|
||||||
imageSrc: imageSrc,
|
communityIcon: imageSrc,
|
||||||
accessType: accessType,
|
accessType: accessType,
|
||||||
isInvitationPending: isInvitationPending
|
isInvitationPending: isInvitationPending
|
||||||
})
|
})
|
||||||
|
@ -275,9 +275,9 @@ QtObject {
|
||||||
openPopup(communityIntroDialogPopup,
|
openPopup(communityIntroDialogPopup,
|
||||||
{communityId: communityId,
|
{communityId: communityId,
|
||||||
stackTitle: qsTr("Share addresses with %1's owner").arg(name),
|
stackTitle: qsTr("Share addresses with %1's owner").arg(name),
|
||||||
name: name,
|
communityName: name,
|
||||||
introMessage: qsTr("Share addresses to rejoin %1").arg(name),
|
introMessage: qsTr("Share addresses to rejoin %1").arg(name),
|
||||||
imageSrc: imageSrc,
|
communityIcon: imageSrc,
|
||||||
accessType: Constants.communityChatOnRequestAccess,
|
accessType: Constants.communityChatOnRequestAccess,
|
||||||
isInvitationPending: false
|
isInvitationPending: false
|
||||||
})
|
})
|
||||||
|
@ -682,9 +682,12 @@ QtObject {
|
||||||
CommunityIntroDialog {
|
CommunityIntroDialog {
|
||||||
id: communityIntroDialog
|
id: communityIntroDialog
|
||||||
property string communityId
|
property string communityId
|
||||||
loginType: root.rootStore.loginType
|
|
||||||
requirementsCheckPending: root.rootStore.requirementsCheckPending
|
requirementsCheckPending: root.rootStore.requirementsCheckPending
|
||||||
|
|
||||||
walletAccountsModel: root.rootStore.walletAccountsModel
|
walletAccountsModel: root.rootStore.walletAccountsModel
|
||||||
|
canProfileProveOwnershipOfProvidedAddressesFn: WalletStore.RootStore.canProfileProveOwnershipOfProvidedAddresses
|
||||||
|
|
||||||
walletAssetsModel: walletAssetsStore.groupedAccountAssetsModel
|
walletAssetsModel: walletAssetsStore.groupedAccountAssetsModel
|
||||||
permissionsModel: {
|
permissionsModel: {
|
||||||
root.rootStore.prepareTokenModelForCommunity(communityIntroDialog.communityId)
|
root.rootStore.prepareTokenModelForCommunity(communityIntroDialog.communityId)
|
||||||
|
@ -703,8 +706,8 @@ QtObject {
|
||||||
communityIntroDialog.keypairSigningModel = root.rootStore.communitiesModuleInst.keypairsSigningModel
|
communityIntroDialog.keypairSigningModel = root.rootStore.communitiesModuleInst.keypairsSigningModel
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignSharedAddressesForAllNonKeycardKeypairs: {
|
onSignProfileKeypairAndAllNonKeycardKeypairs: {
|
||||||
root.rootStore.signSharedAddressesForAllNonKeycardKeypairs()
|
root.rootStore.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignSharedAddressesForKeypair: {
|
onSignSharedAddressesForKeypair: {
|
||||||
|
@ -739,9 +742,21 @@ QtObject {
|
||||||
Connections {
|
Connections {
|
||||||
target: root.rootStore.communitiesModuleInst
|
target: root.rootStore.communitiesModuleInst
|
||||||
|
|
||||||
function onSharedAddressesForAllNonKeycardKeypairsSigned() {
|
function onAllSharedAddressesSigned() {
|
||||||
|
if (communityIntroDialog.profileProvesOwnershipOfSelectedAddresses) {
|
||||||
|
communityIntroDialog.joinCommunity()
|
||||||
|
communityIntroDialog.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (communityIntroDialog.allAddressesToRevealBelongToSingleNonProfileKeypair) {
|
||||||
|
communityIntroDialog.joinCommunity()
|
||||||
|
communityIntroDialog.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!!communityIntroDialog.replaceItem) {
|
if (!!communityIntroDialog.replaceItem) {
|
||||||
communityIntroDialog.replaceLoader.item.sharedAddressesForAllNonKeycardKeypairsSigned()
|
communityIntroDialog.replaceLoader.item.allSigned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -886,24 +901,9 @@ QtObject {
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: editSharedAddressesPopupComponent
|
id: editSharedAddressesPopupComponent
|
||||||
SharedAddressesPopup {
|
CommunityIntroDialog {
|
||||||
id: editSharedAddressesPopup
|
id: editSharedAddressesPopup
|
||||||
|
|
||||||
readonly property var oldSharedAddresses: root.rootStore.myRevealedAddressesForCurrentCommunity
|
|
||||||
readonly property string oldAirdropAddress: root.rootStore.myRevealedAirdropAddressForCurrentCommunity
|
|
||||||
|
|
||||||
onOldSharedAddressesChanged: {
|
|
||||||
editSharedAddressesPopup.setOldSharedAddresses(
|
|
||||||
editSharedAddressesPopup.oldSharedAddresses
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
onOldAirdropAddressChanged: {
|
|
||||||
editSharedAddressesPopup.setOldAirdropAddress(
|
|
||||||
editSharedAddressesPopup.oldAirdropAddress
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
property string communityId
|
property string communityId
|
||||||
|
|
||||||
readonly property var chatStore: ChatStore.RootStore {
|
readonly property var chatStore: ChatStore.RootStore {
|
||||||
|
@ -914,10 +914,17 @@ QtObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isEditMode: true
|
||||||
|
|
||||||
|
currentSharedAddresses: root.rootStore.myRevealedAddressesForCurrentCommunity
|
||||||
|
currentAirdropAddress: root.rootStore.myRevealedAirdropAddressForCurrentCommunity
|
||||||
|
|
||||||
communityName: chatStore.sectionDetails.name
|
communityName: chatStore.sectionDetails.name
|
||||||
communityIcon: chatStore.sectionDetails.image
|
communityIcon: chatStore.sectionDetails.image
|
||||||
requirementsCheckPending: root.rootStore.requirementsCheckPending
|
requirementsCheckPending: root.rootStore.requirementsCheckPending
|
||||||
loginType: chatStore.loginType
|
|
||||||
|
canProfileProveOwnershipOfProvidedAddressesFn: WalletStore.RootStore.canProfileProveOwnershipOfProvidedAddresses
|
||||||
|
|
||||||
walletAccountsModel: root.rootStore.walletAccountsModel
|
walletAccountsModel: root.rootStore.walletAccountsModel
|
||||||
walletAssetsModel: walletAssetsStore.groupedAccountAssetsModel
|
walletAssetsModel: walletAssetsStore.groupedAccountAssetsModel
|
||||||
permissionsModel: {
|
permissionsModel: {
|
||||||
|
@ -927,16 +934,22 @@ QtObject {
|
||||||
assetsModel: chatStore.assetsModel
|
assetsModel: chatStore.assetsModel
|
||||||
collectiblesModel: chatStore.collectiblesModel
|
collectiblesModel: chatStore.collectiblesModel
|
||||||
|
|
||||||
onSharedAddressesChanged: root.rootStore.updatePermissionsModel(
|
getCurrencyAmount: function (balance, symbol) {
|
||||||
editSharedAddressesPopup.communityId, sharedAddresses)
|
return root.currencyStore.getCurrencyAmount(balance, symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
onSharedAddressesUpdated: {
|
||||||
|
root.rootStore.updatePermissionsModel(editSharedAddressesPopup.communityId, sharedAddresses)
|
||||||
|
}
|
||||||
|
|
||||||
onPrepareForSigning: {
|
onPrepareForSigning: {
|
||||||
root.rootStore.prepareKeypairsForSigning(editSharedAddressesPopup.communityId, "", sharedAddresses, airdropAddress, true)
|
root.rootStore.prepareKeypairsForSigning(editSharedAddressesPopup.communityId, "", sharedAddresses, airdropAddress, true)
|
||||||
|
|
||||||
editSharedAddressesPopup.keypairSigningModel = root.rootStore.communitiesModuleInst.keypairsSigningModel
|
editSharedAddressesPopup.keypairSigningModel = root.rootStore.communitiesModuleInst.keypairsSigningModel
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignSharedAddressesForAllNonKeycardKeypairs: {
|
onSignProfileKeypairAndAllNonKeycardKeypairs: {
|
||||||
root.rootStore.signSharedAddressesForAllNonKeycardKeypairs()
|
root.rootStore.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignSharedAddressesForKeypair: {
|
onSignSharedAddressesForKeypair: {
|
||||||
|
@ -952,13 +965,23 @@ QtObject {
|
||||||
Connections {
|
Connections {
|
||||||
target: root.rootStore.communitiesModuleInst
|
target: root.rootStore.communitiesModuleInst
|
||||||
|
|
||||||
function onSharedAddressesForAllNonKeycardKeypairsSigned() {
|
function onAllSharedAddressesSigned() {
|
||||||
editSharedAddressesPopup.sharedAddressesForAllNonKeycardKeypairsSigned()
|
if (editSharedAddressesPopup.profileProvesOwnershipOfSelectedAddresses) {
|
||||||
}
|
editSharedAddressesPopup.editRevealedAddresses()
|
||||||
}
|
editSharedAddressesPopup.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
getCurrencyAmount: function (balance, symbol) {
|
if (editSharedAddressesPopup.allAddressesToRevealBelongToSingleNonProfileKeypair) {
|
||||||
return root.currencyStore.getCurrencyAmount(balance, symbol)
|
editSharedAddressesPopup.editRevealedAddresses()
|
||||||
|
editSharedAddressesPopup.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!editSharedAddressesPopup.replaceItem) {
|
||||||
|
editSharedAddressesPopup.replaceLoader.item.allSigned()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,48 +18,98 @@ import SortFilterProxyModel 0.2
|
||||||
StatusStackModal {
|
StatusStackModal {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string name
|
property bool isEditMode: false
|
||||||
|
|
||||||
|
required property string communityName
|
||||||
|
required property string communityIcon
|
||||||
|
required property bool requirementsCheckPending
|
||||||
|
|
||||||
property string introMessage
|
property string introMessage
|
||||||
property int accessType
|
property int accessType
|
||||||
property url imageSrc
|
|
||||||
property bool isInvitationPending: false
|
property bool isInvitationPending: false
|
||||||
property int loginType: Constants.LoginType.Password
|
|
||||||
|
|
||||||
required property var walletAccountsModel // name, address, emoji, colorId
|
required property var walletAccountsModel // name, address, emoji, colorId
|
||||||
property var walletAssetsModel
|
required property var walletAssetsModel
|
||||||
required property var permissionsModel // id, key, permissionType, holdingsListModel, channelsListModel, isPrivate, tokenCriteriaMet
|
required property var permissionsModel // id, key, permissionType, holdingsListModel, channelsListModel, isPrivate, tokenCriteriaMet
|
||||||
required property var assetsModel
|
required property var assetsModel
|
||||||
required property var collectiblesModel
|
required property var collectiblesModel
|
||||||
|
|
||||||
required property bool requirementsCheckPending
|
|
||||||
|
|
||||||
property var keypairSigningModel
|
property var keypairSigningModel
|
||||||
|
|
||||||
|
property var currentSharedAddresses: []
|
||||||
|
onCurrentSharedAddressesChanged: d.reEvaluateModels()
|
||||||
|
property string currentAirdropAddress: ""
|
||||||
|
onCurrentAirdropAddressChanged: d.reEvaluateModels()
|
||||||
|
|
||||||
property var getCurrencyAmount: function (balance, symbol){}
|
property var getCurrencyAmount: function (balance, symbol){}
|
||||||
|
|
||||||
|
property var canProfileProveOwnershipOfProvidedAddressesFn: function(addresses) { return false }
|
||||||
|
|
||||||
|
readonly property bool profileProvesOwnershipOfSelectedAddresses: {
|
||||||
|
d.selectedSharedAddressesMap // needed for binding
|
||||||
|
const obj = d.getSelectedAddresses()
|
||||||
|
return root.canProfileProveOwnershipOfProvidedAddressesFn(obj.addresses)
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property bool allAddressesToRevealBelongToSingleNonProfileKeypair: {
|
||||||
|
const keyUids = new Set()
|
||||||
|
for (const [key, value] of d.selectedSharedAddressesMap) {
|
||||||
|
keyUids.add(value.keyUid)
|
||||||
|
}
|
||||||
|
return keyUids.size === 1 && !keyUids.has(userProfile.keyUid)
|
||||||
|
}
|
||||||
|
|
||||||
signal prepareForSigning(string airdropAddress, var sharedAddresses)
|
signal prepareForSigning(string airdropAddress, var sharedAddresses)
|
||||||
signal joinCommunity()
|
signal joinCommunity()
|
||||||
signal signSharedAddressesForAllNonKeycardKeypairs()
|
signal editRevealedAddresses()
|
||||||
|
signal signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
signal signSharedAddressesForKeypair(string keyUid)
|
signal signSharedAddressesForKeypair(string keyUid)
|
||||||
signal cancelMembershipRequest()
|
signal cancelMembershipRequest()
|
||||||
signal sharedAddressesUpdated(var sharedAddresses)
|
signal sharedAddressesUpdated(var sharedAddresses)
|
||||||
|
|
||||||
width: 640 // by design
|
width: 640 // by design
|
||||||
padding: 0
|
padding: 0
|
||||||
stackTitle: root.accessType === Constants.communityChatOnRequestAccess ? qsTr("Request to join %1").arg(name) : qsTr("Welcome to %1").arg(name)
|
stackTitle: root.accessType === Constants.communityChatOnRequestAccess ?
|
||||||
|
qsTr("Request to join %1").arg(root.communityName)
|
||||||
|
: qsTr("Welcome to %1").arg(root.communityName)
|
||||||
|
|
||||||
rightButtons: [d.shareButton, finishButton]
|
rightButtons: [d.shareButton, finishButton]
|
||||||
|
|
||||||
finishButton: StatusButton {
|
finishButton: StatusButton {
|
||||||
text: root.isInvitationPending ?
|
text: {
|
||||||
qsTr("Cancel Membership Request")
|
if (root.isInvitationPending) {
|
||||||
: root.accessType === Constants.communityChatOnRequestAccess?
|
return qsTr("Cancel Membership Request")
|
||||||
qsTr("Prove ownership")
|
} else if (root.accessType === Constants.communityChatOnRequestAccess) {
|
||||||
: qsTr("Join %1").arg(root.name)
|
if (d.selectedSharedAddressesCount === d.totalNumOfAddressesForSharing) {
|
||||||
|
return qsTr("Share all addresses to join")
|
||||||
|
}
|
||||||
|
return qsTr("Share %n address(s) to join", "", d.selectedSharedAddressesCount)
|
||||||
|
}
|
||||||
|
return qsTr("Join %1").arg(root.communityName)
|
||||||
|
}
|
||||||
type: root.isInvitationPending ? StatusBaseButton.Type.Danger
|
type: root.isInvitationPending ? StatusBaseButton.Type.Danger
|
||||||
: StatusBaseButton.Type.Normal
|
: StatusBaseButton.Type.Normal
|
||||||
|
|
||||||
|
icon.name: {
|
||||||
|
if (root.profileProvesOwnershipOfSelectedAddresses) {
|
||||||
|
if (userProfile.usingBiometricLogin) {
|
||||||
|
return "touch-id"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userProfile.isKeycardUser) {
|
||||||
|
return "keycard"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "password"
|
||||||
|
}
|
||||||
|
if (root.allAddressesToRevealBelongToSingleNonProfileKeypair) {
|
||||||
|
return "keycard"
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (root.isInvitationPending) {
|
if (root.isInvitationPending) {
|
||||||
root.cancelMembershipRequest()
|
root.cancelMembershipRequest()
|
||||||
|
@ -67,15 +117,48 @@ StatusStackModal {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
root.prepareForSigning(d.selectedAirdropAddress, d.selectedSharedAddresses)
|
d.proceedToSigningOrSubmitRequest(d.communityIntroUid)
|
||||||
root.replace(sharedAddressesSigningPanelComponent)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
backButton: StatusBackButton {
|
||||||
|
visible: !!root.replaceLoader.item
|
||||||
|
&& !(root.replaceLoader.item.componentUid === d.shareAddressesUid && root.isEditMode)
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (d.backActionGoesTo === d.communityIntroUid) {
|
||||||
|
if (root.replaceItem) {
|
||||||
|
root.replaceItem = undefined
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d.backActionGoesTo === d.shareAddressesUid) {
|
||||||
|
d.backActionGoesTo = d.communityIntroUid
|
||||||
|
root.replace(sharedAddressesPanelComponent)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.minimumWidth: implicitWidth
|
||||||
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
|
|
||||||
readonly property var tempAddressesModel: SortFilterProxyModel {
|
readonly property string communityIntroUid: "community-intro"
|
||||||
|
readonly property string shareAddressesUid: "shared-addresses"
|
||||||
|
readonly property string signingPanelUid: "signing-panel"
|
||||||
|
property string backActionGoesTo: d.communityIntroUid
|
||||||
|
|
||||||
|
readonly property int totalNumOfAddressesForSharing: root.walletAccountsModel.count
|
||||||
|
|
||||||
|
property var currentSharedAddressesMap: new Map() // Map[address, [keyUid, selected, isAirdrop]] - used in edit mode only
|
||||||
|
property var selectedSharedAddressesMap: new Map() // Map[address, [keyUid, selected, isAirdrop]]
|
||||||
|
readonly property int selectedSharedAddressesCount: d.selectedSharedAddressesMap.size
|
||||||
|
|
||||||
|
property var initialAddressesModel: SortFilterProxyModel {
|
||||||
sourceModel: root.walletAccountsModel
|
sourceModel: root.walletAccountsModel
|
||||||
sorters: [
|
sorters: [
|
||||||
ExpressionSorter {
|
ExpressionSorter {
|
||||||
|
@ -96,58 +179,188 @@ StatusStackModal {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
// all non-watched addresses by default, unless selected otherwise below in SharedAddressesPanel
|
function proceedToSigningOrSubmitRequest(uidOfComponentThisFunctionIsCalledFrom) {
|
||||||
property var selectedSharedAddresses: tempAddressesModel.count ? ModelUtils.modelToFlatArray(tempAddressesModel, "address") : []
|
const selected = d.getSelectedAddresses()
|
||||||
property string selectedAirdropAddress: selectedSharedAddresses.length ? selectedSharedAddresses[0] : ""
|
root.prepareForSigning(selected.airdropAddress, selected.addresses)
|
||||||
|
if (root.profileProvesOwnershipOfSelectedAddresses) {
|
||||||
|
root.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (root.allAddressesToRevealBelongToSingleNonProfileKeypair) {
|
||||||
|
if (d.selectedSharedAddressesMap.size === 0) {
|
||||||
|
console.error("selected shared addresses must not be empty")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const keyUid = d.selectedSharedAddressesMap.values()[0].keyUid
|
||||||
|
root.signSharedAddressesForKeypair(keyUid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
d.backActionGoesTo = uidOfComponentThisFunctionIsCalledFrom
|
||||||
|
root.replace(sharedAddressesSigningPanelComponent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function deletes/adds it the address from/to the map.
|
||||||
|
function toggleAddressSelection(keyUid, address) {
|
||||||
|
const tmpMap = d.selectedSharedAddressesMap
|
||||||
|
|
||||||
|
const lAddress = address.toLowerCase()
|
||||||
|
const obj = tmpMap.get(lAddress)
|
||||||
|
if (!!obj) {
|
||||||
|
if (tmpMap.size === 1) {
|
||||||
|
console.error("cannot remove the last selected address")
|
||||||
|
}
|
||||||
|
tmpMap.delete(lAddress)
|
||||||
|
if (obj.isAirdrop) {
|
||||||
|
d.selectAirdropAddressForTheFirstSelectedAddress()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tmpMap.set(lAddress, {keyUid: keyUid, selected: true, isAirdrop: false})
|
||||||
|
}
|
||||||
|
|
||||||
|
d.selectedSharedAddressesMap = tmpMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function selects new airdrop address, invalidating old airdrop address selection.
|
||||||
|
function selectAirdropAddressForTheFirstSelectedAddress() {
|
||||||
|
const tmpMap = d.selectedSharedAddressesMap
|
||||||
|
|
||||||
|
// clear previous airdrop address
|
||||||
|
for (const [key, value] of tmpMap) {
|
||||||
|
if (!value.isAirdrop) {
|
||||||
|
d.selectedSharedAddressesMap.set(key, {keyUid: value.keyUid, selected: value.selected, isAirdrop: true})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.selectedSharedAddressesMap = tmpMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function selects new airdrop address, invalidating old airdrop address selection.
|
||||||
|
function selectAirdropAddress(address) {
|
||||||
|
const tmpMap = d.selectedSharedAddressesMap
|
||||||
|
|
||||||
|
// clear previous airdrop address
|
||||||
|
for (const [key, value] of tmpMap) {
|
||||||
|
if (value.isAirdrop) {
|
||||||
|
tmpMap.set(key, {keyUid: value.keyUid, selected: value.selected, isAirdrop: false})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set new airdrop address
|
||||||
|
const lAddress = address.toLowerCase()
|
||||||
|
const obj = tmpMap.get(lAddress)
|
||||||
|
if (!obj) {
|
||||||
|
console.error("cannot set airdrop address for unselected address")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
obj.isAirdrop = true
|
||||||
|
tmpMap.set(lAddress, obj)
|
||||||
|
|
||||||
|
d.selectedSharedAddressesMap = tmpMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an object containing all selected addresses and selected airdrop address.s
|
||||||
|
function getSelectedAddresses() {
|
||||||
|
const result = {addresses: [], airdropAddress: ""}
|
||||||
|
for (const [key, value] of d.selectedSharedAddressesMap) {
|
||||||
|
if (value.selected) {
|
||||||
|
result.addresses.push(key)
|
||||||
|
}
|
||||||
|
if (value.isAirdrop) {
|
||||||
|
result.airdropAddress = key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
function reEvaluateModels() {
|
||||||
|
const tmpSharedAddressesMap = new Map()
|
||||||
|
const tmpCurrentSharedAddressesMap = new Map()
|
||||||
|
for (let i=0; i < d.initialAddressesModel.count; ++i){
|
||||||
|
const obj = d.initialAddressesModel.get(i)
|
||||||
|
if (!!obj) {
|
||||||
|
let isAirdrop = i === 0
|
||||||
|
if (root.isEditMode) {
|
||||||
|
if (root.currentSharedAddresses.indexOf(obj.address) === -1) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
isAirdrop = obj.address.toLowerCase() === root.currentAirdropAddress.toLowerCase()
|
||||||
|
}
|
||||||
|
tmpSharedAddressesMap.set(obj.address, {keyUid: obj.keyUid, selected: true, isAirdrop: isAirdrop})
|
||||||
|
tmpCurrentSharedAddressesMap.set(obj.address, {keyUid: obj.keyUid, selected: true, isAirdrop: isAirdrop})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.selectedSharedAddressesMap = tmpSharedAddressesMap
|
||||||
|
if (root.isEditMode) {
|
||||||
|
d.currentSharedAddressesMap = new Map(tmpCurrentSharedAddressesMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly property var shareButton: StatusFlatButton {
|
readonly property var shareButton: StatusFlatButton {
|
||||||
height: finishButton.height
|
height: finishButton.height
|
||||||
visible: !root.isInvitationPending && !root.replaceItem
|
visible: !root.isInvitationPending && !root.replaceItem
|
||||||
borderColor: Theme.palette.baseColor2
|
borderColor: "transparent"
|
||||||
text: qsTr("Select addresses to share")
|
text: qsTr("Select addresses to share")
|
||||||
onClicked: root.replace(sharedAddressesPanelComponent)
|
onClicked: {
|
||||||
|
d.backActionGoesTo = d.communityIntroUid
|
||||||
|
root.replace(sharedAddressesPanelComponent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
d.reEvaluateModels()
|
||||||
|
|
||||||
|
if (root.isEditMode) {
|
||||||
|
d.backActionGoesTo = d.shareAddressesUid
|
||||||
|
root.replace(sharedAddressesPanelComponent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: sharedAddressesPanelComponent
|
id: sharedAddressesPanelComponent
|
||||||
SharedAddressesPanel {
|
SharedAddressesPanel {
|
||||||
communityName: root.name
|
componentUid: d.shareAddressesUid
|
||||||
communityIcon: root.imageSrc
|
isEditMode: root.isEditMode
|
||||||
loginType: root.loginType
|
communityName: root.communityName
|
||||||
|
communityIcon: root.communityIcon
|
||||||
requirementsCheckPending: root.requirementsCheckPending
|
requirementsCheckPending: root.requirementsCheckPending
|
||||||
walletAccountsModel: SortFilterProxyModel {
|
|
||||||
sourceModel: root.walletAccountsModel
|
|
||||||
sorters: [
|
|
||||||
ExpressionSorter {
|
|
||||||
function isGenerated(modelData) {
|
|
||||||
return modelData.walletType === Constants.generatedWalletType
|
|
||||||
}
|
|
||||||
|
|
||||||
expression: {
|
walletAccountsModel: d.initialAddressesModel
|
||||||
return isGenerated(modelLeft)
|
selectedSharedAddressesMap: d.selectedSharedAddressesMap
|
||||||
}
|
currentSharedAddressesMap: d.currentSharedAddressesMap
|
||||||
},
|
|
||||||
RoleSorter {
|
totalNumOfAddressesForSharing: d.totalNumOfAddressesForSharing
|
||||||
roleName: "position"
|
profileProvesOwnershipOfSelectedAddresses: root.profileProvesOwnershipOfSelectedAddresses
|
||||||
},
|
allAddressesToRevealBelongToSingleNonProfileKeypair: root.allAddressesToRevealBelongToSingleNonProfileKeypair
|
||||||
RoleSorter {
|
|
||||||
roleName: "name"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
walletAssetsModel: root.walletAssetsModel
|
walletAssetsModel: root.walletAssetsModel
|
||||||
permissionsModel: root.permissionsModel
|
permissionsModel: root.permissionsModel
|
||||||
assetsModel: root.assetsModel
|
assetsModel: root.assetsModel
|
||||||
collectiblesModel: root.collectiblesModel
|
collectiblesModel: root.collectiblesModel
|
||||||
|
|
||||||
|
onClose: {
|
||||||
|
root.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
onToggleAddressSelection: {
|
||||||
|
d.toggleAddressSelection(keyUid, address)
|
||||||
|
|
||||||
|
const obj = d.getSelectedAddresses()
|
||||||
|
root.sharedAddressesUpdated(obj.addresses)
|
||||||
|
}
|
||||||
|
|
||||||
|
onAirdropAddressSelected: {
|
||||||
|
d.selectAirdropAddress(address)
|
||||||
|
}
|
||||||
|
|
||||||
onShareSelectedAddressesClicked: {
|
onShareSelectedAddressesClicked: {
|
||||||
d.selectedAirdropAddress = airdropAddress
|
d.proceedToSigningOrSubmitRequest(d.shareAddressesUid)
|
||||||
d.selectedSharedAddresses = sharedAddresses
|
|
||||||
root.replaceItem = undefined // go back, unload us
|
|
||||||
}
|
|
||||||
onSharedAddressesChanged: {
|
|
||||||
root.sharedAddressesUpdated(sharedAddresses)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrencyAmount: function (balance, symbol){
|
getCurrencyAmount: function (balance, symbol){
|
||||||
return root.getCurrencyAmount(balance, symbol)
|
return root.getCurrencyAmount(balance, symbol)
|
||||||
}
|
}
|
||||||
|
@ -158,10 +371,16 @@ StatusStackModal {
|
||||||
id: sharedAddressesSigningPanelComponent
|
id: sharedAddressesSigningPanelComponent
|
||||||
SharedAddressesSigningPanel {
|
SharedAddressesSigningPanel {
|
||||||
|
|
||||||
|
componentUid: d.signingPanelUid
|
||||||
|
isEditMode: root.isEditMode
|
||||||
|
totalNumOfAddressesForSharing: d.totalNumOfAddressesForSharing
|
||||||
|
selectedSharedAddressesMap: d.selectedSharedAddressesMap
|
||||||
|
|
||||||
|
communityName: root.communityName
|
||||||
keypairSigningModel: root.keypairSigningModel
|
keypairSigningModel: root.keypairSigningModel
|
||||||
|
|
||||||
onSignSharedAddressesForAllNonKeycardKeypairs: {
|
onSignProfileKeypairAndAllNonKeycardKeypairs: {
|
||||||
root.signSharedAddressesForAllNonKeycardKeypairs()
|
root.signProfileKeypairAndAllNonKeycardKeypairs()
|
||||||
}
|
}
|
||||||
|
|
||||||
onSignSharedAddressesForKeypair: {
|
onSignSharedAddressesForKeypair: {
|
||||||
|
@ -169,7 +388,11 @@ StatusStackModal {
|
||||||
}
|
}
|
||||||
|
|
||||||
onJoinCommunity: {
|
onJoinCommunity: {
|
||||||
root.joinCommunity()
|
if (root.isEditMode) {
|
||||||
|
root.editRevealedAddresses()
|
||||||
|
} else {
|
||||||
|
root.joinCommunity()
|
||||||
|
}
|
||||||
root.close()
|
root.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,12 +414,12 @@ StatusStackModal {
|
||||||
visible: ((image.status == Image.Loading) ||
|
visible: ((image.status == Image.Loading) ||
|
||||||
(image.status == Image.Ready)) &&
|
(image.status == Image.Ready)) &&
|
||||||
!image.isError
|
!image.isError
|
||||||
image.source: root.imageSrc
|
image.source: root.communityIcon
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusBaseText {
|
StatusBaseText {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: root.introMessage || qsTr("Community <b>%1</b> has no intro message...").arg(root.name)
|
text: root.introMessage || qsTr("Community <b>%1</b> has no intro message...").arg(root.communityName)
|
||||||
color: Theme.palette.directColor1
|
color: Theme.palette.directColor1
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue