refactoring(NetworkSelectItemDelegate): Remove backend dependency and clean the API

This is the first step in refactoring the NetworkFilter, by cleaning the base component that handles the check states.
This component supports multiple configurations:
1. Single selection with or without radio button
2. Multiple selection with or without checkbox
3. Automatic handling of the check state. The component will change the check state based on user clicks
4. Manual handling of the check state. The component will not change the check state, but offers a toggled signal and expects the user to change the check state based on external flows

+ Fix minor bugs
This commit is contained in:
Alex Jbanca 2024-06-12 11:52:11 +03:00 committed by Alex Jbanca
parent 5bdda2e6d9
commit 429203cd66
12 changed files with 566 additions and 110 deletions

View File

@ -54,6 +54,8 @@ SplitView {
sourceModel: NetworksModel.flatNetworks sourceModel: NetworksModel.flatNetworks
filters: ValueFilter { roleName: "isTest"; value: areTestNetworksEnabledCheckbox.checked } filters: ValueFilter { roleName: "isTest"; value: areTestNetworksEnabledCheckbox.checked }
} }
property var filteredFlatModel: networks
property bool areTestNetworksEnabled: areTestNetworksEnabledCheckbox.checked property bool areTestNetworksEnabled: areTestNetworksEnabledCheckbox.checked
function toggleNetwork(chainId) { function toggleNetwork(chainId) {
} }
@ -72,6 +74,13 @@ SplitView {
function processPreferredSharingNetworkToggle(preferredSharingNetworksArray, network) { function processPreferredSharingNetworkToggle(preferredSharingNetworksArray, network) {
console.warn("processPreferredSharingNetworkToggle :: preferredSharingNetworksArray ::", preferredSharingNetworksArray, "network :: ", network) console.warn("processPreferredSharingNetworkToggle :: preferredSharingNetworksArray ::", preferredSharingNetworksArray, "network :: ", network)
const chainId = network.chainId.toString()
if (preferredSharingNetworksArray.includes(chainId)) {
preferredSharingNetworksArray.splice(preferredSharingNetworksArray.indexOf(chainId), 1)
} else {
preferredSharingNetworksArray.push(chainId)
}
return [...preferredSharingNetworksArray]
} }
} }

View File

