feat: display name

This commit is contained in:
Richard Ramos 2022-03-01 20:14:20 -04:00
parent 228a1ed88d
commit b07910e27f
29 changed files with 228 additions and 21 deletions

View File

@ -271,6 +271,7 @@ proc delete*(self: AppController) =
proc startupDidLoad*(self: AppController) = proc startupDidLoad*(self: AppController) =
singletonInstance.engine.setRootContextProperty("localAppSettings", self.localAppSettingsVariant) singletonInstance.engine.setRootContextProperty("localAppSettings", self.localAppSettingsVariant)
singletonInstance.engine.setRootContextProperty("localAccountSettings", self.localAccountSettingsVariant) singletonInstance.engine.setRootContextProperty("localAccountSettings", self.localAccountSettingsVariant)
singletonInstance.engine.setRootContextProperty("globalUtils", self.globalUtilsVariant)
singletonInstance.engine.load(newQUrl("qrc:///main.qml")) singletonInstance.engine.load(newQUrl("qrc:///main.qml"))
# We need to init a language service once qml is loaded # We need to init a language service once qml is loaded
@ -314,6 +315,10 @@ proc load(self: AppController) =
self.gifService.init() self.gifService.init()
singletonInstance.engine.setRootContextProperty("globalUtils", self.globalUtilsVariant) singletonInstance.engine.setRootContextProperty("globalUtils", self.globalUtilsVariant)
let pubKey = self.settingsService.getPublicKey()
singletonInstance.localAccountSensitiveSettings.setFileName(pubKey)
singletonInstance.engine.setRootContextProperty("localAccountSensitiveSettings", self.localAccountSensitiveSettingsVariant)
self.buildAndRegisterLocalAccountSensitiveSettings() self.buildAndRegisterLocalAccountSensitiveSettings()
self.buildAndRegisterUserProfile() self.buildAndRegisterUserProfile()
@ -352,6 +357,7 @@ proc buildAndRegisterLocalAccountSensitiveSettings(self: AppController) =
proc buildAndRegisterUserProfile(self: AppController) = proc buildAndRegisterUserProfile(self: AppController) =
let pubKey = self.settingsService.getPublicKey() let pubKey = self.settingsService.getPublicKey()
let preferredName = self.settingsService.getPreferredName() let preferredName = self.settingsService.getPreferredName()
let displayName = self.settingsService.getDisplayName()
let ensUsernames = self.settingsService.getEnsUsernames() let ensUsernames = self.settingsService.getEnsUsernames()
let firstEnsName = if (ensUsernames.len > 0): ensUsernames[0] else: "" let firstEnsName = if (ensUsernames.len > 0): ensUsernames[0] else: ""
let sendUserStatus = self.settingsService.getSendStatusUpdates() let sendUserStatus = self.settingsService.getSendStatusUpdates()
@ -370,6 +376,7 @@ proc buildAndRegisterUserProfile(self: AppController) =
singletonInstance.userProfile.setFixedData(loggedInAccount.name, loggedInAccount.keyUid, loggedInAccount.identicon, singletonInstance.userProfile.setFixedData(loggedInAccount.name, loggedInAccount.keyUid, loggedInAccount.identicon,
pubKey) pubKey)
singletonInstance.userProfile.setDisplayName(displayName)
singletonInstance.userProfile.setPreferredName(preferredName) singletonInstance.userProfile.setPreferredName(preferredName)
singletonInstance.userProfile.setEnsName(meAsContact.name) singletonInstance.userProfile.setEnsName(meAsContact.name)
singletonInstance.userProfile.setFirstEnsName(firstEnsName) singletonInstance.userProfile.setFirstEnsName(firstEnsName)

View File

