feat(@desktop/wallet): right click context menu added for wallet accounts

Handled options from the context menu for wallet accounts:
- Copy address
- Add new account
- Add watch-only account
This commit is contained in:
Sale Djenic 2023-03-27 14:49:32 +02:00 committed by saledjenic
parent baa7bd161d
commit d8b1e47984
10 changed files with 207 additions and 12 deletions

View File

@ -10,7 +10,7 @@ type
method delete*(self: AccessInterface) {.base.} = method delete*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method load*(self: AccessInterface) {.base.} = method load*(self: AccessInterface, addingWatchOnlyAccount: bool) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method closeAddAccountPopup*(self: AccessInterface, switchToAccWithAddress: string = "") {.base.} = method closeAddAccountPopup*(self: AccessInterface, switchToAccWithAddress: string = "") {.base.} =

View File

@ -72,7 +72,7 @@ method delete*[T](self: Module[T]) =
self.viewVariant.delete self.viewVariant.delete
self.controller.delete self.controller.delete
method load*[T](self: Module[T]) = method load*[T](self: Module[T], addingWatchOnlyAccount: bool) =
self.controller.init() self.controller.init()
self.view.setCurrentState(newMainState(nil)) self.view.setCurrentState(newMainState(nil))
@ -91,12 +91,15 @@ method load*[T](self: Module[T]) =
items.add(item) items.add(item)
item = newKeyPairItem(keyUid = Label_OptionAddWatchOnlyAcc) item = newKeyPairItem(keyUid = Label_OptionAddWatchOnlyAcc)
item.setName(Label_NewWatchOnlyAccount) item.setName(Label_NewWatchOnlyAccount)
item.setIcon("objects") item.setIcon("show")
items.add(item) items.add(item)
self.view.setDisablePopup(false) self.view.setDisablePopup(false)
self.view.setOriginModelItems(items) self.view.setOriginModelItems(items)
self.changeSelectedOrigin(items[0].getKeyUid()) if addingWatchOnlyAccount:
self.changeSelectedOrigin(Label_OptionAddWatchOnlyAcc)
else:
self.changeSelectedOrigin(items[0].getKeyUid())
self.delegate.onAddAccountModuleLoaded() self.delegate.onAddAccountModuleLoaded()
proc tryKeycardSync[T](self: Module[T]) = proc tryKeycardSync[T](self: Module[T]) =

View File

@ -58,7 +58,7 @@ method savedAddressesModuleDidLoad*(self: AccessInterface) {.base.} =
method buySellCryptoModuleDidLoad*(self: AccessInterface) {.base.} = method buySellCryptoModuleDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method runAddAccountPopup*(self: AccessInterface) {.base.} = method runAddAccountPopup*(self: AccessInterface, addingWatchOnlyAccount: bool) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method getAddAccountModule*(self: AccessInterface): QVariant {.base.} = method getAddAccountModule*(self: AccessInterface): QVariant {.base.} =

View File

@ -214,11 +214,11 @@ method destroyAddAccountPopup*(self: Module, switchToAccWithAddress: string = ""
self.addAccountModule.delete self.addAccountModule.delete
self.addAccountModule = nil self.addAccountModule = nil
method runAddAccountPopup*(self: Module) = method runAddAccountPopup*(self: Module, addingWatchOnlyAccount: bool) =
self.destroyAddAccountPopup() self.destroyAddAccountPopup()
self.addAccountModule = add_account_module.newModule(self, self.events, self.keycardService, self.accountsService, self.addAccountModule = add_account_module.newModule(self, self.events, self.keycardService, self.accountsService,
self.walletAccountService) self.walletAccountService)
self.addAccountModule.load() self.addAccountModule.load(addingWatchOnlyAccount)
method getAddAccountModule*(self: Module): QVariant = method getAddAccountModule*(self: Module): QVariant =
if self.addAccountModule.isNil: if self.addAccountModule.isNil:

View File

@ -98,8 +98,8 @@ QtObject:
self.isMnemonicBackedUp = mnemonicBackedUp self.isMnemonicBackedUp = mnemonicBackedUp
self.currentCurrencyChanged() self.currentCurrencyChanged()
proc runAddAccountPopup*(self: View) {.slot.} = proc runAddAccountPopup*(self: View, addingWatchOnlyAccount: bool) {.slot.} =
self.delegate.runAddAccountPopup() self.delegate.runAddAccountPopup(addingWatchOnlyAccount)
proc getAddAccountModule(self: View): QVariant {.slot.} = proc getAddAccountModule(self: View): QVariant {.slot.} =
return self.delegate.getAddAccountModule() return self.delegate.getAddAccountModule()

View File

@ -9,7 +9,8 @@ Action {
enum Type { enum Type {
Normal, Normal,
Danger Danger,
Success
} }
property int type: StatusAction.Type.Normal property int type: StatusAction.Type.Normal
@ -37,6 +38,8 @@ Action {
return Theme.palette.baseColor1 return Theme.palette.baseColor1
if (type === StatusAction.Type.Danger) if (type === StatusAction.Type.Danger)
return Theme.palette.dangerColor1 return Theme.palette.dangerColor1
if (type === StatusAction.Type.Success)
return Theme.palette.successColor1
return Theme.palette.primaryColor1 return Theme.palette.primaryColor1
} }
} }