@ -9,6 +9,7 @@ import SortFilterProxyModel 0.2
import AppLayouts.stores 1.0 import AppLayouts.stores 1.0
import AppLayouts.Wallet.controls 1.0 import AppLayouts.Wallet.controls 1.0
import AppLayouts.Wallet.views 1.0
SplitView { SplitView {
id: root id: root
@ -32,10 +33,10 @@ SplitView {
roles: ["chainId", "layer", "chainName", "isTest", "isEnabled", "iconUrl", "shortName", "chainColor"] roles: ["chainId", "layer", "chainName", "isTest", "isEnabled", "iconUrl", "shortName", "chainColor"]
rolesOverride: [{ role: "enabledState", transform: (mD) => { rolesOverride: [{ role: "enabledState", transform: (mD) => {
return simulatedNimModel.areAllEnabled(sourceModel) return simulatedNimModel.areAllEnabled(sourceModel)
? NetworkSelectItemDelegate.UxEnabledState.AllEnabled ? NetworkSelectionView.UxEnabledState.AllEnabled
: mD.isEnabled : mD.isEnabled
? NetworkSelectItemDelegate.UxEnabledState.Enabled ? NetworkSelectionView.UxEnabledState.Enabled
: NetworkSelectItemDelegate.UxEnabledState.Disabled : NetworkSelectionView.UxEnabledState.Disabled
} }
}] }]
@ -47,11 +48,11 @@ SplitView {
let allEnabled = true let allEnabled = true
for (let i = 0; i < simulatedNimModel.count; i++) { for (let i = 0; i < simulatedNimModel.count; i++) {
const item = simulatedNimModel.get(i) const item = simulatedNimModel.get(i)
if(item.enabledState === NetworkSelectItemDelegate.UxEnabledState.Enabled) { if(item.enabledState === NetworkSelectionView.UxEnabledState.Enabled) {
if(item.chainId !== chainId) { if(item.chainId !== chainId) {
chainIdOnlyEnabled = false chainIdOnlyEnabled = false
} }
} else if(item.enabledState === NetworkSelectItemDelegate.UxEnabledState.Disabled) { } else if(item.enabledState === NetworkSelectionView.UxEnabledState.Disabled) {
if(item.chainId !== chainId) { if(item.chainId !== chainId) {
chainIdOnlyDisabled = false chainIdOnlyDisabled = false
} }
@ -66,15 +67,15 @@ SplitView {
for (let i = 0; i < simulatedNimModel.count; i++) { for (let i = 0; i < simulatedNimModel.count; i++) {
const item = simulatedNimModel.get(i) const item = simulatedNimModel.get(i)
if(allEnabled) { if(allEnabled) {
simulatedNimModel.setProperty(i, "enabledState", item.chainId === chainId ? NetworkSelectItemDelegate.UxEnabledState.Enabled : NetworkSelectItemDelegate.UxEnabledState.Disabled) simulatedNimModel.setProperty(i, "enabledState", item.chainId === chainId ? NetworkSelectionView.UxEnabledState.Enabled : NetworkSelectionView.UxEnabledState.Disabled)
} else if(chainIdOnlyEnabled || chainIdOnlyDisabled) { } else if(chainIdOnlyEnabled || chainIdOnlyDisabled) {
simulatedNimModel.setProperty(i, "enabledState", NetworkSelectItemDelegate.UxEnabledState.AllEnabled) simulatedNimModel.setProperty(i, "enabledState", NetworkSelectionView.UxEnabledState.AllEnabled)
} else if(item.chainId === chainId) { } else if(item.chainId === chainId) {
simulatedNimModel.setProperty(i, "enabledState", item.enabledState === NetworkSelectItemDelegate.UxEnabledState.Enabled simulatedNimModel.setProperty(i, "enabledState", item.enabledState === NetworkSelectionView.UxEnabledState.Enabled
? NetworkSelectItemDelegate.UxEnabledState.Disabled ? NetworkSelectionView.UxEnabledState.Disabled
: NetworkSelectItemDelegate.UxEnabledState.Enabled) : NetworkSelectionView.UxEnabledState.Enabled)
} }
const haveEnabled = item.enabledState !== NetworkSelectItemDelegate.UxEnabledState.Disabled const haveEnabled = item.enabledState !== NetworkSelectionView.UxEnabledState.Disabled
if(item.isEnabled !== haveEnabled) { if(item.isEnabled !== haveEnabled) {
simulatedNimModel.setProperty(i, "isEnabled", haveEnabled) simulatedNimModel.setProperty(i, "isEnabled", haveEnabled)
} }

View File

@ -0,0 +1,97 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml 2.15
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import AppLayouts.Wallet.controls 1.0
import Models 1.0
import Storybook 1.0
import SortFilterProxyModel 0.2
import utils 1.0
SplitView {
id: root
Item {
implicitWidth: delegate.width
NetworkSelectItemDelegate {
id: delegate
title: "Ethereum"
iconUrl: Style.svg("network/Network=Ethereum")
showIndicator: true
multiSelection: true
checkState: checkStateSelector.checkState
nextCheckState: checkState === Qt.Unchecked ? Qt.PartiallyChecked :
checkState === Qt.PartiallyChecked ? Qt.Checked : Qt.Unchecked
onCheckStateChanged: {
checkStateSelector.checkState = checkState
}
}
}
Pane {
id: pane
SplitView.fillWidth: true
ColumnLayout {
CheckBox {
text: "showIndicator"
checked: delegate.showIndicator
onCheckedChanged: {
delegate.showIndicator = checked
}
}
CheckBox {
text: "multiSelection"
checked: delegate.multiSelection
onCheckedChanged: {
delegate.multiSelection = checked
}
}
Label {
text: "title"
}
TextField {
text: delegate.title
onTextChanged: {
delegate.title = text
}
}
Label {
text: "iconUrl"
}
TextField {
text: delegate.iconUrl
onTextChanged: {
delegate.iconUrl = text
}
}
CheckBox {
id: checkStateSelector
text: "checkedState"
tristate: true
checked: true
onCheckStateChanged: {
if(delegate.checkState !== checkState) {
delegate.checkState = checkState
}
}
}
}
}
}
// category: Controls

View File

@ -10,6 +10,7 @@ import utils 1.0
import AppLayouts.Wallet.popups 1.0 import AppLayouts.Wallet.popups 1.0
import AppLayouts.Wallet.controls 1.0 import AppLayouts.Wallet.controls 1.0
import AppLayouts.Wallet.views 1.0
import AppLayouts.stores 1.0 import AppLayouts.stores 1.0
import Models 1.0 import Models 1.0
@ -219,10 +220,10 @@ SplitView {
roles: ["chainId", "layer", "chainName", "isTest", "isEnabled", "iconUrl", "shortName", "chainColor"] roles: ["chainId", "layer", "chainName", "isTest", "isEnabled", "iconUrl", "shortName", "chainColor"]
rolesOverride: [{ role: "enabledState", transform: (mD) => { rolesOverride: [{ role: "enabledState", transform: (mD) => {
return simulatedNimModel.areAllEnabled(sourceModel) return simulatedNimModel.areAllEnabled(sourceModel)
? NetworkSelectItemDelegate.UxEnabledState.AllEnabled ? NetworkSelectionView.UxEnabledState.AllEnabled
: mD.isEnabled : mD.isEnabled
? NetworkSelectItemDelegate.UxEnabledState.Enabled ? NetworkSelectionView.UxEnabledState.Enabled
: NetworkSelectItemDelegate.UxEnabledState.Disabled : NetworkSelectionView.UxEnabledState.Disabled
} }
}] }]
@ -234,11 +235,11 @@ SplitView {
let allEnabled = true let allEnabled = true
for (let i = 0; i < simulatedNimModel.count; i++) { for (let i = 0; i < simulatedNimModel.count; i++) {
const item = simulatedNimModel.get(i) const item = simulatedNimModel.get(i)
if(item.enabledState === NetworkSelectItemDelegate.UxEnabledState.Enabled) { if(item.enabledState === NetworkSelectionView.UxEnabledState.Enabled) {
if(item.chainId !== chainId) { if(item.chainId !== chainId) {
chainIdOnlyEnabled = false chainIdOnlyEnabled = false
} }
} else if(item.enabledState === NetworkSelectItemDelegate.UxEnabledState.Disabled) { } else if(item.enabledState === NetworkSelectionView.UxEnabledState.Disabled) {
if(item.chainId !== chainId) { if(item.chainId !== chainId) {
chainIdOnlyDisabled = false chainIdOnlyDisabled = false
} }
@ -253,15 +254,15 @@ SplitView {
for (let i = 0; i < simulatedNimModel.count; i++) { for (let i = 0; i < simulatedNimModel.count; i++) {
const item = simulatedNimModel.get(i) const item = simulatedNimModel.get(i)
if(allEnabled) { if(allEnabled) {
simulatedNimModel.setProperty(i, "enabledState", item.chainId === chainId ? NetworkSelectItemDelegate.UxEnabledState.Enabled : NetworkSelectItemDelegate.UxEnabledState.Disabled) simulatedNimModel.setProperty(i, "enabledState", item.chainId === chainId ? NetworkSelectionView.UxEnabledState.Enabled : NetworkSelectionView.UxEnabledState.Disabled)
} else if(chainIdOnlyEnabled || chainIdOnlyDisabled) { } else if(chainIdOnlyEnabled || chainIdOnlyDisabled) {
simulatedNimModel.setProperty(i, "enabledState", NetworkSelectItemDelegate.UxEnabledState.AllEnabled) simulatedNimModel.setProperty(i, "enabledState", NetworkSelectionView.UxEnabledState.AllEnabled)
} else if(item.chainId === chainId) { } else if(item.chainId === chainId) {
simulatedNimModel.setProperty(i, "enabledState", item.enabledState === NetworkSelectItemDelegate.UxEnabledState.Enabled simulatedNimModel.setProperty(i, "enabledState", item.enabledState === NetworkSelectionView.UxEnabledState.Enabled
? NetworkSelectItemDelegate.UxEnabledState.Disabled ? NetworkSelectionView.UxEnabledState.Disabled
:NetworkSelectItemDelegate.UxEnabledState.Enabled) :NetworkSelectionView.UxEnabledState.Enabled)
} }
const haveEnabled = item.enabledState !== NetworkSelectItemDelegate.UxEnabledState.Disabled const haveEnabled = item.enabledState !== NetworkSelectionView.UxEnabledState.Disabled
if(item.isEnabled !== haveEnabled) { if(item.isEnabled !== haveEnabled) {
simulatedNimModel.setProperty(i, "isEnabled", haveEnabled) simulatedNimModel.setProperty(i, "isEnabled", haveEnabled)
} }

View File

@ -0,0 +1,260 @@
import QtQuick 2.15
import QtTest 1.15
import AppLayouts.Wallet.controls 1.0
import utils 1.0
Item {
id: root
width: 600
height: 400
Component {
id: componentUnderTest
NetworkSelectItemDelegate {
anchors.centerIn: parent
title: "Ethereum"
iconUrl: Style.svg("network/Network=Ethereum")
onToggled: root.onToggledHandler()
}
}
SignalSpy {
id: toggledSpy
target: controlUnderTest
signalName: "toggled"
}
SignalSpy {
id: checkStateChangedSpy
target: controlUnderTest
signalName: "checkStateChanged"
}
property NetworkSelectItemDelegate controlUnderTest: null
property var onToggledHandler: function(){}
property int externalCheckState: Qt.Unchecked
TestCase {
name: "NetworkSelectItemDelegate"
when: windowShown
function init() {
controlUnderTest = createTemporaryObject(componentUnderTest, root)
toggledSpy.clear()
checkStateChangedSpy.clear()
onToggledHandler = function() {}
}
function test_basicGeometry() {
verify(!!controlUnderTest)
verify(controlUnderTest.width > 0)
verify(controlUnderTest.height > 0)
}
function test_title() {
verify(!!controlUnderTest)
compare(controlUnderTest.title, "Ethereum")
controlUnderTest.title = "Polygon"
compare(controlUnderTest.title, "Polygon")
controlUnderTest.title = ""
compare(controlUnderTest.title, "")
controlUnderTest.title = "Ethereum"
}
function test_icon() {
verify(!!controlUnderTest)
compare(controlUnderTest.iconUrl, Style.svg("network/Network=Ethereum"))
compare(findChild(controlUnderTest, "statusRoundImage").image.source, Style.svg("network/Network=Ethereum"))
controlUnderTest.iconUrl = Style.svg("network/Network=Polygon")
compare(controlUnderTest.iconUrl, Style.svg("network/Network=Polygon"))
compare(findChild(controlUnderTest, "statusRoundImage").image.source, Style.svg("network/Network=Polygon"))
}
function test_indicatorConfig() {
verify(!!controlUnderTest)
verify(!!findChild(controlUnderTest, "networkSelectionRadioButton_Ethereum"))
verify(!findChild(controlUnderTest, "networkSelectionCheckbox_Ethereum"))
compare(controlUnderTest.showIndicator, true)
compare(controlUnderTest.multiSelection, false)
//changing to multiselect -> indicator switches to checkbox
controlUnderTest.multiSelection = true
waitForRendering(controlUnderTest)
waitForItemPolished(controlUnderTest)
verify(!!findChild(controlUnderTest, "networkSelectionCheckbox_Ethereum"))
verify(!findChild(controlUnderTest, "networkSelectionRadioButton_Ethereum"))
//changing removing indicator
controlUnderTest.showIndicator = false
waitForRendering(controlUnderTest)
waitForItemPolished(controlUnderTest)
verify(!findChild(controlUnderTest, "networkSelectionCheckbox_Ethereum"))
verify(!findChild(controlUnderTest, "networkSelectionRadioButton_Ethereum"))
}
function test_toggleByClick() {
verify(!!controlUnderTest)
mouseClick(controlUnderTest)
tryCompare(toggledSpy, "count", 1)
const image = findChild(controlUnderTest, "statusRoundImage")
mouseClick(image)
tryCompare(toggledSpy, "count", 2)
const radioButton = findChild(controlUnderTest, "networkSelectionRadioButton_Ethereum")
mouseClick(radioButton)
tryCompare(toggledSpy, "count", 3)
controlUnderTest.multiSelection = true
waitForItemPolished(controlUnderTest)
const checkBox = findChild(controlUnderTest, "networkSelectionCheckbox_Ethereum")
mouseClick(checkBox)
tryCompare(toggledSpy, "count", 4)
}
function test_autoCheckStateChanges() {
verify(!!controlUnderTest)
compare(controlUnderTest.checkState, Qt.Unchecked)
mouseClick(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Checked)
mouseClick(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Unchecked)
const radioButton = findChild(controlUnderTest, "networkSelectionRadioButton_Ethereum")
mouseClick(radioButton)
compare(controlUnderTest.checkState, Qt.Checked)
mouseClick(radioButton)
compare(controlUnderTest.checkState, Qt.Unchecked)
controlUnderTest.multiSelection = true
waitForItemPolished(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Unchecked)
const checkBox = findChild(controlUnderTest, "networkSelectionCheckbox_Ethereum")
mouseClick(checkBox)
waitForItemPolished(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Checked)
mouseClick(checkBox)
compare(controlUnderTest.checkState, Qt.Unchecked)
mouseClick(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Checked)
mouseClick(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Unchecked)
}
function test_manualCheckStateChanges() {
verify(!!controlUnderTest)
// checkState is not bound to nextCheckState => no automatic check changes
controlUnderTest.nextCheckState = Qt.binding(() => controlUnderTest.checkState)
compare(controlUnderTest.checkState, Qt.Unchecked)
mouseClick(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Unchecked)
let radioButton = findChild(controlUnderTest, "networkSelectionRadioButton_Ethereum")
mouseClick(radioButton)
compare(controlUnderTest.checkState, Qt.Unchecked)
controlUnderTest.multiSelection = true
waitForItemPolished(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Unchecked)
let checkBox = findChild(controlUnderTest, "networkSelectionCheckbox_Ethereum")
mouseClick(checkBox)
compare(controlUnderTest.checkState, Qt.Unchecked)
controlUnderTest.multiSelection = false
waitForItemPolished(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Unchecked)
root.onToggledHandler = function() {
controlUnderTest.checkState = controlUnderTest.checkState === Qt.Checked ? Qt.Unchecked : Qt.Checked
}
mouseClick(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Checked)
radioButton = findChild(controlUnderTest, "networkSelectionRadioButton_Ethereum")
mouseClick(radioButton)
compare(controlUnderTest.checkState, Qt.Unchecked)
controlUnderTest.multiSelection = true
root.onToggledHandler = function() {
controlUnderTest.checkState = controlUnderTest.checkState === Qt.Unchecked ? Qt.PartiallyChecked :
controlUnderTest.checkState === Qt.Checked ? Qt.Unchecked : Qt.Checked
}
mouseClick(controlUnderTest)
compare(controlUnderTest.checkState, Qt.PartiallyChecked)
mouseClick(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Checked)
mouseClick(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Unchecked)
checkBox = findChild(controlUnderTest, "networkSelectionCheckbox_Ethereum")
mouseClick(checkBox)
compare(controlUnderTest.checkState, Qt.PartiallyChecked)
mouseClick(checkBox)
compare(controlUnderTest.checkState, Qt.Checked)
mouseClick(checkBox)
compare(controlUnderTest.checkState, Qt.Unchecked)
}
function test_checkStateBindings() {
verify(!!controlUnderTest)
compare(controlUnderTest.checkState, Qt.Unchecked)
compare(root.externalCheckState, Qt.Unchecked)
controlUnderTest.checkState = Qt.binding(() => root.externalCheckState)
compare(controlUnderTest.checkState, root.externalCheckState)
tryCompare(checkStateChangedSpy, "count", 0)
root.externalCheckState = Qt.Checked
compare(controlUnderTest.checkState, Qt.Checked)
tryCompare(checkStateChangedSpy, "count", 1)
root.externalCheckState = Qt.Unchecked
compare(controlUnderTest.checkState, Qt.Unchecked)
tryCompare(checkStateChangedSpy, "count", 2)
}
function test_interactiveConfig() {
verify(!!controlUnderTest)
compare(controlUnderTest.interactive, true)
controlUnderTest.interactive = false
compare(controlUnderTest.checkState, Qt.Unchecked)
mouseClick(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Unchecked)
let radioButton = findChild(controlUnderTest, "networkSelectionRadioButton_Ethereum")
mouseClick(radioButton)
compare(controlUnderTest.checkState, Qt.Unchecked)
controlUnderTest.multiSelection = true
waitForItemPolished(controlUnderTest)
mouseClick(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Unchecked)
let checkBox = findChild(controlUnderTest, "networkSelectionCheckbox_Ethereum")
mouseClick(checkBox)
compare(controlUnderTest.checkState, Qt.Unchecked)
controlUnderTest.showIndicator = false
mouseClick(controlUnderTest)
compare(controlUnderTest.checkState, Qt.Unchecked)
mouseMove(controlUnderTest, controlUnderTest.width / 2, controlUnderTest.height / 2)
waitForRendering(controlUnderTest)
waitForItemPolished(controlUnderTest)
compare(controlUnderTest.sensor.containsMouse, true)
// manual selection works
controlUnderTest.checkState = Qt.Checked
compare(controlUnderTest.checkState, Qt.Checked)
controlUnderTest.checkState = Qt.Unchecked
compare(controlUnderTest.checkState, Qt.Unchecked)
}
}
}

View File

@ -50,6 +50,7 @@ Loader {
StatusRoundedImage { StatusRoundedImage {
id: statusRoundImage id: statusRoundImage
objectName: "statusRoundImage"
width: parent.width width: parent.width
height: parent.height height: parent.height
image.source: root.asset.isImage ? root.asset.name : "" image.source: root.asset.isImage ? root.asset.name : ""
@ -80,6 +81,7 @@ Loader {
id: roundedIcon id: roundedIcon
StatusRoundIcon { StatusRoundIcon {
objectName: "statusRoundIcon"
asset.bgRadius: root.asset.bgRadius asset.bgRadius: root.asset.bgRadius
asset.bgWidth: root.asset.bgWidth asset.bgWidth: root.asset.bgWidth
asset.bgHeight: root.asset.bgHeight asset.bgHeight: root.asset.bgHeight

View File

@ -59,7 +59,8 @@ StatusComboBox {
root.multiSelection root.multiSelection
NetworkModelHelpers.getChainIconUrl(root.flatNetworks, d.currentIndex) NetworkModelHelpers.getChainIconUrl(root.flatNetworks, d.currentIndex)
} }
readonly property bool allSelected: enabledFlatNetworks.count === root.flatNetworks.count readonly property bool allSelected: root.preferredNetworksMode ? root.preferredSharingNetworks.length === root.flatNetworks.count :
enabledFlatNetworks.count === root.flatNetworks.count
readonly property bool noneSelected: enabledFlatNetworks.count === 0 readonly property bool noneSelected: enabledFlatNetworks.count === 0
// Persist selection between selectPopupLoader reloads // Persist selection between selectPopupLoader reloads
@ -67,7 +68,14 @@ StatusComboBox {
property SortFilterProxyModel enabledFlatNetworks: SortFilterProxyModel { property SortFilterProxyModel enabledFlatNetworks: SortFilterProxyModel {
sourceModel: root.flatNetworks sourceModel: root.flatNetworks
filters: ValueFilter { roleName: "isEnabled"; value: true; enabled: !root.preferredNetworksMode } filters: [
ValueFilter { roleName: "isEnabled"; value: true; enabled: !root.preferredNetworksMode },
FastExpressionFilter {
expression: root.preferredSharingNetworks.includes(chainId.toString())
expectedRoles: ["chainId"]
enabled: root.preferredNetworksMode
}
]
} }
} }
@ -128,7 +136,7 @@ StatusComboBox {
visible: (!d.allSelected || !root.showAllSelectedText) && chainRepeater.count > 0 visible: (!d.allSelected || !root.showAllSelectedText) && chainRepeater.count > 0
Repeater { Repeater {
id: chainRepeater id: chainRepeater
model: root.preferredNetworksMode ? root.flatNetworks: root.multiSelection ? d.enabledFlatNetworks: [] model: root.multiSelection ? d.enabledFlatNetworks: []
delegate: StatusRoundedImage { delegate: StatusRoundedImage {
id: delegateItem id: delegateItem
width: 24 width: 24

View File

@ -1,96 +1,119 @@
import QtQuick 2.15 import QtQuick 2.15
import QtQml 2.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
import StatusQ.Components 0.1 import StatusQ.Components 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0 import utils 1.0
import "../stores/NetworkSelectPopup"
StatusListItem { StatusListItem {
id: root id: root
property var networkModel: null // input/output property
property var singleSelection property int checkState: Qt.Unchecked
property var radioButtonGroup
property bool useEnabledRole: true
property bool showCheckboxes: true
property bool showRadioButtons: true
// Needed for preferred sharing networks //input property
property bool preferredNetworksMode: false // Defines the next state of the checkbox when clicked
property var preferredSharingNetworks: [] // By default, it toggles between checked and unchecked
property bool allChecked: true property int nextCheckState: checkState === Qt.Checked ? Qt.Unchecked : Qt.Checked
signal toggleNetwork(var network, var model, int index) required property string iconUrl
property bool showIndicator: true
property bool multiSelection: false
property bool interactive: true
/// Mirrors Nim's UxEnabledState enum from networks/item.nim // output signal
enum UxEnabledState { // Emitted when the checkbox is clicked
Enabled, // This signal is useful when the check state needs to change
AllEnabled, // only after processing the toggle event E.g backend call
Disabled signal toggled
}
objectName: model.chainName objectName: root.title
title: model.chainName
asset.height: 24 asset.height: 24
asset.width: 24 asset.width: 24
asset.isImage: true asset.isImage: true
asset.name: Style.svg(model.iconUrl) asset.name: root.iconUrl
onClicked: { onClicked: {
if(!root.singleSelection.enabled) { d.toggled()
checkBox.nextCheckState() }
} else if(!radioButton.checked) { // Don't allow uncheck
root.toggleNetwork(({chainId: model.chainId, chainName: model.chainName, iconUrl: model.iconUrl}), root.networkModel, model.index) leftPadding: 16
rightPadding: 16
statusListItemTitleArea.anchors.leftMargin: 12
highlighted: (d.checkState !== Qt.Unchecked && !showIndicator)
Binding on bgColor {
when: highlighted && !root.sensor.containsMouse
value: root.interactive ? Theme.palette.baseColor4 : Theme.palette.primaryColor3
restoreMode: Binding.RestoreBindingOrValue
}
onCheckStateChanged: {
if (checkState !== d.checkState) {
d.checkState = checkState
} }
} }
leftPadding: 12
rightPadding: 0
statusListItemTitleArea.anchors.leftMargin: 12
components: [ components: [
StatusCheckBox { Loader {
id: checkBox id: indicatorLoader
objectName: "networkSelectionCheckbox_" + model.chainName sourceComponent: root.multiSelection ? checkBoxComponent : radioButtonComponent
tristate: true active: root.showIndicator
visible: !root.singleSelection.enabled && root.showCheckboxes
checkState: {
if(root.preferredNetworksMode) {
return root.allChecked ? Qt.PartiallyChecked : preferredSharingNetworks.includes(model.chainId.toString()) ? Qt.Checked : Qt.Unchecked
}
else if(root.useEnabledRole) {
return model.isEnabled ? Qt.Checked : Qt.Unchecked
} else if (model.enabledState === NetworkSelectItemDelegate.UxEnabledState.Enabled) {
return Qt.Checked
} else {
if( model.enabledState === NetworkSelectItemDelegate.UxEnabledState.AllEnabled) {
return Qt.PartiallyChecked
} else {
return Qt.Unchecked
}
}
}
nextCheckState: () => {
Qt.callLater(root.toggleNetwork, model, root.networkModel, model.index)
return Qt.PartiallyChecked
}
},
StatusRadioButton {
id: radioButton
visible: root.singleSelection.enabled && root.showRadioButtons
size: StatusRadioButton.Size.Large
ButtonGroup.group: root.radioButtonGroup
checked: root.singleSelection.currentModel === root.networkModel && root.singleSelection.currentIndex === model.index
onToggled: {
if(checked) {
root.toggleNetwork(({chainId: model.chainId, chainName: model.chainName, iconUrl: model.iconUrl}), root.networkModel, model.index)
}
}
} }
] ]
Component {
id: checkBoxComponent
StatusCheckBox {
id: checkBox
objectName: "networkSelectionCheckbox_" + root.title
checkState: d.checkState
tristate: true
nextCheckState: () => d.checkState
enabled: root.interactive
onClicked: {
d.toggled()
}
}
}
Component {
id: radioButtonComponent
StatusRadioButton {
id: radioButton
objectName: "networkSelectionRadioButton_" + root.title
size: StatusRadioButton.Size.Large
checked: d.checkState !== Qt.Unchecked
enabled: root.interactive
onClicked: {
d.toggled()
}
}
}
QtObject {
id: d
property int checkState: root.checkState
function toggled() {
if (!root.interactive) {
return
}
d.checkState = root.nextCheckState
root.toggled()
}
onCheckStateChanged: {
if (checkState !== root.checkState) {
root.checkState = checkState
}
}
}
} }

View File

@ -75,7 +75,7 @@ StatusDialog {
preferredSharingNetworks: root.preferredSharingNetworks preferredSharingNetworks: root.preferredSharingNetworks
useEnabledRole: root.useEnabledRole useEnabledRole: root.useEnabledRole
singleSelection: d.singleSelection singleSelection: d.singleSelection
onToggleNetwork: { onToggleNetwork: (network, index) => {
root.toggleNetwork(network, index) root.toggleNetwork(network, index)
if(d.singleSelection.enabled) if(d.singleSelection.enabled)
close() close()

View File

@ -136,6 +136,13 @@ StatusDialog {
networkFilter.setChain(root.swapInputParamsForm.selectedNetworkChainId) networkFilter.setChain(root.swapInputParamsForm.selectedNetworkChainId)
} }
} }
Connections {
target: root.swapInputParamsForm
function onSelectedNetworkChainIdChanged() {
networkFilter.setChain(root.swapInputParamsForm.selectedNetworkChainId)
}
}
} }
} }

View File

@ -1,6 +1,7 @@
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Controls 2.15 import QtQuick.Controls 2.15
import StatusQ 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
@ -24,21 +25,71 @@ StatusListView {
signal toggleNetwork(var network, int index) signal toggleNetwork(var network, int index)
/// Mirrors Nim's UxEnabledState enum from networks/item.nim
enum UxEnabledState {
Enabled,
AllEnabled,
Disabled
}
model: root.flatNetworks model: root.flatNetworks
delegate: NetworkSelectItemDelegate { delegate: NetworkSelectItemDelegate {
id: delegateItem
required property var model
readonly property int multiSelectCheckState: {
if(root.preferredNetworksMode) {
return root.preferredSharingNetworks.length === root.count ?
Qt.PartiallyChecked :
root.preferredSharingNetworks.includes(model.chainId.toString()) ? Qt.Checked : Qt.Unchecked
}
else if(root.useEnabledRole) {
return model.isEnabled ? Qt.Checked : Qt.Unchecked
} else if (model.enabledState === NetworkSelectionView.UxEnabledState.Enabled) {
return Qt.Checked
} else {
if( model.enabledState === NetworkSelectionView.UxEnabledState.AllEnabled) {
return Qt.PartiallyChecked
} else {
return Qt.Unchecked
}
}
}
readonly property int singleSelectCheckState: {
if (root.singleSelection.currentModel === root.model && root.singleSelection.currentIndex === model.index)
return Qt.Checked
return Qt.Unchecked
}
implicitHeight: 48 implicitHeight: 48
implicitWidth: root.width implicitWidth: root.width
radioButtonGroup: radioBtnGroup title: model.chainName
networkModel: root.model iconUrl: Style.svg(model.iconUrl)
useEnabledRole: root.useEnabledRole showIndicator: (multiSelection && root.showCheckboxes) || (!multiSelection && root.showRadioButtons)
singleSelection: root.singleSelection multiSelection: !root.singleSelection.enabled
onToggleNetwork: (network, model, index) => root.toggleNetwork(network, index)
preferredNetworksMode: root.preferredNetworksMode Binding on checkState {
preferredSharingNetworks: root.preferredSharingNetworks when: root.singleSelection.enabled
allChecked: root.preferredSharingNetworks.length === root.count value: singleSelectCheckState
showCheckboxes: root.showCheckboxes }
showRadioButtons: root.showRadioButtons
Binding on checkState {
when: !root.singleSelection.enabled
value: multiSelectCheckState
}
nextCheckState: checkState
onToggled: {
if(!root.singleSelection.enabled) {
Qt.callLater(root.toggleNetwork, delegateItem.model, delegateItem.model.index)
} else if(!checkState !== Qt.Checked) { // Don't allow uncheck
checkState = checkState === Qt.Checked ? Qt.Unchecked : Qt.Checked
root.toggleNetwork(delegateItem.model, model.index)
}
}
} }
section { section {
@ -62,8 +113,4 @@ StatusListView {
} }
} }
} }
ButtonGroup {
id: radioBtnGroup
}
} }

View File

@ -1,5 +1,6 @@
AssetsDetailView 1.0 AssetsDetailView.qml AssetsDetailView 1.0 AssetsDetailView.qml
CollectiblesView 1.0 CollectiblesView.qml CollectiblesView 1.0 CollectiblesView.qml
NetworkSelectionView 1.0 NetworkSelectionView.qml
SavedAddresses 1.0 SavedAddresses.qml SavedAddresses 1.0 SavedAddresses.qml
TokenSelectorAssetDelegate 1.0 TokenSelectorAssetDelegate.qml TokenSelectorAssetDelegate 1.0 TokenSelectorAssetDelegate.qml
TokenSelectorView 1.0 TokenSelectorView.qml TokenSelectorView 1.0 TokenSelectorView.qml