feat(@desktop/wallet): This commit is focussed on testing and adding dialog resizing for simple send

fixes #16836
This commit is contained in:
Khushboo Mehta 2024-12-03 10:50:49 +01:00
parent 1bd54401a2
commit 37a6a583cf
11 changed files with 882 additions and 28 deletions

View File

@ -1,18 +1,35 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import SortFilterProxyModel 0.2
import Models 1.0
import Storybook 1.0
import AppLayouts.Wallet.popups.simpleSend 1.0
import AppLayouts.Wallet.stores 1.0
import AppLayouts.Wallet.adaptors 1.0
import utils 1.0
SplitView {
id: root
orientation: Qt.Horizontal
function launchPopup() {
simpleSend.createObject(root)
QtObject {
id: d
readonly property SortFilterProxyModel filteredNetworksModel: SortFilterProxyModel {
sourceModel: NetworksModel.flatNetworks
filters: ValueFilter { roleName: "isTest"; value: testNetworksCheckbox.checked }
}
readonly property WalletAssetsStore walletAssetStore: WalletAssetsStore {
assetsWithFilteredBalances: groupedAccountsAssetsModel
}
readonly property var walletAccountsModel: WalletAccountsModel{}
}
PopupBackground {
@ -27,25 +44,369 @@ SplitView {
text: "Reopen"
enabled: !simpleSend.visible
onClicked: launchPopup()
onClicked: simpleSend.open()
}
Component.onCompleted: launchPopup()
Component.onCompleted: simpleSend.open()
}
Component {
SimpleSendModal {
id: simpleSend
SimpleSendModal {
visible: true
modal: false
closePolicy: Popup.NoAutoClose
visible: true
modal: false
closePolicy: Popup.CloseOnEscape
accountsModel: d.walletAccountsModel
assetsModel: assetsSelectorViewAdaptor.outputAssetsModel
collectiblesModel: collectiblesSelectionAdaptor.model
networksModel: d.filteredNetworksModel
Component.onCompleted: simpleSend.open()
}
TokenSelectorViewAdaptor {
id: assetsSelectorViewAdaptor
assetsModel: d.walletAssetStore.groupedAccountAssetsModel
flatNetworksModel: NetworksModel.flatNetworks
currentCurrency: "USD"
accountAddress: simpleSend.selectedAccountAddress
showCommunityAssets: true
enabledChainIds: [simpleSend.selectedChainId]
}
CollectiblesSelectionAdaptor {
id: collectiblesSelectionAdaptor
accountKey: simpleSend.selectedAccountAddress
networksModel: d.filteredNetworksModel
collectiblesModel: collectiblesBySymbolModel
}
ListModel {
id: collectiblesBySymbolModel
readonly property var data: [
// collection 2
{
tokenId: "id_3",
symbol: "abc",
chainId: NetworksModel.mainnetChainId,
name: "Multi-sequencer Test NFT 1",
contractAddress: "contract_2",
collectionName: "Multi-sequencer Test NFT",
collectionUid: "collection_2",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress1,
balance: 1,
txTimestamp: 1714059810
}
],
imageUrl: Constants.tokenIcon("ETH", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "",
communityName: "",
communityImage: Qt.resolvedUrl("")
},
{
tokenId: "id_4",
symbol: "def",
chainId: NetworksModel.mainnetChainId,
name: "Multi-sequencer Test NFT 2",
contractAddress: "contract_2",
collectionName: "Multi-sequencer Test NFT",
collectionUid: "collection_2",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress1,
balance: 1,
txTimestamp: 1714059811
}
],
imageUrl: Constants.tokenIcon("ETH", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "",
communityName: "",
communityImage: Qt.resolvedUrl("")
},
{
tokenId: "id_5",
symbol: "ghi",
chainId: NetworksModel.mainnetChainId,
name: "Multi-sequencer Test NFT 3",
contractAddress: "contract_2",
collectionName: "Multi-sequencer Test NFT",
collectionUid: "collection_2",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress1,
balance: 1,
txTimestamp: 1714059899
}
],
imageUrl: Constants.tokenIcon("ETH", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "",
communityName: "",
communityImage: Qt.resolvedUrl("")
},
// collection 1
{
tokenId: "id_1",
symbol: "jkl",
chainId: NetworksModel.mainnetChainId,
name: "Genesis",
contractAddress: "contract_1",
collectionName: "ERC-1155 Faucet",
collectionUid: "collection_1",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress1,
balance: 23,
txTimestamp: 1714059862
},
{
accountAddress: d.walletAccountsModel.accountAddress2,
balance: 29,
txTimestamp: 1714054862
}
],
imageUrl: Constants.tokenIcon("DAI", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "",
communityName: "",
communityImage: Qt.resolvedUrl("")
},
{
tokenId: "id_2",
symbol: "mno",
chainId: NetworksModel.mainnetChainId,
name: "QAERC1155",
contractAddress: "contract_1",
collectionName: "ERC-1155 Faucet",
collectionUid: "collection_1",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress1,
balance: 500,
txTimestamp: 1714059864
}
],
imageUrl: Constants.tokenIcon("ZRX", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "",
communityName: "",
communityImage: Qt.resolvedUrl("")
},
// collection 3, community token
{
tokenId: "id_6",
symbol: "pqr",
chainId: NetworksModel.optChainId,
name: "My Token",
contractAddress: "contract_3",
collectionName: "My Token",
collectionUid: "collection_3",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress1,
balance: 1,
txTimestamp: 1714059899
}
],
imageUrl: Constants.tokenIcon("ZRX", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "community_1",
communityName: "My community",
communityImage: Constants.tokenIcon("KIN", false)
},
{
tokenId: "id_7",
symbol: "stu",
chainId: NetworksModel.optChainId,
name: "My Token",
contractAddress: "contract_3",
collectionName: "My Token",
collectionUid: "collection_3",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress1,
balance: 1,
txTimestamp: 1714059899
}
],
imageUrl: Constants.tokenIcon("ZRX", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "community_1",
communityName: "My community",
communityImage: Constants.tokenIcon("KIN", false)
},
{
tokenId: "id_8",
symbol: "vwx",
chainId: NetworksModel.optChainId,
name: "My Token",
contractAddress: "contract_3",
collectionName: "My Token",
collectionUid: "collection_3",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress2,
balance: 1,
txTimestamp: 1714059999
}
],
imageUrl: Constants.tokenIcon("ZRX", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "community_1",
communityName: "My community",
communityImage: Constants.tokenIcon("KIN", false)
},
{
tokenId: "id_9",
symbol: "yz1",
chainId: NetworksModel.optChainId,
name: "My Other Token",
contractAddress: "contract_4",
collectionName: "My Other Token",
collectionUid: "collection_4",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress1,
balance: 1,
txTimestamp: 1714059991
}
],
imageUrl: Constants.tokenIcon("ZRX", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "community_1",
communityName: "My community",
communityImage: Constants.tokenIcon("KIN", false)
},
{
tokenId: "id_10",
symbol: "234",
chainId: NetworksModel.arbChainId,
name: "My Community 2 Token",
contractAddress: "contract_5",
collectionName: "My Community 2 Token",
collectionUid: "collection_5",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress1,
balance: 1,
txTimestamp: 1714059777
}
],
imageUrl: Constants.tokenIcon("ZRX", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "community_2",
communityName: "My community 2",
communityImage: Constants.tokenIcon("ICOS", false)
},
{
tokenId: "id_11",
symbol: "567",
chainId: NetworksModel.arbChainId,
name: "My Community 2 Token",
contractAddress: "contract_5",
collectionName: "My Community 2 Token",
collectionUid: "collection_5",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress1,
balance: 1,
txTimestamp: 1714059778
}
],
imageUrl: Constants.tokenIcon("ZRX", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "community_2",
communityName: "My community 2",
communityImage: Constants.tokenIcon("ICOS", false)
},
{
tokenId: "id_11",
symbol: "8910",
chainId: NetworksModel.arbChainId,
name: "My Community 2 Token",
contractAddress: "contract_5",
collectionName: "My Community 2 Token",
collectionUid: "collection_5",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress2,
balance: 1,
txTimestamp: 1714059779
}
],
imageUrl: Constants.tokenIcon("ZRX", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "community_2",
communityName: "My community 2",
communityImage: Constants.tokenIcon("ICOS", false)
},
{
tokenId: "id_12",
symbol: "111213",
chainId: NetworksModel.arbChainId,
name: "My Community 2 Token",
contractAddress: "contract_5",
collectionName: "My Community 2 Token",
collectionUid: "collection_5",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress3,
balance: 1,
txTimestamp: 1714059779
}
],
imageUrl: Constants.tokenIcon("ZRX", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "community_2",
communityName: "My community 2",
communityImage: Constants.tokenIcon("ICOS", false)
},
{
tokenId: "id_13",
symbol: "141516",
chainId: NetworksModel.arbChainId,
name: "My Community 2 Token",
contractAddress: "contract_5",
collectionName: "My Community 2 Token",
collectionUid: "collection_5",
ownership: [
{
accountAddress: d.walletAccountsModel.accountAddress3,
balance: 1,
txTimestamp: 1714059788
}
],
imageUrl: Constants.tokenIcon("ZRX", false),
mediaUrl: Qt.resolvedUrl(""),
communityId: "community_2",
communityName: "My community 2",
communityImage: Constants.tokenIcon("ICOS", false)
}
]
Component.onCompleted: {
append(data)
}
}
LogsAndControlsPanel {
SplitView.minimumHeight: 100
SplitView.preferredHeight: 100
SplitView.minimumWidth: 300
CheckBox {
id: testNetworksCheckbox
text: "are test networks enabled"
}
}
}

