feat(networkSelector): Refatoring of NetworkSelector to remove backend dependency

This commit is contained in:
Alex Jbanca 2024-06-16 00:33:12 +03:00 committed by Alex Jbanca
parent 8ca51c34cc
commit 901362dfc1
32 changed files with 491 additions and 557 deletions

View File

@ -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

View File

@ -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)

View File

@ -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 {}

View File

@ -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

View File

@ -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

View File

@ -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]
}
}
}

View File

@ -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: `<b>${model.shortName}</b>` }
Label { text: `ID <b>${model.chainId}</b>` }
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

View File

@ -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) {

View File

@ -85,6 +85,7 @@ SplitView {
filters: ValueFilter { roleName: "isTest"; value: false }
}
function toggleNetwork(chainId) {
print ("toggleNetwork called with chainId: " + chainId)
}
function getAllNetworksSupportedString(hovered) {

View File

@ -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)
}
}
}

View File

@ -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)

View File

@ -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",

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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)
}

View File

@ -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(":"))

View File

@ -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 ""
}
}
}

View File

@ -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

View File

@ -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

View File

@ -96,7 +96,7 @@ ConnectedDappsButton {
flatNetworks: root.wcService.flatNetworks
onConnect: {
root.wcService.approvePairSession(sessionProposal, dappChains, selectedAccount)
root.wcService.approvePairSession(sessionProposal, selectedChains, selectedAccount)
}
onDecline: {

View File

@ -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]
}
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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)

View File

@ -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]
}
}
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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

View File

@ -0,0 +1,15 @@
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12.8086" cy="12" r="12" fill="#858CCC"/>
<g clip-path="url(#clip0_722_225208)">
<path d="M14.1708 13.3962L13.2802 15.8398C13.2582 15.906 13.2582 15.9796 13.2802 16.0532L14.8111 20.2558L16.5849 19.2327L14.4578 13.3962C14.4063 13.2638 14.2223 13.2638 14.1708 13.3962Z" fill="#9DA3D6"/>
<path d="M15.9588 9.29077C15.9073 9.15829 15.7233 9.15829 15.6718 9.29077L14.7812 11.7343C14.7591 11.8005 14.7591 11.8741 14.7812 11.9477L17.291 18.8293L19.0647 17.8063L15.9588 9.29813V9.29077Z" fill="#9DA3D6"/>
<path d="M12.8092 3.93767C12.8533 3.93767 12.8975 3.9524 12.9343 3.97448L19.6908 7.87528C19.7717 7.91944 19.8159 8.00776 19.8159 8.09608V15.8977C19.8159 15.986 19.7644 16.0743 19.6908 16.1185L12.9343 20.0193C12.8975 20.0414 12.8533 20.0561 12.8092 20.0561C12.765 20.0561 12.7209 20.0414 12.6841 20.0193L5.92758 16.1185C5.84662 16.0743 5.80246 15.986 5.80246 15.8977V8.08872C5.80246 8.0004 5.85398 7.91208 5.92758 7.86792L12.6841 3.96712C12.7209 3.94503 12.765 3.93032 12.8092 3.93032V3.93767ZM12.8092 2.79688C12.5663 2.79688 12.3308 2.85576 12.11 2.98088L5.3535 6.88168C4.91926 7.13192 4.6543 7.58823 4.6543 8.08872V15.8903C4.6543 16.3908 4.91926 16.8471 5.3535 17.0974L12.11 20.9982C12.3234 21.1233 12.5663 21.1822 12.8092 21.1822C13.0521 21.1822 13.2876 21.1233 13.5084 20.9982L20.2649 17.0974C20.6991 16.8471 20.9641 16.3908 20.9641 15.8903V8.08872C20.9641 7.58823 20.6991 7.13192 20.2649 6.88168L13.501 2.98088C13.2876 2.85576 13.0447 2.79688 12.8018 2.79688H12.8092Z" fill="#CED1EB"/>
<path d="M12.2351 7.53861H10.5202C10.3951 7.53861 10.2773 7.61957 10.2332 7.73733L6.56055 17.8058L8.33431 18.8288L12.3823 7.73733C12.4191 7.63429 12.3455 7.53125 12.2425 7.53125L12.2351 7.53861Z" fill="white"/>
<path d="M15.2381 7.53861H13.5233C13.3981 7.53861 13.2804 7.61957 13.2362 7.73733L9.04102 19.2337L10.8148 20.2567L15.378 7.73733C15.4148 7.63429 15.3412 7.53125 15.2381 7.53125V7.53861Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_722_225208">
<rect width="18.4" height="18.4" fill="white" transform="translate(3.6084 2.80078)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,9 @@
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.8086 24C19.436 24 24.8086 18.6274 24.8086 12C24.8086 5.37258 19.436 0 12.8086 0C6.18118 0 0.808594 5.37258 0.808594 12C0.808594 18.6274 6.18118 24 12.8086 24Z" fill="#858CCC"/>
<path d="M13.1826 3V9.65282L18.8054 12.1657L13.1826 3Z" fill="white" fill-opacity="0.602"/>
<path d="M13.1833 3L7.56055 12.1657L13.1833 9.65282V3Z" fill="white"/>
<path d="M13.1826 16.475V20.9955L18.8086 13.2109L13.1826 16.475Z" fill="white" fill-opacity="0.602"/>
<path d="M13.1823 20.9955V16.475L7.55957 13.2109L13.1823 20.9955Z" fill="white"/>
<path d="M13.1826 15.4293L18.8054 12.1652L13.1826 9.65234V15.4293Z" fill="white" fill-opacity="0.2"/>
<path d="M7.56055 12.1652L13.1833 15.4293V9.65234L7.56055 12.1652Z" fill="white" fill-opacity="0.602"/>
</svg>

