diff --git a/CHANGELOG.md b/CHANGELOG.md index 81243f4e..35a321da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ and this project adheres to ### Added +- **Saving room settings**: room name, topic, guest access, invite requirement, + guest access and encryption can now be changed and saved from the room's + settings pane + - `markRoomReadMsecDelay` setting to configure how long in milliseconds Mirage will wait before marking a focused room as read, defaults to `200` diff --git a/TODO.md b/TODO.md index 021a9753..f0acb7ae 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,6 @@ # TODO -- fields/areas defaultText not updating when unchanged +- text area tab handling - fix cursor over field - update room highlight when creating new room - keyerror when forgetting room while loading members @@ -23,6 +23,9 @@ - Don't send typing notification when switching to a room where the composer has loaded text +- Popups and room settings can't be scrolled when not enough height to show all +- `TextArea`s in Popups grow past window height instead of being scrollable + - Jumping between accounts (clicking in account bar or alt+(Shift+)N) is laggy with hundreds of rooms in between - On startup, if a room's last event is a membership change, @@ -34,9 +37,6 @@ - Catch server 5xx errors when sending message and retry -- Popups and room settings can't be scrolled when not enough height to show all -- `TextArea`s in Popups grow past window height instead of being scrollable - - Handle cases where a known account's access token is invalid - If an account is gone from the user's config, discard UI state last page @@ -63,7 +63,15 @@ - Make clicking on user/room mentions open relevant UI instead of matrix.to URL in browser -- Make rooms fully manageable within Mirage: settings, permissions, unban + +- Missing room settings: + - Set whether to publish this room in the server room directory + - Set history visibility + - Set aliases + - Change members power level + - Setup permissions + - Unban members + - Set flair (which community this room belongs to) - Linkify URLs in topic text areas diff --git a/src/backend/matrix_client.py b/src/backend/matrix_client.py index b585bcf1..53702e11 100644 --- a/src/backend/matrix_client.py +++ b/src/backend/matrix_client.py @@ -972,6 +972,62 @@ class MatrixClient(nio.AsyncClient): return (successes, errors) + async def room_put_state_builder( + self, room_id: str, builder: nio.EventBuilder, + ) -> str: + """Send state event to room based from a `nio.EventBuilder` object.""" + + dct = builder.as_dict() + + response = await self.room_put_state( + room_id = room_id, + event_type = dct["type"], + content = dct["content"], + state_key = dct["state_key"], + ) + return response.event_id + + + async def room_set( + self, + room_id: str, + name: Optional[str] = None, + topic: Optional[str] = None, + encrypt: Optional[bool] = None, + require_invite: Optional[bool] = None, + forbid_guests: Optional[bool] = None, + ) -> None: + """Send setting state events for arguments that aren't `None`.""" + + builders: List[nio.EventBuilder] = [] + + if name is not None: + builders.append(nio.ChangeNameBuilder(name=name)) + + if topic is not None: + builders.append(nio.ChangeTopicBuilder(topic=topic)) + + if encrypt is False: + raise ValueError("Cannot disable encryption in a E2E room") + + if encrypt is True: + builders.append(nio.EnableEncryptionBuilder()) + + if require_invite is not None: + builders.append(nio.ChangeJoinRulesBuilder( + rule="invite" if require_invite else "public", + )) + + if forbid_guests is not None: + builders.append(nio.ChangeGuestAccessBuilder( + access = "forbidden" if forbid_guests else "can_join", + )) + + await asyncio.gather(*[ + self.room_put_state_builder(room_id, b) for b in builders + ]) + + async def get_redacted_event_content( self, nio_type: Type[nio.Event], diff --git a/src/gui/Pages/Chat/RoomPane/SettingsView.qml b/src/gui/Pages/Chat/RoomPane/SettingsView.qml index 514fab64..fa3e2609 100644 --- a/src/gui/Pages/Chat/RoomPane/SettingsView.qml +++ b/src/gui/Pages/Chat/RoomPane/SettingsView.qml @@ -12,8 +12,7 @@ HBox { name: "apply", text: qsTr("Save"), iconName: "apply", - // enabled: anyChange, TODO - enabled: false, + enabled: anyChange, loading: saveFuture !== null, disableWhileLoading: false, }, @@ -28,7 +27,25 @@ HBox { buttonCallbacks: ({ apply: button => { if (saveFuture) saveFuture.cancel() - // TODO + + const args = [ + chat.roomId, + nameField.item.changed ? nameField.item.text : undefined, + topicArea.item.changed ? topicArea.item.text : undefined, + encryptCheckBox.changed ? true : undefined, + + requireInviteCheckbox.changed ? + requireInviteCheckbox.checked : undefined, + + forbidGuestsCheckBox.changed ? + forbidGuestsCheckBox.checked : undefined, + ] + + function onDone() { saveFuture = null } + + saveFuture = py.callClientCoro( + chat.userId, "room_set", args, onDone, onDone, + ) }, cancel: button => {