View File

@ -25,6 +25,7 @@ MenuItem {
readonly property bool hasAction: !!root.action readonly property bool hasAction: !!root.action
readonly property bool isStatusAction: d.hasAction && (root.action instanceof StatusAction) readonly property bool isStatusAction: d.hasAction && (root.action instanceof StatusAction)
readonly property bool isStatusDangerAction: d.isStatusAction && root.action.type === StatusAction.Type.Danger readonly property bool isStatusDangerAction: d.isStatusAction && root.action.type === StatusAction.Type.Danger
readonly property bool isStatusSuccessAction: d.isStatusAction && root.action.type === StatusAction.Type.Success
readonly property StatusAssetSettings originalAssetSettings: d.isStatusSubMenu && root.subMenu.assetSettings readonly property StatusAssetSettings originalAssetSettings: d.isStatusSubMenu && root.subMenu.assetSettings
? root.subMenu.assetSettings ? root.subMenu.assetSettings
@ -130,7 +131,9 @@ MenuItem {
text: root.text text: root.text
color: !root.enabled ? Theme.palette.baseColor1 color: !root.enabled ? Theme.palette.baseColor1
: d.isStatusDangerAction ? Theme.palette.dangerColor1 : Theme.palette.directColor1 : d.isStatusDangerAction ? Theme.palette.dangerColor1
: d.isStatusSuccessAction?
Theme.palette.successColor1 : Theme.palette.directColor1
font.pixelSize: d.fontSettings ? d.fontSettings.pixelSize : d.defaultFontSettings.pixelSize font.pixelSize: d.fontSettings ? d.fontSettings.pixelSize : d.defaultFontSettings.pixelSize
font.bold: d.fontSettings ? d.fontSettings.bold : d.defaultFontSettings.bold font.bold: d.fontSettings ? d.fontSettings.bold : d.defaultFontSettings.bold
@ -155,6 +158,8 @@ MenuItem {
return "transparent" return "transparent"
if (d.isStatusDangerAction) if (d.isStatusDangerAction)
return Theme.palette.dangerColor3; return Theme.palette.dangerColor3;
if (d.isStatusSuccessAction)
return Theme.palette.successColor3;
return Theme.palette.statusMenu.hoverBackgroundColor; return Theme.palette.statusMenu.hoverBackgroundColor;
} }
} }

View File

@ -190,6 +190,10 @@ QtObject {
} }
function runAddAccountPopup() { function runAddAccountPopup() {
walletSection.runAddAccountPopup() walletSection.runAddAccountPopup(false)
}
function runAddWatchOnlyAccountPopup() {
walletSection.runAddAccountPopup(true)
} }
} }

View File

