Add ignored users list to account settings

This commit is contained in:
miruka 2021-04-14 13:53:07 -04:00
parent 719938d1db
commit 93404559b9
4 changed files with 127 additions and 42 deletions

View File

@ -525,13 +525,10 @@ class MatrixClient(nio.AsyncClient):
await asyncio.sleep(0.2)
async def ignore_user(self, user_id: str, ignore: bool) -> None:
ignored = self.ignored_user_ids.copy()
if ignore:
ignored.add(user_id)
else:
ignored.discard(user_id)
async def set_ignored_users(self, *user_ids: str) -> None:
previous_ignored = self.ignored_user_ids
now_ignored = set(user_ids)
no_longer_ignored = previous_ignored - now_ignored
path = ["user", self.user_id, "account_data", "m.ignored_user_list"]
params = {"access_token": self.access_token}
@ -540,18 +537,18 @@ class MatrixClient(nio.AsyncClient):
nio.responses.EmptyResponse,
"PUT",
nio.Api._build_path(path, params),
nio.Api.to_json({"ignored_users": {u: {} for u in ignored}}),
nio.Api.to_json({"ignored_users": {u: {} for u in now_ignored}}),
)
# Invites and messages from ignored users won't be returned anymore on
# syncs, thus will be absent on client restart. Clean up immediatly,
# and also update Member.ignored fields:
# 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"]
with room_model.batch_remove():
for room_id, room in room_model.copy().items():
if ignore and room.inviter_id == user_id:
if room.inviter_id in now_ignored:
self.ignored_rooms.add(room_id)
del room_model[room_id]
self.models.pop((self.user_id, room_id, "events"), None)
@ -561,18 +558,28 @@ class MatrixClient(nio.AsyncClient):
event_model = self.models[self.user_id, room_id, "events"]
member_model = self.models[self.user_id, room_id, "members"]
for user_id in now_ignored:
if user_id in member_model:
member_model[user_id].ignored = ignore
member_model[user_id].ignored = True
for user_id in no_longer_ignored:
if user_id in member_model:
member_model[user_id].ignored = False
if ignore:
with event_model.batch_remove():
for event_id, event in event_model.copy().items():
if event.sender_id == user_id:
if event.sender_id in now_ignored:
del event_model[event_id]
await self.update_account_unread_counts()
async def ignore_user(self, user_id: str, ignore: bool) -> None:
current = self.ignored_user_ids
new = current | {user_id} if ignore else current - {user_id}
await self.set_ignored_users(*new)
async def can_kick(self, room_id: str, target_user_id: str) -> bool:
"""Return whether we can kick a certain user in a room."""

View File

@ -7,7 +7,7 @@ import json
from dataclasses import asdict, dataclass, field
from datetime import datetime, timedelta
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple, Type, Union
from typing import Any, Dict, List, Optional, Set, Tuple, Type, Union
from uuid import UUID
import lxml # nosec
@ -79,6 +79,7 @@ class Account(ModelItem):
total_unread: int = 0
total_highlights: int = 0
local_unreads: bool = False
ignored_users: Set[str] = field(default_factory=set)
# For some reason, Account cannot inherit Presence, because QML keeps
# complaining type error on unknown file

View File

@ -861,8 +861,9 @@ class NioCallbacks:
) -> None:
if ev.type == "m.ignored_user_list":
user_ids = set(ev.content.get("ignored_users", {}))
self.client.ignored_user_ids = user_ids
users = set(ev.content.get("ignored_users", {}))
self.client.ignored_user_ids = users
self.models["accounts"][self.client.user_id].ignored_users = users
# Presence event callbacks

View File

@ -21,25 +21,6 @@ HFlickableColumnPage {
}
function applyChanges() {
if (nameField.item.changed) {
saveButton.nameChangeRunning = true
py.callClientCoro(
userId, "set_displayname", [nameField.item.text], () => {
py.callClientCoro(userId, "update_own_profile", [], () => {
saveButton.nameChangeRunning = false
})
}
)
}
if (aliasFieldItem.changed) {
window.settings.Chat.Composer.Aliases[userId] =
aliasFieldItem.text
window.saveSettings()
}
if (avatar.changed) {
saveButton.avatarChangeRunning = true
@ -50,11 +31,39 @@ HFlickableColumnPage {
py.callClientCoro(userId, "update_own_profile", [], () => {
saveButton.avatarChangeRunning = false
})
}, (errType, [httpCode]) => {
console.error("Avatar upload failed:", httpCode, errType)
saveButton.avatarChangeRunning = false
})
}
if (nameField.item.changed) {
saveButton.nameChangeRunning = true
const name = [nameField.item.text]
py.callClientCoro(userId, "set_displayname", [name] , () => {
py.callClientCoro(userId, "update_own_profile", [], () => {
saveButton.nameChangeRunning = false
})
})
}
if (aliasFieldItem.changed) {
window.settings.Chat.Composer.Aliases[userId] =
aliasFieldItem.text
window.saveSettings()
}
if (ignoredUsersAreaItem.changed) {
saveButton.ignoredUsersChangeRunning = true
const users = ignoredUsersAreaItem.userIds
py.callClientCoro(userId, "set_ignored_users", users, () => {
saveButton.ignoredUsersChangeRunning = false
})
}
}
function cancel() {
@ -80,13 +89,19 @@ HFlickableColumnPage {
property bool nameChangeRunning: false
property bool avatarChangeRunning: false
property bool ignoredUsersChangeRunning: false
disableWhileLoading: false
loading: nameChangeRunning || avatarChangeRunning
loading:
nameChangeRunning ||
avatarChangeRunning ||
ignoredUsersChangeRunning
enabled:
avatar.changed ||
nameField.item.changed ||
(aliasFieldItem.changed && ! aliasFieldItem.error)
(aliasFieldItem.changed && ! aliasFieldItem.error) ||
(ignoredUsersAreaItem.changed && ! ignoredUsersAreaItem.error)
onClicked: applyChanges()
}
@ -314,4 +329,65 @@ HFlickableColumnPage {
}
}
}
HLabeledItem {
id: ignoredUsers
readonly property var userIds:
! ignoredUsersAreaItem.text.trim() ?
[] :
ignoredUsersAreaItem.text.trim().split(/\s+/)
readonly property var invalidUserIds: {
const result = []
for (const user of userIds)
if (! /@.+:.+/.test(user))
result.push(user)
return result
}
loading: ! ready
label.text: qsTr("Ignored users:")
errorLabel.text:
invalidUserIds.length ?
qsTr("Incomplete user ID: %1").arg(invalidUserIds.join(", ")) :
""
Layout.fillWidth: true
HRowLayout {
width: parent.width
HTextArea {
id: ignoredUsersAreaItem
error: ignoredUsers.invalidUserIds.length > 0
focusItemOnTab: ignoredUsersHelpButton
placeholderText: qsTr("@user1:example.org @user2:ex.org")
defaultText:
ready ?
JSON.parse(account.ignored_users).sort().join(" ") :
""
Layout.fillWidth: true
Layout.fillHeight: true
}
FieldHelpButton {
id: ignoredUsersHelpButton
helpText: qsTr(
"List of user IDs, separated by a space, from which you " +
"will not receive messages or room invites.\n\n" +
"Their display name, avatar and online status will also " +
"be hidden from room member lists.\n\n" +
"When removing an user from the ignore list, restarting " +
"%1 is needed to receive anything they might have sent " +
"while being ignored."
).arg(Qt.application.displayName)
}
}
}
}