From 65e19c9caf95a245bd0115e6aa6c67ce0c6650ec Mon Sep 17 00:00:00 2001 From: Doug Date: Fri, 19 Dec 2025 19:18:19 +0000 Subject: [PATCH] feat: Add a method to set your own user's display name within a room For e.g. the /myroomnick slash command. --- bindings/matrix-sdk-ffi/src/room/mod.rs | 8 ++++ crates/matrix-sdk/CHANGELOG.md | 3 ++ crates/matrix-sdk/src/room/mod.rs | 33 ++++++++++++- .../tests/integration/room/joined.rs | 47 +++++++++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/bindings/matrix-sdk-ffi/src/room/mod.rs b/bindings/matrix-sdk-ffi/src/room/mod.rs index 6487ee086cd..1b4bbac4a77 100644 --- a/bindings/matrix-sdk-ffi/src/room/mod.rs +++ b/bindings/matrix-sdk-ffi/src/room/mod.rs @@ -343,6 +343,14 @@ impl Room { Ok(avatar_url_string) } + pub async fn set_own_member_display_name( + &self, + display_name: Option, + ) -> Result<(), ClientError> { + self.inner.set_own_member_display_name(display_name).await?; + Ok(()) + } + /// Get the membership details for the current user. /// /// Returns: diff --git a/crates/matrix-sdk/CHANGELOG.md b/crates/matrix-sdk/CHANGELOG.md index 8d126d56568..b8090b8839f 100644 --- a/crates/matrix-sdk/CHANGELOG.md +++ b/crates/matrix-sdk/CHANGELOG.md @@ -8,6 +8,9 @@ All notable changes to this project will be documented in this file. ### Features +- Add `Room::set_own_member_display_name` to set the current user's display name + within only the one single room (can be used for /myroomnick functionality). + [#5981](https://github.com/matrix-org/matrix-rust-sdk/pull/5981) - Sending `MessageLike` and `RawMessageLike` events through a `Room` now returns the used `EncryptionInfo`, if any. ([#5936](https://github.com/matrix-org/matrix-rust-sdk/pull/5936)) diff --git a/crates/matrix-sdk/src/room/mod.rs b/crates/matrix-sdk/src/room/mod.rs index 144a500cb98..c1821151505 100644 --- a/crates/matrix-sdk/src/room/mod.rs +++ b/crates/matrix-sdk/src/room/mod.rs @@ -114,7 +114,7 @@ use ruma::{ avatar::{self, RoomAvatarEventContent}, encryption::RoomEncryptionEventContent, history_visibility::HistoryVisibility, - member::{MembershipChange, SyncRoomMemberEvent}, + member::{MembershipChange, RoomMemberEventContent, SyncRoomMemberEvent}, message::{ AudioInfo, AudioMessageEventContent, FileInfo, FileMessageEventContent, ImageMessageEventContent, MessageType, RoomMessageEventContent, @@ -1109,6 +1109,37 @@ impl Room { .collect()) } + /// Sets the display name of the current user within this room. + /// + /// *Note*: This is different to [`crate::Account::set_display_name`] which + /// updates the user's display name across all of their rooms. + pub async fn set_own_member_display_name( + &self, + display_name: Option, + ) -> Result { + let user_id = self.own_user_id(); + let member_event = + self.get_state_event_static_for_key::(user_id).await?; + + let Some(member_event) = member_event else { + return Err(Error::InsufficientData); + }; + + let RawSyncOrStrippedState::Sync(raw_event) = member_event else { + return Err(Error::InsufficientData); + }; + + let event = raw_event.deserialize()?; + + let SyncStateEvent::Original(ev) = event else { + return Err(Error::InsufficientData); + }; + + let mut content = ev.content; + content.displayname = display_name; + self.send_state_event_for_key(user_id, content).await + } + /// Get all state events of a given type in this room. pub async fn get_state_events( &self, diff --git a/crates/matrix-sdk/tests/integration/room/joined.rs b/crates/matrix-sdk/tests/integration/room/joined.rs index 3ae01bfad1b..7c86f357d02 100644 --- a/crates/matrix-sdk/tests/integration/room/joined.rs +++ b/crates/matrix-sdk/tests/integration/room/joined.rs @@ -1456,3 +1456,50 @@ async fn test_report_room() { room.report_room(reason.to_owned()).await.unwrap(); } + +#[async_test] +async fn test_set_own_member_display_name() { + // Given a room with an existing member event for the current user. + let (client, server) = logged_in_client_with_server().await; + let mut sync_builder = SyncResponseBuilder::new(); + let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); + let room_id = &DEFAULT_TEST_ROOM_ID; + let user_id = client.user_id().unwrap(); + + let existing_name = "Old Name"; + let existing_avatar_url = mxc_uri!("mxc://example.org/avA7ar"); + + let member_event = EventFactory::new() + .member(user_id) + .display_name(existing_name.to_owned()) + .avatar_url(existing_avatar_url) + .membership(MembershipState::Join); + + let response = sync_builder + .add_joined_room(JoinedRoomBuilder::new(room_id).add_state_event(member_event)) + .build_json_sync_response(); + + mock_sync(&server, response, None).await; + client.sync_once(sync_settings).await.unwrap(); + + let room = client.get_room(room_id).unwrap(); + + // When setting a new display name. + let new_name = "New Name"; + + // Then the user's display name is updated without changing the avatar URL. + Mock::given(method("PUT")) + .and(path_regex(format!(r"^/_matrix/client/r0/rooms/.*/state/m.room.member/{user_id}"))) + .and(header("authorization", "Bearer 1234")) + .and(body_partial_json(json!({ + "displayname": new_name, + "avatar_url": existing_avatar_url.to_string(), + "membership": "join" + }))) + .respond_with(ResponseTemplate::new(200).set_body_json(&*test_json::EVENT_ID)) + .expect(1) + .mount(&server) + .await; + + room.set_own_member_display_name(Some(new_name.to_owned())).await.unwrap(); +}