diff --git a/matrix_sdk/src/client.rs b/matrix_sdk/src/client.rs index 1796d697..0fb0f898 100644 --- a/matrix_sdk/src/client.rs +++ b/matrix_sdk/src/client.rs @@ -2255,13 +2255,12 @@ impl Client { #[cfg(test)] mod test { - use crate::{ClientConfig, HttpError}; + use crate::{ClientConfig, HttpError, RoomMember}; use super::{ get_public_rooms, get_public_rooms_filtered, register::RegistrationKind, Client, Session, SyncSettings, Url, }; - use matrix_sdk_base::RoomMember; use matrix_sdk_common::{ api::r0::{ account::register::Request as RegistrationRequest, diff --git a/matrix_sdk/src/lib.rs b/matrix_sdk/src/lib.rs index 2f65a2d4..5e077caa 100644 --- a/matrix_sdk/src/lib.rs +++ b/matrix_sdk/src/lib.rs @@ -72,8 +72,8 @@ compile_error!("'sso_login' cannot be enabled on 'wasm32' arch"); #[cfg_attr(feature = "docs", doc(cfg(encryption)))] pub use matrix_sdk_base::crypto::{EncryptionInfo, LocalTrust}; pub use matrix_sdk_base::{ - Error as BaseError, Room as BaseRoom, RoomInfo, RoomMember, RoomType, Session, StateChanges, - StoreError, + Error as BaseError, Room as BaseRoom, RoomInfo, RoomMember as BaseRoomMember, RoomType, + Session, StateChanges, StoreError, }; pub use matrix_sdk_common::*; @@ -85,6 +85,8 @@ mod event_handler; mod http_client; /// High-level room API pub mod room; +/// High-level room API +mod room_member; #[cfg(feature = "encryption")] mod device; @@ -100,6 +102,7 @@ pub use device::Device; pub use error::{Error, HttpError, Result}; pub use event_handler::{CustomEvent, EventHandler}; pub use http_client::HttpSend; +pub use room_member::RoomMember; #[cfg(feature = "encryption")] #[cfg_attr(feature = "docs", doc(cfg(encryption)))] pub use sas::Sas; diff --git a/matrix_sdk/src/room/common.rs b/matrix_sdk/src/room/common.rs index 857616eb..b7d0fab5 100644 --- a/matrix_sdk/src/room/common.rs +++ b/matrix_sdk/src/room/common.rs @@ -193,7 +193,13 @@ impl Common { if !self.are_members_synced() { self.request_members().await?; } - Ok(self.inner.active_members().await?) + Ok(self + .inner + .active_members() + .await? + .into_iter() + .map(|member| RoomMember::new(self.client.clone(), member)) + .collect()) } /// Get all members for this room, includes invited, joined and left members. @@ -201,6 +207,12 @@ impl Common { if !self.are_members_synced() { self.request_members().await?; } - Ok(self.inner.members().await?) + Ok(self + .inner + .members() + .await? + .into_iter() + .map(|member| RoomMember::new(self.client.clone(), member)) + .collect()) } } diff --git a/matrix_sdk/src/room_member.rs b/matrix_sdk/src/room_member.rs new file mode 100644 index 00000000..202c3b48 --- /dev/null +++ b/matrix_sdk/src/room_member.rs @@ -0,0 +1,87 @@ +use matrix_sdk_common::api::r0::media::{get_content, get_content_thumbnail}; + +use std::ops::Deref; + +use crate::{BaseRoomMember, Client, Result}; + +/// The high-level `RoomMember` representation +#[derive(Debug, Clone)] +pub struct RoomMember { + inner: BaseRoomMember, + pub(crate) client: Client, +} + +impl Deref for RoomMember { + type Target = BaseRoomMember; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl RoomMember { + pub(crate) fn new(client: Client, member: BaseRoomMember) -> Self { + Self { + inner: member, + client, + } + } + + /// Gets the avatar of this member, if set. + /// + /// Returns the avatar. No guarantee on the size of the image is given. + /// If no size is given the full-sized avatar will be returned. + /// + /// # Arguments + /// + /// * `width` - The desired width of the avatar. + /// + /// * `height` - The desired height of the avatar. + /// + /// # Example + /// ```no_run + /// # use futures::executor::block_on; + /// # use matrix_sdk::Client; + /// # use matrix_sdk::identifiers::room_id; + /// # use matrix_sdk::RoomMember; + /// # use url::Url; + /// # let homeserver = Url::parse("http://example.com").unwrap(); + /// # block_on(async { + /// # let user = "example"; + /// let client = Client::new(homeserver).unwrap(); + /// client.login(user, "password", None, None).await.unwrap(); + /// let room_id = room_id!("!roomid:example.com"); + /// let room = client + /// .get_joined_room(&room_id) + /// .unwrap(); + /// let members = room.members().await.unwrap(); + /// let member = members.first().unwrap(); + /// if let Some(avatar) = member.avatar(Some(96), Some(96)).await.unwrap() { + /// std::fs::write("avatar.png", avatar); + /// } + /// # }) + /// ``` + pub async fn avatar(&self, width: Option, height: Option) -> Result>> { + // TODO: try to offer the avatar from cache, requires avatar cache + if let Some((server_name, media_id)) = + self.avatar_url().and_then(|url| crate::parse_mxc(&url)) + { + if let (Some(width), Some(height)) = (width, height) { + let request = get_content_thumbnail::Request::new( + &media_id, + &server_name, + width.into(), + height.into(), + ); + let response = self.client.send(request, None).await?; + Ok(Some(response.file)) + } else { + let request = get_content::Request::new(&media_id, &server_name); + let response = self.client.send(request, None).await?; + Ok(Some(response.file)) + } + } else { + Ok(None) + } + } +}