@ -12,6 +12,7 @@ QtObject:
# fields which may change during runtime # fields which may change during runtime
isIdenticon: bool isIdenticon: bool
ensName: string ensName: string
displayName: string
firstEnsName: string firstEnsName: string
preferredName: string preferredName: string
thumbnailImage: string thumbnailImage: string
@ -49,7 +50,6 @@ QtObject:
QtProperty[string] pubKey: QtProperty[string] pubKey:
read = getPubKey read = getPubKey
proc nameChanged*(self: UserProfile) {.signal.} proc nameChanged*(self: UserProfile) {.signal.}
proc getUsername*(self: UserProfile): string {.slot.} = proc getUsername*(self: UserProfile): string {.slot.} =
@ -118,6 +118,16 @@ QtObject:
read = getPrettyPreferredName read = getPrettyPreferredName
notify = nameChanged notify = nameChanged
proc setDisplayName*(self: UserProfile, displayName: string) = # Not a slot
self.displayName = displayName
self.nameChanged()
proc getDisplayName*(self: UserProfile): string {.slot.} =
self.displayName
QtProperty[string] displayName:
read = getDisplayName
notify = nameChanged
proc getName*(self: UserProfile): string {.slot.} = proc getName*(self: UserProfile): string {.slot.} =
if(self.preferredName.len > 0): if(self.preferredName.len > 0):
@ -126,13 +136,14 @@ QtObject:
return self.getPrettyFirstEnsName() return self.getPrettyFirstEnsName()
elif(self.ensName.len > 0): elif(self.ensName.len > 0):
return self.getPrettyEnsName() return self.getPrettyEnsName()
elif(self.displayName.len > 0):
return self.getDisplayName()
return self.username return self.username
QtProperty[string] name: QtProperty[string] name:
read = getName read = getName
notify = nameChanged notify = nameChanged
proc imageChanged*(self: UserProfile) {.signal.} proc imageChanged*(self: UserProfile) {.signal.}
proc getIsIdenticon*(self: UserProfile): bool {.slot.} = proc getIsIdenticon*(self: UserProfile): bool {.slot.} =

View File

@ -26,6 +26,9 @@ QtObject:
# Windows doesn't work with paths starting with a slash # Windows doesn't work with paths starting with a slash
result.removePrefix('/') result.removePrefix('/')
proc isAlias*(self: Utils, value: string): bool {.slot.} =
result = procs_from_accounts.isAlias(value)
proc urlFromUserInput*(self: Utils, input: string): string {.slot.} = proc urlFromUserInput*(self: Utils, input: string): string {.slot.} =
result = url_fromUserInput(input) result = url_fromUserInput(input)

View File