View File

@ -75,6 +75,7 @@ SplitView {
header: StatusDialogHeader {
//color: Theme.palette.baseColor3
color: !!ctrlHeaderBgColor.text ? ctrlHeaderBgColor.text : Theme.palette.statusModal.backgroundColor
dropShadowEnabled: ctrlHeaderDropShadow.checked
visible: dialog.title || dialog.subtitle
headline.title: dialog.title
@ -233,6 +234,10 @@ SplitView {
id: ctrlDropShadow
text: "Footer drop shadow"
}
CheckBox {
id: ctrlHeaderDropShadow
text: "Header drop shadow"
}
}
}
}

View File

@ -12,6 +12,14 @@ QtObject {
readonly property int testnetNet: 5
readonly property int customNet: 6
readonly property int mainnetChainId: 1
readonly property int sepMainnetChainId: 11155111
readonly property int optChainId: 10
readonly property int sepOptChainId: 11155420
readonly property int arbChainId: 42161
readonly property int sepArbChainId: 421614
function getShortChainName(chainId) {
if(chainId === root.ethNet)
return "eth"
@ -55,7 +63,7 @@ QtObject {
readonly property var flatNetworks: ListModel {
Component.onCompleted: append([
{
chainId: 1,
chainId: mainnetChainId,
chainName: "Mainnet",
blockExplorerURL: "https://etherscan.io/",
iconUrl: "network/Network=Ethereum",
@ -69,7 +77,7 @@ QtObject {
isRouteEnabled: true,
},
{
chainId: 11155111,
chainId: sepMainnetChainId,
chainName: "Sepolia Mainnet",
blockExplorerURL: "https://sepolia.etherscan.io/",
iconUrl: "network/Network=Ethereum",
@ -83,7 +91,7 @@ QtObject {
isRouteEnabled: true,
},
{
chainId: 10,
chainId: optChainId,
chainName: "Optimism",
blockExplorerURL: "https://optimistic.etherscan.io",
iconUrl: "network/Network=Optimism",
@ -97,7 +105,7 @@ QtObject {
isRouteEnabled: true,
},
{
chainId: 11155420,
chainId: sepOptChainId,
chainName: "Optimism Sepolia",
blockExplorerURL: "https://sepolia-optimism.etherscan.io/",
iconUrl: "network/Network=Optimism",
@ -111,7 +119,7 @@ QtObject {
isRouteEnabled: true,
},
{
chainId: 42161,
chainId: arbChainId,
chainName: "Arbitrum",
blockExplorerURL: "https://arbiscan.io/",
iconUrl: "network/Network=Arbitrum",
@ -125,7 +133,7 @@ QtObject {
isRouteEnabled: true,
},
{
chainId: 421614,
chainId: sepArbChainId,
chainName: "Arbitrum Sepolia",
blockExplorerURL: "https://sepolia-explorer.arbitrum.io/",
iconUrl: "network/Network=Arbitrum",

View File

@ -3,13 +3,20 @@ import QtQuick 2.15
import utils 1.0
ListModel {
readonly property string accountAddress1: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240"
readonly property string accountAddress2: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8881"
readonly property string accountAddress3: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8882"
readonly property string accountAddress4: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8883"
readonly property string accountAddress5: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8884"
readonly property var data: [
{
name: "helloworld",
emoji: "😋",
colorId: Constants.walletAccountColors.primary,
color: "#2A4AF5",
address: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240",
address: accountAddress1,
walletType: "",
canSend: true,
position: 0,
@ -53,7 +60,7 @@ ListModel {
emoji: "🚗",
colorId: Constants.walletAccountColors.army,
color: "#216266",
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8881",
address: accountAddress2,
walletType: Constants.generatedWalletType,
canSend: true,
position: 3,
@ -79,7 +86,7 @@ ListModel {
emoji: "🎨",
colorId: Constants.walletAccountColors.magenta,
color: "#EC266C",
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8882",
address: accountAddress3,
walletType: Constants.seedWalletType,
canSend: true,
position: 1,
@ -114,7 +121,7 @@ ListModel {
emoji: "⌚",
colorId: Constants.walletAccountColors.copper,
color: "#CB6256",
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8883",
address: accountAddress4,
walletType: Constants.watchWalletType,
canSend: false,
position: 2,
@ -131,7 +138,7 @@ ListModel {
emoji: "🔑",
colorId: Constants.walletAccountColors.camel,
color: "#C78F67",
address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8884",
address: accountAddress5,
walletType: Constants.keyWalletType,
canSend: true,
position: 4,

View File

@ -1,5 +1,6 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
import QtQuick.Layouts 1.15
import QtQml.Models 2.15
import QtQml 2.15
@ -32,7 +33,8 @@ Dialog {
anchors.centerIn: Overlay.overlay
padding: 16
margins: 64
// by design
margins: root.contentItem.Window.window.height <= 780 ? 28: 64
modal: true
// workaround for https://bugreports.qt.io/browse/QTBUG-87804

View File

@ -1,5 +1,6 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import QtGraphicalEffects 1.15
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
@ -9,6 +10,7 @@ Rectangle {
readonly property alias headline: headline
readonly property alias actions: actions
property bool dropShadowEnabled
property alias leftComponent: leftComponentLoader.sourceComponent
@ -63,4 +65,12 @@ Rectangle {
anchors.bottom: parent.bottom
width: parent.width
}
layer.enabled: root.dropShadowEnabled
layer.effect: DropShadow {
horizontalOffset: 0
verticalOffset: 2
samples: 37
color: Theme.palette.dropShadow
}
}

View File

@ -17,6 +17,9 @@ Control {
/** Expected model structure: see SearchableCollectiblesPanel::model **/
property alias collectiblesModel: tokenSelectorPanel.collectiblesModel
/** Exposes insatnce of popup **/
property var popup: dropdown
readonly property bool isTokenSelected: tokenSelectorButton.selected
signal assetSelected(string key)
@ -54,7 +57,6 @@ Control {
y: parent.height + 4
width: 448
closePolicy: Popup.CloseOnPressOutsideParent
horizontalPadding: 0
bottomPadding: 0

View File

@ -0,0 +1,140 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import AppLayouts.Wallet.controls 1.0
RowLayout {
id: root
/**
Expected model structure:
- tokensKey: unique string ID of the token (asset); e.g. "ETH" or contract address
- name: user visible token name (e.g. "Ethereum")
- symbol: user visible token symbol (e.g. "ETH")
- decimals: number of decimal places
- communityId:optional; ID of the community this token belongs to, if any
- marketDetails: object containing props like `currencyPrice` for the computed values below
- balances: submodel[ chainId:int, account:string, balance:BigIntString, iconUrl:string ]
- currentBalance: amount of tokens
- currencyBalance: e.g. `1000.42` in user's fiat currency
- currencyBalanceAsString: e.g. "1 000,42 CZK" formatted as a string according to the user's locale
- balanceAsString: `1.42` formatted as e.g. "1,42" in user's locale
- iconSource: string
**/
required property var assetsModel
/**
Expected model structure:
- groupName: group name (from collection or community name)
- icon: from imageUrl or mediaUrl
- type: can be "community" or "other"
- subitems: submodel of collectibles/collections of the group
- key: key of collection (community type) or collectible (other type)
- name: name of the subitem (of collectible or collection)
- balance: balance of collection (in case of community collectibles)
or collectible (in case of ERC-1155)
- icon: icon of the subitem
**/
required property var collectiblesModel
/**
Expected model structure:
- chainId: network chain id
- chainName: name of network
- iconUrl: network icon url
**/
required property var networksModel
/** input property holds header is being scrolled **/
property bool isScrolling
/** input property holds if the header is the sticky header **/
property bool isStickyHeader
/** property that exposes the selected network **/
readonly property int selectedNetworkChainId: selectedNetworkEntry.item.chainId
/** signal to propagate that an asset was selected **/
signal assetSelected(string key)
/** signal to propagate that a collection was selected **/
signal collectionSelected(string key)
/** signal to propagate that a collectible was selected **/
signal collectibleSelected(string key)
implicitHeight: sendModalTitleText.height
spacing: 8
// if not closed during scrolling they move with the header and it feels undesirable
onIsScrollingChanged: {
tokenSelector.popup.close()
networkFilter.control.popup.close()
}
StatusBaseText {
id: sendModalTitleText
Layout.preferredWidth: contentWidth
lineHeightMode: Text.FixedHeight
lineHeight: root.isStickyHeader ? 30 : 38
font.pixelSize: root.isStickyHeader ? 22 : 28
elide: Text.ElideRight
text: qsTr("Send")
}
TokenSelector {
id: tokenSelector
Layout.fillWidth: true
Layout.maximumWidth: implicitWidth
assetsModel: root.assetsModel
collectiblesModel: root.collectiblesModel
onCollectibleSelected: root.collectibleSelected(key)
onCollectionSelected: root.collectionSelected(key)
onAssetSelected: root.assetSelected(key)
}
// Horizontal spacer
RowLayout {}
StatusBaseText {
Layout.alignment: Qt.AlignRight
text: qsTr("On:")
color: Theme.palette.baseColor1
font.pixelSize: 13
lineHeight: 38
lineHeightMode: Text.FixedHeight
verticalAlignment: Text.AlignVCenter
visible: networkFilter.visible
}
NetworkFilter {
id: networkFilter
Layout.alignment: Qt.AlignTop
control.bottomPadding: 0
flatNetworks: root.networksModel
multiSelection: false
showSelectionIndicator: false
showTitle: false
}
ModelEntry {
id: selectedNetworkEntry
sourceModel: root.networksModel
key: "chainId"
value: networkFilter.selection[0]
}
}

View File

@ -0,0 +1,128 @@
import QtQuick 2.14
import QtGraphicalEffects 1.15
import StatusQ.Core.Theme 0.1
import StatusQ.Popups.Dialog 0.1
Rectangle {
id: root
/**
Expected model structure:
- tokensKey: unique string ID of the token (asset); e.g. "ETH" or contract address
- name: user visible token name (e.g. "Ethereum")
- symbol: user visible token symbol (e.g. "ETH")
- decimals: number of decimal places
- communityId:optional; ID of the community this token belongs to, if any
- marketDetails: object containing props like `currencyPrice` for the computed values below
- balances: submodel[ chainId:int, account:string, balance:BigIntString, iconUrl:string ]
- currentBalance: amount of tokens
- currencyBalance: e.g. `1000.42` in user's fiat currency
- currencyBalanceAsString: e.g. "1 000,42 CZK" formatted as a string according to the user's locale
- balanceAsString: `1.42` formatted as e.g. "1,42" in user's locale
- iconSource: string
**/
required property var assetsModel
/**
Expected model structure:
- groupName: group name (from collection or community name)
- icon: from imageUrl or mediaUrl
- type: can be "community" or "other"
- subitems: submodel of collectibles/collections of the group
- key: key of collection (community type) or collectible (other type)
- name: name of the subitem (of collectible or collection)
- balance: balance of collection (in case of community collectibles)
or collectible (in case of ERC-1155)
- icon: icon of the subitem
**/
required property var collectiblesModel
/**
Expected model structure:
- chainId: network chain id
- chainName: name of network
- iconUrl: network icon url
**/
required property var networksModel
/** this property decided if the sticky header is visible or not.
Not using visible property directly here as the animation on
implicitHeight doesnt work
**/
property bool isScrolling
/** property that exposes the selected network **/
readonly property int selectedNetworkChainId: sendModalHeader.selectedNetworkChainId
/** signal to propagate that an asset was selected **/
signal assetSelected(string key)
/** signal to propagate that a collection was selected **/
signal collectionSelected(string key)
/** signal to propagate that a collectible was selected **/
signal collectibleSelected(string key)
enabled: root.isScrolling
color: Theme.palette.baseColor3
radius: 8
implicitHeight: root.isScrolling ?
sendModalHeader.implicitHeight +
sendModalHeader.anchors.topMargin +
sendModalHeader.anchors.bottomMargin:
0
implicitWidth: sendModalHeader.implicitWidth +
sendModalHeader.anchors.leftMargin +
sendModalHeader.anchors.rightMargin
// Drawer animation for stickey heade
Behavior on implicitHeight {
NumberAnimation { duration: 350 }
}
// cover for the bottom rounded corners
Rectangle {
width: parent.width
height: parent.radius
anchors.bottom: parent.bottom
color: parent.color
}
SendModalHeader {
id: sendModalHeader
width: parent.width
anchors {
fill: parent
leftMargin: Theme.xlPadding
rightMargin: Theme.xlPadding
topMargin: 16
bottomMargin: 12
}
isStickyHeader: true
isScrolling: root.isScrolling
networksModel: root.networksModel
assetsModel: root.assetsModel
collectiblesModel: root.collectiblesModel
onCollectibleSelected: root.collectibleSelected(key)
onCollectionSelected: root.collectionSelected(key)
onAssetSelected: root.assetSelected(key)
}
StatusDialogDivider {
anchors.bottom: parent.bottom
width: parent.width
}
layer.enabled: true
layer.effect: DropShadow {
horizontalOffset: 0
verticalOffset: 2
samples: 37
color: Theme.palette.dropShadow
}
}

View File

@ -12,3 +12,5 @@ SignInfoBox 1.0 SignInfoBox.qml
SwapInputPanel 1.0 SwapInputPanel.qml
TokenSelectorPanel 1.0 TokenSelectorPanel.qml
WalletHeader 1.0 WalletHeader.qml
SendModalHeader 1.0 SendModalHeader.qml
StickySendModalHeader 1.0 StickySendModalHeader.qml

View File

@ -1,17 +1,206 @@
import QtQuick 2.15
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Popups.Dialog 0.1
import shared.popups.send.views 1.0
import shared.controls 1.0
import AppLayouts.Wallet.panels 1.0
StatusDialog {
id: popup
id: root
title: qsTr("Send")
/**
TODO: use the newly defined WalletAccountsSelectorAdaptor
in https://github.com/status-im/status-desktop/pull/16834
This will also remove watch only accounts from the list
Expected model structure:
- name: name of account
- address: wallet address
- color: color of the account
- emoji: emoji selected for the account
- currencyBalance: total currency balance in CurrencyAmount
- accountBalance: balance of selected token + selected chain
**/
required property var accountsModel
/**
Expected model structure:
- tokensKey: unique string ID of the token (asset); e.g. "ETH" or contract address
- name: user visible token name (e.g. "Ethereum")
- symbol: user visible token symbol (e.g. "ETH")
- decimals: number of decimal places
- communityId:optional; ID of the community this token belongs to, if any
- marketDetails: object containing props like `currencyPrice` for the computed values below
- balances: submodel[ chainId:int, account:string, balance:BigIntString, iconUrl:string ]
- currentBalance: amount of tokens
- currencyBalance: e.g. `1000.42` in user's fiat currency
- currencyBalanceAsString: e.g. "1 000,42 CZK" formatted as a string according to the user's locale
- balanceAsString: `1.42` formatted as e.g. "1,42" in user's locale
- iconSource: string
**/
required property var assetsModel
/**
Expected model structure:
- groupName: group name (from collection or community name)
- icon: from imageUrl or mediaUrl
- type: can be "community" or "other"
- subitems: submodel of collectibles/collections of the group
- key: key of collection (community type) or collectible (other type)
- name: name of the subitem (of collectible or collection)
- balance: balance of collection (in case of community collectibles)
or collectible (in case of ERC-1155)
- icon: icon of the subitem
**/
required property var collectiblesModel
/**
Expected model structure:
- chainId: network chain id
- chainName: name of network
- iconUrl: network icon url
**/
required property var networksModel
/** TODO: rethink property definitions needed to pre set values +
expose values to outside world **/
property int selectedChainId: sendModalHeader.selectedNetworkChainId
property string selectedAccountAddress: accountSelector.currentAccountAddress
QtObject {
id: d
readonly property bool isScrolling:
scrollView.flickable.contentY > sendModalHeader.height
}
width: 556
padding: 0
leftPadding: Theme.xlPadding
rightPadding: Theme.xlPadding
topMargin: margins + accountSelector.height + Theme.padding
background: StatusDialogBackground {
implicitHeight: 846
implicitWidth: 556
color: Theme.palette.baseColor3
}
Item {
id: sendModalcontentItem
anchors.fill: parent
anchors.top: parent.top
implicitWidth: parent.width
implicitHeight: scrollView.implicitHeight
// Floating account Selector
AccountSelectorHeader {
id: accountSelector
anchors.top: parent.top
anchors.topMargin: -accountSelector.height - Theme.padding
anchors.left: parent.left
anchors.leftMargin: -Theme.xlPadding
model: root.accountsModel
}
// Sticky header only visible when scrolling
StickySendModalHeader {
width: root.width
anchors.top: accountSelector.bottom
anchors.topMargin:Theme.padding
anchors.left: parent.left
anchors.leftMargin: -Theme.xlPadding
z: 1
networksModel: root.networksModel
assetsModel: root.assetsModel
collectiblesModel: root.collectiblesModel
isScrolling: d.isScrolling
onCollectibleSelected: console.log("collectible selected:", key)
onCollectionSelected: console.log("collection selected:", key)
onAssetSelected: console.log("asset selected:", key)
}
// Main scrollable Layout
StatusScrollView {
id: scrollView
anchors.fill: parent
anchors.topMargin: 28
contentWidth: availableWidth
padding: 0
StatusScrollBar.vertical {
id: verticalScrollbar
parent: sendModalcontentItem
x: sendModalcontentItem.width + root.rightPadding - verticalScrollbar.width
}
ColumnLayout {
id: scrollViewLayout
width: scrollView.availableWidth
spacing: 20
// Header that scrolls
SendModalHeader {
id: sendModalHeader
Layout.fillWidth: true
isScrolling: d.isScrolling
networksModel: root.networksModel
assetsModel: root.assetsModel
collectiblesModel: root.collectiblesModel
onCollectibleSelected: console.log("collectible selected:", key)
onCollectionSelected: console.log("collection selected:", key)
onAssetSelected: console.log("asset selected:", key)
}
// TODO: Remove these Dummy items added only to test dialog resizing
readonly property string longLoremIpsum: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
Text {
Layout.fillWidth: true
text: scrollViewLayout.longLoremIpsum.repeat(3)
wrapMode: Text.WordWrap
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 200
opacity: 0.2
color: "red"
}
Text {
Layout.fillWidth: true
text: scrollViewLayout.longLoremIpsum.repeat(3)
wrapMode: Text.WordWrap
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 200
opacity: 0.2
color: "red"
}
// End Dummy items
}
}
}
// TODO:: move to new location and rework if needed
footer: TransactionModalFooter {
width: parent.width
pending: false
nextButtonText: qsTr("Review Send")
maxFiatFees: "..."
totalTimeEstimate: "..."
}
}