272 lines
7.0 KiB
QML
272 lines
7.0 KiB
QML
import QtQuick 2.15
|
|
import QtQuick.Controls 2.15
|
|
import QtQuick.Layouts 1.15
|
|
|
|
import StatusQ 0.1
|
|
import Storybook 1.0
|
|
|
|
import SortFilterProxyModel 0.2
|
|
|
|
Item {
|
|
id: root
|
|
|
|
readonly property int numberOfTokens: 2000
|
|
|
|
readonly property var colors: [
|
|
"purple", "lightgreen", "red", "blue", "darkgreen"
|
|
]
|
|
|
|
function getRandomInt(max) {
|
|
return Math.floor(Math.random() * max);
|
|
}
|
|
|
|
ListModel {
|
|
id: networksModel
|
|
|
|
ListElement {
|
|
chainId: "1"
|
|
name: "Mainnet"
|
|
color: "purple"
|
|
}
|
|
ListElement {
|
|
chainId: "2"
|
|
name: "Optimism"
|
|
color: "lightgreen"
|
|
}
|
|
ListElement {
|
|
chainId: "3"
|
|
name: "Status"
|
|
color: "red"
|
|
}
|
|
ListElement {
|
|
chainId: "4"
|
|
name: "Abitrum"
|
|
color: "blue"
|
|
}
|
|
ListElement {
|
|
chainId: "5"
|
|
name: "Sepolia"
|
|
color: "darkgreen"
|
|
}
|
|
}
|
|
|
|
ListModel {
|
|
id: tokensModel
|
|
|
|
Component.onCompleted: {
|
|
// Populate model with given number of tokens containing random
|
|
// balances
|
|
const numberOfTokens = root.numberOfTokens
|
|
const tokens = []
|
|
|
|
const chainIds = []
|
|
|
|
for (let n = 0; n < networksModel.count; n++)
|
|
chainIds.push(networksModel.get(n).chainId)
|
|
|
|
for (let i = 0; i < numberOfTokens; i++) {
|
|
const balances = []
|
|
const numberOfBalances = 1 + getRandomInt(networksModel.count)
|
|
const chainIdsCpy = [...chainIds]
|
|
|
|
for (let i = 0; i < numberOfBalances; i++) {
|
|
const chainId = chainIdsCpy.splice(
|
|
getRandomInt(chainIdsCpy.length), 1)[0]
|
|
|
|
balances.push({
|
|
chainId: chainId,
|
|
balance: 1 + getRandomInt(200)
|
|
})
|
|
}
|
|
|
|
tokens.push({ name: `Token ${i + 1}`, balances })
|
|
}
|
|
|
|
append(tokens)
|
|
}
|
|
}
|
|
|
|
// Proxy model joining networksModel to submodels under "balances" role.
|
|
// Additionally submodel is filtered and sorted via SFPM. Submodel is
|
|
// accessible via "submodel" context property.
|
|
SubmodelProxyModel {
|
|
id: submodelProxyModel
|
|
|
|
sourceModel: tokensModel
|
|
|
|
delegateModel: SortFilterProxyModel {
|
|
readonly property LeftJoinModel joinModel: LeftJoinModel {
|
|
leftModel: submodel
|
|
rightModel: networksModel
|
|
|
|
joinRole: "chainId"
|
|
}
|
|
|
|
sourceModel: joinModel
|
|
|
|
filters: ExpressionFilter {
|
|
expression: balance >= thresholdSlider.value
|
|
}
|
|
|
|
sorters: RoleSorter {
|
|
roleName: "name"
|
|
enabled: sortCheckBox.checked
|
|
}
|
|
}
|
|
|
|
submodelRoleName: "balances"
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
anchors.margins: 10
|
|
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
// ListView consuming model don't have to do any transformation
|
|
// of the submodels internally because it's handled externally via
|
|
// SubmodelProxyModel.
|
|
ListView {
|
|
id: listView
|
|
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
reuseItems: true
|
|
|
|
ScrollBar.vertical: ScrollBar {}
|
|
|
|
clip: true
|
|
spacing: 18
|
|
|
|
model: submodelProxyModel
|
|
|
|
delegate: ColumnLayout {
|
|
id: delegateRoot
|
|
|
|
width: ListView.view.width
|
|
height: 46
|
|
spacing: 0
|
|
|
|
readonly property var balances: model.balances
|
|
|
|
Label {
|
|
Layout.fillWidth: true
|
|
text: model.name
|
|
font.bold: true
|
|
}
|
|
|
|
RowLayout {
|
|
spacing: 14
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Repeater {
|
|
model: delegateRoot.balances
|
|
|
|
Rectangle {
|
|
width: label.implicitWidth * 1.5
|
|
height: label.implicitHeight * 2
|
|
|
|
color: "transparent"
|
|
border.width: 2
|
|
border.color: model.color
|
|
|
|
Label {
|
|
id: label
|
|
|
|
anchors.centerIn: parent
|
|
|
|
text: `${model.name} (${model.balance})`
|
|
font.pixelSize: 10
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.preferredWidth: 1
|
|
Layout.fillHeight: true
|
|
Layout.rightMargin: 20
|
|
|
|
color: "lightgray"
|
|
}
|
|
|
|
ListView {
|
|
Layout.preferredWidth: 150
|
|
Layout.fillHeight: true
|
|
|
|
spacing: 20
|
|
|
|
model: networksModel
|
|
|
|
delegate: ColumnLayout {
|
|
width: ListView.view.width
|
|
|
|
Label {
|
|
Layout.fillWidth: true
|
|
text: model.name
|
|
font.bold: true
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.preferredWidth: changeColorButton.width
|
|
Layout.preferredHeight: 10
|
|
|
|
color: model.color
|
|
}
|
|
|
|
Button {
|
|
id: changeColorButton
|
|
|
|
text: "Change color"
|
|
|
|
onClicked: {
|
|
const currentIdx = root.colors.indexOf(model.color)
|
|
const numberOfColors = root.colors.length
|
|
const nextIdx = (currentIdx + 1) % numberOfColors
|
|
|
|
networksModel.setProperty(model.index, "color",
|
|
root.colors[nextIdx])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MenuSeparator {
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
RowLayout {
|
|
Label {
|
|
text: `Number of tokens: ${listView.count}, minimum balance:`
|
|
}
|
|
|
|
Slider {
|
|
id: thresholdSlider
|
|
|
|
from: 0
|
|
to: 201
|
|
stepSize: 1
|
|
}
|
|
|
|
Label {
|
|
text: thresholdSlider.value
|
|
}
|
|
|
|
CheckBox {
|
|
id: sortCheckBox
|
|
|
|
text: "sort networks by name"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// category: Models
|