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"
|
||||
section: "Components"
|
||||
}
|
||||
ListElement {
|
||||
title: "AddressesInputList"
|
||||
section: "Components"
|
||||
}
|
||||
ListElement {
|
||||
title: "AddressesSelectorPanel"
|
||||
section: "Components"
|
||||
}
|
||||
ListElement {
|
||||
title: "AirdropRecipientsSelector"
|
||||
section: "Components"
|
||||
}
|
||||
ListElement {
|
||||
title: "AirdropTokensSelector"
|
||||
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=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": [
|
||||
"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",
|
||||
|
|
|
@ -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
|
||||
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
|
||||
AddressesModel 1.0 AddressesModel.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
|
||||
UsersModel 1.0 UsersModel.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
|
||||
CommunityCategoryListItem 1.0 CommunityCategoryListItem.qml
|
||||
CommunityListItem 1.0 CommunityListItem.qml
|
||||
HoldingTypes 1.0 HoldingTypes.qml
|
||||
HoldingsDropdown 1.0 HoldingsDropdown.qml
|
||||
InDropdown 1.0 InDropdown.qml
|
||||
MembersSelectorPanel 1.0 MembersSelectorPanel.qml
|
||||
PermissionItem 1.0 PermissionItem.qml
|
||||
PermissionsDropdown 1.0 PermissionsDropdown.qml
|
||||
singleton PermissionTypes 1.0 PermissionTypes.qml
|
||||
|
|
Loading…
Reference in New Issue