Add a "Dismissed contact requests" tab in the Contacts panel (#17021)

* chore(ContactPanel): add tooltips to contact panel buttons

* feat(contacts): add a tab for dismissed contacts and a button to undo

Fixes #16844

Adds a tab in the Messaging>Contacts page that shows the dismissed contact requests.
it has a button to undo the rejection. That is simply a call to accept the old contact request, which then makes the two users mutual contacts
This commit is contained in:
Jonathan Rainville 2025-01-14 10:18:31 -05:00 committed by GitHub
parent 866a1a6020
commit a6e6546a08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 78 additions and 0 deletions

View File

@ -42,6 +42,7 @@ Item {
mutualContactsModel: adaptor.mutualContacts mutualContactsModel: adaptor.mutualContacts
blockedContactsModel: adaptor.blockedContacts blockedContactsModel: adaptor.blockedContacts
pendingContactsModel: adaptor.pendingContacts pendingContactsModel: adaptor.pendingContacts
dismissedReceivedRequestContactsModel: adaptor.dismissedReceivedRequestContactsModel
pendingReceivedContactsCount: adaptor.pendingReceivedRequestContacts.count pendingReceivedContactsCount: adaptor.pendingReceivedRequestContacts.count
} }

View File

@ -57,6 +57,7 @@ StatusSectionLayout {
property var blockedContactsModel property var blockedContactsModel
property var pendingContactsModel property var pendingContactsModel
property int pendingReceivedContactsCount property int pendingReceivedContactsCount
property var dismissedReceivedRequestContactsModel
required property bool isCentralizedMetricsEnabled required property bool isCentralizedMetricsEnabled
@ -246,6 +247,7 @@ StatusSectionLayout {
blockedContactsModel: root.blockedContactsModel blockedContactsModel: root.blockedContactsModel
pendingContactsModel: root.pendingContactsModel pendingContactsModel: root.pendingContactsModel
pendingReceivedContactsCount: root.pendingReceivedContactsCount pendingReceivedContactsCount: root.pendingReceivedContactsCount
dismissedReceivedRequestContactsModel: root.dismissedReceivedRequestContactsModel
} }
} }

View File

