Skip to content

Commit

Permalink
feat: Improvements for community admins
Browse files Browse the repository at this point in the history
- add ability to copy display name of a message author
- add possibility to search for a member by a un/compressed chat key
- adjust the search field placeholder text to "Search by member name or
chat key"

- update SB with some more variations
- cleanup some the signal handling

Fixes #16790
  • Loading branch information
caybro committed Dec 4, 2024
1 parent 5bf4ba2 commit 9596d61
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 103 deletions.
15 changes: 14 additions & 1 deletion storybook/pages/StatusMessagePage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ SplitView {
trustIndicator: StatusContactVerificationIcons.TrustedType.None
outgoingStatus: StatusMessage.OutgoingStatus.Delivered
}
ListElement {
timestamp: 1667937930159
senderId: "zqdeadbeef86"
senderDisplayName: "8⃣6⃣.stateofus.eth"
contentType: StatusMessage.ContentType.Text
message: "Test message for a user with emoji + ENS name"
isContact: false
isAReply: false
trustIndicator: StatusContactVerificationIcons.TrustedType.None
outgoingStatus: StatusMessage.OutgoingStatus.Delivered
}
ListElement {
timestamp: 1719769718000
senderId: "zq123456790"
Expand Down Expand Up @@ -186,6 +197,7 @@ SplitView {
SplitView.fillWidth: true
SplitView.fillHeight: true
color: Theme.palette.statusAppLayout.rightPanelBackgroundColor
clip: true

ListView {
anchors.margins: 16
Expand Down Expand Up @@ -236,7 +248,7 @@ SplitView {
onReplyProfileClicked: logs.logEvent("StatusMessage::replyProfileClicked")
onReplyMessageClicked: logs.logEvent("StatusMessage::replyMessageClicked")
onResendClicked: logs.logEvent("StatusMessage::resendClicked")
onLinkActivated: logs.logEvent("StatusMessage::linkActivated" + link)
onLinkActivated: logs.logEvent("StatusMessage::linkActivated", ["link"], arguments)
onImageClicked: logs.logEvent("StatusMessage::imageClicked")
}
}
Expand All @@ -254,3 +266,4 @@ SplitView {
}

// category: Components
// status: good
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import QtQuick 2.14
import QtQuick 2.15

import StatusQ.Core 0.1
import StatusQ.Controls 0.1
Expand Down
15 changes: 8 additions & 7 deletions ui/StatusQ/src/StatusQ/Components/StatusMemberListItem.qml
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,13 @@ ItemDelegate {
/*!
\qmlproperty string StatusMemberListItem::status
This property holds the connectivity status of the member represented.
0 - offline
1 - online
2 - doNotDisturb
3 - idle
int unknown: -1
int inactive: 0
int online: 1
*/
// FIXME: move Constants.userStatus from status-desktop
// FIXME: move Constants.onlineStatus from status-desktop
property int status: 0
/*!
\qmlproperty string StatusMemberListItem::isAdmin
Expand Down Expand Up @@ -228,7 +229,7 @@ ItemDelegate {

StatusToolTip {
text: parent.text
delay: 0
delay: 50
visible: parent.truncated && primaryTextHandler.hovered
}
}
Expand All @@ -252,7 +253,7 @@ ItemDelegate {

StatusToolTip {
text: parent.text
delay: 0
delay: 50
visible: parent.truncated && secondaryTextHandler.hovered
}
}
Expand Down
5 changes: 2 additions & 3 deletions ui/StatusQ/src/StatusQ/Components/StatusMessage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,8 @@ Control {
property StatusMessageDetails messageDetails: StatusMessageDetails {}
property StatusMessageDetails replyDetails: StatusMessageDetails {}

signal clicked(var sender, var mouse)
signal profilePictureClicked(var sender, var mouse)
signal senderNameClicked(var sender, var mouse)
signal senderNameClicked(var sender)
signal replyProfileClicked(var sender, var mouse)
signal replyMessageClicked(var mouse)

Expand Down Expand Up @@ -265,7 +264,7 @@ Control {
amISender: root.messageDetails.amISender
messageOriginInfo: root.messageDetails.messageOriginInfo
resendError: root.messageDetails.amISender ? root.resendError : ""
onClicked: root.senderNameClicked(sender, mouse)
onClicked: (sender) => root.senderNameClicked(sender)
onResendClicked: root.resendClicked()
timestamp: root.timestamp
showFullTimestamp: root.isInPinnedPopup
Expand Down
41 changes: 24 additions & 17 deletions ui/StatusQ/src/StatusQ/Components/StatusMessageHeader.qml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import QtQuick 2.15
import QtQuick.Layouts 1.15

import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Expand Down Expand Up @@ -28,7 +28,7 @@ Item {
property int outgoingStatus: StatusMessage.OutgoingStatus.Unknown
property bool showOutgointStatusLabel: false

signal clicked(var sender, var mouse)
signal clicked(var sender)
signal resendClicked()

implicitHeight: layout.implicitHeight
Expand All @@ -46,29 +46,39 @@ Item {
spacing: 4
width: parent.width

StatusBaseText {
TextEdit {
id: primaryDisplayName
objectName: "StatusMessageHeader_DisplayName"
verticalAlignment: Text.AlignVCenter
Layout.fillWidth: true
Layout.maximumWidth: Math.ceil(implicitWidth)
Layout.bottomMargin: 2 // offset for the underline to stay vertically centered
font.weight: Font.Medium
font.underline: mouseArea.containsMouse
font.underline: root.displayNameClickable && hhandler.hovered
font.family: Theme.baseFont.name
font.pixelSize: Theme.primaryTextFontSize
wrapMode: Text.WordWrap
color: Theme.palette.primaryColor1
selectionColor: Theme.palette.primaryColor2
selectedTextColor: Theme.palette.primaryColor3
text: root.amISender ? qsTr("You") : Emoji.parse(root.sender.displayName)
MouseArea {
id: mouseArea
anchors.fill: parent
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
readOnly: true
selectByMouse: true
textFormat: TextEdit.AutoText

// to make the text easier to select, but w/o inflating the spacing with other items in the parent RowLayout
leftPadding: 4
rightPadding: 4
Layout.leftMargin: -4
Layout.rightMargin: -4

HoverHandler {
id: hhandler
cursorShape: !!parent.selectedText ? Qt.IBeamCursor : root.displayNameClickable ? Qt.PointingHandCursor : undefined
}
TapHandler {
enabled: root.displayNameClickable
hoverEnabled: true
onClicked: {
root.clicked(this, mouse)
}
onSingleTapped: root.clicked(this)
}
}

Expand All @@ -77,7 +87,6 @@ Item {
active: root.messageOriginInfo
asynchronous: true
sourceComponent: StatusBaseText {
id: messageOriginInfo
verticalAlignment: Text.AlignVCenter
color: Theme.palette.baseColor1
font.pixelSize: Theme.asideTextFontSize
Expand All @@ -90,7 +99,6 @@ Item {
active: !root.amISender
asynchronous: true
sourceComponent: StatusContactVerificationIcons {
id: verificationIcons
isContact: root.isContact
trustIndicator: root.trustIndicator
}
Expand Down Expand Up @@ -148,7 +156,6 @@ Item {
Component {
id: dotComponent
StatusBaseText {
id: dot
verticalAlignment: Text.AlignVCenter
font.pixelSize: Theme.asideTextFontSize
color: Theme.palette.baseColor1
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import QtQuick 2.0
import QtQuick 2.15

import StatusQ.Core 0.1

QtObject {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import QtQuick 2.14
import QtQuick.Shapes 1.13
import QtQuick.Layouts 1.14
import QtQuick 2.15
import QtQuick.Shapes 1.15
import QtQuick.Layouts 1.15

import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Expand Down
25 changes: 0 additions & 25 deletions ui/app/AppLayouts/Communities/panels/MembersSettingsPanel.qml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ SettingsPage {
property int memberRole
property bool editable: true

signal membershipRequestsClicked()
signal kickUserClicked(string id)
signal banUserClicked(string id, bool deleteAllMessages)
signal unbanUserClicked(string id)
Expand Down Expand Up @@ -123,12 +122,6 @@ SettingsPage {
rootStore: root.rootStore
utilsStore: root.utilsStore
memberRole: root.memberRole
placeholderText: {
if (root.membersModel.ModelCount.count === 0)
return qsTr("No members to search")

return qsTr("Search %1's %n member(s)", "", root.membersModel ? root.membersModel.ModelCount.count : 0).arg(root.communityName)
}
panelType: MembersTabPanel.TabType.AllMembers

Layout.fillWidth: true
Expand Down Expand Up @@ -156,12 +149,6 @@ SettingsPage {
rootStore: root.rootStore
utilsStore: root.utilsStore
memberRole: root.memberRole
placeholderText: {
if (root.pendingMembersModel.ModelCount.count === 0)
return qsTr("No pending requests to search")

return qsTr("Search %1's %n pending request(s)", "", root.pendingMembersModel.ModelCount.count).arg(root.communityName)
}
panelType: MembersTabPanel.TabType.PendingRequests

Layout.fillWidth: true
Expand All @@ -176,12 +163,6 @@ SettingsPage {
rootStore: root.rootStore
utilsStore: root.utilsStore
memberRole: root.memberRole
placeholderText: {
if (root.declinedMembersModel.ModelCount.count === 0)
return qsTr("No rejected members to search")

return qsTr("Search %1's %n rejected member(s)", "", root.declinedMembersModel.ModelCount.count).arg(root.communityName)
}
panelType: MembersTabPanel.TabType.DeclinedRequests

Layout.fillWidth: true
Expand All @@ -195,12 +176,6 @@ SettingsPage {
rootStore: root.rootStore
utilsStore: root.utilsStore
memberRole: root.memberRole
placeholderText: {
if (root.bannedMembersModel.ModelCount.count === 0)
return qsTr("No banned members to search")

return qsTr("Search %1's %n banned member(s)", "", root.bannedMembersModel.ModelCount.count).arg(root.communityName)
}
panelType: MembersTabPanel.TabType.BannedMembers

Layout.fillWidth: true
Expand Down
63 changes: 36 additions & 27 deletions ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import SortFilterProxyModel 0.2
Item {
id: root

property string placeholderText
property string placeholderText: qsTr("Search by member name or chat key")
property var model
property RootStore rootStore
property SharedStores.UtilsStore utilsStore
Expand Down Expand Up @@ -60,7 +60,7 @@ Item {
Layout.preferredWidth: 400
Layout.leftMargin: 12
placeholderText: root.placeholderText
enabled: !!model && model.count > 0
enabled: !!root.model && !root.model.ModelCount.empty
}

StatusListView {
Expand All @@ -71,8 +71,16 @@ Item {
Layout.fillHeight: true

model: SortFilterProxyModel {
id: filteredModel
sourceModel: root.model

function searchPredicate(ensName, displayName, aliasName) {
const lowerCaseSearchString = memberSearch.text.toLowerCase()
const secondaryName = ProfileUtils.displayName("", ensName, displayName, aliasName)

return secondaryName.toLowerCase().includes(lowerCaseSearchString)
}

sorters : [
StringSorter {
roleName: "preferredDisplayName"
Expand All @@ -81,21 +89,23 @@ Item {
]

filters: AnyOf {
enabled: memberSearch.text !== ""
// substring search for either nickname or the other primary/secondary display name
SearchFilter {
roleName: "localNickname"
searchPhrase: memberSearch.text
}
SearchFilter {
roleName: "displayName"
searchPhrase: memberSearch.text
}
SearchFilter {
roleName: "ensName"
searchPhrase: memberSearch.text
FastExpressionFilter {
expression: {
memberSearch.text
return filteredModel.searchPredicate(model.ensName, model.displayName, model.alias)
}
expectedRoles: ["ensName", "displayName", "alias"]
}
SearchFilter {
roleName: "alias"
searchPhrase: memberSearch.text
// exact search for the full key
ValueFilter {
roleName: "compressedPubKey"
value: memberSearch.text
}
}
}
Expand Down Expand Up @@ -346,25 +356,24 @@ Item {
ProfileContextMenu {
id: memberContextMenuView

property string pubKey
required property string pubKey

onOpenProfileClicked: Global.openProfilePopup(memberContextMenuView.pubKey, null)
onOpenProfileClicked: Global.openProfilePopup(pubKey, null)
onCreateOneToOneChat: {
Global.changeAppSectionBySectionType(Constants.appSection.chat)
root.rootStore.chatCommunitySectionModule.createOneToOneChat("", membersContextMenuView.pubKey, "")
root.rootStore.chatCommunitySectionModule.createOneToOneChat("", pubKey, "")
}
onReviewContactRequest: Global.openReviewContactRequestPopup(memberContextMenuView.pubKey, null)
onSendContactRequest: Global.openContactRequestPopup(memberContextMenuView.pubKey, null)
onEditNickname: Global.openNicknamePopupRequested(memberContextMenuView.pubKey, null)
onRemoveNickname: root.rootStore.contactsStore.changeContactNickname(memberContextMenuView.pubKey,
"", memberContextMenuView.displayName, true)
onUnblockContact: Global.unblockContactRequested(memberContextMenuView.pubKey)
onMarkAsUntrusted: Global.markAsUntrustedRequested(memberContextMenuView.pubKey)
onRemoveTrustStatus: root.rootStore.contactsStore.removeTrustStatus(memberContextMenuView.pubKey)
onRemoveContact: Global.removeContactRequested(memberContextMenuView.pubKey)
onBlockContact: Global.blockContactRequested(memberContextMenuView.pubKey)
onMarkAsTrusted: Global.openMarkAsIDVerifiedPopup(memberContextMenuView.pubKey, null)
onRemoveTrustedMark: Global.openRemoveIDVerificationDialog(memberContextMenuView.pubKey, null)
onReviewContactRequest: Global.openReviewContactRequestPopup(pubKey, null)
onSendContactRequest: Global.openContactRequestPopup(pubKey, null)
onEditNickname: Global.openNicknamePopupRequested(pubKey, null)
onRemoveNickname: root.rootStore.contactsStore.changeContactNickname(pubKey, "", displayName, true)
onUnblockContact: Global.unblockContactRequested(pubKey)
onMarkAsUntrusted: Global.markAsUntrustedRequested(pubKey)
onRemoveTrustStatus: root.rootStore.contactsStore.removeTrustStatus(pubKey)
onRemoveContact: Global.removeContactRequested(pubKey)
onBlockContact: Global.blockContactRequested(pubKey)
onMarkAsTrusted: Global.openMarkAsIDVerifiedPopup(pubKey, null)
onRemoveTrustedMark: Global.openRemoveIDVerificationDialog(pubKey, null)
onClosed: destroy()
}
}
Expand Down
4 changes: 2 additions & 2 deletions ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ StatusSectionLayout {
StatusQUtils.Utils.filterXSS(item.introMessage),
StatusQUtils.Utils.filterXSS(item.outroMessage),
item.options.requestToJoinEnabled ? Constants.communityChatOnRequestAccess
: Constants.communityChatPublicAccess,
: Constants.communityChatPublicAccess,
item.color.toString().toUpperCase(),
item.selectedTags,
Utils.getImageAndCropInfoJson(item.logoImagePath, item.logoCropRect),
Expand Down Expand Up @@ -298,7 +298,7 @@ StatusSectionLayout {
declinedMembersModel: root.declinedMembers

editable: root.isAdmin || root.isOwner || root.isTokenMasterOwner
memberRole: community.memberRole
memberRole: root.community.memberRole
communityName: root.community.name

onKickUserClicked: root.rootStore.removeUserFromCommunity(id)
Expand Down
Loading

0 comments on commit 9596d61

Please sign in to comment.