feat(Profile flow): Block/unblock user

- implement block and unblock user popups with optional "Remove contact" and "Remove ID verification" check boxes
- emit (combined) toasts

Fixes #13522
This commit is contained in:
Lukáš Tinkl 2024-02-20 19:52:07 +01:00 committed by Lukáš Tinkl
parent b0e24b0396
commit 343cfa0982
8 changed files with 137 additions and 140 deletions

View File

@ -31,7 +31,7 @@ import StatusQ.Core.Theme 0.1
Control {
id: root
implicitWidth: 614
implicitHeight: rowContent.height
padding: 16
/*!
\qmlproperty alias StatusWarningBox::text
@ -64,7 +64,10 @@ Control {
This property sets the StatusWarningBox text color.
*/
property color textColor: Theme.palette.warningColor1
/*!
\qmlproperty int StatusWarningBox::textSize
This property sets the StatusWarningBox text pixel size
*/
property int textSize: Theme.primaryTextFontSize
background: Rectangle {
@ -80,19 +83,8 @@ Control {
}
}
contentItem: Item {
id: rowContent
width: parent.width
height: (row.height+32)//xlPadding
RowLayout {
id: row
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
anchors.verticalCenter: parent.verticalCenter
height: warningText.contentHeight
spacing: 6
contentItem: RowLayout {
spacing: 8
StatusIcon {
Layout.alignment: Qt.AlignTop
icon: root.icon
@ -108,6 +100,5 @@ Control {
color: root.textColor
}
}
}
}

View File

@ -141,12 +141,12 @@ QtObject {
openPopup(markAsUntrustedComponent, {publicKey, contactDetails})
}
function openBlockContactPopup(publicKey: string, contactName: string) {
openPopup(blockContactConfirmationComponent, {contactName: contactName, contactAddress: publicKey})
function openBlockContactPopup(publicKey: string, contactDetails) {
openPopup(blockContactConfirmationComponent, {publicKey, contactDetails})
}
function openUnblockContactPopup(publicKey: string, contactName: string) {
openPopup(unblockContactConfirmationComponent, {contactName: contactName, contactAddress: publicKey})
function openUnblockContactPopup(publicKey: string, contactDetails) {
openPopup(unblockContactConfirmationComponent, {publicKey, contactDetails})
}
function openChangeProfilePicPopup(cb) {
@ -546,8 +546,9 @@ QtObject {
Component {
id: unblockContactConfirmationComponent
UnblockContactConfirmationDialog {
onUnblockButtonClicked: {
rootStore.contactStore.unblockContact(contactAddress)
onAccepted: {
rootStore.contactStore.unblockContact(publicKey)
Global.displaySuccessToastMessage(qsTr("%1 unblocked").arg(mainDisplayName))
close()
}
onClosed: destroy()
@ -557,8 +558,13 @@ QtObject {
Component {
id: blockContactConfirmationComponent
BlockContactConfirmationDialog {
onBlockButtonClicked: {
rootStore.contactStore.blockContact(contactAddress)
onAccepted: {
rootStore.contactStore.blockContact(publicKey)
if (removeIDVerification)
rootStore.contactStore.cancelVerificationRequest(publicKey)
if (removeContact)
rootStore.contactStore.removeContact(publicKey)
Global.displaySuccessToastMessage(qsTr("%1 blocked").arg(mainDisplayName))
close()
}
onClosed: destroy()

View File

@ -1,48 +1,78 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml.Models 2.15
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import utils 1.0
import StatusQ.Controls 0.1
CommonContactDialog {
id: root
import "../panels"
import "."
readonly property bool removeIDVerification: ctrlRemoveIDVerification.checked
readonly property bool removeContact: ctrlRemoveContact.checked
// TODO: replace with StatusModal
ModalPopup {
id: blockContactConfirmationDialog
height: 237
width: 400
title: qsTr("Block user")
property string contactAddress: ""
property string contactName: ""
signal blockButtonClicked()
title: qsTr("Block User")
StyledText {
text: qsTr("Blocking will stop new messages from reaching you from %1.").arg(contactName)
font.pixelSize: 15
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.WordWrap
readonly property var d: QtObject {
id: d
readonly property int outgoingVerificationStatus: contactDetails.verificationStatus
readonly property int incomingVerificationStatus: contactDetails.incomingVerificationStatus
readonly property bool isVerificationRequestReceived: incomingVerificationStatus === Constants.verificationStatus.verifying ||
incomingVerificationStatus === Constants.verificationStatus.verified
readonly property bool isTrusted: outgoingVerificationStatus === Constants.verificationStatus.trusted ||
incomingVerificationStatus === Constants.verificationStatus.trusted
}
footer: Item {
id: footerContainer
width: parent.width
height: children[0].height
StatusBaseText {
Layout.fillWidth: true
wrapMode: Text.WordWrap
lineHeight: 22
lineHeightMode: Text.FixedHeight
text: qsTr("You will not see %1s messages but %1 can still see your messages in mutual group chats and communities. %1 will be unable to message you.").arg(mainDisplayName)
}
StatusWarningBox {
Layout.fillWidth: true
Layout.topMargin: Style.current.padding
icon: "warning"
iconColor: Theme.palette.dangerColor1
bgColor: Theme.palette.dangerColor1
borderColor: Theme.palette.dangerColor2
textColor: Theme.palette.directColor1
textSize: Theme.secondaryTextFontSize
text: qsTr("Blocking a user purges the database of all messages that youve previously received from %1 in all contexts. This can take a moment.").arg(mainDisplayName)
}
StatusCheckBox {
Layout.topMargin: Style.current.halfPadding
id: ctrlRemoveContact
visible: contactDetails.isContact
checked: visible
enabled: false
text: qsTr("Remove contact")
}
StatusCheckBox {
id: ctrlRemoveIDVerification
visible: contactDetails.isContact && !d.isTrusted && d.isVerificationRequestReceived
checked: visible
enabled: false
text: qsTr("Remove ID verification")
}
rightButtons: ObjectModel {
StatusFlatButton {
text: qsTr("Cancel")
onClicked: root.close()
}
StatusButton {
anchors.right: parent.right
anchors.rightMargin: Style.current.smallPadding
type: StatusBaseButton.Type.Danger
text: qsTr("Block User")
anchors.bottom: parent.bottom
onClicked: blockContactConfirmationDialog.blockButtonClicked()
text: qsTr("Block")
onClicked: root.accepted()
}
}
}

View File

@ -8,7 +8,6 @@ import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import utils 1.0
import shared.controls 1.0
CommonContactDialog {
id: root

View File

@ -1,49 +1,33 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml.Models 2.15
import utils 1.0
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import "../panels"
import "./"
CommonContactDialog {
id: root
// TODO: replace with StatusModal
ModalPopup {
id: unblockContactConfirmationDialog
height: 237
width: 400
title: qsTr("Unblock user")
property string contactAddress: ""
property string contactName: ""
signal unblockButtonClicked()
title: qsTr("Unblock User")
StyledText {
text: qsTr("Unblocking will allow new messages you received from %1 to reach you.").arg(contactName)
font.pixelSize: 15
anchors.left: parent.left
anchors.right: parent.right
StatusBaseText {
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: qsTr("Unblocking %1 will allow new messages you receive from %1 to reach you.").arg(mainDisplayName)
}
footer: Item {
id: footerContainer
width: parent.width
height: children[0].height
rightButtons: ObjectModel {
StatusFlatButton {
text: qsTr("Cancel")
onClicked: root.close()
}
StatusButton {
anchors.right: parent.right
anchors.rightMargin: Style.current.smallPadding
type: StatusBaseButton.Type.Danger
text: qsTr("Unblock User")
anchors.bottom: parent.bottom
onClicked: unblockContactConfirmationDialog.unblockButtonClicked()
text: qsTr("Unblock")
onClicked: root.accepted()
}
}
}

View File

@ -49,10 +49,10 @@ Pane {
QtObject {
id: d
property var contactDetails: Utils.getContactDetailsAsJson(root.publicKey, !isCurrentUser, !isCurrentUser)
property var contactDetails: Utils.getContactDetailsAsJson(root.publicKey, !isCurrentUser, !isCurrentUser, true)
function reload() {
contactDetails = Utils.getContactDetailsAsJson(root.publicKey, !isCurrentUser, !isCurrentUser)
contactDetails = Utils.getContactDetailsAsJson(root.publicKey, !isCurrentUser, !isCurrentUser, true)
}
readonly property bool isCurrentUser: root.profileStore.pubkey === root.publicKey
@ -183,8 +183,8 @@ Pane {
StatusButton {
size: StatusButton.Size.Small
type: StatusBaseButton.Type.Danger
text: qsTr("Block User")
onClicked: Global.blockContactRequested(root.publicKey, d.mainDisplayName)
text: qsTr("Block user")
onClicked: Global.blockContactRequested(root.publicKey, d.contactDetails)
}
}
@ -192,8 +192,8 @@ Pane {
id: btnUnblockUserComponent
StatusButton {
size: StatusButton.Size.Small
text: qsTr("Unblock")
onClicked: Global.unblockContactRequested(root.publicKey, d.mainDisplayName)
text: qsTr("Unblock user")
onClicked: Global.unblockContactRequested(root.publicKey, d.contactDetails)
}
}
@ -327,7 +327,7 @@ Pane {
if (d.isCurrentUser)
return btnEditProfileComponent
// blocked contact
// blocked user
if (d.isBlocked)
return btnUnblockUserComponent
@ -335,10 +335,6 @@ Pane {
if (d.contactRequestState === Constants.ContactRequestState.Received)
return btnAcceptContactRequestComponent
// block user
if (d.contactDetails.trustStatus === Constants.trustStatus.untrustworthy)
return btnBlockUserComponent
// mutual contact
if (d.isContact || d.contactRequestState === Constants.ContactRequestState.Mutual)
return btnSendMessageComponent
@ -434,6 +430,15 @@ Pane {
}
}
StatusMenuSeparator {}
StatusAction {
text: qsTr("Remove ID verification")
icon.name: "warning"
type: StatusAction.Type.Danger
enabled: d.isContact && d.isTrusted
onTriggered: {
removeVerificationConfirmationDialog.open()
}
}
StatusAction {
text: qsTr("Remove nickname")
icon.name: "delete"
@ -441,15 +446,6 @@ Pane {
enabled: !d.isCurrentUser && !!d.contactDetails.localNickname
onTriggered: root.contactsStore.changeContactNickname(root.publicKey, "", d.optionalDisplayName, true)
}
StatusAction {
text: qsTr("Unblock user")
icon.name: "cancel"
type: StatusAction.Type.Danger
enabled: d.isBlocked
onTriggered: {
Global.unblockContactRequested(root.publicKey, d.mainDisplayName)
}
}
StatusAction {
text: qsTr("Mark as untrusted")
icon.name: "warning"
@ -468,15 +464,6 @@ Pane {
root.contactsStore.removeTrustStatus(root.publicKey)
}
}
StatusAction {
text: qsTr("Remove ID verification")
icon.name: "warning"
type: StatusAction.Type.Danger
enabled: d.isContact && d.isTrusted
onTriggered: {
removeVerificationConfirmationDialog.open()
}
}
StatusAction {
text: qsTr("Remove contact")
icon.name: "remove-contact"
@ -492,7 +479,7 @@ Pane {
type: StatusAction.Type.Danger
enabled: !d.isBlocked
onTriggered: {
Global.blockContactRequested(root.publicKey, d.mainDisplayName)
Global.blockContactRequested(root.publicKey, d.contactDetails)
}
}
}

View File

@ -211,7 +211,7 @@ StatusMenu {
icon.name: "cancel"
type: StatusAction.Type.Danger
enabled: !root.isMe && root.isBlockedContact && !root.isBridgedAccount
onTriggered: Global.unblockContactRequested(root.selectedUserPublicKey, root.selectedUserDisplayName)
onTriggered: Global.unblockContactRequested(root.selectedUserPublicKey, root.contactDetails)
}
// TODO Remove ID verification + confirmation dialog
@ -252,6 +252,6 @@ StatusMenu {
icon.name: "cancel"
type: StatusAction.Type.Danger
enabled: !root.isMe && !root.isBlockedContact && !root.isBridgedAccount
onTriggered: Global.blockContactRequested(root.selectedUserPublicKey, root.selectedUserDisplayName)
onTriggered: Global.blockContactRequested(root.selectedUserPublicKey, root.contactDetails)
}
}

View File

@ -22,8 +22,8 @@ QtObject {
signal openCreateChatView()
signal closeCreateChatView()
signal blockContactRequested(string publicKey, string contactName)
signal unblockContactRequested(string publicKey, string contactName)
signal blockContactRequested(string publicKey, var contactDetails)
signal unblockContactRequested(string publicKey, var contactDetails)
signal displayToastMessage(string title, string subTitle, string icon, bool loading, int ephNotifType, string url)
signal displayToastWithActionMessage(string title, string subTitle, string icon, string iconColor, bool loading, int ephNotifType, int actionType, string data)