feat(Airdrops): Component for selecting recipient addresses and members
Closes: #9799
This commit is contained in:
parent
0ebc5e4194
commit
6768f62451
|
@ -165,6 +165,18 @@ ListModel {
|
||||||
title: "StatusGroupBox"
|
title: "StatusGroupBox"
|
||||||
section: "Components"
|
section: "Components"
|
||||||
}
|
}
|
||||||
|
ListElement {
|
||||||
|
title: "AddressesInputList"
|
||||||
|
section: "Components"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
title: "AddressesSelectorPanel"
|
||||||
|
section: "Components"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
title: "AirdropRecipientsSelector"
|
||||||
|
section: "Components"
|
||||||
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
title: "AirdropTokensSelector"
|
title: "AirdropTokensSelector"
|
||||||
section: "Components"
|
section: "Components"
|
||||||
|
|
|
@ -3,6 +3,18 @@
|
||||||
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=1159%3A114479",
|
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=1159%3A114479",
|
||||||
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=1684%3A127762"
|
"https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?node-id=1684%3A127762"
|
||||||
],
|
],
|
||||||
|
"AirdropRecipientsSelector": [
|
||||||
|
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22628-494998",
|
||||||
|
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22628-495258",
|
||||||
|
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22647-497754",
|
||||||
|
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=28045-533663",
|
||||||
|
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=28045-533912",
|
||||||
|
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22628-495493",
|
||||||
|
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22628-495928",
|
||||||
|
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22628-496145",
|
||||||
|
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22642-496092",
|
||||||
|
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22647-498080"
|
||||||
|
],
|
||||||
"AirdropTokensSelector": [
|
"AirdropTokensSelector": [
|
||||||
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22602-495563",
|
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22602-495563",
|
||||||
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22628-494998",
|
"https://www.figma.com/file/17fc13UBFvInrLgNUKJJg5/Kuba%E2%8E%9CDesktop?node-id=22628-494998",
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
import QtQuick.Layouts 1.14
|
||||||
|
|
||||||
|
import AppLayouts.Chat.controls.community 1.0
|
||||||
|
|
||||||
|
import Storybook 1.0
|
||||||
|
import Models 1.0
|
||||||
|
|
||||||
|
SplitView {
|
||||||
|
orientation: Qt.Vertical
|
||||||
|
|
||||||
|
Logs { id: logs }
|
||||||
|
|
||||||
|
Pane {
|
||||||
|
SplitView.fillWidth: true
|
||||||
|
SplitView.fillHeight: true
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "lightgray"
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressesInputList {
|
||||||
|
width: 500
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
enabled: isEnabledCheckBox.checked
|
||||||
|
|
||||||
|
model: AddressesModel {
|
||||||
|
id: addressesModel
|
||||||
|
}
|
||||||
|
|
||||||
|
onAddAddressesRequested: {
|
||||||
|
addressesModel.addAddressesFromString(addresses)
|
||||||
|
clearInput()
|
||||||
|
positionListAtEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemoveAddressRequested: addressesModel.remove(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogsAndControlsPanel {
|
||||||
|
id: logsAndControlsPanel
|
||||||
|
|
||||||
|
SplitView.minimumHeight: 100
|
||||||
|
SplitView.preferredHeight: 160
|
||||||
|
|
||||||
|
logsView.logText: logs.logText
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: isEnabledCheckBox
|
||||||
|
|
||||||
|
text: "Enabled"
|
||||||
|
checked: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Clear"
|
||||||
|
|
||||||
|
onClicked: addressesModel.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
import QtQuick 2.14
|
||||||
|
import QtQuick.Controls 2.14
|
||||||
|
import QtQuick.Layouts 1.14
|
||||||
|
|
||||||
|
import AppLayouts.Chat.controls.community 1.0
|
||||||
|
|
||||||
|
import Storybook 1.0
|
||||||
|
import Models 1.0
|
||||||
|
|
||||||
|
SplitView {
|
||||||
|
orientation: Qt.Vertical
|
||||||
|
|
||||||
|
Logs { id: logs }
|
||||||
|
|
||||||
|
Pane {
|
||||||
|
SplitView.fillWidth: true
|
||||||
|
SplitView.fillHeight: true
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "lightgray"
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: timer
|
||||||
|
|
||||||
|
interval: 1000
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
addressesModel.addAddressesFromString(
|
||||||
|
addressesSelectorPanel.text)
|
||||||
|
addressesSelectorPanel.clearInput()
|
||||||
|
addressesSelectorPanel.positionListAtEnd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressesSelectorPanel {
|
||||||
|
id: addressesSelectorPanel
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: 500
|
||||||
|
|
||||||
|
model: AddressesModel {
|
||||||
|
id: addressesModel
|
||||||
|
}
|
||||||
|
|
||||||
|
Binding on loading { value: isLoadingCheckBox.checked }
|
||||||
|
Binding on loading { value: timer.running }
|
||||||
|
|
||||||
|
onAddAddressesRequested: timer.start()
|
||||||
|
onRemoveAddressRequested: addressesModel.remove(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogsAndControlsPanel {
|
||||||
|
SplitView.minimumHeight: 100
|
||||||
|
SplitView.preferredHeight: 160
|
||||||
|
|
||||||
|
logsView.logText: logs.logText
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: isLoadingCheckBox
|
||||||
|
|
||||||
|
text: "Is loading"
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Clear"
|
||||||
|
|
||||||
|
onClicked: addressesModel.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,175 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
|
import AppLayouts.Chat.controls.community 1.0
|
||||||
|
|
||||||
|
import Models 1.0
|
||||||
|
import Storybook 1.0
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
|
||||||
|
SplitView {
|
||||||
|
property bool globalUtilsReady: false
|
||||||
|
property bool mainModuleReady: false
|
||||||
|
|
||||||
|
orientation: Qt.Vertical
|
||||||
|
|
||||||
|
Logs { id: logs }
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
function isCompressedPubKey(publicKey) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
function getColorId(publicKey) {
|
||||||
|
return Math.floor(Math.random() * 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
Utils.globalUtilsInst = this
|
||||||
|
globalUtilsReady = true
|
||||||
|
|
||||||
|
}
|
||||||
|
Component.onDestruction: {
|
||||||
|
globalUtilsReady = false
|
||||||
|
Utils.globalUtilsInst = {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
function getContactDetailsAsJson() {
|
||||||
|
return JSON.stringify({ ensVerified: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
mainModuleReady = true
|
||||||
|
Utils.mainModuleInst = this
|
||||||
|
}
|
||||||
|
Component.onDestruction: {
|
||||||
|
mainModuleReady = false
|
||||||
|
Utils.mainModuleInst = {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pane {
|
||||||
|
SplitView.fillWidth: true
|
||||||
|
SplitView.fillHeight: true
|
||||||
|
|
||||||
|
AddressesModel {
|
||||||
|
id: addresses
|
||||||
|
}
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
id: members
|
||||||
|
|
||||||
|
property int counter: 0
|
||||||
|
|
||||||
|
function addMember() {
|
||||||
|
const i = counter++
|
||||||
|
const key = `pub_key_${i}`
|
||||||
|
|
||||||
|
append({
|
||||||
|
alias: "",
|
||||||
|
colorId: "1",
|
||||||
|
displayName: `contact ${i}`,
|
||||||
|
ensName: "",
|
||||||
|
icon: "",
|
||||||
|
isContact: true,
|
||||||
|
localNickname: "",
|
||||||
|
onlineStatus: 1,
|
||||||
|
pubKey: key,
|
||||||
|
isVerified: true,
|
||||||
|
isUntrustworthy: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
for (let i = 0; i < 4; i++)
|
||||||
|
addMember()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: loader
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
active: globalUtilsReady && mainModuleReady
|
||||||
|
|
||||||
|
sourceComponent: AirdropRecipientsSelector {
|
||||||
|
id: selector
|
||||||
|
|
||||||
|
addressesModel: addresses
|
||||||
|
loadingAddresses: timer.running
|
||||||
|
membersModel: members
|
||||||
|
showAddressesInputWhenEmpty:
|
||||||
|
showAddressesInputWhenEmptyCheckBox.checked
|
||||||
|
|
||||||
|
onAddAddressesRequested: timer.start()
|
||||||
|
onRemoveAddressRequested: addresses.remove(index)
|
||||||
|
onRemoveMemberRequested: members.remove(index)
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: timer
|
||||||
|
|
||||||
|
interval: 1000
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
addresses.addAddressesFromString(
|
||||||
|
selector.addressesInputText)
|
||||||
|
selector.clearAddressesInput()
|
||||||
|
selector.positionAddressesListAtEnd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogsAndControlsPanel {
|
||||||
|
SplitView.minimumHeight: 100
|
||||||
|
SplitView.preferredHeight: 180
|
||||||
|
|
||||||
|
logsView.logText: logs.logText
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Button {
|
||||||
|
text: "Clear addresses list"
|
||||||
|
onClicked: addresses.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Clear members list"
|
||||||
|
onClicked: members.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: showAddressesInputWhenEmptyCheckBox
|
||||||
|
|
||||||
|
text: "Show addresses input when empty"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Add member"
|
||||||
|
onClicked: {
|
||||||
|
members.addMember()
|
||||||
|
loader.item.positionMembersListAtEnd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuSeparator {}
|
||||||
|
|
||||||
|
TextEdit {
|
||||||
|
readOnly: true
|
||||||
|
selectByMouse: true
|
||||||
|
text: "valid address: 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
ListElement {
|
||||||
|
address: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
|
||||||
|
valid: true
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
address: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756ccx"
|
||||||
|
valid: false
|
||||||
|
}
|
||||||
|
|
||||||
|
function addAddressesFromString(addresses) {
|
||||||
|
const words = addresses.trim().split(/[\s+,]/)
|
||||||
|
const existing = new Set()
|
||||||
|
|
||||||
|
for (let i = 0; i < count; i++)
|
||||||
|
existing.add(get(i).address)
|
||||||
|
|
||||||
|
words.forEach(word => {
|
||||||
|
if (word === "" || existing.has(word))
|
||||||
|
return
|
||||||
|
|
||||||
|
const valid = Utils.isValidAddress(word)
|
||||||
|
append({ valid, address: word })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,14 @@
|
||||||
singleton ModelsData 1.0 ModelsData.qml
|
AddressesModel 1.0 AddressesModel.qml
|
||||||
singleton PermissionsModel 1.0 PermissionsModel.qml
|
|
||||||
singleton NetworksModel 1.0 NetworksModel.qml
|
|
||||||
singleton MintedCollectiblesModel 1.0 MintedCollectiblesModel.qml
|
|
||||||
IconModel 1.0 IconModel.qml
|
|
||||||
BannerModel 1.0 BannerModel.qml
|
|
||||||
UsersModel 1.0 UsersModel.qml
|
|
||||||
AssetsModel 1.0 AssetsModel.qml
|
|
||||||
CollectiblesModel 1.0 CollectiblesModel.qml
|
|
||||||
ChannelsModel 1.0 ChannelsModel.qml
|
|
||||||
AssetsCollectiblesIconsModel 1.0 AssetsCollectiblesIconsModel.qml
|
AssetsCollectiblesIconsModel 1.0 AssetsCollectiblesIconsModel.qml
|
||||||
|
AssetsModel 1.0 AssetsModel.qml
|
||||||
|
BannerModel 1.0 BannerModel.qml
|
||||||
|
ChannelsModel 1.0 ChannelsModel.qml
|
||||||
|
CollectiblesModel 1.0 CollectiblesModel.qml
|
||||||
|
IconModel 1.0 IconModel.qml
|
||||||
TokenHoldersModel 1.0 TokenHoldersModel.qml
|
TokenHoldersModel 1.0 TokenHoldersModel.qml
|
||||||
|
UsersModel 1.0 UsersModel.qml
|
||||||
WalletAccountsModel 1.0 WalletAccountsModel.qml
|
WalletAccountsModel 1.0 WalletAccountsModel.qml
|
||||||
|
singleton MintedCollectiblesModel 1.0 MintedCollectiblesModel.qml
|
||||||
|
singleton ModelsData 1.0 ModelsData.qml
|
||||||
|
singleton NetworksModel 1.0 NetworksModel.qml
|
||||||
|
singleton PermissionsModel 1.0 PermissionsModel.qml
|
||||||
|
|
|
@ -0,0 +1,203 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
import StatusQ.Core.Utils 0.1
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
|
||||||
|
Control {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias model: listView.model
|
||||||
|
readonly property alias count: listView.count
|
||||||
|
|
||||||
|
property string text: listView.footerItem.text
|
||||||
|
property int maximumTextInputHeight: 156
|
||||||
|
|
||||||
|
property int maximumHeight: 405
|
||||||
|
|
||||||
|
signal addAddressesRequested(string addresses)
|
||||||
|
signal removeAddressRequested(int index)
|
||||||
|
|
||||||
|
function clearInput() {
|
||||||
|
listView.footerItem.edit.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
function positionListAtEnd() {
|
||||||
|
listView.positionViewAtEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
padding: 8
|
||||||
|
rightPadding: 13
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
readonly property int delegateHeight: 32
|
||||||
|
readonly property int spacing: 8
|
||||||
|
readonly property int scrollBarWidth: 4
|
||||||
|
readonly property int scrollBarOffset: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
radius: Style.current.radius
|
||||||
|
color: Theme.palette.indirectColor1
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: StatusListView {
|
||||||
|
id: listView
|
||||||
|
|
||||||
|
readonly property int maximumHeight:
|
||||||
|
root.maximumHeight - root.bottomPadding - root.topPadding
|
||||||
|
|
||||||
|
clip: false
|
||||||
|
|
||||||
|
verticalScrollBar {
|
||||||
|
implicitWidth: d.scrollBarWidth + ScrollBar.vertical.padding * 2
|
||||||
|
parent: listView.parent
|
||||||
|
anchors {
|
||||||
|
left: listView.right
|
||||||
|
top: listView.top
|
||||||
|
bottom: listView.bottom
|
||||||
|
leftMargin: -verticalScrollBar.leftPadding + d.scrollBarOffset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spacing: d.spacing
|
||||||
|
implicitHeight: Math.min(contentHeight, maximumHeight)
|
||||||
|
implicitWidth: root.availableWidth
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
id: delegate
|
||||||
|
|
||||||
|
radius: height / 2
|
||||||
|
color: Theme.palette.directColor8
|
||||||
|
|
||||||
|
width: ListView.view.width
|
||||||
|
height: d.delegateHeight
|
||||||
|
|
||||||
|
states: State {
|
||||||
|
when: !model.valid
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: delegate
|
||||||
|
|
||||||
|
color: Theme.palette.alphaColor(
|
||||||
|
Theme.palette.dangerColor1, 0.05)
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: statusIcon
|
||||||
|
|
||||||
|
width: 21
|
||||||
|
height: 21
|
||||||
|
icon: "warning"
|
||||||
|
color: Theme.palette.dangerColor1
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: addressText
|
||||||
|
|
||||||
|
color: Theme.palette.dangerColor1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusIcon {
|
||||||
|
id: statusIcon
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.horizontalCenter: parent.left
|
||||||
|
anchors.horizontalCenterOffset: 18
|
||||||
|
|
||||||
|
width: 16
|
||||||
|
height: 16
|
||||||
|
icon: "checkbox"
|
||||||
|
color: Theme.palette.successColor1
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
id: addressText
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: deleteIcon.left
|
||||||
|
anchors.margins: 7
|
||||||
|
anchors.leftMargin: 34
|
||||||
|
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
|
||||||
|
font.pixelSize: 15
|
||||||
|
font.weight: Font.Medium
|
||||||
|
|
||||||
|
elide: Text.ElideMiddle
|
||||||
|
text: model.address
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusIcon {
|
||||||
|
id: deleteIcon
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
|
||||||
|
width: 16
|
||||||
|
height: 16
|
||||||
|
|
||||||
|
icon: "delete"
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.removeAddressRequested(model.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: StatusBaseInput {
|
||||||
|
id: input
|
||||||
|
|
||||||
|
showBackground: false
|
||||||
|
maximumLength: 2000
|
||||||
|
|
||||||
|
width: root.availableWidth
|
||||||
|
|
||||||
|
leftPadding: 0
|
||||||
|
rightPadding: 0
|
||||||
|
|
||||||
|
multiline: true
|
||||||
|
|
||||||
|
topPadding: bottomPadding + (listView.count ? d.spacing : 0)
|
||||||
|
|
||||||
|
height: edit.implicitHeight + topPadding + bottomPadding
|
||||||
|
|
||||||
|
placeholderText: qsTr("Example: 0x39cf...fbd2")
|
||||||
|
|
||||||
|
Keys.onPressed: {
|
||||||
|
if ((event.key !== Qt.Key_Return && event.key !== Qt.Key_Enter)
|
||||||
|
|| event.modifiers & Qt.ShiftModifier) {
|
||||||
|
event.accepted = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
event.accepted = true
|
||||||
|
|
||||||
|
if (input.text.length > 0)
|
||||||
|
root.addAddressesRequested(input.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
onHeightChanged: Qt.callLater(() => listView.positionViewAtEnd())
|
||||||
|
|
||||||
|
verticalAlignment: Qt.AlignTop
|
||||||
|
placeholder.verticalAlignment: Qt.AlignTop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
|
import StatusQ.Components 0.1
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
|
||||||
|
import SortFilterProxyModel 0.2
|
||||||
|
|
||||||
|
|
||||||
|
Control {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias model: addressesInputList.model
|
||||||
|
property alias text: addressesInputList.text
|
||||||
|
|
||||||
|
property bool loading: false
|
||||||
|
|
||||||
|
signal addAddressesRequested(string addresses)
|
||||||
|
signal removeAddressRequested(int index)
|
||||||
|
|
||||||
|
readonly property alias count: addressesInputList.count
|
||||||
|
readonly property alias validAddressesCount: validAddressesModel.count
|
||||||
|
readonly property int invalidAddressesCount: addressesInputList.count
|
||||||
|
- validAddressesCount
|
||||||
|
|
||||||
|
function clearInput() {
|
||||||
|
addressesInputList.clearInput()
|
||||||
|
}
|
||||||
|
|
||||||
|
function positionListAtEnd() {
|
||||||
|
addressesInputList.positionListAtEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Column {
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
width: root.availableWidth
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
text: qsTr("ETH addresses")
|
||||||
|
font.pixelSize: Theme.tertiaryTextFontSize
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
visible: !root.loading && root.validAddressesCount > 0
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
text: qsTr("%n valid address(s)", "", root.validAddressesCount)
|
||||||
|
+ (root.invalidAddressesCount > 0 ? " / " : "")
|
||||||
|
font.pixelSize: Theme.tertiaryTextFontSize
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
visible: !root.loading && root.invalidAddressesCount > 0
|
||||||
|
color: Theme.palette.dangerColor1
|
||||||
|
text: root.validAddressesCount > 0
|
||||||
|
? qsTr("%n invalid",
|
||||||
|
"invalid addresses, where \"addresses\" is implicit",
|
||||||
|
root.invalidAddressesCount)
|
||||||
|
: qsTr("%n invalid address(s)", "", root.invalidAddressesCount)
|
||||||
|
font.pixelSize: Theme.tertiaryTextFontSize
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusLoadingIndicator {
|
||||||
|
visible: root.loading
|
||||||
|
|
||||||
|
Layout.preferredWidth: 10
|
||||||
|
Layout.preferredHeight: 10
|
||||||
|
Layout.rightMargin: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SortFilterProxyModel {
|
||||||
|
id: validAddressesModel
|
||||||
|
|
||||||
|
sourceModel: root.model ?? null
|
||||||
|
|
||||||
|
filters: ValueFilter {
|
||||||
|
roleName: "valid"
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressesInputList {
|
||||||
|
id: addressesInputList
|
||||||
|
|
||||||
|
enabled: !root.loading
|
||||||
|
width: root.availableWidth
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
addAddressesRequested.connect(root.addAddressesRequested)
|
||||||
|
removeAddressRequested.connect(root.removeAddressRequested)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
|
||||||
|
import StatusQ.Components 0.1
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
|
||||||
|
StatusFlowSelector {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias addressesModel: addressesSelectorPanel.model
|
||||||
|
property alias membersModel: membersSelectorPanel.model
|
||||||
|
|
||||||
|
property alias loadingAddresses: addressesSelectorPanel.loading
|
||||||
|
property alias addressesInputText: addressesSelectorPanel.text
|
||||||
|
|
||||||
|
property bool showAddressesInputWhenEmpty: false
|
||||||
|
|
||||||
|
signal addAddressesRequested(string addresses)
|
||||||
|
signal removeAddressRequested(int index)
|
||||||
|
signal removeMemberRequested(int index)
|
||||||
|
|
||||||
|
placeholderItem.visible: !addressesSelectorPanel.visible &&
|
||||||
|
!membersSelectorPanel.visible
|
||||||
|
|
||||||
|
title: qsTr("To")
|
||||||
|
icon: Style.svg("member")
|
||||||
|
flowSpacing: 12
|
||||||
|
|
||||||
|
placeholderText: qsTr("Example: 12 addresses and 3 members")
|
||||||
|
|
||||||
|
function clearAddressesInput() {
|
||||||
|
addressesSelectorPanel.clearInput()
|
||||||
|
}
|
||||||
|
|
||||||
|
function positionAddressesListAtEnd() {
|
||||||
|
addressesSelectorPanel.positionListAtEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
function positionMembersListAtEnd() {
|
||||||
|
membersSelectorPanel.positionListAtEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressesSelectorPanel {
|
||||||
|
id: addressesSelectorPanel
|
||||||
|
|
||||||
|
visible: count > 0 || root.showAddressesInputWhenEmpty
|
||||||
|
width: root.availableWidth
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
addAddressesRequested.connect(root.addAddressesRequested)
|
||||||
|
removeAddressRequested.connect(root.removeAddressRequested)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MembersSelectorPanel {
|
||||||
|
id: membersSelectorPanel
|
||||||
|
|
||||||
|
visible: count > 0
|
||||||
|
width: root.availableWidth
|
||||||
|
|
||||||
|
Component.onCompleted: removeMemberRequested.connect(
|
||||||
|
root.removeMemberRequested)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
|
||||||
|
import shared.controls.delegates 1.0
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
|
||||||
|
Control {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias model: listView.model
|
||||||
|
property int maximumListHeight: 188
|
||||||
|
|
||||||
|
readonly property alias count: listView.count
|
||||||
|
|
||||||
|
signal removeMemberRequested(int index)
|
||||||
|
|
||||||
|
function positionListAtEnd() {
|
||||||
|
listView.positionViewAtEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
readonly property int delegateHeight: 47
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Column {
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
width: root.availableWidth
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
component Text: StatusBaseText {
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
text: qsTr("Members")
|
||||||
|
font.pixelSize: Theme.tertiaryTextFontSize
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("Members")
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("%n member(s)", "", root.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: root.availableWidth
|
||||||
|
height: Math.min(root.maximumListHeight,
|
||||||
|
d.delegateHeight * root.count)
|
||||||
|
|
||||||
|
radius: Style.current.radius
|
||||||
|
color: Theme.palette.indirectColor1
|
||||||
|
|
||||||
|
StatusListView {
|
||||||
|
id: listView
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
delegate: ContactListItemDelegate {
|
||||||
|
width: ListView.view.width
|
||||||
|
height: d.delegateHeight
|
||||||
|
asset.width: 29
|
||||||
|
asset.height: 29
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
StatusIcon {
|
||||||
|
id: deleteIcon
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
|
||||||
|
width: 16
|
||||||
|
height: 16
|
||||||
|
|
||||||
|
icon: "delete"
|
||||||
|
color: Theme.palette.directColor1
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
|
||||||
|
onClicked: root.removeMemberRequested(model.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,13 @@
|
||||||
|
AddressesInputList 1.0 AddressesInputList.qml
|
||||||
|
AddressesSelectorPanel 1.0 AddressesSelectorPanel.qml
|
||||||
|
AirdropRecipientsSelector 1.0 AirdropRecipientsSelector.qml
|
||||||
AirdropTokensSelector 1.0 AirdropTokensSelector.qml
|
AirdropTokensSelector 1.0 AirdropTokensSelector.qml
|
||||||
CommunityCategoryListItem 1.0 CommunityCategoryListItem.qml
|
CommunityCategoryListItem 1.0 CommunityCategoryListItem.qml
|
||||||
CommunityListItem 1.0 CommunityListItem.qml
|
CommunityListItem 1.0 CommunityListItem.qml
|
||||||
HoldingTypes 1.0 HoldingTypes.qml
|
HoldingTypes 1.0 HoldingTypes.qml
|
||||||
HoldingsDropdown 1.0 HoldingsDropdown.qml
|
HoldingsDropdown 1.0 HoldingsDropdown.qml
|
||||||
InDropdown 1.0 InDropdown.qml
|
InDropdown 1.0 InDropdown.qml
|
||||||
|
MembersSelectorPanel 1.0 MembersSelectorPanel.qml
|
||||||
PermissionItem 1.0 PermissionItem.qml
|
PermissionItem 1.0 PermissionItem.qml
|
||||||
PermissionsDropdown 1.0 PermissionsDropdown.qml
|
PermissionsDropdown 1.0 PermissionsDropdown.qml
|
||||||
singleton PermissionTypes 1.0 PermissionTypes.qml
|
singleton PermissionTypes 1.0 PermissionTypes.qml
|
||||||
|
|
Loading…
Reference in New Issue