refactor(ChannelContextMenu): remove dependency on active channel

This commit does a bunch of things:

- First and foremost, it removes the active channel dependency.
  This is needed to have it operate on the correct channel object,
  without forcing us to change the active channel (e.g. right-clicking
  on a channel item that's not active, will make it active eventually)
- To make that work, this commit changes the `ChannelContextMenu`
  to receive a `ChatItemView`, so it can be used for things like determining
  what menu options are shown, what members are in a group, whether
  someone is admin of a group etc.
- This also required a new `QtProperty` called `contextChannel`.
  The reason this is required, is because in some cases, like receiving
  members count of groups, we need a complete `ChatItemView` object
  as we don't have access to certain APIs otherwise.
- Unfortunately, we can't pass down `activeChannel` every where for that
  because sometimes the context menu should not actually operate on
  the active channel.

Fixes: #1755
This commit is contained in:
Pascal Precht 2021-01-25 16:58:33 +01:00 committed by Iuri Matias
parent 2b3bbb0b1e
commit b1e5a15e2a
5 changed files with 59 additions and 43 deletions

View File

@ -35,6 +35,7 @@ QtObject:
groups*: GroupsView groups*: GroupsView
transactions*: TransactionsView transactions*: TransactionsView
activeChannel*: ChatItemView activeChannel*: ChatItemView
contextChannel*: ChatItemView
previousActiveChannelIndex: int previousActiveChannelIndex: int
activeCommunity*: CommunityItemView activeCommunity*: CommunityItemView
observedCommunity*: CommunityItemView observedCommunity*: CommunityItemView
@ -54,6 +55,7 @@ QtObject:
proc delete(self: ChatsView) = proc delete(self: ChatsView) =
self.chats.delete self.chats.delete
self.activeChannel.delete self.activeChannel.delete
self.contextChannel.delete
self.observedCommunity.delete self.observedCommunity.delete
self.activeCommunity.delete self.activeCommunity.delete
self.currentSuggestions.delete self.currentSuggestions.delete
@ -73,6 +75,7 @@ QtObject:
result.connected = false result.connected = false
result.chats = newChannelsList(status) result.chats = newChannelsList(status)
result.activeChannel = newChatItemView(status) result.activeChannel = newChatItemView(status)
result.contextChannel = newChatItemView(status)
result.activeCommunity = newCommunityItemView(status) result.activeCommunity = newCommunityItemView(status)
result.observedCommunity = newCommunityItemView(status) result.observedCommunity = newCommunityItemView(status)
result.currentSuggestions = newSuggestionsList() result.currentSuggestions = newSuggestionsList()
@ -190,6 +193,8 @@ QtObject:
proc activeChannelChanged*(self: ChatsView) {.signal.} proc activeChannelChanged*(self: ChatsView) {.signal.}
proc contextChannelChanged*(self: ChatsView) {.signal.}
proc sendingMessage*(self: ChatsView) {.signal.} proc sendingMessage*(self: ChatsView) {.signal.}
proc appReady*(self: ChatsView) {.signal.} proc appReady*(self: ChatsView) {.signal.}
@ -267,6 +272,19 @@ QtObject:
write = setActiveChannel write = setActiveChannel
notify = activeChannelChanged notify = activeChannelChanged
proc setContextChannel*(self: ChatsView, channel: string) {.slot.} =
let contextChannel = self.chats.getChannel(self.chats.chats.findIndexById(channel))
self.contextChannel.setChatItem(contextChannel)
self.contextChannelChanged()
proc getContextChannel*(self: ChatsView): QVariant {.slot.} =
newQVariant(self.contextChannel)
QtProperty[QVariant] contextChannel:
read = getContextChannel
write = setContextChannel
notify = contextChannelChanged
proc setActiveChannelToTimeline*(self: ChatsView) {.slot.} = proc setActiveChannelToTimeline*(self: ChatsView) {.slot.} =
if not self.activeChannel.chatItem.isNil: if not self.activeChannel.chatItem.isNil:
self.previousActiveChannelIndex = self.chats.chats.findIndexById(self.activeChannel.id) self.previousActiveChannelIndex = self.chats.chats.findIndexById(self.activeChannel.id)

View File

@ -38,7 +38,7 @@ Rectangle {
onClicked: { onClicked: {
switch (chatsModel.activeChannel.chatType) { switch (chatsModel.activeChannel.chatType) {
case Constants.chatTypePrivateGroupChat: case Constants.chatTypePrivateGroupChat:
groupInfoPopup.open() groupInfoPopup.openMenu(chatsModel.activeChannel, chatsModel.getActiveChannelIdx())
break; break;
case Constants.chatTypeOneToOne: case Constants.chatTypeOneToOne:
const profileImage = appMain.getProfileImage(chatsModel.activeChannel.id) const profileImage = appMain.getProfileImage(chatsModel.activeChannel.id)
@ -128,7 +128,7 @@ Rectangle {
icon.height: chatTopBarContent.iconSize icon.height: chatTopBarContent.iconSize
//% "Group Information" //% "Group Information"
text: qsTrId("group-information") text: qsTrId("group-information")
onTriggered: groupInfoPopup.open() onTriggered: groupInfoPopup.openMenu(chatsModel.activeChannel, chatsModel.getActiveChannelIdx())
} }
Action { Action {
icon.source: "../../../img/close.svg" icon.source: "../../../img/close.svg"

View File

@ -168,12 +168,13 @@ Rectangle {
wrapper.hovered = false wrapper.hovered = false
} }
onClicked: { onClicked: {
chatsModel.setActiveChannelByIndex(index)
chatGroupsListView.currentIndex = index
if (mouse.button & Qt.RightButton) { if (mouse.button & Qt.RightButton) {
channelContextMenu.openMenu(chatsModel.activeChannel, index) chatsModel.setContextChannel(chatId)
channelContextMenu.openMenu(chatsModel.contextChannel, index)
return; return;
} }
chatsModel.setActiveChannelByIndex(index)
chatGroupsListView.currentIndex = index
} }
} }

View File

@ -7,13 +7,8 @@ import "../../../../imports"
PopupMenu { PopupMenu {
property int channelIndex property int channelIndex
property bool channelMuted property var contextChannel
property int chatType
property string chatName
property string chatId
property string chatIdenticon
property var groupInfoPopup property var groupInfoPopup
property var groupsListView
id: channelContextMenu id: channelContextMenu
width: 175 width: 175
@ -31,11 +26,7 @@ PopupMenu {
] ]
function openMenu(channel, index) { function openMenu(channel, index) {
channelContextMenu.channelMuted = channel.muted channelContextMenu.contextChannel = channel
channelContextMenu.chatType = channel.chatType
channelContextMenu.chatName = channel.name
channelContextMenu.chatId = channel.id
channelContextMenu.chatIdenticon = channel.identicon
if (index !== undefined) { if (index !== undefined) {
channelContextMenu.channelIndex = index channelContextMenu.channelIndex = index
} }
@ -43,13 +34,13 @@ PopupMenu {
} }
Action { Action {
enabled: channelContextMenu.chatType !== Constants.chatTypePublic enabled: channelContextMenu.contextChannel.chatType !== Constants.chatTypePublic
text: { text: {
if (channelContextMenu.chatType === Constants.chatTypeOneToOne) { if (channelContextMenu.contextChannel.chatType === Constants.chatTypeOneToOne) {
//% "View Profile" //% "View Profile"
return qsTrId("view-profile") return qsTrId("view-profile")
} }
if (channelContextMenu.chatType === Constants.chatTypePrivateGroupChat) { if (channelContextMenu.contextChannel.chatType === Constants.chatTypePrivateGroupChat) {
//% "View Group" //% "View Group"
return qsTrId("view-group") return qsTrId("view-group")
} }
@ -60,16 +51,16 @@ PopupMenu {
icon.width: 16 icon.width: 16
icon.height: 16 icon.height: 16
onTriggered: { onTriggered: {
//chatsModel.setActiveChannelByIndex(channelContextMenu.channelIndex) if (channelContextMenu.contextChannel.chatType === Constants.chatTypeOneToOne) {
if (!!groupsListView) { const userProfileImage = appMain.getProfileImage(channelContextMenu.contextChannel.id)
groupsListView.currentIndex = channelContextMenu.channelIndex return openProfilePopup(
channelContextMenu.contextChannel.name,
channelContextMenu.contextChannel.id,
userProfileImage || channelContextMenu.contextChannel.identicon
)
} }
if (channelContextMenu.chatType === Constants.chatTypeOneToOne) { if (channelContextMenu.contextChannel.chatType === Constants.chatTypePrivateGroupChat) {
const userProfileImage = appMain.getProfileImage(channelContextMenu.chatId) return groupInfoPopup.openMenu(channelContextMenu.contextChannel)
return openProfilePopup(channelContextMenu.chatName, channelContextMenu.chatId, userProfileImage || channelContextMenu.chatIdenticon)
}
if (channelContextMenu.chatType === Constants.chatTypePrivateGroupChat) {
return groupInfoPopup.open()
} }
} }
} }
@ -77,7 +68,7 @@ PopupMenu {
Separator {} Separator {}
Action { Action {
text: channelContextMenu.channelMuted ? text: channelContextMenu.contextChannel.muted ?
//% "Unmute chat" //% "Unmute chat"
qsTrId("unmute-chat") : qsTrId("unmute-chat") :
//% "Mute chat" //% "Mute chat"
@ -118,11 +109,11 @@ PopupMenu {
Action { Action {
text: { text: {
if (channelContextMenu.chatType === Constants.chatTypeOneToOne) { if (channelContextMenu.contextChannel.chatType === Constants.chatTypeOneToOne) {
//% "Delete chat" //% "Delete chat"
return qsTrId("delete-chat") return qsTrId("delete-chat")
} }
if (channelContextMenu.chatType === Constants.chatTypePrivateGroupChat) { if (channelContextMenu.contextChannel.chatType === Constants.chatTypePrivateGroupChat) {
//% "Leave group" //% "Leave group"
return qsTrId("leave-group") return qsTrId("leave-group")
} }
@ -130,7 +121,7 @@ PopupMenu {
return qsTrId("leave-chat") return qsTrId("leave-chat")
} }
icon.source: { icon.source: {
if (channelContextMenu.chatType === Constants.chatTypeOneToOne) { if (channelContextMenu.contextChannel.chatType === Constants.chatTypeOneToOne) {
return "../../../img/delete.svg" return "../../../img/delete.svg"
} }
return "../../../img/leave_chat.svg" return "../../../img/leave_chat.svg"

View File

@ -13,18 +13,19 @@ ModalPopup {
property int memberCount: 1 property int memberCount: 1
readonly property int maxMembers: 10 readonly property int maxMembers: 10
property var pubKeys: [] property var pubKeys: []
property var channel
property bool isAdmin: false property bool isAdmin: false
function resetSelectedMembers(){ function resetSelectedMembers(){
pubKeys = []; pubKeys = [];
memberCount = chatsModel.activeChannel.members.rowCount(); memberCount = channel.members.rowCount();
currMemberCount = memberCount; currMemberCount = memberCount;
contactList.membersData.clear(); contactList.membersData.clear();
const contacts = chatView.getContactListObject() const contacts = chatView.getContactListObject()
contacts.forEach(function (contact) { contacts.forEach(function (contact) {
if(chatsModel.activeChannel.contains(contact.pubKey) || if(popup.channel.contains(contact.pubKey) ||
!contact.isContact) { !contact.isContact) {
return; return;
} }
@ -32,16 +33,21 @@ ModalPopup {
}) })
} }
function openMenu(channel) {
popup.channel = channel
popup.open()
}
onOpened: { onOpened: {
addMembers = false; addMembers = false;
popup.isAdmin = chatsModel.activeChannel.isAdmin(profileModel.profile.pubKey) popup.isAdmin = popup.channel.isAdmin(profileModel.profile.pubKey)
btnSelectMembers.enabled = false; btnSelectMembers.enabled = false;
resetSelectedMembers(); resetSelectedMembers();
} }
function doAddMembers(){ function doAddMembers(){
if(pubKeys.length === 0) return; if(pubKeys.length === 0) return;
chatsModel.groups.addMembers(chatsModel.activeChannel.id, JSON.stringify(pubKeys)); chatsModel.groups.addMembers(popup.channel.id, JSON.stringify(pubKeys));
popup.close(); popup.close();
} }
@ -55,14 +61,14 @@ ModalPopup {
width: 36 width: 36
height: 36 height: 36
anchors.top: parent.top anchors.top: parent.top
color: chatsModel.activeChannel.color color: popup.channel.color
chatName: chatsModel.activeChannel.name chatName: popup.channel.name
} }
StyledTextEdit { StyledTextEdit {
id: groupName id: groupName
//% "Add members" //% "Add members"
text: addMembers ? qsTrId("add-members") : chatsModel.activeChannel.name text: addMembers ? qsTrId("add-members") : popup.channel.name
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 2 anchors.topMargin: 2
anchors.left: letterIdenticon.right anchors.left: letterIdenticon.right
@ -174,7 +180,7 @@ ModalPopup {
pubKeys.splice(idx, 1); pubKeys.splice(idx, 1);
} }
} }
memberCount = chatsModel.activeChannel.members.rowCount() + pubKeys.length; memberCount = popup.channel.members.rowCount() + pubKeys.length;
btnSelectMembers.enabled = pubKeys.length > 0 btnSelectMembers.enabled = pubKeys.length > 0
} }
} }
@ -201,7 +207,7 @@ ModalPopup {
spacing: 15 spacing: 15
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
model: chatsModel.activeChannel.members model: popup.channel.members
delegate: Item { delegate: Item {
id: contactRow id: contactRow
width: parent.width width: parent.width
@ -273,14 +279,14 @@ ModalPopup {
icon.source: "../../../img/make-admin.svg" icon.source: "../../../img/make-admin.svg"
//% "Make Admin" //% "Make Admin"
text: qsTrId("make-admin") text: qsTrId("make-admin")
onTriggered: chatsModel.groups.makeAdmin(chatsModel.activeChannel.id, model.pubKey) onTriggered: chatsModel.groups.makeAdmin(popup.channel.id, model.pubKey)
} }
Action { Action {
icon.source: "../../../img/remove-from-group.svg" icon.source: "../../../img/remove-from-group.svg"
icon.color: Style.current.red icon.color: Style.current.red
//% "Remove From Group" //% "Remove From Group"
text: qsTrId("remove-from-group") text: qsTrId("remove-from-group")
onTriggered: chatsModel.groups.kickMember(chatsModel.activeChannel.id, model.pubKey) onTriggered: chatsModel.groups.kickMember(popup.channel.id, model.pubKey)
} }
} }
} }