feat(@desktop/wallet): Networks - Edit Network

fixes #11434
This commit is contained in:
Khushboo Mehta 2023-07-11 17:10:26 +02:00 committed by Khushboo-dev-cpp
parent c3c74b9f61
commit 4d6c8a840b
21 changed files with 782 additions and 203 deletions

View File

@ -0,0 +1,40 @@
import strformat
import ./item
type
CombinedItem* = object
prod: Item
test: Item
layer: int
proc initCombinedItem*(
prod: Item,
test: Item,
layer: int
): CombinedItem =
result.prod = prod
result.test = test
result.layer = layer
proc `$`*(self: CombinedItem): string =
result = fmt"""CombinedItem(
prod: {self.prod},
test: {self.test},
layer: {self.layer},
]"""
proc getProd*(self: CombinedItem): Item =
return self.prod
proc getTest*(self: CombinedItem): Item =
return self.test
proc getLayer*(self: CombinedItem): int =
return self.layer
proc getShortName*(self: CombinedItem, areTestNetworksEnabled: bool): string =
if areTestNetworksEnabled:
return self.test.shortName()
else:
return self.prod.shortName()

View File

@ -0,0 +1,78 @@
import NimQml, Tables, strutils, strformat
import ./combined_item
type
ModelRole* {.pure.} = enum
Prod = UserRole + 1,
Test
Layer
QtObject:
type
CombinedModel* = ref object of QAbstractListModel
items: seq[CombinedItem]
proc delete(self: CombinedModel) =
self.items = @[]
self.QAbstractListModel.delete
proc setup(self: CombinedModel) =
self.QAbstractListModel.setup
proc newCombinedModel*(): CombinedModel =
new(result, delete)
result.setup
proc `$`*(self: CombinedModel): string =
for i in 0 ..< self.items.len:
result &= fmt"""[{i}]:({$self.items[i]})"""
proc countChanged(self: CombinedModel) {.signal.}
proc getCount(self: CombinedModel): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
method rowCount*(self: CombinedModel, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: CombinedModel): Table[int, string] =
{
ModelRole.Prod.int:"prod",
ModelRole.Test.int:"test",
ModelRole.Layer.int:"layer",
}.toTable
method data(self: CombinedModel, index: QModelIndex, role: int): QVariant =
if (not index.isValid):
return
if (index.row < 0 or index.row >= self.items.len):
return
let item = self.items[index.row]
let enumRole = role.ModelRole
case enumRole:
of ModelRole.Prod:
result = newQVariant(item.getProd())
of ModelRole.Test:
result = newQVariant(item.getTest())
of ModelRole.Layer:
result = newQVariant(item.getLayer())
proc setItems*(self: CombinedModel, items: seq[CombinedItem]) =
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()
proc getAllNetworksSupportedPrefix*(self: CombinedModel, areTestNetworksEnabled: bool): string =
var networkString = ""
for item in self.items:
networkString = networkString & item.getShortName(areTestNetworksEnabled) & ':'
return networkString

View File

@ -34,11 +34,14 @@ proc init*(self: Controller) =
self.events.on(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED) do(e: Args):
self.delegate.refreshNetworks()
proc getNetworks*(self: Controller): seq[NetworkDto] =
return self.networkService.getNetworks()
proc getNetworks*(self: Controller): seq[CombinedNetworkDto] =
return self.networkService.getCombinedNetworks()
proc areTestNetworksEnabled*(self: Controller): bool =
return self.settingsService.areTestNetworksEnabled()
proc toggleTestNetworksEnabled*(self: Controller) =
self.walletAccountService.toggleTestNetworksEnabled()
self.walletAccountService.toggleTestNetworksEnabled()
proc updateNetworkEndPointValues*(self: Controller, chainId: int, newMainRpcInput, newFailoverRpcUrl: string) =
self.networkService.updateNetworkEndPointValues(chainId, newMainRpcInput, newFailoverRpcUrl)

View File

