Add ignore user options in member context menues
This commit is contained in:
		| @@ -543,29 +543,32 @@ class MatrixClient(nio.AsyncClient): | |||||||
|             nio.Api.to_json({"ignored_users": {u: {} for u in ignored}}), |             nio.Api.to_json({"ignored_users": {u: {} for u in ignored}}), | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         if not ignore: |  | ||||||
|             return |  | ||||||
|  |  | ||||||
|         # Invites and messages from ignored users won't be returned anymore on |         # Invites and messages from ignored users won't be returned anymore on | ||||||
|         # syncs, thus will be absent on client restart. Clean up immediatly: |         # syncs, thus will be absent on client restart. Clean up immediatly, | ||||||
|  |         # and also update Member.ignored fields: | ||||||
|  |  | ||||||
|         room_model = self.models[self.user_id, "rooms"] |         room_model = self.models[self.user_id, "rooms"] | ||||||
|  |  | ||||||
|         with room_model.batch_remove(): |         with room_model.batch_remove(): | ||||||
|             for room_id, room in room_model.copy().items(): |             for room_id, room in room_model.copy().items(): | ||||||
|                 if room.inviter_id == user_id: |                 if ignore and room.inviter_id == user_id: | ||||||
|                     self.ignored_rooms.add(room_id) |                     self.ignored_rooms.add(room_id) | ||||||
|                     del room_model[room_id] |                     del room_model[room_id] | ||||||
|                     self.models.pop((self.user_id, room_id, "events"), None) |                     self.models.pop((self.user_id, room_id, "events"), None) | ||||||
|                     self.models.pop((self.user_id, room_id, "members"), None) |                     self.models.pop((self.user_id, room_id, "members"), None) | ||||||
|                     continue |                     continue | ||||||
|  |  | ||||||
|                 event_model = self.models[self.user_id, room_id, "events"] |                 event_model  = self.models[self.user_id, room_id, "events"] | ||||||
|  |                 member_model = self.models[self.user_id, room_id, "members"] | ||||||
|  |  | ||||||
|                 with event_model.batch_remove(): |                 if user_id in member_model: | ||||||
|                     for event_id, event in event_model.copy().items(): |                     member_model[user_id].ignored = ignore | ||||||
|                         if event.sender_id == user_id: |  | ||||||
|                             del event_model[event_id] |                 if ignore: | ||||||
|  |                     with event_model.batch_remove(): | ||||||
|  |                         for event_id, event in event_model.copy().items(): | ||||||
|  |                             if event.sender_id == user_id: | ||||||
|  |                                 del event_model[event_id] | ||||||
|  |  | ||||||
|         await self.update_account_unread_counts() |         await self.update_account_unread_counts() | ||||||
|  |  | ||||||
| @@ -2251,6 +2254,7 @@ class MatrixClient(nio.AsyncClient): | |||||||
|                               if member.display_name else "", |                               if member.display_name else "", | ||||||
|             avatar_url      = member.avatar_url or "", |             avatar_url      = member.avatar_url or "", | ||||||
|             typing          = user_id in room.typing_users, |             typing          = user_id in room.typing_users, | ||||||
|  |             ignored         = user_id in self.ignored_user_ids, | ||||||
|             power_level     = member.power_level, |             power_level     = member.power_level, | ||||||
|             invited         = member.invited, |             invited         = member.invited, | ||||||
|             last_read_event = last_read_event, |             last_read_event = last_read_event, | ||||||
|   | |||||||
| @@ -275,6 +275,7 @@ class Member(ModelItem): | |||||||
|     typing:          bool     = False |     typing:          bool     = False | ||||||
|     power_level:     int      = 0 |     power_level:     int      = 0 | ||||||
|     invited:         bool     = False |     invited:         bool     = False | ||||||
|  |     ignored:         bool     = False | ||||||
|     profile_updated: datetime = ZERO_DATE |     profile_updated: datetime = ZERO_DATE | ||||||
|     last_read_event: str      = "" |     last_read_event: str      = "" | ||||||
|  |  | ||||||
| @@ -287,13 +288,15 @@ class Member(ModelItem): | |||||||
|         return ( |         return ( | ||||||
|             self.invited, |             self.invited, | ||||||
|             other.power_level, |             other.power_level, | ||||||
|             self.presence, |             self.ignored, | ||||||
|  |             Presence.State.offline if self.ignored else self.presence, | ||||||
|             (self.display_name or self.id[1:]).lower(), |             (self.display_name or self.id[1:]).lower(), | ||||||
|             self.id, |             self.id, | ||||||
|         ) < ( |         ) < ( | ||||||
|             other.invited, |             other.invited, | ||||||
|             self.power_level, |             self.power_level, | ||||||
|             other.presence, |             other.ignored, | ||||||
|  |             Presence.State.offline if other.ignored else other.presence, | ||||||
|             (other.display_name or other.id[1:]).lower(), |             (other.display_name or other.id[1:]).lower(), | ||||||
|             other.id, |             other.id, | ||||||
|         ) |         ) | ||||||
|   | |||||||
| @@ -16,7 +16,9 @@ HTile { | |||||||
|  |  | ||||||
|     backgroundColor: theme.chat.roomPane.listView.member.background |     backgroundColor: theme.chat.roomPane.listView.member.background | ||||||
|     contentOpacity: |     contentOpacity: | ||||||
|         model.invited ? theme.chat.roomPane.listView.member.invitedOpacity : 1 |         model.invited || model.ignored ? | ||||||
|  |         theme.chat.roomPane.listView.member.invitedOpacity : | ||||||
|  |         1 | ||||||
|  |  | ||||||
|     contentItem: ContentRow { |     contentItem: ContentRow { | ||||||
|         tile: member |         tile: member | ||||||
| @@ -25,12 +27,12 @@ HTile { | |||||||
|             id: avatar |             id: avatar | ||||||
|             clientUserId: chat.userId |             clientUserId: chat.userId | ||||||
|             userId: model.id |             userId: model.id | ||||||
|             displayName: model.display_name |             displayName: model.ignored ? "" : model.display_name | ||||||
|             mxc: model.avatar_url |             mxc: model.ignored ? "" : model.avatar_url | ||||||
|             powerLevel: model.power_level |             powerLevel: model.power_level | ||||||
|             invited: model.invited |             invited: model.invited | ||||||
|             compact: member.compact |             compact: member.compact | ||||||
|             presence: model.presence |             presence: model.ignored ? "offline" : model.presence | ||||||
|             shiftMembershipIconPositionBy: |             shiftMembershipIconPositionBy: | ||||||
|                 roomPane.width >= width + 8 * 3 ? -8 : -4 |                 roomPane.width >= width + 8 * 3 ? -8 : -4 | ||||||
|         } |         } | ||||||
| @@ -40,11 +42,17 @@ HTile { | |||||||
|                 spacing: theme.spacing |                 spacing: theme.spacing | ||||||
|  |  | ||||||
|                 TitleLabel { |                 TitleLabel { | ||||||
|                     text: model.display_name || model.id |                     text: | ||||||
|  |                         model.ignored ? | ||||||
|  |                         model.id : | ||||||
|  |                         (model.display_name || model.id) | ||||||
|  |  | ||||||
|                     color: |                     color: | ||||||
|                         member.colorName ? |                         member.colorName ? | ||||||
|                         utils.nameColor( |                         utils.nameColor( | ||||||
|                             model.display_name || model.id.substring(1) |                             model.ignored ? | ||||||
|  |                             model.id : | ||||||
|  |                             (model.display_name || model.id.substring(1)) | ||||||
|                         ) : |                         ) : | ||||||
|                         theme.chat.roomPane.listView.member.name |                         theme.chat.roomPane.listView.member.name | ||||||
|  |  | ||||||
| @@ -54,7 +62,7 @@ HTile { | |||||||
|                 TitleRightInfoLabel { |                 TitleRightInfoLabel { | ||||||
|                     id: lastActiveAt |                     id: lastActiveAt | ||||||
|                     tile: member |                     tile: member | ||||||
|                     visible: presenceTimer.running |                     visible: ! model.ignored && presenceTimer.running | ||||||
|                     hideUnderWidth: 130 |                     hideUnderWidth: 130 | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @@ -62,7 +70,10 @@ HTile { | |||||||
|             SubtitleLabel { |             SubtitleLabel { | ||||||
|                 tile: member |                 tile: member | ||||||
|                 color: theme.chat.roomPane.listView.member.subtitle |                 color: theme.chat.roomPane.listView.member.subtitle | ||||||
|                 text: utils.escapeHtml(model.status_msg.trim()) || model.id |                 text: | ||||||
|  |                     model.ignored ? | ||||||
|  |                     qsTr("Ignored") : | ||||||
|  |                     (utils.escapeHtml(model.status_msg.trim()) || model.id) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             HoverHandler { id: nameHover } |             HoverHandler { id: nameHover } | ||||||
| @@ -72,7 +83,7 @@ HTile { | |||||||
|                 text: |                 text: | ||||||
|                     model.id + |                     model.id + | ||||||
|                     ( |                     ( | ||||||
|                         model.status_msg.trim() ? |                         ! model.ignored && model.status_msg.trim() ? | ||||||
|                         " - " + model.status_msg.trim() : |                         " - " + model.status_msg.trim() : | ||||||
|                         "" |                         "" | ||||||
|                     ) |                     ) | ||||||
| @@ -80,12 +91,15 @@ HTile { | |||||||
|  |  | ||||||
|             Timer { |             Timer { | ||||||
|                 id: presenceTimer |                 id: presenceTimer | ||||||
|  |                 repeat: true | ||||||
|                 running: |                 running: | ||||||
|  |                     ! model.ignored && | ||||||
|                     ! model.currently_active && |                     ! model.currently_active && | ||||||
|                     model.last_active_at > new Date(1) |                     model.last_active_at > new Date(1) | ||||||
|                 repeat: true |  | ||||||
|                 interval: |                 interval: | ||||||
|                     new Date() - model.last_active_at < 60000 ? 10000 : 60000 |                     new Date() - model.last_active_at < 60000 ? 10000 : 60000 | ||||||
|  |  | ||||||
|                 triggeredOnStart: true |                 triggeredOnStart: true | ||||||
|                 onTriggered: lastActiveAt.text = Qt.binding(() => |                 onTriggered: lastActiveAt.text = Qt.binding(() => | ||||||
|                     utils.formatRelativeTime(new Date() - model.last_active_at) |                     utils.formatRelativeTime(new Date() - model.last_active_at) | ||||||
| @@ -101,6 +115,24 @@ HTile { | |||||||
|             onTriggered: Clipboard.text = model.id |             onTriggered: Clipboard.text = model.id | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         HMenuItemPopupSpawner { | ||||||
|  |             icon.name: model.ignored ? "stop-ignore-user" : "ignore-user" | ||||||
|  |             icon.color: | ||||||
|  |                 model.ignored ? | ||||||
|  |                 theme.colors.positiveBackground : | ||||||
|  |                 theme.colors.negativeBackground | ||||||
|  |  | ||||||
|  |             text: model.ignored ? qsTr("Stop ignoring") : qsTr("Ignore") | ||||||
|  |  | ||||||
|  |             popup: "Popups/IgnoreUserPopup.qml" | ||||||
|  |             properties: ({ | ||||||
|  |                 userId: chat.userId, | ||||||
|  |                 targetUserId: model.id, | ||||||
|  |                 targetDisplayName: model.display_name, | ||||||
|  |                 ignore: ! model.ignored | ||||||
|  |             }) | ||||||
|  |         } | ||||||
|  |  | ||||||
|         HMenuItemPopupSpawner { |         HMenuItemPopupSpawner { | ||||||
|             property bool permissionToKick: false |             property bool permissionToKick: false | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										65
									
								
								src/gui/Popups/IgnoreUserPopup.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/gui/Popups/IgnoreUserPopup.qml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | |||||||
|  | // Copyright Mirage authors & contributors <https://github.com/mirukana/mirage> | ||||||
|  | // SPDX-License-Identifier: LGPL-3.0-or-later | ||||||
|  |  | ||||||
|  | import QtQuick 2.12 | ||||||
|  | import QtQuick.Layouts 1.12 | ||||||
|  | import "../Base" | ||||||
|  | import "../Base/Buttons" | ||||||
|  |  | ||||||
|  | HFlickableColumnPopup { | ||||||
|  |     id: root | ||||||
|  |  | ||||||
|  |     property string userId | ||||||
|  |     property string targetUserId | ||||||
|  |     property string targetDisplayName | ||||||
|  |     property bool ignore | ||||||
|  |  | ||||||
|  |     function apply() { | ||||||
|  |         py.callClientCoro(userId, "ignore_user", [targetUserId, ignore]) | ||||||
|  |         root.close() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     page.footer: AutoDirectionLayout { | ||||||
|  |         ApplyButton { | ||||||
|  |             id: ignoreButton | ||||||
|  |             icon.name: root.ignore ? "ignore-user" : "stop-ignore-user" | ||||||
|  |             text: root.ignore ? qsTr("Ignore") : qsTr("Stop ignoring") | ||||||
|  |             onClicked: root.apply() | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         CancelButton { | ||||||
|  |             onClicked: root.close() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     onOpened: ignoreButton.forceActiveFocus() | ||||||
|  |  | ||||||
|  |     SummaryLabel { | ||||||
|  |         readonly property string userText: | ||||||
|  |             utils.coloredNameHtml(root.targetDisplayName, root.targetUserId) | ||||||
|  |  | ||||||
|  |         textFormat: Text.StyledText | ||||||
|  |         text: | ||||||
|  |             root.ignore ? | ||||||
|  |             qsTr("Ignore %1?").arg(userText) : | ||||||
|  |             qsTr("Stop ignoring %1?").arg(userText) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     DetailsLabel { | ||||||
|  |         text: | ||||||
|  |             root.ignore ? qsTr( | ||||||
|  |                 "You will no longer see their messages and invites.\n\n" + | ||||||
|  |  | ||||||
|  |                 "Their name, avatar and online status will also be hidden " + | ||||||
|  |                 "in room member lists." | ||||||
|  |             ) : qsTr( | ||||||
|  |                 "You will receive their messages and room invites again.\n\n" + | ||||||
|  |  | ||||||
|  |                 "Their names, avatar and online status will also become " + | ||||||
|  |                 "visible in room member lists.\n\n" + | ||||||
|  |  | ||||||
|  |                 "After restarting %1, any message or room invite they had " + | ||||||
|  |                 "sent while being ignored will become visible." | ||||||
|  |             ).arg(Qt.application.displayName) | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								src/icons/thin/ignore-user.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/icons/thin/ignore-user.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | <svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"> | ||||||
|  |     <path d="m19.604 2.562-3.346 3.137c-1.27-.428-2.686-.699-4.243-.699-7.569 0-12.015 6.551-12.015 6.551s1.928 2.951 5.146 5.138l-2.911 2.909 1.414 1.414 17.37-17.035zm-6.016 5.779c-3.288-1.453-6.681 1.908-5.265 5.206l-1.726 1.707c-1.814-1.16-3.225-2.65-4.06-3.66 1.493-1.648 4.817-4.594 9.478-4.594.927 0 1.796.119 2.61.315zm-2.883 7.431 5.09-4.993c1.017 3.111-2.003 6.067-5.09 4.993zm13.295-4.221s-4.252 7.449-11.985 7.449c-1.379 0-2.662-.291-3.851-.737l1.614-1.583c.715.193 1.458.32 2.237.32 4.791 0 8.104-3.527 9.504-5.364-.729-.822-1.956-1.99-3.587-2.952l1.489-1.46c2.982 1.9 4.579 4.327 4.579 4.327z"/> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 701 B | 
							
								
								
									
										3
									
								
								src/icons/thin/stop-ignore-user.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/icons/thin/stop-ignore-user.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | <svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"> | ||||||
|  |     <path d="m12.015 7c4.751 0 8.063 3.012 9.504 4.636-1.401 1.837-4.713 5.364-9.504 5.364-4.42 0-7.93-3.536-9.478-5.407 1.493-1.647 4.817-4.593 9.478-4.593zm0-2c-7.569 0-12.015 6.551-12.015 6.551s4.835 7.449 12.015 7.449c7.733 0 11.985-7.449 11.985-7.449s-4.291-6.551-11.985-6.551zm-.015 3c-2.21 0-4 1.791-4 4s1.79 4 4 4c2.209 0 4-1.791 4-4s-1.791-4-4-4zm-.004 3.999c-.564.564-1.479.564-2.044 0s-.565-1.48 0-2.044c.564-.564 1.479-.564 2.044 0s.565 1.479 0 2.044z"/> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 558 B | 
		Reference in New Issue
	
	Block a user
	