import QtQuick 2.15 import QtQuick.Layouts 1.15 import StatusQ.Core 0.1 import StatusQ.Controls 0.1 import StatusQ.Core.Theme 0.1 import utils 1.0 import shared.popups.keycard.helpers 1.0 import SortFilterProxyModel 0.2 ColumnLayout { id: root required property string componentUid required property bool isEditMode property var keypairSigningModel 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] signal joinCommunity() signal signProfileKeypairAndAllNonKeycardKeypairs() signal signSharedAddressesForKeypair(string keyUid) function allSigned() { d.allSigned = true } QtObject { id: d readonly property int selectedSharedAddressesCount: root.selectedSharedAddressesMap.size 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 { enabled: d.allSigned text: { if (d.selectedSharedAddressesCount === root.totalNumOfAddressesForSharing) { return qsTr("Share all addresses to join") } return qsTr("Share %n address(s) to join", "", d.selectedSharedAddressesCount) } onClicked: { root.joinCommunity() } } } ColumnLayout { Layout.fillWidth: true Layout.margins: Style.current.xlPadding 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 %1, authenticate the associated keypairs...", "", d.selectedSharedAddressesCount).arg(root.communityName) } RowLayout { Layout.fillWidth: true visible: nonKeycardProfileKeypair.visible StatusBaseText { Layout.fillWidth: true text: qsTr("Stored on device") font.pixelSize: Constants.keycard.general.fontSize2 color: Theme.palette.baseColor1 wrapMode: Text.WordWrap } } StatusListView { id: nonKeycardProfileKeypair Layout.fillWidth: true Layout.preferredHeight: nonKeycardProfileKeypair.contentHeight visible: nonKeycardProfileKeypair.model.count > 0 spacing: Style.current.padding model: SortFilterProxyModel { sourceModel: root.keypairSigningModel filters: ExpressionFilter { expression: model.keyPair.keyUid === userProfile.keyUid && !userProfile.isKeycardUser } } delegate: KeyPairItem { id: kpOnDeviceDelegate 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 { 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 { visible: nonKeycardProfileKeypair.visible Layout.fillWidth: true Layout.preferredHeight: Style.current.xlPadding } RowLayout { Layout.fillWidth: true visible: keycardKeypairs.visible StatusBaseText { text: qsTr("Stored on keycard") 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 { id: keycardKeypairs Layout.fillWidth: true Layout.preferredHeight: keycardKeypairs.contentHeight visible: keycardKeypairs.model.count > 0 spacing: Style.current.padding model: SortFilterProxyModel { sourceModel: root.keypairSigningModel filters: ExpressionFilter { expression: model.keyPair.migratedToKeycard } } delegate: KeyPairItem { id: kpOnKeycardDelegate width: ListView.view.width sensor.hoverEnabled: !model.keyPair.ownershipVerified 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 { text: qsTr("Authenticate") visible: !model.keyPair.ownershipVerified icon.name: "keycard" onClicked: { if (model.keyPair.keyUid === userProfile.keyUid) { root.signProfileKeypairAndAllNonKeycardKeypairs() return } 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 } } } } } }