@ -12,12 +12,14 @@ ContactListItemDelegate {
property bool showSendMessageButton: false property bool showSendMessageButton: false
property bool showRejectContactRequestButton: false property bool showRejectContactRequestButton: false
property bool showAcceptContactRequestButton: false property bool showAcceptContactRequestButton: false
property bool showRemoveRejectionButton: false
property string contactText: "" property string contactText: ""
signal contextMenuRequested signal contextMenuRequested
signal sendMessageRequested signal sendMessageRequested
signal acceptContactRequested signal acceptContactRequested
signal rejectRequestRequested signal rejectRequestRequested
signal removeRejectionRequested
icon.width: 40 icon.width: 40
icon.height: 40 icon.height: 40
@ -32,6 +34,11 @@ ContactListItemDelegate {
icon.color: Theme.palette.directColor1 icon.color: Theme.palette.directColor1
tooltip.text: qsTr("Send message") tooltip.text: qsTr("Send message")
onClicked: root.sendMessageRequested() onClicked: root.sendMessageRequested()
StatusToolTip {
text: qsTr('Send message')
visible: parent.hovered
}
}, },
StatusFlatRoundButton { StatusFlatRoundButton {
objectName: "declineBtn" objectName: "declineBtn"
@ -42,6 +49,11 @@ ContactListItemDelegate {
icon.color: Theme.palette.dangerColor1 icon.color: Theme.palette.dangerColor1
tooltip.text: qsTr("Reject") tooltip.text: qsTr("Reject")
onClicked: root.rejectRequestRequested() onClicked: root.rejectRequestRequested()
StatusToolTip {
text: qsTr('Decline Request')
visible: parent.hovered
}
}, },
StatusFlatRoundButton { StatusFlatRoundButton {
objectName: "acceptBtn" objectName: "acceptBtn"
@ -52,6 +64,25 @@ ContactListItemDelegate {
icon.color: Theme.palette.successColor1 icon.color: Theme.palette.successColor1
tooltip.text: qsTr("Accept") tooltip.text: qsTr("Accept")
onClicked: root.acceptContactRequested() onClicked: root.acceptContactRequested()
StatusToolTip {
text: qsTr('Accept Request')
visible: parent.hovered
}
},
StatusFlatRoundButton {
objectName: "removeRejectBtn"
visible: showRemoveRejectionButton
width: visible ? 32 : 0
height: visible ? 32 : 0
icon.name: "cancel"
icon.color: Theme.palette.dangerColor1
onClicked: root.removeRejectionRequested()
StatusToolTip {
text: qsTr('Remove Rejection')
visible: parent.hovered
}
}, },
StatusBaseText { StatusBaseText {
text: root.contactText text: root.contactText

View File

@ -16,6 +16,7 @@ StatusListView {
signal sendMessageRequested(string publicKey) signal sendMessageRequested(string publicKey)
signal acceptContactRequested(string publicKey) signal acceptContactRequested(string publicKey)
signal rejectContactRequested(string publicKey) signal rejectContactRequested(string publicKey)
signal rejectionRemoved(string publicKey)
objectName: "ContactListPanel_ListView" objectName: "ContactListPanel_ListView"
@ -32,6 +33,7 @@ StatusListView {
showRejectContactRequestButton: showRejectContactRequestButton:
model.contactRequest === Constants.ContactRequestState.Received model.contactRequest === Constants.ContactRequestState.Received
showAcceptContactRequestButton: showRejectContactRequestButton showAcceptContactRequestButton: showRejectContactRequestButton
showRemoveRejectionButton: model.contactRequest === Constants.ContactRequestState.Dismissed
contactText: model.contactRequest === Constants.ContactRequestState.Sent contactText: model.contactRequest === Constants.ContactRequestState.Sent
? qsTr("Contact Request Sent") : "" ? qsTr("Contact Request Sent") : ""
@ -41,5 +43,6 @@ StatusListView {
onSendMessageRequested: root.sendMessageRequested(model.pubKey) onSendMessageRequested: root.sendMessageRequested(model.pubKey)
onAcceptContactRequested: root.acceptContactRequested(model.pubKey) onAcceptContactRequested: root.acceptContactRequested(model.pubKey)
onRejectRequestRequested: root.rejectContactRequested(model.pubKey) onRejectRequestRequested: root.rejectContactRequested(model.pubKey)
onRemoveRejectionRequested: root.rejectionRemoved(model.pubKey)
} }
} }

View File

@ -31,6 +31,7 @@ SettingsContentBase {
required property var blockedContactsModel required property var blockedContactsModel
required property var pendingContactsModel required property var pendingContactsModel
required property int pendingReceivedContactsCount required property int pendingReceivedContactsCount
required property var dismissedReceivedRequestContactsModel
property alias searchStr: searchBox.text property alias searchStr: searchBox.text
@ -87,6 +88,13 @@ SettingsContentBase {
text: qsTr("Pending Requests") text: qsTr("Pending Requests")
badge.value: root.pendingReceivedContactsCount badge.value: root.pendingReceivedContactsCount
} }
StatusTabButton {
objectName: "ContactsView_DismissedRequest_Button"
width: implicitWidth
enabled: !root.dismissedReceivedRequestContactsModel.ModelCount.empty
text: qsTr("Dismissed Requests")
}
StatusTabButton { StatusTabButton {
objectName: "ContactsView_Blocked_Button" objectName: "ContactsView_Blocked_Button"
@ -175,6 +183,21 @@ SettingsContentBase {
ViewSection.CurrentLabelAtStart ViewSection.CurrentLabelAtStart
} }
ContactsList {
model: SortFilterProxyModel {
sourceModel: root.dismissedReceivedRequestContactsModel
filters: UserSearchFilter {
searchString: searchBox.text
}
sorters: StringSorter {
roleName: "preferredDisplayName"
caseSensitivity: Qt.CaseInsensitive
}
}
}
ContactsList { ContactsList {
model: SortFilterProxyModel { model: SortFilterProxyModel {
sourceModel: root.blockedContactsModel sourceModel: root.blockedContactsModel
@ -198,6 +221,7 @@ SettingsContentBase {
onSendMessageRequested: root.contactsStore.joinPrivateChat(publicKey) onSendMessageRequested: root.contactsStore.joinPrivateChat(publicKey)
onAcceptContactRequested: root.contactsStore.acceptContactRequest(publicKey, "") onAcceptContactRequested: root.contactsStore.acceptContactRequest(publicKey, "")
onRejectContactRequested: root.contactsStore.dismissContactRequest(publicKey, "") onRejectContactRequested: root.contactsStore.dismissContactRequest(publicKey, "")
onRejectionRemoved: root.contactsStore.acceptContactRequest(publicKey, "")
} }
component SectionComponent: Rectangle { component SectionComponent: Rectangle {

View File

@ -1752,6 +1752,7 @@ Item {
blockedContactsModel: contactsModelAdaptor.blockedContacts blockedContactsModel: contactsModelAdaptor.blockedContacts
pendingContactsModel: contactsModelAdaptor.pendingContacts pendingContactsModel: contactsModelAdaptor.pendingContacts
pendingReceivedContactsCount: contactsModelAdaptor.pendingReceivedRequestContacts.count pendingReceivedContactsCount: contactsModelAdaptor.pendingReceivedRequestContacts.count
dismissedReceivedRequestContactsModel: contactsModelAdaptor.dimissedReceivedRequestContacts
Binding on settingsSubsection { Binding on settingsSubsection {
value: profileLoader.settingsSubsection value: profileLoader.settingsSubsection

View File

@ -92,4 +92,19 @@ QObject {
} }
] ]
} }
readonly property var dimissedReceivedRequestContacts: SortFilterProxyModel {
sourceModel: root.allContacts ?? null
filters: [
ValueFilter {
roleName: "contactRequest"
value: Constants.ContactRequestState.Dismissed
},
ValueFilter {
roleName: "isBlocked"
value: false
}
]
}
} }

View File

@ -500,6 +500,7 @@ QtObject {
readonly property int mutualContacts: 0 readonly property int mutualContacts: 0
readonly property int pendingContacts: 1 readonly property int pendingContacts: 1
readonly property int blockedContacts: 2 readonly property int blockedContacts: 2
readonly property int rejectedReceivedContactRequest: 3
} }
readonly property QtObject keypair: QtObject { readonly property QtObject keypair: QtObject {