fix(Profile): Added menu to remove profile image
This commit is contained in:
parent
e0cd28d5f4
commit
f60dacc45d
|
@ -1,115 +0,0 @@
|
||||||
import QtQuick 2.13
|
|
||||||
import QtQuick.Dialogs 1.3
|
|
||||||
|
|
||||||
import utils 1.0
|
|
||||||
|
|
||||||
import StatusQ.Controls 0.1
|
|
||||||
|
|
||||||
import shared 1.0
|
|
||||||
import shared.panels 1.0
|
|
||||||
import shared.popups 1.0
|
|
||||||
|
|
||||||
// TODO: replace with StatusModal
|
|
||||||
ModalPopup {
|
|
||||||
id: popup
|
|
||||||
title: qsTr("Profile picture")
|
|
||||||
|
|
||||||
property var profileStore
|
|
||||||
|
|
||||||
property string selectedImage // selectedImage is for us to be able to analyze it before setting it as current
|
|
||||||
property string uploadError
|
|
||||||
property url largeImage: popup.profileStore.profileLargeImage
|
|
||||||
property bool hasIdentityImage: !!popup.profileStore.profileLargeImage
|
|
||||||
|
|
||||||
onClosed: {
|
|
||||||
destroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
onSelectedImageChanged: {
|
|
||||||
if (!selectedImage) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cropImageModal.open()
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
RoundedImage {
|
|
||||||
id: profilePic
|
|
||||||
source: popup.largeImage
|
|
||||||
width: 160
|
|
||||||
height: 160
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
border.width: 1
|
|
||||||
border.color: Style.current.border
|
|
||||||
onClicked: imageDialog.open()
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
visible: !!uploadError
|
|
||||||
text: uploadError
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: profilePic.bottom
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
font.pixelSize: 13
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
anchors.topMargin: 13
|
|
||||||
font.weight: Font.Thin
|
|
||||||
color: Style.current.danger
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageCropperModal {
|
|
||||||
id: cropImageModal
|
|
||||||
|
|
||||||
selectedImage: popup.selectedImage
|
|
||||||
ratio: "1:1"
|
|
||||||
onCropFinished: {
|
|
||||||
popup.uploadError = popup.profileStore.uploadImage(selectedImage, aX, aY, bX, bY)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
footer: Item {
|
|
||||||
width: parent.width
|
|
||||||
height: uploadBtn.height
|
|
||||||
|
|
||||||
StatusFlatButton {
|
|
||||||
visible: popup.hasIdentityImage
|
|
||||||
type: StatusBaseButton.Type.Danger
|
|
||||||
text: qsTr("Remove")
|
|
||||||
anchors.right: uploadBtn.left
|
|
||||||
anchors.rightMargin: Style.current.padding
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
onClicked: {
|
|
||||||
popup.uploadError = popup.profileStore.removeImage()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StatusButton {
|
|
||||||
id: uploadBtn
|
|
||||||
text: qsTr("Upload")
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
onClicked: {
|
|
||||||
imageDialog.open()
|
|
||||||
}
|
|
||||||
|
|
||||||
FileDialog {
|
|
||||||
id: imageDialog
|
|
||||||
title: qsTr("Please choose an image")
|
|
||||||
folder: shortcuts.pictures
|
|
||||||
nameFilters: [
|
|
||||||
qsTr("Image files (*.jpg *.jpeg *.png)")
|
|
||||||
]
|
|
||||||
onAccepted: {
|
|
||||||
selectedImage = imageDialog.fileUrls[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -58,6 +58,8 @@ ColumnLayout {
|
||||||
Layout.leftMargin: Style.current.padding
|
Layout.leftMargin: Style.current.padding
|
||||||
Layout.rightMargin: Style.current.padding
|
Layout.rightMargin: Style.current.padding
|
||||||
|
|
||||||
|
store: root.profileStore
|
||||||
|
|
||||||
displayName: profileStore.name
|
displayName: profileStore.name
|
||||||
pubkey: profileStore.pubkey
|
pubkey: profileStore.pubkey
|
||||||
icon: profileStore.profileLargeImage
|
icon: profileStore.profileLargeImage
|
||||||
|
|
|
@ -1,213 +0,0 @@
|
||||||
import QtQuick 2.13
|
|
||||||
|
|
||||||
import "../panels"
|
|
||||||
|
|
||||||
import utils 1.0
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
property Image image
|
|
||||||
property alias selectorRectangle: selectorRectangle
|
|
||||||
property string ratio: ""
|
|
||||||
property var splitRatio: !!ratio ? ratio.split(":") : null
|
|
||||||
property int widthRatio: !!ratio ? parseInt(splitRatio[0]) : -1
|
|
||||||
property int heightRatio: !!ratio ? parseInt(splitRatio[1]) : -1
|
|
||||||
property bool settingCorners: false
|
|
||||||
property int draggedCorner: 0
|
|
||||||
property bool ready: false
|
|
||||||
|
|
||||||
readonly property int topLeft: 0
|
|
||||||
readonly property int topRight: 1
|
|
||||||
readonly property int bottomLeft: 2
|
|
||||||
readonly property int bottomRight: 3
|
|
||||||
|
|
||||||
width: image.width
|
|
||||||
height: image.height
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: selectorRectangle
|
|
||||||
visible: false
|
|
||||||
x: 0
|
|
||||||
y: 0
|
|
||||||
border.width: 2
|
|
||||||
border.color: Style.current.orange
|
|
||||||
color: Style.current.transparent
|
|
||||||
|
|
||||||
function fitRatio(makeBigger) {
|
|
||||||
if (!!ratio) {
|
|
||||||
if ((makeBigger && selectorRectangle.width < selectorRectangle.height) || (!makeBigger && selectorRectangle.width > selectorRectangle.height)) {
|
|
||||||
selectorRectangle.width = (selectorRectangle.height/heightRatio) * widthRatio
|
|
||||||
} else {
|
|
||||||
selectorRectangle.height = (selectorRectangle.width/widthRatio) * heightRatio
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function initialSetup() {
|
|
||||||
selectorRectangle.width = image.width
|
|
||||||
selectorRectangle.height = image.height
|
|
||||||
|
|
||||||
fitRatio()
|
|
||||||
topLeftCorner.x = 0
|
|
||||||
topLeftCorner.y = 0
|
|
||||||
topRightCorner.x = selectorRectangle.width - topRightCorner.width
|
|
||||||
topRightCorner.y = 0
|
|
||||||
bottomLeftCorner.x = 0
|
|
||||||
bottomLeftCorner.y = selectorRectangle.height - topRightCorner.height
|
|
||||||
bottomRightCorner.x = selectorRectangle.width - topRightCorner.width
|
|
||||||
bottomRightCorner.y = selectorRectangle.height - topRightCorner.height
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function adjustRectangleSize() {
|
|
||||||
if (!selectorRectangle.visible) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
selectorRectangle.width = bottomRightCorner.x + bottomRightCorner.width - topLeftCorner.x
|
|
||||||
selectorRectangle.height = bottomRightCorner.y + bottomRightCorner.height - topLeftCorner.y
|
|
||||||
selectorRectangle.x = topLeftCorner.x
|
|
||||||
selectorRectangle.y = topLeftCorner.y
|
|
||||||
|
|
||||||
if (!!ratio) {
|
|
||||||
// FIXME with a ratio that is not 1:1, the rectangle can go out of bounds
|
|
||||||
fitRatio()
|
|
||||||
|
|
||||||
switch(draggedCorner) {
|
|
||||||
case topLeft:
|
|
||||||
selectorRectangle.x = topLeftCorner.x
|
|
||||||
selectorRectangle.y = topLeftCorner.y
|
|
||||||
break
|
|
||||||
case topRight:
|
|
||||||
selectorRectangle.x = topRightCorner.x - selectorRectangle.width + topRightCorner.width
|
|
||||||
selectorRectangle.y = topRightCorner.y
|
|
||||||
break
|
|
||||||
case bottomLeft:
|
|
||||||
selectorRectangle.x = bottomLeftCorner.x
|
|
||||||
selectorRectangle.y = bottomLeftCorner.y - selectorRectangle.height + bottomLeftCorner.height
|
|
||||||
break
|
|
||||||
case bottomRight:
|
|
||||||
selectorRectangle.x = bottomRightCorner.x - selectorRectangle.width + bottomRightCorner.width
|
|
||||||
selectorRectangle.y = bottomRightCorner.y - selectorRectangle.height + bottomRightCorner.height
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: image
|
|
||||||
onStatusChanged: {
|
|
||||||
if (image.status === Image.Ready) {
|
|
||||||
selectorRectangle.initialSetup()
|
|
||||||
selectorRectangle.visible = true
|
|
||||||
root.ready = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function putCorners() {
|
|
||||||
settingCorners = true
|
|
||||||
|
|
||||||
topLeftCorner.x = selectorRectangle.x
|
|
||||||
topLeftCorner.y = selectorRectangle.y
|
|
||||||
topRightCorner.x = selectorRectangle.x + selectorRectangle.width - topRightCorner.width
|
|
||||||
topRightCorner.y = selectorRectangle.y
|
|
||||||
bottomLeftCorner.x = selectorRectangle.x
|
|
||||||
bottomLeftCorner.y = selectorRectangle.y + selectorRectangle.height - topRightCorner.height
|
|
||||||
bottomRightCorner.x = selectorRectangle.x + selectorRectangle.width - topRightCorner.width
|
|
||||||
bottomRightCorner.y = selectorRectangle.y + selectorRectangle.height - topRightCorner.height
|
|
||||||
|
|
||||||
settingCorners = false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Size calculations are only done on top-left and bottom-right, because the other two corners follow them
|
|
||||||
CropCornerRectangle {
|
|
||||||
id: topLeftCorner
|
|
||||||
onXChanged: {
|
|
||||||
if (settingCorners) return
|
|
||||||
if (x < 0) x = 0
|
|
||||||
if (x > topRightCorner.x - width) x = topRightCorner.x - width
|
|
||||||
|
|
||||||
bottomLeftCorner.x = x
|
|
||||||
selectorRectangle.adjustRectangleSize()
|
|
||||||
}
|
|
||||||
onYChanged: {
|
|
||||||
if (settingCorners) return
|
|
||||||
if (y < 0) y = 0
|
|
||||||
if (y > bottomRightCorner.y - height) y = bottomRightCorner.y - height
|
|
||||||
|
|
||||||
topRightCorner.y = y
|
|
||||||
selectorRectangle.adjustRectangleSize()
|
|
||||||
}
|
|
||||||
onPressed: {
|
|
||||||
draggedCorner = topLeft
|
|
||||||
}
|
|
||||||
|
|
||||||
onReleased: {
|
|
||||||
putCorners()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CropCornerRectangle {
|
|
||||||
id: topRightCorner
|
|
||||||
onXChanged: {
|
|
||||||
if (settingCorners) return
|
|
||||||
bottomRightCorner.x = x
|
|
||||||
}
|
|
||||||
onYChanged: {
|
|
||||||
if (settingCorners) return
|
|
||||||
topLeftCorner.y = y
|
|
||||||
}
|
|
||||||
onPressed: {
|
|
||||||
draggedCorner = topRight
|
|
||||||
}
|
|
||||||
onReleased: {
|
|
||||||
putCorners()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CropCornerRectangle {
|
|
||||||
id: bottomLeftCorner
|
|
||||||
onXChanged: {
|
|
||||||
if (settingCorners) return
|
|
||||||
topLeftCorner.x = x
|
|
||||||
}
|
|
||||||
onYChanged: {
|
|
||||||
if (settingCorners) return
|
|
||||||
bottomRightCorner.y = y
|
|
||||||
}
|
|
||||||
onPressed: {
|
|
||||||
draggedCorner = bottomLeft
|
|
||||||
}
|
|
||||||
onReleased: {
|
|
||||||
putCorners()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CropCornerRectangle {
|
|
||||||
id: bottomRightCorner
|
|
||||||
onXChanged: {
|
|
||||||
if (settingCorners) return
|
|
||||||
if (x < topLeftCorner.x + topLeftCorner.width) x = topLeftCorner.x + topLeftCorner.width
|
|
||||||
if (x > image.width - width) x = image.width - width
|
|
||||||
topRightCorner.x = x
|
|
||||||
|
|
||||||
selectorRectangle.adjustRectangleSize()
|
|
||||||
}
|
|
||||||
onYChanged: {
|
|
||||||
if (settingCorners) return
|
|
||||||
if (y < topRightCorner.y + topRightCorner.height) y = topRightCorner.y + topRightCorner.height
|
|
||||||
if (y > image.height - height) y = image.height - height
|
|
||||||
bottomLeftCorner.y = y
|
|
||||||
|
|
||||||
selectorRectangle.adjustRectangleSize()
|
|
||||||
}
|
|
||||||
onPressed: {
|
|
||||||
draggedCorner = bottomRight
|
|
||||||
}
|
|
||||||
onReleased: {
|
|
||||||
putCorners()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,6 +7,7 @@ import shared.controls 1.0
|
||||||
|
|
||||||
import StatusQ.Controls 0.1
|
import StatusQ.Controls 0.1
|
||||||
import StatusQ.Components 0.1
|
import StatusQ.Components 0.1
|
||||||
|
import StatusQ.Popups 0.1
|
||||||
import StatusQ.Core.Utils 0.1 as StatusQUtils
|
import StatusQ.Core.Utils 0.1 as StatusQUtils
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
@ -94,7 +95,12 @@ Item {
|
||||||
icon.width: d.getSize(8, 12, 20)
|
icon.width: d.getSize(8, 12, 20)
|
||||||
icon.height: d.getSize(8, 12, 20)
|
icon.height: d.getSize(8, 12, 20)
|
||||||
|
|
||||||
onClicked: Global.openChangeProfilePicPopup()
|
onClicked: {
|
||||||
|
if (!!root.store.profileLargeImage)
|
||||||
|
imageEditMenu.popup(this, mouse.x, mouse.y);
|
||||||
|
else
|
||||||
|
Global.openChangeProfilePicPopup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,4 +216,22 @@ Item {
|
||||||
publicKey: root.pubkey
|
publicKey: root.pubkey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StatusPopupMenu {
|
||||||
|
id: imageEditMenu
|
||||||
|
|
||||||
|
StatusMenuItem {
|
||||||
|
text: qsTr("Upload a file")
|
||||||
|
icon.name: "download"
|
||||||
|
iconRotation: 180
|
||||||
|
onTriggered: Global.openChangeProfilePicPopup()
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusMenuItem {
|
||||||
|
text: qsTr("Remove image")
|
||||||
|
type: StatusMenuItem.Danger
|
||||||
|
icon.name: "delete"
|
||||||
|
onTriggered: root.store.removeImage()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
import QtQuick 2.13
|
|
||||||
|
|
||||||
import utils 1.0
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
signal released()
|
|
||||||
signal pressed()
|
|
||||||
|
|
||||||
id: root
|
|
||||||
width: 25
|
|
||||||
height: 25
|
|
||||||
border.width: 2
|
|
||||||
border.color: Style.current.orange
|
|
||||||
color: Utils.setColorAlpha(Style.current.orange, 0.5)
|
|
||||||
|
|
||||||
Drag.active: dragArea.drag.active
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: dragArea
|
|
||||||
property int oldX
|
|
||||||
property int oldY
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
drag.target: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onReleased: root.released()
|
|
||||||
onPressed: root.pressed()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
import QtQuick 2.13
|
|
||||||
import QtQuick.Controls 2.13
|
|
||||||
import QtQuick.Layouts 1.13
|
|
||||||
|
|
||||||
import utils 1.0
|
|
||||||
|
|
||||||
import StatusQ.Controls 0.1
|
|
||||||
|
|
||||||
import "../controls"
|
|
||||||
import "."
|
|
||||||
|
|
||||||
// TODO: replace with StatusModal
|
|
||||||
ModalPopup {
|
|
||||||
property string selectedImage
|
|
||||||
property string ratio: "1:1"
|
|
||||||
property int aX: 0
|
|
||||||
property int aY: 0
|
|
||||||
property int bX: 0
|
|
||||||
property int bY: 0
|
|
||||||
signal cropFinished(aX: int, aY: int, bX: int, bY: int)
|
|
||||||
|
|
||||||
id: cropImageModal
|
|
||||||
width: image.width + 50
|
|
||||||
height: image.height + 170
|
|
||||||
title: qsTr("Crop your image (optional)")
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: image
|
|
||||||
width: 400
|
|
||||||
source: cropImageModal.selectedImage
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageCropper {
|
|
||||||
id: imageCropper
|
|
||||||
x: image.x
|
|
||||||
y: image.y
|
|
||||||
image: image
|
|
||||||
ratio: cropImageModal.ratio
|
|
||||||
onReadyChanged: {
|
|
||||||
if (ready) {
|
|
||||||
// cropImageModal.calculateCrop()
|
|
||||||
cropImageModal.aX = Qt.binding(function() {
|
|
||||||
const aXPercent = imageCropper.selectorRectangle.x / image.width
|
|
||||||
return Math.round(aXPercent * image.sourceSize.width)
|
|
||||||
})
|
|
||||||
cropImageModal.aY = Qt.binding(function() {
|
|
||||||
const aYPercent = imageCropper.selectorRectangle.y / image.height
|
|
||||||
return Math.round(aYPercent * image.sourceSize.height)
|
|
||||||
})
|
|
||||||
cropImageModal.bX = Qt.binding(function() {
|
|
||||||
const bXPercent = (imageCropper.selectorRectangle.x + imageCropper.selectorRectangle.width) / image.width
|
|
||||||
return Math.round(bXPercent * image.sourceSize.width)
|
|
||||||
})
|
|
||||||
cropImageModal.bY = Qt.binding(function() {
|
|
||||||
const bYPercent = (imageCropper.selectorRectangle.y + imageCropper.selectorRectangle.height) / image.height
|
|
||||||
return Math.round(bYPercent * image.sourceSize.height)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
footer: StatusButton {
|
|
||||||
id: doneBtn
|
|
||||||
text: qsTr("Finish")
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
onClicked: {
|
|
||||||
const aXPercent = imageCropper.selectorRectangle.x / image.width
|
|
||||||
const aYPercent = imageCropper.selectorRectangle.y / image.height
|
|
||||||
const bXPercent = (imageCropper.selectorRectangle.x + imageCropper.selectorRectangle.width) / image.width
|
|
||||||
const bYPercent = (imageCropper.selectorRectangle.y + imageCropper.selectorRectangle.height) / image.height
|
|
||||||
|
|
||||||
|
|
||||||
const aX = Math.round(aXPercent * image.sourceSize.width)
|
|
||||||
const aY = Math.round(aYPercent * image.sourceSize.height)
|
|
||||||
|
|
||||||
const bX = Math.round(bXPercent * image.sourceSize.width)
|
|
||||||
const bY = Math.round(bYPercent * image.sourceSize.height)
|
|
||||||
|
|
||||||
cropImageModal.cropFinished(aX, aY, bX, bY)
|
|
||||||
cropImageModal.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue