diff --git a/src/app/modules/main/wallet_section/networks/model.nim b/src/app/modules/main/wallet_section/networks/model.nim
index 2c2dc480cd..6acab13c92 100644
--- a/src/app/modules/main/wallet_section/networks/model.nim
+++ b/src/app/modules/main/wallet_section/networks/model.nim
@@ -180,12 +180,12 @@ QtObject:
break
return networkString
- proc getNetworkIds*(self: Model, shortNames: string): string =
+ proc getNetworkIds*(self: Model, shortNames: string, areTestNetworksEnabled: bool): string =
var networkIds = ""
let networksNames = shortNames.split(":")
for name in networksNames:
for item in self.delegate.getFlatNetworksList():
- if item.shortName == name:
+ if item.shortName == name and item.isTest == areTestNetworksEnabled:
networkIds = networkIds & $item.chainId & ':'
break
return networkIds
diff --git a/src/app/modules/main/wallet_section/networks/view.nim b/src/app/modules/main/wallet_section/networks/view.nim
index 4a4df17499..d45e4794bc 100644
--- a/src/app/modules/main/wallet_section/networks/view.nim
+++ b/src/app/modules/main/wallet_section/networks/view.nim
@@ -95,7 +95,7 @@ QtObject:
return self.flatNetworks.getNetworkShortNames(preferredNetworks, self.areTestNetworksEnabled)
proc getNetworkIds*(self: View, shortNames: string): string {.slot.} =
- return self.flatNetworks.getNetworkIds(shortNames)
+ return self.flatNetworks.getNetworkIds(shortNames, self.areTestNetworksEnabled)
proc getBlockExplorerURL*(self: View, chainId: int): string {.slot.} =
return self.flatNetworks.getBlockExplorerURL(chainId)
diff --git a/storybook/pages/AccountViewPage.qml b/storybook/pages/AccountViewPage.qml
index 39d8516b3a..53c6e5d3d1 100644
--- a/storybook/pages/AccountViewPage.qml
+++ b/storybook/pages/AccountViewPage.qml
@@ -54,7 +54,6 @@ SplitView {
sourceModel: NetworksModel.flatNetworks
filters: ValueFilter { roleName: "isTest"; value: areTestNetworksEnabledCheckbox.checked }
}
-
property var filteredFlatModel: networks
property bool areTestNetworksEnabled: areTestNetworksEnabledCheckbox.checked
function toggleNetwork(chainId) {
@@ -71,17 +70,6 @@ SplitView {
function updateWalletAccountPreferredChains(address, preferredChainIds) {
console.warn("updateWalletAccountPreferredChains :: address ::", address, "preferredChainIds :: ", preferredChainIds)
}
-
- function processPreferredSharingNetworkToggle(preferredSharingNetworksArray, 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]
- }
}
property var keyPairModel: WalletKeyPairModel {}
diff --git a/storybook/pages/AddEditSavedAddressPopupPage.qml b/storybook/pages/AddEditSavedAddressPopupPage.qml
index be260b4c00..9001deb6f9 100644
--- a/storybook/pages/AddEditSavedAddressPopupPage.qml
+++ b/storybook/pages/AddEditSavedAddressPopupPage.qml
@@ -2,6 +2,7 @@ import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
+import StatusQ.Core.Utils 0.1
import SortFilterProxyModel 0.2
import Storybook 1.0
@@ -42,7 +43,7 @@ SplitView {
destroyOnClose: true
modal: false
closePolicy: Popup.NoAutoClose
-
+
flatNetworks: SortFilterProxyModel {
sourceModel: NetworksModel.flatNetworks
filters: ValueFilter { roleName: "isTest"; value: false }
@@ -55,6 +56,11 @@ SplitView {
function createOrUpdateSavedAddress(name, address, ens, colorId, chainShortNames) {
logs.logEvent("createOrUpdateSavedAddress", ["name", "address", "ens", "colorId", "chainShortNames"], arguments)
}
+ function getNetworkIds(chainSortNames) {
+ let shortNames = chainSortNames.split(":").filter((shortName) => shortName.length > 0)
+ const chainIds = shortNames.map((shortName) => ModelUtils.getByKey(NetworksModel.flatNetworks, "shortName", shortName).chainId)
+ return chainIds.join(":")
+ }
}
// Emulate resolving ENS by simple validation
diff --git a/storybook/pages/EditOwnerTokenViewPage.qml b/storybook/pages/EditOwnerTokenViewPage.qml
index 56d81e808b..97cacc0eff 100644
--- a/storybook/pages/EditOwnerTokenViewPage.qml
+++ b/storybook/pages/EditOwnerTokenViewPage.qml
@@ -46,6 +46,7 @@ SplitView {
communityName: communityName.text
communityLogo: doodles.checked ? ModelsData.collectibles.doodles : ModelsData.collectibles.mana
communityColor: color1.checked ? "#FFC4E9" : "#f44336"
+ ownerToken.chainId: 42161
flatNetworks: SortFilterProxyModel {
sourceModel: NetworksModel.flatNetworks
diff --git a/storybook/pages/NetworkFilterPage.qml b/storybook/pages/NetworkFilterPage.qml
index 927509a4a2..893895c8b4 100644
--- a/storybook/pages/NetworkFilterPage.qml
+++ b/storybook/pages/NetworkFilterPage.qml
@@ -15,83 +15,10 @@ SplitView {
id: root
Logs { id: logs }
- readonly property string ethereumName : "Ethereum Mainnet"
+ readonly property string ethereumName : "Mainnet"
readonly property string optimismName : "Optimism"
readonly property string arbitrumName : "Arbitrum"
-
-
- // Keep a clone so that the UX can be modified without affecting the original model
- CloneModel {
- id: simulatedNimModel
-
- sourceModel: SortFilterProxyModel {
- sourceModel: NetworksModel.flatNetworks
- filters: ValueFilter { roleName: "isTest"; value: false }
- }
-
- roles: ["chainId", "layer", "chainName", "isTest", "isEnabled", "iconUrl", "shortName", "chainColor"]
- rolesOverride: [{ role: "enabledState", transform: (mD) => {
- return simulatedNimModel.areAllEnabled(sourceModel)
- ? NetworkSelectionView.UxEnabledState.AllEnabled
- : mD.isEnabled
- ? NetworkSelectionView.UxEnabledState.Enabled
- : NetworkSelectionView.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 === NetworkSelectionView.UxEnabledState.Enabled) {
- if(item.chainId !== chainId) {
- chainIdOnlyEnabled = false
- }
- } else if(item.enabledState === NetworkSelectionView.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 ? NetworkSelectionView.UxEnabledState.Enabled : NetworkSelectionView.UxEnabledState.Disabled)
- } else if(chainIdOnlyEnabled || chainIdOnlyDisabled) {
- simulatedNimModel.setProperty(i, "enabledState", NetworkSelectionView.UxEnabledState.AllEnabled)
- } else if(item.chainId === chainId) {
- simulatedNimModel.setProperty(i, "enabledState", item.enabledState === NetworkSelectionView.UxEnabledState.Enabled
- ? NetworkSelectionView.UxEnabledState.Disabled
- : NetworkSelectionView.UxEnabledState.Enabled)
- }
- const haveEnabled = item.enabledState !== NetworkSelectionView.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
- }
- }
-
SplitView {
orientation: Qt.Vertical
SplitView.fillWidth: true
@@ -107,30 +34,13 @@ SplitView {
anchors.centerIn: parent
- flatNetworks: simulatedNimModel
+ flatNetworks: NetworksModel.flatNetworks
multiSelection: multiSelectionCheckBox.checked
showAllSelectedText: ctrlShowAllSelectedText.checked
showTitle: ctrlShowTitle.checked
- showCheckboxes: ctrlShowCheckBoxes.checked
- showRadioButtons: ctrlShowRadioButtons.checked
-
- onToggleNetwork: (network) => {
- logs.logEvent("onToggleNetwork: " + network.chainName)
-
- if(multiSelection) {
- simulatedNimModel.toggleNetwork(network)
- } else {
- if(network.chainName === root.ethereumName)
- ethRadioBtn.checked = true
-
- else if(network.chainName === root.optimismName)
- optRadioBtn.checked = true
-
- else if(network.chainName === root.arbitrumName)
- arbRadioBtn.checked = true
- }
- }
+ selectionAllowed: selectionAllowedCheckBox.checked
+ showSelectionIndicator: (ctrlShowCheckBoxes.checked && multiSelection) || (ctrlShowRadioButtons.checked && !multiSelection)
}
}
@@ -154,13 +64,11 @@ SplitView {
CheckBox {
id: multiSelectionCheckBox
text: "Multi selection"
- checked: true
- onCheckedChanged: if(!checked) ethRadioBtn.checked = true
+ checked: false
}
CheckBox {
id: ctrlShowTitle
- visible: !multiSelectionCheckBox.checked
text: "Show title text"
checked: true
}
@@ -186,6 +94,12 @@ SplitView {
checked: true
}
+ CheckBox {
+ id: selectionAllowedCheckBox
+ text: "Selection allowed"
+ checked: true
+ }
+
ColumnLayout {
visible: !multiSelectionCheckBox.checked
Label {
@@ -197,19 +111,22 @@ SplitView {
id: ethRadioBtn
text: root.ethereumName
- onCheckedChanged: if(checked) networkFilter.setChain(NetworksModel.ethNet)
+ checked: networkFilter.selection.includes(NetworksModel.ethNet)
+ onToggled: networkFilter.selection = [NetworksModel.ethNet]
}
RadioButton {
id: optRadioBtn
text: root.optimismName
- onCheckedChanged: if(checked) networkFilter.setChain(NetworksModel.optimismNet)
+ checked: networkFilter.selection.includes(NetworksModel.optimismNet)
+ onToggled: networkFilter.selection = [NetworksModel.optimismNet]
}
RadioButton {
id: arbRadioBtn
text: root.arbitrumName
- onCheckedChanged: if(checked) networkFilter.setChain(NetworksModel.arbitrumNet)
+ checked: networkFilter.selection.includes(NetworksModel.arbitrumNet)
+ onToggled: networkFilter.selection = [NetworksModel.arbitrumNet]
}
}
}
diff --git a/storybook/pages/NetworkSelectPopupPage.qml b/storybook/pages/NetworkSelectPopupPage.qml
index 01239758be..d6e3c2059a 100644
--- a/storybook/pages/NetworkSelectPopupPage.qml
+++ b/storybook/pages/NetworkSelectPopupPage.qml
@@ -2,6 +2,7 @@ import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
+import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Popups 0.1
@@ -39,16 +40,7 @@ SplitView {
Layout.alignment: Qt.AlignHCenter
- flatNetworks: simulatedNimModel
-
- onToggleNetwork: (network) => {
- if(multiSelection) {
- simulatedNimModel.toggleNetwork(network)
- } else {
- lastSingleSelectionLabel.text = `[${network.chainName}] (NL) - ID: ${network.chainId}, Icon: ${network.iconUrl}`
- }
- }
-
+ flatNetworks: availableNetworks
multiSelection: multiSelectionCheckbox.checked
}
@@ -56,21 +48,15 @@ SplitView {
Item {
id: popupPlaceholder
- Layout.preferredWidth: networkSelectPopup.width
- Layout.preferredHeight: networkSelectPopup.height
+ Layout.preferredWidth: networkSelectPopup.implicitWidth
+ Layout.preferredHeight: networkSelectPopup.implicitHeight
NetworkSelectPopup {
id: networkSelectPopup
-
- flatNetworks: simulatedNimModel
-
- useEnabledRole: false
-
- visible: true
+ flatNetworks: availableNetworks
+ multiSelection: multiSelectionCheckbox.checked
closePolicy: Popup.NoAutoClose
-
- // Simulates a network toggle
- onToggleNetwork: (network, index) => simulatedNimModel.toggleNetwork(network)
+ visible: true
}
}
@@ -86,15 +72,21 @@ SplitView {
}
Label {
id: lastSingleSelectionLabel
- text: "-"
+ text: selectedEntry.available ? `[${selectedEntry.item.chainName}] - ID: ${selectedEntry.item.chainId}, Icon: ${selectedEntry.item.iconUrl}` : "-"
+ }
+
+ ModelEntry {
+ id: selectedEntry
+ sourceModel: availableNetworks
+ key: "chainId"
}
}
Item {
id: singleSelectionPopupPlaceholder
- Layout.preferredWidth: selectPopupLoader.item ? selectPopupLoader.item.width : 0
- Layout.preferredHeight: selectPopupLoader.item ? selectPopupLoader.item.height : 0
+ Layout.preferredWidth: selectPopupLoader.item ? selectPopupLoader.item.implicitWidth : 0
+ Layout.preferredHeight: selectPopupLoader.item ? selectPopupLoader.item.implicitHeight : 0
property var currentModel: networkFilter.flatNetworks
property int currentIndex: 0
@@ -105,20 +97,15 @@ SplitView {
active: false
sourceComponent: NetworkSelectPopup {
- flatNetworks: simulatedNimModel
-
- singleSelection {
- enabled: true
- currentModel: singleSelectionPopupPlaceholder.currentModel
- currentIndex: singleSelectionPopupPlaceholder.currentIndex
- }
-
- onToggleNetwork: (network, index) => {
- lastSingleSelectionLabel.text = `[${network.chainName}] - ID: ${network.chainId}, Icon: ${network.iconUrl}`
- singleSelectionPopupPlaceholder.currentIndex = index
- }
-
+ flatNetworks: availableNetworks
+ selection: selectedEntry.available ? [selectedEntry.value] : []
onClosed: selectPopupLoader.active = false
+
+ onSelectionChanged: {
+ if (selectedEntry.value !== selection[0]) {
+ selectedEntry.value = selection[0]
+ }
+ }
}
onLoaded: item.open()
@@ -143,9 +130,11 @@ SplitView {
Layout.fillWidth: true
Layout.fillHeight: true
- model: simulatedNimModel
+ model: availableNetworks
delegate: ItemDelegate {
+ required property var model
+
width: allNetworksListView.width
implicitHeight: delegateRowLayout.implicitHeight
@@ -167,20 +156,20 @@ SplitView {
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
+ checkState: networkSelectPopup.selection.includes(model.chainId) ? Qt.Checked : Qt.Unchecked
+ onToggled: {
+ let currentSelection = networkSelectPopup.selection
+ if (checkState === Qt.Checked && !currentSelection.includes(model.chainId)) {
+ currentSelection.push(model.chainId)
+ } else {
+ currentSelection = currentSelection.filter(id => id !== model.chainId)
+ }
+ networkSelectPopup.selection = [...currentSelection]
}
}
}
}
}
-
- onClicked: allNetworksListView.currentIndex = index
}
}
CheckBox {
@@ -199,7 +188,15 @@ SplitView {
text: "Test Networks Mode"
checked: false
- onCheckedChanged: Qt.callLater(simulatedNimModel.cloneModel, availableNetworks)
+ }
+
+ CheckBox {
+ id: allowSelection
+ Layout.margins: 5
+
+ text: "Allow Selection"
+ checked: networkSelectPopup.selectionAllowed
+ onToggled: networkSelectPopup.selectionAllowed = checked
}
}
}
@@ -210,74 +207,6 @@ SplitView {
sourceModel: NetworksModel.flatNetworks
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)
- ? NetworkSelectionView.UxEnabledState.AllEnabled
- : mD.isEnabled
- ? NetworkSelectionView.UxEnabledState.Enabled
- : NetworkSelectionView.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 === NetworkSelectionView.UxEnabledState.Enabled) {
- if(item.chainId !== chainId) {
- chainIdOnlyEnabled = false
- }
- } else if(item.enabledState === NetworkSelectionView.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 ? NetworkSelectionView.UxEnabledState.Enabled : NetworkSelectionView.UxEnabledState.Disabled)
- } else if(chainIdOnlyEnabled || chainIdOnlyDisabled) {
- simulatedNimModel.setProperty(i, "enabledState", NetworkSelectionView.UxEnabledState.AllEnabled)
- } else if(item.chainId === chainId) {
- simulatedNimModel.setProperty(i, "enabledState", item.enabledState === NetworkSelectionView.UxEnabledState.Enabled
- ? NetworkSelectionView.UxEnabledState.Disabled
- :NetworkSelectionView.UxEnabledState.Enabled)
- }
- const haveEnabled = item.enabledState !== NetworkSelectionView.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
- }
- }
}
// category: Popups
diff --git a/storybook/pages/ReceiveModalPage.qml b/storybook/pages/ReceiveModalPage.qml
index 8093e00704..9da6d5f568 100644
--- a/storybook/pages/ReceiveModalPage.qml
+++ b/storybook/pages/ReceiveModalPage.qml
@@ -74,27 +74,16 @@ SplitView {
return result
}
- function processPreferredSharingNetworkToggle(preferredSharingNetworks, toggledNetwork) {
- let prefChains = preferredSharingNetworks
- if(prefChains.length === filteredFlatModel.count) {
- prefChains = [toggledNetwork.chainId.toString()]
+ function getNetworkIds(chainShortNames) {
+ let result = ""
+ if (!chainShortNames) return result
+
+ let shortNames = chainShortNames.split(":").filter((shortName) => shortName.length > 0)
+ for(let i = 0; i< shortNames.length; i++) {
+ let chainId = ModelUtils.getByKey(NetworksModel.flatNetworks, "shortName", shortNames[i]).chainId
+ result += ":" + chainId.toString()
}
- else if(!prefChains.includes(toggledNetwork.chainId.toString())) {
- prefChains.push(toggledNetwork.chainId.toString())
- }
- else {
- if(prefChains.length === 1) {
- prefChains = getAllNetworksChainIds()
- }
- else {
- for(var i = 0; i < prefChains.length;i++) {
- if(prefChains[i] === toggledNetwork.chainId.toString()) {
- prefChains.splice(i, 1)
- }
- }
- }
- }
- return prefChains
+ return result
}
function addressWasShown(account) {
diff --git a/storybook/pages/WalletHeaderPage.qml b/storybook/pages/WalletHeaderPage.qml
index 26dcc8ac4d..e0832bf74c 100644
--- a/storybook/pages/WalletHeaderPage.qml
+++ b/storybook/pages/WalletHeaderPage.qml
@@ -85,6 +85,7 @@ SplitView {
filters: ValueFilter { roleName: "isTest"; value: false }
}
function toggleNetwork(chainId) {
+ print ("toggleNetwork called with chainId: " + chainId)
}
function getAllNetworksSupportedString(hovered) {
diff --git a/storybook/qmlTests/tests/tst_NetworkSelectPopup.qml b/storybook/qmlTests/tests/tst_NetworkSelectPopup.qml
new file mode 100644
index 0000000000..763a2c4da0
--- /dev/null
+++ b/storybook/qmlTests/tests/tst_NetworkSelectPopup.qml
@@ -0,0 +1,89 @@
+import QtQuick 2.14
+import QtTest 1.15
+
+import AppLayouts.Wallet.popups 1.0
+
+import utils 1.0
+
+import Models 1.0
+
+Item {
+ id: root
+ width: 600
+ height: 400
+
+ Component {
+ id: componentUnderTest
+ NetworkSelectPopup {
+ anchors.centerIn: parent
+ flatNetworks: NetworksModel.flatNetworks
+ visible: true
+ }
+ }
+
+ SignalSpy {
+ id: selectionChangedSpy
+ target: controlUnderTest
+ signalName: "onSelectionChanged"
+ }
+
+ property NetworkSelectPopup controlUnderTest: null
+
+ TestCase {
+ name: "NetworkSelectPopup"
+ when: windowShown
+
+ function init() {
+ controlUnderTest = createTemporaryObject(componentUnderTest, root)
+ controlUnderTest.open()
+ compare(controlUnderTest.opened, true)
+ selectionChangedSpy.clear()
+ }
+
+ function test_basicGeometry() {
+ verify(!!controlUnderTest)
+ compare(controlUnderTest.width, 300)
+ compare(controlUnderTest.height, controlUnderTest.contentHeight + controlUnderTest.padding * 2)
+ }
+
+ function test_selectionBindings() {
+ //single selection - select using the selectio property
+ compare(controlUnderTest.multiSelection, false)
+ controlUnderTest.selection = [controlUnderTest.flatNetworks.get(0).chainId]
+ compare(controlUnderTest.selection, [controlUnderTest.flatNetworks.get(0).chainId])
+ compare(selectionChangedSpy.count, 1)
+
+ //single selection - select using the view
+ const secondDelegate = findChild(controlUnderTest.contentItem, "networkSelectorDelegate_" + controlUnderTest.flatNetworks.get(1).chainName)
+ mouseClick(secondDelegate)
+ compare(controlUnderTest.selection, [controlUnderTest.flatNetworks.get(1).chainId])
+ compare(selectionChangedSpy.count, 2)
+
+ // multi selection - select using selection property
+ controlUnderTest.open()
+ controlUnderTest.multiSelection = true
+ controlUnderTest.selection = [controlUnderTest.flatNetworks.get(0).chainId, controlUnderTest.flatNetworks.get(1).chainId]
+ compare(controlUnderTest.selection, [controlUnderTest.flatNetworks.get(0).chainId, controlUnderTest.flatNetworks.get(1).chainId])
+ compare(selectionChangedSpy.count, 3)
+
+ // multi selection - select using the view
+ const thirdDelegate = findChild(controlUnderTest.contentItem, "networkSelectorDelegate_" + controlUnderTest.flatNetworks.get(2).chainName)
+ mouseClick(thirdDelegate)
+ compare(controlUnderTest.selection, [controlUnderTest.flatNetworks.get(0).chainId, controlUnderTest.flatNetworks.get(1).chainId, controlUnderTest.flatNetworks.get(2).chainId])
+ compare(selectionChangedSpy.count, 4)
+ }
+
+ function test_closeAfterSingleSelection() {
+ compare(controlUnderTest.multiSelection, false)
+ const secondDelegate = findChild(controlUnderTest.contentItem, "networkSelectorDelegate_" + controlUnderTest.flatNetworks.get(1).chainName)
+ mouseClick(secondDelegate)
+ compare(controlUnderTest.opened, false)
+
+ controlUnderTest.open()
+ controlUnderTest.multiSelection = true
+ const thirdDelegate = findChild(controlUnderTest.contentItem, "networkSelectorDelegate_" + controlUnderTest.flatNetworks.get(2).chainName)
+ mouseClick(thirdDelegate)
+ compare(controlUnderTest.opened, true)
+ }
+ }
+}
\ No newline at end of file
diff --git a/storybook/qmlTests/tests/tst_NetworkSelectorView.qml b/storybook/qmlTests/tests/tst_NetworkSelectorView.qml
index a584e3524c..3ecda1ffef 100644
--- a/storybook/qmlTests/tests/tst_NetworkSelectorView.qml
+++ b/storybook/qmlTests/tests/tst_NetworkSelectorView.qml
@@ -81,7 +81,7 @@ Item {
verify(!!delegate)
compare(delegate.title, model.chainName)
- compare(delegate.iconUrl, Style.svg(model.iconUrl))
+ compare(delegate.iconUrl, (model.isTest ? Style.svg(model.iconUrl + "-test") : Style.svg(model.iconUrl)))
compare(delegate.showIndicator, controlUnderTest.showIndicator)
compare(delegate.multiSelection, controlUnderTest.multiSelection)
compare(delegate.checkState, controlUnderTest.selection.includes(model.chainId) ? Qt.Checked : Qt.Unchecked)
diff --git a/storybook/src/Models/NetworksModel.qml b/storybook/src/Models/NetworksModel.qml
index 65a7c85e4d..afcdaaea17 100644
--- a/storybook/src/Models/NetworksModel.qml
+++ b/storybook/src/Models/NetworksModel.qml
@@ -100,7 +100,7 @@ QtObject {
chainId: 420,
chainName: "Optimism Goerli Testnet",
blockExplorerUrl: "https://goerli-optimism.etherscan.io/",
- iconUrl: "network/Network=Testnet",
+ iconUrl: "network/Network=Optimism",
chainColor: "#939BA1",
shortName: "goOpt",
nativeCurrencyName: "Ether",
@@ -128,7 +128,7 @@ QtObject {
chainId: 421613,
chainName: "Arbitrum Goerli",
blockExplorerUrl: "https://goerli.arbiscan.io/",
- iconUrl: "network/Network=Testnet",
+ iconUrl: "network/Network=Arbitrum",
chainColor: "#939BA1",
shortName: "goArb",
nativeCurrencyName: "Ether",
diff --git a/ui/StatusQ/src/StatusQ/Controls/StatusComboBox.qml b/ui/StatusQ/src/StatusQ/Controls/StatusComboBox.qml
index 9147613300..b3783efe1a 100644
--- a/ui/StatusQ/src/StatusQ/Controls/StatusComboBox.qml
+++ b/ui/StatusQ/src/StatusQ/Controls/StatusComboBox.qml
@@ -17,6 +17,7 @@ Item {
property alias contentItem: comboBox.contentItem
property alias comboBoxListViewSection: listView.section
readonly property alias indicator: statusIndicator
+ property alias popup: comboBox.popup
property alias currentIndex: comboBox.currentIndex
property alias currentValue: comboBox.currentValue
diff --git a/ui/app/AppLayouts/Communities/views/EditOwnerTokenView.qml b/ui/app/AppLayouts/Communities/views/EditOwnerTokenView.qml
index 40c730ccb6..2c5873b7d6 100644
--- a/ui/app/AppLayouts/Communities/views/EditOwnerTokenView.qml
+++ b/ui/app/AppLayouts/Communities/views/EditOwnerTokenView.qml
@@ -1,6 +1,7 @@
import QtQuick 2.15
import QtQuick.Layouts 1.14
+import StatusQ 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
@@ -80,8 +81,6 @@ StatusScrollView {
contentWidth: mainLayout.width
contentHeight: mainLayout.height
- Component.onCompleted: networkSelector.setChain(ownerToken.chainId)
-
ColumnLayout {
id: mainLayout
@@ -262,10 +261,6 @@ StatusScrollView {
property string label
property string description
- function setChain(chainId) { netFilter.setChain(chainId) }
-
- readonly property alias currentNetworkName: netFilter.currentValue
-
Layout.fillWidth: true
Layout.topMargin: Style.current.padding
spacing: 8
@@ -282,6 +277,8 @@ StatusScrollView {
Layout.fillWidth: true
flatNetworks: root.flatNetworks
+ selection: !!ownerToken.chainId ? [ownerToken.chainId] : [SQUtils.ModelUtils.getByKey(flatNetworks, "layer", 2).chainId/*first layer 2 network*/]
+
multiSelection: false
control.topPadding: 10
control.background: Rectangle {
@@ -290,17 +287,17 @@ StatusScrollView {
color: "transparent"
border.color: Theme.palette.directColor7
}
-
- onToggleNetwork: (network) => {
+
+ onToggleNetwork: {
// Set Owner Token network properties:
- ownerToken.chainId = network.chainId
- ownerToken.chainName = network.chainName
- ownerToken.chainIcon = network.iconUrl
+ ownerToken.chainId = singleSelectionItemData.chainId
+ ownerToken.chainName = singleSelectionItemData.chainName
+ ownerToken.chainIcon = singleSelectionItemData.iconUrl
// Set TMaster Token network properties:
- tMasterToken.chainId = network.chainId
- tMasterToken.chainName = network.chainName
- tMasterToken.chainIcon = network.iconUrl
+ tMasterToken.chainId = singleSelectionItemData.chainId
+ tMasterToken.chainName = singleSelectionItemData.chainName
+ tMasterToken.chainIcon = singleSelectionItemData.iconUrl
}
}
}
diff --git a/ui/app/AppLayouts/Profile/stores/WalletStore.qml b/ui/app/AppLayouts/Profile/stores/WalletStore.qml
index 488583ec85..cd7a28a868 100644
--- a/ui/app/AppLayouts/Profile/stores/WalletStore.qml
+++ b/ui/app/AppLayouts/Profile/stores/WalletStore.qml
@@ -162,29 +162,6 @@ QtObject {
return networksModuleInst.getNetworkShortNames(chainIds)
}
- function processPreferredSharingNetworkToggle(preferredSharingNetworks, toggledNetwork) {
- let prefChains = preferredSharingNetworks
- if(prefChains.length === root.flatNetworks.count) {
- prefChains = [toggledNetwork.chainId.toString()]
- }
- else if(!prefChains.includes(toggledNetwork.chainId.toString())) {
- prefChains.push(toggledNetwork.chainId.toString())
- }
- else {
- if(prefChains.length === 1) {
- prefChains = getAllNetworksChainIds()
- }
- else {
- for(var i = 0; i < prefChains.length;i++) {
- if(prefChains[i] === toggledNetwork.chainId.toString()) {
- prefChains.splice(i, 1)
- }
- }
- }
- }
- return prefChains
- }
-
function copyToClipboard(textToCopy) {
globalUtils.copyToClipboard(textToCopy)
}
diff --git a/ui/app/AppLayouts/Profile/views/wallet/AccountView.qml b/ui/app/AppLayouts/Profile/views/wallet/AccountView.qml
index b9aae728e0..f04c4a0211 100644
--- a/ui/app/AppLayouts/Profile/views/wallet/AccountView.qml
+++ b/ui/app/AppLayouts/Profile/views/wallet/AccountView.qml
@@ -43,12 +43,8 @@ ColumnLayout {
readonly property bool privateKeyAccount: !!root.keyPair? root.keyPair.pairType === Constants.keypair.type.privateKeyImport: false
readonly property bool seedImport: !!root.keyPair? root.keyPair.pairType === Constants.keypair.type.seedImport: false
readonly property string preferredSharingNetworks: !!root.account? root.account.preferredSharingChainIds: ""
- property var preferredSharingNetworksArray: preferredSharingNetworks.split(":").filter(Boolean)
+ property var preferredSharingNetworksArray: preferredSharingNetworks.split(":").filter(Boolean).map(Number)
property string preferredSharingNetworkShortNames: walletStore.getNetworkShortNames(preferredSharingNetworks)
- onPreferredSharingNetworksChanged: {
- preferredSharingNetworksArray = preferredSharingNetworks.split(":").filter(Boolean)
- preferredSharingNetworkShortNames = walletStore.getNetworkShortNames(preferredSharingNetworks)
- }
}
spacing: 0
@@ -257,11 +253,15 @@ ColumnLayout {
components: [
NetworkFilter {
flatNetworks: root.walletStore.filteredFlatModel
- preferredNetworksMode: true
- preferredSharingNetworks: d.preferredSharingNetworksArray
- onToggleNetwork: (network) => {
- d.preferredSharingNetworksArray = root.walletStore.processPreferredSharingNetworkToggle(d.preferredSharingNetworksArray, network)
- }
+ multiSelection: true
+ selection: d.preferredSharingNetworksArray
+
+ onSelectionChanged: {
+ if (selection !== d.preferredSharingNetworksArray) {
+ d.preferredSharingNetworksArray = selection
+ }
+ }
+
control.popup.onClosed: {
if (!!root.account) {
root.walletStore.updateWalletAccountPreferredChains(root.account.address, d.preferredSharingNetworksArray.join(":"))
diff --git a/ui/app/AppLayouts/Wallet/controls/NetworkFilter.qml b/ui/app/AppLayouts/Wallet/controls/NetworkFilter.qml
index e9c0955cfa..10ad629e1f 100644
--- a/ui/app/AppLayouts/Wallet/controls/NetworkFilter.qml
+++ b/ui/app/AppLayouts/Wallet/controls/NetworkFilter.qml
@@ -1,4 +1,5 @@
import QtQuick 2.15
+import QtQml 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
@@ -15,6 +16,7 @@ import StatusQ.Controls 0.1
import SortFilterProxyModel 0.2
import AppLayouts.Wallet.helpers 1.0
+import AppLayouts.Wallet.popups 1.0
import utils 1.0
@@ -24,70 +26,28 @@ StatusComboBox {
id: root
required property var flatNetworks
+ readonly property alias singleSelectionItemData: d.singleSelectionItem.item
+
property bool multiSelection: true
- property bool preferredNetworksMode: false
- property var preferredSharingNetworks: []
+ property bool showSelectionIndicator: true
property bool showAllSelectedText: true
- property bool showCheckboxes: true
- property bool showRadioButtons: true
property bool showTitle: true
+ property bool selectionAllowed: true
+ property var selection: []
- /// \c network is a network.model.nim entry
- /// It is called for every toggled network if \c multiSelection is \c true
- /// If \c multiSelection is \c false, it is called only for the selected network when the selection changes
- signal toggleNetwork(var network)
+ signal toggleNetwork(int chainId, int index)
- function setChain(chainId) {
- if(!multiSelection && !!root.flatNetworks && root.flatNetworks.count > 0) {
- d.currentIndex = NetworkModelHelpers.getChainIndexByChainId(root.flatNetworks, chainId)
- if(d.currentIndex == -1)
- d.currentIndex = NetworkModelHelpers.getChainIndexForFirstLayer2Network(root.flatNetworks)
-
- // Notify change:
- root.toggleNetwork(ModelUtils.get(root.flatNetworks, d.currentIndex))
+ onSelectionChanged: {
+ if (root.selection !== networkSelectorView.selection) {
+ networkSelectorView.selection = root.selection
}
}
- QtObject {
- id: d
-
- readonly property string selectedChainName: {
- root.multiSelection
- NetworkModelHelpers.getChainName(root.flatNetworks, d.currentIndex)
- }
- readonly property string selectedIconUrl: {
- root.multiSelection
- NetworkModelHelpers.getChainIconUrl(root.flatNetworks, d.currentIndex)
- }
- readonly property bool allSelected: root.preferredNetworksMode ? root.preferredSharingNetworks.length === root.flatNetworks.count :
- enabledFlatNetworks.count === root.flatNetworks.count
- readonly property bool noneSelected: enabledFlatNetworks.count === 0
-
- // Persist selection between selectPopupLoader reloads
- property int currentIndex: 0
-
- property SortFilterProxyModel enabledFlatNetworks: SortFilterProxyModel {
- sourceModel: root.flatNetworks
- filters: [
- ValueFilter { roleName: "isEnabled"; value: true; enabled: !root.preferredNetworksMode },
- FastExpressionFilter {
- expression: root.preferredSharingNetworks.includes(chainId.toString())
- expectedRoles: ["chainId"]
- enabled: root.preferredNetworksMode
- }
- ]
- }
- }
-
- onMultiSelectionChanged: root.setChain()
-
control.padding: 12
control.spacing: 0
control.rightPadding: 36
control.topPadding: 7
- control.popup.x: root.width - control.popup.width
- control.popup.width: 300
control.popup.horizontalPadding: 4
control.popup.verticalPadding: 4
@@ -101,49 +61,46 @@ StatusComboBox {
control.indicator: SQP.StatusComboboxIndicator {
x: root.control.mirrored ? root.control.horizontalPadding : root.width - width - root.control.horizontalPadding
y: root.control.topPadding + (root.control.availableHeight - height) / 2
+ visible: !d.selectionUnavailable
}
control.contentItem: RowLayout {
- spacing: Style.current.padding
+ spacing: Style.current.halfPadding
StatusSmartIdenticon {
objectName: "contentItemIcon"
Layout.alignment: Qt.AlignVCenter
asset.height: 24
asset.width: 24
asset.isImage: !root.multiSelection
- asset.name: !root.multiSelection ? Style.svg(d.selectedIconUrl) : ""
+ asset.name: !root.multiSelection ? Style.svg(d.singleSelectionIconUrl) : ""
active: !root.multiSelection
visible: active
}
- StatusBaseText {
- objectName: "contentItemText"
- Layout.alignment: Qt.AlignVCenter
- Layout.fillWidth: true
- font.pixelSize: Style.current.additionalTextSize
- font.weight: Font.Medium
- elide: Text.ElideRight
- lineHeight: 24
- lineHeightMode: Text.FixedHeight
- verticalAlignment: Text.AlignVCenter
- text: root.multiSelection ? (d.noneSelected ? qsTr("Select networks"): d.allSelected && root.showAllSelectedText ? qsTr("All networks") : "")
- : (root.showTitle ? d.selectedChainName : "")
- color: Theme.palette.baseColor1
- visible: !!text
- }
Row {
id: row
spacing: -4
visible: (!d.allSelected || !root.showAllSelectedText) && chainRepeater.count > 0
Repeater {
id: chainRepeater
- model: root.multiSelection ? d.enabledFlatNetworks: []
+ model: SortFilterProxyModel {
+ sourceModel: root.multiSelection ? root.flatNetworks : null
+ filters: FastExpressionFilter {
+ expression: {
+ root.selection
+ return root.selection.includes(model.chainId)
+ }
+ expectedRoles: ["chainId"]
+ }
+ }
delegate: StatusRoundedImage {
id: delegateItem
+ required property var model
+ required property int index
+
width: 24
height: 24
- image.source: Style.svg(model.iconUrl)
+ image.source: model.isTest ? Style.svg(model.iconUrl + "-test") : Style.svg(model.iconUrl)
z: index + 1
- visible: root.preferredNetworksMode ? root.preferredSharingNetworks.includes(model.chainId.toString()): image.source !== ""
image.layer.enabled: index < chainRepeater.count - 1 && row.spacing < 0
image.layer.effect: OpacityMask {
@@ -167,31 +124,83 @@ StatusComboBox {
}
}
}
+
+ StatusBaseText {
+ objectName: "contentItemText"
+ Layout.alignment: Qt.AlignVCenter
+ Layout.fillWidth: true
+ font.pixelSize: Style.current.additionalTextSize
+ font.weight: Font.Medium
+ elide: Text.ElideRight
+ lineHeight: 24
+ lineHeightMode: Text.FixedHeight
+ verticalAlignment: Text.AlignVCenter
+ text: d.titleText
+ color: Theme.palette.baseColor1
+ visible: !!text
+ }
}
- control.popup.contentItem: NetworkSelectionView {
+ popup: NetworkSelectPopup {
+ id: networkSelectorView
+ y: control.height + 4
+ x: root.width - width
+
flatNetworks: root.flatNetworks
- preferredSharingNetworks: root.preferredSharingNetworks
- preferredNetworksMode: root.preferredNetworksMode
- showCheckboxes: root.showCheckboxes
- showRadioButtons: root.showRadioButtons
+ selectionAllowed: root.selectionAllowed
+ multiSelection: root.multiSelection
+ showSelectionIndicator: root.showSelectionIndicator
+ selection: root.selection
- implicitWidth: contentWidth
- implicitHeight: contentHeight
-
- singleSelection {
- enabled: !root.multiSelection
- currentModel: root.flatNetworks
- currentIndex: d.currentIndex
+ onSelectionChanged: {
+ if (root.selection !== networkSelectorView.selection) {
+ root.selection = networkSelectorView.selection
+ }
}
- useEnabledRole: false
+ onToggleNetwork: root.toggleNetwork(chainId, index)
+ }
- onToggleNetwork: (network, index) => {
- d.currentIndex = index
- root.toggleNetwork(network)
- if(singleSelection.enabled)
- control.popup.close()
- }
+ Connections {
+ target: control.popup
+ enabled: !root.multiSelection
+ function onOpened() {
+ if (d.selectionUnavailable)
+ control.popup.close()
+ }
+ }
+
+ QtObject {
+ id: d
+ readonly property bool allSelected: root.selection.length === root.flatNetworks.count
+ readonly property bool noneSelected: root.selection.length === 0
+ readonly property bool oneSelected: root.selection.length === 1
+ readonly property bool selectionUnavailable: root.flatNetworks.count <= 1 && d.oneSelected
+
+ readonly property ModelEntry singleSelectionItem: ModelEntry {
+ sourceModel: d.oneSelected ? root.flatNetworks : null
+ key: "chainId"
+ value: root.selection[0] ?? -1
+ }
+
+ readonly property string singleSelectionIconUrl: singleSelectionItem.item.iconUrl ?? ""
+ readonly property string singleCelectionChainName: singleSelectionItem.item.chainName ?? ""
+
+ readonly property string titleText: {
+ if (d.oneSelected && root.showTitle) {
+ return d.singleCelectionChainName
+ }
+
+ if (root.multiSelection) {
+ if (d.noneSelected) {
+ return qsTr("Select networks")
+ }
+ if (d.allSelected && root.showAllSelectedText) {
+ return qsTr("All networks")
+ }
+ }
+
+ return ""
+ }
}
}
diff --git a/ui/app/AppLayouts/Wallet/controls/NetworkSelectItemDelegate.qml b/ui/app/AppLayouts/Wallet/controls/NetworkSelectItemDelegate.qml
index ab5992679a..907cc5bf11 100644
--- a/ui/app/AppLayouts/Wallet/controls/NetworkSelectItemDelegate.qml
+++ b/ui/app/AppLayouts/Wallet/controls/NetworkSelectItemDelegate.qml
@@ -43,7 +43,7 @@ StatusListItem {
leftPadding: 16
rightPadding: 16
statusListItemTitleArea.anchors.leftMargin: 12
- highlighted: (d.checkState !== Qt.Unchecked && !showIndicator)
+ highlighted: d.checkState !== Qt.Unchecked && !showIndicator
Binding on bgColor {
when: highlighted && !root.sensor.containsMouse
diff --git a/ui/app/AppLayouts/Wallet/controls/StatusNetworkSelector.qml b/ui/app/AppLayouts/Wallet/controls/StatusNetworkSelector.qml
index 599951dbd9..f64c09a9b8 100644
--- a/ui/app/AppLayouts/Wallet/controls/StatusNetworkSelector.qml
+++ b/ui/app/AppLayouts/Wallet/controls/StatusNetworkSelector.qml
@@ -193,7 +193,7 @@ Rectangle {
asset.height: root.asset.height
asset.width: root.asset.width
- asset.name: root.useLetterIdenticons ? model.text : Style.svg(model.iconUrl)
+ asset.name: root.useLetterIdenticons ? model.text : (model.isTest ? Style.svg(model.iconUrl + "-test") : Style.svg(model.iconUrl))
asset.isImage: root.asset.isImage
asset.bgColor: root.asset.bgColor
asset.isLetterIdenticon: root.useLetterIdenticons
diff --git a/ui/app/AppLayouts/Wallet/panels/DAppsWorkflow.qml b/ui/app/AppLayouts/Wallet/panels/DAppsWorkflow.qml
index 6dc668d208..712ee41ab3 100644
--- a/ui/app/AppLayouts/Wallet/panels/DAppsWorkflow.qml
+++ b/ui/app/AppLayouts/Wallet/panels/DAppsWorkflow.qml
@@ -96,7 +96,7 @@ ConnectedDappsButton {
flatNetworks: root.wcService.flatNetworks
onConnect: {
- root.wcService.approvePairSession(sessionProposal, dappChains, selectedAccount)
+ root.wcService.approvePairSession(sessionProposal, selectedChains, selectedAccount)
}
onDecline: {
diff --git a/ui/app/AppLayouts/Wallet/panels/WalletHeader.qml b/ui/app/AppLayouts/Wallet/panels/WalletHeader.qml
index 727c44785f..7e1055db32 100644
--- a/ui/app/AppLayouts/Wallet/panels/WalletHeader.qml
+++ b/ui/app/AppLayouts/Wallet/panels/WalletHeader.qml
@@ -124,10 +124,29 @@ Item {
Layout.alignment: Qt.AlignTop
flatNetworks: walletStore.filteredFlatModel
+ onToggleNetwork: walletStore.toggleNetwork(chainId)
- onToggleNetwork: (network) => {
- walletStore.toggleNetwork(network.chainId)
- }
+ Binding on selection {
+ value: chainIdsAggregator.value
+ }
+
+ FunctionAggregator {
+ id: chainIdsAggregator
+
+ readonly property SortFilterProxyModel enabledNetworksModel: SortFilterProxyModel{
+ sourceModel: walletStore.filteredFlatModel
+ filters: ValueFilter {
+ roleName: "isEnabled"
+ value: true
+ }
+ }
+
+ model: enabledNetworksModel
+ initialValue: []
+ roleName: "chainId"
+
+ aggregateFunction: (aggr, value) => [...aggr, value]
+ }
}
}
diff --git a/ui/app/AppLayouts/Wallet/popups/AddEditSavedAddressPopup.qml b/ui/app/AppLayouts/Wallet/popups/AddEditSavedAddressPopup.qml
index 7456ddace3..16a3b73115 100644
--- a/ui/app/AppLayouts/Wallet/popups/AddEditSavedAddressPopup.qml
+++ b/ui/app/AppLayouts/Wallet/popups/AddEditSavedAddressPopup.qml
@@ -9,8 +9,10 @@ import shared.controls 1.0
import shared.panels 1.0
import shared.stores 1.0 as SharedStores
+import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
+import StatusQ.Core.Utils 0.1 as StatusQUtils
import StatusQ.Controls 0.1
import StatusQ.Controls.Validators 0.1
import StatusQ.Popups 0.1
@@ -96,6 +98,14 @@ StatusModal {
property string storedChainShortNames: ""
property bool chainShortNamesDirty: false
+ property var networkSelection: []
+
+ onNetworkSelectionChanged: {
+ if (d.networkSelection !== networkSelectPopup.selection) {
+ networkSelectPopup.selection = d.networkSelection
+ }
+ }
+
property bool addressInputValid: d.editMode ||
addressInput.input.dirty &&
d.addressInputIsAddress &&
@@ -183,7 +193,7 @@ StatusModal {
d.ens = ""
d.address = Constants.zeroAddress
d.chainShortNames = ""
- flatNetworksModelCopy.setEnabledNetworks([])
+ d.networkSelection = []
}
d.cardsModel.clear()
@@ -458,12 +468,12 @@ StatusModal {
d.ens = ""
d.address = prefixAndAddress.address
d.chainShortNames = prefixAndAddress.prefix
-
- let prefixArrWithColumn = d.getPrefixArrayWithColumns(prefixAndAddress.prefix)
- if (!prefixArrWithColumn)
- prefixArrWithColumn = []
-
- flatNetworksModelCopy.setEnabledNetworks(prefixArrWithColumn)
+
+ Qt.callLater(()=> {
+ // Sync chain short names with model. This could result in removing networks from this text
+ // Call it later to avoid binding loop warnings
+ d.networkSelection = store.getNetworkIds(d.chainShortNames).split(":").filter(Boolean).map(Number)
+ })
}
}
@@ -491,9 +501,10 @@ StatusModal {
}
function getUnknownPrefixes(prefixes) {
+ const networksCount = root.flatNetworks.rowCount()
let unknownPrefixes = prefixes.filter(e => {
- for (let i = 0; i < flatNetworksModelCopy.count; i++) {
- if (e == flatNetworksModelCopy.get(i).shortName)
+ for (let i = 0; i < networksCount; i++) {
+ if (e == StatusQUtils.ModelUtils.get(root.flatNetworks, i).shortName)
return false
}
return true
@@ -595,28 +606,25 @@ StatusModal {
defaultItemImageSource: "add"
rightButtonVisible: true
- property bool modelUpdateBlocked: false
-
- function blockModelUpdate(value) {
- modelUpdateBlocked = value
- }
-
itemsModel: SortFilterProxyModel {
- sourceModel: flatNetworksModelCopy
- filters: ValueFilter {
- roleName: "isEnabled"
- value: true
+ sourceModel: root.flatNetworks
+ filters: FastExpressionFilter {
+ readonly property var filteredNetworks: d.networkSelection
+ expression: {
+ return filteredNetworks.length > 0 && filteredNetworks.includes(model.chainId)
+ }
+ expectedRoles: ["chainId"]
}
onCountChanged: {
- if (!networkSelector.modelUpdateBlocked && d.initialized) {
+ if (d.initialized) {
// Initially source model is empty, filter proxy is also empty, but does
// extra work and mistakenly overwrites d.chainShortNames property
if (sourceModel.count != 0) {
const prefixAndAddress = Utils.splitToChainPrefixAndAddress(addressInput.plainText)
const syncedPrefix = addressInput.syncChainPrefixWithModel(prefixAndAddress.prefix, this)
- d.chainShortNames = syncedPrefix
- addressInput.setPlainText(syncedPrefix + prefixAndAddress.address)
+ if (addressInput.text !== syncedPrefix + prefixAndAddress.address)
+ addressInput.setPlainText(syncedPrefix + prefixAndAddress.address)
}
}
}
@@ -624,17 +632,18 @@ StatusModal {
addButton.highlighted: networkSelectPopup.visible
addButton.onClicked: {
- networkSelectPopup.openAtPosition(addButton.x, networkSelector.y + addButton.height + Style.current.xlPadding)
+ networkSelectPopup.openAtPosition(addButton.x, addButton.height + Style.current.xlPadding)
}
onItemClicked: function (item, index, mouse) {
// Append first item
if (index === 0 && defaultItem.visible)
- networkSelectPopup.openAtPosition(defaultItem.x, networkSelector.y + defaultItem.height + Style.current.xlPadding)
+ networkSelectPopup.openAtPosition(defaultItem.x, defaultItem.height + Style.current.xlPadding)
}
onItemRightButtonClicked: function (item, index, mouse) {
- item.modelRef.isEnabled = !item.modelRef.isEnabled
+ let networkSelection = [...d.networkSelection]
+ d.networkSelection = networkSelection.filter(n => n !== item.modelRef.chainId)
d.chainShortNamesDirty = true
}
@@ -659,32 +668,36 @@ StatusModal {
}
}
]
+
+ NetworkSelectPopup {
+ id: networkSelectPopup
+
+ function openAtPosition(x, y) {
+ networkSelectPopup.x = x
+ networkSelectPopup.y = y
+ networkSelectPopup.open()
+ }
+
+ flatNetworks: root.flatNetworks
+ selection: d.networkSelection
+ multiSelection: true
+
+ onSelectionChanged: {
+ if (d.networkSelection !== networkSelectPopup.selection) {
+ d.networkSelection = networkSelectPopup.selection
+ d.chainShortNamesDirty = true
+ }
+ }
+
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
+
+ modal: true
+ dim: false
+ }
}
}
}
- NetworkSelectPopup {
- id: networkSelectPopup
-
- flatNetworks: flatNetworksModelCopy
-
- onToggleNetwork: (network) => {
- network.isEnabled = !network.isEnabled
- d.chainShortNamesDirty = true
- }
-
- closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
-
- function openAtPosition(xPos, yPos) {
- x = xPos
- y = yPos
- open()
- }
-
- modal: true
- dim: false
- }
-
rightButtons: [
StatusButton {
text: d.editMode? qsTr("Save") : qsTr("Add address")
@@ -695,21 +708,4 @@ StatusModal {
objectName: "addSavedAddress"
}
]
-
- CloneModel {
- id: flatNetworksModelCopy
-
- sourceModel: root.flatNetworks
- roles: ["layer", "chainId", "chainColor", "chainName","shortName", "iconUrl"]
- rolesOverride: [{ role: "isEnabled", transform: (modelData) => Boolean(false) }]
-
- function setEnabledNetworks(prefixArr) {
- networkSelector.blockModelUpdate(true)
- for (let i = 0; i < count; i++) {
- // Add only those chainShortNames to the model, that have column ":" at the end, making it a valid chain prefix
- setProperty(i, "isEnabled", prefixArr.includes(get(i).shortName + ":"))
- }
- networkSelector.blockModelUpdate(false)
- }
- }
}
diff --git a/ui/app/AppLayouts/Wallet/popups/NetworkSelectPopup.qml b/ui/app/AppLayouts/Wallet/popups/NetworkSelectPopup.qml
index 9cf89ea49e..d8d65cc647 100644
--- a/ui/app/AppLayouts/Wallet/popups/NetworkSelectPopup.qml
+++ b/ui/app/AppLayouts/Wallet/popups/NetworkSelectPopup.qml
@@ -10,45 +10,31 @@ import SortFilterProxyModel 0.2
import utils 1.0
-import "../stores/NetworkSelectPopup"
import "../controls"
import "../views"
-StatusDialog {
+Popup {
id: root
- property var flatNetworks
- property var preferredSharingNetworks: []
- property bool preferredNetworksMode: false
+ required property var flatNetworks
- /// Grouped properties for single selection state. \c singleSelection.enabled is \c false by default
- /// \see SingleSelectionInfo
- property alias singleSelection: d.singleSelection
+ property bool showSelectionIndicator: true
+ property bool selectionAllowed: true
+ property bool multiSelection: false
+ property var selection: []
- property bool useEnabledRole: true
+ signal toggleNetwork(int chainId, int index)
- /// \c network is a network.model.nim entry. \c model and \c index for the current selection
- /// It is called for every toggled network if \c singleSelection.enabled is \c false
- /// If \c singleSelection.enabled is \c true, it is called only for the selected network when the selection changes
- /// \see SingleSelectionInfo
- signal toggleNetwork(var network, int index)
-
- QtObject {
- id: d
-
- property SingleSelectionInfo singleSelection: SingleSelectionInfo {}
+ onSelectionChanged: {
+ if (root.selection !== scrollView.selection) {
+ scrollView.selection = root.selection
+ }
}
modal: false
- standardButtons: Dialog.NoButton
-
- anchors.centerIn: undefined
padding: 4
- width: 360
- implicitHeight: Math.min(432, scrollView.contentHeight + root.padding * 2)
-
- closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
+ implicitWidth: 300
background: Rectangle {
radius: Style.current.radius
@@ -65,20 +51,25 @@ StatusDialog {
}
}
- NetworkSelectionView {
+ contentItem: NetworkSelectorView {
id: scrollView
- width: parent.width
- height: parent.height
- anchors.fill: parent
- flatNetworks: root.flatNetworks
- preferredNetworksMode: root.preferredNetworksMode
- preferredSharingNetworks: root.preferredSharingNetworks
- useEnabledRole: root.useEnabledRole
- singleSelection: d.singleSelection
- onToggleNetwork: (network, index) => {
- root.toggleNetwork(network, index)
- if(d.singleSelection.enabled)
- close()
+
+ model: root.flatNetworks
+ interactive: root.selectionAllowed
+ multiSelection: root.multiSelection
+ showIndicator: root.showSelectionIndicator
+ selection: root.selection
+
+ onSelectionChanged: {
+ if (root.selection !== scrollView.selection) {
+ root.selection = scrollView.selection
+ }
+ }
+
+ onToggleNetwork: {
+ if (!root.multiSelection && root.closePolicy !== Popup.NoAutoClose)
+ root.close()
+ root.toggleNetwork(chainId, index)
}
}
}
diff --git a/ui/app/AppLayouts/Wallet/popups/ReceiveModal.qml b/ui/app/AppLayouts/Wallet/popups/ReceiveModal.qml
index 0edfbc2147..8911b4b17f 100644
--- a/ui/app/AppLayouts/Wallet/popups/ReceiveModal.qml
+++ b/ui/app/AppLayouts/Wallet/popups/ReceiveModal.qml
@@ -45,7 +45,7 @@ StatusModal {
signal updatePreferredChains(string address, string preferredChains)
onSelectedAccountChanged: {
- d.preferredChainIdsArray = root.selectedAccount.preferredSharingChainIds.split(":").filter(Boolean)
+ d.preferredChainIdsArray = root.selectedAccount.preferredSharingChainIds.split(":").filter(Boolean).map(Number)
}
width: 556
@@ -158,7 +158,15 @@ StatusModal {
readonly property bool multiChainView: tabBar.currentIndex === 1
readonly property int advanceFooterHeight: 88
- property var preferredChainIdsArray: root.selectedAccount.preferredSharingChainIds.split(":").filter(Boolean)
+ property var preferredChainIdsArray: []
+ Binding on preferredChainIdsArray {
+ value: root.selectedAccount.preferredSharingChainIds.split(":").filter(Boolean).map(Number)
+ }
+ onPreferredChainIdsArrayChanged: {
+ if (preferredChainIdsArray !== selectPopup.selection) {
+ selectPopup.selection = preferredChainIdsArray
+ }
+ }
property var preferredChainIds: d.preferredChainIdsArray.join(":")
readonly property string preferredChainShortNames: d.multiChainView? root.getNetworkShortNames(d.preferredChainIds) : ""
@@ -274,8 +282,8 @@ StatusModal {
enabled: false
button.visible: false
title: model.shortName
- asset.name: Style.svg("tiny/" + model.iconUrl)
- visible: d.preferredChainIdsArray.includes(model.chainId.toString())
+ asset.name: model.isTest ? Style.svg(model.iconUrl + "-test") : Style.svg(model.iconUrl)
+ visible: d.preferredChainIdsArray.includes(model.chainId)
}
}
}
@@ -302,16 +310,15 @@ StatusModal {
margins: -1 // to allow positioning outside the bounds of the dialog
flatNetworks: root.store.filteredFlatModel
- preferredNetworksMode: true
- preferredSharingNetworks: d.preferredChainIdsArray
-
- useEnabledRole: false
+ selection: d.preferredChainIdsArray
+ multiSelection: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
- onToggleNetwork: (network, index) => {
- d.preferredChainIdsArray = store.processPreferredSharingNetworkToggle(d.preferredChainIdsArray, network)
- }
+ onSelectionChanged: {
+ if (selection !== d.preferredChainIdsArray)
+ d.preferredChainIdsArray = selection
+ }
onClosed: {
root.updatePreferredChains(root.selectedAccount.address, d.preferredChainIds)
diff --git a/ui/app/AppLayouts/Wallet/popups/swap/SwapModal.qml b/ui/app/AppLayouts/Wallet/popups/swap/SwapModal.qml
index b6d1b0b3d3..626bfedceb 100644
--- a/ui/app/AppLayouts/Wallet/popups/swap/SwapModal.qml
+++ b/ui/app/AppLayouts/Wallet/popups/swap/SwapModal.qml
@@ -119,15 +119,14 @@ StatusDialog {
objectName: "networkFilter"
Layout.alignment: Qt.AlignVCenter
multiSelection: false
- showRadioButtons: false
+ showSelectionIndicator: false
showTitle: false
flatNetworks: root.swapAdaptor.filteredFlatNetworksModel
- onToggleNetwork: (network) => {
- root.swapInputParamsForm.selectedNetworkChainId = network.chainId
- }
- Component.onCompleted: {
- if(root.swapInputParamsForm.selectedNetworkChainId !== -1)
- networkFilter.setChain(root.swapInputParamsForm.selectedNetworkChainId)
+ selection: [root.swapInputParamsForm.selectedNetworkChainId]
+ onSelectionChanged: {
+ if (root.swapInputParamsForm.selectedNetworkChainId !== selection[0]) {
+ root.swapInputParamsForm.selectedNetworkChainId = selection[0]
+ }
}
}
@@ -141,7 +140,7 @@ StatusDialog {
Connections {
target: root.swapInputParamsForm
function onSelectedNetworkChainIdChanged() {
- networkFilter.setChain(root.swapInputParamsForm.selectedNetworkChainId)
+ networkFilter.selection = [root.swapInputParamsForm.selectedNetworkChainId]
}
}
}
diff --git a/ui/app/AppLayouts/Wallet/stores/NetworkSelectPopup/SingleSelectionInfo.qml b/ui/app/AppLayouts/Wallet/stores/NetworkSelectPopup/SingleSelectionInfo.qml
deleted file mode 100644
index 0de6a03acd..0000000000
--- a/ui/app/AppLayouts/Wallet/stores/NetworkSelectPopup/SingleSelectionInfo.qml
+++ /dev/null
@@ -1,8 +0,0 @@
-import QtQml 2.15
-
-/// Inline component was failing on Linux with "Cannot assign to property of unknown type" so we need to use a separate file for it.
-QtObject {
- property bool enabled: false
- property var currentModel
- property int currentIndex: 0
-}
diff --git a/ui/app/AppLayouts/Wallet/stores/RootStore.qml b/ui/app/AppLayouts/Wallet/stores/RootStore.qml
index 275fd2115e..324461694e 100644
--- a/ui/app/AppLayouts/Wallet/stores/RootStore.qml
+++ b/ui/app/AppLayouts/Wallet/stores/RootStore.qml
@@ -474,29 +474,6 @@ QtObject {
}
}
- function processPreferredSharingNetworkToggle(preferredSharingNetworks, toggledNetwork) {
- let prefChains = preferredSharingNetworks
- if(prefChains.length === root.filteredFlatModel.count) {
- prefChains = [toggledNetwork.chainId.toString()]
- }
- else if(!prefChains.includes(toggledNetwork.chainId.toString())) {
- prefChains.push(toggledNetwork.chainId.toString())
- }
- else {
- if(prefChains.length === 1) {
- prefChains = getAllNetworksChainIds()
- }
- else {
- for(var i = 0; i < prefChains.length;i++) {
- if(prefChains[i] === toggledNetwork.chainId.toString()) {
- prefChains.splice(i, 1)
- }
- }
- }
- }
- return prefChains
- }
-
function updateWatchAccountHiddenFromTotalBalance(address, hideFromTotalBalance) {
walletSectionAccounts.updateWatchAccountHiddenFromTotalBalance(address, hideFromTotalBalance)
}
diff --git a/ui/app/AppLayouts/Wallet/views/NetworkSelectorView.qml b/ui/app/AppLayouts/Wallet/views/NetworkSelectorView.qml
index 86b3117983..c9a0241ee1 100644
--- a/ui/app/AppLayouts/Wallet/views/NetworkSelectorView.qml
+++ b/ui/app/AppLayouts/Wallet/views/NetworkSelectorView.qml
@@ -21,6 +21,7 @@ StatusListView {
chainId [int] - chain unique identifier
iconUrl [string] - SVG icon name. e.g. "network/Network=Ethereum"
layer [int] - chain layer. e.g. 1 or 2
+ isTest [bool] - true if the chain is a testnet
**/
property bool showIndicator: true
property bool multiSelection: false
@@ -71,7 +72,7 @@ StatusListView {
height: 48
width: ListView.view.width
title: model.chainName
- iconUrl: Style.svg(model.iconUrl)
+ iconUrl: model.isTest ? Style.svg(model.iconUrl + "-test") : Style.svg(model.iconUrl)
showIndicator: root.showIndicator
multiSelection: root.multiSelection
interactive: root.interactive
@@ -100,7 +101,8 @@ StatusListView {
required property int section
width: parent.width
height: active ? 44 : 0
- sourceComponent: section === 2 ? layer2text: null
+ active: section === 2
+ sourceComponent: layer2text
Component {
id: layer2text
diff --git a/ui/imports/assets/icons/network/Network=Arbitrum-test.svg b/ui/imports/assets/icons/network/Network=Arbitrum-test.svg
new file mode 100644
index 0000000000..113382dc3a
--- /dev/null
+++ b/ui/imports/assets/icons/network/Network=Arbitrum-test.svg
@@ -0,0 +1,15 @@
+
diff --git a/ui/imports/assets/icons/network/Network=Ethereum-test.svg b/ui/imports/assets/icons/network/Network=Ethereum-test.svg
new file mode 100644
index 0000000000..80e559685f
--- /dev/null
+++ b/ui/imports/assets/icons/network/Network=Ethereum-test.svg
@@ -0,0 +1,9 @@
+
diff --git a/ui/imports/assets/icons/network/Network=Optimism-test.svg b/ui/imports/assets/icons/network/Network=Optimism-test.svg
new file mode 100644
index 0000000000..9fbfc8ad6e
--- /dev/null
+++ b/ui/imports/assets/icons/network/Network=Optimism-test.svg
@@ -0,0 +1,5 @@
+
diff --git a/ui/imports/shared/popups/walletconnect/ConnectDAppModal.qml b/ui/imports/shared/popups/walletconnect/ConnectDAppModal.qml
index 59da3af04c..9f9c68a9ff 100644
--- a/ui/imports/shared/popups/walletconnect/ConnectDAppModal.qml
+++ b/ui/imports/shared/popups/walletconnect/ConnectDAppModal.qml
@@ -8,6 +8,7 @@ import QtGraphicalEffects 1.15
import StatusQ 0.1
import StatusQ.Core 0.1
+import StatusQ.Core.Utils 0.1
import StatusQ.Popups.Dialog 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
@@ -31,6 +32,7 @@ StatusDialog {
required property var flatNetworks
readonly property alias selectedAccount: d.selectedAccount
+ readonly property alias selectedChains: d.selectedChains
readonly property int notConnectedStatus: 0
readonly property int connectionSuccessfulStatus: 1
@@ -206,14 +208,21 @@ StatusDialog {
Layout.fillWidth: true
}
- // TODO: replace with a specialized network selection control
NetworkFilter {
+ id: networkFilter
Layout.preferredWidth: accountsDropdown.Layout.preferredWidth
flatNetworks: d.filteredChains
- showAllSelectedText: false
- showCheckboxes: false
- enabled: d.connectionStatus === root.notConnectedStatus
+ showTitle: true
+ multiSelection: true
+ selectionAllowed: d.connectionStatus === root.notConnectedStatus && d.allChainIdsAggregator.value.length > 1
+ selection: d.selectedChains
+
+ onSelectionChanged: {
+ if (d.selectedChains !== networkFilter.selection) {
+ d.selectedChains = networkFilter.selection
+ }
+ }
}
}
}
@@ -372,6 +381,7 @@ StatusDialog {
}
property var selectedAccount: ({})
+ property var selectedChains: allChainIdsAggregator.value
readonly property var filteredChains: LeftJoinModel {
leftModel: d.dappChains
@@ -380,6 +390,14 @@ StatusDialog {
joinRole: "chainId"
}
+ readonly property FunctionAggregator allChainIdsAggregator: FunctionAggregator {
+ model: d.filteredChains
+ initialValue: []
+ roleName: "chainId"
+
+ aggregateFunction: (aggr, value) => [...aggr, value]
+ }
+
readonly property var dappChains: ListModel {}
property int connectionStatus: notConnectedStatus