Skip to content

Commit fc5216c

Browse files
committed
Code cleanup, make logic better with less cloning
1 parent c0a7293 commit fc5216c

3 files changed

Lines changed: 134 additions & 150 deletions

File tree

src/home/rooms_list.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ pub enum InviteState {
358358

359359
/// The value in the RoomsList's `space_map` that contains info about a space.
360360
#[derive(Default)]
361-
struct SpaceMapValue {
361+
struct SpaceMapValue {
362362
/// Whether this space is fully paginated, meaning that our client has obtained
363363
/// the full list of direct children within this space.
364364
///
@@ -1406,13 +1406,12 @@ impl RoomsListRef {
14061406
self.borrow()?.space_request_sender.clone()
14071407
}
14081408

1409-
/// Returns the set of direct child rooms and subspaces for the given space.
1410-
///
1411-
/// Returns a tuple of `(direct_child_rooms, direct_subspaces)`.
1412-
pub fn get_space_children(&self, space_id: &OwnedRoomId) -> Option<(Arc<HashSet<OwnedRoomId>>, Arc<HashSet<OwnedRoomId>>)> {
1413-
let inner = self.borrow()?;
1414-
let smv = inner.space_map.get(space_id)?;
1415-
Some((Arc::clone(&smv.direct_child_rooms), Arc::clone(&smv.direct_subspaces)))
1409+
/// Returns the parent chain of the given space, if known.
1410+
pub fn get_space_parent_chain(&self, space_id: &OwnedRoomId) -> Option<ParentChain> {
1411+
self.borrow()?
1412+
.space_map
1413+
.get(space_id)
1414+
.map(|smv| smv.parent_chain.clone())
14161415
}
14171416
}
14181417

src/home/space_lobby.rs

Lines changed: 94 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@
66
//! that allows the user to click on it to show the `SpaceLobby`.
77
//!
88
9-
use std::{collections::{HashMap, HashSet}, sync::Arc};
9+
use std::collections::{HashMap, HashSet};
10+
use imbl::Vector;
1011
use makepad_widgets::*;
1112
use matrix_sdk::ruma::OwnedRoomId;
13+
use matrix_sdk_ui::spaces::SpaceRoom;
1214
use tokio::sync::mpsc::UnboundedSender;
1315
use crate::{
1416
home::rooms_list::RoomsListRef,
1517
shared::avatar::{AvatarWidgetExt, AvatarWidgetRefExt},
16-
space_service_sync::{ParentChain, SpaceRequest, SpaceRoomInfo, SpaceRoomListAction},
18+
space_service_sync::{SpaceRequest, SpaceRoomExt, SpaceRoomListAction},
1719
utils::{self, RoomNameId},
1820
};
1921

@@ -433,6 +435,7 @@ live_design! {
433435
// The hierarchical tree list
434436
tree_list = <PortalList> {
435437
keep_invisible: false,
438+
max_pull_down: 0.0,
436439
auto_tail: false,
437440
width: Fill, height: Fill
438441
flow: Down,
@@ -518,11 +521,7 @@ pub struct TreeLines {
518521
}
519522

520523
impl Widget for TreeLines {
521-
fn handle_event(&mut self, cx: &mut Cx, event: &Event, _scope: &mut Scope) {
522-
// No interaction needed
523-
let _ = event;
524-
let _ = cx;
525-
}
524+
fn handle_event(&mut self, _cx: &mut Cx, _event: &Event, _scope: &mut Scope) { }
526525

527526
fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawStep {
528527
let indent_pixel = (self.draw_bg.level + 1.0) * self.draw_bg.indent_width;
@@ -539,7 +538,7 @@ impl Widget for TreeLines {
539538
pub struct SubspaceEntry {
540539
#[deref] view: View,
541540
#[animator] animator: Animator,
542-
#[rust] room_id: Option<OwnedRoomId>,
541+
#[rust] space_id: Option<OwnedRoomId>,
543542
}
544543

545544
/// A clickable entry for a child room.
@@ -553,7 +552,7 @@ pub struct RoomEntry {
553552
/// Action emitted when a subspace entry is clicked.
554553
#[derive(Clone, Debug, DefaultNone)]
555554
pub enum SubspaceEntryAction {
556-
Clicked { room_id: OwnedRoomId },
555+
Clicked { space_id: OwnedRoomId },
557556
None,
558557
}
559558

@@ -575,9 +574,12 @@ impl Widget for SubspaceEntry {
575574
Hit::FingerHoverOut(_) => { self.animator_play(cx, ids!(hover.off)); }
576575
Hit::FingerDown(_) => { cx.set_key_focus(self.view.area()); }
577576
Hit::FingerUp(fe) if fe.is_over && fe.is_primary_hit() && fe.was_tap() => {
578-
if let Some(room_id) = &self.room_id {
579-
cx.widget_action(self.widget_uid(), &scope.path,
580-
SubspaceEntryAction::Clicked { room_id: room_id.clone() });
577+
if let Some(space_id) = self.space_id.clone() {
578+
cx.widget_action(
579+
self.widget_uid(),
580+
&scope.path,
581+
SubspaceEntryAction::Clicked { space_id },
582+
);
581583
}
582584
}
583585
_ => {}
@@ -601,9 +603,9 @@ impl Widget for RoomEntry {
601603
Hit::FingerHoverOut(_) => { self.animator_play(cx, ids!(hover.off)); }
602604
Hit::FingerDown(_) => { cx.set_key_focus(self.view.area()); }
603605
Hit::FingerUp(fe) if fe.is_over && fe.is_primary_hit() && fe.was_tap() => {
604-
if let Some(room_id) = &self.room_id {
606+
if let Some(room_id) = self.room_id.clone() {
605607
cx.widget_action(self.widget_uid(), &scope.path,
606-
RoomEntryAction::Clicked { room_id: room_id.clone() });
608+
RoomEntryAction::Clicked { room_id });
607609
}
608610
}
609611
_ => {}
@@ -617,13 +619,14 @@ impl Widget for RoomEntry {
617619
}
618620

619621

620-
/// An entry in the flattened tree to be displayed.
622+
/// An entry in the tree to be displayed.
621623
#[derive(Clone, Debug)]
624+
#[allow(clippy::large_enum_variant)]
622625
enum TreeEntry {
623626
/// A regular space or room entry.
624627
Item {
625628
/// The detailed info about this space or room.
626-
info: SpaceRoomInfo,
629+
info: SpaceRoom,
627630
/// The nesting level (0 = direct child of the displayed space).
628631
level: usize,
629632
/// Whether this entry is the last child of its parent.
@@ -653,12 +656,12 @@ pub struct SpaceLobbyScreen {
653656

654657
/// Cache of detailed children for each space we've fetched.
655658
/// Key is the space_id, value is the list of its direct children.
656-
#[rust] children_cache: HashMap<OwnedRoomId, Arc<Vec<SpaceRoomInfo>>>,
659+
#[rust] children_cache: HashMap<OwnedRoomId, Vector<SpaceRoom>>,
657660

658661
/// The set of space IDs that are currently expanded (showing their children).
659662
#[rust] expanded_spaces: HashSet<OwnedRoomId>,
660663

661-
/// The flattened list of tree entries to display.
664+
/// The ordered list of children to display in the space tree.
662665
#[rust] tree_entries: Vec<TreeEntry>,
663666

664667
/// The set of space IDs that are currently loading their children.
@@ -672,16 +675,14 @@ impl Widget for SpaceLobbyScreen {
672675
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
673676
self.view.handle_event(cx, event, scope);
674677

675-
// Listen for actions from the space service.
676678
if let Event::Actions(actions) = event {
677679
for action in actions {
678-
// Handle detailed children response
679680
if let Some(SpaceRoomListAction::DetailedChildren { space_id, children, .. }) = action.downcast_ref() {
680-
self.handle_detailed_children(cx, space_id, children);
681+
self.update_children_in_space(cx, space_id, children);
681682
}
682683

683684
// Handle SubspaceEntry clicks
684-
if let SubspaceEntryAction::Clicked { room_id } = action.as_widget_action().cast() {
685+
if let SubspaceEntryAction::Clicked { space_id: room_id } = action.as_widget_action().cast() {
685686
self.toggle_space_expansion(cx, &room_id);
686687
}
687688

@@ -724,12 +725,10 @@ impl Widget for SpaceLobbyScreen {
724725
} else if let Some(entry) = self.tree_entries.get(item_id) {
725726
match entry {
726727
TreeEntry::Item { info, level, is_last, parent_mask } => {
727-
728-
729-
if info.is_space {
728+
if info.is_space() {
730729
let item = list.item(cx, item_id, id!(subspace_entry));
731730
if let Some(mut inner) = item.borrow_mut::<SubspaceEntry>() {
732-
inner.room_id = Some(info.room_id.clone());
731+
inner.space_id = Some(info.room_id.clone());
733732
}
734733

735734
// Configure tree lines
@@ -750,7 +749,7 @@ impl Widget for SpaceLobbyScreen {
750749
// Avatar
751750
let avatar_ref = item.avatar(ids!(avatar));
752751
let first_char = utils::user_name_first_letter(&info.display_name);
753-
avatar_ref.show_text(cx, None, None, first_char.as_deref().unwrap_or("#"));
752+
avatar_ref.show_text(cx, None, None, first_char.unwrap_or("#"));
754753

755754
// Text
756755
item.label(ids!(content.name_label)).set_text(cx, &info.display_name);
@@ -779,7 +778,7 @@ impl Widget for SpaceLobbyScreen {
779778
// Avatar
780779
let avatar_ref = item.avatar(ids!(avatar));
781780
let first_char = utils::user_name_first_letter(&info.display_name);
782-
avatar_ref.show_text(cx, None, None, first_char.as_deref().unwrap_or("#"));
781+
avatar_ref.show_text(cx, None, None, first_char.unwrap_or("#"));
783782

784783
// Text
785784
item.label(ids!(content.name_label)).set_text(cx, &info.display_name);
@@ -819,9 +818,8 @@ impl Widget for SpaceLobbyScreen {
819818
impl SpaceLobbyScreen {
820819

821820
/// Handle receiving detailed children for a space.
822-
fn handle_detailed_children(&mut self, cx: &mut Cx, space_id: &OwnedRoomId, children: &Arc<Vec<SpaceRoomInfo>>) {
823-
// Store in cache and remove from loading set
824-
self.children_cache.insert(space_id.clone(), Arc::clone(children));
821+
fn update_children_in_space(&mut self, cx: &mut Cx, space_id: &OwnedRoomId, children: &Vector<SpaceRoom>) {
822+
self.children_cache.insert(space_id.clone(), children.clone());
825823
self.loading_subspaces.remove(space_id);
826824

827825
// If this is for our displayed space, mark as loaded and rebuild tree
@@ -847,9 +845,12 @@ impl SpaceLobbyScreen {
847845
if !self.children_cache.contains_key(space_id) {
848846
self.loading_subspaces.insert(space_id.clone());
849847
if let Some(sender) = &self.space_request_sender {
848+
let parent_chain = cx.get_global::<RoomsListRef>()
849+
.get_space_parent_chain(space_id)
850+
.unwrap_or_default();
850851
let _ = sender.send(SpaceRequest::GetDetailedChildren {
851852
space_id: space_id.clone(),
852-
parent_chain: ParentChain::new(),
853+
parent_chain,
853854
});
854855
}
855856
}
@@ -861,26 +862,43 @@ impl SpaceLobbyScreen {
861862

862863
/// Rebuild the flattened tree entries based on the current expansion state.
863864
fn rebuild_tree_entries(&mut self) {
864-
self.tree_entries.clear();
865-
866865
let Some(space_name_id) = &self.space_name_id else { return };
867866
let root_space_id = space_name_id.room_id().clone();
868-
869867
// Build tree starting from root
870-
self.build_tree_for_space(&root_space_id, 0, 0);
868+
let mut new_tree_entries = Vec::new();
869+
Self::build_tree_for_space(
870+
&self.children_cache,
871+
&self.expanded_spaces,
872+
&self.loading_subspaces,
873+
&mut new_tree_entries,
874+
&root_space_id,
875+
0,
876+
0,
877+
);
878+
self.tree_entries = new_tree_entries;
871879
}
872880

873-
/// Build tree entries for a space and its expanded children.
874-
fn build_tree_for_space(&mut self, space_id: &OwnedRoomId, level: usize, parent_mask: u32) {
875-
let children = match self.children_cache.get(space_id) {
876-
Some(c) => Arc::clone(c),
877-
None => return,
878-
};
881+
/// Recursively build the tree of spaces and their expanded children such that they
882+
/// can be displayed in the SpaceLobbyScreen's PortalList.
883+
//
884+
// Note: this is intentionally *not* a method (it doesn't take &mut self),
885+
// in order to make it possible to recursively call it while borrowing only select
886+
// fields of `Self`.
887+
fn build_tree_for_space(
888+
children_cache: &HashMap<OwnedRoomId, Vector<SpaceRoom>>,
889+
expanded_spaces: &HashSet<OwnedRoomId>,
890+
loading_subspaces: &HashSet<OwnedRoomId>,
891+
tree_entries: &mut Vec<TreeEntry>,
892+
space_id: &OwnedRoomId,
893+
level: usize,
894+
parent_mask: u32,
895+
) {
896+
let Some(children) = children_cache.get(space_id) else { return };
879897

880898
// Sort: spaces first, then rooms, both alphabetically
881899
let mut sorted_children: Vec<_> = children.iter().collect();
882900
sorted_children.sort_by(|a, b| {
883-
match (a.is_space, b.is_space) {
901+
match (a.is_space(), b.is_space()) {
884902
(true, false) => std::cmp::Ordering::Less,
885903
(false, true) => std::cmp::Ordering::Greater,
886904
_ => a.display_name.to_lowercase().cmp(&b.display_name.to_lowercase()),
@@ -892,15 +910,15 @@ impl SpaceLobbyScreen {
892910
for (i, child) in sorted_children.iter().enumerate() {
893911
let is_last = i == count - 1;
894912

895-
self.tree_entries.push(TreeEntry::Item {
913+
tree_entries.push(TreeEntry::Item {
896914
info: (*child).clone(),
897915
level,
898916
is_last,
899917
parent_mask,
900918
});
901919

902920
// If this is an expanded space, recursively add its children or a loading indicator
903-
if child.is_space && self.expanded_spaces.contains(&child.room_id) {
921+
if child.is_space() && expanded_spaces.contains(&child.room_id) {
904922
// Calculate mask for children:
905923
// If we are NOT the last child, our level needs a continuation line for our children.
906924
// If we ARE the last child, our level does NOT need a line.
@@ -911,11 +929,19 @@ impl SpaceLobbyScreen {
911929
parent_mask | (1 << level)
912930
};
913931

914-
if self.children_cache.contains_key(&child.room_id) {
915-
self.build_tree_for_space(&child.room_id, level + 1, child_mask);
916-
} else if self.loading_subspaces.contains(&child.room_id) {
932+
if children_cache.contains_key(&child.room_id) {
933+
Self::build_tree_for_space(
934+
children_cache,
935+
expanded_spaces,
936+
loading_subspaces,
937+
tree_entries,
938+
&child.room_id,
939+
level + 1,
940+
child_mask,
941+
);
942+
} else if loading_subspaces.contains(&child.room_id) {
917943
// Show loading indicator
918-
self.tree_entries.push(TreeEntry::Loading {
944+
tree_entries.push(TreeEntry::Loading {
919945
level: level + 1,
920946
parent_mask: child_mask,
921947
});
@@ -925,56 +951,43 @@ impl SpaceLobbyScreen {
925951
}
926952

927953
pub fn set_displayed_space(&mut self, cx: &mut Cx, space_name_id: &RoomNameId) {
928-
// If this space is already being displayed, then do nothing.
954+
let space_name = space_name_id.to_string();
955+
let parent_name = self.view.label(ids!(header.parent_space_row.parent_name));
956+
parent_name.set_text(cx, &space_name);
957+
958+
// If this space is already being displayed, then the only thing we may need to do
959+
// is update its name in the top-level header (already done above).
929960
if self.space_name_id.as_ref().is_some_and(|sni| sni.room_id() == space_name_id.room_id()) {
930961
return;
931962
}
932963

933-
// Clear previous state
964+
self.space_name_id = Some(space_name_id.clone());
965+
let rooms_list_ref = cx.get_global::<RoomsListRef>();
966+
if let Some(sender) = rooms_list_ref.get_space_request_sender() {
967+
// Request detailed children for this space so we can start populating it.
968+
let parent_chain_opt = rooms_list_ref.get_space_parent_chain(space_name_id.room_id());
969+
let _ = sender.send(SpaceRequest::GetDetailedChildren {
970+
space_id: space_name_id.room_id().clone(),
971+
parent_chain: parent_chain_opt.unwrap_or_default(),
972+
});
973+
self.space_request_sender = Some(sender);
974+
}
975+
934976
self.tree_entries.clear();
935977
self.expanded_spaces.clear();
936978
self.is_loading = true;
937979

938-
// Set the new space
939-
self.space_name_id = Some(space_name_id.clone());
940-
941-
// Update parent space header
942-
let space_name = space_name_id.to_string();
943-
self.view.label(ids!(header.parent_space_row.parent_name)).set_text(cx, &space_name);
944-
945980
// Set parent avatar
946981
let avatar_ref = self.view.avatar(ids!(header.parent_space_row.parent_avatar));
947982
let first_char = utils::user_name_first_letter(&space_name);
948-
avatar_ref.show_text(cx, None, None, first_char.as_deref().unwrap_or("#"));
949-
950-
// Request detailed children for this space
951-
if let Some(sender) = &self.space_request_sender {
952-
let _ = sender.send(SpaceRequest::GetDetailedChildren {
953-
space_id: space_name_id.room_id().clone(),
954-
parent_chain: ParentChain::new(),
955-
});
956-
}
957-
983+
avatar_ref.show_text(cx, None, None, first_char.unwrap_or("#"));
958984
self.redraw(cx);
959985
}
960-
961-
/// Set the space request sender channel.
962-
pub fn set_space_request_sender(&mut self, sender: UnboundedSender<SpaceRequest>) {
963-
self.space_request_sender = Some(sender);
964-
}
965986
}
966987

967988
impl SpaceLobbyScreenRef {
968989
pub fn set_displayed_space(&self, cx: &mut Cx, space_name_id: &RoomNameId) {
969990
let Some(mut inner) = self.borrow_mut() else { return };
970-
971-
// Get the space request sender from RoomsList via Cx global if needed
972-
if inner.space_request_sender.is_none() {
973-
if let Some(sender) = cx.get_global::<RoomsListRef>().get_space_request_sender() {
974-
inner.space_request_sender = Some(sender);
975-
}
976-
}
977-
978991
inner.set_displayed_space(cx, space_name_id);
979992
}
980993
}

0 commit comments

Comments
 (0)