From e67d649c463ff1dd8d977ac63fb518ab2e9c37a5 Mon Sep 17 00:00:00 2001 From: MishkaRogachev Date: Mon, 25 Jul 2022 18:07:19 +0300 Subject: [PATCH] feat(desktop): New invite to community popup with message --- .../modules/main/chat_section/controller.nim | 4 +- .../main/chat_section/io_interface.nim | 2 +- src/app/modules/main/chat_section/module.nim | 4 +- src/app/modules/main/chat_section/view.nim | 4 +- .../communities/controller.nim | 4 +- .../communities/io_interface.nim | 2 +- .../profile_section/communities/module.nim | 4 +- .../main/profile_section/communities/view.nim | 4 +- src/app_service/service/community/service.nim | 4 +- src/backend/communities.nim | 5 +- ui/app/AppLayouts/Chat/controls/Contact.qml | 2 - ...ommunityProfilePopupInviteFriendsPanel.qml | 92 ++++++++++------ ...ommunityProfilePopupInviteMessagePanel.qml | 53 +++++++++ .../community/CommunityProfilePopup.qml | 11 +- .../InviteFriendsToCommunityPopup.qml | 104 ++++++++++-------- .../Chat/views/CommunitySettingsView.qml | 10 +- .../Profile/views/CommunitiesView.qml | 8 +- ui/app/mainui/AppMain.qml | 10 +- .../shared/controls/ContactsListAndSearch.qml | 15 ++- ui/imports/shared/controls/Input.qml | 2 - ui/imports/shared/views/ExistingContacts.qml | 16 ++- .../shared/views/NoFriendsRectangle.qml | 4 +- ui/imports/shared/views/PickedContacts.qml | 57 ++++++++++ ui/imports/shared/views/qmldir | 1 + vendor/status-go | 2 +- 25 files changed, 287 insertions(+), 137 deletions(-) create mode 100644 ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupInviteMessagePanel.qml create mode 100644 ui/imports/shared/views/PickedContacts.qml diff --git a/src/app/modules/main/chat_section/controller.nim b/src/app/modules/main/chat_section/controller.nim index 16733ec9b69..51391eb211b 100644 --- a/src/app/modules/main/chat_section/controller.nim +++ b/src/app/modules/main/chat_section/controller.nim @@ -454,8 +454,8 @@ method unmuteCategory*(self: Controller, categoryId: string) = proc setCommunityMuted*(self: Controller, muted: bool) = self.communityService.setCommunityMuted(self.sectionId, muted) -proc inviteUsersToCommunity*(self: Controller, pubKeys: string): string = - result = self.communityService.inviteUsersToCommunityById(self.sectionId, pubKeys) +proc inviteUsersToCommunity*(self: Controller, pubKeys: string, inviteMessage: string): string = + result = self.communityService.inviteUsersToCommunityById(self.sectionId, pubKeys, inviteMessage) proc reorderCommunityCategories*(self: Controller, categoryId: string, position: int) = self.communityService.reorderCommunityCategories(self.sectionId, categoryId, position) diff --git a/src/app/modules/main/chat_section/io_interface.nim b/src/app/modules/main/chat_section/io_interface.nim index b6ece6c4786..89a649cd93d 100644 --- a/src/app/modules/main/chat_section/io_interface.nim +++ b/src/app/modules/main/chat_section/io_interface.nim @@ -284,7 +284,7 @@ method exportCommunity*(self: AccessInterface): string {.base.} = method setCommunityMuted*(self: AccessInterface, muted: bool) {.base.} = raise newException(ValueError, "No implementation available") -method inviteUsersToCommunity*(self: AccessInterface, pubKeysJSON: string): string {.base.} = +method inviteUsersToCommunity*(self: AccessInterface, pubKeysJSON: string, inviteMessage: string): string {.base.} = raise newException(ValueError, "No implementation available") method createCommunityCategory*(self: AccessInterface, name: string, channels: seq[string]) {.base.} = diff --git a/src/app/modules/main/chat_section/module.nim b/src/app/modules/main/chat_section/module.nim index a6495bdc70d..7fcc76d136d 100644 --- a/src/app/modules/main/chat_section/module.nim +++ b/src/app/modules/main/chat_section/module.nim @@ -792,8 +792,8 @@ method exportCommunity*(self: Module): string = method setCommunityMuted*(self: Module, muted: bool) = self.controller.setCommunityMuted(muted) -method inviteUsersToCommunity*(self: Module, pubKeysJSON: string): string = - result = self.controller.inviteUsersToCommunity(pubKeysJSON) +method inviteUsersToCommunity*(self: Module, pubKeysJSON: string, inviteMessage: string): string = + result = self.controller.inviteUsersToCommunity(pubKeysJSON, inviteMessage) method prepareEditCategoryModel*(self: Module, categoryId: string) = self.view.editCategoryChannelsModel().clearItems() diff --git a/src/app/modules/main/chat_section/view.nim b/src/app/modules/main/chat_section/view.nim index d302b80e299..e7d1408ec0a 100644 --- a/src/app/modules/main/chat_section/view.nim +++ b/src/app/modules/main/chat_section/view.nim @@ -274,8 +274,8 @@ QtObject: proc setCommunityMuted*(self: View, muted: bool) {.slot.} = self.delegate.setCommunityMuted(muted) - proc inviteUsersToCommunity*(self: View, pubKeysJSON: string): string {.slot.} = - result = self.delegate.inviteUsersToCommunity(pubKeysJSON) + proc inviteUsersToCommunity*(self: View, pubKeysJSON: string, inviteMessage: string): string {.slot.} = + result = self.delegate.inviteUsersToCommunity(pubKeysJSON, inviteMessage) proc createCommunityCategory*(self: View, name: string, channels: string) {.slot.} = let channelsSeq = map(parseJson(channels).getElems(), proc(x:JsonNode):string = x.getStr()) diff --git a/src/app/modules/main/profile_section/communities/controller.nim b/src/app/modules/main/profile_section/communities/controller.nim index 56d07b6697a..8c196d6e294 100644 --- a/src/app/modules/main/profile_section/communities/controller.nim +++ b/src/app/modules/main/profile_section/communities/controller.nim @@ -17,8 +17,8 @@ proc newController*(delegate: io_interface.AccessInterface, proc delete*(self: Controller) = discard -proc inviteUsersToCommunity*(self: Controller, communityID: string, pubKeys: string): string = - result = self.communityService.inviteUsersToCommunityById(communityID, pubKeys) +proc inviteUsersToCommunity*(self: Controller, communityID: string, pubKeys: string, inviteMessage: string): string = + result = self.communityService.inviteUsersToCommunityById(communityID, pubKeys, inviteMessage) proc leaveCommunity*(self: Controller, communityID: string) = self.communityService.leaveCommunity(communityID) diff --git a/src/app/modules/main/profile_section/communities/io_interface.nim b/src/app/modules/main/profile_section/communities/io_interface.nim index 05f8b51c804..fff775653bd 100644 --- a/src/app/modules/main/profile_section/communities/io_interface.nim +++ b/src/app/modules/main/profile_section/communities/io_interface.nim @@ -22,7 +22,7 @@ method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} = method viewDidLoad*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") -method inviteUsersToCommunity*(self: AccessInterface, communityID: string, pubKeysJSON: string): string {.base.} = +method inviteUsersToCommunity*(self: AccessInterface, communityID: string, pubKeysJSON: string, inviteMessage: string): string {.base.} = raise newException(ValueError, "No implementation available") method leaveCommunity*(self: AccessInterface, communityID: string) {.base.} = diff --git a/src/app/modules/main/profile_section/communities/module.nim b/src/app/modules/main/profile_section/communities/module.nim index ff8c444153a..50bda1e40f8 100644 --- a/src/app/modules/main/profile_section/communities/module.nim +++ b/src/app/modules/main/profile_section/communities/module.nim @@ -42,8 +42,8 @@ method viewDidLoad*(self: Module) = method getModuleAsVariant*(self: Module): QVariant = return self.viewVariant -method inviteUsersToCommunity*(self: Module, communityID: string, pubKeysJSON: string): string = - result = self.controller.inviteUsersToCommunity(communityID, pubKeysJSON) +method inviteUsersToCommunity*(self: Module, communityID: string, pubKeysJSON: string, inviteMessage: string): string = + result = self.controller.inviteUsersToCommunity(communityID, pubKeysJSON, inviteMessage) method leaveCommunity*(self: Module, communityID: string) = self.controller.leaveCommunity(communityID) diff --git a/src/app/modules/main/profile_section/communities/view.nim b/src/app/modules/main/profile_section/communities/view.nim index 3afc65fe111..6b79dd3eb80 100644 --- a/src/app/modules/main/profile_section/communities/view.nim +++ b/src/app/modules/main/profile_section/communities/view.nim @@ -19,8 +19,8 @@ QtObject: proc load*(self: View) = self.delegate.viewDidLoad() - method inviteUsersToCommunity*(self: View, communityID: string, pubKeysJSON: string): string {.slot.} = - result = self.delegate.inviteUsersToCommunity(communityID, pubKeysJSON) + method inviteUsersToCommunity*(self: View, communityID: string, pubKeysJSON: string, inviteMessage: string): string {.slot.} = + result = self.delegate.inviteUsersToCommunity(communityID, pubKeysJSON, inviteMessage) method leaveCommunity*(self: View, communityID: string) {.slot.} = self.delegate.leaveCommunity(communityID) diff --git a/src/app_service/service/community/service.nim b/src/app_service/service/community/service.nim index d7bc808c6bd..0a5fca608c0 100644 --- a/src/app_service/service/community/service.nim +++ b/src/app_service/service/community/service.nim @@ -1069,7 +1069,7 @@ QtObject: except Exception as e: error "Error declining request to join community", msg = e.msg - proc inviteUsersToCommunityById*(self: Service, communityId: string, pubKeysJson: string): string = + proc inviteUsersToCommunityById*(self: Service, communityId: string, pubKeysJson: string, inviteMessage: string): string = try: let pubKeysParsed = pubKeysJson.parseJson var pubKeys: seq[string] = @[] @@ -1077,7 +1077,7 @@ QtObject: pubKeys.add(pubKey.getStr) # We no longer send invites, but merely share the community so # users can request access (with automatic acception) - let response = status_go.shareCommunityToUsers(communityId, pubKeys) + let response = status_go.shareCommunityToUsers(communityId, pubKeys, inviteMessage) discard self.chatService.processMessageUpdateAfterSend(response) except Exception as e: error "Error sharing community", msg = e.msg diff --git a/src/backend/communities.nim b/src/backend/communities.nim index 5dd0ebe3f62..d6b3dca3d9c 100644 --- a/src/backend/communities.nim +++ b/src/backend/communities.nim @@ -274,10 +274,11 @@ proc inviteUsersToCommunity*(communityId: string, pubKeys: seq[string]): RpcResp "users": pubKeys }]) -proc shareCommunityToUsers*(communityId: string, pubKeys: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} = +proc shareCommunityToUsers*(communityId: string, pubKeys: seq[string], inviteMessage: string): RpcResponse[JsonNode] {.raises: [Exception].} = return callPrivateRPC("shareCommunity".prefix, %*[{ "communityId": communityId, - "users": pubKeys + "users": pubKeys, + "inviteMessage": inviteMessage }]) proc getCommunitiesSettings*(): RpcResponse[JsonNode] {.raises: [Exception].} = diff --git a/ui/app/AppLayouts/Chat/controls/Contact.qml b/ui/app/AppLayouts/Chat/controls/Contact.qml index 7d4bfcef415..cee00d8e6cc 100644 --- a/ui/app/AppLayouts/Chat/controls/Contact.qml +++ b/ui/app/AppLayouts/Chat/controls/Contact.qml @@ -33,8 +33,6 @@ Rectangle { visible: isVisible && (isContact || isUser) height: visible ? 64 : 0 - anchors.right: parent.right - anchors.left: parent.left border.width: 0 radius: Style.current.radius color: isHovered ? Style.current.backgroundHover : Style.current.transparent diff --git a/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupInviteFriendsPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupInviteFriendsPanel.qml index d6e8df0a7dc..cc84cabc01f 100644 --- a/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupInviteFriendsPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupInviteFriendsPanel.qml @@ -1,18 +1,18 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import QtQuick.Dialogs 1.3 -import QtQuick.Layouts 1.13 -import QtGraphicalEffects 1.13 +import QtQuick 2.14 +import QtQuick.Layouts 1.4 + +import StatusQ.Components 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Popups 0.1 import utils 1.0 -import shared.controls 1.0 import shared 1.0 +import shared.controls 1.0 import shared.panels 1.0 +import shared.views 1.0 import shared.status 1.0 -import StatusQ.Components 0.1 -import StatusQ.Popups 0.1 -Column { +ColumnLayout { id: root property string headerTitle: "" @@ -20,43 +20,67 @@ Column { property var rootStore property var contactsStore property var community - property alias contactListSearch: contactFieldAndList - StatusDescriptionListItem { - title: qsTr("Share community") - subTitle: `${Constants.communityLinkPrefix}${root.community && root.community.id.substring(0, 4)}...${root.community && root.community.id.substring(root.community.id.length -2)}` - tooltip.text: qsTr("Copied!") - icon.name: "copy" - iconButton.onClicked: { - let link = `${Constants.communityLinkPrefix}${root.community.id}` - root.rootStore.copyToClipboard(link) - tooltip.visible = !tooltip.visible - } - width: parent.width - } + property var pubKeys: ([]) - StatusModalDivider { - bottomPadding: Style.current.padding - } + spacing: Style.current.padding StyledText { id: headline text: qsTr("Contacts") font.pixelSize: Style.current.primaryTextFontSize color: Style.current.secondaryText - anchors.left: parent.left - anchors.leftMargin: Style.current.padding } - ContactsListAndSearch { - id: contactFieldAndList - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width - 32 + StatusInput { + id: filterInput + placeholderText: qsTr("Search contacts") + input.icon.name: "search" + input.clearable: true + Layout.fillWidth: true + } + + ExistingContacts { + id: existingContacts + contactsStore: root.contactsStore community: root.community - showCheckbox: true hideCommunityMembers: true - showSearch: false - rootStore: root.rootStore + showCheckbox: true + filterText: filterInput.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 + } + Layout.rightMargin: -Style.current.padding + Layout.fillWidth: true + Layout.fillHeight: true + } + + StatusModalDivider { + bottomPadding: Style.current.padding + Layout.fillWidth: true + } + + StatusDescriptionListItem { + title: qsTr("Share community") + subTitle: `${Constants.communityLinkPrefix}${root.community && root.community.id.substring(0, 4)}...${root.community && root.community.id.substring(root.community.id.length -2)}` + tooltip.text: qsTr("Copied!") + icon.name: "copy" + iconButton.onClicked: { + let link = `${Constants.communityLinkPrefix}${root.community.id}` + root.rootStore.copyToClipboard(link) + tooltip.visible = !tooltip.visible + } } } diff --git a/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupInviteMessagePanel.qml b/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupInviteMessagePanel.qml new file mode 100644 index 00000000000..20b945751e5 --- /dev/null +++ b/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupInviteMessagePanel.qml @@ -0,0 +1,53 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.4 + +import StatusQ.Core 0.1 +import StatusQ.Components 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Popups 0.1 + +import utils 1.0 +import shared 1.0 +import shared.views 1.0 +import shared.status 1.0 + +ColumnLayout { + id: root + + property var pubKeys: ([]) + + property var rootStore + property var contactsStore + + property alias inviteMessage: messageInput.text + + spacing: Style.current.padding + + QtObject { + id: d + + readonly property int maxMsgLength: 140 + readonly property int msgHeight: 108 + } + + StatusInput { + id: messageInput + label: qsTr("Invitation Message") + charLimit: d.maxMsgLength + placeholderText: qsTr("The message a contact will get with community invitation") + input.multiline: true + input.implicitHeight: d.msgHeight + input.verticalAlignment: TextEdit.AlignTop + Layout.minimumHeight: 150 // TODO: implicitHeight is not calculated well from input.implicitHeight + Layout.fillWidth: true + } + + PickedContacts { + id: existingContacts + enabled: false + contactsStore: root.contactsStore + pubKeys: root.pubKeys + Layout.fillWidth: true + Layout.fillHeight: true + } +} diff --git a/ui/app/AppLayouts/Chat/popups/community/CommunityProfilePopup.qml b/ui/app/AppLayouts/Chat/popups/community/CommunityProfilePopup.qml index 19c60359d05..22440dc3aa0 100644 --- a/ui/app/AppLayouts/Chat/popups/community/CommunityProfilePopup.qml +++ b/ui/app/AppLayouts/Chat/popups/community/CommunityProfilePopup.qml @@ -90,13 +90,6 @@ StatusModal { community: root.community contactsStore: root.contactsStore rootStore: root.store - - contactListSearch.chatKey.text: "" - contactListSearch.pubKey: "" - contactListSearch.pubKeys: [] - contactListSearch.ensUsername: "" - contactListSearch.existingContacts.visible: root.hasAddedContacts - contactListSearch.noContactsRect.visible: !contactListSearch.existingContacts.visible } } } @@ -117,9 +110,9 @@ StatusModal { text: qsTr("Invite") visible: root.contentItem.depth > 2 height: !visible ? 0 : implicitHeight - enabled: root.contentItem.currentItem.contactListSearch !== undefined && root.contentItem.currentItem.contactListSearch.pubKeys.length > 0 + enabled: root.contentItem.currentItem !== undefined && root.contentItem.currentItem.pubKeys.length > 0 onClicked: { - root.contentItem.currentItem.sendInvites(root.contentItem.currentItem.contactListSearch.pubKeys) + root.contentItem.currentItem.sendInvites(root.contentItem.currentItem.pubKeys, "") // NOTE: empty message root.contentItem.pop() } } diff --git a/ui/app/AppLayouts/Chat/popups/community/InviteFriendsToCommunityPopup.qml b/ui/app/AppLayouts/Chat/popups/community/InviteFriendsToCommunityPopup.qml index 7e58745a401..dc95a53d138 100644 --- a/ui/app/AppLayouts/Chat/popups/community/InviteFriendsToCommunityPopup.qml +++ b/ui/app/AppLayouts/Chat/popups/community/InviteFriendsToCommunityPopup.qml @@ -1,76 +1,90 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.3 -import QtQuick.Layouts 1.3 -import QtQml.Models 2.3 +import QtQuick 2.14 +import QtQuick.Layouts 1.4 import StatusQ.Controls 0.1 import StatusQ.Components 0.1 import StatusQ.Popups 0.1 import utils 1.0 +import shared.panels 1.0 import "../../views" import "../../panels/communities" -StatusModal { - id: popup +StatusStackModal { + id: root property var rootStore property var contactsStore property var community property var communitySectionModule - property bool hasAddedContacts - signal sendInvites(var pubKeys) + property var pubKeys: ([]) + property string inviteMessage: "" + property string validationError: "" + property string successMessage: "" - onOpened: { - contentItem.community = community; + signal sendInvites(var pubKeys, string inviteMessage) - contentItem.contactListSearch.chatKey.text = ""; - contentItem.contactListSearch.pubKey = ""; - contentItem.contactListSearch.pubKeys = []; - contentItem.contactListSearch.ensUsername = ""; - contentItem.contactListSearch.chatKey.forceActiveFocus(Qt.MouseFocusReason); - contentItem.contactListSearch.existingContacts.visible = hasAddedContacts; - contentItem.contactListSearch.noContactsRect.visible = !contentItem.contactListSearch.existingContacts.visible; + function processInviteResult(error) { + if (error) { + console.error('Error inviting', error); + root.validationError = error; + } else { + root.validationError = ""; + root.successMessage = qsTr("Invite successfully sent"); + } } - margins: 32 - height: 550 + onOpened: { + root.pubKeys = []; + root.successMessage = ""; + root.validationError = ""; + } - header.title: qsTr("Invite friends") + stackTitle: qsTr("Invite Contacts to %1").arg(community.name) + width: 640 + height: 700 - function processInviteResult(error) { - if (error) { - console.error('Error inviting', error) - contactFieldAndList.validationError = error - return + nextButton: StatusButton { + text: qsTr("Next") + enabled: root.pubKeys.length + onClicked: { + root.currentIndex++; } - popup.contentItem.contactListSearch.successMessage = qsTr("Invite successfully sent") } - contentItem: CommunityProfilePopupInviteFriendsPanel { - id: contactFieldAndList - rootStore: popup.rootStore - contactsStore: popup.contactsStore - community: popup.community + finishButton: StatusButton { + enabled: root.pubKeys.length > 0 + text: qsTr("Send Invites") + onClicked: { + root.sendInvites(root.pubKeys, root.inviteMessage); + root.close(); + } } - leftButtons: [ - StatusBackButton { - onClicked: { - popup.close() - } - } - ] + subHeaderItem: StyledText { + text: root.validationError || root.successMessage + visible: root.validationError !== "" || root.successMessage !== "" + font.pixelSize: 13 + color: !!root.validationError ? Style.current.danger : Style.current.success + Layout.alignment: Qt.AlignHCenter + Layout.preferredHeight: visible ? contentHeight : 0 + } - rightButtons: [ - StatusButton { - enabled: popup.contentItem.contactListSearch.pubKeys.length > 0 - text: qsTr("Invite") - onClicked : { - popup.sendInvites(popup.contentItem.contactListSearch.pubKeys) - } + stackItems: [ + CommunityProfilePopupInviteFriendsPanel { + width: parent.width + rootStore: root.rootStore + contactsStore: root.contactsStore + community: root.community + onPubKeysChanged: root.pubKeys = pubKeys + }, + CommunityProfilePopupInviteMessagePanel { + width: parent.width + contactsStore: root.contactsStore + pubKeys: root.pubKeys + onInviteMessageChanged: root.inviteMessage = inviteMessage } ] } diff --git a/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml b/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml index 65c377a4c69..f954dc3ca4f 100644 --- a/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml +++ b/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml @@ -229,13 +229,13 @@ StatusAppTwoPanelLayout { anchors.centerIn: parent rootStore: root.rootStore contactsStore: root.rootStore.contactsStore - onClosed: { - destroy() + onClosed: () => { + destroy(); } - onSendInvites: { - const error = root.chatCommunitySectionModule.inviteUsersToCommunity(JSON.stringify(pubKeys)) - processInviteResult(error) + onSendInvites: (pubKeys, inviteMessage) => { + const error = root.communitySectionModule.inviteUsersToCommunity(JSON.stringify(pubKeys), inviteMessage); + processInviteResult(error); } } } diff --git a/ui/app/AppLayouts/Profile/views/CommunitiesView.qml b/ui/app/AppLayouts/Profile/views/CommunitiesView.qml index 435fa63274d..8b42cdbd793 100644 --- a/ui/app/AppLayouts/Profile/views/CommunitiesView.qml +++ b/ui/app/AppLayouts/Profile/views/CommunitiesView.qml @@ -92,14 +92,14 @@ SettingsContentBase { anchors.centerIn: parent rootStore: root.rootStore contactsStore: root.contactStore - onClosed: { - destroy() + onClosed: () => { + destroy(); } onSendInvites: { const error = root.profileSectionStore.communitiesProfileModule.inviteUsersToCommunity( - community.id, JSON.stringify(pubKeys)) - processInviteResult(error) + community.id, JSON.stringify(pubKeys), inviteMessage); + processInviteResult(error); } } diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index 54e4e946510..85386d3b017 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -719,13 +719,13 @@ Item { anchors.centerIn: parent rootStore: appMain.rootStore contactsStore: appMain.rootStore.contactStore - onClosed: { - destroy() + onClosed: () => { + destroy(); } - onSendInvites: { - const error = communitySectionModule.inviteUsersToCommunity(JSON.stringify(pubKeys)) - processInviteResult(error) + onSendInvites: (pubKeys, inviteMessage) => { + const error = communitySectionModule.inviteUsersToCommunity(JSON.stringify(pubKeys), inviteMessage); + processInviteResult(error); } } } diff --git a/ui/imports/shared/controls/ContactsListAndSearch.qml b/ui/imports/shared/controls/ContactsListAndSearch.qml index 67e56c74ee7..2bc4a90baef 100644 --- a/ui/imports/shared/controls/ContactsListAndSearch.qml +++ b/ui/imports/shared/controls/ContactsListAndSearch.qml @@ -2,11 +2,12 @@ import QtQuick 2.14 import QtQuick.Layouts 1.4 import QtGraphicalEffects 1.14 -import utils 1.0 -import shared.stores 1.0 import StatusQ.Core.Theme 0.1 import StatusQ.Controls 0.1 +import utils 1.0 +import shared.stores 1.0 + import "../" import "../views" import "../panels" @@ -65,6 +66,7 @@ Item { ColumnLayout { id: column anchors.fill: parent + anchors.rightMargin: Style.current.bigPadding spacing: Style.current.smallPadding Input { @@ -225,13 +227,18 @@ Item { onAddToContactsButtonClicked: { root.contactsStore.addContact(pubKey) } + Layout.fillWidth: true + Layout.rightMargin: Style.current.padding + } + + Item { + Layout.fillHeight: true } - Layout.fillWidth: true } NoFriendsRectangle { id: noContactsRect - visible: showContactList + visible: showContactList && existingContacts.count === 0 anchors.centerIn: parent rootStore: root.rootStore } diff --git a/ui/imports/shared/controls/Input.qml b/ui/imports/shared/controls/Input.qml index 948aa9f17cb..edaacd8aa3f 100644 --- a/ui/imports/shared/controls/Input.qml +++ b/ui/imports/shared/controls/Input.qml @@ -50,8 +50,6 @@ Item { signal textEdited(string inputValue) signal keyPressed(var event) - anchors.right: parent.right - anchors.left: parent.left implicitHeight: inputRectangle.height + (hasLabel ? inputLabel.height + labelMargin : 0) + (!keepHeight &&!!validationError ? (validationErrorText.height + validationErrorTopMargin) : 0) diff --git a/ui/imports/shared/views/ExistingContacts.qml b/ui/imports/shared/views/ExistingContacts.qml index caa54cc6d71..63b7d1a3119 100644 --- a/ui/imports/shared/views/ExistingContacts.qml +++ b/ui/imports/shared/views/ExistingContacts.qml @@ -1,6 +1,6 @@ -import QtQuick 2.13 -import QtQuick.Controls 2.13 -import QtQuick.Layouts 1.13 +import QtQuick 2.14 +import QtQuick.Controls 2.14 +import QtQuick.Layouts 1.14 import StatusQ.Core 0.1 @@ -22,6 +22,8 @@ Item { property bool hideCommunityMembers: false property var pubKeys: ([]) + readonly property alias count: contactListView.count + signal contactClicked(var contact) function matchesAlias(name, filter) { @@ -29,12 +31,13 @@ Item { return parts.some(p => p.startsWith(filter)) } - implicitWidth: contactListView.implicitWidth + implicitWidth: contactListView.implicitWidth + contactListView.margins implicitHeight: visible ? Math.min(contactListView.contentHeight, (expanded ? 320 : 192)) : 0 StatusListView { id: contactListView anchors.fill: parent + rightMargin: 0 spacing: 0 model: root.contactsStore.myContactsModel @@ -48,6 +51,9 @@ Item { name: model.displayName image: model.icon isVisible: { + if (isChecked) + return true; + return model.isContact && !model.isBlocked && (root.filterText === "" || root.matchesAlias(model.alias.toLowerCase(), root.filterText.toLowerCase()) || model.displayName.toLowerCase().includes(root.filterText.toLowerCase()) || @@ -63,5 +69,3 @@ Item { } } } - - diff --git a/ui/imports/shared/views/NoFriendsRectangle.qml b/ui/imports/shared/views/NoFriendsRectangle.qml index 2f578dde812..b7c91723b72 100644 --- a/ui/imports/shared/views/NoFriendsRectangle.qml +++ b/ui/imports/shared/views/NoFriendsRectangle.qml @@ -10,8 +10,8 @@ import "../popups" Item { id: noContactsRect - width: 260 - height: visible ? 120 : 0 + implicitWidth: 260 + implicitHeight: visible ? 120 : 0 property string text: qsTr("You don’t have any contacts yet. Invite your friends to start chatting.") property alias textColor: noContacts.color diff --git a/ui/imports/shared/views/PickedContacts.qml b/ui/imports/shared/views/PickedContacts.qml new file mode 100644 index 00000000000..802ce53e3b0 --- /dev/null +++ b/ui/imports/shared/views/PickedContacts.qml @@ -0,0 +1,57 @@ +import QtQuick 2.14 +import QtQuick.Controls 2.14 +import QtQuick.Layouts 1.14 + +import StatusQ.Core 0.1 + +import utils 1.0 +import shared.status 1.0 +import shared.stores 1.0 +// TODO move Contact into shared to get rid of that import +import AppLayouts.Chat.controls 1.0 + +import SortFilterProxyModel 0.2 + +Item { + id: root + + property var contactsStore + + property var pubKeys: ([]) + + readonly property alias count: contactGridView.count + + signal contactClicked(var contact) + + function matchesAlias(name, filter) { + let parts = name.split(" ") + return parts.some(p => p.startsWith(filter)) + } + + implicitWidth: contactGridView.implicitWidth + contactGridView.margins + implicitHeight: visible ? contactGridView.contentHeight : 0 + + StatusGridView { + id: contactGridView + anchors.fill: parent + rightMargin: 0 + cellWidth: parent.width / 2 + + model: SortFilterProxyModel { + sourceModel: root.contactsStore.myContactsModel + filters: [ + ExpressionFilter { expression: root.pubKeys.indexOf(model.pubKey) > -1 } + ] + } + delegate: Contact { + width: contactGridView.cellWidth + showCheckbox: false + pubKey: model.pubKey + isContact: model.isContact + isUser: false + name: model.displayName + image: model.icon + } + } +} + \ No newline at end of file diff --git a/ui/imports/shared/views/qmldir b/ui/imports/shared/views/qmldir index 44b123605df..b3711e0c9c5 100644 --- a/ui/imports/shared/views/qmldir +++ b/ui/imports/shared/views/qmldir @@ -1,5 +1,6 @@ EnsResolver 1.0 EnsResolver.qml ExistingContacts 1.0 ExistingContacts.qml +PickedContacts 1.0 PickedContacts.qml NoFriendsRectangle 1.0 NoFriendsRectangle.qml SearchResults 1.0 SearchResults.qml TransactionPreview 1.0 TransactionPreview.qml diff --git a/vendor/status-go b/vendor/status-go index 2edcf0e3606..081974da1e4 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit 2edcf0e3606dd54b469053080cbe951169cbc813 +Subproject commit 081974da1e4ee03f912fef85a37fc1d13580ad8c