@ -27,3 +27,6 @@ method storeIdentityImage*(self: Controller, address: string, image: string, aX:
method deleteIdentityImage*(self: Controller, address: string) = method deleteIdentityImage*(self: Controller, address: string) =
self.profileService.deleteIdentityImage(address) self.profileService.deleteIdentityImage(address)
method setDisplayName*(self: Controller, displayName: string): bool =
self.profileService.setDisplayName(displayName)

View File

@ -16,3 +16,6 @@ method storeIdentityImage*(self: AccessInterface, address: string, image: string
method deleteIdentityImage*(self: AccessInterface, address: string) {.base.} = method deleteIdentityImage*(self: AccessInterface, address: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method setDisplayName*(self: AccessInterface, displayName: string): bool {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -22,6 +22,9 @@ method storeIdentityImage*(self: AccessInterface, imageUrl: string, aX: int, aY:
method deleteIdentityImage*(self: AccessInterface) {.base.} = method deleteIdentityImage*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method setDisplayName*(self: AccessInterface, displayName: string) {.base.} =
raise newException(ValueError, "No implementation available")
# View Delegate Interface # View Delegate Interface
# Delegate for the view must be declared here due to use of QtObject and multi # Delegate for the view must be declared here due to use of QtObject and multi
# inheritance, which is not well supported in Nim. # inheritance, which is not well supported in Nim.

View File

@ -66,3 +66,9 @@ method deleteIdentityImage*(self: Module) =
self.controller.deleteIdentityImage(address) self.controller.deleteIdentityImage(address)
singletonInstance.userProfile.setLargeImage("") singletonInstance.userProfile.setLargeImage("")
singletonInstance.userProfile.setThumbnailImage("") singletonInstance.userProfile.setThumbnailImage("")
method setDisplayName*(self: Module, displayName: string) =
if self.controller.setDisplayName(displayName):
singletonInstance.userProfile.setDisplayName(displayName)
else:
error "could not set display name"

View File

@ -27,6 +27,8 @@ QtObject:
self.delegate.storeIdentityImage(imageUrl, aX, aY, bX, bY) self.delegate.storeIdentityImage(imageUrl, aX, aY, bX, bY)
proc remove*(self: View): string {.slot.} = proc remove*(self: View): string {.slot.} =
self.delegate.deleteIdentityImage() self.delegate.deleteIdentityImage()
proc setDisplayName(self: View, displayName: string) {.slot.} =
self.delegate.setDisplayName(displayName)

View File

@ -19,6 +19,7 @@ type
events: EventEmitter events: EventEmitter
accountsService: accounts_service.ServiceInterface accountsService: accounts_service.ServiceInterface
selectedAccountId: string selectedAccountId: string
displayName: string
proc newController*(delegate: io_interface.AccessInterface, proc newController*(delegate: io_interface.AccessInterface,
events: EventEmitter, events: EventEmitter,
@ -48,8 +49,11 @@ method setSelectedAccountByIndex*(self: Controller, index: int) =
let accounts = self.getGeneratedAccounts() let accounts = self.getGeneratedAccounts()
self.selectedAccountId = accounts[index].id self.selectedAccountId = accounts[index].id
method setDisplayName*(self: Controller, displayName: string) =
self.displayName = displayName
method storeSelectedAccountAndLogin*(self: Controller, password: string) = method storeSelectedAccountAndLogin*(self: Controller, password: string) =
if(not self.accountsService.setupAccount(self.selectedAccountId, password)): if(not self.accountsService.setupAccount(self.selectedAccountId, password, self.displayName)):
self.delegate.setupAccountError() self.delegate.setupAccountError()
method validateMnemonic*(self: Controller, mnemonic: string): string = method validateMnemonic*(self: Controller, mnemonic: string): string =

View File

@ -16,6 +16,9 @@ method getGeneratedAccounts*(self: AccessInterface): seq[GeneratedAccountDto] {.
method setSelectedAccountByIndex*(self: AccessInterface, index: int) {.base.} = method setSelectedAccountByIndex*(self: AccessInterface, index: int) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method setDisplayName*(self: AccessInterface, displayName: string) {.base.} =
raise newException(ValueError, "No implementation available")
method storeSelectedAccountAndLogin*(self: AccessInterface, password: string) {.base.} = method storeSelectedAccountAndLogin*(self: AccessInterface, password: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")

View File

@ -53,6 +53,9 @@ method viewDidLoad*(self: Module) =
method setSelectedAccountByIndex*(self: Module, index: int) = method setSelectedAccountByIndex*(self: Module, index: int) =
self.controller.setSelectedAccountByIndex(index) self.controller.setSelectedAccountByIndex(index)
method setDisplayName*(self: Module, displayName: string) =
self.controller.setDisplayName(displayName)
method storeSelectedAccountAndLogin*(self: Module, password: string) = method storeSelectedAccountAndLogin*(self: Module, password: string) =
self.controller.storeSelectedAccountAndLogin(password) self.controller.storeSelectedAccountAndLogin(password)

View File

@ -19,3 +19,6 @@ method validateMnemonic*(self: AccessInterface, mnemonic: string):
method importMnemonic*(self: AccessInterface, mnemonic: string) {.base.} = method importMnemonic*(self: AccessInterface, mnemonic: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method setDisplayName*(self: AccessInterface, displayName: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -60,6 +60,9 @@ QtObject:
read = getImportedAccountAddress read = getImportedAccountAddress
notify = importedAccountChanged notify = importedAccountChanged
proc setDisplayName*(self: View, displayName: string) {.slot.} =
self.delegate.setDisplayName(displayName)
proc setSelectedAccountByIndex*(self: View, index: int) {.slot.} = proc setSelectedAccountByIndex*(self: View, index: int) {.slot.} =
self.delegate.setSelectedAccountByIndex(index) self.delegate.setSelectedAccountByIndex(index)

View File

@ -49,6 +49,9 @@ proc generateAliasFromPk*(publicKey: string): string =
proc generateIdenticonFromPk*(publicKey: string): string = proc generateIdenticonFromPk*(publicKey: string): string =
return status_account.generateIdenticon(publicKey).result.getStr return status_account.generateIdenticon(publicKey).result.getStr
proc isAlias*(value: string): bool =
return status_account.isAlias(value)
method init*(self: Service) = method init*(self: Service) =
try: try:
let response = status_account.generateAddresses(PATHS) let response = status_account.generateAddresses(PATHS)
@ -179,12 +182,13 @@ proc getSubaccountDataForAccountId(self: Service, accountId: string): JsonNode =
return self.prepareSubaccountJsonObject(self.importedAccount) return self.prepareSubaccountJsonObject(self.importedAccount)
proc prepareAccountSettingsJsonObject(self: Service, account: GeneratedAccountDto, proc prepareAccountSettingsJsonObject(self: Service, account: GeneratedAccountDto,
installationId: string): JsonNode = installationId: string, displayName: string): JsonNode =
result = %* { result = %* {
"key-uid": account.keyUid, "key-uid": account.keyUid,
"mnemonic": account.mnemonic, "mnemonic": account.mnemonic,
"public-key": account.derivedAccounts.whisper.publicKey, "public-key": account.derivedAccounts.whisper.publicKey,
"name": account.alias, "name": account.alias,
"display-name": displayName,
"address": account.address, "address": account.address,
"eip1581-address": account.derivedAccounts.eip1581.address, "eip1581-address": account.derivedAccounts.eip1581.address,
"dapps-address": account.derivedAccounts.defaultWallet.address, "dapps-address": account.derivedAccounts.defaultWallet.address,
@ -206,14 +210,15 @@ proc prepareAccountSettingsJsonObject(self: Service, account: GeneratedAccountDt
} }
proc getAccountSettings(self: Service, accountId: string, proc getAccountSettings(self: Service, accountId: string,
installationId: string): JsonNode = installationId: string,
displayName: string): JsonNode =
for acc in self.generatedAccounts: for acc in self.generatedAccounts:
if(acc.id == accountId): if(acc.id == accountId):
return self.prepareAccountSettingsJsonObject(acc, installationId) return self.prepareAccountSettingsJsonObject(acc, installationId, displayName)
if(self.importedAccount.isValid()): if(self.importedAccount.isValid()):
if(self.importedAccount.id == accountId): if(self.importedAccount.id == accountId):
return self.prepareAccountSettingsJsonObject(self.importedAccount, installationId) return self.prepareAccountSettingsJsonObject(self.importedAccount, installationId, displayName)
proc getDefaultNodeConfig*(self: Service, installationId: string): JsonNode = proc getDefaultNodeConfig*(self: Service, installationId: string): JsonNode =
let networkConfig = getNetworkConfig(DEFAULT_NETWORK_NAME) let networkConfig = getNetworkConfig(DEFAULT_NETWORK_NAME)
@ -244,12 +249,12 @@ proc getDefaultNodeConfig*(self: Service, installationId: string): JsonNode =
# TODO: commented since it's not necessary (we do the connections thru C bindings). Enable it thru an option once status-nodes are able to be configured in desktop # TODO: commented since it's not necessary (we do the connections thru C bindings). Enable it thru an option once status-nodes are able to be configured in desktop
# result["ListenAddr"] = if existsEnv("STATUS_PORT"): newJString("0.0.0.0:" & $getEnv("STATUS_PORT")) else: newJString("0.0.0.0:30305") # result["ListenAddr"] = if existsEnv("STATUS_PORT"): newJString("0.0.0.0:" & $getEnv("STATUS_PORT")) else: newJString("0.0.0.0:30305")
method setupAccount*(self: Service, accountId, password: string): bool = method setupAccount*(self: Service, accountId, password, displayName: string): bool =
try: try:
let installationId = $genUUID() let installationId = $genUUID()
let accountDataJson = self.getAccountDataForAccountId(accountId) let accountDataJson = self.getAccountDataForAccountId(accountId)
let subaccountDataJson = self.getSubaccountDataForAccountId(accountId) let subaccountDataJson = self.getSubaccountDataForAccountId(accountId)
let settingsJson = self.getAccountSettings(accountId, installationId) let settingsJson = self.getAccountSettings(accountId, installationId, displayName)
let nodeConfigJson = self.getDefaultNodeConfig(installationId) let nodeConfigJson = self.getDefaultNodeConfig(installationId)
if(accountDataJson.isNil or subaccountDataJson.isNil or settingsJson.isNil or if(accountDataJson.isNil or subaccountDataJson.isNil or settingsJson.isNil or

View File

@ -20,7 +20,7 @@ method openedAccounts*(self: ServiceInterface): seq[AccountDto] {.base.} =
method generatedAccounts*(self: ServiceInterface): seq[GeneratedAccountDto] {.base.} = method generatedAccounts*(self: ServiceInterface): seq[GeneratedAccountDto] {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method setupAccount*(self: ServiceInterface, accountId, password: string): bool {.base.} = method setupAccount*(self: ServiceInterface, accountId, password, displayName: string): bool {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method getLoggedInAccount*(self: ServiceInterface): AccountDto {.base.} = method getLoggedInAccount*(self: ServiceInterface): AccountDto {.base.} =
@ -47,5 +47,8 @@ method clear*(self: ServiceInterface) {.base.} =
method generateAlias*(self: ServiceInterface, publicKey: string): string {.base.} = method generateAlias*(self: ServiceInterface, publicKey: string): string {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method isAlias*(self: ServiceInterface, value: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method verifyAccountPassword*(self: ServiceInterface, account: string, password: string): bool {.base.} = method verifyAccountPassword*(self: ServiceInterface, account: string, password: string): bool {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")

View File

@ -40,3 +40,11 @@ method deleteIdentityImage*(self: Service, address: string) =
except Exception as e: except Exception as e:
error "error: ", methodName="deleteIdentityImage", errName = e.name, errDesription = e.msg error "error: ", methodName="deleteIdentityImage", errName = e.name, errDesription = e.msg
method setDisplayName*(self: Service, displayName: string): bool =
try:
discard status_accounts.setDisplayName(displayName)
return true
except Exception as e:
error "error: ", methodName="setDisplayName", errName = e.name, errDesription = e.msg
return false

View File

@ -18,3 +18,6 @@ method storeIdentityImage*(self: ServiceInterface, address: string, image: strin
method deleteIdentityImage*(self: ServiceInterface, address: string) {.base.} = method deleteIdentityImage*(self: ServiceInterface, address: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method setDisplayName*(self: ServiceInterface, displayName: string): bool {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -44,6 +44,7 @@ const KEY_AUTO_MESSAGE_ENABLED* = "auto-message-enabled?"
const KEY_GIF_FAVORITES* = "gifs/favorite-gifs" const KEY_GIF_FAVORITES* = "gifs/favorite-gifs"
const KEY_GIF_RECENTS* = "gifs/recent-gifs" const KEY_GIF_RECENTS* = "gifs/recent-gifs"
const KEY_GIF_API_KEY* = "gifs/api-key" const KEY_GIF_API_KEY* = "gifs/api-key"
const KEY_DISPLAY_NAME = "display-name"
const PROFILE_PICTURES_VISIBILITY_CONTACTS_ONLY* = 1 const PROFILE_PICTURES_VISIBILITY_CONTACTS_ONLY* = 1
const PROFILE_PICTURES_VISIBILITY_EVERYONE* = 2 const PROFILE_PICTURES_VISIBILITY_EVERYONE* = 2
@ -88,6 +89,7 @@ type
dappsAddress*: string dappsAddress*: string
eip1581Address*: string eip1581Address*: string
installationId*: string installationId*: string
displayName*: string
preferredName*: string preferredName*: string
ensUsernames*: seq[string] ensUsernames*: seq[string]
keyUid*: string keyUid*: string
@ -183,6 +185,7 @@ proc toSettingsDto*(jsonObj: JsonNode): SettingsDto =
discard jsonObj.getProp(KEY_EIP1581_ADDRESS, result.eip1581Address) discard jsonObj.getProp(KEY_EIP1581_ADDRESS, result.eip1581Address)
discard jsonObj.getProp(KEY_INSTALLATION_ID, result.installationId) discard jsonObj.getProp(KEY_INSTALLATION_ID, result.installationId)
discard jsonObj.getProp(KEY_PREFERRED_NAME, result.preferredName) discard jsonObj.getProp(KEY_PREFERRED_NAME, result.preferredName)
discard jsonObj.getProp(KEY_DISPLAY_NAME, result.displayName)
discard jsonObj.getProp(KEY_KEY_UID, result.keyUid) discard jsonObj.getProp(KEY_KEY_UID, result.keyUid)
discard jsonObj.getProp(KEY_LATEST_DERIVED_PATH, result.latestDerivedPath) discard jsonObj.getProp(KEY_LATEST_DERIVED_PATH, result.latestDerivedPath)
discard jsonObj.getProp(KEY_LINK_PREVIEW_REQUEST_ENABLED, result.linkPreviewRequestEnabled) discard jsonObj.getProp(KEY_LINK_PREVIEW_REQUEST_ENABLED, result.linkPreviewRequestEnabled)

View File

@ -109,6 +109,9 @@ method savePreferredName*(self: Service, value: string): bool =
method getPreferredName*(self: Service): string = method getPreferredName*(self: Service): string =
return self.settings.preferredName return self.settings.preferredName
method getDisplayName*(self: Service): string =
return self.settings.displayName
method saveNewEnsUsername*(self: Service, username: string): bool = method saveNewEnsUsername*(self: Service, username: string): bool =
var newEnsUsernames = self.settings.ensUsernames var newEnsUsernames = self.settings.ensUsernames
newEnsUsernames.add(username) newEnsUsernames.add(username)

View File

@ -65,6 +65,9 @@ method savePreferredName*(self: ServiceInterface, value: string): bool {.base.}
method getPreferredName*(self: ServiceInterface): string {.base.} = method getPreferredName*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method getDisplayName*(self: ServiceInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method saveNewEnsUsername*(self: ServiceInterface, username: string): bool {.base.} = method saveNewEnsUsername*(self: ServiceInterface, username: string): bool {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")

View File

@ -9,7 +9,7 @@ export response_type
logScope: logScope:
topics = "rpc-accounts" topics = "rpc-accounts"
const NUMBER_OF_ADDRESSES_TO_GENERATE = 5 const NUMBER_OF_ADDRESSES_TO_GENERATE = 1
const MNEMONIC_PHRASE_LENGTH = 12 const MNEMONIC_PHRASE_LENGTH = 12
const GENERATED* = "generated" const GENERATED* = "generated"
@ -61,6 +61,11 @@ proc generateAlias*(publicKey: string): RpcResponse[JsonNode] {.raises: [Excepti
error "error doing rpc request", methodName = "generateAlias", exception=e.msg error "error doing rpc request", methodName = "generateAlias", exception=e.msg
raise newException(RpcException, e.msg) raise newException(RpcException, e.msg)
proc isAlias*(value: string): bool =
let response = status_go.isAlias(value)
let r = Json.decode(response, JsonNode)
return r["result"].getBool()
proc generateIdenticon*(publicKey: string): RpcResponse[JsonNode] {.raises: [Exception].} = proc generateIdenticon*(publicKey: string): RpcResponse[JsonNode] {.raises: [Exception].} =
try: try:
let response = status_go.identicon(publicKey) let response = status_go.identicon(publicKey)
@ -255,3 +260,7 @@ proc storeIdentityImage*(keyUID: string, imagePath: string, aX, aY, bX, bY: int)
proc deleteIdentityImage*(keyUID: string): RpcResponse[JsonNode] {.raises: [Exception].} = proc deleteIdentityImage*(keyUID: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [keyUID] let payload = %* [keyUID]
result = core.callPrivateRPC("multiaccounts_deleteIdentityImage", payload) result = core.callPrivateRPC("multiaccounts_deleteIdentityImage", payload)
proc setDisplayName*(displayName: string): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* [displayName]
result = core.callPrivateRPC("setDisplayName".prefix, payload)

View File

@ -5,10 +5,14 @@ import QtGraphicalEffects 1.13
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import utils 1.0 import utils 1.0
import shared 1.0 import shared 1.0
import shared.panels 1.0
import shared.popups 1.0 import shared.popups 1.0
import "../panels" import shared.controls 1.0
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import "../panels"1
import "../stores" import "../stores"
// TODO: replace with StatusModal // TODO: replace with StatusModal
@ -21,9 +25,40 @@ ModalPopup {
title: qsTrId("intro-wizard-title2") title: qsTrId("intro-wizard-title2")
height: 504 height: 504
property string displayNameValidationError: ""
Input {
id: displayNameInput
placeholderText: "DisplayName"
validationError: displayNameValidationError
onTextChanged: {
if(displayNameInput.text === ""){
displayNameValidationError = qsTr("Display name is required")
} else if (!displayNameInput.text.match(/^[a-zA-Z0-9\- ]+$/)){
displayNameValidationError = qsTr("Only letters, numbers, underscores and hyphens allowed")
} else if (displayNameInput.text.length > 24) {
displayNameValidationError = qsTr("24 character username limit")
} else if (displayNameInput.text.length < 5) {
displayNameValidationError = qsTr("Username must be at least 5 characters")
} else if (displayNameInput.text.endsWith(".eth")) {
displayNameValidationError = qsTr(`Usernames ending with ".eth" are not allowed`)
} else if (displayNameInput.text.endsWith("-eth")) {
displayNameValidationError = qsTr(`Usernames ending with "-eth" are not allowed`)
} else if (displayNameInput.text.endsWith("_eth")) {
displayNameValidationError = qsTr(`Usernames ending with "_eth" are not allowed`)
} else if (globalUtils.isAlias(displayNameInput.text)){
displayNameValidationError = qsTr("Sorry, the name you have chosen is not allowed, try picking another username")
}
}
}
AccountListPanel { AccountListPanel {
id: accountList id: accountList
anchors.fill: parent anchors.top: displayNameInput.bottom
anchors.topMargin: 100
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
interactive: false interactive: false
model: OnboardingStore.onBoardingModul.accountsModel model: OnboardingStore.onBoardingModul.accountsModel
@ -34,9 +69,11 @@ ModalPopup {
selectedIndex = index selectedIndex = index
} }
} }
footer: StatusRoundButton { footer: StatusRoundButton {
objectName: "submitButton" objectName: "submitButton"
id: submitBtn id: submitBtn
enabled: displayNameInput.text !== ""
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.topMargin: Style.current.padding anchors.topMargin: Style.current.padding
anchors.right: parent.right anchors.right: parent.right
@ -44,7 +81,7 @@ ModalPopup {
icon.width: 20 icon.width: 20
icon.height: 16 icon.height: 16
onClicked : { onClicked : {
onNextClick(selectedIndex); onNextClick(selectedIndex, displayNameInput.text);
popup.close() popup.close()
} }
} }

View File

@ -9,7 +9,8 @@ QtObject {
onBoardingModul.importMnemonic(mnemonic) onBoardingModul.importMnemonic(mnemonic)
} }
function setCurrentAccount(selectedAccountIdx) { function setCurrentAccountAndDisplayName(selectedAccountIdx, displayName) {
onBoardingModul.setDisplayName(displayName)
onBoardingModul.setSelectedAccountByIndex(selectedAccountIdx) onBoardingModul.setSelectedAccountByIndex(selectedAccountIdx)
} }

View File

@ -16,9 +16,9 @@ Item {
GenKeyModal { GenKeyModal {
property bool wentNext: false property bool wentNext: false
id: genKeyModal id: genKeyModal
onNextClick: function (selectedIndex) { onNextClick: function (selectedIndex, displayName) {
wentNext = true wentNext = true
OnboardingStore.setCurrentAccount(selectedIndex) OnboardingStore.setCurrentAccountAndDisplayName(selectedIndex, displayName)
createPasswordModal.open() createPasswordModal.open()
} }
onClosed: function () { onClosed: function () {

View File

@ -9,6 +9,7 @@ QtObject {
property string pubkey: userProfile.pubKey property string pubkey: userProfile.pubKey
property string name: userProfile.name // in case of ens returns pretty ens form property string name: userProfile.name // in case of ens returns pretty ens form
property string username: userProfile.username property string username: userProfile.username
property string displayName: userProfile.displayName
property string ensName: userProfile.preferredName || userProfile.firstEnsName || userProfile.ensName property string ensName: userProfile.preferredName || userProfile.firstEnsName || userProfile.ensName
property string profileLargeImage: userProfile.largeImage property string profileLargeImage: userProfile.largeImage
property string icon: userProfile.icon property string icon: userProfile.icon
@ -30,4 +31,8 @@ QtObject {
function copyToClipboard(value) { function copyToClipboard(value) {
globalUtils.copyToClipboard(value) globalUtils.copyToClipboard(value)
} }
function setDisplayName(displayName) {
root.profileModule.setDisplayName(displayName)
}
} }

View File

@ -0,0 +1,53 @@
import QtQuick 2.12
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import QtQml.Models 2.3
import utils 1.0
import shared 1.0
import shared.panels 1.0
import shared.popups 1.0
import shared.controls 1.0
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
StatusModal {
id: popup
property var profileStore
onOpened: {
displayNameInput.forceActiveFocus(Qt.MouseFocusReason);
}
contentItem: Item {
width: popup.width
height: childrenRect.height
Column {
anchors.top: parent.top
anchors.topMargin: 16
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - 32
spacing: 16
Input {
id: displayNameInput
placeholderText: "DisplayName"
text: root.profileStore.displayName
//validationError: popup.nicknameTooLong ? qsTrId("your-nickname-is-too-long") : ""
}
}
}
rightButtons: [
StatusButton {
id: doneBtn
text: "Ok"
// enabled: !popup.nicknameTooLong
onClicked: {
popup.profileStore.setDisplayName(displayNameInput.text)
}
}
]
}

View File

@ -85,6 +85,26 @@ Item {
color: Theme.palette.directColor1 color: Theme.palette.directColor1
} }
Component {
id: displayNamePopupComponent
DisplayNamePopup {
profileStore: root.profileStore
onClosed: {
destroy()
}
}
}
StatusButton {
id: "editDisplayName"
text: "Edit"
anchors.left: profileName.right
anchors.leftMargin: Style.current.halfPadding
onClicked: {
Global.openPopup(displayNamePopupComponent);
}
}
Address { Address {
id: pubkeyText id: pubkeyText
text: root.profileStore.ensName !== "" ? root.profileStore.username : root.profileStore.pubkey text: root.profileStore.ensName !== "" ? root.profileStore.username : root.profileStore.pubkey

@ -1 +1 @@
Subproject commit a47b8fa2eb66f270403121774220001ab0fbd59e Subproject commit 50e8f7eef01d801fc3be0168a0eae37137b08439

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 4f5121b4efd4bd8bb3d0de5a357baa70f3068c6c Subproject commit 50ec6f97e01bbd8b61672a1c7db938774b233dbe