feat: list preferred username, available ens names and send preferred username on new messages

This commit is contained in:
Richard Ramos 2020-08-05 15:50:55 -04:00 committed by Pascal Precht
parent 43f4f8775b
commit 40e8802218
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
7 changed files with 272 additions and 44 deletions

View File

@ -53,7 +53,7 @@ QtObject:
let userWallet = status_settings.getSetting[string](Setting.WalletRootAddress, "0x0") let userWallet = status_settings.getSetting[string](Setting.WalletRootAddress, "0x0")
let pubkey = status_ens.pubkey(ens) let pubkey = status_ens.pubkey(ens)
if ownerAddr != "": if ownerAddr != "":
if pubkey == "": if pubkey == "" and ownerAddr == userWallet:
output = "owned" # "Continuing will connect this username with your chat key." output = "owned" # "Continuing will connect this username with your chat key."
elif pubkey == userPubkey: elif pubkey == userPubkey:
output = "connected" output = "connected"
@ -65,13 +65,24 @@ QtObject:
output = "taken" output = "taken"
output output
proc connect(self: EnsManager, username: string) {.slot.} = proc add*(self: EnsManager, username: string) =
let ensUsername = username & status_ens.domain self.beginInsertRows(newQModelIndex(), self.usernames.len, self.usernames.len)
self.usernames.add(username)
self.endInsertRows()
proc connect(self: EnsManager, username: string, isStatus: bool) {.slot.} =
var ensUsername = username
if isStatus:
ensUsername = ensUsername & status_ens.domain
var usernames = status_settings.getSetting[seq[string]](Setting.Usernames, @[]) var usernames = status_settings.getSetting[seq[string]](Setting.Usernames, @[])
let preferredUsername = status_settings.getSetting[string](Setting.PreferredUsername, "")
usernames.add ensUsername usernames.add ensUsername
discard status_settings.saveSetting(Setting.Usernames, %*usernames) discard status_settings.saveSetting(Setting.Usernames, %*usernames)
discard status_settings.saveSetting(Setting.PreferredUsername, ensUsername) if usernames.len == 1:
discard status_settings.saveSetting(Setting.PreferredUsername, ensUsername)
self.add ensUsername
proc preferredUsername(self: EnsManager): string {.slot.} =
result = status_settings.getSetting[string](Setting.PreferredUsername, "")
method rowCount(self: EnsManager, index: QModelIndex = nil): int = method rowCount(self: EnsManager, index: QModelIndex = nil): int =
return self.usernames.len return self.usernames.len
@ -88,8 +99,3 @@ QtObject:
{ {
EnsRoles.UserName.int:"username" EnsRoles.UserName.int:"username"
}.toTable }.toTable
proc add*(self: EnsManager, username: string) =
self.beginInsertRows(newQModelIndex(), self.usernames.len, self.usernames.len)
self.usernames.add(username)
self.endInsertRows()

View File

@ -19,7 +19,8 @@ proc isDeviceSetup*():bool =
result = false result = false
proc syncAllDevices*() = proc syncAllDevices*() =
discard syncDevices() let preferredUsername = getSetting[string](Setting.PreferredUsername, "")
discard syncDevices(preferredUsername)
proc advertise*() = proc advertise*() =
discard sendPairInstallation() discard sendPairInstallation()

View File

