feat: add input to search and use ENS for community invite

fixes #2138
This commit is contained in:
Jonathan Rainville 2021-03-31 15:14:09 -04:00 committed by Iuri Matias
parent 63b3ee3942
commit c42bd1ea78
10 changed files with 235 additions and 66 deletions

View File

@ -12,26 +12,36 @@ ModalPopup {
id: popup
property string communityId: chatsModel.communities.activeCommunity.id
property var pubKeys: []
property var goBack
onOpened: {
pubKeys = [];
inviteBtn.enabled = false
contactList.membersData.clear();
// TODO remove friends that are already members
getContactListObject(contactList.membersData)
noContactsRect.visible = !profileModel.contacts.list.hasAddedContacts();
contactList.visible = !noContactsRect.visible;
contactFieldAndList.chatKey.text = ""
contactFieldAndList.pubKey = ""
contactFieldAndList.pubKeys = []
contactFieldAndList.ensUsername = ""
contactFieldAndList.chatKey.forceActiveFocus(Qt.MouseFocusReason)
contactFieldAndList.existingContacts.visible = profileModel.contacts.list.hasAddedContacts()
contactFieldAndList.noContactsRect.visible = !contactFieldAndList.existingContacts.visible
}
//% "Invite friends"
title: qsTrId("invite-friends")
height: 630
function sendInvites(pubKeys) {
const error = chatsModel.communities.inviteUsersToCommunityById(popup.communityId, JSON.stringify(pubKeys))
if (error) {
console.error('Error inviting', error)
contactFieldAndList.validationError = error
return
}
contactFieldAndList.successMessage = qsTr("Invite successfully sent")
}
Item {
anchors.fill: parent
TextWithLabel {
id: shareCommunity
anchors.top: parent.top
@ -51,40 +61,18 @@ ModalPopup {
anchors.rightMargin: -Style.current.padding
}
StyledText {
//% "Contacts"
text: qsTrId("contacts")
anchors.left: parent.left
ContactsListAndSearch {
id: contactFieldAndList
anchors.top: sep.bottom
anchors.topMargin: Style.current.smallPadding
font.pixelSize: 15
font.weight: Font.Thin
color: Style.current.secondaryText
}
NoFriendsRectangle {
id: noContactsRect
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
ContactList {
id: contactList
selectMode: true
anchors.top: sep.bottom
anchors.topMargin: 100
onItemChecked: function(pubKey, itemChecked) {
var idx = pubKeys.indexOf(pubKey)
if (itemChecked) {
if (idx === -1) {
pubKeys.push(pubKey)
}
} else {
if (idx > -1) {
pubKeys.splice(idx, 1);
}
anchors.bottom: parent.bottom
showCheckbox: true
onUserClicked: function (isContact, pubKey, ensName) {
if (isContact) {
// those are just added to the list to by added by the bunch
return
}
inviteBtn.enabled = pubKeys.length > 0
sendInvites([pubKey])
}
}
}
@ -111,16 +99,11 @@ ModalPopup {
id: inviteBtn
anchors.bottom: parent.bottom
anchors.right: parent.right
enabled: contactFieldAndList.pubKeys.length > 0
//% "Invite"
text: qsTrId("invite-button")
onClicked : {
const error = chatsModel.communities.inviteUsersToCommunityById(popup.communityId, JSON.stringify(popup.pubKeys))
// TODO show error to user also should we show success?
if (error) {
console.error('Error inviting', error)
return
}
popup.close()
sendInvites(contactFieldAndList.pubKeys)
}
}
}

View File

@ -157,7 +157,7 @@ ModalPopup {
anchors.horizontalCenter: parent.horizontalCenter
}
PrivateChatPopupExistingContacts {
ExistingContacts {
id: existingContacts
anchors.topMargin: this.height > 0 ? Style.current.xlPadding : 0
anchors.top: chatKey.bottom
@ -168,7 +168,7 @@ ModalPopup {
expanded: !searchResults.loading && popup.pubKey === "" && !searchResults.showProfileNotFoundMessage
}
PrivateChatPopupSearchResults {
SearchResults {
id: searchResults
anchors.top: existingContacts.visible ? existingContacts.bottom : chatKey.bottom
anchors.topMargin: Style.current.padding

View File

@ -9,6 +9,5 @@ GroupChatPopup 1.0 GroupChatPopup.qml
StickerButton 1.0 StickerButton.qml
StickerMarket 1.0 StickerMarket.qml
StickersPopup 1.0 StickersPopup.qml
InviteFriendsPopup 1.0 InviteFriendsPopup.qml
StickerPackIconWithIndicator 1.0 StickerPackIconWithIndicator.qml
SuggestedChannels 1.0 SuggestedChannels.qml

View File

@ -4,7 +4,6 @@ import QtQuick.Layouts 1.13
import "../../../../imports"
import "../../../../shared"
import "../../../../shared/status"
import "../../Chat/components"
import "./Contacts"
Item {
@ -195,7 +194,7 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
}
PrivateChatPopupSearchResults {
SearchResults {
id: searchResults
anchors.top: addContactSearchInput.bottom
anchors.topMargin: Style.current.xlPadding

View File

@ -364,6 +364,7 @@ DISTFILES += \
shared/AccountSelector.qml \
shared/AddButton.qml \
shared/Address.qml \
shared/ContactsListAndSearch.qml \
shared/CropCornerRectangle.qml \
shared/DelegateModelGeneralized.qml \
shared/FormGroup.qml \

View File

@ -0,0 +1,183 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtGraphicalEffects 1.13
import "../imports"
import "../shared/status"
Item {
property string validationError: ""
property string successMessage: ""
property alias chatKey: chatKey
property alias existingContacts: existingContacts
property alias noContactsRect: noContactsRect
property string pubKey : ""
property string ensUsername : ""
property bool showCheckbox: false
signal userClicked(bool isContact, string pubKey, string ensName)
property var pubKeys: ([])
id: root
width: parent.width
property var resolveENS: Backpressure.debounce(root, 500, function (ensName) {
noContactsRect.visible = false
searchResults.loading = true
searchResults.showProfileNotFoundMessage = false
chatsModel.resolveENS(ensName)
});
function validate() {
if (!Utils.isChatKey(chatKey.text) && !Utils.isValidETHNamePrefix(chatKey.text)) {
//% "Enter a valid chat key or ENS username"
validationError = qsTrId("enter-a-valid-chat-key-or-ens-username");
pubKey = ""
ensUsername = "";
} else if (profileModel.profile.pubKey === chatKey.text) {
//% "Can't chat with yourself"
validationError = qsTrId("can-t-chat-with-yourself");
} else {
validationError = ""
}
return validationError === ""
}
Input {
id: chatKey
//% "Enter ENS username or chat key"
placeholderText: qsTrId("enter-contact-code")
Keys.onReleased: {
searchResults.pubKey = ""
if (!validate()) {
searchResults.showProfileNotFoundMessage = false
noContactsRect.visible = false
return;
}
chatKey.text = chatKey.text.trim();
if (Utils.isChatKey(chatKey.text)){
pubKey = chatKey.text;
if (!profileModel.contacts.isAdded(pubKey)) {
searchResults.username = utilsModel.generateAlias(pubKey)
searchResults.userAlias = Utils.compactAddress(pubKey, 4)
searchResults.pubKey = pubKey
}
noContactsRect.visible = false
return;
}
Qt.callLater(resolveENS, chatKey.text)
}
textField.anchors.rightMargin: clearBtn.width + Style.current.padding + 2
Connections {
target: chatsModel
onEnsWasResolved: {
if(chatKey.text == ""){
ensUsername.text = "";
pubKey = "";
} else if(resolvedPubKey == ""){
ensUsername.text = "";
searchResults.pubKey = pubKey = "";
searchResults.showProfileNotFoundMessage = true
} else {
if (profileModel.profile.pubKey === resolvedPubKey) {
//% "Can't chat with yourself"
validationError = qsTrId("can-t-chat-with-yourself");
} else {
searchResults.username = chatsModel.formatENSUsername(chatKey.text)
let userAlias = utilsModel.generateAlias(resolvedPubKey)
userAlias = userAlias.length > 20 ? userAlias.substring(0, 19) + "..." : userAlias
searchResults.userAlias = userAlias + " • " + Utils.compactAddress(resolvedPubKey, 4)
searchResults.pubKey = pubKey = resolvedPubKey;
}
searchResults.showProfileNotFoundMessage = false
}
searchResults.loading = false;
noContactsRect.visible = pubKey === "" && ensUsername.text === "" && !profileModel.contacts.list.hasAddedContacts() && !profileNotFoundMessage.visible
}
}
StatusIconButton {
id: clearBtn
icon.name: "close-icon"
type: "secondary"
visible: chatKey.text !== ""
icon.width: 14
icon.height: 14
width: 14
height: 14
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
anchors.verticalCenter: parent.verticalCenter
onClicked: {
chatKey.text = ""
chatKey.forceActiveFocus(Qt.MouseFocusReason)
searchResults.showProfileNotFoundMessage = false
searchResults.pubKey = pubKey = ""
noContactsRect.visible = false
searchResults.loading = false
}
}
}
StyledText {
id: message
text: validationError || successMessage
visible: validationError !== "" || successMessage !== ""
font.pixelSize: 13
color: !!validationError ? Style.current.danger : Style.current.success
anchors.top: chatKey.bottom
anchors.topMargin: Style.current.smallPadding
anchors.horizontalCenter: parent.horizontalCenter
}
ExistingContacts {
id: existingContacts
anchors.topMargin: this.height > 0 ? Style.current.xlPadding : 0
anchors.top: chatKey.bottom
showCheckbox: root.showCheckbox
filterText: chatKey.text
pubKeys: root.pubKeys
onContactClicked: function (contact) {
if (!contact || typeof contact === "string") {
return
}
const index = root.pubKeys.indexOf(contact.pubKey)
const pubKeysCopy = Object.assign([], root.pubKeys)
if (index === -1) {
pubKeysCopy.push(contact.pubKey)
} else {
pubKeysCopy.splice(index, 1)
}
root.pubKeys = pubKeysCopy
userClicked(true, contact.pubKey, profileModel.contacts.addedContacts.userName(contact.pubKey, contact.name))
}
expanded: !searchResults.loading && pubKey === "" && !searchResults.showProfileNotFoundMessage
}
SearchResults {
id: searchResults
anchors.top: existingContacts.visible ? existingContacts.bottom : chatKey.bottom
anchors.topMargin: Style.current.padding
hasExistingContacts: existingContacts.visible
loading: false
onResultClicked: {
if (!validate()) {
return
}
userClicked(false, pubKey, chatKey.text)
}
onAddToContactsButtonClicked: profileModel.contacts.addContact(pubKey)
}
NoFriendsRectangle {
id: noContactsRect
anchors.top: chatKey.bottom
anchors.topMargin: Style.current.xlPadding * 3
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
}

View File

@ -1,10 +1,11 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import "../../../../imports"
import "../../../../shared"
import "../../../../shared/status"
import "./"
import "../imports"
import "./status"
// TODO move Contact into shared to get rid of that import
import "../app/AppLayouts/Chat/components"
import "."
Item {
id: root
@ -12,6 +13,8 @@ Item {
anchors.right: parent.right
property string filterText: ""
property bool expanded: true
property bool showCheckbox: false
property var pubKeys: ([])
signal contactClicked(var contact)
function matchesAlias(name, filter) {
@ -33,7 +36,8 @@ Item {
id: contactListView
model: profileModel.contacts.list
delegate: Contact {
showCheckbox: false
showCheckbox: root.showCheckbox
isChecked: root.pubKeys.indexOf(model.pubKey) > -1
pubKey: model.pubKey
isContact: model.isContact
isUser: false
@ -50,7 +54,6 @@ Item {
}
}
}
}

View File

@ -1,7 +1,7 @@
import QtQuick 2.12
import QtQuick.Controls 2.3
import "../../../../imports"
import "../../../../shared"
import "../imports"
import "."
ModalPopup {
id: popup

View File

@ -1,7 +1,7 @@
import QtQuick 2.13
import "../../../../imports"
import "../../../../shared"
import "../../../../shared/status"
import "../imports"
import "."
import "./status"
Item {
id: noContactsRect

View File

@ -1,9 +1,10 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import "../../../../imports"
import "../../../../shared"
import "../../../../shared/status"
import "../imports"
import "./status"
// TODO move Contact into shared to get rid of that import
import "../app/AppLayouts/Chat/components"
import "./"