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 StatusQ.Popups 0.1 import utils 1.0 import AppLayouts.Wallet.popups 1.0 import AppLayouts.Wallet.controls 1.0 import AppLayouts.stores 1.0 import Models 1.0 import SortFilterProxyModel 0.2 SplitView { id: root Pane { SplitView.fillWidth: true SplitView.fillHeight: true ColumnLayout { id: controlLayout anchors.fill: parent // Leave some space so that the popup will be opened without accounting for Layer ColumnLayout { Layout.maximumHeight: 50 } NetworkFilter { id: networkFilter Layout.preferredWidth: 200 Layout.preferredHeight: 100 Layout.alignment: Qt.AlignHCenter allNetworks: simulatedNimModel layer1Networks: SortFilterProxyModel { function rowData(index, propName) { return get(index)[propName] } sourceModel: simulatedNimModel filters: ValueFilter { roleName: "layer"; value: 1; } } layer2Networks: SortFilterProxyModel { sourceModel: simulatedNimModel filters: [ValueFilter { roleName: "layer"; value: 2; }, ValueFilter { roleName: "isTest"; value: false; }] } testNetworks: SortFilterProxyModel { sourceModel: simulatedNimModel filters: [ValueFilter { roleName: "layer"; value: 2; }, ValueFilter { roleName: "isTest"; value: true; }] } enabledNetworks: SortFilterProxyModel { sourceModel: simulatedNimModel filters: ValueFilter { roleName: "isEnabled"; value: true; } } onToggleNetwork: (network) => { if(multiSelection) { simulatedNimModel.toggleNetwork(network) } else { lastSingleSelectionLabel.text = `[${network.chainName}] (NL) - ID: ${network.chainId}, Icon: ${network.iconUrl}` } } multiSelection: multiSelectionCheckbox.checked isChainVisible: isChainVisibleCheckbox.checked } // Dummy item to make space for popup Item { id: popupPlaceholder Layout.preferredWidth: networkSelectPopup.width Layout.preferredHeight: networkSelectPopup.height NetworkSelectPopup { id: networkSelectPopup layer1Networks: networkFilter.layer1Networks layer2Networks: networkFilter.layer2Networks testNetworks: networkFilter.testNetworks useEnabledRole: false visible: true closePolicy: Popup.NoAutoClose // Simulates a network toggle onToggleNetwork: (network, networkModel, index) => simulatedNimModel.toggleNetwork(network) } } ColumnLayout { Layout.preferredHeight: 30 Layout.maximumHeight: 30 } RowLayout { Button { text: "Single Selection Popup" onClicked: selectPopupLoader.active = true } Label { id: lastSingleSelectionLabel text: "-" } } Item { id: singleSelectionPopupPlaceholder Layout.preferredWidth: selectPopupLoader.item ? selectPopupLoader.item.width : 0 Layout.preferredHeight: selectPopupLoader.item ? selectPopupLoader.item.height : 0 property var currentModel: networkFilter.layer2Networks property int currentIndex: 0 Loader { id: selectPopupLoader active: false sourceComponent: NetworkSelectPopup { layer1Networks: networkFilter.layer1Networks layer2Networks: networkFilter.layer2Networks testNetworks: networkFilter.testNetworks singleSelection { enabled: true currentModel: singleSelectionPopupPlaceholder.currentModel currentIndex: singleSelectionPopupPlaceholder.currentIndex } onToggleNetwork: (network, networkModel, index) => { lastSingleSelectionLabel.text = `[${network.chainName}] - ID: ${network.chainId}, Icon: ${network.iconUrl}` singleSelectionPopupPlaceholder.currentModel = networkModel singleSelectionPopupPlaceholder.currentIndex = index } onClosed: selectPopupLoader.active = false } onLoaded: item.open() } } // Vertical separator ColumnLayout {} } } Pane { SplitView.minimumWidth: 300 SplitView.fillWidth: true SplitView.minimumHeight: 300 ColumnLayout { anchors.fill: parent ListView { id: allNetworksListView Layout.fillWidth: true Layout.fillHeight: true model: simulatedNimModel delegate: ItemDelegate { width: allNetworksListView.width implicitHeight: delegateRowLayout.implicitHeight highlighted: ListView.isCurrentItem RowLayout { id: delegateRowLayout anchors.fill: parent Column { Layout.margins: 5 spacing: 3 Label { text: model.chainName } Row { spacing: 5 Label { text: `${model.shortName}` } Label { text: `ID ${model.chainId}` } CheckBox { checkState: model.isEnabled ? Qt.Checked : Qt.Unchecked tristate: true nextCheckState: () => { const nextEnabled = (checkState !== Qt.Checked) availableNetworks.sourceModel.setProperty(availableNetworks.mapToSource(index), "isEnabled", nextEnabled) Qt.callLater(() => { simulatedNimModel.cloneModel(availableNetworks) }) return nextEnabled ? Qt.Checked : Qt.Unchecked } } } } } onClicked: allNetworksListView.currentIndex = index } } CheckBox { id: multiSelectionCheckbox Layout.margins: 5 text: "Multi Selection" checked: true } CheckBox { id: testModeCheckbox Layout.margins: 5 text: "Test Networks Mode" checked: false onCheckedChanged: Qt.callLater(simulatedNimModel.cloneModel, availableNetworks) } CheckBox { id: isChainVisibleCheckbox Layout.margins: 5 text: "Is chain visible" checked: true } } } SortFilterProxyModel { id: availableNetworks // Simulate Nim's way of providing access to data function rowData(index, propName) { return get(index)[propName] } sourceModel: NetworksModel.allNetworks filters: ValueFilter { roleName: "isTest"; value: testModeCheckbox.checked; } } // Keep a clone so that the UX can be modified without affecting the original model CloneModel { id: simulatedNimModel sourceModel: availableNetworks roles: ["chainId", "layer", "chainName", "isTest", "isEnabled", "iconUrl", "shortName", "chainColor"] rolesOverride: [{ role: "enabledState", transform: (mD) => { return simulatedNimModel.areAllEnabled(sourceModel) ? NetworkSelectPopup.UxEnabledState.AllEnabled : mD.isEnabled ? NetworkSelectPopup.UxEnabledState.Enabled : NetworkSelectPopup.UxEnabledState.Disabled } }] /// Simulate the Nim model function toggleNetwork(network) { const chainId = network.chainId let chainIdOnlyEnabled = true let chainIdOnlyDisabled = true let allEnabled = true for (let i = 0; i < simulatedNimModel.count; i++) { const item = simulatedNimModel.get(i) if(item.enabledState === NetworkSelectPopup.UxEnabledState.Enabled) { if(item.chainId !== chainId) { chainIdOnlyEnabled = false } } else if(item.enabledState === NetworkSelectPopup.UxEnabledState.Disabled) { if(item.chainId !== chainId) { chainIdOnlyDisabled = false } allEnabled = false } else { if(item.chainId === chainId) { chainIdOnlyDisabled = false chainIdOnlyEnabled = false } } } for (let i = 0; i < simulatedNimModel.count; i++) { const item = simulatedNimModel.get(i) if(allEnabled) { simulatedNimModel.setProperty(i, "enabledState", item.chainId === chainId ? NetworkSelectPopup.UxEnabledState.Enabled : NetworkSelectPopup.UxEnabledState.Disabled) } else if(chainIdOnlyEnabled || chainIdOnlyDisabled) { simulatedNimModel.setProperty(i, "enabledState", NetworkSelectPopup.UxEnabledState.AllEnabled) } else if(item.chainId === chainId) { simulatedNimModel.setProperty(i, "enabledState", item.enabledState === NetworkSelectPopup.UxEnabledState.Enabled ? NetworkSelectPopup.UxEnabledState.Disabled :NetworkSelectPopup.UxEnabledState.Enabled) } const haveEnabled = item.enabledState !== NetworkSelectPopup.UxEnabledState.Disabled if(item.isEnabled !== haveEnabled) { simulatedNimModel.setProperty(i, "isEnabled", haveEnabled) } } } function areAllEnabled(modelToCheck) { for (let i = 0; i < modelToCheck.count; i++) { if(!(modelToCheck.get(i).isEnabled)) { return false } } return true } } }