From 612a10e9a1560dc98b3cade6da7d13f23cc52202 Mon Sep 17 00:00:00 2001 From: Alvin Date: Thu, 23 Oct 2025 23:41:39 +0800 Subject: [PATCH 1/5] Fix room name display issues for invited rooms and newly joined rooms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR addresses room name display issues in three scenarios: 1. Room invitations showing "Empty Room" instead of actual names 2. Tombstoned room replacements not showing correct names without restart 3. Rooms joined from other clients not displaying names correctly Root cause: The comparison logic in `update_room()` was comparing references to SDK's internal state rather than cached snapshots, causing UI updates to be skipped when room names changed. Key changes: - Use `RoomDisplayName` enum instead of `Option` for type safety - Properly preserve `EmptyWas` variant to maintain previous name semantics - Implement name fallback order: canonical_alias → alt_alias → room_id - Update invited room display list when names change - Store and compare cached display names to detect all changes - Only send updates when names actually change (not on every event) Addresses all review comments from #590. Signed-off-by: Alvin --- src/home/invite_screen.rs | 9 ++- src/home/room_preview.rs | 22 ++++--- src/home/rooms_list.rs | 103 ++++++++++++++++++++++++++------ src/room/room_display_filter.rs | 16 ++++- src/sliding_sync.rs | 28 ++++++--- src/utils.rs | 39 +++++++++++- 6 files changed, 179 insertions(+), 38 deletions(-) diff --git a/src/home/invite_screen.rs b/src/home/invite_screen.rs index 80d7b292..99521a34 100644 --- a/src/home/invite_screen.rs +++ b/src/home/invite_screen.rs @@ -8,7 +8,7 @@ use std::ops::Deref; use makepad_widgets::*; use matrix_sdk::ruma::OwnedRoomId; -use crate::{app::AppStateAction, home::rooms_list::RoomsListRef, join_leave_room_modal::{JoinLeaveModalKind, JoinLeaveRoomModalAction}, room::{BasicRoomDetails, RoomPreviewAvatar}, shared::{avatar::AvatarWidgetRefExt, popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, restore_status_view::RestoreStatusViewWidgetExt}, sliding_sync::{submit_async_request, MatrixRequest}, utils::{self, room_name_or_id}}; +use crate::{app::AppStateAction, home::rooms_list::RoomsListRef, join_leave_room_modal::{JoinLeaveModalKind, JoinLeaveRoomModalAction}, room::{BasicRoomDetails, RoomPreviewAvatar}, shared::{avatar::AvatarWidgetRefExt, popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, restore_status_view::RestoreStatusViewWidgetExt}, sliding_sync::{submit_async_request, MatrixRequest}, utils::{self, display_name_with_fallback, room_name_or_id}}; use super::rooms_list::{InviteState, InviterInfo}; @@ -527,7 +527,12 @@ impl InviteScreen { self.info = Some(InviteDetails { room_info: BasicRoomDetails { room_id: room_id.clone(), - room_name: invite.room_name.clone(), + room_name: Some(display_name_with_fallback( + &invite.room_name, + invite.canonical_alias.as_ref(), + &invite.alt_aliases, + &invite.room_id, + )), room_avatar: invite.room_avatar.clone(), }, inviter: invite.inviter_info.clone(), diff --git a/src/home/room_preview.rs b/src/home/room_preview.rs index 04363513..0fd8eea0 100644 --- a/src/home/room_preview.rs +++ b/src/home/room_preview.rs @@ -5,7 +5,7 @@ use crate::{ room::RoomPreviewAvatar, shared::{ avatar::AvatarWidgetExt, html_or_plaintext::HtmlOrPlaintextWidgetExt, unread_badge::UnreadBadgeWidgetExt as _, - }, utils::{self, relative_format} + }, utils::{self, display_name_with_fallback, relative_format} }; use super::rooms_list::{InvitedRoomInfo, InviterInfo, JoinedRoomInfo, RoomsListScopeProps}; @@ -296,9 +296,13 @@ impl RoomPreviewContent { cx: &mut Cx, room_info: &JoinedRoomInfo, ) { - if let Some(ref name) = room_info.room_name { - self.view.label(id!(room_name)).set_text(cx, name); - } + let display_name = display_name_with_fallback( + &room_info.room_name, + room_info.canonical_alias.as_ref(), + &room_info.alt_aliases, + &room_info.room_id, + ); + self.view.label(id!(room_name)).set_text(cx, &display_name); if let Some((ts, msg)) = room_info.latest.as_ref() { if let Some(human_readable_date) = relative_format(*ts) { self.view @@ -324,11 +328,13 @@ impl RoomPreviewContent { cx: &mut Cx, room_info: &InvitedRoomInfo, ) { - self.view.label(id!(room_name)).set_text( - cx, - room_info.room_name.as_deref() - .unwrap_or("Invite to unnamed room"), + let display_name = display_name_with_fallback( + &room_info.room_name, + room_info.canonical_alias.as_ref(), + &room_info.alt_aliases, + &room_info.room_id, ); + self.view.label(id!(room_name)).set_text(cx, &display_name); // Hide the timestamp field, and use the latest message field to show the inviter. self.view.label(id!(timestamp)).set_text(cx, ""); let inviter_string = match &room_info.inviter_info { diff --git a/src/home/rooms_list.rs b/src/home/rooms_list.rs index 16454f3b..09802d97 100644 --- a/src/home/rooms_list.rs +++ b/src/home/rooms_list.rs @@ -1,12 +1,12 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc}; use crossbeam_queue::SegQueue; use makepad_widgets::*; -use matrix_sdk::{ruma::{events::tag::Tags, MilliSecondsSinceUnixEpoch, OwnedRoomAliasId, OwnedRoomId, OwnedUserId}, RoomState}; +use matrix_sdk::{RoomDisplayName, ruma::{events::tag::Tags, MilliSecondsSinceUnixEpoch, OwnedRoomAliasId, OwnedRoomId, OwnedUserId}, RoomState}; use crate::{ app::{AppState, SelectedRoom}, room::{room_display_filter::{RoomDisplayFilter, RoomDisplayFilterBuilder, RoomFilterCriteria, SortFn}, RoomPreviewAvatar}, shared::{collapsible_header::{CollapsibleHeaderAction, CollapsibleHeaderWidgetRefExt, HeaderCategory}, jump_to_bottom_button::UnreadMessageCount, popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, room_filter_input_bar::RoomFilterAction}, - sliding_sync::{submit_async_request, MatrixRequest, PaginationDirection}, utils::room_name_or_id, + sliding_sync::{submit_async_request, MatrixRequest, PaginationDirection}, utils::display_name_with_fallback, }; use super::room_preview::RoomPreviewAction; @@ -132,7 +132,7 @@ pub enum RoomsListUpdate { /// Update the displayable name for the given room. UpdateRoomName { room_id: OwnedRoomId, - new_room_name: Option, + new_room_name: RoomDisplayName, }, /// Update the avatar (image) for the given room. UpdateRoomAvatar { @@ -201,7 +201,7 @@ pub struct JoinedRoomInfo { /// The matrix ID of this room. pub room_id: OwnedRoomId, /// The displayable name of this room, if known. - pub room_name: Option, + pub room_name: RoomDisplayName, /// The number of unread messages in this room. pub num_unread_messages: u64, /// The number of unread mentions in this room. @@ -240,7 +240,7 @@ pub struct InvitedRoomInfo { /// The matrix ID of this room. pub room_id: OwnedRoomId, /// The displayable name of this room, if known. - pub room_name: Option, + pub room_name: RoomDisplayName, /// The canonical alias for this room, if any. pub canonical_alias: Option, /// The alternative aliases for this room, if any. @@ -399,7 +399,6 @@ impl RoomsList { RoomsListUpdate::AddJoinedRoom(joined_room) => { let room_id = joined_room.room_id.clone(); let is_direct = joined_room.is_direct; - let room_name = joined_room.room_name.clone(); let should_display = (self.display_filter)(&joined_room); let replaced = self.all_joined_rooms.insert(room_id.clone(), joined_room); if replaced.is_none() { @@ -425,10 +424,19 @@ impl RoomsList { self.displayed_invited_rooms.iter() .position(|r| r == &room_id) .map(|index| self.displayed_invited_rooms.remove(index)); + let new_room_name = self.all_joined_rooms.get(&room_id).map(|room| display_name_with_fallback( + &room.room_name, + room.canonical_alias.as_ref(), + &room.alt_aliases, + &room.room_id, + )); cx.widget_action( self.widget_uid(), &scope.path, - RoomsListAction::InviteAccepted { room_id, room_name } + RoomsListAction::InviteAccepted { + room_id: room_id.clone(), + room_name: new_room_name, + } ); } self.update_status_rooms_count(); @@ -460,9 +468,11 @@ impl RoomsList { } } RoomsListUpdate::UpdateRoomName { room_id, new_room_name } => { + // Try to update joined room first if let Some(room) = self.all_joined_rooms.get_mut(&room_id) { let was_displayed = (self.display_filter)(room); - room.room_name = new_room_name; + // Keep the full RoomDisplayName to preserve EmptyWas semantics + room.room_name = new_room_name.clone(); let should_display = (self.display_filter)(room); match (was_displayed, should_display) { // No need to update the displayed rooms list. @@ -482,14 +492,37 @@ impl RoomsList { // Room was not displayed but should now be displayed. (false, true) => { if room.is_direct { - self.displayed_direct_rooms.push(room_id); + self.displayed_direct_rooms.push(room_id.clone()); } else { - self.displayed_regular_rooms.push(room_id); + self.displayed_regular_rooms.push(room_id.clone()); } } } - } else { - error!("Error: couldn't find room {room_id} to update room name"); + } + // If not a joined room, try to update invited room + else { + let invited_rooms_ref = get_invited_rooms(cx); + let mut invited_rooms = invited_rooms_ref.borrow_mut(); + if let Some(invited_room) = invited_rooms.get_mut(&room_id) { + let was_displayed = (self.display_filter)(invited_room); + invited_room.room_name = new_room_name; + let should_display = (self.display_filter)(invited_room); + match (was_displayed, should_display) { + (true, true) | (false, false) => { } + (true, false) => { + self.displayed_invited_rooms.iter() + .position(|r| r == &room_id) + .map(|index| self.displayed_invited_rooms.remove(index)); + } + (false, true) => { + if !self.displayed_invited_rooms.contains(&room_id) { + self.displayed_invited_rooms.push(room_id.clone()); + } + } + } + } else { + warning!("Warning: couldn't find invited room {} to update room name", room_id); + } } } RoomsListUpdate::UpdateIsDirect { room_id, is_direct } => { @@ -497,9 +530,15 @@ impl RoomsList { if room.is_direct == is_direct { continue; } + let room_name_text = display_name_with_fallback( + &room.room_name, + room.canonical_alias.as_ref(), + &room.alt_aliases, + &room.room_id, + ); enqueue_popup_notification(PopupItem { message: format!("{} was changed from {} to {}.", - room_name_or_id(room.room_name.as_ref(), &room_id), + room_name_text, if room.is_direct { "direct" } else { "regular" }, if is_direct { "direct" } else { "regular" } ), @@ -832,10 +871,30 @@ impl RoomsList { /// Returns a room's avatar and displayable name. pub fn get_room_avatar_and_name(&self, room_id: &OwnedRoomId) -> Option<(RoomPreviewAvatar, Option)> { self.all_joined_rooms.get(room_id) - .map(|room_info| (room_info.avatar.clone(), room_info.room_name.clone())) + .map(|room_info| { + ( + room_info.avatar.clone(), + Some(display_name_with_fallback( + &room_info.room_name, + room_info.canonical_alias.as_ref(), + &room_info.alt_aliases, + &room_info.room_id, + )), + ) + }) .or_else(|| { self.invited_rooms.borrow().get(room_id) - .map(|room_info| (room_info.room_avatar.clone(), room_info.room_name.clone())) + .map(|room_info| { + ( + room_info.room_avatar.clone(), + Some(display_name_with_fallback( + &room_info.room_name, + room_info.canonical_alias.as_ref(), + &room_info.alt_aliases, + &room_info.room_id, + )), + ) + }) }) } } @@ -860,12 +919,22 @@ impl Widget for RoomsList { let new_selected_room = if let Some(jr) = self.all_joined_rooms.get(&clicked_room_id) { SelectedRoom::JoinedRoom { room_id: jr.room_id.clone().into(), - room_name: jr.room_name.clone(), + room_name: Some(display_name_with_fallback( + &jr.room_name, + jr.canonical_alias.as_ref(), + &jr.alt_aliases, + &jr.room_id, + )), } } else if let Some(ir) = self.invited_rooms.borrow().get(&clicked_room_id) { SelectedRoom::InvitedRoom { room_id: ir.room_id.to_owned().into(), - room_name: ir.room_name.clone(), + room_name: Some(display_name_with_fallback( + &ir.room_name, + ir.canonical_alias.as_ref(), + &ir.alt_aliases, + &ir.room_id, + )), } } else { error!("BUG: couldn't find clicked room details for room {clicked_room_id}"); diff --git a/src/room/room_display_filter.rs b/src/room/room_display_filter.rs index 0453bda1..b164ab68 100644 --- a/src/room/room_display_filter.rs +++ b/src/room/room_display_filter.rs @@ -7,7 +7,7 @@ use matrix_sdk::ruma::{ OwnedRoomAliasId, RoomAliasId, RoomId, }; -use crate::home::rooms_list::{InvitedRoomInfo, JoinedRoomInfo}; +use crate::{home::rooms_list::{InvitedRoomInfo, JoinedRoomInfo}, utils::display_name_with_fallback}; static EMPTY_TAGS: Tags = BTreeMap::new(); @@ -29,7 +29,12 @@ impl FilterableRoom for JoinedRoomInfo { } fn room_name(&self) -> Cow<'_, str> { - self.room_name.as_deref().map(Into::into).unwrap_or_default() + Cow::Owned(display_name_with_fallback( + &self.room_name, + self.canonical_alias.as_ref(), + &self.alt_aliases, + &self.room_id, + )) } fn unread_mentions(&self) -> u64 { @@ -63,7 +68,12 @@ impl FilterableRoom for InvitedRoomInfo { } fn room_name(&self) -> Cow<'_, str> { - self.room_name.as_deref().map(Into::into).unwrap_or_default() + Cow::Owned(display_name_with_fallback( + &self.room_name, + self.canonical_alias.as_ref(), + &self.alt_aliases, + &self.room_id, + )) } fn unread_mentions(&self) -> u64 { diff --git a/src/sliding_sync.rs b/src/sliding_sync.rs index 2d1f3fd1..098788bb 100644 --- a/src/sliding_sync.rs +++ b/src/sliding_sync.rs @@ -48,7 +48,7 @@ use crate::{ jump_to_bottom_button::UnreadMessageCount, popup_list::{enqueue_popup_notification, PopupItem, PopupKind} }, - utils::{self, avatar_from_room_name, AVATAR_THUMBNAIL_FORMAT}, + utils::{self, avatar_from_room_name, preferred_room_name, AVATAR_THUMBNAIL_FORMAT}, verification::add_verification_event_handlers_and_sync_client }; @@ -2167,9 +2167,15 @@ async fn update_room( } if old_room.display_name != new_room.display_name { log!("Updating room {} name: {:?} --> {:?}", new_room_id, old_room.display_name, new_room.display_name); + + let new_name = new_room + .display_name + .clone() + .unwrap_or(RoomDisplayName::Empty); + enqueue_rooms_list_update(RoomsListUpdate::UpdateRoomName { room_id: new_room_id.clone(), - new_room_name: new_room.display_name.as_ref().map(|n| n.to_string()), + new_room_name: new_name, }); } @@ -2328,8 +2334,12 @@ async fn add_new_room( let latest = latest_event.as_ref().map( |ev| get_latest_event_details(ev, &new_room.room_id) ); - let room_name = new_room.display_name.as_ref().map(|n| n.to_string()); - let room_avatar = room_avatar(&new_room.room, room_name.as_deref()).await; + let room_display_name = new_room + .display_name + .clone() + .unwrap_or(RoomDisplayName::Empty); + let room_name_text = preferred_room_name(&room_display_name); + let room_avatar = room_avatar(&new_room.room, room_name_text.as_deref()).await; let inviter_info = if let Some(inviter) = invite_details.and_then(|d| d.inviter) { Some(InviterInfo { @@ -2347,7 +2357,7 @@ async fn add_new_room( }; rooms_list::enqueue_rooms_list_update(RoomsListUpdate::AddInvitedRoom(InvitedRoomInfo { room_id: new_room.room_id.clone(), - room_name, + room_name: room_display_name, inviter_info, room_avatar, canonical_alias: new_room.room.canonical_alias(), @@ -2406,7 +2416,11 @@ async fn add_new_room( // We need to add the room to the `ALL_JOINED_ROOMS` list before we can // send the `AddJoinedRoom` update to the UI, because the UI might immediately // issue a `MatrixRequest` that relies on that room being in `ALL_JOINED_ROOMS`. - let room_name = new_room.display_name.as_ref().map(|n| n.to_string()); + let room_display_name = new_room + .display_name + .clone() + .unwrap_or(RoomDisplayName::Empty); + let room_name = preferred_room_name(&room_display_name); rooms_list::enqueue_rooms_list_update(RoomsListUpdate::AddJoinedRoom(JoinedRoomInfo { room_id: new_room.room_id.clone(), latest, @@ -2415,7 +2429,7 @@ async fn add_new_room( num_unread_mentions: new_room.num_unread_mentions, // start with a basic text avatar; the avatar image will be fetched asynchronously below. avatar: avatar_from_room_name(room_name.as_deref()), - room_name, + room_name: room_display_name, canonical_alias: new_room.room.canonical_alias(), alt_aliases: new_room.room.alt_aliases(), has_been_paginated: false, diff --git a/src/utils.rs b/src/utils.rs index 59cdba7f..85b361e2 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -7,7 +7,11 @@ use url::Url; use unicode_segmentation::UnicodeSegmentation; use chrono::{DateTime, Duration, Local, TimeZone}; use makepad_widgets::{error, image_cache::ImageError, makepad_micro_serde::{DeRon, DeRonErr, DeRonState, SerRon, SerRonState}, Cx, Event, ImageRef}; -use matrix_sdk::{media::{MediaFormat, MediaThumbnailSettings}, ruma::{api::client::media::get_content_thumbnail::v3::Method, MilliSecondsSinceUnixEpoch, OwnedRoomId, RoomId}}; +use matrix_sdk::{ + media::{MediaFormat, MediaThumbnailSettings}, + ruma::{api::client::media::get_content_thumbnail::v3::Method, MilliSecondsSinceUnixEpoch, OwnedRoomAliasId, OwnedRoomId, RoomId}, + RoomDisplayName, +}; use matrix_sdk_ui::timeline::{EventTimelineItem, PaginationError, TimelineDetails}; use crate::{room::RoomPreviewAvatar, sliding_sync::{submit_async_request, MatrixRequest}}; @@ -142,6 +146,39 @@ pub fn unix_time_millis_to_datetime(millis: MilliSecondsSinceUnixEpoch) -> Optio Local.timestamp_millis_opt(millis).single() } +/// Converts a `RoomDisplayName` to the text we prefer to show in the Rooms list. +/// +/// Returns `None` when the display name is explicitly empty so that callers can +/// fall back to aliases or the room ID. +pub fn preferred_room_name(display_name: &RoomDisplayName) -> Option { + match display_name { + RoomDisplayName::Empty => None, + _ => Some(display_name.to_string()), + } +} + +/// Returns the room name that should be shown to the user, falling back to aliases or the room ID. +pub fn display_name_with_fallback( + display_name: &RoomDisplayName, + canonical_alias: Option<&OwnedRoomAliasId>, + alt_aliases: &[OwnedRoomAliasId], + room_id: &OwnedRoomId, +) -> String { + if let Some(name) = preferred_room_name(display_name) { + return name; + } + + if let Some(alias) = canonical_alias { + return alias.as_str().to_owned(); + } + + if let Some(alias) = alt_aliases.first() { + return alias.as_str().to_owned(); + } + + format!("Room ID {}", room_id.as_str()) +} + /// Returns a string error message, handling special cases related to joining/leaving rooms. pub fn stringify_join_leave_error( error: &matrix_sdk::Error, From b46f56fa708c9683c8c6e097d8726a6a0cf62c8e Mon Sep 17 00:00:00 2001 From: Alvin Date: Wed, 29 Oct 2025 10:11:28 +0800 Subject: [PATCH 2/5] Remove preferred_room_name and use RoomDisplayName directly --- src/app.rs | 17 +++--- src/home/invite_screen.rs | 43 +++++++------- src/home/main_desktop_ui.rs | 18 +++--- src/home/main_mobile_ui.rs | 4 +- src/home/room_preview.rs | 16 +----- src/home/room_screen.rs | 66 ++++++++++++--------- src/home/rooms_list.rs | 53 +++++------------ src/home/tombstone_footer.rs | 24 ++++---- src/join_leave_room_modal.rs | 36 ++++++------ src/room/mod.rs | 4 +- src/room/room_display_filter.rs | 16 +----- src/shared/mentionable_text_input.rs | 1 + src/sliding_sync.rs | 22 +++++-- src/utils.rs | 85 ++++++++++++++++------------ 14 files changed, 201 insertions(+), 204 deletions(-) diff --git a/src/app.rs b/src/app.rs index 3eff1c71..339acd86 100644 --- a/src/app.rs +++ b/src/app.rs @@ -7,7 +7,7 @@ use std::collections::HashMap; use makepad_widgets::{makepad_micro_serde::*, *}; -use matrix_sdk::ruma::{OwnedRoomId, RoomId}; +use matrix_sdk::{RoomDisplayName, ruma::{OwnedRoomId, RoomId}}; use crate::{ avatar_cache::clear_avatar_cache, home::{ main_desktop_ui::MainDesktopUiAction, new_message_context_menu::NewMessageContextMenuWidgetRefExt, room_screen::{clear_timeline_states, MessageAction}, rooms_list::{clear_all_invited_rooms, enqueue_rooms_list_update, RoomsListAction, RoomsListRef, RoomsListUpdate} @@ -20,6 +20,7 @@ use crate::{ }, sliding_sync::current_user_id, utils::{ room_name_or_id, OwnedRoomIdRon, + RoomDisplayNameRon, }, verification::VerificationAction, verification_modal::{ VerificationModalAction, VerificationModalWidgetRefExt, @@ -576,7 +577,7 @@ impl App { // Select and scroll to the destination room in the rooms list. let new_selected_room = SelectedRoom::JoinedRoom { room_id: destination_room.room_id.clone().into(), - room_name: destination_room.room_name.clone(), + room_name: RoomDisplayNameRon::from(destination_room.room_name.clone()), }; enqueue_rooms_list_update(RoomsListUpdate::ScrollToRoom(destination_room.room_id.clone())); cx.widget_action( @@ -624,11 +625,11 @@ pub struct SavedDockState { pub enum SelectedRoom { JoinedRoom { room_id: OwnedRoomIdRon, - room_name: Option, + room_name: RoomDisplayNameRon, }, InvitedRoom { room_id: OwnedRoomIdRon, - room_name: Option, + room_name: RoomDisplayNameRon, }, } @@ -640,10 +641,10 @@ impl SelectedRoom { } } - pub fn room_name(&self) -> Option<&String> { + pub fn room_name(&self) -> &RoomDisplayName { match self { - SelectedRoom::JoinedRoom { room_name, .. } => room_name.as_ref(), - SelectedRoom::InvitedRoom { room_name, .. } => room_name.as_ref(), + SelectedRoom::JoinedRoom { room_name, .. } => &room_name.0, + SelectedRoom::InvitedRoom { room_name, .. } => &room_name.0, } } @@ -656,7 +657,7 @@ impl SelectedRoom { pub fn upgrade_invite_to_joined(&mut self, room_id: &RoomId) -> bool { match self { SelectedRoom::InvitedRoom { room_id: id, room_name } if id.0 == room_id => { - let name = room_name.take(); + let name = room_name.clone(); *self = SelectedRoom::JoinedRoom { room_id: id.clone(), room_name: name, diff --git a/src/home/invite_screen.rs b/src/home/invite_screen.rs index 99521a34..178be9ad 100644 --- a/src/home/invite_screen.rs +++ b/src/home/invite_screen.rs @@ -6,9 +6,9 @@ use std::ops::Deref; use makepad_widgets::*; -use matrix_sdk::ruma::OwnedRoomId; +use matrix_sdk::{RoomDisplayName, ruma::OwnedRoomId}; -use crate::{app::AppStateAction, home::rooms_list::RoomsListRef, join_leave_room_modal::{JoinLeaveModalKind, JoinLeaveRoomModalAction}, room::{BasicRoomDetails, RoomPreviewAvatar}, shared::{avatar::AvatarWidgetRefExt, popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, restore_status_view::RestoreStatusViewWidgetExt}, sliding_sync::{submit_async_request, MatrixRequest}, utils::{self, display_name_with_fallback, room_name_or_id}}; +use crate::{app::AppStateAction, home::rooms_list::RoomsListRef, join_leave_room_modal::{JoinLeaveModalKind, JoinLeaveRoomModalAction}, room::{BasicRoomDetails, RoomPreviewAvatar}, shared::{avatar::AvatarWidgetRefExt, popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, restore_status_view::RestoreStatusViewWidgetExt}, sliding_sync::{submit_async_request, MatrixRequest}, utils::{self, room_name_or_id}}; use super::rooms_list::{InviteState, InviterInfo}; @@ -268,7 +268,7 @@ pub struct InviteScreen { /// The ID of the room that has been invited. /// This is used to wait for RoomsPanel #[rust] room_id: Option, - #[rust] room_name: String, + #[rust(RoomDisplayName::Empty)] room_name: RoomDisplayName, #[rust] is_loaded: bool, #[rust] all_rooms_loaded: bool, } @@ -351,7 +351,8 @@ impl Widget for InviteScreen { Some(JoinRoomResultAction::Failed { room_id, error }) if room_id == &info.room_id => { self.invite_state = InviteState::WaitingOnUserInput; if !self.has_shown_confirmation { - let msg = utils::stringify_join_leave_error(error, info.room_name.as_deref(), true, true); + let room_label = room_name_or_id(&info.room_name, &info.room_id); + let msg = utils::stringify_join_leave_error(error, Some(room_label.as_str()), true, true); enqueue_popup_notification(PopupItem { message: msg, kind: PopupKind::Error, auto_dismissal_duration: None }); } continue; @@ -395,9 +396,14 @@ impl Widget for InviteScreen { fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep { + let room_display_text = self.room_id + .as_ref() + .map(|id| room_name_or_id(&self.room_name, id)) + .unwrap_or_else(|| self.room_name.to_string()); + if !self.is_loaded { let mut restore_status_view = self.view.restore_status_view(id!(restore_status_view)); - restore_status_view.set_content(cx, self.all_rooms_loaded, &self.room_name); + restore_status_view.set_content(cx, self.all_rooms_loaded, &room_display_text); return restore_status_view.draw(cx, scope); } let Some(info) = self.info.as_ref() else { @@ -467,10 +473,8 @@ impl Widget for InviteScreen { ); } } - room_view.label(id!(room_name)).set_text( - cx, - info.room_name.as_deref().unwrap_or_else(|| info.room_id.as_str()), - ); + let invite_room_label = room_name_or_id(&info.room_name, &info.room_id); + room_view.label(id!(room_name)).set_text(cx, &invite_room_label); // Third, set the buttons' text based on the invite state. let cancel_button = self.view.button(id!(cancel_button)); @@ -516,9 +520,10 @@ impl Widget for InviteScreen { impl InviteScreen { /// Sets the ID of the invited room that will be displayed by this screen. - pub fn set_displayed_invite>>(&mut self, cx: &mut Cx, room_id: OwnedRoomId, room_name: S) { + pub fn set_displayed_invite(&mut self, cx: &mut Cx, room_id: OwnedRoomId, room_name: RoomDisplayName) { self.room_id = Some(room_id.clone()); - self.room_name = room_name_or_id(room_name.into(), &room_id); + self.room_name = room_name; + let room_display_text = room_name_or_id(&self.room_name, &room_id); if let Some(invite) = super::rooms_list::get_invited_rooms(cx) .borrow() @@ -527,12 +532,7 @@ impl InviteScreen { self.info = Some(InviteDetails { room_info: BasicRoomDetails { room_id: room_id.clone(), - room_name: Some(display_name_with_fallback( - &invite.room_name, - invite.canonical_alias.as_ref(), - &invite.alt_aliases, - &invite.room_id, - )), + room_name: invite.room_name.clone(), room_avatar: invite.room_avatar.clone(), }, inviter: invite.inviter_info.clone(), @@ -543,13 +543,18 @@ impl InviteScreen { self.all_rooms_loaded = true; self.redraw(cx); } - self.view.restore_status_view(id!(restore_status_view)).set_visible(cx, !self.is_loaded); + self.view + .restore_status_view(id!(restore_status_view)) + .set_content(cx, self.all_rooms_loaded, &room_display_text); + self.view + .restore_status_view(id!(restore_status_view)) + .set_visible(cx, !self.is_loaded); } } impl InviteScreenRef { /// See [`InviteScreen::set_displayed_invite()`]. - pub fn set_displayed_invite>>(&self, cx: &mut Cx, room_id: OwnedRoomId, room_name: S) { + pub fn set_displayed_invite(&self, cx: &mut Cx, room_id: OwnedRoomId, room_name: RoomDisplayName) { if let Some(mut inner) = self.borrow_mut() { inner.set_displayed_invite(cx, room_id, room_name); } diff --git a/src/home/main_desktop_ui.rs b/src/home/main_desktop_ui.rs index ca728618..f6c4c86f 100644 --- a/src/home/main_desktop_ui.rs +++ b/src/home/main_desktop_ui.rs @@ -1,5 +1,5 @@ use makepad_widgets::*; -use matrix_sdk::ruma::OwnedRoomId; +use matrix_sdk::{RoomDisplayName, ruma::OwnedRoomId}; use tokio::sync::Notify; use std::{collections::HashMap, sync::Arc}; @@ -129,11 +129,11 @@ impl MainDesktopUI { let (kind, name) = match &room { SelectedRoom::JoinedRoom { room_id, room_name } => ( live_id!(room_screen), - room_name_or_id(room_name.as_ref(), room_id), + room_name_or_id(&RoomDisplayName::from(room_name.clone()), OwnedRoomId::from(room_id.clone())), ), SelectedRoom::InvitedRoom { room_id, room_name } => ( live_id!(invite_screen), - room_name_or_id(room_name.as_ref(), room_id), + room_name_or_id(&RoomDisplayName::from(room_name.clone()), OwnedRoomId::from(room_id.clone())), ), }; let new_tab_widget = dock.create_and_select_tab( @@ -155,14 +155,14 @@ impl MainDesktopUI { new_widget.as_room_screen().set_displayed_room( cx, room_id.clone().into(), - room.room_name().cloned(), + room.room_name().clone(), ); } SelectedRoom::InvitedRoom { room_id, room_name: _ } => { new_widget.as_invite_screen().set_displayed_invite( cx, room_id.clone().into(), - room.room_name().cloned() + room.room_name().clone() ); } } @@ -231,14 +231,14 @@ impl MainDesktopUI { cx: &mut Cx, _scope: &mut Scope, room_id: OwnedRoomId, - room_name: Option, + room_name: RoomDisplayName, ) { let dock = self.view.dock(id!(dock)); let Some((new_widget, true)) = dock.replace_tab( cx, LiveId::from_str(room_id.as_str()), live_id!(room_screen), - Some(room_name_or_id(room_name.as_ref(), &room_id)), + Some(room_name_or_id(&room_name, &room_id)), false, ) else { // Nothing we can really do here except log an error. @@ -363,14 +363,14 @@ impl WidgetMatchEvent for MainDesktopUI { widget.as_room_screen().set_displayed_room( cx, room_id.clone().into(), - room_name.clone(), + room_name.clone().into(), ); } Some(SelectedRoom::InvitedRoom { room_id, room_name }) => { widget.as_invite_screen().set_displayed_invite( cx, room_id.clone().into(), - room_name.clone(), + room_name.clone().into(), ); } _ => { } diff --git a/src/home/main_mobile_ui.rs b/src/home/main_mobile_ui.rs index 94902a4b..05b27e37 100644 --- a/src/home/main_mobile_ui.rs +++ b/src/home/main_mobile_ui.rs @@ -80,7 +80,7 @@ impl Widget for MainMobileUI { // Get a reference to the `RoomScreen` widget and tell it which room's data to show. self.view .room_screen(id!(room_screen)) - .set_displayed_room(cx, room_id.clone().into(), room_name.clone()); + .set_displayed_room(cx, room_id.clone().into(), room_name.clone().into()); } Some(SelectedRoom::InvitedRoom { room_id, room_name }) => { show_welcome = false; @@ -88,7 +88,7 @@ impl Widget for MainMobileUI { show_invite = true; self.view .invite_screen(id!(invite_screen)) - .set_displayed_invite(cx, room_id.clone().into(), room_name.clone()); + .set_displayed_invite(cx, room_id.clone().into(), room_name.clone().into()); } None => { show_welcome = true; diff --git a/src/home/room_preview.rs b/src/home/room_preview.rs index 0fd8eea0..527bb31b 100644 --- a/src/home/room_preview.rs +++ b/src/home/room_preview.rs @@ -5,7 +5,7 @@ use crate::{ room::RoomPreviewAvatar, shared::{ avatar::AvatarWidgetExt, html_or_plaintext::HtmlOrPlaintextWidgetExt, unread_badge::UnreadBadgeWidgetExt as _, - }, utils::{self, display_name_with_fallback, relative_format} + }, utils::{self, relative_format, room_name_or_id} }; use super::rooms_list::{InvitedRoomInfo, InviterInfo, JoinedRoomInfo, RoomsListScopeProps}; @@ -296,12 +296,7 @@ impl RoomPreviewContent { cx: &mut Cx, room_info: &JoinedRoomInfo, ) { - let display_name = display_name_with_fallback( - &room_info.room_name, - room_info.canonical_alias.as_ref(), - &room_info.alt_aliases, - &room_info.room_id, - ); + let display_name = room_name_or_id(&room_info.room_name, &room_info.room_id); self.view.label(id!(room_name)).set_text(cx, &display_name); if let Some((ts, msg)) = room_info.latest.as_ref() { if let Some(human_readable_date) = relative_format(*ts) { @@ -328,12 +323,7 @@ impl RoomPreviewContent { cx: &mut Cx, room_info: &InvitedRoomInfo, ) { - let display_name = display_name_with_fallback( - &room_info.room_name, - room_info.canonical_alias.as_ref(), - &room_info.alt_aliases, - &room_info.room_id, - ); + let display_name = room_name_or_id(&room_info.room_name, &room_info.room_id); self.view.label(id!(room_name)).set_text(cx, &display_name); // Hide the timestamp field, and use the latest message field to show the inviter. self.view.label(id!(timestamp)).set_text(cx, ""); diff --git a/src/home/room_screen.rs b/src/home/room_screen.rs index cb992b66..d45153e8 100644 --- a/src/home/room_screen.rs +++ b/src/home/room_screen.rs @@ -7,7 +7,7 @@ use bytesize::ByteSize; use imbl::Vector; use makepad_widgets::{image_cache::ImageBuffer, *}; use matrix_sdk::{ - room::RoomMember, ruma::{ + room::RoomMember, RoomDisplayName, ruma::{ events::{ receipt::Receipt, room::{ @@ -557,7 +557,7 @@ pub struct RoomScreen { /// The room ID of the currently-shown room. #[rust] room_id: Option, /// The display name of the currently-shown room. - #[rust] room_name: String, + #[rust(RoomDisplayName::Empty)] room_name: RoomDisplayName, /// The persistent UI-relevant states for the room that this widget is currently displaying. #[rust] tl_state: Option, /// The set of pinned events in this room. @@ -694,15 +694,15 @@ impl Widget for RoomScreen { if let ShowUserProfileAction::ShowUserProfile(profile_and_room_id) = action.as_widget_action().cast() { // Only show the user profile in room that this avatar belongs to if self.room_id.as_ref().is_some_and(|r| r == &profile_and_room_id.room_id) { - self.show_user_profile( - cx, - &user_profile_sliding_pane, - UserProfilePaneInfo { - profile_and_room_id, - room_name: self.room_name.clone(), - room_member: None, - }, - ); + self.show_user_profile( + cx, + &user_profile_sliding_pane, + UserProfilePaneInfo { + profile_and_room_id, + room_name: self.current_room_label(), + room_member: None, + }, + ); } } } @@ -797,7 +797,7 @@ impl Widget for RoomScreen { let (room_display_name, room_avatar_url) = get_client() .and_then(|client| client.get_room(&room_id)) .map(|room| ( - room.cached_display_name().map(|name| name.to_string()), + room.cached_display_name(), room.avatar_url() )) .unwrap_or((None, None)); @@ -815,7 +815,7 @@ impl Widget for RoomScreen { room_screen_widget_uid, room_id, room_members: None, - room_display_name: None, + room_display_name: Some(self.room_name.clone()), room_avatar_url: None, } } else { @@ -902,7 +902,8 @@ impl Widget for RoomScreen { // If the room isn't loaded yet, we show the restore status label only. if !self.is_loaded { let mut restore_status_view = self.view.restore_status_view(id!(restore_status_view)); - restore_status_view.set_content(cx, self.all_rooms_loaded, &self.room_name); + let room_label = self.current_room_label(); + restore_status_view.set_content(cx, self.all_rooms_loaded, &room_label); return restore_status_view.draw(cx, scope); } if self.tl_state.is_none() { @@ -1076,7 +1077,8 @@ impl Widget for RoomScreen { // If the list is not filling the viewport, we need to back paginate the timeline // until we have enough events items to fill the viewport. if !tl_state.fully_paginated && !list.is_filling_viewport() { - log!("Automatically paginating timeline to fill viewport for room \"{}\" ({})", self.room_name, room_id); + let room_label = room_name_or_id(&self.room_name, &room_id); + log!("Automatically paginating timeline to fill viewport for room \"{}\" ({})", room_label, room_id); submit_async_request(MatrixRequest::PaginateRoomTimeline { room_id: room_id.clone(), num_events: 50, @@ -1089,6 +1091,13 @@ impl Widget for RoomScreen { } impl RoomScreen { + fn current_room_label(&self) -> String { + match self.room_id.as_ref() { + Some(room_id) => room_name_or_id(&self.room_name, room_id), + None => self.room_name.to_string(), + } + } + /// Processes all pending background updates to the currently-shown timeline. /// /// Redraws this RoomScreen view if any updates were applied. @@ -1097,6 +1106,7 @@ impl RoomScreen { let jump_to_bottom = self.jump_to_bottom_button(id!(jump_to_bottom)); let curr_first_id = portal_list.first_id(); let ui = self.widget_uid(); + let room_label_cached = self.current_room_label(); let Some(tl) = self.tl_state.as_mut() else { return }; let mut done_loading = false; @@ -1294,9 +1304,9 @@ impl RoomScreen { } } TimelineUpdate::PaginationError { error, direction } => { - error!("Pagination error ({direction}) in room \"{}\", {}: {error:?}", self.room_name, tl.room_id); + error!("Pagination error ({direction}) in room \"{}\", {}: {error:?}", room_label_cached, tl.room_id); enqueue_popup_notification(PopupItem { - message: utils::stringify_pagination_error(&error, &self.room_name), + message: utils::stringify_pagination_error(&error, room_label_cached.as_str()), auto_dismissal_duration: None, kind: PopupKind::Error, }); @@ -1458,7 +1468,7 @@ impl RoomScreen { }, room_id: self.room_id.clone().unwrap(), }, - room_name: self.room_name.clone(), + room_name: self.current_room_label(), // TODO: use the extra `via` parameters room_member: None, }, @@ -1997,8 +2007,9 @@ impl RoomScreen { let rooms_list_ref = cx.get_global::(); let is_loaded_now = rooms_list_ref.is_room_loaded(&room_id); if is_loaded_now && !self.is_loaded { + let room_label = self.current_room_label(); log!("Detected that room \"{}\" ({}) is now loaded for the first time", - self.room_name, room_id, + room_label, room_id, ); is_first_time_being_loaded = true; } @@ -2012,7 +2023,8 @@ impl RoomScreen { // when they first open the room, and there might not be any messages yet. if is_first_time_being_loaded { if !tl_state.fully_paginated { - log!("Sending a first-time backwards pagination request for room \"{}\" {}", self.room_name, room_id); + let room_label = self.current_room_label(); + log!("Sending a first-time backwards pagination request for room \"{}\" {}", room_label, room_id); submit_async_request(MatrixRequest::PaginateRoomTimeline { room_id: room_id.clone(), num_events: 50, @@ -2152,11 +2164,11 @@ impl RoomScreen { } /// Sets this `RoomScreen` widget to display the timeline for the given room. - pub fn set_displayed_room>>( + pub fn set_displayed_room( &mut self, cx: &mut Cx, room_id: OwnedRoomId, - room_name: S, + room_name: RoomDisplayName, ) { // If the room is already being displayed, then do nothing. if self.room_id.as_ref().is_some_and(|id| id == &room_id) { return; } @@ -2164,7 +2176,7 @@ impl RoomScreen { self.hide_timeline(); // Reset the the state of the inner loading pane. self.loading_pane(id!(loading_pane)).take_state(); - self.room_name = room_name_or_id(room_name.into(), &room_id); + self.room_name = room_name; self.room_id = Some(room_id.clone()); // We initially tell every MentionableTextInput widget that the current user @@ -2279,11 +2291,11 @@ impl RoomScreen { impl RoomScreenRef { /// See [`RoomScreen::set_displayed_room()`]. - pub fn set_displayed_room>>( + pub fn set_displayed_room( &self, cx: &mut Cx, room_id: OwnedRoomId, - room_name: S, + room_name: RoomDisplayName, ) { let Some(mut inner) = self.borrow_mut() else { return }; inner.set_displayed_room(cx, room_id, room_name); @@ -2296,7 +2308,7 @@ pub struct RoomScreenProps { pub room_screen_widget_uid: WidgetUid, pub room_id: OwnedRoomId, pub room_members: Option>>, - pub room_display_name: Option, + pub room_display_name: Option, pub room_avatar_url: Option, } @@ -4162,4 +4174,4 @@ pub fn clear_timeline_states(_cx: &mut Cx) { TIMELINE_STATES.with_borrow_mut(|states| { states.clear(); }); -} \ No newline at end of file +} diff --git a/src/home/rooms_list.rs b/src/home/rooms_list.rs index 09802d97..0126fb39 100644 --- a/src/home/rooms_list.rs +++ b/src/home/rooms_list.rs @@ -6,7 +6,7 @@ use crate::{ app::{AppState, SelectedRoom}, room::{room_display_filter::{RoomDisplayFilter, RoomDisplayFilterBuilder, RoomFilterCriteria, SortFn}, RoomPreviewAvatar}, shared::{collapsible_header::{CollapsibleHeaderAction, CollapsibleHeaderWidgetRefExt, HeaderCategory}, jump_to_bottom_button::UnreadMessageCount, popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, room_filter_input_bar::RoomFilterAction}, - sliding_sync::{submit_async_request, MatrixRequest, PaginationDirection}, utils::display_name_with_fallback, + sliding_sync::{submit_async_request, MatrixRequest, PaginationDirection}, utils::{room_name_or_id, RoomDisplayNameRon}, }; use super::room_preview::RoomPreviewAction; @@ -186,7 +186,7 @@ pub enum RoomsListAction { /// to a `RoomScreen` to display now-joined room. InviteAccepted { room_id: OwnedRoomId, - room_name: Option, + room_name: RoomDisplayName, }, None, } @@ -424,12 +424,10 @@ impl RoomsList { self.displayed_invited_rooms.iter() .position(|r| r == &room_id) .map(|index| self.displayed_invited_rooms.remove(index)); - let new_room_name = self.all_joined_rooms.get(&room_id).map(|room| display_name_with_fallback( - &room.room_name, - room.canonical_alias.as_ref(), - &room.alt_aliases, - &room.room_id, - )); + let new_room_name = self.all_joined_rooms + .get(&room_id) + .map(|room| room.room_name.clone()) + .unwrap_or(RoomDisplayName::Empty); cx.widget_action( self.widget_uid(), &scope.path, @@ -530,12 +528,7 @@ impl RoomsList { if room.is_direct == is_direct { continue; } - let room_name_text = display_name_with_fallback( - &room.room_name, - room.canonical_alias.as_ref(), - &room.alt_aliases, - &room.room_id, - ); + let room_name_text = room_name_or_id(&room.room_name, &room.room_id); enqueue_popup_notification(PopupItem { message: format!("{} was changed from {} to {}.", room_name_text, @@ -869,17 +862,12 @@ impl RoomsList { } /// Returns a room's avatar and displayable name. - pub fn get_room_avatar_and_name(&self, room_id: &OwnedRoomId) -> Option<(RoomPreviewAvatar, Option)> { + pub fn get_room_avatar_and_name(&self, room_id: &OwnedRoomId) -> Option<(RoomPreviewAvatar, RoomDisplayName)> { self.all_joined_rooms.get(room_id) .map(|room_info| { ( room_info.avatar.clone(), - Some(display_name_with_fallback( - &room_info.room_name, - room_info.canonical_alias.as_ref(), - &room_info.alt_aliases, - &room_info.room_id, - )), + room_info.room_name.clone(), ) }) .or_else(|| { @@ -887,12 +875,7 @@ impl RoomsList { .map(|room_info| { ( room_info.room_avatar.clone(), - Some(display_name_with_fallback( - &room_info.room_name, - room_info.canonical_alias.as_ref(), - &room_info.alt_aliases, - &room_info.room_id, - )), + room_info.room_name.clone(), ) }) }) @@ -919,22 +902,12 @@ impl Widget for RoomsList { let new_selected_room = if let Some(jr) = self.all_joined_rooms.get(&clicked_room_id) { SelectedRoom::JoinedRoom { room_id: jr.room_id.clone().into(), - room_name: Some(display_name_with_fallback( - &jr.room_name, - jr.canonical_alias.as_ref(), - &jr.alt_aliases, - &jr.room_id, - )), + room_name: RoomDisplayNameRon::from(jr.room_name.clone()), } } else if let Some(ir) = self.invited_rooms.borrow().get(&clicked_room_id) { SelectedRoom::InvitedRoom { room_id: ir.room_id.to_owned().into(), - room_name: Some(display_name_with_fallback( - &ir.room_name, - ir.canonical_alias.as_ref(), - &ir.alt_aliases, - &ir.room_id, - )), + room_name: RoomDisplayNameRon::from(ir.room_name.clone()), } } else { error!("BUG: couldn't find clicked room details for room {clicked_room_id}"); @@ -1158,7 +1131,7 @@ impl RoomsListRef { } /// See [`RoomsList::get_room_avatar_and_name()`]. - pub fn get_room_avatar_and_name(&self, room_id: &OwnedRoomId) -> Option<(RoomPreviewAvatar, Option)> { + pub fn get_room_avatar_and_name(&self, room_id: &OwnedRoomId) -> Option<(RoomPreviewAvatar, RoomDisplayName)> { let inner = self.borrow()?; inner.get_room_avatar_and_name(room_id) } diff --git a/src/home/tombstone_footer.rs b/src/home/tombstone_footer.rs index b6a88610..814a5181 100644 --- a/src/home/tombstone_footer.rs +++ b/src/home/tombstone_footer.rs @@ -7,6 +7,7 @@ use makepad_widgets::*; use matrix_sdk::{ ruma::OwnedRoomId, + RoomDisplayName, SuccessorRoom }; @@ -15,7 +16,7 @@ use crate::{ home::rooms_list::RoomsListRef, room::{BasicRoomDetails, RoomPreviewAvatar}, shared::avatar::AvatarWidgetExt, - utils + utils::{self, room_name_or_id} }; const DEFAULT_TOMBSTONE_REASON: &str = "This room has been replaced and is no longer active"; @@ -127,10 +128,12 @@ impl TombstoneFooter { successor_room.reason.as_deref().unwrap_or(DEFAULT_TOMBSTONE_REASON), ); let rooms_list_ref = cx.get_global::(); - let (successor_avatar_preview, room_name, is_joined) = rooms_list_ref + let (successor_avatar_preview, successor_room_name, is_joined) = match rooms_list_ref .get_room_avatar_and_name(&successor_room.room_id) - .map(|(avatar, name)| (avatar, name, true)) - .unwrap_or_default(); + { + Some((avatar, name)) => (avatar, name, true), + None => (RoomPreviewAvatar::default(), RoomDisplayName::Empty, false), + }; match &successor_avatar_preview { RoomPreviewAvatar::Text(text) => { @@ -146,19 +149,16 @@ impl TombstoneFooter { ); } } + let display_name = room_name_or_id(&successor_room_name, &successor_room.room_id); let successor_info = Some(BasicRoomDetails { room_id: successor_room.room_id.clone(), - room_name, + room_name: successor_room_name.clone(), room_avatar: successor_avatar_preview, }); - self.view.label(id!(successor_room_name)).set_text( - cx, - successor_info - .as_ref() - .and_then(|f| f.room_name.as_ref()) - .map_or("(Unknown room name)", |v| v), - ); + self.view + .label(id!(successor_room_name)) + .set_text(cx, &display_name); let join_successor_button = self.view.button(id!(join_successor_button)); join_successor_button.reset_hover(cx); diff --git a/src/join_leave_room_modal.rs b/src/join_leave_room_modal.rs index c54a2a76..c8da0c2e 100644 --- a/src/join_leave_room_modal.rs +++ b/src/join_leave_room_modal.rs @@ -3,7 +3,7 @@ //! Also used as a confirmation dialog for accepting or rejecting room invites. use makepad_widgets::*; -use matrix_sdk::ruma::OwnedRoomId; +use matrix_sdk::{RoomDisplayName, ruma::OwnedRoomId}; use crate::{home::invite_screen::{InviteDetails, JoinRoomResultAction, LeaveRoomResultAction}, room::BasicRoomDetails, shared::popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, sliding_sync::{submit_async_request, MatrixRequest}, utils::{self, room_name_or_id}}; @@ -173,12 +173,12 @@ impl JoinLeaveModalKind { } } - pub fn room_name(&self) -> Option<&str> { + pub fn room_name(&self) -> &RoomDisplayName { match self { - JoinLeaveModalKind::AcceptInvite(invite) => invite.room_name.as_deref(), - JoinLeaveModalKind::RejectInvite(invite) => invite.room_name.as_deref(), - JoinLeaveModalKind::JoinRoom(room) => room.room_name.as_deref(), - JoinLeaveModalKind::LeaveRoom(room) => room.room_name.as_deref(), + JoinLeaveModalKind::AcceptInvite(invite) => &invite.room_name, + JoinLeaveModalKind::RejectInvite(invite) => &invite.room_name, + JoinLeaveModalKind::JoinRoom(room) => &room.room_name, + JoinLeaveModalKind::LeaveRoom(room) => &room.room_name, } } } @@ -249,7 +249,7 @@ impl WidgetMatchEvent for JoinLeaveRoomModal { description = format!( "Accepting an invitation to join \"{}\".\n\n\ Waiting for confirmation from the homeserver...", - room_name_or_id(invite.room_name.as_ref(), &invite.room_id), + room_name_or_id(&invite.room_name, &invite.room_id), ); accept_button_text = "Joining..."; submit_async_request(MatrixRequest::JoinRoom { @@ -261,7 +261,7 @@ impl WidgetMatchEvent for JoinLeaveRoomModal { description = format!( "Rejecting an invitation to join \"{}\".\n\n\ Waiting for confirmation from the homeserver...", - room_name_or_id(invite.room_name.as_ref(), &invite.room_id), + room_name_or_id(&invite.room_name, &invite.room_id), ); accept_button_text = "Rejecting..."; submit_async_request(MatrixRequest::LeaveRoom { @@ -273,7 +273,7 @@ impl WidgetMatchEvent for JoinLeaveRoomModal { description = format!( "Joining \"{}\".\n\n\ Waiting for confirmation from the homeserver...", - room_name_or_id(room.room_name.as_ref(), &room.room_id), + room_name_or_id(&room.room_name, &room.room_id), ); accept_button_text = "Joining..."; submit_async_request(MatrixRequest::JoinRoom { @@ -285,7 +285,7 @@ impl WidgetMatchEvent for JoinLeaveRoomModal { description = format!( "Leaving \"{}\".\n\n\ Waiting for confirmation from the homeserver...", - room_name_or_id(room.room_name.as_ref(), &room.room_id), + room_name_or_id(&room.room_name, &room.room_id), ); accept_button_text = "Leaving..."; submit_async_request(MatrixRequest::LeaveRoom { @@ -325,7 +325,8 @@ impl WidgetMatchEvent for JoinLeaveRoomModal { Some(JoinRoomResultAction::Failed { room_id, error }) if room_id == kind.room_id() => { self.view.label(id!(title)).set_text(cx, "Error joining room!"); let was_invite = matches!(kind, JoinLeaveModalKind::AcceptInvite(_) | JoinLeaveModalKind::RejectInvite(_)); - let msg = utils::stringify_join_leave_error(error, kind.room_name(), true, was_invite); + let room_label = room_name_or_id(kind.room_name(), room_id); + let msg = utils::stringify_join_leave_error(error, Some(room_label.as_str()), true, was_invite); self.view.label(id!(description)).set_text(cx, &msg); enqueue_popup_notification(PopupItem { message: msg, @@ -376,15 +377,16 @@ impl WidgetMatchEvent for JoinLeaveRoomModal { let title: &str; let description: String; let popup_msg: String; + let room_label = room_name_or_id(kind.room_name(), room_id); match kind { JoinLeaveModalKind::AcceptInvite(_) | JoinLeaveModalKind::RejectInvite(_) => { title = "Error rejecting invite!"; - description = utils::stringify_join_leave_error(error, kind.room_name(), false, true); + description = utils::stringify_join_leave_error(error, Some(room_label.as_str()), false, true); popup_msg = "Failed to reject invite.".into(); } JoinLeaveModalKind::JoinRoom(_) | JoinLeaveModalKind::LeaveRoom(_) => { title = "Error leaving room!"; - description = utils::stringify_join_leave_error(error, kind.room_name(), false, false); + description = utils::stringify_join_leave_error(error, Some(room_label.as_str()), false, false); popup_msg = "Failed to leave room.".into(); } } @@ -430,7 +432,7 @@ impl JoinLeaveRoomModal { title = "Accept this invite?"; description = format!( "Are you sure you want to accept this invite to join \"{}\"?", - room_name_or_id(invite.room_name.as_ref(), &invite.room_id), + room_name_or_id(&invite.room_name, &invite.room_id), ); tip_button = "Join"; } @@ -440,7 +442,7 @@ impl JoinLeaveRoomModal { "Are you sure you want to reject this invite to join \"{}\"?\n\n\ If this is a private room, you won't be able to join this room \ without being re-invited to it.", - room_name_or_id(invite.room_name.as_ref(), &invite.room_id) + room_name_or_id(&invite.room_name, &invite.room_id) ); tip_button = "Reject"; } @@ -448,7 +450,7 @@ impl JoinLeaveRoomModal { title = "Join this room?"; description = format!( "Are you sure you want to join \"{}\"?", - room_name_or_id(room.room_name.as_ref(), &room.room_id) + room_name_or_id(&room.room_name, &room.room_id) ); tip_button = "Join"; } @@ -458,7 +460,7 @@ impl JoinLeaveRoomModal { "Are you sure you want to leave \"{}\"?\n\n\ If this is a private room, you won't be able to join this room \ without being re-invited to it.", - room_name_or_id(room.room_name.as_ref(), &room.room_id) + room_name_or_id(&room.room_name, &room.room_id) ); tip_button = "Leave"; } diff --git a/src/room/mod.rs b/src/room/mod.rs index 71e860f2..f02f9fbb 100644 --- a/src/room/mod.rs +++ b/src/room/mod.rs @@ -1,6 +1,6 @@ use std::sync::Arc; use makepad_widgets::Cx; -use matrix_sdk::ruma::OwnedRoomId; +use matrix_sdk::{RoomDisplayName, ruma::OwnedRoomId}; pub mod reply_preview; pub mod room_input_bar; @@ -17,7 +17,7 @@ pub fn live_design(cx: &mut Cx) { #[derive(Clone, Debug)] pub struct BasicRoomDetails { pub room_id: OwnedRoomId, - pub room_name: Option, + pub room_name: RoomDisplayName, pub room_avatar: RoomPreviewAvatar, } diff --git a/src/room/room_display_filter.rs b/src/room/room_display_filter.rs index b164ab68..9c6b9dd8 100644 --- a/src/room/room_display_filter.rs +++ b/src/room/room_display_filter.rs @@ -7,7 +7,7 @@ use matrix_sdk::ruma::{ OwnedRoomAliasId, RoomAliasId, RoomId, }; -use crate::{home::rooms_list::{InvitedRoomInfo, JoinedRoomInfo}, utils::display_name_with_fallback}; +use crate::{home::rooms_list::{InvitedRoomInfo, JoinedRoomInfo}, utils::room_name_or_id}; static EMPTY_TAGS: Tags = BTreeMap::new(); @@ -29,12 +29,7 @@ impl FilterableRoom for JoinedRoomInfo { } fn room_name(&self) -> Cow<'_, str> { - Cow::Owned(display_name_with_fallback( - &self.room_name, - self.canonical_alias.as_ref(), - &self.alt_aliases, - &self.room_id, - )) + Cow::Owned(room_name_or_id(&self.room_name, &self.room_id)) } fn unread_mentions(&self) -> u64 { @@ -68,12 +63,7 @@ impl FilterableRoom for InvitedRoomInfo { } fn room_name(&self) -> Cow<'_, str> { - Cow::Owned(display_name_with_fallback( - &self.room_name, - self.canonical_alias.as_ref(), - &self.alt_aliases, - &self.room_id, - )) + Cow::Owned(room_name_or_id(&self.room_name, &self.room_id)) } fn unread_mentions(&self) -> u64 { diff --git a/src/shared/mentionable_text_input.rs b/src/shared/mentionable_text_input.rs index 2d2a91f8..29b23ed1 100644 --- a/src/shared/mentionable_text_input.rs +++ b/src/shared/mentionable_text_input.rs @@ -489,6 +489,7 @@ impl MentionableTextInput { // Get room avatar fallback text from room display name let room_name_first_char = room_props.room_display_name .as_ref() + .map(|name| name.to_string()) .and_then(|name| name.graphemes(true).next().map(|s| s.to_uppercase())) .filter(|s| s != "@" && s.chars().all(|c| c.is_alphabetic())) .unwrap_or_else(|| "R".to_string()); diff --git a/src/sliding_sync.rs b/src/sliding_sync.rs index 098788bb..117c9689 100644 --- a/src/sliding_sync.rs +++ b/src/sliding_sync.rs @@ -48,7 +48,7 @@ use crate::{ jump_to_bottom_button::UnreadMessageCount, popup_list::{enqueue_popup_notification, PopupItem, PopupKind} }, - utils::{self, avatar_from_room_name, preferred_room_name, AVATAR_THUMBNAIL_FORMAT}, + utils::{self, avatar_from_room_name, AVATAR_THUMBNAIL_FORMAT}, verification::add_verification_event_handlers_and_sync_client }; @@ -2338,8 +2338,14 @@ async fn add_new_room( .display_name .clone() .unwrap_or(RoomDisplayName::Empty); - let room_name_text = preferred_room_name(&room_display_name); - let room_avatar = room_avatar(&new_room.room, room_name_text.as_deref()).await; + let room_name_for_avatar = match &room_display_name { + RoomDisplayName::Empty => None, + RoomDisplayName::EmptyWas(name) + | RoomDisplayName::Named(name) + | RoomDisplayName::Aliased(name) + | RoomDisplayName::Calculated(name) => Some(name.as_str()), + }; + let room_avatar = room_avatar(&new_room.room, room_name_for_avatar).await; let inviter_info = if let Some(inviter) = invite_details.and_then(|d| d.inviter) { Some(InviterInfo { @@ -2420,7 +2426,13 @@ async fn add_new_room( .display_name .clone() .unwrap_or(RoomDisplayName::Empty); - let room_name = preferred_room_name(&room_display_name); + let room_name_for_avatar = match &room_display_name { + RoomDisplayName::Empty => None, + RoomDisplayName::EmptyWas(name) + | RoomDisplayName::Named(name) + | RoomDisplayName::Aliased(name) + | RoomDisplayName::Calculated(name) => Some(name.as_str()), + }; rooms_list::enqueue_rooms_list_update(RoomsListUpdate::AddJoinedRoom(JoinedRoomInfo { room_id: new_room.room_id.clone(), latest, @@ -2428,7 +2440,7 @@ async fn add_new_room( num_unread_messages: new_room.num_unread_messages, num_unread_mentions: new_room.num_unread_mentions, // start with a basic text avatar; the avatar image will be fetched asynchronously below. - avatar: avatar_from_room_name(room_name.as_deref()), + avatar: avatar_from_room_name(room_name_for_avatar), room_name: room_display_name, canonical_alias: new_room.room.canonical_alias(), alt_aliases: new_room.room.alt_aliases(), diff --git a/src/utils.rs b/src/utils.rs index 85b361e2..52636efb 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -9,7 +9,7 @@ use chrono::{DateTime, Duration, Local, TimeZone}; use makepad_widgets::{error, image_cache::ImageError, makepad_micro_serde::{DeRon, DeRonErr, DeRonState, SerRon, SerRonState}, Cx, Event, ImageRef}; use matrix_sdk::{ media::{MediaFormat, MediaThumbnailSettings}, - ruma::{api::client::media::get_content_thumbnail::v3::Method, MilliSecondsSinceUnixEpoch, OwnedRoomAliasId, OwnedRoomId, RoomId}, + ruma::{api::client::media::get_content_thumbnail::v3::Method, MilliSecondsSinceUnixEpoch, OwnedRoomId, RoomId}, RoomDisplayName, }; use matrix_sdk_ui::timeline::{EventTimelineItem, PaginationError, TimelineDetails}; @@ -148,37 +148,6 @@ pub fn unix_time_millis_to_datetime(millis: MilliSecondsSinceUnixEpoch) -> Optio /// Converts a `RoomDisplayName` to the text we prefer to show in the Rooms list. /// -/// Returns `None` when the display name is explicitly empty so that callers can -/// fall back to aliases or the room ID. -pub fn preferred_room_name(display_name: &RoomDisplayName) -> Option { - match display_name { - RoomDisplayName::Empty => None, - _ => Some(display_name.to_string()), - } -} - -/// Returns the room name that should be shown to the user, falling back to aliases or the room ID. -pub fn display_name_with_fallback( - display_name: &RoomDisplayName, - canonical_alias: Option<&OwnedRoomAliasId>, - alt_aliases: &[OwnedRoomAliasId], - room_id: &OwnedRoomId, -) -> String { - if let Some(name) = preferred_room_name(display_name) { - return name; - } - - if let Some(alias) = canonical_alias { - return alias.as_str().to_owned(); - } - - if let Some(alias) = alt_aliases.first() { - return alias.as_str().to_owned(); - } - - format!("Room ID {}", room_id.as_str()) -} - /// Returns a string error message, handling special cases related to joining/leaving rooms. pub fn stringify_join_leave_error( error: &matrix_sdk::Error, @@ -277,13 +246,13 @@ pub fn stringify_pagination_error( /// Returns a string representation of the room name or ID. pub fn room_name_or_id( - room_name: Option>, + room_name: &RoomDisplayName, room_id: impl AsRef, ) -> String { - room_name.map_or_else( - || format!("Room ID {}", room_id.as_ref()), - |name| name.into(), - ) + match room_name { + RoomDisplayName::Empty => format!("Empty (ID {})", room_id.as_ref()), + other => other.to_string(), + } } /// Formats a given Unix timestamp in milliseconds into a relative human-readable date. @@ -763,6 +732,48 @@ impl Display for OwnedRoomIdRon { } } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct RoomDisplayNameRon(pub RoomDisplayName); +impl SerRon for RoomDisplayNameRon { + fn ser_ron(&self, d: usize, s: &mut SerRonState) { + let serialized = serde_json::to_string(&self.0) + .unwrap_or_else(|e| { + error!("Failed to serialize RoomDisplayName to ron: {e}"); + // Fallback to empty variant to keep serialization going. + serde_json::to_string(&RoomDisplayName::Empty).expect("serialization of Empty must succeed") + }); + serialized.ser_ron(d, s); + } +} +impl DeRon for RoomDisplayNameRon { + fn de_ron(s: &mut DeRonState, i: &mut Chars) -> Result { + let serialized = String::de_ron(s, i)?; + serde_json::from_str::(&serialized) + .map(RoomDisplayNameRon) + .map_err(|e| DeRonErr { + msg: e.to_string(), + line: s.line, + col: s.col, + }) + } +} +impl From for RoomDisplayNameRon { + fn from(value: RoomDisplayName) -> Self { + RoomDisplayNameRon(value) + } +} +impl From for RoomDisplayName { + fn from(value: RoomDisplayNameRon) -> Self { + value.0 + } +} +impl std::ops::Deref for RoomDisplayNameRon { + type Target = RoomDisplayName; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + /// Returns a text avatar string containing the first character of the room name. /// /// Skips the first character if it is a `#` or `!`, the sigils used for Room aliases and Room IDs. From 8178e6cb387768cd3315ee6389f53e67d9d7c446 Mon Sep 17 00:00:00 2001 From: Alvin Date: Tue, 4 Nov 2025 12:41:00 +0800 Subject: [PATCH 3/5] update RoomName instead of RoomNameRon Signed-off-by: Alvin --- src/app.rs | 12 +-- src/home/main_desktop_ui.rs | 4 +- src/home/rooms_list.rs | 6 +- src/sliding_sync.rs | 29 ++---- src/utils.rs | 179 +++++++++++++++++++++++++++++------- 5 files changed, 165 insertions(+), 65 deletions(-) diff --git a/src/app.rs b/src/app.rs index 8a745895..b86905bc 100644 --- a/src/app.rs +++ b/src/app.rs @@ -20,7 +20,7 @@ use crate::{ }, sliding_sync::current_user_id, utils::{ room_name_or_id, OwnedRoomIdRon, - RoomDisplayNameRon, + RoomName, }, verification::VerificationAction, verification_modal::{ VerificationModalAction, VerificationModalWidgetRefExt, @@ -577,7 +577,7 @@ impl App { // Select and scroll to the destination room in the rooms list. let new_selected_room = SelectedRoom::JoinedRoom { room_id: destination_room.room_id.clone().into(), - room_name: RoomDisplayNameRon::from(destination_room.room_name.clone()), + room_name: destination_room.room_name.clone().into(), }; enqueue_rooms_list_update(RoomsListUpdate::ScrollToRoom(destination_room.room_id.clone())); cx.widget_action( @@ -625,11 +625,11 @@ pub struct SavedDockState { pub enum SelectedRoom { JoinedRoom { room_id: OwnedRoomIdRon, - room_name: RoomDisplayNameRon, + room_name: RoomName, }, InvitedRoom { room_id: OwnedRoomIdRon, - room_name: RoomDisplayNameRon, + room_name: RoomName, }, } @@ -643,8 +643,8 @@ impl SelectedRoom { pub fn room_name(&self) -> &RoomDisplayName { match self { - SelectedRoom::JoinedRoom { room_name, .. } => &room_name.0, - SelectedRoom::InvitedRoom { room_name, .. } => &room_name.0, + SelectedRoom::JoinedRoom { room_name, .. } => room_name.as_ref(), + SelectedRoom::InvitedRoom { room_name, .. } => room_name.as_ref(), } } diff --git a/src/home/main_desktop_ui.rs b/src/home/main_desktop_ui.rs index 1b78afaf..71481b30 100644 --- a/src/home/main_desktop_ui.rs +++ b/src/home/main_desktop_ui.rs @@ -132,11 +132,11 @@ impl MainDesktopUI { let (kind, name) = match &room { SelectedRoom::JoinedRoom { room_id, room_name } => ( id!(room_screen), - room_name_or_id(&RoomDisplayName::from(room_name.clone()), room_id), + room_name_or_id(RoomDisplayName::from(room_name.clone()), room_id), ), SelectedRoom::InvitedRoom { room_id, room_name } => ( id!(invite_screen), - room_name_or_id(&RoomDisplayName::from(room_name.clone()), room_id), + room_name_or_id(RoomDisplayName::from(room_name.clone()), room_id), ), }; let new_tab_widget = dock.create_and_select_tab( diff --git a/src/home/rooms_list.rs b/src/home/rooms_list.rs index 02f9d488..812c9a50 100644 --- a/src/home/rooms_list.rs +++ b/src/home/rooms_list.rs @@ -6,7 +6,7 @@ use crate::{ app::{AppState, SelectedRoom}, room::{room_display_filter::{RoomDisplayFilter, RoomDisplayFilterBuilder, RoomFilterCriteria, SortFn}, FetchedRoomAvatar}, shared::{collapsible_header::{CollapsibleHeaderAction, CollapsibleHeaderWidgetRefExt, HeaderCategory}, jump_to_bottom_button::UnreadMessageCount, popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, room_filter_input_bar::RoomFilterAction}, - sliding_sync::{submit_async_request, MatrixRequest, PaginationDirection}, utils::{room_name_or_id, RoomDisplayNameRon}, + sliding_sync::{submit_async_request, MatrixRequest, PaginationDirection}, utils::room_name_or_id, }; use super::rooms_list_entry::RoomsListEntryAction; @@ -882,12 +882,12 @@ impl Widget for RoomsList { let new_selected_room = if let Some(jr) = self.all_joined_rooms.get(&clicked_room_id) { SelectedRoom::JoinedRoom { room_id: jr.room_id.clone().into(), - room_name: RoomDisplayNameRon::from(jr.room_name.clone()), + room_name: jr.room_name.clone().into(), } } else if let Some(ir) = self.invited_rooms.borrow().get(&clicked_room_id) { SelectedRoom::InvitedRoom { room_id: ir.room_id.to_owned().into(), - room_name: RoomDisplayNameRon::from(ir.room_name.clone()), + room_name: ir.room_name.clone().into(), } } else { error!("BUG: couldn't find clicked room details for room {clicked_room_id}"); diff --git a/src/sliding_sync.rs b/src/sliding_sync.rs index c2244062..bd7eab05 100644 --- a/src/sliding_sync.rs +++ b/src/sliding_sync.rs @@ -48,7 +48,7 @@ use crate::{ jump_to_bottom_button::UnreadMessageCount, popup_list::{enqueue_popup_notification, PopupItem, PopupKind} }, - utils::{self, avatar_from_room_name, AVATAR_THUMBNAIL_FORMAT}, + utils::{self, avatar_from_room_name, AVATAR_THUMBNAIL_FORMAT, RoomName}, verification::add_verification_event_handlers_and_sync_client }; @@ -2387,14 +2387,7 @@ async fn add_new_room( .display_name .clone() .unwrap_or(RoomDisplayName::Empty); - let room_name_for_avatar = match &room_display_name { - RoomDisplayName::Empty => None, - RoomDisplayName::EmptyWas(name) - | RoomDisplayName::Named(name) - | RoomDisplayName::Aliased(name) - | RoomDisplayName::Calculated(name) => Some(name.as_str()), - }; - let room_avatar = room_avatar(&new_room.room, room_name_for_avatar).await; + let room_avatar = room_avatar(&new_room.room, RoomName::from(room_display_name.clone())).await; let inviter_info = if let Some(inviter) = invite_details.and_then(|d| d.inviter) { Some(InviterInfo { @@ -2475,13 +2468,7 @@ async fn add_new_room( .display_name .clone() .unwrap_or(RoomDisplayName::Empty); - let room_name_for_avatar = match &room_display_name { - RoomDisplayName::Empty => None, - RoomDisplayName::EmptyWas(name) - | RoomDisplayName::Named(name) - | RoomDisplayName::Aliased(name) - | RoomDisplayName::Calculated(name) => Some(name.as_str()), - }; + let room_name_for_avatar = RoomName::from(room_display_name.clone()); rooms_list::enqueue_rooms_list_update(RoomsListUpdate::AddJoinedRoom(JoinedRoomInfo { room_id: new_room.room_id.clone(), latest, @@ -2489,7 +2476,7 @@ async fn add_new_room( num_unread_messages: new_room.num_unread_messages, num_unread_mentions: new_room.num_unread_mentions, // start with a basic text avatar; the avatar image will be fetched asynchronously below. - avatar: avatar_from_room_name(room_name_for_avatar), + avatar: avatar_from_room_name(room_name_for_avatar.as_str()), room_name: room_display_name, canonical_alias: new_room.room.canonical_alias(), alt_aliases: new_room.room.alt_aliases(), @@ -3114,10 +3101,10 @@ async fn update_latest_event(room: &Room) { /// Spawn a new async task to fetch the room's new avatar. fn spawn_fetch_room_avatar(room: &RoomListServiceRoomInfo) { let room_id = room.room_id.clone(); - let room_name = room.display_name.as_ref().map(|n| n.to_string()); + let room_name = room.display_name.clone().map(RoomName::from).unwrap_or_default(); let inner_room = room.room.clone(); Handle::current().spawn(async move { - let avatar = room_avatar(&inner_room, room_name.as_deref()).await; + let avatar = room_avatar(&inner_room, room_name).await; rooms_list::enqueue_rooms_list_update(RoomsListUpdate::UpdateRoomAvatar { room_id, avatar, @@ -3127,7 +3114,7 @@ fn spawn_fetch_room_avatar(room: &RoomListServiceRoomInfo) { /// Fetches and returns the avatar image for the given room (if one exists), /// otherwise returns a text avatar string of the first character of the room name. -async fn room_avatar(room: &Room, room_name: Option<&str>) -> FetchedRoomAvatar { +async fn room_avatar(room: &Room, room_name: RoomName) -> FetchedRoomAvatar { match room.avatar(AVATAR_THUMBNAIL_FORMAT.into()).await { Ok(Some(avatar)) => FetchedRoomAvatar::Image(avatar.into()), _ => { @@ -3140,7 +3127,7 @@ async fn room_avatar(room: &Room, room_name: Option<&str>) -> FetchedRoomAvatar } } } - utils::avatar_from_room_name(room_name) + utils::avatar_from_room_name(room_name.as_str()) } } } diff --git a/src/utils.rs b/src/utils.rs index 504fe303..73bc53a8 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -146,8 +146,6 @@ pub fn unix_time_millis_to_datetime(millis: MilliSecondsSinceUnixEpoch) -> Optio Local.timestamp_millis_opt(millis).single() } -/// Converts a `RoomDisplayName` to the text we prefer to show in the Rooms list. -/// /// Returns a string error message, handling special cases related to joining/leaving rooms. pub fn stringify_join_leave_error( error: &matrix_sdk::Error, @@ -246,13 +244,10 @@ pub fn stringify_pagination_error( /// Returns a string representation of the room name or ID. pub fn room_name_or_id( - room_name: &RoomDisplayName, + room_name: impl IntoRoomName, room_id: impl AsRef, ) -> String { - match room_name { - RoomDisplayName::Empty => format!("Empty (ID {})", room_id.as_ref()), - other => other.to_string(), - } + room_name.into_room_name().display_with_fallback(room_id) } /// Formats a given Unix timestamp in milliseconds into a relative human-readable date. @@ -733,23 +728,157 @@ impl Display for OwnedRoomIdRon { } #[derive(Clone, Debug, PartialEq, Eq)] -pub struct RoomDisplayNameRon(pub RoomDisplayName); -impl SerRon for RoomDisplayNameRon { +pub struct RoomName(pub RoomDisplayName); + +impl RoomName { + pub fn into_inner(self) -> RoomDisplayName { + self.0 + } + + pub fn as_str(&self) -> Option<&str> { + room_display_name_str(&self.0) + } + + pub fn display_with_fallback(&self, room_id: impl AsRef) -> String { + match &self.0 { + RoomDisplayName::Empty => format!("Unnamed (ID {})", room_id.as_ref()), + RoomDisplayName::EmptyWas(name) => format!("Empty Room (was \"{name}\")"), + other => other.to_string(), + } + } +} + +impl Default for RoomName { + fn default() -> Self { + Self(RoomDisplayName::Empty) + } +} + +impl std::ops::Deref for RoomName { + type Target = RoomDisplayName; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::borrow::Borrow for RoomName { + fn borrow(&self) -> &RoomDisplayName { + &self.0 + } +} + +impl AsRef for RoomName { + fn as_ref(&self) -> &RoomDisplayName { + &self.0 + } +} + +impl std::fmt::Display for RoomName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(&self.0, f) + } +} + +impl From for RoomName { + fn from(value: RoomDisplayName) -> Self { + Self(value) + } +} + +impl From<&RoomDisplayName> for RoomName { + fn from(value: &RoomDisplayName) -> Self { + Self(value.clone()) + } +} + +impl From for RoomDisplayName { + fn from(value: RoomName) -> Self { + value.0 + } +} + +pub fn room_display_name_str(display_name: &RoomDisplayName) -> Option<&str> { + match display_name { + RoomDisplayName::Empty => None, + RoomDisplayName::EmptyWas(name) + | RoomDisplayName::Named(name) + | RoomDisplayName::Aliased(name) + | RoomDisplayName::Calculated(name) => Some(name.as_str()), + } +} + +pub trait IntoRoomName { + fn into_room_name(self) -> RoomName; +} + +impl IntoRoomName for RoomName { + fn into_room_name(self) -> RoomName { + self + } +} + +impl IntoRoomName for &RoomName { + fn into_room_name(self) -> RoomName { + self.clone() + } +} + +impl IntoRoomName for RoomDisplayName { + fn into_room_name(self) -> RoomName { + RoomName(self) + } +} + +impl IntoRoomName for &RoomDisplayName { + fn into_room_name(self) -> RoomName { + RoomName(self.clone()) + } +} + +impl IntoRoomName for String { + fn into_room_name(self) -> RoomName { + RoomName(RoomDisplayName::Named(self)) + } +} + +impl IntoRoomName for &str { + fn into_room_name(self) -> RoomName { + RoomName(RoomDisplayName::Named(self.to_owned())) + } +} + +impl<'a> IntoRoomName for Cow<'a, str> { + fn into_room_name(self) -> RoomName { + RoomName(RoomDisplayName::Named(self.into_owned())) + } +} + +impl IntoRoomName for Option +where + T: IntoRoomName, +{ + fn into_room_name(self) -> RoomName { + self.map(IntoRoomName::into_room_name).unwrap_or_default() + } +} + +impl SerRon for RoomName { fn ser_ron(&self, d: usize, s: &mut SerRonState) { - let serialized = serde_json::to_string(&self.0) - .unwrap_or_else(|e| { - error!("Failed to serialize RoomDisplayName to ron: {e}"); - // Fallback to empty variant to keep serialization going. - serde_json::to_string(&RoomDisplayName::Empty).expect("serialization of Empty must succeed") - }); + let serialized = serde_json::to_string(&self.0).unwrap_or_else(|e| { + error!("Failed to serialize RoomDisplayName to ron: {e}"); + serde_json::to_string(&RoomDisplayName::Empty) + .expect("serialization of Empty must succeed") + }); serialized.ser_ron(d, s); } } -impl DeRon for RoomDisplayNameRon { + +impl DeRon for RoomName { fn de_ron(s: &mut DeRonState, i: &mut Chars) -> Result { let serialized = String::de_ron(s, i)?; serde_json::from_str::(&serialized) - .map(RoomDisplayNameRon) + .map(RoomName) .map_err(|e| DeRonErr { msg: e.to_string(), line: s.line, @@ -757,22 +886,6 @@ impl DeRon for RoomDisplayNameRon { }) } } -impl From for RoomDisplayNameRon { - fn from(value: RoomDisplayName) -> Self { - RoomDisplayNameRon(value) - } -} -impl From for RoomDisplayName { - fn from(value: RoomDisplayNameRon) -> Self { - value.0 - } -} -impl std::ops::Deref for RoomDisplayNameRon { - type Target = RoomDisplayName; - fn deref(&self) -> &Self::Target { - &self.0 - } -} /// Returns a text avatar string containing the first character of the room name. /// From 23462372adb5f4e2c54b0ebcbd3416dac68eae95 Mon Sep 17 00:00:00 2001 From: Alvin Date: Tue, 4 Nov 2025 14:21:16 +0800 Subject: [PATCH 4/5] Update room name handling --- src/home/invite_screen.rs | 20 ++++++++++---------- src/home/main_desktop_ui.rs | 16 +++++++--------- src/home/main_mobile_ui.rs | 2 +- src/home/room_screen.rs | 26 +++++++++----------------- src/shared/restore_status_view.rs | 22 ++++++++++++++++++---- 5 files changed, 45 insertions(+), 41 deletions(-) diff --git a/src/home/invite_screen.rs b/src/home/invite_screen.rs index 6ac3f644..82560db7 100644 --- a/src/home/invite_screen.rs +++ b/src/home/invite_screen.rs @@ -8,7 +8,7 @@ use std::ops::Deref; use makepad_widgets::*; use matrix_sdk::{RoomDisplayName, ruma::OwnedRoomId}; -use crate::{app::AppStateAction, home::rooms_list::RoomsListRef, join_leave_room_modal::{JoinLeaveModalKind, JoinLeaveRoomModalAction}, room::{BasicRoomDetails, FetchedRoomAvatar}, shared::{avatar::AvatarWidgetRefExt, popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, restore_status_view::RestoreStatusViewWidgetExt}, sliding_sync::{submit_async_request, MatrixRequest}, utils::{self, room_name_or_id}}; +use crate::{app::AppStateAction, home::rooms_list::RoomsListRef, join_leave_room_modal::{JoinLeaveModalKind, JoinLeaveRoomModalAction}, room::{BasicRoomDetails, FetchedRoomAvatar}, shared::{avatar::AvatarWidgetRefExt, popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, restore_status_view::RestoreStatusViewWidgetExt}, sliding_sync::{submit_async_request, MatrixRequest}, utils::{self, room_name_or_id, RoomName}}; use super::rooms_list::{InviteState, InviterInfo}; @@ -396,14 +396,11 @@ impl Widget for InviteScreen { fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep { - let room_display_text = self.room_id - .as_ref() - .map(|id| room_name_or_id(&self.room_name, id)) - .unwrap_or_else(|| self.room_name.to_string()); - if !self.is_loaded { let mut restore_status_view = self.view.restore_status_view(ids!(restore_status_view)); - restore_status_view.set_content(cx, self.all_rooms_loaded, &room_display_text); + let room_id = self.room_id.as_ref().map(|id| id.as_ref()); + let room_name = RoomName::from(self.room_name.clone()); + restore_status_view.set_content(cx, self.all_rooms_loaded, room_name, room_id); return restore_status_view.draw(cx, scope); } let Some(info) = self.info.as_ref() else { @@ -523,8 +520,6 @@ impl InviteScreen { pub fn set_displayed_invite(&mut self, cx: &mut Cx, room_id: OwnedRoomId, room_name: RoomDisplayName) { self.room_id = Some(room_id.clone()); self.room_name = room_name; - let room_display_text = room_name_or_id(&self.room_name, &room_id); - if let Some(invite) = super::rooms_list::get_invited_rooms(cx) .borrow() .get(&room_id) @@ -545,7 +540,12 @@ impl InviteScreen { } self.view .restore_status_view(ids!(restore_status_view)) - .set_content(cx, self.all_rooms_loaded, &room_display_text); + .set_content( + cx, + self.all_rooms_loaded, + RoomName::from(self.room_name.clone()), + Some(room_id.as_ref()), + ); self.view .restore_status_view(ids!(restore_status_view)) .set_visible(cx, !self.is_loaded); diff --git a/src/home/main_desktop_ui.rs b/src/home/main_desktop_ui.rs index 71481b30..27d4c9ec 100644 --- a/src/home/main_desktop_ui.rs +++ b/src/home/main_desktop_ui.rs @@ -154,11 +154,11 @@ impl MainDesktopUI { if let Some(new_widget) = new_tab_widget { self.room_order.push(room.clone()); match &room { - SelectedRoom::JoinedRoom { room_id, .. } => { + SelectedRoom::JoinedRoom { room_id, room_name } => { new_widget.as_room_screen().set_displayed_room( cx, room_id.clone().into(), - room.room_name().clone(), + room_name.as_ref().clone(), ); } SelectedRoom::InvitedRoom { room_id, room_name: _ } => { @@ -250,11 +250,9 @@ impl MainDesktopUI { }; // Set the info to be displayed in the newly-replaced RoomScreen.. - new_widget.as_room_screen().set_displayed_room( - cx, - room_id.clone(), - room_name.clone(), - ); + new_widget + .as_room_screen() + .set_displayed_room(cx, room_id.clone(), room_name.clone()); // Go through all existing `SelectedRoom` instances and replace the // `SelectedRoom::InvitedRoom`s with `SelectedRoom::JoinedRoom`s. @@ -366,14 +364,14 @@ impl WidgetMatchEvent for MainDesktopUI { widget.as_room_screen().set_displayed_room( cx, room_id.clone().into(), - room_name.clone().into(), + room_name.as_ref().clone(), ); } Some(SelectedRoom::InvitedRoom { room_id, room_name }) => { widget.as_invite_screen().set_displayed_invite( cx, room_id.clone().into(), - room_name.clone().into(), + room_name.as_ref().clone(), ); } _ => { } diff --git a/src/home/main_mobile_ui.rs b/src/home/main_mobile_ui.rs index 88679d96..82216e2a 100644 --- a/src/home/main_mobile_ui.rs +++ b/src/home/main_mobile_ui.rs @@ -80,7 +80,7 @@ impl Widget for MainMobileUI { // Get a reference to the `RoomScreen` widget and tell it which room's data to show. self.view .room_screen(ids!(room_screen)) - .set_displayed_room(cx, room_id.clone().into(), room_name.clone().into()); + .set_displayed_room(cx, room_id.clone().into(), room_name.as_ref().clone()); } Some(SelectedRoom::InvitedRoom { room_id, room_name }) => { show_welcome = false; diff --git a/src/home/room_screen.rs b/src/home/room_screen.rs index fe9afb9c..1847ac96 100644 --- a/src/home/room_screen.rs +++ b/src/home/room_screen.rs @@ -34,7 +34,7 @@ use crate::{ shared::{ avatar::AvatarWidgetRefExt, callout_tooltip::TooltipAction, html_or_plaintext::{HtmlOrPlaintextRef, HtmlOrPlaintextWidgetRefExt, RobrixHtmlLinkAction}, jump_to_bottom_button::{JumpToBottomButtonWidgetExt, UnreadMessageCount}, popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, restore_status_view::RestoreStatusViewWidgetExt, styles::*, text_or_image::{TextOrImageRef, TextOrImageWidgetRefExt}, timestamp::TimestampWidgetRefExt }, - sliding_sync::{get_client, submit_async_request, take_timeline_endpoints, BackwardsPaginateUntilEventRequest, MatrixRequest, PaginationDirection, TimelineEndpoints, TimelineRequestSender, UserPowerLevels}, utils::{self, room_name_or_id, unix_time_millis_to_datetime, ImageFormat, MEDIA_THUMBNAIL_FORMAT} + sliding_sync::{get_client, submit_async_request, take_timeline_endpoints, BackwardsPaginateUntilEventRequest, MatrixRequest, PaginationDirection, TimelineEndpoints, TimelineRequestSender, UserPowerLevels}, utils::{self, room_name_or_id, unix_time_millis_to_datetime, ImageFormat, MEDIA_THUMBNAIL_FORMAT, RoomName} }; use crate::home::event_reaction_list::ReactionListWidgetRefExt; use crate::home::room_read_receipt::AvatarRowWidgetRefExt; @@ -699,7 +699,7 @@ impl Widget for RoomScreen { &user_profile_sliding_pane, UserProfilePaneInfo { profile_and_room_id, - room_name: self.current_room_label(), + room_name: self.room_name.to_string(), room_member: None, }, ); @@ -902,8 +902,9 @@ impl Widget for RoomScreen { // If the room isn't loaded yet, we show the restore status label only. if !self.is_loaded { let mut restore_status_view = self.view.restore_status_view(ids!(restore_status_view)); - let room_label = self.current_room_label(); - restore_status_view.set_content(cx, self.all_rooms_loaded, &room_label); + let room_id = self.room_id.as_deref(); + let room_name = RoomName::from(self.room_name.clone()); + restore_status_view.set_content(cx, self.all_rooms_loaded, room_name, room_id); return restore_status_view.draw(cx, scope); } if self.tl_state.is_none() { @@ -1091,13 +1092,6 @@ impl Widget for RoomScreen { } impl RoomScreen { - fn current_room_label(&self) -> String { - match self.room_id.as_ref() { - Some(room_id) => room_name_or_id(&self.room_name, room_id), - None => self.room_name.to_string(), - } - } - /// Processes all pending background updates to the currently-shown timeline. /// /// Redraws this RoomScreen view if any updates were applied. @@ -1106,8 +1100,8 @@ impl RoomScreen { let jump_to_bottom = self.jump_to_bottom_button(ids!(jump_to_bottom)); let curr_first_id = portal_list.first_id(); let ui = self.widget_uid(); - let room_label_cached = self.current_room_label(); let Some(tl) = self.tl_state.as_mut() else { return }; + let room_label_cached = self.room_name.to_string(); let mut done_loading = false; let mut should_continue_backwards_pagination = false; @@ -1468,7 +1462,7 @@ impl RoomScreen { }, room_id: self.room_id.clone().unwrap(), }, - room_name: self.current_room_label(), + room_name: self.room_name.to_string(), // TODO: use the extra `via` parameters room_member: None, }, @@ -2018,9 +2012,8 @@ impl RoomScreen { let rooms_list_ref = cx.get_global::(); let is_loaded_now = rooms_list_ref.is_room_loaded(&room_id); if is_loaded_now && !self.is_loaded { - let room_label = self.current_room_label(); log!("Detected that room \"{}\" ({}) is now loaded for the first time", - room_label, room_id, + self.room_name, room_id, ); is_first_time_being_loaded = true; } @@ -2034,8 +2027,7 @@ impl RoomScreen { // when they first open the room, and there might not be any messages yet. if is_first_time_being_loaded { if !tl_state.fully_paginated { - let room_label = self.current_room_label(); - log!("Sending a first-time backwards pagination request for room \"{}\" {}", room_label, room_id); + log!("Sending a first-time backwards pagination request for room \"{}\" {}", self.room_name, room_id); submit_async_request(MatrixRequest::PaginateRoomTimeline { room_id: room_id.clone(), num_events: 50, diff --git a/src/shared/restore_status_view.rs b/src/shared/restore_status_view.rs index f3c48b68..6903b398 100644 --- a/src/shared/restore_status_view.rs +++ b/src/shared/restore_status_view.rs @@ -6,6 +6,9 @@ //! the current room no longer exists. use makepad_widgets::*; +use matrix_sdk::ruma::RoomId; + +use crate::utils::RoomName; live_design! { use link::theme::*; @@ -90,16 +93,28 @@ impl RestoreStatusViewRef { /// is still being loaded from the homeserver. /// /// The `room_name` parameter is used to fill in the room name in the error message. - pub fn set_content(&self, cx: &mut Cx, all_rooms_loaded: bool, room_name: &str) { + pub fn set_content( + &self, + cx: &mut Cx, + all_rooms_loaded: bool, + room_name: RoomName, + room_id: Option<&RoomId>, + ) { let Some(inner) = self.borrow() else { return }; let restore_status_spinner = inner.view.view(ids!(restore_status_spinner)); let restore_status_label = inner.view.label(ids!(restore_status_label)); if all_rooms_loaded { restore_status_spinner.set_visible(cx, false); + let display_name = match room_id { + Some(id) => room_name.display_with_fallback(id), + None => room_name.to_string(), + }; restore_status_label.set_text( cx, - &format!("Room \"{room_name}\" was not found in the homeserver's list \ - of all rooms.\n\nYou may close this screen.") + &format!( + "Room \"{display_name}\" was not found in the homeserver's list \ + of all rooms.\n\nYou may close this screen." + ), ); } else { restore_status_spinner.set_visible(cx, true); @@ -110,4 +125,3 @@ impl RestoreStatusViewRef { } } } - From 386df39f1ec1a193cb5dae545be28313a1e4a237 Mon Sep 17 00:00:00 2001 From: Alvin Date: Wed, 5 Nov 2025 11:57:25 +0800 Subject: [PATCH 5/5] clean code --- src/home/invite_screen.rs | 5 ++--- src/home/main_desktop_ui.rs | 4 ++-- src/home/room_screen.rs | 14 +++++--------- src/utils.rs | 6 +----- 4 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/home/invite_screen.rs b/src/home/invite_screen.rs index 2a5d15ed..0416391c 100644 --- a/src/home/invite_screen.rs +++ b/src/home/invite_screen.rs @@ -352,7 +352,7 @@ impl Widget for InviteScreen { self.invite_state = InviteState::WaitingOnUserInput; if !self.has_shown_confirmation { let room_label = room_name_or_id(&info.room_name, &info.room_id); - let msg = utils::stringify_join_leave_error(error, Some(room_label.as_str()), true, true); + let msg = utils::stringify_join_leave_error(error, Some(&room_label), true, true); enqueue_popup_notification(PopupItem { message: msg, kind: PopupKind::Error, auto_dismissal_duration: None }); } continue; @@ -399,8 +399,7 @@ impl Widget for InviteScreen { if !self.is_loaded { let mut restore_status_view = self.view.restore_status_view(ids!(restore_status_view)); let room_id = self.room_id.as_ref().map(|id| id.as_ref()); - let room_name = RoomName::from(self.room_name.clone()); - restore_status_view.set_content(cx, self.all_rooms_loaded, room_name, room_id); + restore_status_view.set_content(cx, self.all_rooms_loaded, self.room_name.clone().into(), room_id); return restore_status_view.draw(cx, scope); } let Some(info) = self.info.as_ref() else { diff --git a/src/home/main_desktop_ui.rs b/src/home/main_desktop_ui.rs index 27d4c9ec..e9666f3d 100644 --- a/src/home/main_desktop_ui.rs +++ b/src/home/main_desktop_ui.rs @@ -132,11 +132,11 @@ impl MainDesktopUI { let (kind, name) = match &room { SelectedRoom::JoinedRoom { room_id, room_name } => ( id!(room_screen), - room_name_or_id(RoomDisplayName::from(room_name.clone()), room_id), + room_name_or_id(room_name.clone().into_inner(), room_id), ), SelectedRoom::InvitedRoom { room_id, room_name } => ( id!(invite_screen), - room_name_or_id(RoomDisplayName::from(room_name.clone()), room_id), + room_name_or_id(room_name.clone().into_inner(), room_id), ), }; let new_tab_widget = dock.create_and_select_tab( diff --git a/src/home/room_screen.rs b/src/home/room_screen.rs index ab5cecef..d886a077 100644 --- a/src/home/room_screen.rs +++ b/src/home/room_screen.rs @@ -34,7 +34,7 @@ use crate::{ shared::{ avatar::AvatarWidgetRefExt, callout_tooltip::TooltipAction, html_or_plaintext::{HtmlOrPlaintextRef, HtmlOrPlaintextWidgetRefExt, RobrixHtmlLinkAction}, jump_to_bottom_button::{JumpToBottomButtonWidgetExt, UnreadMessageCount}, popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, restore_status_view::RestoreStatusViewWidgetExt, styles::*, text_or_image::{TextOrImageRef, TextOrImageWidgetRefExt}, timestamp::TimestampWidgetRefExt }, - sliding_sync::{get_client, submit_async_request, take_timeline_endpoints, BackwardsPaginateUntilEventRequest, MatrixRequest, PaginationDirection, TimelineEndpoints, TimelineRequestSender, UserPowerLevels}, utils::{self, room_name_or_id, unix_time_millis_to_datetime, ImageFormat, MEDIA_THUMBNAIL_FORMAT, RoomName} + sliding_sync::{get_client, submit_async_request, take_timeline_endpoints, BackwardsPaginateUntilEventRequest, MatrixRequest, PaginationDirection, TimelineEndpoints, TimelineRequestSender, UserPowerLevels}, utils::{self, unix_time_millis_to_datetime, ImageFormat, MEDIA_THUMBNAIL_FORMAT, RoomName} }; use crate::home::event_reaction_list::ReactionListWidgetRefExt; use crate::home::room_read_receipt::AvatarRowWidgetRefExt; @@ -491,7 +491,6 @@ live_design! { draw_bg: { color: (COLOR_PRIMARY_DARKER) } - restore_status_view = {} // Widgets within this view will get shifted upwards when the on-screen keyboard is shown. @@ -1078,8 +1077,7 @@ impl Widget for RoomScreen { // If the list is not filling the viewport, we need to back paginate the timeline // until we have enough events items to fill the viewport. if !tl_state.fully_paginated && !list.is_filling_viewport() { - let room_label = room_name_or_id(&self.room_name, room_id); - log!("Automatically paginating timeline to fill viewport for room \"{}\" ({})", room_label, room_id); + log!("Automatically paginating timeline to fill viewport for room \"{}\" ({})", self.room_name, room_id); submit_async_request(MatrixRequest::PaginateRoomTimeline { room_id: room_id.clone(), num_events: 50, @@ -1101,7 +1099,6 @@ impl RoomScreen { let curr_first_id = portal_list.first_id(); let ui = self.widget_uid(); let Some(tl) = self.tl_state.as_mut() else { return }; - let room_label_cached = self.room_name.to_string(); let mut done_loading = false; let mut should_continue_backwards_pagination = false; @@ -1298,9 +1295,9 @@ impl RoomScreen { } } TimelineUpdate::PaginationError { error, direction } => { - error!("Pagination error ({direction}) in room \"{}\", {}: {error:?}", room_label_cached, tl.room_id); + error!("Pagination error ({direction}) in room \"{}\", {}: {error:?}", self.room_name, tl.room_id); enqueue_popup_notification(PopupItem { - message: utils::stringify_pagination_error(&error, room_label_cached.as_str()), + message: utils::stringify_pagination_error(&error, &self.room_name.to_string()), auto_dismissal_duration: None, kind: PopupKind::Error, }); @@ -1919,7 +1916,6 @@ impl RoomScreen { // and search our locally-known timeline history for the replied-to message. } self.redraw(cx); - } /// Shows the user profile sliding pane with the given avatar info. @@ -4177,4 +4173,4 @@ pub fn clear_timeline_states(_cx: &mut Cx) { TIMELINE_STATES.with_borrow_mut(|states| { states.clear(); }); -} +} \ No newline at end of file diff --git a/src/utils.rs b/src/utils.rs index 73bc53a8..292e120f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -7,11 +7,7 @@ use url::Url; use unicode_segmentation::UnicodeSegmentation; use chrono::{DateTime, Duration, Local, TimeZone}; use makepad_widgets::{error, image_cache::ImageError, makepad_micro_serde::{DeRon, DeRonErr, DeRonState, SerRon, SerRonState}, Cx, Event, ImageRef}; -use matrix_sdk::{ - media::{MediaFormat, MediaThumbnailSettings}, - ruma::{api::client::media::get_content_thumbnail::v3::Method, MilliSecondsSinceUnixEpoch, OwnedRoomId, RoomId}, - RoomDisplayName, -}; +use matrix_sdk::{media::{MediaFormat, MediaThumbnailSettings}, ruma::{api::client::media::get_content_thumbnail::v3::Method, MilliSecondsSinceUnixEpoch, OwnedRoomId, RoomId}, RoomDisplayName}; use matrix_sdk_ui::timeline::{EventTimelineItem, PaginationError, TimelineDetails}; use crate::{room::FetchedRoomAvatar, sliding_sync::{submit_async_request, MatrixRequest}};