After

Width:  |  Height:  |  Size: 846 B

View File

@ -0,0 +1,5 @@
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.8086 24C19.436 24 24.8086 18.6274 24.8086 12C24.8086 5.37258 19.436 0 12.8086 0C6.18118 0 0.808594 5.37258 0.808594 12C0.808594 18.6274 6.18118 24 12.8086 24Z" fill="#858CCC"/>
<path d="M9.30958 15.1879C8.59438 15.1879 8.00878 15.0199 7.55278 14.6839C7.10158 14.3431 6.87598 13.8535 6.87598 13.2247C6.87598 13.0903 6.89038 12.9319 6.91918 12.7399C6.99598 12.3079 7.10638 11.7895 7.25038 11.1799C7.65838 9.52872 8.71438 8.70312 10.4136 8.70312C10.8744 8.70312 11.292 8.77992 11.6568 8.93832C12.0216 9.08712 12.3096 9.31752 12.5208 9.62472C12.732 9.92712 12.8376 10.2871 12.8376 10.7047C12.8376 10.8295 12.8232 10.9879 12.7944 11.1799C12.7032 11.7127 12.5976 12.2359 12.468 12.7399C12.2568 13.5607 11.8968 14.1799 11.3784 14.5879C10.8648 14.9911 10.1736 15.1879 9.30958 15.1879ZM9.43918 13.8919C9.77518 13.8919 10.0584 13.7911 10.2936 13.5943C10.5336 13.3975 10.7064 13.0951 10.8072 12.6823C10.9464 12.1159 11.052 11.6263 11.124 11.2039C11.148 11.0791 11.1624 10.9495 11.1624 10.8151C11.1624 10.2679 10.8792 9.99432 10.308 9.99432C9.97198 9.99432 9.68398 10.0951 9.44398 10.2919C9.20878 10.4887 9.04078 10.7911 8.93998 11.2039C8.82958 11.6071 8.72398 12.0967 8.61358 12.6823C8.58958 12.8023 8.57518 12.9271 8.57518 13.0615C8.57038 13.6183 8.86318 13.8919 9.43918 13.8919Z" fill="white"/>
<path d="M13.2544 15.1002C13.1872 15.1002 13.1392 15.081 13.1008 15.0378C13.072 14.9898 13.0624 14.937 13.072 14.8746L14.3152 9.01857C14.3248 8.95137 14.3584 8.89857 14.416 8.85537C14.4688 8.81217 14.5264 8.79297 14.5888 8.79297H16.984C17.6512 8.79297 18.184 8.93217 18.5872 9.20577C18.9952 9.48417 19.2016 9.88257 19.2016 10.4058C19.2016 10.5546 19.1824 10.713 19.1488 10.8762C19 11.5674 18.6976 12.0762 18.2368 12.4074C17.7856 12.7386 17.1664 12.9018 16.3792 12.9018H15.1648L14.752 14.8746C14.7376 14.9418 14.7088 14.9946 14.6512 15.0378C14.5984 15.081 14.5408 15.1002 14.4784 15.1002H13.2544ZM16.4416 11.6586C16.696 11.6586 16.912 11.5914 17.0992 11.4522C17.2912 11.313 17.416 11.1162 17.4784 10.857C17.4976 10.7562 17.5072 10.665 17.5072 10.5882C17.5072 10.4154 17.4544 10.281 17.3536 10.1898C17.2528 10.0938 17.0752 10.0458 16.8304 10.0458H15.7504L15.4096 11.6586H16.4416Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -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