diff --git a/.gitignore b/.gitignore index bed053999d..53ded5f7c8 100644 --- a/.gitignore +++ b/.gitignore @@ -51,7 +51,8 @@ CTestTestfile.cmake _deps .cache/ - +# QtCreator shadow builds +build-*/ # https://github.com/github/gitignore/blob/master/C%2B%2B.gitignore # Prerequisites diff --git a/ui/StatusQ b/ui/StatusQ index a9c79b0359..457e5fe4af 160000 --- a/ui/StatusQ +++ b/ui/StatusQ @@ -1 +1 @@ -Subproject commit a9c79b03595d7c8f515aa014cad0471dec7a6b11 +Subproject commit 457e5fe4af51a0c32a0b81b86fd2f9ebdce7d32d diff --git a/ui/imports/shared/panels/EditCroppedImagePanel.qml b/ui/imports/shared/panels/EditCroppedImagePanel.qml new file mode 100644 index 0000000000..0b4045aa85 --- /dev/null +++ b/ui/imports/shared/panels/EditCroppedImagePanel.qml @@ -0,0 +1,218 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 +import QtQuick.Controls 2.14 +import QtQuick.Dialogs 1.3 + +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.Controls 0.1 +import StatusQ.Controls.Validators 0.1 +import StatusQ.Popups 0.1 + +Item { + id: root + + property alias source: bannerPreview.source + property alias cropRect: bannerPreview.cropRect + /*required*/ property alias aspectRatio: bannerPreview.aspectRatio + + property bool roundedImage: true + + /*required*/ property string imageFileDialogTitle: "" + /*required*/ property string title: "" + /*required*/ property string acceptButtonText: "" + + property string dataImage: "" + + property bool userSelectedImage: false + readonly property bool nothingToShow: state === d.noImageState + + implicitWidth: mainLayout.implicitWidth + implicitHeight: mainLayout.implicitHeight + + + states: [ + State { + name: d.dataImageState + when: root.dataImage.length > 0 && !userSelectedImage + }, + State { + name: d.noImageState + when: root.dataImage.length === 0 && !userSelectedImage + }, + State { + name: d.imageSelectedState + when: userSelectedImage + } + ] + + QtObject { + id: d + + readonly property string dataImageState: "dataImage" + readonly property string noImageState: "noImage" + readonly property string imageSelectedState: "imageSelected" + } + + ColumnLayout { + id: mainLayout + + anchors.fill: parent + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + + visible: !bannerEditor.visible + + StatusRoundedImage { + id: profilePic + + anchors.fill: parent + + visible: root.state === d.dataImageState + + image.source: root.dataImage + showLoadingIndicator: true + border.width: 1 + border.color: Style.current.border + } + + StatusImageCropPanel + { + id: bannerPreview + + anchors.fill: parent + + visible: root.state === d.imageSelectedState + + interactive: false + wallColor: Theme.palette.statusAppLayout.backgroundColor + wallTransparency: 1 + margins: 0 + + windowStyle: roundedImage ? StatusImageCrop.WindowStyle.Rounded : StatusImageCrop.WindowStyle.Rectangular + } + + StatusRoundButton { + id: editButton + + icon.name: "edit" + + // bottom-right corner + x: root.userSelectedImage + ? bannerPreview.cropWindow.x + bannerPreview.cropWindow.width - (roundedImage ? editButton.width : editButton.width/2 + bannerPreview.radius) + : parent.width - editButton.width + y: (root.userSelectedImage + ? bannerPreview.cropWindow.y + bannerPreview.cropWindow.height - (roundedImage ? editButton.height + Style.current.smallPadding : editButton.height/2) + : parent.width - editButton.height) - Style.current.smallPadding + + type: StatusRoundButton.Type.Secondary + + onClicked: bannerFileDialog.open() + } + } + + Rectangle { + id: bannerEditor + + Layout.fillWidth: true + Layout.fillHeight: true + + visible: root.state === d.noImageState + + radius: roundedImage ? Math.max(width, height)/2 : bannerPreview.radius + color: Style.current.inputBackground + + StatusRoundButton { + id: addButton + + icon.name: "add" + + // top-right corner + x: parent.width - (roundedImage ? editButton.width : editButton.width/2 + bannerEditor.radius) + y: roundedImage ? addButton.height/2 : -addButton.height/2 + bannerEditor.radius + + type: StatusRoundButton.Type.Secondary + + onClicked: bannerFileDialog.open() + z: bannerEditor.z + 1 + } + + FileDialog { + id: bannerFileDialog + + title: root.imageFileDialogTitle + folder: root.userSelectedImage ? bannerCropper.source.substr(0, bannerCropper.source.lastIndexOf("/")) : shortcuts.pictures + nameFilters: [qsTr("Image files (*.jpg *.jpeg, *.jfif, *.png *.tiff *.heif)")] + onAccepted: { + if(bannerFileDialog.fileUrls.length > 0) { + bannerCropper.source = bannerFileDialog.fileUrls[0] + bannerCropperModal.open() + } + } + onRejected: { + if(root.userSelectedImage) + bannerCropperModal.open() + } + } + + StatusModal { + id: bannerCropperModal + + header.title: root.title + + anchors.centerIn: Overlay.overlay + + Item { + implicitWidth: 480 + implicitHeight: 350 + + anchors.fill: parent + + ColumnLayout { + anchors.fill: parent + + StatusImageCropPanel { + id: bannerCropper + + Layout.fillWidth: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + Layout.leftMargin: Style.current.padding * 2 + Layout.topMargin: Style.current.bigPadding + Layout.rightMargin: Layout.leftMargin + Layout.bottomMargin: Layout.topMargin + + windowStyle: bannerPreview.windowStyle + aspectRatio: bannerPreview.aspectRatio + + enableCheckers: true + } + } + } + + rightButtons: [ + StatusButton { + text: root.acceptButtonText + + enabled: bannerCropper.sourceSize.width > 0 && bannerCropper.sourceSize.height > 0 + + onClicked: { + bannerCropperModal.close() + bannerPreview.setCropRect(bannerCropper.cropRect) + bannerPreview.source = bannerCropper.source + root.userSelectedImage = true + } + } + ] + } + } + } +} diff --git a/ui/imports/shared/panels/NoImageUploadedPanel.qml b/ui/imports/shared/panels/NoImageUploadedPanel.qml new file mode 100644 index 0000000000..380702a161 --- /dev/null +++ b/ui/imports/shared/panels/NoImageUploadedPanel.qml @@ -0,0 +1,51 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 + +import utils 1.0 +import shared.panels 1.0 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 + +/*! + /brief Image icon and ulopad text hints for banner and logo + */ +Item { + id: root + + implicitWidth: mainLayout.implicitWidth + implicitHeight: mainLayout.implicitHeight + + property bool showARHint: false + + ColumnLayout { + id: mainLayout + + SVGImage { + id: imageImg + source: Style.svg("images_icon") + width: 20 + height: 18 + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + } + + StatusBaseText { + id: uploadText + text: qsTr("Upload") + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + Layout.topMargin: 5 + font.pixelSize: 15 + color: Theme.palette.baseColor1 + } + + StatusBaseText { + id: optimalARText + text: qsTr("Wide aspect ratio is optimal") + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + visible: root.showARHint + Layout.topMargin: 5 + font.pixelSize: 15 + color: Theme.palette.baseColor1 + } + } +} diff --git a/ui/imports/shared/panels/qmldir b/ui/imports/shared/panels/qmldir index 7ce1187ff1..06c7e89db6 100644 --- a/ui/imports/shared/panels/qmldir +++ b/ui/imports/shared/panels/qmldir @@ -16,3 +16,5 @@ SplitViewHandle 1.0 SplitViewHandle.qml StyledText 1.0 StyledText.qml SVGImage 1.0 SVGImage.qml TextWithLabel 1.0 TextWithLabel.qml +EditCroppedImagePanel 1.0 EditCroppedImagePanel.qml +NoImageUploadedPanel 1.0 NoImageUploadedPanel.qml \ No newline at end of file