@ -0,0 +1,104 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import StatusQ.Popups 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0
import "../stores"
StatusMenu {
id: root
property var account
signal editAccountClicked()
signal deleteAccountClicked()
signal addNewAccountClicked()
signal addWatchOnlyAccountClicked()
width: 204
onAboutToShow: {
d.resetCopyAddressAction()
}
QtObject {
id: d
function resetCopyAddressAction() {
copyAddressAction.action.text = qsTr("Copy address")
copyAddressAction.action.type = StatusAction.Type.Normal
copyAddressAction.action.icon.name = "copy"
copyAddressAction.action.icon.color = Theme.palette.primaryColor1
}
}
StatusMenuItem {
id: copyAddressAction
enabled: !!root.account
text: qsTr("Copy address")
action: StatusAction {}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
RootStore.copyToClipboard(root.account.address?? "")
copyAddressAction.action.text = qsTr("Address copied")
copyAddressAction.action.type = StatusAction.Type.Success
copyAddressAction.action.icon.name = "tiny/checkmark"
copyAddressAction.action.icon.color = Theme.palette.successColor1
Backpressure.debounce(root, 1500, function () {
d.resetCopyAddressAction()
root.dismiss()
})()
}
}
}
StatusMenuSeparator {
visible: !!root.account
}
StatusAction {
enabled: !!root.account
text: qsTr("Edit")
icon.name: "pencil-outline"
onTriggered: {
root.editAccountClicked()
}
}
StatusAction {
enabled: !!root.account && root.account.walletType !== ""
text: qsTr("Delete")
icon.name: "info"
type: StatusAction.Type.Danger
onTriggered: {
root.deleteAccountClicked()
}
}
StatusMenuSeparator {
visible: !!root.account
}
StatusAction {
text: qsTr("Add new account")
icon.name: "add"
onTriggered: {
root.addNewAccountClicked()
}
}
StatusAction {
text: qsTr("Add watch-only account")
icon.name: "show"
onTriggered: {
root.addWatchOnlyAccountClicked()
}
}
}

View File

@ -51,6 +51,19 @@ Rectangle {
} }
} }
Loader {
id: walletBckgAccountContextMenu
sourceComponent: AccountContextMenu {
onAddNewAccountClicked: {
RootStore.runAddAccountPopup()
}
onAddWatchOnlyAccountClicked: {
RootStore.runAddWatchOnlyAccountPopup()
}
}
}
Connections { Connections {
target: walletSection target: walletSection
@ -62,6 +75,18 @@ Rectangle {
} }
} }
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: {
if (mouse.button === Qt.RightButton) {
walletBckgAccountContextMenu.active = true
walletBckgAccountContextMenu.item.popup(mouse.x, mouse.y)
}
}
}
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
spacing: Style.current.padding spacing: Style.current.padding
@ -73,6 +98,14 @@ Rectangle {
Layout.rightMargin: Style.current.padding Layout.rightMargin: Style.current.padding
Layout.topMargin: Style.current.padding Layout.topMargin: Style.current.padding
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: {
mouse.accepted = true
}
}
StatusBaseText { StatusBaseText {
id: walletTitleText id: walletTitleText
text: qsTr("Wallet") text: qsTr("Wallet")
@ -100,6 +133,14 @@ Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: Style.current.padding Layout.leftMargin: Style.current.padding
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: {
mouse.accepted = true
}
}
StyledTextEditWithLoadingState { StyledTextEditWithLoadingState {
id: walletAmountValue id: walletAmountValue
objectName: "walletLeftListAmountValue" objectName: "walletLeftListAmountValue"
@ -177,6 +218,11 @@ Rectangle {
errorIcon.tooltip.maxWidth: 300 errorIcon.tooltip.maxWidth: 300
errorIcon.tooltip.text: networkConnectionStore.accountBalanceNotAvailableText errorIcon.tooltip.text: networkConnectionStore.accountBalanceNotAvailableText
onClicked: { onClicked: {
if (mouse.button === Qt.RightButton) {
accountContextMenu.active = true
accountContextMenu.item.popup(mouse.x, mouse.y)
return
}
changeSelectedAccount(index) changeSelectedAccount(index)
showSavedAddresses = false showSavedAddresses = false
} }
@ -195,6 +241,27 @@ Rectangle {
height: 15 height: 15
} }
] ]
Loader {
id: accountContextMenu
sourceComponent: AccountContextMenu {
account: model
onEditAccountClicked: {
}
onDeleteAccountClicked: {
}
onAddNewAccountClicked: {
RootStore.runAddAccountPopup()
}
onAddWatchOnlyAccountClicked: {
RootStore.runAddWatchOnlyAccountPopup()
}
}
}
} }
readonly property bool footerOverlayed: contentHeight > availableHeight readonly property bool footerOverlayed: contentHeight > availableHeight
@ -254,6 +321,15 @@ Rectangle {
onClicked: { onClicked: {
showSavedAddresses = true showSavedAddresses = true
} }
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
propagateComposedEvents: true
onClicked: {
mouse.accepted = true
}
}
} }
} }