From ebe4f03c362a531fd8115517ea67957b3cbd75f4 Mon Sep 17 00:00:00 2001 From: Devin R Date: Thu, 16 Apr 2020 21:00:50 -0400 Subject: [PATCH] room: implement room_name according to spec, add RoomSummary to RoomName --- src/async_client.rs | 5 ++++- src/base_client.rs | 7 +++--- src/models/room.rs | 53 +++++++++++++++++++++++++++++++-------------- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/async_client.rs b/src/async_client.rs index 8fe1418b..f206b9e9 100644 --- a/src/async_client.rs +++ b/src/async_client.rs @@ -561,7 +561,7 @@ impl AsyncClient { let mut response = self.send(request).await?; for (room_id, room) in &mut response.rooms.join { - let _matrix_room = { + let matrix_room = { let mut client = self.base_client.write().await; for event in &room.state.events { if let EventResult::Ok(e) = event { @@ -572,6 +572,9 @@ impl AsyncClient { client.get_or_create_room(&room_id).clone() }; + // RoomSummary contains information for calculating room name + matrix_room.write().await.set_room_summary(&room.summary); + // re looping is not ideal here for event in &mut room.state.events { if let EventResult::Ok(e) = event { diff --git a/src/base_client.rs b/src/base_client.rs index 33a0314f..e00facf7 100644 --- a/src/base_client.rs +++ b/src/base_client.rs @@ -26,6 +26,7 @@ use crate::api::r0 as api; use crate::error::Result; use crate::events::collections::all::{RoomEvent, StateEvent}; use crate::events::presence::PresenceEvent; +use api::sync::sync_events::RoomSummary; // `NonRoomEvent` is what it is aliased as use crate::events::collections::only::Event as NonRoomEvent; use crate::events::ignored_user_list::IgnoredUserListEvent; @@ -160,7 +161,7 @@ impl Client { pub(crate) async fn calculate_room_name(&self, room_id: &RoomId) -> Option { if let Some(room) = self.joined_rooms.get(room_id) { let room = room.read().await; - Some(room.room_name.calculate_name(room_id, &room.members)) + Some(room.room_name.calculate_name(&room.members)) } else { None } @@ -168,9 +169,9 @@ impl Client { pub(crate) async fn calculate_room_names(&self) -> Vec { let mut res = Vec::new(); - for (id, room) in &self.joined_rooms { + for (_id, room) in &self.joined_rooms { let room = room.read().await; - res.push(room.room_name.calculate_name(id, &room.members)) + res.push(room.room_name.calculate_name(&room.members)) } res } diff --git a/src/models/room.rs b/src/models/room.rs index 9701d04a..e3a93a05 100644 --- a/src/models/room.rs +++ b/src/models/room.rs @@ -18,6 +18,7 @@ use std::convert::TryFrom; use super::RoomMember; +use crate::api::r0::sync::sync_events::RoomSummary; use crate::events::collections::all::{RoomEvent, StateEvent}; use crate::events::presence::PresenceEvent; use crate::events::room::{ @@ -42,6 +43,17 @@ pub struct RoomName { canonical_alias: Option, /// List of `RoomAliasId`s the room has been given. aliases: Vec, + /// Users which can be used to generate a room name if the room does not have + /// one. Required if room name or canonical aliases are not set or empty. + pub heroes: Vec, + /// Number of users whose membership status is `join`. + /// Required if field has changed since last sync; otherwise, it may be + /// omitted. + pub joined_member_count: Option, + /// Number of users whose membership status is `invite`. + /// Required if field has changed since last sync; otherwise, it may be + /// omitted. + pub invited_member_count: Option, } #[derive(Debug, PartialEq, Eq)] @@ -112,11 +124,7 @@ impl RoomName { true } - pub fn calculate_name( - &self, - room_id: &RoomId, - members: &HashMap, - ) -> String { + pub fn calculate_name(&self, members: &HashMap) -> String { // https://matrix.org/docs/spec/client_server/latest#calculating-the-display-name-for-a-room. // the order in which we check for a name ^^ if let Some(name) = &self.name { @@ -126,19 +134,21 @@ impl RoomName { } else if !self.aliases.is_empty() { self.aliases[0].alias().to_string() } else { - let mut names = members - .values() - .flat_map(|m| m.display_name.clone()) - .take(3) - .collect::>(); + let joined = self.joined_member_count.unwrap_or(UInt::max_value()); + let invited = self.invited_member_count.unwrap_or(UInt::max_value()); + let heroes = UInt::new(self.heroes.len() as u64).unwrap(); + let one = UInt::new(1).unwrap(); - if names.is_empty() { - // TODO implement the rest of display name for room spec - format!("Room {}", room_id) - } else { - // stabilize order + if heroes >= (joined + invited - one) { + let mut names = self.heroes.iter().take(3).cloned().collect::>(); names.sort(); names.join(", ") + } else if heroes < (joined + invited - one) && invited + joined > one { + let mut names = self.heroes.iter().take(3).cloned().collect::>(); + names.sort(); + format!("{}, and {} others", names.join(", "), (joined + invited)) + } else { + format!("Empty Room (was {} others)", members.len()) } } } @@ -169,7 +179,7 @@ impl Room { /// Return the display name of the room. pub fn calculate_name(&self) -> String { - self.room_name.calculate_name(&self.room_id, &self.members) + self.room_name.calculate_name(&self.members) } /// Is the room a encrypted room. @@ -239,6 +249,17 @@ impl Room { true } + pub(crate) fn set_room_summary(&mut self, summary: &RoomSummary) { + let RoomSummary { + heroes, + joined_member_count, + invited_member_count, + } = summary; + self.room_name.heroes = heroes.clone(); + self.room_name.invited_member_count = invited_member_count.clone(); + self.room_name.joined_member_count = joined_member_count.clone(); + } + /// Handle a room.member updating the room state if necessary. /// /// Returns true if the joined member list changed, false otherwise.