bash: py: command not found

feat(@desktop/wallet): Add emoji to Wallet accounts.
Support added to:
1. Wallet list
2. Adding a new account
3. Editing an account

fixes #4926
This commit is contained in:
Khushboo Mehta 2022-03-10 18:01:17 +01:00 committed by Iuri Matias
parent aef8d0c4ab
commit 6e0471c943
30 changed files with 767 additions and 674 deletions

View File

@ -26,17 +26,17 @@ method init*(self: Controller) =
method getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAccountDto] =
return self.walletAccountService.getWalletAccounts()
method generateNewAccount*(self: Controller, password: string, accountName: string, color: string): string =
return self.walletAccountService.generateNewAccount(password, accountName, color)
method generateNewAccount*(self: Controller, password: string, accountName: string, color: string, emoji: string): string =
return self.walletAccountService.generateNewAccount(password, accountName, color, emoji)
method addAccountsFromPrivateKey*(self: Controller, privateKey: string, password: string, accountName: string, color: string): string =
return self.walletAccountService.addAccountsFromPrivateKey(privateKey, password, accountName, color)
method addAccountsFromPrivateKey*(self: Controller, privateKey: string, password: string, accountName: string, color: string, emoji: string): string =
return self.walletAccountService.addAccountsFromPrivateKey(privateKey, password, accountName, color, emoji)
method addAccountsFromSeed*(self: Controller, seedPhrase: string, password: string, accountName: string, color: string): string =
return self.walletAccountService.addAccountsFromSeed(seedPhrase, password, accountName, color)
method addAccountsFromSeed*(self: Controller, seedPhrase: string, password: string, accountName: string, color: string, emoji: string): string =
return self.walletAccountService.addAccountsFromSeed(seedPhrase, password, accountName, color, emoji)
method addWatchOnlyAccount*(self: Controller, address: string, accountName: string, color: string): string =
return self.walletAccountService.addWatchOnlyAccount(address, accountName, color)
method addWatchOnlyAccount*(self: Controller, address: string, accountName: string, color: string, emoji: string): string =
return self.walletAccountService.addWatchOnlyAccount(address, accountName, color, emoji)
method deleteAccount*(self: Controller, address: string) =
self.walletAccountService.deleteAccount(address)

View File