@ -26,4 +26,7 @@ method toggleTestNetworksEnabled*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
raise newException(ValueError, "No implementation available")
raise newException(ValueError, "No implementation available")
method updateNetworkEndPointValues*(self: AccessInterface, chainId: int, newMainRpcInput, newFailoverRpcUrl: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -1,53 +1,140 @@
import strformat
import NimQml, strformat
type
Item* = object
chainId: int
layer: int
chainName: string
iconUrl: string
shortName: string
chainColor: string
QtObject:
type Item* = ref object of QObject
chainId: int
layer: int
chainName: string
iconUrl: string
shortName: string
chainColor: string
rpcURL: string
fallbackURL: string
blockExplorerURL: string
nativeCurrencySymbol: string
proc initItem*(
chainId: int,
layer: int,
chainName: string,
iconUrl: string,
shortName: string,
chainColor: string,
): Item =
result.chainId = chainId
result.layer = layer
result.chainName = chainName
result.iconUrl = iconUrl
result.shortName = shortName
result.chainColor = chainColor
proc setup*(self: Item,
chainId: int,
layer: int,
chainName: string,
iconUrl: string,
shortName: string,
chainColor: string,
rpcURL: string,
fallbackURL: string,
blockExplorerURL: string,
nativeCurrencySymbol: string
) =
self.QObject.setup
self.chainId = chainId
self.layer = layer
self.chainName = chainName
self.iconUrl = iconUrl
self.shortName = shortName
self.chainColor = chainColor
self.rpcURL = rpcURL
self.fallbackURL = fallbackURL
self.blockExplorerURL = blockExplorerURL
self.nativeCurrencySymbol = nativeCurrencySymbol
proc `$`*(self: Item): string =
result = fmt"""NetworkItem(
chainId: {self.chainId},
chainName: {self.chainName},
layer: {self.layer},
iconUrl:{self.iconUrl},
shortName: {self.shortName},
chainColor: {self.chainColor},
]"""
proc delete*(self: Item) =
self.QObject.delete
proc getChainId*(self: Item): int =
return self.chainId
proc newItem*(
chainId: int,
layer: int,
chainName: string,
iconUrl: string,
shortName: string,
chainColor: string,
rpcURL: string,
fallbackURL: string,
blockExplorerURL: string,
nativeCurrencySymbol: string
): Item =
new(result, delete)
result.setup(chainId, layer, chainName, iconUrl, shortName, chainColor, rpcURL, fallbackURL, blockExplorerURL, nativeCurrencySymbol)
proc getLayer*(self: Item): int =
return self.layer
proc `$`*(self: Item): string =
result = fmt"""NetworkItem(
chainId: {self.chainId},
chainName: {self.chainName},
layer: {self.layer},
iconUrl:{self.iconUrl},
shortName: {self.shortName},
chainColor: {self.chainColor},
rpcURL: {self.rpcURL},
fallbackURL: {self.fallbackURL},
blockExplorerURL: {self.blockExplorerURL},
nativeCurrencySymbol: {self.nativeCurrencySymbol},
]"""
proc getChainName*(self: Item): string =
return self.chainName
proc chainIdChanged*(self: Item) {.signal.}
proc chainId*(self: Item): int {.slot.} =
return self.chainId
QtProperty[int] chainId:
read = chainId
notify = chainIdChanged
proc getIconURL*(self: Item): string =
return self.iconUrl
proc layerChanged*(self: Item) {.signal.}
proc layer*(self: Item): int {.slot.} =
return self.layer
QtProperty[int] layer:
read = layer
notify = layerChanged
proc getShortName*(self: Item): string =
return self.shortName
proc chainNameChanged*(self: Item) {.signal.}
proc chainName*(self: Item): string {.slot.} =
return self.chainName
QtProperty[string] chainName:
read = chainName
notify = chainNameChanged
proc getChainColor*(self: Item): string =
return self.chainColor
proc iconUrlChanged*(self: Item) {.signal.}
proc iconUrl*(self: Item): string {.slot.} =
return self.iconUrl
QtProperty[string] iconUrl:
read = iconUrl
notify = iconUrlChanged
proc shortNameChanged*(self: Item) {.signal.}
proc shortName*(self: Item): string {.slot.} =
return self.shortName
QtProperty[string] shortName:
read = shortName
notify = shortNameChanged
proc chainColorChanged*(self: Item) {.signal.}
proc chainColor*(self: Item): string {.slot.} =
return self.chainColor
QtProperty[string] chainColor:
read = chainColor
notify = chainColorChanged
proc rpcURLChanged*(self: Item) {.signal.}
proc rpcURL*(self: Item): string {.slot.} =
return self.rpcURL
QtProperty[string] rpcURL:
read = rpcURL
notify = rpcURLChanged
proc fallbackURLChanged*(self: Item) {.signal.}
proc fallbackURL*(self: Item): string {.slot.} =
return self.fallbackURL
QtProperty[string] fallbackURL:
read = fallbackURL
notify = fallbackURLChanged
proc blockExplorerURLChanged*(self: Item) {.signal.}
proc blockExplorerURL*(self: Item): string {.slot.} =
return self.blockExplorerURL
QtProperty[string] blockExplorerURL:
read = blockExplorerURL
notify = blockExplorerURLChanged
proc nativeCurrencySymbolChanged*(self: Item) {.signal.}
proc nativeCurrencySymbol*(self: Item): string {.slot.} =
return self.nativeCurrencySymbol
QtProperty[string] nativeCurrencySymbol:
read = nativeCurrencySymbol
notify = nativeCurrencySymbolChanged

View File

@ -1,104 +0,0 @@
import NimQml, Tables, strutils, strformat
import ./item
const EXPLORER_TX_PREFIX* = "/tx/"
type
ModelRole* {.pure.} = enum
ChainId = UserRole + 1,
Layer
ChainName
IconUrl
ShortName
ChainColor
QtObject:
type
Model* = ref object of QAbstractListModel
items: seq[Item]
proc delete(self: Model) =
self.items = @[]
self.QAbstractListModel.delete
proc setup(self: Model) =
self.QAbstractListModel.setup
proc newModel*(): Model =
new(result, delete)
result.setup
proc `$`*(self: Model): string =
for i in 0 ..< self.items.len:
result &= fmt"""[{i}]:({$self.items[i]})"""
proc countChanged(self: Model) {.signal.}
proc getCount(self: Model): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
method rowCount*(self: Model, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: Model): Table[int, string] =
{
ModelRole.ChainId.int:"chainId",
ModelRole.Layer.int:"layer",
ModelRole.ChainName.int:"chainName",
ModelRole.IconUrl.int:"iconUrl",
ModelRole.ShortName.int:"shortName",
ModelRole.ChainColor.int:"chainColor",
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
if (not index.isValid):
return
if (index.row < 0 or index.row >= self.items.len):
return
let item = self.items[index.row]
let enumRole = role.ModelRole
case enumRole:
of ModelRole.ChainId:
result = newQVariant(item.getChainId())
of ModelRole.Layer:
result = newQVariant(item.getLayer())
of ModelRole.ChainName:
result = newQVariant(item.getChainName())
of ModelRole.IconUrl:
result = newQVariant(item.getIconURL())
of ModelRole.ShortName:
result = newQVariant(item.getShortName())
of ModelRole.ChainColor:
result = newQVariant(item.getChainColor())
proc rowData*(self: Model, index: int, column: string): string {.slot.} =
if (index >= self.items.len):
return
let item = self.items[index]
case column:
of "chainId": result = $item.getChainId()
of "layer": result = $item.getLayer()
of "chainName": result = $item.getChainName()
of "iconUrl": result = $item.getIconURL()
of "shortName": result = $item.getShortName()
of "chainColor": result = $item.getChainColor()
proc setItems*(self: Model, items: seq[Item]) =
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()
proc getAllNetworksSupportedPrefix*(self: Model): string =
var networkString = ""
for item in self.items:
networkString = networkString & item.getShortName() & ':'
return networkString

View File

@ -1,6 +1,6 @@
import Tables, NimQml
import ../io_interface as delegate_interface
import io_interface, view, controller
import io_interface, view, controller, combined_item, item
import ../../../../../core/eventemitter
import ../../../../../../app_service/service/network/service as network_service
import ../../../../../../app_service/service/wallet_account/service as wallet_account_service
@ -39,10 +39,38 @@ method getModuleAsVariant*(self: Module): QVariant =
return self.viewVariant
method refreshNetworks*(self: Module) =
self.view.load(self.controller.getNetworks())
var combinedItems: seq[CombinedItem] = @[]
for n in self.controller.getNetworks():
var prod = newItem(
n.prod.chainId,
n.prod.layer,
n.prod.chainName,
n.prod.iconUrl,
n.prod.shortName,
n.prod.chainColor,
n.prod.rpcURL,
n.prod.fallbackURL,
n.prod.blockExplorerURL,
n.prod.nativeCurrencySymbol
)
var test = newItem(
n.test.chainId,
n.test.layer,
n.test.chainName,
n.test.iconUrl,
n.test.shortName,
n.test.chainColor,
n.test.rpcURL,
n.test.fallbackURL,
n.test.blockExplorerURL,
n.test.nativeCurrencySymbol
)
combinedItems.add(initCombinedItem(prod,test,n.prod.layer))
self.view.setItems(combinedItems)
method load*(self: Module) =
self.controller.init()
self.view.load()
self.view.setAreTestNetworksEnabled(self.controller.areTestNetworksEnabled())
self.refreshNetworks()
@ -61,4 +89,7 @@ method areTestNetworksEnabled*(self: Module): bool =
method toggleTestNetworksEnabled*(self: Module) =
self.controller.toggleTestNetworksEnabled()
self.refreshNetworks()
self.refreshNetworks()
method updateNetworkEndPointValues*(self: Module, chainId: int, newMainRpcInput, newFailoverRpcUrl: string) =
self.controller.updateNetworkEndPointValues(chainId, newMainRpcInput, newFailoverRpcUrl)

View File

@ -1,27 +1,29 @@
import Tables, NimQml, sequtils, sugar
import ../../../../../../app_service/service/network/dto
#import ../../../../../../app_service/service/network/dto
import ./io_interface
import ./model
import ./item
#import ./item
import ./combined_item
import ./combined_model
QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
networks: Model
combinedNetworks: CombinedModel
areTestNetworksEnabled: bool
proc setup(self: View) =
self.QObject.setup
proc delete*(self: View) =
self.combinedNetworks.delete
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.delegate = delegate
result.networks = newModel()
result.combinedNetworks = newCombinedModel()
result.setup()
proc areTestNetworksEnabledChanged*(self: View) {.signal.}
@ -42,29 +44,21 @@ QtObject:
self.areTestNetworksEnabled = not self.areTestNetworksEnabled
self.areTestNetworksEnabledChanged()
proc networksChanged*(self: View) {.signal.}
proc combinedNetworksChanged*(self: View) {.signal.}
proc getCombinedNetworks(self: View): QVariant {.slot.} =
return newQVariant(self.combinedNetworks)
QtProperty[QVariant] combinedNetworks:
read = getCombinedNetworks
notify = combinedNetworksChanged
proc getNetworks(self: View): QVariant {.slot.} =
return newQVariant(self.networks)
QtProperty[QVariant] networks:
read = getNetworks
notify = networksChanged
proc load*(self: View, networks: seq[NetworkDto]) =
var items: seq[Item] = @[]
for n in networks:
items.add(initItem(
n.chainId,
n.layer,
n.chainName,
n.iconUrl,
n.shortName,
n.chainColor
))
self.networks.setItems(items)
proc load*(self: View) =
self.delegate.viewDidLoad()
proc setItems*(self: View, combinedItems: seq[CombinedItem]) =
self.combinedNetworks.setItems(combinedItems)
proc getAllNetworksSupportedPrefix*(self: View): string {.slot.} =
return self.networks.getAllNetworksSupportedPrefix()
return self.combinedNetworks.getAllNetworksSupportedPrefix(self.areTestNetworksEnabled)
proc updateNetworkEndPointValues*(self: View, chainId: int, newMainRpcInput, newFailoverRpcUrl: string) =
self.delegate.updateNetworkEndPointValues(chainId, newMainRpcInput, newFailoverRpcUrl)

View File

@ -9,7 +9,7 @@ type NetworkDto* = ref object
layer* {.serializedFieldName("layer").}: int
chainName* {.serializedFieldName("chainName").}: string
rpcURL* {.serializedFieldName("rpcUrl").}: string
fallbackURL* {.serializedFieldName("fallbackUrl").}: string
fallbackURL* {.serializedFieldName("fallbackURL").}: string
blockExplorerURL* {.serializedFieldName("blockExplorerUrl").}: string
iconURL* {.serializedFieldName("iconUrl").}: string
nativeCurrencyName* {.serializedFieldName("nativeCurrencyName").}: string
@ -20,10 +20,6 @@ type NetworkDto* = ref object
shortName* {.serializedFieldName("shortName").}: string
relatedChainId* {.serializedFieldName("relatedChainId").}: int
type CombinedNetworkDto* = ref object
prod* {.serializedFieldName("Prod").}: NetworkDto
test* {.serializedFieldName("Test").}: NetworkDto
proc `$`*(self: NetworkDto): string =
return fmt"""Network(
chainId:{self.chainId},
@ -51,3 +47,14 @@ proc sntSymbol*(self: NetworkDto): string =
return "SNT"
else:
return "STT"
type CombinedNetworkDto* = ref object
prod* {.serializedFieldName("Prod").}: NetworkDto
test* {.serializedFieldName("Test").}: NetworkDto
proc `$`*(self: CombinedNetworkDto): string =
return fmt"""CombinedNetworkDto(
prod:{$self.prod},
test:{$self.test},
)"""

View File

@ -45,6 +45,9 @@ proc fetchNetworks*(self: Service, useCached: bool = true): seq[CombinedNetworkD
self.networks = result
self.networksInited = true
proc getCombinedNetworks*(self: Service): seq[CombinedNetworkDto] =
return self.fetchNetworks()
proc getNetworks*(self: Service): seq[NetworkDto] =
let testNetworksEnabled = self.settingsService.areTestNetworksEnabled()
@ -136,3 +139,18 @@ proc getNetworkForCollectibles*(self: Service): NetworkDto =
return self.getNetwork(Goerli)
return self.getNetwork(Mainnet)
proc updateNetworkEndPointValues*(self: Service, chainId: int, newMainRpcInput, newFailoverRpcUrl: string) =
let network = self.getNetwork(chainId)
if network.rpcURL == newMainRpcInput and network.fallbackURL == newFailoverRpcUrl:
return
if network.rpcURL != newMainRpcInput:
network.rpcURL = newMainRpcInput
if network.fallbackURL != newFailoverRpcUrl:
network.fallbackURL = newFailoverRpcUrl
self.upsertNetwork(network)

View File

@ -81,6 +81,10 @@ ListModel {
title: "OwnerTokenWelcomeView"
section: "Views"
}
ListElement {
title: "EditNetworkView"
section: "Views"
}
ListElement {
title: "StatusCommunityCard"
section: "Panels"

View File

@ -0,0 +1,108 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import AppLayouts.Profile.views.wallet 1.0
import Storybook 1.0
import utils 1.0
SplitView {
Logs { id: logs }
QtObject {
id: d
property var network: [{
prod: {
chainId: 1,
nativeCurrencyDecimals: 18,
layer: 1,
chainName: "Mainnet",
rpcURL: "https://eth-archival.gateway.pokt.network/v1/lb/7178a5d77466455882b2fb60",
fallbackURL: "https://eth-archival.gateway.pokt.network/v1/lb/7178a5d77466455882b2fb60",
blockExplorerURL: "https://etherscan.io/",
iconURL: "network/Network=Ethereum",
nativeCurrencyName: "Ether",
nativeCurrencySymbol: "ETH",
isTest: false,
enabled: true,
chainColor: "#627EEA",
shortName: "eth",
relatedChainId: 5,
},
test: {
chainId: 5,
nativeCurrencyDecimals: 18,
layer: 1,
chainName: "Mainnet",
rpcURL: "https://goerli-archival.gateway.pokt.network/v1/lb/7178a5d77466455882b2fb60",
fallbackURL: "https://eth-archival.gateway.pokt.network/v1/lb/7178a5d77466455882b2fb60",
blockExplorerURL: "https://goerli.etherscan.io/",
iconURL: "network/Network=Ethereum",
nativeCurrencyName: "Ether",
nativeCurrencySymbol: "ETH",
isTest: true,
enabled: true,
chainColor: "#939BA1",
shortName: "eth",
relatedChainId: 1
}
}]
property var timer: Timer {
interval: 1000
onTriggered: {
let state = checkbox.checked ? EditNetworkForm.Verified: EditNetworkForm.InvalidURL
networkModule.urlVerified(networkModule.url, state)
}
}
}
property var networkModule: QtObject {
id: networkModule
signal urlVerified(string url, int status)
property string url
function evaluateRpcEndPoint(url) {
networkModule.url = url
d.timer.restart()
}
}
SplitView {
orientation: Qt.Vertical
SplitView.fillWidth: true
Item {
SplitView.fillWidth: true
SplitView.fillHeight: true
EditNetworkView {
width: 560
combinedNetwork: d.network[0]
onEvaluateRpcEndPoint: networkModule.evaluateRpcEndPoint(url)
networksModule: networkModule
onUpdateNetworkValues: console.error(String("Updated network with chainId %1 with new main rpc url = %2 and faalback rpc =%3").arg(chainId).arg(newMainRpcInput).arg(newFailoverRpcUrl))
}
}
LogsAndControlsPanel {
id: logsAndControlsPanel
SplitView.minimumHeight: 100
SplitView.preferredHeight: childrenRect.height
logsView.logText: logs.logText
CheckBox {
id: checkbox
text: "valid url"
checked: true
}
}
}
}

View File

@ -22,7 +22,7 @@ StatusListItem {
title: account.name
subTitle: {
const elidedAddress = StatusQUtils.Utils.elideText(account.address,6,4)
return sensor.containsMouse ? WalletUtils.colorizedChainPrefix(chainShortNames) + Utils.richColorText(elidedAddress, Theme.palette.directColor1) : elidedAddress
return sensor.containsMouse ? WalletUtils.colorizedChainPrefix(chainShortNames) + Utils.richColorText(elidedAddress, Theme.palette.directColor1) : chainShortNames + elidedAddress
}
asset.color: !!account.colorId ? Utils.getColorForId(account.colorId): ""
asset.emoji: account.emoji

View File

@ -11,7 +11,7 @@ QtObject {
property var accountSensitiveSettings: Global.appIsReady? localAccountSensitiveSettings : null
readonly property bool areTestNetworksEnabled: networksModule.areTestNetworksEnabled
property var networks: networksModule.networks
readonly property var combinedNetworks: networksModule.combinedNetworks
function toggleTestNetworksEnabled(){
networksModule.toggleTestNetworksEnabled()
@ -50,4 +50,12 @@ QtObject {
function runAddAccountPopup() {
walletSection.runAddAccountPopup(false)
}
function evaluateRpcEndPoint(url) {
// TODO: connect with nim api once its ready
}
function updateNetworkEndPointValues(chainId, newMainRpcInput, newFailoverRpcUrl) {
networksModule.updateNetworkEndPointValues(chainId, newMainRpcInput, newFailoverRpcUrl)
}
}

View File

@ -16,10 +16,12 @@ Item {
property int contentWidth
readonly property int contentHeight: root.height - titleRow.height - Style.current.padding
property alias titleRowLeftComponentLoader: leftLoader
property alias titleRowComponentLoader: loader
property list<Item> headerComponents
property alias bottomHeaderComponents: secondHeaderRow.contentItem
default property Item content
property alias titleLayout: titleLayout
property bool dirty: false
property bool saveChangesButtonEnabled: false
@ -59,11 +61,16 @@ Item {
spacing: 0
RowLayout {
id: titleLayout
Layout.preferredWidth: (parent.width - Style.current.padding)
Layout.preferredHeight: visible ? d.titleRowHeight : 0
Layout.leftMargin: Style.current.padding
visible: (root.sectionTitle !== "")
Loader {
id: leftLoader
}
StatusBaseText {
Layout.fillWidth: true
text: root.sectionTitle

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.13
import QtGraphicalEffects 1.13
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import utils 1.0
import shared 1.0
@ -25,15 +26,21 @@ SettingsContentBase {
readonly property int mainViewIndex: 0;
readonly property int networksViewIndex: 1;
readonly property int accountOrderViewIndex: 2;
readonly property int accountViewIndex: 3;
readonly property int editNetworksViewIndex: 2;
readonly property int accountOrderViewIndex: 3;
readonly property int accountViewIndex: 4;
Component.onCompleted: {
root.titleRowComponentLoader.sourceComponent = addNewAccountButtonComponent
}
function resetStack() {
stackContainer.currentIndex = mainViewIndex;
if(stackContainer.currentIndex === root.editNetworksViewIndex) {
stackContainer.currentIndex = root.networksViewIndex
}
else {
stackContainer.currentIndex = mainViewIndex;
}
}
StackLayout {
@ -46,6 +53,9 @@ SettingsContentBase {
root.rootStore.backButtonName = ""
root.sectionTitle = qsTr("Wallet")
root.titleRowComponentLoader.sourceComponent = undefined
root.titleRowLeftComponentLoader.sourceComponent = undefined
root.titleRowLeftComponentLoader.visible = false
root.titleLayout.spacing = 5
if (currentIndex == root.mainViewIndex) {
root.titleRowComponentLoader.sourceComponent = addNewAccountButtonComponent
@ -55,6 +65,13 @@ SettingsContentBase {
root.rootStore.backButtonName = qsTr("Wallet")
root.sectionTitle = qsTr("Networks")
}
if(currentIndex == root.editNetworksViewIndex) {
root.rootStore.backButtonName = qsTr("Networks")
root.sectionTitle = qsTr("Edit %1").arg(!!editNetwork.combinedNetwork.prod && !!editNetwork.combinedNetwork.prod.chainName ? editNetwork.combinedNetwork.prod.chainName: "")
root.titleRowLeftComponentLoader.visible = true
root.titleRowLeftComponentLoader.sourceComponent = networkIcon
root.titleLayout.spacing = 12
}
else if(currentIndex == root.accountViewIndex) {
root.rootStore.backButtonName = qsTr("Wallet")
root.sectionTitle = ""
@ -88,14 +105,33 @@ SettingsContentBase {
}
NetworksView {
Layout.fillWidth: true
walletStore: root.walletStore
onGoBack: {
stackContainer.currentIndex = mainViewIndex
}
onEditNetwork: {
editNetwork.combinedNetwork = network
stackContainer.currentIndex = editNetworksViewIndex
}
}
EditNetworkView {
id: editNetwork
Layout.fillHeight: true
Layout.fillWidth: true
networksModule: root.walletStore.networksModule
onEvaluateRpcEndPoint: root.walletStore.evaluateRpcEndPoint(url)
onUpdateNetworkValues: root.walletStore.updateNetworkValues(chainId, newMainRpcInput, newFailoverRpcUrl)
}
AccountOrderView {
Layout.fillWidth: true
Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding
walletStore: root.walletStore
onGoBack: {
stackContainer.currentIndex = mainViewIndex
@ -123,5 +159,15 @@ SettingsContentBase {
onClicked: root.walletStore.runAddAccountPopup()
}
}
Component {
id: networkIcon
StatusRoundedImage {
width: 28
height: 28
image.source: Style.svg(!!editNetwork.combinedNetwork.prod && !!editNetwork.combinedNetwork.prod.iconUrl ? editNetwork.combinedNetwork.prod.iconUrl: "")
image.fillMode: Image.PreserveAspectCrop
}
}
}
}

View File

@ -28,11 +28,7 @@ StatusListView {
font.pixelSize: Style.current.primaryTextFontSize
bottomPadding: Style.current.padding
}
anchors.top: parent.top
anchors.left: parent.left
width: parent.width
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
model: SortFilterProxyModel {
sourceModel: walletStore.accounts
sorters: [
@ -86,7 +82,6 @@ StatusListView {
visualIndex: delegateRoot.visualIndex
draggable: accountsView.count > 1
title: {
console.log(model.name, model.position)
return model.name
}
secondaryTitle: model.address

View File

@ -0,0 +1,195 @@
import QtQuick 2.13
import QtQuick.Layouts 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import shared.panels 1.0
import utils 1.0
ColumnLayout {
id: root
property var network
property var networksModule
signal evaluateEndPoint(string url)
signal updateNetworkValues(int chainId, string newMainRpcInput, string newFailoverRpcUrl)
enum EvaluationState {
UnTouched,
Pending,
Verified,
InvalidURL,
PingUnsuccessful
}
QtObject {
id: d
property int evaluationStatus: EditNetworkForm.UnTouched
property int evaluationStatusFallBackRpc: EditNetworkForm.UnTouched
property var evaluateRpcEndPoint: Backpressure.debounce(root, 400, function (value) {
root.evaluateEndPoint(value)
})
function revertValues() {
warningCheckbox.checked = false
d.evaluationStatus = EditNetworkForm.UnTouched
d.evaluationStatusFallBackRpc = EditNetworkForm.UnTouched
if(!!network) {
mainRpcInput.text = network.rpcURL
failoverRpcUrlInput.text = network.fallbackURL
}
}
function getUrlStatusText(status, text) {
switch(status) {
case EditNetworkForm.Pending:
return qsTr("Checking RPC...")
case EditNetworkForm.InvalidURL:
return qsTr("What is %1? This isnt a URL 😒").arg(text)
case EditNetworkForm.PingUnsuccessful:
return qsTr("RPC appears to be either offline or this is not a valid JSON RPC endpoint URL")
case EditNetworkForm.Verified:
return qsTr("RPC successfully reached")
default: return ""
}
}
}
onVisibleChanged: if(!visible) {d.revertValues()}
Connections {
target: networksModule
function onUrlVerified(url, status) {
if(url === mainRpcInput.text) {
d.evaluationStatus = status
}
else if(url === failoverRpcUrlInput.text) {
d.evaluationStatusFallBackRpc = status
}
}
}
spacing: 20
StatusInput {
Layout.fillWidth: true
label: qsTr("Network name")
text: !!network ? network.chainName : ""
input.enabled: false
}
StatusInput {
Layout.fillWidth: true
label: qsTr("Short name")
text: !!network ? network.shortName : ""
input.enabled: false
}
StatusInput {
Layout.fillWidth: true
label: qsTr("Chain ID")
text: !!network ? network.chainId : ""
input.enabled: false
}
StatusInput {
Layout.fillWidth: true
label: qsTr("Native Token Symbol")
text: !!network ? network.nativeCurrencySymbol : ""
input.enabled: false
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
StatusBaseText {
id: requiredText
anchors.top: parent.top
anchors.topMargin: 4
anchors.right: parent.right
elide: Text.ElideRight
text: qsTr("Required")
font.pixelSize: 12
color: Theme.palette.baseColor1
}
StatusInput {
id: mainRpcInput
width: parent.width
label: qsTr("Main JSON RPC URL")
text: !!network ? network.rpcURL : ""
onTextChanged: {
if(!!text && text !== network.rpcURL) {
d.evaluationStatus = EditNetworkForm.Pending
Qt.callLater(d.evaluateRpcEndPoint, text);
}
}
errorMessageCmp.horizontalAlignment: d.evaluationStatus === EditNetworkForm.Pending ||
d.evaluationStatus === EditNetworkForm.Verified ?
Text.AlignLeft: Text.AlignRight
errorMessageCmp.visible: d.evaluationStatus !== EditNetworkForm.UnTouched
errorMessageCmp.text: d.getUrlStatusText(d.evaluationStatus, text)
errorMessageCmp.color: d.evaluationStatus === EditNetworkForm.Pending ?
Theme.palette.baseColor1:
d.evaluationStatus === EditNetworkForm.Verified ?
Theme.palette.successColor1 : Theme.palette.dangerColor1
}
}
StatusInput {
id: failoverRpcUrlInput
Layout.fillWidth: true
label: qsTr("Failover JSON RPC URL")
text: !!network ? network.fallbackURL : ""
onTextChanged: {
if(!!text && text !== network.fallbackURL) {
d.evaluationStatusFallBackRpc = EditNetworkForm.Pending
Qt.callLater(d.evaluateRpcEndPoint, text);
}
}
errorMessageCmp.horizontalAlignment: d.evaluationStatusFallBackRpc === EditNetworkForm.Pending ||
d.evaluationStatusFallBackRpc === EditNetworkForm.Verified ?
Text.AlignLeft: Text.AlignRight
errorMessageCmp.visible: d.evaluationStatusFallBackRpc !== EditNetworkForm.UnTouched
errorMessageCmp.text: d.getUrlStatusText(d.evaluationStatusFallBackRpc, text)
errorMessageCmp.color: d.evaluationStatusFallBackRpc === EditNetworkForm.Pending ?
Theme.palette.baseColor1:
d.evaluationStatusFallBackRpc === EditNetworkForm.Verified ?
Theme.palette.successColor1 : Theme.palette.dangerColor1
}
StatusInput {
Layout.fillWidth: true
label: qsTr("Block Explorer")
text: !!network ? network.blockExplorerURL : ""
input.enabled: false
}
StatusCheckBox {
id: warningCheckbox
Layout.fillWidth: true
text: qsTr("I understand that changing network settings can cause unforeseen issues, errors, security risks and potentially even loss of funds.")
checkState: Qt.Unchecked
font.pixelSize: 15
}
Separator {}
Row {
Layout.alignment: Qt.AlignRight
spacing: 8
StatusButton {
text: qsTr("Revert to default")
normalColor: "transparent"
enabled: d.evaluationStatus !== EditNetworkForm.UnTouched || d.evaluationStatusFallBackRpc !== EditNetworkForm.UnTouched
onClicked: d.revertValues()
}
StatusButton {
text: qsTr("Save Changes")
enabled: (d.evaluationStatus === EditNetworkForm.Verified || d.evaluationStatusFallBackRpc === EditNetworkForm.Verified) && warningCheckbox.checked
onClicked: root.updateNetworkValues(network.chainId, mainRpcInput.text, failoverRpcUrlInput.text)
}
}
}

View File

@ -0,0 +1,53 @@
import QtQuick 2.13
import QtQuick.Layouts 1.13
import StatusQ.Controls 0.1
import utils 1.0
import "../../views"
ColumnLayout {
id: root
property var networksModule
property var combinedNetwork
signal evaluateRpcEndPoint(string url)
signal updateNetworkValues(int chainId, string newMainRpcInput, string newFailoverRpcUrl)
StatusTabBar {
id: editPreviwTabBar
StatusTabButton {
text: qsTr("Live Network")
width: implicitWidth
}
StatusTabButton {
text: qsTr("Test Network")
width: implicitWidth
}
}
StackLayout {
id: stackLayout
Layout.preferredHeight: currentIndex === 0 ? editLiveNetwork.height: editTestNetwork.height
Layout.fillWidth: true
currentIndex: editPreviwTabBar.currentIndex
EditNetworkForm {
id: editLiveNetwork
network: !!root.combinedNetwork ? root.combinedNetwork.prod: null
networksModule: root.networksModule
onEvaluateEndPoint: root.evaluateRpcEndPoint(url)
onUpdateNetworkValues: root.updateNetworkValues(chainId, newMainRpcInput, newFailoverRpcUrl)
}
EditNetworkForm {
id: editTestNetwork
network: !!root.combinedNetwork ? root.combinedNetwork.test: null
networksModule: root.networksModule
onEvaluateEndPoint: root.evaluateRpcEndPoint(url)
onUpdateNetworkValues: root.updateNetworkValues(chainId, newMainRpcInput, newFailoverRpcUrl)
}
}
}

View File

@ -1,5 +1,4 @@
import QtQuick 2.13
import SortFilterProxyModel 0.2
import shared.status 1.0
import shared.popups 1.0
@ -12,6 +11,8 @@ import StatusQ.Components 0.1
import StatusQ.Popups.Dialog 0.1
import utils 1.0
import SortFilterProxyModel 0.2
import "../../stores"
import "../../controls"
@ -20,6 +21,7 @@ Item {
signal goBack
property WalletStore walletStore
signal editNetwork(var network)
Column {
id: column
@ -31,15 +33,16 @@ Item {
Repeater {
id: layer1List
model: SortFilterProxyModel {
sourceModel: walletStore.networks
sourceModel: walletStore.combinedNetworks
filters: ValueFilter {
roleName: "layer"
value: 1
}
}
delegate: WalletNetworkDelegate {
network: model
network: areTestNetworksEnabled ? model.test: model.prod
areTestNetworksEnabled: walletStore.areTestNetworksEnabled
onClicked: editNetwork(model)
}
}
@ -58,15 +61,16 @@ Item {
Repeater {
id: layer2List
model: SortFilterProxyModel {
sourceModel: walletStore.networks
sourceModel: walletStore.combinedNetworks
filters: ValueFilter {
roleName: "layer"
value: 2
}
}
delegate: WalletNetworkDelegate {
network: model
network: areTestNetworksEnabled ? model.test: model.prod
areTestNetworksEnabled: walletStore.areTestNetworksEnabled
onClicked: editNetwork(model)
}
}

View File

@ -0,0 +1,2 @@
EditNetworkView 1.0 EditNetworkView.qml
EditNetworkForm 1.0 EditNetworkForm.qml