diff --git a/ui/app/AppLayouts/Chat/controls/community/CommunityBannerPicker.qml b/ui/app/AppLayouts/Chat/controls/community/CommunityBannerPicker.qml new file mode 100644 index 0000000000..279d1b99be --- /dev/null +++ b/ui/app/AppLayouts/Chat/controls/community/CommunityBannerPicker.qml @@ -0,0 +1,68 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 +import QtQuick.Controls 2.14 +import QtQuick.Dialogs 1.3 +import QtGraphicalEffects 1.13 + +import utils 1.0 +import shared.panels 1.0 +import shared.popups 1.0 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Layout 0.1 +import StatusQ.Components 0.1 +import StatusQ.Popups 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Controls.Validators 0.1 + +Item { + id: root + + property alias source: editor.source + property alias cropRect: editor.cropRect + property string imageData + + implicitHeight: layout.implicitHeight + implicitWidth: layout.implicitWidth + + ColumnLayout { + id: layout + + anchors.fill: parent + + spacing: 8 + + StatusBaseText { + text: qsTr("Community banner") + + font.pixelSize: 15 + color: Theme.palette.directColor1 + } + + EditCroppedImagePanel { + id: editor + + Layout.preferredWidth: 475 + Layout.preferredHeight: Layout.preferredWidth / aspectRatio + Layout.alignment: Qt.AlignHCenter + + imageFileDialogTitle: qsTr("Choose an image for banner") + title: qsTr("Community banner") + acceptButtonText: qsTr("Make this my Community banner") + + roundedImage: false + aspectRatio: 375/184 + + dataImage: root.imageData + + NoImageUploadedPanel { + anchors.centerIn: parent + + visible: !editor.userSelectedImage && !root.imageData + showARHint: true + } + } + } +} + diff --git a/ui/app/AppLayouts/Chat/controls/community/CommunityColorPicker.qml b/ui/app/AppLayouts/Chat/controls/community/CommunityColorPicker.qml new file mode 100644 index 0000000000..1a9b8aa9d5 --- /dev/null +++ b/ui/app/AppLayouts/Chat/controls/community/CommunityColorPicker.qml @@ -0,0 +1,55 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 +import QtQuick.Controls 2.14 + +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 + +ColumnLayout { + id: root + + property color color: Theme.palette.primaryColor1 + + spacing: 8 + + StatusBaseText { + text: qsTr("Community colour") + font.pixelSize: 15 + color: Theme.palette.directColor1 + } + + StatusPickerButton { + Layout.fillWidth: true + + property string validationError: "" + + bgColor: root.color + contentColor: Theme.palette.indirectColor1 + text: root.color.toString() + + onClicked: { + colorDialog.color = root.color + colorDialog.open() + } + onTextChanged: { + validationError = Utils.validateAndReturnError( + text, + Utils.Validate.NoEmpty | Utils.Validate.TextHexColor) + } + + StatusColorDialog { + id: colorDialog + anchors.centerIn: parent + header.title: qsTr("Community Colour") + previewText: qsTr("White text should be legable on top of this colour") + acceptText: qsTr("Select Community Colour") + onAccepted: { + root.color = color + } + } + } +} diff --git a/ui/app/AppLayouts/Chat/controls/community/CommunityDescriptionInput.qml b/ui/app/AppLayouts/Chat/controls/community/CommunityDescriptionInput.qml new file mode 100644 index 0000000000..5fd3dc0dc5 --- /dev/null +++ b/ui/app/AppLayouts/Chat/controls/community/CommunityDescriptionInput.qml @@ -0,0 +1,30 @@ +import QtQuick 2.14 + +import utils 1.0 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Controls.Validators 0.1 + +StatusInput { + id: root + + leftPadding: 0 + rightPadding: 0 + label: qsTr("Description") + charLimit: 140 + + input.placeholderText: qsTr("What your community is about") + input.multiline: true + input.implicitHeight: 88 + + validators: [ + StatusMinLengthValidator { + minLength: 1 + errorMessage: Utils.getErrorMessage(root.errors, + qsTr("community description")) + } + ] + validationMode: StatusInput.ValidationMode.Always +} diff --git a/ui/app/AppLayouts/Chat/controls/community/CommunityIntroMessageInput.qml b/ui/app/AppLayouts/Chat/controls/community/CommunityIntroMessageInput.qml new file mode 100644 index 0000000000..f9edc2f03e --- /dev/null +++ b/ui/app/AppLayouts/Chat/controls/community/CommunityIntroMessageInput.qml @@ -0,0 +1,34 @@ +import QtQuick 2.14 + +import utils 1.0 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Controls.Validators 0.1 + +StatusInput { + id: root + + leftPadding: 0 + rightPadding: 0 + label: qsTr("Community introduction and rules") + charLimit: 1400 + + input.multiline: true + input.implicitHeight: 400 + + input.placeholder.text: qsTr("What new members will read before joining (eg. community rules, welcome message, etc.). Members will need to tick a check box agreeing to these rules before they are allowed to join your community.") + input.placeholder.wrapMode: Text.WordWrap + + input.verticalAlignment: TextEdit.AlignTop + + validators: [ + StatusMinLengthValidator { + minLength: 1 + errorMessage: Utils.getErrorMessage(root.errors, + qsTr("community intro message")) + } + ] + validationMode: StatusInput.ValidationMode.Always +} diff --git a/ui/app/AppLayouts/Chat/controls/community/CommunityLogoPicker.qml b/ui/app/AppLayouts/Chat/controls/community/CommunityLogoPicker.qml new file mode 100644 index 0000000000..0b82a6cbb1 --- /dev/null +++ b/ui/app/AppLayouts/Chat/controls/community/CommunityLogoPicker.qml @@ -0,0 +1,63 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 +import QtQuick.Controls 2.14 +import QtQuick.Dialogs 1.3 +import QtGraphicalEffects 1.13 + +import utils 1.0 +import shared.panels 1.0 +import shared.popups 1.0 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Layout 0.1 +import StatusQ.Components 0.1 +import StatusQ.Popups 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Controls.Validators 0.1 + +Item { + id: root + + property alias source: editor.source + property alias cropRect: editor.cropRect + property string imageData + + implicitWidth: layout.implicitWidth + implicitHeight: layout.implicitHeight + + ColumnLayout { + id: layout + + anchors.fill: parent + + spacing: 8 + + StatusBaseText { + text: qsTr("Community logo") + font.pixelSize: 15 + color: Theme.palette.directColor1 + } + + EditCroppedImagePanel { + id: editor + + Layout.preferredWidth: 128 + Layout.preferredHeight: Layout.preferredWidth / aspectRatio + Layout.alignment: Qt.AlignHCenter + + imageFileDialogTitle: qsTr("Choose an image as logo") + title: qsTr("Community logo") + acceptButtonText: qsTr("Make this my Community logo") + + dataImage: root.imageData + + NoImageUploadedPanel { + anchors.centerIn: parent + + visible: !editor.userSelectedImage && !root.imageData + } + } + } +} + diff --git a/ui/app/AppLayouts/Chat/controls/community/CommunityNameInput.qml b/ui/app/AppLayouts/Chat/controls/community/CommunityNameInput.qml new file mode 100644 index 0000000000..ca92eeb79b --- /dev/null +++ b/ui/app/AppLayouts/Chat/controls/community/CommunityNameInput.qml @@ -0,0 +1,26 @@ +import QtQuick 2.14 + +import utils 1.0 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Controls.Validators 0.1 + +StatusInput { + id: root + + leftPadding: 0 + rightPadding: 0 + label: qsTr("Community name") + charLimit: 30 + input.placeholderText: qsTr("A catchy name") + validators: [ + StatusMinLengthValidator { + minLength: 1 + errorMessage: Utils.getErrorMessage(root.errors, + qsTr("community name")) + } + ] + validationMode: StatusInput.ValidationMode.Always +} diff --git a/ui/app/AppLayouts/Chat/controls/community/CommunityOptions.qml b/ui/app/AppLayouts/Chat/controls/community/CommunityOptions.qml new file mode 100644 index 0000000000..8a9efcb97e --- /dev/null +++ b/ui/app/AppLayouts/Chat/controls/community/CommunityOptions.qml @@ -0,0 +1,77 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Components 0.1 +import StatusQ.Controls 0.1 + +ColumnLayout { + id: root + + property alias archiveSupportOptionVisible: archiveSupport.visible + + property alias archiveSupportEnabled: archiveSupportToggle.checked + property alias requestToJoinEnabled: requestToJoinToggle.checked + property alias pinMessagesEnabled: pinMessagesToggle.checked + + spacing: 0 + + QtObject { + id: d + readonly property real optionHeight: 64 + } + + RowLayout { + id: archiveSupport + + Layout.fillWidth: true + + StatusBaseText { + text: qsTr("Community history service") + } + + Item { + Layout.fillWidth: true + implicitHeight: d.optionHeight + } + + StatusCheckBox { + id: archiveSupportToggle + } + } + + RowLayout { + Layout.fillWidth: true + + StatusBaseText { + text: qsTr("Request to join required") + } + + Item { + Layout.fillWidth: true + implicitHeight: d.optionHeight + } + + StatusCheckBox { + id: requestToJoinToggle + } + } + + RowLayout { + Layout.fillWidth: true + + StatusBaseText { + text: qsTr("Any member can pin a message") + } + + Item { + Layout.fillWidth: true + implicitHeight: d.optionHeight + } + + StatusCheckBox { + id: pinMessagesToggle + } + } +} diff --git a/ui/app/AppLayouts/Chat/controls/community/CommunityOutroMessageInput.qml b/ui/app/AppLayouts/Chat/controls/community/CommunityOutroMessageInput.qml new file mode 100644 index 0000000000..c36e2dd9cf --- /dev/null +++ b/ui/app/AppLayouts/Chat/controls/community/CommunityOutroMessageInput.qml @@ -0,0 +1,29 @@ +import QtQuick 2.14 + +import utils 1.0 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Controls.Validators 0.1 + +StatusInput { + id: root + + leftPadding: 0 + rightPadding: 0 + label: qsTr("Leaving community message") + charLimit: 80 + + input.placeholder.text: qsTr("The message a member will see when they leave your community") + input.placeholder.wrapMode: Text.WordWrap + + validators: [ + StatusMinLengthValidator { + minLength: 1 + errorMessage: Utils.getErrorMessage(root.errors, + qsTr("community intro message")) + } + ] + validationMode: StatusInput.ValidationMode.Always +} diff --git a/ui/app/AppLayouts/Chat/layouts/SettingsPageLayout.qml b/ui/app/AppLayouts/Chat/layouts/SettingsPageLayout.qml index c33f3def7f..f237b99f53 100644 --- a/ui/app/AppLayouts/Chat/layouts/SettingsPageLayout.qml +++ b/ui/app/AppLayouts/Chat/layouts/SettingsPageLayout.qml @@ -17,6 +17,7 @@ Item { // optional property string previousPage property bool dirty: false + property bool editable: false readonly property Item contentItem: contentLoader.item @@ -30,7 +31,8 @@ Item { } function notifyDirty() { - toastAnimation.running = true + cancelChangesButtonAnimation.running = true + saveChangesButtonAnimation.running = true saveChangesButton.forceActiveFocus() } @@ -74,76 +76,73 @@ Item { id: contentLoader Layout.fillWidth: true Layout.fillHeight: true + Layout.leftMargin: 24 + Layout.rightMargin: 24 sourceComponent: root.content } - } - Rectangle { - id: toastMessage + Rectangle { + Layout.fillWidth: true - anchors { - bottom: parent.bottom - horizontalCenter: parent.horizontalCenter - bottomMargin: 16 - } + implicitHeight: buttonsLayout.implicitHeight - height: toastContent.height + 16 - width: toastContent.width + 16 + color: Theme.palette.statusToastMessage.backgroundColor + visible: root.editable - opacity: root.dirty ? 1 : 0 - color: Theme.palette.statusToastMessage.backgroundColor - radius: 8 - border.color: Theme.palette.dangerColor2 - border.width: 2 - layer.enabled: true - layer.effect: DropShadow { - verticalOffset: 3 - radius: 8 - samples: 15 - fast: true - cached: true - color: Theme.palette.dangerColor2 - spread: 0.1 - } + RowLayout { + id: buttonsLayout - NumberAnimation on border.width { - id: toastAnimation - from: 0 - to: 4 - loops: 2 - duration: 600 + anchors.fill: parent + enabled: root.dirty - onFinished: toastMessage.border.width = 2 - } + Item { + Layout.fillWidth: true + } - RowLayout { - id: toastContent + StatusButton { + id: cancelChangesButton - x: 8 - y: 8 + text: qsTr("Cancel changes") + type: StatusBaseButton.Type.Danger - StatusBaseText { - text: qsTr("Changes detected!") - color: Theme.palette.directColor1 + border.color: textColor + border.width: 0 + + onClicked: root.resetChangesClicked() + + NumberAnimation on border.width { + id: cancelChangesButtonAnimation + from: 0 + to: 2 + loops: 2 + duration: 600 + + onFinished: cancelChangesButton.border.width = 0 + } + } + + StatusButton { + id: saveChangesButton + + text: qsTr("Save changes") + + border.color: textColor + border.width: 0 + + onClicked: root.saveChangesClicked() + + NumberAnimation on border.width { + id: saveChangesButtonAnimation + from: 0 + to: 2 + loops: 2 + duration: 600 + + onFinished: saveChangesButton.border.width = 0 + } + } } - - StatusButton { - text: qsTr("Cancel") - type: StatusBaseButton.Type.Danger - onClicked: root.resetChangesClicked() - } - - StatusButton { - id: saveChangesButton - - text: qsTr("Save changes") - onClicked: root.saveChangesClicked() - } - } - - Behavior on opacity { - NumberAnimation {} } } } diff --git a/ui/app/AppLayouts/Chat/panels/communities/CommunityEditSettingsPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/CommunityEditSettingsPanel.qml index a52f8dbe63..104f3405f1 100644 --- a/ui/app/AppLayouts/Chat/panels/communities/CommunityEditSettingsPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/communities/CommunityEditSettingsPanel.qml @@ -16,21 +16,24 @@ import StatusQ.Popups 0.1 import StatusQ.Controls 0.1 import StatusQ.Controls.Validators 0.1 +import "../../controls/community" + Flickable { id: root - property color color: Theme.palette.primaryColor1 - property alias name: nameInput.text property alias description: descriptionTextInput.text - property string logoImageData: "" - property alias logoImagePath: logoEditor.source - property alias logoCropRect: logoEditor.cropRect - property string bannerImageData: "" - property alias bannerPath: bannerEditor.source - property alias bannerCropRect: bannerEditor.cropRect - property bool isCommunityHistoryArchiveSupportEnabled: false - property alias historyArchiveSupportToggle: historyArchiveSupportToggle.checked + property alias introMessage: introMessageTextInput.text + property alias outroMessage: outroMessageTextInput.text + property alias color: colorPicker.color + property alias options: options + + property alias logoImageData: logoPicker.imageData + property alias logoImagePath: logoPicker.source + property alias logoCropRect: logoPicker.cropRect + property alias bannerImageData: bannerPicker.imageData + property alias bannerPath: bannerPicker.source + property alias bannerCropRect: bannerPicker.cropRect contentWidth: layout.width contentHeight: layout.height @@ -38,182 +41,64 @@ Flickable { interactive: contentHeight > height flickableDirection: Flickable.VerticalFlick + implicitWidth: 600 + implicitHeight: 800 + ColumnLayout { id: layout width: root.width spacing: 12 - StatusInput { + CommunityNameInput { id: nameInput - Layout.fillWidth: true - - leftPadding: 0 - rightPadding: 0 - label: qsTr("Community name") - charLimit: 30 - input.placeholderText: qsTr("A catchy name") - validators: [ - StatusMinLengthValidator { - minLength: 1 - errorMessage: Utils.getErrorMessage(nameInput.errors, - qsTr("community name")) - } - ] - validationMode: StatusInput.ValidationMode.Always - Component.onCompleted: nameInput.input.forceActiveFocus(Qt.MouseFocusReason) } - StatusInput { + CommunityDescriptionInput { id: descriptionTextInput - Layout.fillWidth: true - - leftPadding: 0 - rightPadding: 0 - label: qsTr("Description") - charLimit: 140 - - input.placeholderText: qsTr("What your community is about") - input.multiline: true - input.implicitHeight: 88 - - validators: [ - StatusMinLengthValidator { - minLength: 1 - errorMessage: Utils.getErrorMessage( - descriptionTextInput.errors, - qsTr("community description")) - } - ] - validationMode: StatusInput.ValidationMode.Always } - ColumnLayout { - spacing: 8 - - // Logo - // - StatusBaseText { - text: qsTr("Community logo") - font.pixelSize: 15 - color: Theme.palette.directColor1 - } - - EditCroppedImagePanel { - id: logoEditor - - Layout.preferredWidth: 128 - Layout.preferredHeight: Layout.preferredWidth / aspectRatio - Layout.alignment: Qt.AlignHCenter - - imageFileDialogTitle: qsTr("Choose an image as logo") - title: qsTr("Community logo") - acceptButtonText: qsTr("Make this my Community logo") - - dataImage: root.logoImageData - - NoImageUploadedPanel { - anchors.centerIn: parent - - visible: !logoEditor.userSelectedImage && !root.logoImageData - } - } - - // Banner - // - StatusBaseText { - text: qsTr("Community banner") - - font.pixelSize: 15 - color: Theme.palette.directColor1 - } - - EditCroppedImagePanel { - id: bannerEditor - - Layout.preferredWidth: 475 - Layout.preferredHeight: Layout.preferredWidth / aspectRatio - Layout.alignment: Qt.AlignHCenter - - imageFileDialogTitle: qsTr("Choose an image for banner") - title: qsTr("Community banner") - acceptButtonText: qsTr("Make this my Community banner") - - roundedImage: false - aspectRatio: 375/184 - - dataImage: root.bannerImageData - - NoImageUploadedPanel { - anchors.centerIn: parent - - visible: !bannerEditor.userSelectedImage && !root.bannerImageData - showARHint: true - } - } - - Rectangle { - Layout.fillWidth: true - } + CommunityLogoPicker { + id: logoPicker + Layout.fillWidth: true } - ColumnLayout { + CommunityBannerPicker { + id: bannerPicker Layout.fillWidth: true - spacing: 8 - - StatusBaseText { - text: qsTr("Community colour") - font.pixelSize: 15 - color: Theme.palette.directColor1 - } - - StatusPickerButton { - Layout.fillWidth: true - - property string validationError: "" - - bgColor: root.color - contentColor: Theme.palette.indirectColor1 - text: root.color.toString() - - onClicked: { - colorDialog.color = root.color; - colorDialog.open(); - } - onTextChanged: { - validationError = Utils.validateAndReturnError(text, - Utils.Validate.NoEmpty | - Utils.Validate.TextHexColor); - } - - StatusColorDialog { - id: colorDialog - anchors.centerIn: parent - header.title: qsTr("Community Colour") - previewText: qsTr("White text should be legable on top of this colour") - acceptText: qsTr("Select Community Colour") - onAccepted: { - root.color = color; - } - } - } } - StatusListItem { - title: qsTr("Community history service") - + CommunityColorPicker { + id: colorPicker Layout.fillWidth: true - visible: root.isCommunityHistoryArchiveSupportEnabled + } - components: [ - StatusSwitch { - id: historyArchiveSupportToggle - enabled: root.isCommunityHistoryArchiveSupportEnabled - } - ] + StatusModalDivider { + Layout.fillWidth: true + Layout.bottomMargin: -layout.spacing + } + + CommunityOptions { + id: options + } + + StatusModalDivider { + Layout.fillWidth: true + Layout.topMargin: -layout.spacing + Layout.bottomMargin: 8 + } + + CommunityIntroMessageInput { + id: introMessageTextInput + Layout.fillWidth: true + } + + CommunityOutroMessageInput { + id: outroMessageTextInput + Layout.fillWidth: true } Item { diff --git a/ui/app/AppLayouts/Chat/panels/communities/CommunityOverviewSettingsPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/CommunityOverviewSettingsPanel.qml index f1fca5579a..8db58f62c8 100644 --- a/ui/app/AppLayouts/Chat/panels/communities/CommunityOverviewSettingsPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/communities/CommunityOverviewSettingsPanel.qml @@ -9,27 +9,26 @@ import StatusQ.Components 0.1 import "../../layouts" -/*! TODO: very confusing to be refactored - - The "API" properties are just for input purposes and to track the initial state - used in evaluating the dirty flag. They should not be updated based - on user input. The final relevant values are accessed through the \c item member of \c edit property - */ StackLayout { id: root property string name property string description + property string introMessage + property string outroMessage property string logoImageData property string bannerImageData property rect bannerCropRect property color color + property bool archiveSupportEnabled + property bool requestToJoinEnabled + property bool pinMessagesEnabled + + property bool archiveSupportOptionVisible: false property bool editable: false property bool owned: false - property bool isCommunityHistoryArchiveSupportEnabled: false - property bool historyArchiveSupportToggle: false - signal edited(Item item) // item containing edited fields (name, description, logoImagePath, bannerPath, bannerCropRect, color) + signal edited(Item item) // item containing edited fields (name, description, logoImagePath, color, options, etc..) clip: true @@ -128,31 +127,39 @@ StackLayout { previousPage: qsTr("Overview") title: qsTr("Edit Community") + editable: true content: CommunityEditSettingsPanel { - id: communityEditSettingsPanel - name: root.name description: root.description + introMessage: root.introMessage + outroMessage: root.outroMessage color: root.color logoImageData: root.logoImageData bannerImageData: root.bannerImageData - isCommunityHistoryArchiveSupportEnabled: root.isCommunityHistoryArchiveSupportEnabled - historyArchiveSupportToggle: root.historyArchiveSupportToggle + options { + archiveSupportOptionVisible: root.archiveSupportOptionVisible + archiveSupportEnabled: root.archiveSupportEnabled + requestToJoinEnabled: root.requestToJoinEnabled + pinMessagesEnabled: root.pinMessagesEnabled + } Component.onCompleted: { editCommunityPage.dirty = Qt.binding(() => { - return root.name !== name || - root.description !== description || + return root.name != name || + root.description != description || + root.introMessage != introMessage || + root.outroMessage != outroMessage || + root.archiveSupportEnabled != options.archiveSupportEnabled || + root.requestToJoinEnabled != options.requestToJoinEnabled || + root.pinMessagesEnabled != options.pinMessagesEnabled || + root.color != color || logoImagePath.length > 0 || isValidRect(logoCropRect) || - root.color !== color || bannerPath.length > 0 || - isValidRect(bannerCropRect) || - root.historyArchiveSupportToggle !== historyArchiveSupportToggle + isValidRect(bannerCropRect) }) - function isValidRect(r /*rect*/) { return r.width !== 0 && r.height !== 0 } } } diff --git a/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupOverviewPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupOverviewPanel.qml index baa8696981..679ef769e3 100644 --- a/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupOverviewPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/communities/CommunityProfilePopupOverviewPanel.qml @@ -20,7 +20,6 @@ Column { signal membersListButtonClicked() signal notificationsButtonClicked(bool checked) - signal editButtonClicked() signal transferOwnershipButtonClicked() signal leaveButtonClicked() signal copyToClipboard(string link) @@ -111,16 +110,6 @@ Column { bottomPadding: 8 } - StatusListItem { - anchors.horizontalCenter: parent.horizontalCenter - visible: root.community.amISectionAdmin - //% "Edit community" - title: qsTrId("edit-community") - icon.name: "edit" - type: StatusListItem.Type.Secondary - sensor.onClicked: root.editButtonClicked() - } - StatusListItem { anchors.horizontalCenter: parent.horizontalCenter visible: root.community.amISectionAdmin diff --git a/ui/app/AppLayouts/Chat/popups/community/CommunityProfilePopup.qml b/ui/app/AppLayouts/Chat/popups/community/CommunityProfilePopup.qml index b8881db68e..812ff948e0 100644 --- a/ui/app/AppLayouts/Chat/popups/community/CommunityProfilePopup.qml +++ b/ui/app/AppLayouts/Chat/popups/community/CommunityProfilePopup.qml @@ -64,12 +64,6 @@ StatusModal { onMembersListButtonClicked: root.contentItem.push(membersList) onNotificationsButtonClicked: root.communitySectionModule.setCommunityMuted(checked) - onEditButtonClicked: Global.openPopup(editCommunityroot, { - store: root.store, - community: root.community, - communitySectionModule: root.communitySectionModule, - onSave: root.close - }) onTransferOwnershipButtonClicked: Global.openPopup(transferOwnershiproot, { privateKey: communitySectionModule.exportCommunity(root.community.id), store: root.store @@ -94,18 +88,6 @@ StatusModal { } } - Component { - id: editCommunityroot - CreateCommunityPopup { - anchors.centerIn: parent - store: root.store - isEdit: true - onClosed: { - destroy() - } - } - } - Component { id: membersList CommunityProfilePopupMembersListPanel { diff --git a/ui/app/AppLayouts/Chat/popups/community/CreateCategoryPopup.qml b/ui/app/AppLayouts/Chat/popups/community/CreateCategoryPopup.qml index 7cc0fdb0c1..e5a5399b26 100644 --- a/ui/app/AppLayouts/Chat/popups/community/CreateCategoryPopup.qml +++ b/ui/app/AppLayouts/Chat/popups/community/CreateCategoryPopup.qml @@ -48,14 +48,20 @@ StatusModal { qsTrId("new-category") contentItem: Column { + property alias categoryName: nameInput width: root.width - property alias categoryName: nameInput + topPadding: 16 StatusInput { id: nameInput + + anchors.left: parent.left + anchors.leftMargin: 16 + + label: qsTr("Category title") charLimit: maxCategoryNameLength - input.placeholderText: qsTr("Category title") + input.placeholderText: qsTr("Name the category") validators: [StatusMinLengthValidator { minLength: 1 errorMessage: Utils.getErrorMessage(nameInput.errors, qsTr("category name")) diff --git a/ui/app/AppLayouts/Chat/popups/community/CreateChannelPopup.qml b/ui/app/AppLayouts/Chat/popups/community/CreateChannelPopup.qml index 815085cbda..e9a6cefa48 100644 --- a/ui/app/AppLayouts/Chat/popups/community/CreateChannelPopup.qml +++ b/ui/app/AppLayouts/Chat/popups/community/CreateChannelPopup.qml @@ -101,10 +101,15 @@ StatusModal { Column { id: content - width: popup.width + width: popup.width + topPadding: 16 StatusInput { id: nameInput + + anchors.left: parent.left + anchors.leftMargin: 16 + label: qsTr("Channel name") charLimit: popup.maxChannelNameLength input.placeholderText: qsTr("Name the channel") @@ -208,6 +213,10 @@ StatusModal { StatusInput { id: descriptionTextArea + + anchors.left: parent.left + anchors.leftMargin: 16 + label: qsTr("Description") charLimit: 140 diff --git a/ui/app/AppLayouts/Chat/popups/community/CreateCommunityPopup.qml b/ui/app/AppLayouts/Chat/popups/community/CreateCommunityPopup.qml index 6515d108f2..cbda54b9c4 100644 --- a/ui/app/AppLayouts/Chat/popups/community/CreateCommunityPopup.qml +++ b/ui/app/AppLayouts/Chat/popups/community/CreateCommunityPopup.qml @@ -1,6 +1,7 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.3 -import QtGraphicalEffects 1.13 +import QtQuick 2.14 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.14 +import QtGraphicalEffects 1.14 import QtQuick.Dialogs 1.3 import utils 1.0 @@ -14,417 +15,168 @@ import StatusQ.Controls 0.1 import StatusQ.Controls.Validators 0.1 import StatusQ.Popups 0.1 +import "../../controls/community" + StatusModal { - id: popup - height: 509 + id: root property var store - property var communitySectionModule - property bool isEdit: false - property QtObject community: null - property var onSave: () => {} - readonly property int maxCommunityNameLength: 30 - readonly property int maxCommunityDescLength: 140 - readonly property var communityColorValidator: Utils.Validate.NoEmpty - | Utils.Validate.TextHexColor - onOpened: { - if (isEdit) { - contentItem.communityName.input.text = community.name; - contentItem.communityDescription.input.text = community.description; - contentItem.communityColor.color = community.color; - contentItem.communityColor.colorSelected = true - if (community.largeImage) { - contentItem.communityImage.selectedImage = community.largeImage - } - requestToJoinCheckbox.checked = community.access === Constants.communityChatOnRequestAccess + width: 640 + height: 720 + + // Code below is needed because StatusModal content padding is messed up + // FIXME: when StatusModal is reworked + topPadding: 64 + 16 // 64 is header height + leftPadding: 16 + rightPadding: 16 + bottomPadding: 71 + 16 // 71 is footer height + + header.title: qsTr("Create New Community") + + rightButtons: [ + StatusButton { + text: qsTr("Next") + enabled: generalView.canGoNext + visible: generalView.visible + + onClicked: stackLayout.currentIndex = stackLayout.currentIndex + 1 + }, + StatusButton { + text: qsTr("Create Community") + enabled: introMessageInput.valid && outroMessageInput.valid + visible: introMessageInput.visible + + onClicked: d.createCommunity() } - contentItem.communityName.input.edit.forceActiveFocus() - } - onClosed: destroy() - - function isFormValid() { - return contentItem.communityName.valid && contentItem.communityDescription.valid && - Utils.validateAndReturnError(contentItem.communityColor.color.toString().toUpperCase(), - communityColorValidator) === "" - } - - header.title: isEdit ? - qsTr("Edit Community") : - qsTr("Create New Community") - - contentItem: ScrollView { - - id: scrollView - - property ScrollBar vScrollBar: ScrollBar.vertical - - property alias communityName: nameInput - property alias communityDescription: descriptionTextArea - property alias communityColor: colorDialog - property alias communityImage: addImageButton - property alias imageCropperModal: imageCropperModal - property alias historyArchiveSupportToggle: historyArchiveSupportToggle - property alias pinMessagesAllMembersCheckbox: pinMessagesAllMembersCheckbox - - contentHeight: content.height - bottomPadding: 8 - width: popup.width - - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff - - clip: true - - function scrollBackUp() { - vScrollBar.setPosition(0) - } - - Column { - id: content - width: popup.width - spacing: 8 - - Item { - height: 8 - width: parent.width - } - - StatusInput { - id: nameInput - label: qsTr("Name your community") - charLimit: maxCommunityNameLength - input.placeholderText: qsTr("A catchy name") - validators: [ - StatusMinLengthValidator { - minLength: 1 - errorMessage: Utils.getErrorMessage(nameInput.errors, "community name") - }, - StatusRegularExpressionValidator { - regularExpression: /^[^<>]+$/ - errorMessage: qsTr("This is not a valid community name") - } - ] - validationMode: StatusInput.ValidationMode.Always - } - - StatusInput { - id: descriptionTextArea - label: qsTr("Give it a short description") - charLimit: maxCommunityDescLength - - input.placeholderText: qsTr("What your community is about") - input.multiline: true - input.implicitHeight: 88 - input.verticalAlignment: TextEdit.AlignTop - - validators: [StatusMinLengthValidator { - minLength: 1 - errorMessage: Utils.getErrorMessage(descriptionTextArea.errors, "community description") - }] - validationMode: StatusInput.ValidationMode.Always - } - - StatusBaseText { - id: thumbnailText - //% "Thumbnail image" - text: qsTrId("thumbnail-image") - font.pixelSize: 15 - color: Theme.palette.directColor1 - anchors.left: parent.left - anchors.leftMargin: 16 - anchors.topMargin: 8 - } - - Item { - width: parent.width - height: addImageButton.height + 32 - - Rectangle { - id: addImageButton - color: imagePreview.visible ? "transparent" : Style.current.inputBackground - width: 128 - height: width - radius: width / 2 - anchors.centerIn: parent - property string selectedImage: "" - - FileDialog { - id: imageDialog - //% "Please choose an image" - title: qsTrId("please-choose-an-image") - folder: shortcuts.pictures - nameFilters: [ - //% "Image files (*.jpg *.jpeg *.png)" - qsTrId("image-files----jpg---jpeg---png-") - ] - onAccepted: { - addImageButton.selectedImage = imageDialog.fileUrls[0] - imageCropperModal.open() - } - } - - Rectangle { - id: imagePreviewCropper - clip: true - width: parent.width - height: parent.height - radius: parent.width / 2 - visible: !!addImageButton.selectedImage - - Image { - id: imagePreview - visible: !!addImageButton.selectedImage - source: addImageButton.selectedImage - fillMode: Image.PreserveAspectFit - width: parent.width - height: parent.height - } - layer.enabled: true - layer.effect: OpacityMask { - maskSource: Rectangle { - anchors.centerIn: parent - width: imageCropperModal.width - height: imageCropperModal.height - radius: width / 2 - } - } - } - - Item { - id: addImageCenter - visible: !imagePreview.visible - width: uploadText.width - height: childrenRect.height - anchors.centerIn: parent - - SVGImage { - id: imageImg - source: Style.svg("images_icon") - width: 20 - height: 18 - anchors.horizontalCenter: parent.horizontalCenter - } - - StatusBaseText { - id: uploadText - //% "Upload" - text: qsTrId("upload") - anchors.top: imageImg.bottom - anchors.topMargin: 5 - font.pixelSize: 15 - color: Theme.palette.baseColor1 - } - } - - StatusRoundButton { - type: StatusRoundButton.Type.Secondary - icon.name: "add" - anchors.top: parent.top - anchors.right: parent.right - anchors.rightMargin: Style.current.halfPadding - highlighted: sensor.containsMouse - } - - MouseArea { - id: sensor - hoverEnabled: true - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: imageDialog.open() - } - - ImageCropperModal { - id: imageCropperModal - selectedImage: addImageButton.selectedImage - ratio: "1:1" - } - } - } - - StatusBaseText { - text: qsTr("Community colour") - font.pixelSize: 15 - color: Theme.palette.directColor1 - anchors.left: parent.left - anchors.leftMargin: 16 - } - - Item { - anchors.horizontalCenter: parent.horizontalCenter - height: colorSelectorButton.height + 16 - width: parent.width - 32 - - StatusPickerButton { - id: colorSelectorButton - anchors.top: parent.top - anchors.topMargin: 10 - - property string validationError: "" - - bgColor: colorDialog.colorSelected ? - colorDialog.color : Theme.palette.baseColor2 - contentColor: colorDialog.colorSelected ? Theme.palette.indirectColor1 : Theme.palette.baseColor1 - text: colorDialog.colorSelected ? - colorDialog.color.toString().toUpperCase() : - qsTr("Pick a colour") - - onClicked: colorDialog.open(); - onTextChanged: { - if (colorDialog.colorSelected) { - validationError = Utils.validateAndReturnError(text, communityColorValidator) - } - } - } - - StatusColorDialog { - id: colorDialog - anchors.centerIn: parent - property bool colorSelected: false - color: Theme.palette.primaryColor1 - onAccepted: colorSelected = true - } - - StatusBaseText { - text: colorSelectorButton.validationError - visible: !!text - color: Theme.palette.dangerColor1 - anchors.top: colorSelectorButton.bottom - anchors.topMargin: 4 - anchors.right: colorSelectorButton.right - } - } - - StatusModalDivider { - topPadding: 8 - bottomPadding: 8 - visible: !isEdit - } - - StatusListItem { - anchors.horizontalCenter: parent.horizontalCenter - visible: popup.store.isCommunityHistoryArchiveSupportEnabled - title: qsTr("Community history service") - sensor.onClicked: { - if (popup.store.isCommunityHistoryArchiveSupportEnabled) { - historyArchiveSupportToggle.checked = !historyArchiveSupportToggle.checked - } - } - components: [ - StatusCheckBox { - id: historyArchiveSupportToggle - enabled: popup.store.isCommunityHistoryArchiveSupportEnabled - checked: isEdit ? community.historyArchiveSupportEnabled : false - } - ] - } - - StatusListItem { - anchors.horizontalCenter: parent.horizontalCenter - title: qsTr("Request to join required") - sensor.onClicked: { - requestToJoinCheckbox.checked = !requestToJoinCheckbox.checked - } - components: [ - StatusCheckBox { - id: requestToJoinCheckbox - checked: true - } - ] - } - - StatusListItem { - anchors.horizontalCenter: parent.horizontalCenter - title: qsTr("Any member can pin a message") - sensor.onClicked: { - pinMessagesAllMembersCheckbox.checked = !pinMessagesAllMembersCheckbox.checked - } - components: [ - StatusCheckBox { - id: pinMessagesAllMembersCheckbox - checked: isEdit ? community.pinMessageAllMembersEnabled : false - } - ] - } - } - - } + ] leftButtons: [ StatusRoundButton { id: btnBack - visible: isEdit icon.name: "arrow-right" icon.width: 20 icon.height: 16 rotation: 180 - onClicked: popup.destroy() + visible: stackLayout.currentIndex !== 0 + + onClicked: stackLayout.currentIndex = 0 } ] - rightButtons: [ - StatusButton { - id: btnCreateEdit - enabled: isFormValid() - text: isEdit ? - //% "Save" - qsTrId("Save") : - //% "Create" - qsTrId("create") - onClicked: { - if (!isFormValid()) { - popup.contentItem.scrollBackUp() - return + StackLayout { + id: stackLayout + + anchors.fill: parent + + Flickable { + id: generalView + + readonly property bool canGoNext: nameInput.valid && descriptionTextInput.valid + + clip: true + contentHeight: generalViewLayout.height + interactive: contentHeight > height + flickableDirection: Flickable.VerticalFlick + + ColumnLayout { + id: generalViewLayout + width: generalView.width + spacing: 12 + + CommunityNameInput { + id: nameInput + Layout.fillWidth: true + Component.onCompleted: nameInput.input.forceActiveFocus( + Qt.MouseFocusReason) } - let error = false; - if(isEdit) { - error = communitySectionModule.editCommunity( - Utils.filterXSS(popup.contentItem.communityName.input.text), - Utils.filterXSS(popup.contentItem.communityDescription.input.text), - requestToJoinCheckbox.checked ? Constants.communityChatOnRequestAccess : Constants.communityChatPublicAccess, - popup.contentItem.communityColor.color.toString().toUpperCase(), - // to retain the existing image, pass "" for the image path - popup.contentItem.communityImage.selectedImage === community.largeImage ? "" : - popup.contentItem.communityImage.selectedImage, - popup.contentItem.imageCropperModal.aX, - popup.contentItem.imageCropperModal.aY, - popup.contentItem.imageCropperModal.bX, - popup.contentItem.imageCropperModal.bY, - popup.contentItem.historyArchiveSupportToggle.checked, - popup.contentItem.pinMessagesAllMembersCheckbox.checked - ) - } else { - error = popup.store.createCommunity( - Utils.filterXSS(popup.contentItem.communityName.input.text), - Utils.filterXSS(popup.contentItem.communityDescription.input.text), - requestToJoinCheckbox.checked ? Constants.communityChatOnRequestAccess : Constants.communityChatPublicAccess, - popup.contentItem.communityColor.color.toString().toUpperCase(), - popup.contentItem.communityImage.selectedImage, - popup.contentItem.imageCropperModal.aX, - popup.contentItem.imageCropperModal.aY, - popup.contentItem.imageCropperModal.bX, - popup.contentItem.imageCropperModal.bY, - popup.contentItem.historyArchiveSupportToggle.checked, - popup.contentItem.pinMessagesAllMembersCheckbox.checked - ) + CommunityDescriptionInput { + id: descriptionTextInput + Layout.fillWidth: true } - if (error) { - creatingError.text = error.error - return creatingError.open() + CommunityLogoPicker { + id: logoPicker + Layout.fillWidth: true + } + + CommunityColorPicker { + id: colorPicker + Layout.fillWidth: true + } + + StatusModalDivider { + Layout.fillWidth: true + } + + CommunityOptions { + id: options + + archiveSupportOptionVisible: root.store.isCommunityHistoryArchiveSupportEnabled + archiveSupportEnabled: archiveSupportOptionVisible + } + + Item { + Layout.fillHeight: true } - popup.onSave() - popup.close() } } - ] + + ColumnLayout { + id: introOutroMessageView + + spacing: 12 + + CommunityIntroMessageInput { + id: introMessageInput + + Layout.fillWidth: true + Layout.fillHeight: true + + input.maximumHeight: 0 + } + + CommunityOutroMessageInput { + id: outroMessageInput + + Layout.fillWidth: true + } + } + } + + QtObject { + id: d + + function createCommunity() { + let error = store.createCommunity( + Utils.filterXSS(nameInput.input.text), + Utils.filterXSS(descriptionTextInput.input.text), + Utils.filterXSS(introMessageInput.input.text), + Utils.filterXSS(outroMessageInput.input.text), + options.requestToJoinEnabled ? Constants.communityChatOnRequestAccess : Constants.communityChatPublicAccess, + colorPicker.color.toString().toUpperCase(), + logoPicker.source, + logoPicker.cropRect.x, + logoPicker.cropRect.y, + logoPicker.cropRect.x + logoPicker.cropRect.width, + logoPicker.cropRect.y + logoPicker.cropRect.height, + options.archiveSupportEnabled, + options.pinMessagesEnabled + ) + if (error) { + errorDialog.text = error.error + errorDialog.open() + } + root.close() + } + } MessageDialog { - id: creatingError - //% "Error creating the community" - title: qsTrId("error-creating-the-community") + id: errorDialog + + title: qsTr("Error creating the community") icon: StandardIcon.Critical standardButtons: StandardButton.Ok } } - diff --git a/ui/app/AppLayouts/Chat/stores/RootStore.qml b/ui/app/AppLayouts/Chat/stores/RootStore.qml index 8df9a50893..2d7ca560a7 100644 --- a/ui/app/AppLayouts/Chat/stores/RootStore.qml +++ b/ui/app/AppLayouts/Chat/stores/RootStore.qml @@ -230,8 +230,8 @@ QtObject { // Not Refactored Yet property var activeCommunityChatsModel: "" //chatsModelInst.communities.activeCommunity.chats - function createCommunity(communityName, communityDescription, checkedMembership, communityColor, communityImage, imageCropperModalaX, imageCropperModalaY, imageCropperModalbX, imageCropperModalbY, historyArchiveSupportEnabled, pinMessagesAllowedForMembers) { - communitiesModuleInst.createCommunity(communityName, communityDescription, checkedMembership, communityColor, communityImage, imageCropperModalaX, imageCropperModalaY, imageCropperModalbX, imageCropperModalbY, historyArchiveSupportEnabled, pinMessagesAllowedForMembers); + function createCommunity(name, description, introMessage, outroMessage, checkedMembership, color, image, imageAX, imageAY, imageBX, imageBY, historyArchiveSupportEnabled, pinMessagesAllowedForMembers) { + communitiesModuleInst.createCommunity(name, description, introMessage, outroMessage, checkedMembership, color, image, imageAX, imageAY, imageBX, imageBY, historyArchiveSupportEnabled, pinMessagesAllowedForMembers); } function importCommunity(communityKey) { diff --git a/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml b/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml index bb351ef732..f78945bb4b 100644 --- a/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml +++ b/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml @@ -116,24 +116,35 @@ StatusAppTwoPanelLayout { CommunityOverviewSettingsPanel { name: root.community.name description: root.community.description + introMessage: root.community.introMessage + outroMessage: root.community.outroMessage logoImageData: root.community.image bannerImageData: root.community.bannerImageData color: root.community.color + archiveSupportEnabled: root.community.historyArchiveSupportEnabled + requestToJoinEnabled: root.community.access === Constants.communityChatOnRequestAccess + pinMessagesEnabled: root.community.pinMessageAllMembersEnabled + + archiveSupportOptionVisible: root.rootStore.isCommunityHistoryArchiveSupportEnabled editable: root.community.amISectionAdmin - isCommunityHistoryArchiveSupportEnabled: root.rootStore.isCommunityHistoryArchiveSupportEnabled - historyArchiveSupportToggle: community.historyArchiveSupportEnabled onEdited: { - root.chatCommunitySectionModule.editCommunity( + let error = root.chatCommunitySectionModule.editCommunity( Utils.filterXSS(item.name), Utils.filterXSS(item.description), - root.community.access, + Utils.filterXSS(item.introMessage), + Utils.filterXSS(item.outroMessage), + item.options.requestToJoinEnabled ? Constants.communityChatOnRequestAccess : Constants.communityChatPublicAccess, item.color.toString().toUpperCase(), JSON.stringify({imagePath: String(item.logoImagePath).replace("file://", ""), cropRect: item.logoCropRect}), JSON.stringify({imagePath: String(item.bannerPath).replace("file://", ""), cropRect: item.bannerCropRect}), - item.historyArchiveSupportToggle, - false /*TODO port the modal implementation*/ + item.options.archiveSupportEnabled, + item.options.pinMessagesEnabled ) + if (error) { + errorDialog.text = error.error + errorDialog.open() + } } } @@ -181,4 +192,11 @@ StatusAppTwoPanelLayout { id: d property int currentIndex: 0 } + + MessageDialog { + id: errorDialog + title: qsTr("Error editing the community") + icon: StandardIcon.Critical + standardButtons: StandardButton.Ok + } } diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index cd62c613ae..7d9a174b53 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -337,18 +337,6 @@ Item { }) } - StatusMenuItem { - enabled: model.amISectionAdmin - //% "Edit Community" - text: qsTrId("edit-community") - icon.name: "edit" - onTriggered: Global.openPopup(editCommunityPopup, { - store: appMain.rootStore, - community: model, - communitySectionModule: communityContextMenu.chatCommunitySectionModule - }) - } - StatusMenuSeparator {} StatusMenuItem { @@ -738,17 +726,6 @@ Item { } } - Component { - id: editCommunityPopup - CreateCommunityPopup { - anchors.centerIn: parent - isEdit: true - onClosed: { - destroy() - } - } - } - Component { id: pinnedMessagesPopupComponent PinnedMessagesPopup { diff --git a/ui/imports/shared/popups/CommunityIntroDialog.qml b/ui/imports/shared/popups/CommunityIntroDialog.qml new file mode 100644 index 0000000000..1d618a949f --- /dev/null +++ b/ui/imports/shared/popups/CommunityIntroDialog.qml @@ -0,0 +1,86 @@ +import QtQuick 2.14 +import QtQuick.Controls 2.14 +import QtQuick.Layouts 1.1 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Components 0.1 +import StatusQ.Popups 0.1 + +StatusModal { + id: root + + property string name + property string introMessage + property url imageSrc + + signal joined + + // Code below is needed because StatusModal content padding is messed up + // FIXME: when StatusModal is reworked + width: undefined // popup is able to determine size from its content + topPadding: 64 + 16 // 64 is header height + leftPadding: 16 + rightPadding: 16 + bottomPadding: 71 + 16 // 71 is footer height + + header.title: qsTr("Welcome to %1").arg(name) + + rightButtons: [ + StatusButton { + text: qsTr("Join %1").arg(root.name) + enabled: checkBox.checked + onClicked: { + root.joined() + root.close() + } + } + ] + + ColumnLayout { + anchors.fill: parent + + spacing: 24 + + StatusRoundedImage { + Layout.alignment: Qt.AlignCenter + Layout.preferredHeight: 64 + Layout.preferredWidth: 64 + + visible: image.status == Image.Loading || image.status == Image.Ready + image.source: root.imageSrc + } + + ScrollView { + Layout.preferredWidth: contentWidth + Layout.minimumWidth: 300 + + Layout.fillHeight: true + Layout.preferredHeight: contentHeight + Layout.maximumHeight: 400 + + contentWidth: messageContent.width + contentHeight: messageContent.height + + clip: true + + StatusBaseText { + id: messageContent + + width: Math.min(implicitWidth, 640) + + text: root.introMessage !== "" ? root.introMessage : qsTr("Community %1 has no intro message...").arg(root.name) + clip: true + color: Theme.palette.directColor1 + wrapMode: Text.WordWrap + } + } + + StatusCheckBox { + id: checkBox + Layout.alignment: Qt.AlignCenter + text: qsTr("I agree with the above") + } + } +} diff --git a/ui/imports/shared/popups/qmldir b/ui/imports/shared/popups/qmldir index aca329794f..5097e19501 100644 --- a/ui/imports/shared/popups/qmldir +++ b/ui/imports/shared/popups/qmldir @@ -1,6 +1,7 @@ ChatCommandsPopup 1.0 ChatCommandsPopup.qml BlockContactConfirmationDialog 1.0 BlockContactConfirmationDialog.qml ConfirmationDialog 1.0 ConfirmationDialog.qml +CommunityIntroDialog 1.0 CommunityIntroDialog.qml DownloadModal 1.0 DownloadModal.qml DownloadPage 1.0 DownloadPage.qml ImageCropperModal 1.0 ImageCropperModal.qml diff --git a/ui/imports/shared/views/chat/InvitationBubbleView.qml b/ui/imports/shared/views/chat/InvitationBubbleView.qml index 9f83fd82ff..915a175d46 100644 --- a/ui/imports/shared/views/chat/InvitationBubbleView.qml +++ b/ui/imports/shared/views/chat/InvitationBubbleView.qml @@ -75,6 +75,21 @@ Item { } } + Component { + id: communityIntroDialog + + CommunityIntroDialog { + anchors.centerIn: parent + + property var joinMethod: () => {} + + name: root.invitedCommunity ? root.invitedCommunity.name : "" + introMessage: root.invitedCommunity ? root.invitedCommunity.introMessage : "" + imageSrc: root.invitedCommunity ? root.invitedCommunity.image : "" + + onJoined: joinMethod() + } + } Loader { id: rectangleBubbleLoader @@ -297,6 +312,7 @@ Item { //% "Unsupported state" text: qsTrId("unsupported-state") onClicked: { + let onBtnClick = function(){ let error @@ -304,19 +320,20 @@ Item { root.store.setActiveCommunity(communityId); return } else if (rectangleBubble.state === "unjoined") { - error = root.store.joinCommunity(communityId) + Global.openPopup(communityIntroDialog, { joinMethod: () => { + let error = root.store.joinCommunity(communityId) + if (error) joiningError.showError(error) + } }); } else if (rectangleBubble.state === "requestToJoin") { - error = root.store.requestToJoinCommunity(communityId, userProfile.name) - if (!error) { - rectangleBubble.isPendingRequest = root.store.isCommunityRequestPending(communityId) - } + Global.openPopup(communityIntroDialog, { joinMethod: () => { + let error = root.store.requestToJoinCommunity(communityId, userProfile.name) + if (error) joiningError.showError(error) + else rectangleBubble.isPendingRequest = root.store.isCommunityRequestPending(communityId) + } }); } - if (error) { - joiningError.text = error - return joiningError.open() - } + if (error) joiningError.showError(error) } if (localAccountSensitiveSettings.communitiesEnabled) { @@ -328,6 +345,12 @@ Item { MessageDialog { id: joiningError + + function showError(error) { + joiningError.text = error + joiningError.open() + } + //% "Error joining the community" title: qsTrId("error-joining-the-community") icon: StandardIcon.Critical