@ -1,8 +1,9 @@
import json, times, strutils, sequtils, chronicles import json, times, strutils, sequtils, chronicles, json_serialization
import core, utils import core, utils
import ../chat/[chat, message] import ../chat/[chat, message]
import ../../signals/messages import ../../signals/messages
import ./types import ./types
import ./settings
proc buildFilter*(chat: Chat):JsonNode = proc buildFilter*(chat: Chat):JsonNode =
if chat.chatType == ChatType.PrivateGroupChat: if chat.chatType == ChatType.PrivateGroupChat:
@ -72,34 +73,38 @@ proc generateSymKeyFromPassword*(): string =
]))["result"]).strip(chars = {'"'}) ]))["result"]).strip(chars = {'"'})
proc sendChatMessage*(chatId: string, msg: string, replyTo: string, contentType: int): string = proc sendChatMessage*(chatId: string, msg: string, replyTo: string, contentType: int): string =
let preferredUsername = getSetting[string](Setting.PreferredUsername, "")
callPrivateRPC("sendChatMessage".prefix, %* [ callPrivateRPC("sendChatMessage".prefix, %* [
{ {
"chatId": chatId, "chatId": chatId,
"text": msg, "text": msg,
"responseTo": replyTo, "responseTo": replyTo,
"ensName": nil, "ensName": preferredUsername,
"sticker": nil, "sticker": nil,
"contentType": contentType "contentType": contentType
} }
]) ])
proc sendImageMessage*(chatId: string, image: string): string = proc sendImageMessage*(chatId: string, image: string): string =
let preferredUsername = getSetting[string](Setting.PreferredUsername, "")
callPrivateRPC("sendChatMessage".prefix, %* [ callPrivateRPC("sendChatMessage".prefix, %* [
{ {
"chatId": chatId, "chatId": chatId,
"contentType": ContentType.Image.int, "contentType": ContentType.Image.int,
"imagePath": image, "imagePath": image,
"ensName": preferredUsername,
"text": "Update to latest version to see a nice image here!" "text": "Update to latest version to see a nice image here!"
} }
]) ])
proc sendStickerMessage*(chatId: string, sticker: Sticker): string = proc sendStickerMessage*(chatId: string, sticker: Sticker): string =
let preferredUsername = getSetting[string](Setting.PreferredUsername, "")
callPrivateRPC("sendChatMessage".prefix, %* [ callPrivateRPC("sendChatMessage".prefix, %* [
{ {
"chatId": chatId, "chatId": chatId,
"text": "Update to latest version to see a nice sticker here!", "text": "Update to latest version to see a nice sticker here!",
"responseTo": nil, "responseTo": nil,
"ensName": nil, "ensName": preferredUsername,
"sticker": { "sticker": {
"hash": sticker.hash, "hash": sticker.hash,
"pack": sticker.packId "pack": sticker.packId

View File

@ -14,9 +14,7 @@ proc getOurInstallations*(useCached: bool = true): JsonNode =
dirty = false dirty = false
result = installations result = installations
proc syncDevices*(): string = proc syncDevices*(preferredName: string): string =
# These are not being used at the moment
let preferredName = ""
let photoPath = "" let photoPath = ""
result = callPrivateRPC("syncDevices".prefix, %* [preferredName, photoPath]) result = callPrivateRPC("syncDevices".prefix, %* [preferredName, photoPath])

View File

@ -3,10 +3,93 @@ import QtQuick.Layouts 1.3
import QtQuick.Controls 2.14 import QtQuick.Controls 2.14
import "../../../../../imports" import "../../../../../imports"
import "../../../../../shared" import "../../../../../shared"
import "../../../Chat/ChatColumn/MessageComponents"
Item { Item {
property var onClick: function(){} property var onClick: function(){}
// Defaults to show message
property bool isMessage: true
property bool isEmoji: false
property bool isCurrentUser: false
property int contentType: 1
property string message: qsTr("Hey")
property string authorCurrentMsg: "0"
property string authorPrevMsg: "1"
property var clickMessage: function(){}
property string identicon: profileModel.profile.identicon
property int timestamp: 1577872140
Component {
id: statusENS
Item {
Text {
id: usernameTxt
text: username.substr(0, username.indexOf("."))
color: Style.current.textColor
}
Text {
anchors.top: usernameTxt.bottom
anchors.topMargin: 2
text: username.substr(username.indexOf("."))
color: Style.current.darkGrey
}
}
}
Component {
id: normalENS
Item {
Text {
id: usernameTxt
text: username
font.pixelSize: 16
color: Style.current.textColor
anchors.top: parent.top
anchors.topMargin: 5
}
}
}
Component {
id: ensDelegate
Item {
height: 45
Rectangle {
id: circle
width: 35
height: 35
radius: 35
color: Style.current.blue
StyledText {
text: "@"
opacity: 0.7
font.weight: Font.Bold
font.pixelSize: 16
color: Style.current.white
anchors.centerIn: parent
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
}
Loader {
sourceComponent: model.username.endsWith(".stateofus.eth") ? statusENS : normalENS
property string username: model.username
active: true
anchors.left: circle.right
anchors.leftMargin: Style.current.smallPadding
}
}
}
}
StyledText { StyledText {
id: sectionTitle id: sectionTitle
//% "ENS usernames" //% "ENS usernames"
@ -51,27 +134,136 @@ Item {
} }
} }
ScrollView {
id: sview StyledText {
clip: true id: usernamesLabel
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff text: qsTr("Your usernames")
contentHeight: contentItem.childrenRect.height anchors.left: parent.left
anchors.top: addUsername.bottom anchors.top: addUsername.bottom
anchors.topMargin: Style.current.padding anchors.topMargin: 24
anchors.bottom: parent.bottom font.pixelSize: 16
}
Item {
anchors.top: usernamesLabel.bottom
anchors.topMargin: 10
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
height: 200
id: ensList
Item { ScrollView {
id: contentItem anchors.fill: parent
anchors.right: parent.right; Layout.fillWidth: true
anchors.left: parent.left; Layout.fillHeight: true
StyledText { ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
id: title ScrollBar.vertical.policy: lvEns.contentHeight > lvEns.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
text: "TODO: Show ENS username list"
anchors.top: parent.top ListView {
id: lvEns
anchors.fill: parent
model: profileModel.ens
spacing: 10
clip: true
delegate: ensDelegate
} }
} }
} }
Separator {
id: separator
anchors.topMargin: Style.current.padding
anchors.top: ensList.bottom
}
StyledText {
id: chatSettingsLabel
visible: profileModel.ens.rowCount() > 1
text: qsTr("Chat Settings")
anchors.left: parent.left
anchors.top: ensList.bottom
anchors.topMargin: 24
font.pixelSize: 16
}
StyledText {
id: usernameLabel
visible: chatSettingsLabel.visible
text: qsTr("Primary Username")
anchors.left: parent.left
anchors.top: chatSettingsLabel.bottom
anchors.topMargin: 24
font.pixelSize: 14
font.weight: Font.Bold
}
StyledText {
id: usernameLabel2
visible: chatSettingsLabel.visible
text: profileModel.ens.preferredUsername()
anchors.left: usernameLabel.right
anchors.leftMargin: Style.current.padding
anchors.top: chatSettingsLabel.bottom
anchors.topMargin: 24
font.pixelSize: 14
}
Item {
anchors.top: profileModel.ens.rowCount() == 1 ? separator.bottom : usernameLabel.bottom
anchors.topMargin: Style.current.padding * 2
UserImage {
id: chatImage
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
anchors.top: parent.top
anchors.topMargin: 20
}
UsernameLabel {
id: chatName
text: profileModel.ens.preferredUsername()
anchors.leftMargin: 20
anchors.top: parent.top
anchors.topMargin: 0
anchors.left: chatImage.right
}
Rectangle {
property int chatVerticalPadding: 7
property int chatHorizontalPadding: 12
id: chatBox
color: Style.current.secondaryBackground
height: 35
width: 80
radius: 16
anchors.left: chatImage.right
anchors.leftMargin: 8
anchors.top: chatImage.top
ChatText {
id: chatText
anchors.top: parent.top
anchors.topMargin: chatBox.chatVerticalPadding
anchors.left: parent.left
anchors.leftMargin: chatBox.chatHorizontalPadding
horizontalAlignment: Text.AlignLeft
color: Style.current.textColor
}
RectangleCorner {}
}
ChatTime {
id: chatTime
anchors.top: chatBox.bottom
anchors.topMargin: 4
anchors.bottomMargin: Style.current.padding
anchors.right: chatBox.right
anchors.rightMargin: Style.current.padding
}
}
} }

View File

@ -12,31 +12,33 @@ Item {
property string validationMessage: "" property string validationMessage: ""
property bool valid: false property bool valid: false
property bool isStatus: true property bool isStatus: true
property bool loading: false
property string ensStatus: "" property string ensStatus: ""
property var validateENS: Backpressure.debounce(searchENS, 500, function (ensName, isStatus){ property var validateENS: Backpressure.debounce(searchENS, 500, function (ensName, isStatus){
profileModel.ens.validate(ensName, isStatus) profileModel.ens.validate(ensName, isStatus)
}); });
function validate() { function validate(ensUsername) {
validationMessage = ""; validationMessage = "";
valid = false; valid = false;
ensStatus = ""; ensStatus = "";
if (ensUsername.text.length < 4) { if (ensUsername.length < 4) {
validationMessage = qsTr("At least 4 characters. Latin letters, numbers, and lowercase only."); validationMessage = qsTr("At least 4 characters. Latin letters, numbers, and lowercase only.");
} else if(isStatus && !ensUsername.text.match(/^[a-z0-9]+$/)){ } else if(isStatus && !ensUsername.match(/^[a-z0-9]+$/)){
validationMessage = qsTr("Letters and numbers only."); validationMessage = qsTr("Letters and numbers only.");
} else if(!isStatus && !ensUsername.text.endsWith(".eth")){ } else if(!isStatus && !ensUsername.endsWith(".eth")){
validationMessage = qsTr("Type the entire username including the custom domain like username.domain.eth") validationMessage = qsTr("Type the entire username including the custom domain like username.domain.eth")
} }
return validationMessage === ""; return validationMessage === "";
} }
function onKeyReleased(){ function onKeyReleased(ensUsername){
if (!validate()) { if (!validate(ensUsername)) {
return; return;
} }
Qt.callLater(validateENS, ensUsername.text, isStatus) loading = true;
Qt.callLater(validateENS, ensUsername, isStatus)
} }
StyledText { StyledText {
@ -60,8 +62,26 @@ Item {
radius: 120 radius: 120
color: Style.current.blue color: Style.current.blue
SVGImage {
id: imgIcon
visible: ensStatus === "taken"
fillMode: Image.PreserveAspectFit
source: "../../../../img/block-icon-white.svg"
width: 20
height: 20
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
StyledText { StyledText {
text: "@" visible: ensStatus !== "taken"
text: {
if((ensStatus === "available" || ensStatus === "connected" || ensStatus === "connected-different-key")){
return "✓"
} else {
return "@"
}
}
opacity: 0.7 opacity: 0.7
font.weight: Font.Bold font.weight: Font.Bold
font.pixelSize: 18 font.pixelSize: 18
@ -79,13 +99,15 @@ Item {
anchors.right: btnContinue.left anchors.right: btnContinue.left
anchors.rightMargin: 24 anchors.rightMargin: 24
Keys.onReleased: { Keys.onReleased: {
onKeyReleased(); onKeyReleased(ensUsername.text);
} }
Connections { Connections {
target: profileModel.ens target: profileModel.ens
onEnsWasResolved: { onEnsWasResolved: {
if(!validate(ensUsername.text)) return;
valid = false; valid = false;
loading = false;
ensStatus = ensResult; ensStatus = ensResult;
switch(ensResult){ switch(ensResult){
case "available": case "available":
@ -139,7 +161,7 @@ Item {
if(!valid) return; if(!valid) return;
if(ensStatus === "connected"){ if(ensStatus === "connected"){
profileModel.ens.connect(ensUsername.text); profileModel.ens.connect(ensUsername.text, isStatus);
onClick(ensStatus, ensUsername.text); onClick(ensStatus, ensUsername.text);
return; return;
} }
@ -188,8 +210,9 @@ Item {
anchors.fill: parent anchors.fill: parent
onClicked : { onClicked : {
isStatus = !isStatus; isStatus = !isStatus;
if(validate()) let ensUser = ensUsername.text;
validateENS(ensUsername.text, isStatus) if(validate(ensUser))
validateENS(ensUser, isStatus)
} }
} }
} }

View File

@ -0,0 +1,3 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.99967 13.6668C3.31778 13.6668 0.333008 10.6821 0.333008 7.00016C0.333008 3.31826 3.31778 0.333496 6.99967 0.333496C10.6816 0.333496 13.6663 3.31826 13.6663 7.00016C13.6663 10.6821 10.6816 13.6668 6.99967 13.6668ZM2.91208 10.3806C2.77375 10.519 2.54581 10.5094 2.42998 10.3518C1.74037 9.41312 1.33301 8.25421 1.33301 7.00016C1.33301 3.87055 3.87006 1.3335 6.99967 1.3335C8.25373 1.3335 9.41263 1.74086 10.3513 2.43047C10.509 2.5463 10.5185 2.77424 10.3802 2.91257L2.91208 10.3806ZM3.61919 11.0878C3.48086 11.2261 3.4904 11.454 3.64806 11.5699C4.58672 12.2595 5.74562 12.6668 6.99967 12.6668C10.1293 12.6668 12.6663 10.1298 12.6663 7.00016C12.6663 5.74611 12.259 4.5872 11.5694 3.64855C11.4535 3.49089 11.2256 3.48135 11.0873 3.61968L3.61919 11.0878Z" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 922 B