@ -13,16 +13,16 @@ method init*(self: AccessInterface) {.base.} =
method getWalletAccounts*(self: AccessInterface): seq[wallet_account_service.WalletAccountDto] {.base.} =
raise newException(ValueError, "No implementation available")
method generateNewAccount*(self: AccessInterface, password: string, accountName: string, color: string): string {.base.} =
method generateNewAccount*(self: AccessInterface, password: string, accountName: string, color: string, emoji: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method addAccountsFromPrivateKey*(self: AccessInterface, privateKey: string, password: string, accountName: string, color: string): string {.base.} =
method addAccountsFromPrivateKey*(self: AccessInterface, privateKey: string, password: string, accountName: string, color: string, emoji: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method addAccountsFromSeed*(self: AccessInterface, seedPhrase: string, password: string, accountName: string, color: string): string {.base.} =
method addAccountsFromSeed*(self: AccessInterface, seedPhrase: string, password: string, accountName: string, color: string, emoji: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method addWatchOnlyAccount*(self: AccessInterface, address: string, accountName: string, color: string): string {.base.} =
method addWatchOnlyAccount*(self: AccessInterface, address: string, accountName: string, color: string, emoji: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method deleteAccount*(self: AccessInterface, address: string) {.base.} =

View File

@ -11,16 +11,16 @@ method load*(self: AccessInterface) {.base.} =
method isLoaded*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method generateNewAccount*(self: AccessInterface, password: string, accountName: string, color: string): string {.base.} =
method generateNewAccount*(self: AccessInterface, password: string, accountName: string, color: string, emoji: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method addAccountsFromPrivateKey*(self: AccessInterface, privateKey: string, password: string, accountName: string, color: string): string {.base.} =
method addAccountsFromPrivateKey*(self: AccessInterface, privateKey: string, password: string, accountName: string, color: string, emoji: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method addAccountsFromSeed*(self: AccessInterface, seedPhrase: string, password: string, accountName: string, color: string): string {.base.} =
method addAccountsFromSeed*(self: AccessInterface, seedPhrase: string, password: string, accountName: string, color: string, emoji: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method addWatchOnlyAccount*(self: AccessInterface, address: string, accountName: string, color: string): string {.base.} =
method addWatchOnlyAccount*(self: AccessInterface, address: string, accountName: string, color: string, emoji: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method deleteAccount*(self: AccessInterface, address: string) {.base.} =

View File

@ -13,6 +13,7 @@ type
isChat: bool
currencyBalance: float64
assets: account_tokens.Model
emoji: string
proc initItem*(
name: string,
@ -24,7 +25,8 @@ proc initItem*(
isWallet: bool,
isChat: bool,
currencyBalance: float64,
assets: account_tokens.Model
assets: account_tokens.Model,
emoji: string
): Item =
result.name = name
result.address = address
@ -36,6 +38,7 @@ proc initItem*(
result.isChat = isChat
result.currencyBalance = currencyBalance
result.assets = assets
result.emoji = emoji
proc `$`*(self: Item): string =
result = fmt"""WalletAccountItem(
@ -49,6 +52,7 @@ proc `$`*(self: Item): string =
isChat: {self.isChat},
currencyBalance: {self.currencyBalance},
assets.len: {self.assets.getCount()},
emoji: {self.emoji}
]"""
proc getName*(self: Item): string =
@ -60,6 +64,9 @@ proc getAddress*(self: Item): string =
proc getPath*(self: Item): string =
return self.path
proc getEmoji*(self: Item): string =
return self.emoji
proc getColor*(self: Item): string =
return self.color

View File

@ -13,7 +13,8 @@ type
IsWallet,
IsChat,
CurrencyBalance,
Assets
Assets,
Emoji
QtObject:
type
@ -58,7 +59,8 @@ QtObject:
ModelRole.IsWallet.int:"isWallet",
ModelRole.IsChat.int:"isChat",
ModelRole.Assets.int:"assets",
ModelRole.CurrencyBalance.int:"currencyBalance"
ModelRole.CurrencyBalance.int:"currencyBalance",
ModelRole.Emoji.int: "emoji"
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
@ -92,6 +94,8 @@ QtObject:
result = newQVariant(item.getCurrencyBalance())
of ModelRole.Assets:
result = newQVariant(item.getAssets())
of ModelRole.Emoji:
result = newQVariant(item.getEmoji())
proc setItems*(self: Model, items: seq[Item]) =
self.beginResetModel()

View File

@ -62,7 +62,8 @@ method refreshWalletAccounts*(self: Module) =
w.isWallet,
w.isChat,
w.getCurrencyBalance(),
assets
assets,
w.emoji
))
self.view.setItems(items)
@ -100,17 +101,17 @@ method viewDidLoad*(self: Module) =
self.moduleLoaded = true
self.delegate.accountsModuleDidLoad()
method generateNewAccount*(self: Module, password: string, accountName: string, color: string): string =
return self.controller.generateNewAccount(password, accountName, color)
method generateNewAccount*(self: Module, password: string, accountName: string, color: string, emoji: string): string =
return self.controller.generateNewAccount(password, accountName, color, emoji)
method addAccountsFromPrivateKey*(self: Module, privateKey: string, password: string, accountName: string, color: string): string =
return self.controller.addAccountsFromPrivateKey(privateKey, password, accountName, color)
method addAccountsFromPrivateKey*(self: Module, privateKey: string, password: string, accountName: string, color: string, emoji: string): string =
return self.controller.addAccountsFromPrivateKey(privateKey, password, accountName, color, emoji)
method addAccountsFromSeed*(self: Module, seedPhrase: string, password: string, accountName: string, color: string): string =
return self.controller.addAccountsFromSeed(seedPhrase, password, accountName, color)
method addAccountsFromSeed*(self: Module, seedPhrase: string, password: string, accountName: string, color: string, emoji: string): string =
return self.controller.addAccountsFromSeed(seedPhrase, password, accountName, color, emoji)
method addWatchOnlyAccount*(self: Module, address: string, accountName: string, color: string): string =
return self.controller.addWatchOnlyAccount(address, accountName, color)
method addWatchOnlyAccount*(self: Module, address: string, accountName: string, color: string, emoji: string): string =
return self.controller.addWatchOnlyAccount(address, accountName, color, emoji)
method deleteAccount*(self: Module, address: string) =
self.controller.deleteAccount(address)

View File

@ -103,17 +103,17 @@ QtObject:
self.imported.setItems(imported)
self.generated.setItems(generated)
proc generateNewAccount*(self: View, password: string, accountName: string, color: string): string {.slot.} =
return self.delegate.generateNewAccount(password, accountName, color)
proc generateNewAccount*(self: View, password: string, accountName: string, color: string, emoji: string): string {.slot.} =
return self.delegate.generateNewAccount(password, accountName, color, emoji)
proc addAccountsFromPrivateKey*(self: View, privateKey: string, password: string, accountName: string, color: string): string {.slot.} =
return self.delegate.addAccountsFromPrivateKey(privateKey, password, accountName, color)
proc addAccountsFromPrivateKey*(self: View, privateKey: string, password: string, accountName: string, color: string, emoji: string): string {.slot.} =
return self.delegate.addAccountsFromPrivateKey(privateKey, password, accountName, color, emoji)
proc addAccountsFromSeed*(self: View, seedPhrase: string, password: string, accountName: string, color: string): string {.slot.} =
return self.delegate.addAccountsFromSeed(seedPhrase, password, accountName, color)
proc addAccountsFromSeed*(self: View, seedPhrase: string, password: string, accountName: string, color: string, emoji: string): string {.slot.} =
return self.delegate.addAccountsFromSeed(seedPhrase, password, accountName, color, emoji)
proc addWatchOnlyAccount*(self: View, address: string, accountName: string, color: string): string {.slot.} =
return self.delegate.addWatchOnlyAccount(address, accountName, color)
proc addWatchOnlyAccount*(self: View, address: string, accountName: string, color: string, emoji: string): string {.slot.} =
return self.delegate.addWatchOnlyAccount(address, accountName, color, emoji)
proc deleteAccount*(self: View, address: string) {.slot.} =
self.delegate.deleteAccount(address)

View File

@ -26,5 +26,5 @@ method init*(self: Controller) =
method getWalletAccount*(self: Controller, accountIndex: int): wallet_account_service.WalletAccountDto =
return self.walletAccountService.getWalletAccount(accountIndex)
method update*(self: Controller, address: string, accountName: string, color: string) =
self.walletAccountService.updateWalletAccount(address, accountName, color)
method update*(self: Controller, address: string, accountName: string, color: string, emoji: string) =
self.walletAccountService.updateWalletAccount(address, accountName, color, emoji)

View File

@ -13,7 +13,7 @@ method init*(self: AccessInterface) {.base.} =
method getWalletAccount*(self: AccessInterface, accountIndex: int): wallet_account_service.WalletAccountDto {.base.} =
raise newException(ValueError, "No implementation available")
method update*(self: AccessInterface, address: string, accountName: string, color: string) {.base.} =
method update*(self: AccessInterface, address: string, accountName: string, color: string, emoji: string) {.base.} =
raise newException(ValueError, "No implementation available")
type

View File

@ -14,7 +14,7 @@ method isLoaded*(self: AccessInterface): bool {.base.} =
method switchAccount*(self: AccessInterface, accountIndex: int) {.base.} =
raise newException(ValueError, "No implementation available")
method update*(self: AccessInterface, address: string, accountName: string, color: string) {.base.} =
method update*(self: AccessInterface, address: string, accountName: string, color: string, emoji: string) {.base.} =
raise newException(ValueError, "No implementation available")
# View Delegate Interface

View File

@ -65,5 +65,5 @@ method switchAccount*(self: Module, accountIndex: int) =
let walletAccount = self.controller.getWalletAccount(accountIndex)
self.view.setData(walletAccount)
method update*(self: Module, address: string, accountName: string, color: string) =
self.controller.update(address, accountName, color)
method update*(self: Module, address: string, accountName: string, color: string, emoji: string) =
self.controller.update(address, accountName, color, emoji)

View File

@ -18,6 +18,7 @@ QtObject:
isChat: bool
currencyBalance: float64
assets: account_tokens.Model
emoji: string
proc setup(self: View) =
self.QObject.setup
@ -114,8 +115,17 @@ QtObject:
read = getAssets
notify = assetsChanged
proc update(self: View, address: string, accountName: string, color: string) {.slot.} =
self.delegate.update(address, accountName, color)
proc getEmoji(self: View): QVariant {.slot.} =
return newQVariant(self.emoji)
proc emojiChanged(self: View) {.signal.}
QtProperty[QVariant] emoji:
read = getEmoji
notify = emojiChanged
proc update(self: View, address: string, accountName: string, color: string, emoji: string) {.slot.} =
self.delegate.update(address, accountName, color, emoji)
proc setData*(self: View, dto: wallet_account_service.WalletAccountDto) =
self.name = dto.name
@ -134,6 +144,8 @@ proc setData*(self: View, dto: wallet_account_service.WalletAccountDto) =
self.isChatChanged()
self.currencyBalance = dto.getCurrencyBalance()
self.currencyBalanceChanged()
self.emoji = dto.emoji
self.emojiChanged()
let assets = account_tokens.newModel()

View File

@ -25,6 +25,7 @@ type
isWallet*: bool
isChat*: bool
tokens*: seq[WalletTokenDto]
emoji*: string
proc newDto*(
name: string,
@ -34,7 +35,8 @@ proc newDto*(
publicKey: string,
walletType: string,
isWallet: bool,
isChat: bool
isChat: bool,
emoji: string
): WalletAccountDto =
return WalletAccountDto(
name: name,
@ -44,7 +46,8 @@ proc newDto*(
publicKey: publicKey,
walletType: walletType,
isWallet: isWallet,
isChat: isChat
isChat: isChat,
emoji: emoji
)
proc toWalletAccountDto*(jsonObj: JsonNode): WalletAccountDto =
@ -57,6 +60,7 @@ proc toWalletAccountDto*(jsonObj: JsonNode): WalletAccountDto =
discard jsonObj.getProp("chat", result.isChat)
discard jsonObj.getProp("public-key", result.publicKey)
discard jsonObj.getProp("type", result.walletType)
discard jsonObj.getProp("emoji", result.emoji)
proc getCurrencyBalance*(self: WalletAccountDto): float64 =
return self.tokens.map(t => t.currencyBalance).foldl(a + b, 0.0)

View File

@ -244,49 +244,53 @@ method addNewAccountToLocalStore(self: Service) =
self.accounts[newAccount.address] = newAccount
self.events.emit(SIGNAL_WALLET_ACCOUNT_SAVED, AccountSaved(account: newAccount))
method generateNewAccount*(self: Service, password: string, accountName: string, color: string): string =
method generateNewAccount*(self: Service, password: string, accountName: string, color: string, emoji: string): string =
try:
discard status_go_wallet.generateAccount(
password,
accountName,
color)
color,
emoji)
except Exception as e:
return fmt"Error generating new account: {e.msg}"
self.addNewAccountToLocalStore()
method addAccountsFromPrivateKey*(self: Service, privateKey: string, password: string, accountName: string, color: string): string =
method addAccountsFromPrivateKey*(self: Service, privateKey: string, password: string, accountName: string, color: string, emoji: string): string =
try:
discard status_go_wallet.addAccountWithPrivateKey(
privateKey,
password,
accountName,
color,
emoji
)
except Exception as e:
return fmt"Error adding account with private key: {e.msg}"
self.addNewAccountToLocalStore()
method addAccountsFromSeed*(self: Service, mnemonic: string, password: string, accountName: string, color: string): string =
method addAccountsFromSeed*(self: Service, mnemonic: string, password: string, accountName: string, color: string, emoji: string): string =
try:
discard status_go_wallet.addAccountWithMnemonic(
mnemonic,
password,
accountName,
color,
emoji
)
except Exception as e:
return fmt"Error adding account with mnemonic: {e.msg}"
self.addNewAccountToLocalStore()
method addWatchOnlyAccount*(self: Service, address: string, accountName: string, color: string): string =
method addWatchOnlyAccount*(self: Service, address: string, accountName: string, color: string, emoji: string): string =
try:
discard status_go_wallet.addAccountWatch(
address,
accountName,
color,
emoji
)
except Exception as e:
return fmt"Error adding account with mnemonic: {e.msg}"
@ -316,16 +320,18 @@ method toggleNetworkEnabled*(self: Service, chainId: int) =
self.refreshBalances()
self.events.emit(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED, NetwordkEnabledToggled())
method updateWalletAccount*(self: Service, address: string, accountName: string, color: string) =
method updateWalletAccount*(self: Service, address: string, accountName: string, color: string, emoji: string) =
let account = self.accounts[address]
status_go_accounts.updateAccount(
accountName,
account.address,
account.publicKey,
account.walletType,
color
color,
emoji
)
account.name = accountName
account.color = color
account.emoji = emoji
self.events.emit(SIGNAL_WALLET_ACCOUNT_UPDATED, WalletAccountUpdated(account: account))

View File

@ -24,16 +24,16 @@ method getWalletAccount*(self: ServiceInterface, accountIndex: int): WalletAccou
method getCurrencyBalance*(self: ServiceInterface): float64 {.base.} =
raise newException(ValueError, "No implementation available")
method generateNewAccount*(self: ServiceInterface, password: string, accountName: string, color: string): string {.base.} =
method generateNewAccount*(self: ServiceInterface, password: string, accountName: string, color: string, emoji: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method addAccountsFromPrivateKey*(self: ServiceInterface, privateKey: string, password: string, accountName: string, color: string): string {.base.} =
method addAccountsFromPrivateKey*(self: ServiceInterface, privateKey: string, password: string, accountName: string, color: string, emoji: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method addAccountsFromSeed*(self: ServiceInterface, seedPhrase: string, password: string, accountName: string, color: string): string {.base.} =
method addAccountsFromSeed*(self: ServiceInterface, seedPhrase: string, password: string, accountName: string, color: string, emoji: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method addWatchOnlyAccount*(self: ServiceInterface, address: string, accountName: string, color: string): string {.base.} =
method addWatchOnlyAccount*(self: ServiceInterface, address: string, accountName: string, color: string, emoji: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method deleteAccount*(self: ServiceInterface, address: string) {.base.} =
@ -42,7 +42,7 @@ method deleteAccount*(self: ServiceInterface, address: string) {.base.} =
method updateCurrency*(self: ServiceInterface, newCurrency: string) {.base.} =
raise newException(ValueError, "No implementation available")
method updateWalletAccount*(self: ServiceInterface, address: string, accountName: string, color: string) {.base.} =
method updateWalletAccount*(self: ServiceInterface, address: string, accountName: string, color: string, emoji: string) {.base.} =
raise newException(ValueError, "No implementation available")
method toggleTokenVisible*(self: ServiceInterface, chainId: int, symbol: string) {.base.} =
@ -52,4 +52,4 @@ method getPrice*(self: ServiceInterface, crypto: string, fiat: string): float64
raise newException(ValueError, "No implementation available")
method getIndex*(self: ServiceInterface, address: string): int {.base.} =
raise newException(ValueError, "No implementation available")
raise newException(ValueError, "No implementation available")

View File

@ -23,9 +23,10 @@ proc getAccounts*(): RpcResponse[JsonNode] {.raises: [Exception].} =
proc deleteAccount*(address: string): RpcResponse[JsonNode] {.raises: [Exception].} =
return core.callPrivateRPC("accounts_deleteAccount", %* [address])
proc updateAccount*(name, address, publicKey, walletType, color: string) {.raises: [Exception].} =
proc updateAccount*(name, address, publicKey, walletType, color, emoji: string) {.raises: [Exception].} =
discard core.callPrivateRPC("accounts_saveAccounts", %* [
[{
"emoji": emoji,
"color": color,
"name": name,
"address": address,

View File

@ -11,18 +11,18 @@ proc getPendingTransactions*(): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* []
result = core.callPrivateRPC("wallet_getPendingTransactions", payload)
proc generateAccount*(password, name, color: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [hashPassword(password), name, color]
proc generateAccount*(password, name, color, emoji: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [hashPassword(password), name, color, emoji]
return core.callPrivateRPC("accounts_generateAccount", payload)
proc addAccountWithMnemonic*(mnemonic, password, name, color: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [mnemonic, hashPassword(password), name, color]
proc addAccountWithMnemonic*(mnemonic, password, name, color, emoji: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [mnemonic, hashPassword(password), name, color, emoji]
return core.callPrivateRPC("accounts_addAccountWithMnemonic", payload)
proc addAccountWithPrivateKey*(privateKey, password, name, color: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [privateKey, hashPassword(password), name, color]
proc addAccountWithPrivateKey*(privateKey, password, name, color, emoji: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [privateKey, hashPassword(password), name, color, emoji]
return core.callPrivateRPC("accounts_addAccountWithPrivateKey", payload)
proc addAccountWatch*(address, name, color: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [address, name, color]
proc addAccountWatch*(address, name, color, emoji: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [address, name, color, emoji]
return core.callPrivateRPC("accounts_addAccountWatch", payload)

@ -1 +1 @@
Subproject commit 381150a7b55d53b3cb59d9ee2c4f50985488c708
Subproject commit 428b165198e53caa5a55ef605f241cc4b6f7e02d

View File

@ -18,6 +18,7 @@ Item {
property bool hideSignPhraseModal: false
property var store
property var contactsStore
property var emojiPopup: null
function showSigningPhrasePopup(){
if(!hideSignPhraseModal && !RootStore.hideSignPhraseModal){
@ -52,6 +53,7 @@ Item {
RightTabView {
changeSelectedAccount: leftTab.changeSelectedAccount
store: walletView.store
emojiPopup: walletView.emojiPopup
}
}
@ -94,6 +96,7 @@ Item {
else
rightPanelStackView.replace(walletContainer)
}
emojiPopup: walletView.emojiPopup
}
rightPanel: StackView {

View File

@ -1,109 +0,0 @@
import QtQuick 2.13
import QtGraphicalEffects 1.13
import utils 1.0
import shared 1.0
import shared.panels 1.0
Rectangle {
id: walletDelegate
property string locale: ""
property string currency: ""
property int selectedAccountIndex
property bool selected: index === selectedAccountIndex
property bool hovered
signal clicked(int index)
height: 64
color: {
if (selected) {
return Style.current.menuBackgroundActive
}
if (hovered) {
return Style.current.backgroundHoverLight
}
return Style.current.transparent
}
radius: Style.current.radius
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
SVGImage {
id: walletIcon
width: 12
height: 12
anchors.top: parent.top
anchors.topMargin: Style.current.smallPadding
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
source: Style.svg("walletIcon")
}
ColorOverlay {
anchors.fill: walletIcon
source: walletIcon
color: {
Utils.getCurrentThemeAccountColor(model.color) || Style.current.accountColors[0]
}
}
StyledText {
id: walletName
text: name
elide: Text.ElideRight
anchors.right: walletBalance.left
anchors.rightMargin: Style.current.smallPadding
anchors.top: parent.top
anchors.topMargin: Style.current.smallPadding
anchors.left: walletIcon.right
anchors.leftMargin: Style.current.smallPadding
font.pixelSize: 15
font.weight: Font.Medium
color: Style.current.textColor
}
StyledText {
id: walletAddress
font.family: Style.current.fontHexRegular.name
text: address
anchors.right: parent.right
anchors.rightMargin: parent.width/2
elide: Text.ElideMiddle
anchors.bottom: parent.bottom
anchors.bottomMargin: Style.current.smallPadding
anchors.left: walletIcon.left
font.pixelSize: 15
font.weight: Font.Medium
color: Style.current.secondaryText
opacity: selected ? 0.7 : 1
}
StyledText {
id: walletBalance
text: {
Utils.toLocaleString(currencyBalance.toFixed(2), locale, {"currency": true}) + " " + walletDelegate.currency.toUpperCase()
}
anchors.top: parent.top
anchors.topMargin: Style.current.smallPadding
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
font.pixelSize: 15
font.weight: Font.Medium
color: Style.current.textColor
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onEntered: {
walletDelegate.hovered = true
}
onExited: {
walletDelegate.hovered = false
}
onClicked: {
walletDelegate.clicked(index)
}
}
}

View File

@ -21,6 +21,7 @@ Item {
property var changeSelectedAccount
property var store
property var walletStore
property var emojiPopup
height: walletAddress.y + walletAddress.height
anchors.right: parent.right
@ -109,8 +110,10 @@ Item {
Component {
id: accountSettingsModalComponent
AccountSettingsModal {
anchors.centerIn: parent
onClosed: destroy()
changeSelectedAccount: walletHeader.changeSelectedAccount
emojiPopup: walletHeader.emojiPopup
}
}

View File

@ -6,126 +6,151 @@ import QtQuick.Dialogs 1.3
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import StatusQ.Controls.Validators 0.1
import utils 1.0
import shared.panels 1.0
import shared.popups 1.0
import shared.panels 1.0
import shared.controls 1.0
import "../stores"
// TODO: replace with StatusModal
ModalPopup {
StatusModal {
id: popup
property var currentAccount: RootStore.currentAccount
property var changeSelectedAccount
property var emojiPopup
// TODO add icon when we have that feature
//% "Status account settings"
title: qsTrId("status-account-settings")
header.title: qsTrId("status-account-settings")
height: 675
property int marginBetweenInputs: 35
property string accountNameValidationError: ""
function validate() {
if (accountNameInput.text === "") {
//% "You need to enter an account name"
accountNameValidationError = qsTrId("you-need-to-enter-an-account-name")
} else {
accountNameValidationError = ""
}
return accountNameValidationError === ""
}
property int marginBetweenInputs: 30
onOpened: {
accountNameInput.forceActiveFocus(Qt.MouseFocusReason)
}
Input {
id: accountNameInput
//% "Enter an account name..."
placeholderText: qsTrId("enter-an-account-name...")
//% "Account name"
label: qsTrId("account-name")
text: currentAccount.name
validationError: popup.accountNameValidationError
}
StatusWalletColorSelect {
id: accountColorInput
selectedColor: currentAccount.iconColor.toUpperCase()
model: Theme.palette.accountColors
anchors.top: accountNameInput.bottom
anchors.topMargin: marginBetweenInputs
anchors.left: parent.left
anchors.right: parent.right
}
TextWithLabel {
id: typeText
//% "Type"
label: qsTrId("type")
text: {
var result = ""
switch (currentAccount.walletType) {
//% "Watch-only"
case Constants.watchWalletType: result = qsTrId("watch-only"); break;
case Constants.keyWalletType:
//% "Off Status tree"
case Constants.seedWalletType: result = qsTrId("off-status-tree"); break;
//% "On Status tree"
default: result = qsTrId("on-status-tree")
}
return result
Connections {
enabled: popup.opened
target: emojiPopup
onEmojiSelected: function (emojiText, atCursor) {
popup.contentItem.accountNameInput.input.icon.emoji = emojiText
}
anchors.top: accountColorInput.bottom
anchors.topMargin: marginBetweenInputs
}
TextWithLabel {
id: addressText
//% "Wallet address"
label: qsTrId("wallet-address")
text: currentAccount.address
fontFamily: Style.current.fontHexRegular.name
anchors.top: typeText.bottom
anchors.topMargin: marginBetweenInputs
contentItem: Column {
property alias accountNameInput: accountNameInput
width: popup.width
spacing: marginBetweenInputs
topPadding: Style.current.padding
StatusInput {
id: accountNameInput
//% "Enter an account name..."
input.placeholderText: qsTrId("enter-an-account-name...")
input.text: currentAccount.name
//% "Account name"
label: qsTrId("account-name")
input.isIconSelectable: true
input.icon.emoji: currentAccount.emoji
input.icon.color: currentAccount.color
input.icon.name: !currentAccount.emoji ? "filled-account": ""
onIconClicked: {
popup.emojiPopup.open()
popup.emojiPopup.x = Global.applicationWindow.width/2 - popup.emojiPopup.width/2 + popup.width/2
popup.emojiPopup.y = Global.applicationWindow.height/2 - popup.emojiPopup.height/2
}
validators: [
StatusMinLengthValidator {
//% "You need to enter an account name"
errorMessage: qsTrId("you-need-to-enter-an-account-name")
minLength: 1
}
]
}
StatusColorSelectorGrid {
id: accountColorInput
anchors.top: selectedColor.bottom
anchors.topMargin: 10
anchors.horizontalCenter: parent.horizontalCenter
//% "color"
titleText: qsTr("color").toUpperCase()
selectedColor: currentAccount.color
selectedColorIndex: {
for (let i = 0; i < model.length; i++) {
if(model[i] === currentAccount.color)
return i
}
}
onSelectedColorChanged: {
if(selectedColor !== currentAccount.color) {
accountNameInput.input.icon.color = selectedColor
}
}
}
Column {
width: parent.width
leftPadding: Style.current.padding
spacing: Style.current.padding
TextWithLabel {
id: typeText
//% "Type"
label: qsTrId("type")
text: {
var result = ""
switch (currentAccount.walletType) {
//% "Watch-only"
case Constants.watchWalletType: result = qsTrId("watch-only"); break;
case Constants.keyWalletType:
//% "Off Status tree"
case Constants.seedWalletType: result = qsTrId("off-status-tree"); break;
//% "On Status tree"
default: result = qsTrId("on-status-tree")
}
return result
}
}
TextWithLabel {
id: addressText
//% "Wallet address"
label: qsTrId("wallet-address")
text: currentAccount.address
fontFamily: Style.current.fontHexRegular.name
}
TextWithLabel {
id: pathText
visible: currentAccount.walletType !== Constants.watchWalletType && currentAccount.walletType !== Constants.keyWalletType
//% "Derivation path"
label: qsTrId("derivation-path")
text: currentAccount.path
}
TextWithLabel {
id: storageText
visible: currentAccount.walletType !== Constants.watchWalletType
//% "Storage"
label: qsTrId("storage")
//% "This device"
text: qsTrId("this-device")
}
}
}
TextWithLabel {
id: pathText
visible: currentAccount.walletType !== Constants.watchWalletType && currentAccount.walletType !== Constants.keyWalletType
//% "Derivation path"
label: qsTrId("derivation-path")
text: currentAccount.path
anchors.top: addressText.bottom
anchors.topMargin: marginBetweenInputs
}
TextWithLabel {
id: storageText
visible: currentAccount.walletType !== Constants.watchWalletType
//% "Storage"
label: qsTrId("storage")
//% "This device"
text: qsTrId("this-device")
anchors.top: pathText.bottom
anchors.topMargin: marginBetweenInputs
}
footer: Item {
width: parent.width
height: saveBtn.height
rightButtons: [
StatusButton {
visible: currentAccount.walletType === Constants.watchWalletType
anchors.top: parent.top
anchors.right: saveBtn.left
anchors.rightMargin: Style.current.padding
//% "Delete account"
text: qsTrId("delete-account")
type: StatusBaseButton.Type.Danger
@ -157,12 +182,9 @@ ModalPopup {
onClicked : {
confirmationDialog.open()
}
}
},
StatusButton {
id: saveBtn
anchors.top: parent.top
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
//% "Save changes"
text: qsTrId("save-changes")
@ -175,12 +197,12 @@ ModalPopup {
standardButtons: StandardButton.Ok
}
onClicked : {
if (!validate()) {
return
}
onClicked : {
if (!accountNameInput.valid) {
return
}
const error = RootStore.updateCurrentAccount(currentAccount.address, accountNameInput.text, accountColorInput.selectedColor);
const error = RootStore.updateCurrentAccount(currentAccount.address, accountNameInput.text, accountColorInput.selectedColor, accountNameInput.input.icon.emoji);
if (error) {
Global.playErrorSound();
@ -191,5 +213,5 @@ ModalPopup {
popup.close();
}
}
}
]
}

View File

@ -7,25 +7,23 @@ import utils 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import StatusQ.Controls.Validators 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils
import shared.panels 1.0
import shared.popups 1.0
import shared.controls 1.0
import "../stores"
// TODO: replace with StatusModal
ModalPopup {
StatusModal {
id: popup
//% "Add account from private key"
title: qsTrId("add-private-key-account")
height: 600
property int marginBetweenInputs: 38
property string passwordValidationError: ""
property string privateKeyValidationError: ""
property string accountNameValidationError: ""
property bool loading: false
property var emojiPopup: null
signal afterAddAccount()
@ -40,13 +38,6 @@ ModalPopup {
passwordValidationError = ""
}
if (accountNameInput.text === "") {
//% "You need to enter an account name"
accountNameValidationError = qsTrId("you-need-to-enter-an-account-name")
} else {
accountNameValidationError = ""
}
if (accountPKeyInput.text === "") {
//% "You need to enter a private key"
privateKeyValidationError = qsTrId("you-need-to-enter-a-private-key")
@ -57,119 +48,159 @@ ModalPopup {
privateKeyValidationError = ""
}
return passwordValidationError === "" && privateKeyValidationError === "" && accountNameValidationError === ""
return passwordValidationError === "" && privateKeyValidationError === "" && accountNameInput.valid
}
//% "Add account from private key"
header.title: qsTrId("add-private-key-account")
onOpened: {
passwordInput.text = ""
accountPKeyInput.text = ""
accountNameInput.reset()
accountNameInput.text = ""
accountNameInput.input.icon.emoji = StatusQUtils.Emoji.getRandomEmoji()
passwordValidationError = ""
privateKeyValidationError = ""
accountNameValidationError = ""
accountColorInput.selectedColor = Style.current.accountColors[Math.floor(Math.random() * Style.current.accountColors.length)]
accountColorInput.selectedColorIndex = Math.floor(Math.random() * accountColorInput.model.length)
passwordInput.forceActiveFocus(Qt.MouseFocusReason)
}
Input {
id: passwordInput
//% "Enter your password"
placeholderText: qsTrId("enter-your-password…")
//% "Password"
label: qsTrId("password")
textField.echoMode: TextInput.Password
validationError: popup.passwordValidationError
Connections {
enabled: popup.opened
target: emojiPopup
onEmojiSelected: function (emojiText, atCursor) {
popup.contentItem.accountNameInput.input.icon.emoji = emojiText
}
}
StyledTextArea {
id: accountPKeyInput
customHeight: 88
anchors.top: passwordInput.bottom
anchors.topMargin: marginBetweenInputs
anchors.left: parent.left
anchors.right: parent.right
validationError: popup.privateKeyValidationError
//% "Private key"
label: qsTrId("private-key")
textField.wrapMode: Text.WordWrap
textField.horizontalAlignment: TextEdit.AlignHCenter
textField.verticalAlignment: TextEdit.AlignVCenter
textField.font.weight: Font.DemiBold
//% "Paste the contents of your private key"
placeholderText: qsTrId("paste-the-contents-of-your-private-key")
textField.placeholderTextColor: Style.current.secondaryText
textField.selectByKeyboard: true
textField.selectionColor: Style.current.secondaryBackground
textField.selectedTextColor: Style.current.secondaryText
}
contentItem: Column {
property alias accountNameInput: accountNameInput
Input {
id: accountNameInput
anchors.top: accountPKeyInput.bottom
anchors.topMargin: marginBetweenInputs
//% "Enter an account name..."
placeholderText: qsTrId("enter-an-account-name...")
//% "Account name"
label: qsTrId("account-name")
validationError: popup.accountNameValidationError
}
width: popup.width
spacing: 8
topPadding: 20
StatusWalletColorSelect {
id: accountColorInput
anchors.top: accountNameInput.bottom
anchors.topMargin: marginBetweenInputs
anchors.left: parent.left
anchors.right: parent.right
model: Theme.palette.accountColors
}
Column {
width: parent.width
spacing: Style.current.xlPadding
// To-Do Password hidden option not supported in StatusQ StatusBaseInput
Input {
id: passwordInput
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
width: parent.width
footer: StatusButton {
anchors.top: parent.top
anchors.right: parent.right
text: loading ?
//% "Loading..."
qsTrId("loading") :
//% "Add account"
qsTrId("add-account")
//% "Enter your password"
placeholderText: qsTrId("enter-your-password…")
//% "Password"
label: qsTrId("password")
textField.echoMode: TextInput.Password
validationError: popup.passwordValidationError
inputLabel.font.pixelSize: 15
inputLabel.font.weight: Font.Normal
}
// To-Do use StatusInput
StyledTextArea {
id: accountPKeyInput
customHeight: 88
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
enabled: !loading && passwordInput.text !== "" && accountNameInput.text !== "" && accountPKeyInput.text !== ""
MessageDialog {
id: accountError
title: "Adding the account failed"
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
validationError: popup.privateKeyValidationError
//% "Private key"
label: qsTrId("private-key")
textField.wrapMode: Text.WordWrap
textField.horizontalAlignment: TextEdit.AlignHCenter
textField.verticalAlignment: TextEdit.AlignVCenter
textField.font.weight: Font.DemiBold
//% "Paste the contents of your private key"
placeholderText: qsTrId("paste-the-contents-of-your-private-key")
textField.placeholderTextColor: Style.current.secondaryText
textField.selectByKeyboard: true
textField.selectionColor: Style.current.secondaryBackground
textField.selectedTextColor: Style.current.secondaryText
}
}
onClicked : {
// TODO the loaidng doesn't work because the function freezes th eview. Might need to use threads
loading = true
if (!validate()) {
return loading = false
StatusInput {
id: accountNameInput
//% "Enter an account name..."
input.placeholderText: qsTrId("enter-an-account-name...")
//% "Account name"
label: qsTrId("account-name")
input.isIconSelectable: true
input.icon.color: accountColorInput.selectedColor ? accountColorInput.selectedColor : Theme.palette.directColor1
onIconClicked: {
popup.emojiPopup.open()
popup.emojiPopup.x = Global.applicationWindow.width/2 - popup.emojiPopup.width/2 + popup.width/2
popup.emojiPopup.y = Global.applicationWindow.height/2 - popup.emojiPopup.height/2
}
const errMessage = RootStore.addAccountsFromPrivateKey(accountPKeyInput.text, passwordInput.text, accountNameInput.text, accountColorInput.selectedColor)
loading = false
if (errMessage) {
Global.playErrorSound();
if (Utils.isInvalidPasswordMessage(errMessage)) {
//% "Wrong password"
popup.passwordValidationError = qsTrId("wrong-password")
} else {
accountError.text = errMessage
accountError.open()
validators: [
StatusMinLengthValidator {
//% "You need to enter an account name"
errorMessage: qsTrId("you-need-to-enter-an-account-name")
minLength: 1
}
return
}
popup.afterAddAccount()
popup.close();
]
}
StatusColorSelectorGrid {
id: accountColorInput
anchors.horizontalCenter: parent.horizontalCenter
//% "color"
titleText: qsTr("color").toUpperCase()
}
Item {
width: parent.width
height: 8
}
}
}
/*##^##
Designer {
D{i:0;formeditorColor:"#ffffff";height:500;width:400}
rightButtons: [
StatusButton {
text: loading ?
//% "Loading..."
qsTrId("loading") :
//% "Add account"
qsTrId("add-account")
enabled: !loading && passwordInput.text !== "" && accountNameInput.text !== "" && accountPKeyInput.text !== ""
MessageDialog {
id: accountError
title: "Adding the account failed"
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
}
onClicked : {
// TODO the loaidng doesn't work because the function freezes th eview. Might need to use threads
loading = true
if (!validate()) {
return loading = false
}
const errMessage = RootStore.addAccountsFromPrivateKey(accountPKeyInput.text, passwordInput.text, accountNameInput.text, accountColorInput.selectedColor, accountNameInput.input.icon.emoji)
loading = false
if (errMessage) {
Global.playErrorSound();
if (Utils.isInvalidPasswordMessage(errMessage)) {
//% "Wrong password"
popup.passwordValidationError = qsTrId("wrong-password")
} else {
accountError.text = errMessage
accountError.open()
}
return
}
popup.afterAddAccount()
popup.close();
}
}
]
}
##^##*/

View File

@ -7,22 +7,21 @@ import utils 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import StatusQ.Controls.Validators 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils
import shared.popups 1.0
import shared.controls 1.0
import "../stores"
// TODO: replace with StatusModal
ModalPopup {
StatusModal {
id: popup
height: 615
property int marginBetweenInputs: 38
property string passwordValidationError: ""
property string seedValidationError: ""
property string accountNameValidationError: ""
property bool loading: false
property var emojiPopup: null
signal afterAddAccount()
@ -43,13 +42,6 @@ ModalPopup {
passwordValidationError = ""
}
if (accountNameInput.text === "") {
//% "You need to enter an account name"
accountNameValidationError = qsTrId("you-need-to-enter-an-account-name")
} else {
accountNameValidationError = ""
}
if (seedPhraseTextArea.textArea.text === "") {
//% "You need to enter a seed phrase"
seedValidationError = qsTrId("you-need-to-enter-a-seed-phrase")
@ -60,102 +52,144 @@ ModalPopup {
seedValidationError = ""
}
return passwordValidationError === "" && seedValidationError === "" && accountNameValidationError === ""
}
onOpened: {
seedPhraseTextArea.textArea.text = "";
passwordInput.text = "";
accountNameInput.text = "";
passwordValidationError = "";
seedValidationError = "";
accountNameValidationError = "";
accountColorInput.selectedColor = Theme.palette.accountColors[Math.floor(Math.random() * Theme.palette.accountColors.length)]
passwordInput.forceActiveFocus(Qt.MouseFocusReason)
return passwordValidationError === "" && seedValidationError === "" && accountNameInput.valid
}
//% "Add account with a seed phrase"
title: qsTrId("add-seed-account")
header.title: qsTrId("add-seed-account")
Input {
id: passwordInput
//% "Enter your password"
placeholderText: qsTrId("enter-your-password…")
//% "Password"
label: qsTrId("password")
textField.echoMode: TextInput.Password
validationError: popup.passwordValidationError
onOpened: {
seedPhraseTextArea.textArea.text = ""
passwordInput.text = ""
accountNameInput.text = ""
accountNameInput.reset()
accountNameInput.input.icon.emoji = StatusQUtils.Emoji.getRandomEmoji()
passwordValidationError = ""
seedValidationError = ""
accountColorInput.selectedColorIndex = Math.floor(Math.random() * accountColorInput.model.length)
passwordInput.forceActiveFocus(Qt.MouseFocusReason)
}
SeedPhraseTextArea {
id: seedPhraseTextArea
anchors.top: passwordInput.bottom
anchors.topMargin: marginBetweenInputs
width: parent.width
Connections {
enabled: popup.opened
target: emojiPopup
onEmojiSelected: function (emojiText, atCursor) {
popup.contentItem.accountNameInput.input.icon.emoji = emojiText
}
}
Input {
id: accountNameInput
anchors.top: seedPhraseTextArea.bottom
anchors.topMargin: marginBetweenInputs
//% "Enter an account name..."
placeholderText: qsTrId("enter-an-account-name...")
//% "Account name"
label: qsTrId("account-name")
validationError: popup.accountNameValidationError
}
contentItem: Column {
property alias accountNameInput: accountNameInput
StatusWalletColorSelect {
id: accountColorInput
anchors.top: accountNameInput.bottom
anchors.topMargin: marginBetweenInputs
anchors.left: parent.left
anchors.right: parent.right
model: Theme.palette.accountColors
}
width: popup.width
spacing: 8
topPadding: 20
footer: StatusButton {
anchors.top: parent.top
anchors.right: parent.right
text: loading ?
//% "Loading..."
qsTrId("loading") :
//% "Add account"
qsTrId("add-account")
Column {
width: parent.width
spacing: Style.current.xlPadding
// To-Do Password hidden option not supported in StatusQ StatusBaseInput
Input {
id: passwordInput
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
width: parent.width
enabled: !loading && passwordInput.text !== "" && accountNameInput.text !== "" && seedPhraseTextArea.correctWordCount
MessageDialog {
id: accountError
title: "Adding the account failed"
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
//% "Enter your password"
placeholderText: qsTrId("enter-your-password…")
//% "Password"
label: qsTrId("password")
textField.echoMode: TextInput.Password
validationError: popup.passwordValidationError
inputLabel.font.pixelSize: 15
inputLabel.font.weight: Font.Normal
}
// To-Do use StatusInput
SeedPhraseTextArea {
id: seedPhraseTextArea
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
width: parent.width - 2*Style.current.padding
}
}
onClicked : {
// TODO the loading doesn't work because the function freezes the view. Might need to use threads
loading = true
if (!validate() || !seedPhraseTextArea.validateSeed()) {
Global.playErrorSound();
return loading = false
StatusInput {
id: accountNameInput
//% "Enter an account name..."
input.placeholderText: qsTrId("enter-an-account-name...")
//% "Account name"
label: qsTrId("account-name")
input.isIconSelectable: true
input.icon.color: accountColorInput.selectedColor ? accountColorInput.selectedColor : Theme.palette.directColor1
onIconClicked: {
popup.emojiPopup.open()
popup.emojiPopup.x = Global.applicationWindow.width/2 - popup.emojiPopup.width/2 + popup.width/2
popup.emojiPopup.y = Global.applicationWindow.height/2 - popup.emojiPopup.height/2
}
const errMessage = RootStore.addAccountsFromSeed(seedPhraseTextArea.textArea.text, passwordInput.text, accountNameInput.text, accountColorInput.selectedColor)
loading = false
if (errMessage) {
Global.playErrorSound();
if (Utils.isInvalidPasswordMessage(errMessage)) {
//% "Wrong password"
popup.passwordValidationError = qsTrId("wrong-password")
} else {
accountError.text = errMessage
accountError.open()
validators: [
StatusMinLengthValidator {
//% "You need to enter an account name"
errorMessage: qsTrId("you-need-to-enter-an-account-name")
minLength: 1
}
return
}
popup.afterAddAccount()
popup.reset()
popup.close();
]
}
StatusColorSelectorGrid {
id: accountColorInput
anchors.horizontalCenter: parent.horizontalCenter
//% "color"
titleText: qsTr("color").toUpperCase()
}
Item {
width: parent.width
height: 8
}
}
rightButtons: [
StatusButton {
text: loading ?
//% "Loading..."
qsTrId("loading") :
//% "Add account"
qsTrId("add-account")
enabled: !loading && passwordInput.text !== "" && accountNameInput.text !== "" && seedPhraseTextArea.correctWordCount
MessageDialog {
id: accountError
title: "Adding the account failed"
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
}
onClicked : {
// TODO the loading doesn't work because the function freezes the view. Might need to use threads
loading = true
if (!validate() || !seedPhraseTextArea.validateSeed()) {
Global.playErrorSound();
return loading = false
}
const errMessage = RootStore.addAccountsFromSeed(seedPhraseTextArea.textArea.text, passwordInput.text, accountNameInput.text, accountColorInput.selectedColor, accountNameInput.input.icon.emoji)
loading = false
if (errMessage) {
Global.playErrorSound();
if (Utils.isInvalidPasswordMessage(errMessage)) {
//% "Wrong password"
popup.passwordValidationError = qsTrId("wrong-password")
} else {
accountError.text = errMessage
accountError.open()
}
return
}
popup.afterAddAccount()
popup.reset()
popup.close();
}
}
]
}

View File

@ -6,121 +6,140 @@ import utils 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Popups 0.1
import StatusQ.Controls 0.1
import StatusQ.Controls.Validators 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils
import shared.popups 1.0
import shared.controls 1.0
import "../stores"
// TODO: replace with StatusModal
ModalPopup {
StatusModal {
id: popup
//% "Add a watch-only account"
title: qsTrId("add-watch-account")
property int marginBetweenInputs: 38
property string addressError: ""
property string accountNameValidationError: ""
property bool loading: false
property var emojiPopup: null
signal afterAddAccount()
function validate() {
if (addressInput.text === "") {
//% "You need to enter an address"
addressError = qsTrId("you-need-to-enter-an-address")
} else if (!Utils.isAddress(addressInput.text)) {
//% "This needs to be a valid address (starting with 0x)"
addressError = qsTrId("this-needs-to-be-a-valid-address-(starting-with-0x)")
} else {
addressError = ""
}
if (accountNameInput.text === "") {
//% "You need to enter an account name"
accountNameValidationError = qsTrId("you-need-to-enter-an-account-name")
} else {
accountNameValidationError = ""
}
return addressError === "" && accountNameValidationError === ""
}
//% "Add a watch-only account"
header.title: qsTrId("add-watch-account")
onOpened: {
addressError = "";
accountNameValidationError = "";
addressInput.text = "";
accountNameInput.text = "";
accountColorInput.selectedColor = Style.current.accountColors[Math.floor(Math.random() * Style.current.accountColors.length)]
addressInput.text = ""
addressInput.reset()
accountNameInput.text = ""
accountNameInput.reset()
accountNameInput.input.icon.emoji = StatusQUtils.Emoji.getRandomEmoji()
accountColorInput.selectedColorIndex = Math.floor(Math.random() * accountColorInput.model.length)
addressInput.forceActiveFocus(Qt.MouseFocusReason)
}
Input {
id: addressInput
// TODO add QR code reader for the address
//% "Enter address..."
placeholderText: qsTrId("enter-address...")
//% "Account address"
label: qsTrId("wallet-key-title")
validationError: popup.addressError
}
Input {
id: accountNameInput
anchors.top: addressInput.bottom
anchors.topMargin: marginBetweenInputs
//% "Enter an account name..."
placeholderText: qsTrId("enter-an-account-name...")
//% "Account name"
label: qsTrId("account-name")
validationError: popup.accountNameValidationError
}
StatusWalletColorSelect {
id: accountColorInput
anchors.top: accountNameInput.bottom
anchors.topMargin: marginBetweenInputs
anchors.left: parent.left
anchors.right: parent.right
model: Theme.palette.accountColors
}
footer: StatusButton {
anchors.top: parent.top
anchors.right: parent.right
text: loading ?
//% "Loading..."
qsTrId("loading") :
//% "Add account"
qsTrId("add-account")
enabled: !loading && addressInput.text !== "" && accountNameInput.text !== ""
MessageDialog {
id: accountError
title: "Adding the account failed"
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
}
onClicked : {
// TODO the loaidng doesn't work because the function freezes th eview. Might need to use threads
loading = true
if (!validate()) {
Global.playErrorSound();
return loading = false
}
const error = RootStore.addWatchOnlyAccount(addressInput.text, accountNameInput.text, accountColorInput.selectedColor);
loading = false
if (error) {
Global.playErrorSound();
accountError.text = error
return accountError.open()
}
popup.afterAddAccount()
popup.close();
Connections {
enabled: popup.opened
target: emojiPopup
onEmojiSelected: function (emojiText, atCursor) {
popup.contentItem.accountNameInput.input.icon.emoji = emojiText
}
}
contentItem: Column {
property alias accountNameInput: accountNameInput
width: popup.width
spacing: 8
topPadding: 20
StatusInput {
id: addressInput
// TODO add QR code reader for the address
//% "Enter address..."
input.placeholderText: qsTrId("enter-address...")
//% "Account address"
label: qsTrId("wallet-key-title")
validators: [
StatusAddressValidator {
//% "This needs to be a valid address (starting with 0x)"
errorMessage: qsTrId("this-needs-to-be-a-valid-address-(starting-with-0x)")
},
StatusMinLengthValidator {
//% "You need to enter an address"
errorMessage: qsTrId("you-need-to-enter-an-address")
minLength: 1
}
]
}
StatusInput {
id: accountNameInput
//% "Enter an account name..."
input.placeholderText: qsTrId("enter-an-account-name...")
//% "Account name"
label: qsTrId("account-name")
input.isIconSelectable: true
input.icon.color: accountColorInput.selectedColor ? accountColorInput.selectedColor : Theme.palette.directColor1
onIconClicked: {
popup.emojiPopup.open()
popup.emojiPopup.x = Global.applicationWindow.width/2 - popup.emojiPopup.width/2 + popup.width/2
popup.emojiPopup.y = Global.applicationWindow.height/2 - popup.emojiPopup.height/2
}
validators: [
StatusMinLengthValidator {
//% "You need to enter an account name"
errorMessage: qsTrId("you-need-to-enter-an-account-name")
minLength: 1
}
]
}
StatusColorSelectorGrid {
id: accountColorInput
anchors.horizontalCenter: parent.horizontalCenter
//% "color"
titleText: qsTr("color").toUpperCase()
}
Item {
width: parent.width
height: 8
}
}
rightButtons: [
StatusButton {
text: loading ?
//% "Loading..."
qsTrId("loading") :
//% "Add account"
qsTrId("add-account")
enabled: !loading && addressInput.text !== "" && accountNameInput.text !== ""
MessageDialog {
id: accountError
title: "Adding the account failed"
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
}
onClicked : {
// TODO the loaidng doesn't work because the function freezes th eview. Might need to use threads
loading = true
if (!addressInput.valid || !accountNameInput.valid) {
Global.playErrorSound();
return loading = false
}
const error = RootStore.addWatchOnlyAccount(addressInput.text, accountNameInput.text, accountColorInput.selectedColor, accountNameInput.input.icon.emoji);
loading = false
if (error) {
Global.playErrorSound();
accountError.text = error
return accountError.open()
}
popup.afterAddAccount()
popup.close();
}
}
]
}

View File

@ -6,26 +6,28 @@ import utils 1.0
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
import shared.popups 1.0
import shared.controls 1.0
import "../stores"
// TODO: replace with StatusModal
ModalPopup {
StatusModal {
id: popup
//% "Generate an account"
title: qsTrId("generate-a-new-account")
property int marginBetweenInputs: 38
property string passwordValidationError: ""
property string accountNameValidationError: ""
property bool loading: false
property var emojiPopup: null
signal afterAddAccount()
//% "Generate an account"
header.title: qsTrId("generate-a-new-account")
function validate() {
if (passwordInput.text === "") {
//% "You need to enter a password"
@ -36,98 +38,131 @@ ModalPopup {
} else {
passwordValidationError = ""
}
if (accountNameInput.text === "") {
//% "You need to enter an account name"
accountNameValidationError = qsTrId("you-need-to-enter-an-account-name")
} else {
accountNameValidationError = ""
return passwordValidationError === "" && accountNameInput.valid
}
return passwordValidationError === "" && accountNameValidationError === ""
}
onOpened: {
passwordValidationError = "";
accountNameValidationError = "";
passwordInput.text = "";
accountNameInput.reset()
accountNameInput.text = "";
accountColorInput.selectedColor = Style.current.accountColors[Math.floor(Math.random() * Style.current.accountColors.length)]
accountNameInput.input.icon.emoji = StatusQUtils.Emoji.getRandomEmoji()
colorSelectionGrid.selectedColorIndex = Math.floor(Math.random() * colorSelectionGrid.model.length)
passwordInput.forceActiveFocus(Qt.MouseFocusReason)
}
Input {
id: passwordInput
//% "Enter your password"
placeholderText: qsTrId("enter-your-password…")
//% "Password"
label: qsTrId("password")
textField.echoMode: TextInput.Password
validationError: popup.passwordValidationError
Connections {
enabled: popup.opened
target: emojiPopup
onEmojiSelected: function (emojiText, atCursor) {
popup.contentItem.accountNameInput.input.icon.emoji = emojiText
}
}
Input {
id: accountNameInput
anchors.top: passwordInput.bottom
anchors.topMargin: marginBetweenInputs
//% "Enter an account name..."
placeholderText: qsTrId("enter-an-account-name...")
//% "Account name"
label: qsTrId("account-name")
validationError: popup.accountNameValidationError
}
contentItem: Column {
property alias accountNameInput: accountNameInput
width: popup.width
spacing: 8
topPadding: 20
StatusWalletColorSelect {
id: accountColorInput
selectedColor: Theme.palette.accountColors[0]
anchors.top: accountNameInput.bottom
anchors.topMargin: marginBetweenInputs
width: parent.width
model: Theme.palette.accountColors
}
// To-Do Password hidden option not supported in StatusQ StatusBaseInput
Item {
width: parent.width
height: passwordInput.height
Input {
id: passwordInput
anchors.fill: parent
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
footer: StatusButton {
anchors.top: parent.top
anchors.right: parent.right
text: loading ?
//% "Loading..."
qsTrId("loading") :
//% "Add account"
qsTrId("add-account")
enabled: !loading && passwordInput.text !== "" && accountNameInput.text !== ""
MessageDialog {
id: accountError
title: "Adding the account failed"
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
//% "Enter your password"
placeholderText: qsTrId("enter-your-password…")
//% "Password"
label: qsTrId("password")
textField.echoMode: TextInput.Password
validationError: popup.passwordValidationError
inputLabel.font.pixelSize: 15
inputLabel.font.weight: Font.Normal
}
}
onClicked : {
// TODO the loaidng doesn't work because the function freezes th eview. Might need to use threads
loading = true
if (!validate()) {
Global.playErrorSound();
return loading = false
StatusInput {
id: accountNameInput
//% "Enter an account name..."
input.placeholderText: qsTrId("enter-an-account-name...")
//% "Account name"
label: qsTrId("account-name")
input.isIconSelectable: true
input.icon.color: colorSelectionGrid.selectedColor ? colorSelectionGrid.selectedColor : Theme.palette.directColor1
onIconClicked: {
popup.emojiPopup.open()
popup.emojiPopup.x = Global.applicationWindow.width/2 - popup.emojiPopup.width/2 + popup.width/2
popup.emojiPopup.y = Global.applicationWindow.height/2 - popup.emojiPopup.height/2
}
const errMessage = RootStore.generateNewAccount(passwordInput.text, accountNameInput.text, accountColorInput.selectedColor)
console.log(errMessage)
loading = false
if (errMessage) {
Global.playErrorSound();
if (Utils.isInvalidPasswordMessage(errMessage)) {
//% "Wrong password"
popup.passwordValidationError = qsTrId("wrong-password")
} else {
accountError.text = errMessage;
accountError.open();
validators: [
StatusMinLengthValidator {
//% "You need to enter an account name"
errorMessage: qsTrId("you-need-to-enter-an-account-name")
minLength: 1
}
return
}
popup.afterAddAccount();
popup.close();
]
}
StatusColorSelectorGrid {
id: colorSelectionGrid
anchors.horizontalCenter: parent.horizontalCenter
//% "color"
titleText: qsTr("color").toUpperCase()
}
Item {
width: parent.width
height: 8
}
}
rightButtons: [
StatusButton {
text: loading ?
//% "Loading..."
qsTrId("loading") :
//% "Add account"
qsTrId("add-account")
enabled: !loading && passwordInput.text !== "" && accountNameInput.text !== ""
MessageDialog {
id: accountError
title: "Adding the account failed"
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
}
onClicked : {
// TODO the loaidng doesn't work because the function freezes th eview. Might need to use threads
loading = true
if (!validate()) {
Global.playErrorSound();
return loading = false
}
const errMessage = RootStore.generateNewAccount(passwordInput.text, accountNameInput.text, colorSelectionGrid.selectedColor, accountNameInput.input.icon.emoji)
console.log(errMessage)
loading = false
if (errMessage) {
Global.playErrorSound();
if (Utils.isInvalidPasswordMessage(errMessage)) {
//% "Wrong password"
popup.passwordValidationError = qsTrId("wrong-password")
} else {
accountError.text = errMessage;
accountError.open();
}
return
}
popup.afterAddAccount();
popup.close();
}
}
]
}

View File

@ -105,28 +105,28 @@ QtObject {
walletSection.switchAccount(newIndex)
}
function generateNewAccount(password, accountName, color) {
return walletSectionAccounts.generateNewAccount(password, accountName, color)
function generateNewAccount(password, accountName, color, emoji) {
return walletSectionAccounts.generateNewAccount(password, accountName, color, emoji)
}
function addAccountsFromPrivateKey(privateKey, password, accountName, color) {
return walletSectionAccounts.addAccountsFromPrivateKey(privateKey, password, accountName, color)
function addAccountsFromPrivateKey(privateKey, password, accountName, color, emoji) {
return walletSectionAccounts.addAccountsFromPrivateKey(privateKey, password, accountName, color, emoji)
}
function addAccountsFromSeed(seedPhrase, password, accountName, color) {
return walletSectionAccounts.addAccountsFromSeed(seedPhrase, password, accountName, color)
function addAccountsFromSeed(seedPhrase, password, accountName, color, emoji) {
return walletSectionAccounts.addAccountsFromSeed(seedPhrase, password, accountName, color, emoji)
}
function addWatchOnlyAccount(address, accountName, color) {
return walletSectionAccounts.addWatchOnlyAccount(address, accountName, color)
function addWatchOnlyAccount(address, accountName,color, emoji) {
return walletSectionAccounts.addWatchOnlyAccount(address, accountName, color, emoji)
}
function deleteAccount(address) {
return walletSectionAccounts.deleteAccount(address)
}
function updateCurrentAccount(address, accountName, color) {
return walletSectionCurrent.update(address, accountName, color)
function updateCurrentAccount(address, accountName, color, emoji) {
return walletSectionCurrent.update(address, accountName, color, emoji)
}
function updateCurrency(newCurrency) {

View File

@ -9,6 +9,7 @@ import shared.panels 1.0
import shared.controls 1.0
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import "../controls"
import "../popups"
@ -20,6 +21,7 @@ Rectangle {
property int selectedAccountIndex: 0
property var changeSelectedAccount: function(){}
property var showSavedAddresses: function(showSavedAddresses){}
property var emojiPopup: null
function onAfterAddAccount () {
walletInfoContainer.changeSelectedAccount(RootStore.accounts.rowCount() - 1)
@ -111,22 +113,30 @@ Rectangle {
GenerateAccountModal {
id: generateAccountModal
anchors.centerIn: parent
onAfterAddAccount: walletInfoContainer.onAfterAddAccount()
emojiPopup: walletInfoContainer.emojiPopup
}
AddAccountWithSeedModal {
id: addAccountWithSeedModal
anchors.centerIn: parent
onAfterAddAccount: walletInfoContainer.onAfterAddAccount()
emojiPopup: walletInfoContainer.emojiPopup
}
AddAccountWithPrivateKeyModal {
id: addAccountWithPrivateKeydModal
anchors.centerIn: parent
onAfterAddAccount: walletInfoContainer.onAfterAddAccount()
emojiPopup: walletInfoContainer.emojiPopup
}
AddWatchOnlyAccountModal {
id: addWatchOnlyAccountModal
anchors.centerIn: parent
onAfterAddAccount: walletInfoContainer.onAfterAddAccount()
emojiPopup: walletInfoContainer.emojiPopup
}
ScrollView {
@ -134,8 +144,8 @@ Rectangle {
anchors.bottomMargin: btnSavedAddresses.height + Style.current.padding
anchors.top: walletValueTextContainer.bottom
anchors.topMargin: Style.current.padding
anchors.right: parent.right
anchors.left: parent.left
anchors.horizontalCenter: parent.horizontalCenter
width: 272
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: listView.contentHeight > listView.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
clip: true
@ -150,10 +160,17 @@ Rectangle {
boundsBehavior: Flickable.StopAtBounds
clip: true
delegate: WalletDelegate {
currency: RootStore.currentCurrency
locale: RootStore.locale
selectedAccountIndex: walletInfoContainer.selectedAccountIndex
delegate: StatusListItem {
width: parent.width
highlighted: index === selectedAccountIndex
title: model.name
subTitle: Utils.toLocaleString(model.currencyBalance.toFixed(2), RootStore.locale, {"model.currency": true}) + " " + RootStore.currentCurrency.toUpperCase()
icon.emoji: !!model.emoji ? model.emoji: ""
icon.color: model.color
icon.name: !model.emoji ? "filled-account": ""
icon.letterSize: 14
icon.isLetterIdenticon: !!model.emoji ? true : false
icon.background.color: Theme.palette.indirectColor1
onClicked: {
changeSelectedAccount(index)
showSavedAddresses(false)

View File

@ -19,6 +19,7 @@ Item {
property var changeSelectedAccount
property alias currentTabIndex: walletTabBar.currentIndex
property var store
property var emojiPopup
WalletHeader {
id: walletHeader
@ -28,6 +29,7 @@ Item {
changeSelectedAccount: walletContainer.changeSelectedAccount
store: walletContainer.store
walletStore: RootStore
emojiPopup: walletContainer.emojiPopup
}
RowLayout {

View File

@ -497,6 +497,7 @@ Item {
Layout.fillHeight: true
store: appMain.rootStore
contactsStore: appMain.rootStore.profileSectionStore.contactsStore
emojiPopup: statusEmojiPopup
}
Component {