From 4a088fc4aeb24401c8d011109f3430229934a056 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 25 Jul 2023 18:00:49 -0700 Subject: [PATCH] Make major collab panel headers non-interactive --- crates/collab_ui/src/panel.rs | 258 ++++++++++++++------------ crates/theme/src/theme.rs | 2 +- styles/src/style_tree/collab_panel.ts | 41 +--- 3 files changed, 146 insertions(+), 155 deletions(-) diff --git a/crates/collab_ui/src/panel.rs b/crates/collab_ui/src/panel.rs index e78f3ce22f92b63487405e547ae84796923f2194..bf0397ec765ee2a52143313f7e67dc8cf05aac97 100644 --- a/crates/collab_ui/src/panel.rs +++ b/crates/collab_ui/src/panel.rs @@ -444,123 +444,122 @@ impl CollabPanel { self.entries .push(ContactEntry::Header(Section::Contacts, 0)); - if !self.collapsed_sections.contains(&Section::Contacts) { - let mut request_entries = Vec::new(); - let incoming = user_store.incoming_contact_requests(); - if !incoming.is_empty() { - self.match_candidates.clear(); - self.match_candidates - .extend( - incoming - .iter() - .enumerate() - .map(|(ix, user)| StringMatchCandidate { - id: ix, - string: user.github_login.clone(), - char_bag: user.github_login.chars().collect(), - }), - ); - let matches = executor.block(match_strings( - &self.match_candidates, - &query, - true, - usize::MAX, - &Default::default(), - executor.clone(), - )); - request_entries.extend( - matches.iter().map(|mat| { - ContactEntry::IncomingRequest(incoming[mat.candidate_id].clone()) - }), + let mut request_entries = Vec::new(); + let incoming = user_store.incoming_contact_requests(); + if !incoming.is_empty() { + self.match_candidates.clear(); + self.match_candidates + .extend( + incoming + .iter() + .enumerate() + .map(|(ix, user)| StringMatchCandidate { + id: ix, + string: user.github_login.clone(), + char_bag: user.github_login.chars().collect(), + }), ); - } + let matches = executor.block(match_strings( + &self.match_candidates, + &query, + true, + usize::MAX, + &Default::default(), + executor.clone(), + )); + request_entries.extend( + matches + .iter() + .map(|mat| ContactEntry::IncomingRequest(incoming[mat.candidate_id].clone())), + ); + } - let outgoing = user_store.outgoing_contact_requests(); - if !outgoing.is_empty() { - self.match_candidates.clear(); - self.match_candidates - .extend( - outgoing - .iter() - .enumerate() - .map(|(ix, user)| StringMatchCandidate { - id: ix, - string: user.github_login.clone(), - char_bag: user.github_login.chars().collect(), - }), - ); - let matches = executor.block(match_strings( - &self.match_candidates, - &query, - true, - usize::MAX, - &Default::default(), - executor.clone(), - )); - request_entries.extend( - matches.iter().map(|mat| { - ContactEntry::OutgoingRequest(outgoing[mat.candidate_id].clone()) - }), + let outgoing = user_store.outgoing_contact_requests(); + if !outgoing.is_empty() { + self.match_candidates.clear(); + self.match_candidates + .extend( + outgoing + .iter() + .enumerate() + .map(|(ix, user)| StringMatchCandidate { + id: ix, + string: user.github_login.clone(), + char_bag: user.github_login.chars().collect(), + }), ); - } + let matches = executor.block(match_strings( + &self.match_candidates, + &query, + true, + usize::MAX, + &Default::default(), + executor.clone(), + )); + request_entries.extend( + matches + .iter() + .map(|mat| ContactEntry::OutgoingRequest(outgoing[mat.candidate_id].clone())), + ); + } - if !request_entries.is_empty() { - self.entries - .push(ContactEntry::Header(Section::Requests, 1)); - if !self.collapsed_sections.contains(&Section::Requests) { - self.entries.append(&mut request_entries); - } + if !request_entries.is_empty() { + self.entries + .push(ContactEntry::Header(Section::Requests, 1)); + if !self.collapsed_sections.contains(&Section::Requests) { + self.entries.append(&mut request_entries); } + } - let contacts = user_store.contacts(); - if !contacts.is_empty() { - self.match_candidates.clear(); - self.match_candidates - .extend(contacts.iter().enumerate().map(|(ix, contact)| { - StringMatchCandidate { + let contacts = user_store.contacts(); + if !contacts.is_empty() { + self.match_candidates.clear(); + self.match_candidates + .extend( + contacts + .iter() + .enumerate() + .map(|(ix, contact)| StringMatchCandidate { id: ix, string: contact.user.github_login.clone(), char_bag: contact.user.github_login.chars().collect(), - } - })); + }), + ); - let matches = executor.block(match_strings( - &self.match_candidates, - &query, - true, - usize::MAX, - &Default::default(), - executor.clone(), - )); + let matches = executor.block(match_strings( + &self.match_candidates, + &query, + true, + usize::MAX, + &Default::default(), + executor.clone(), + )); - let (mut online_contacts, offline_contacts) = matches - .iter() - .partition::, _>(|mat| contacts[mat.candidate_id].online); - if let Some(room) = ActiveCall::global(cx).read(cx).room() { - let room = room.read(cx); - online_contacts.retain(|contact| { - let contact = &contacts[contact.candidate_id]; - !room.contains_participant(contact.user.id) - }); - } + let (mut online_contacts, offline_contacts) = matches + .iter() + .partition::, _>(|mat| contacts[mat.candidate_id].online); + if let Some(room) = ActiveCall::global(cx).read(cx).room() { + let room = room.read(cx); + online_contacts.retain(|contact| { + let contact = &contacts[contact.candidate_id]; + !room.contains_participant(contact.user.id) + }); + } - for (matches, section) in [ - (online_contacts, Section::Online), - (offline_contacts, Section::Offline), - ] { - if !matches.is_empty() { - self.entries.push(ContactEntry::Header(section, 1)); - if !self.collapsed_sections.contains(§ion) { - let active_call = &ActiveCall::global(cx).read(cx); - for mat in matches { - let contact = &contacts[mat.candidate_id]; - self.entries.push(ContactEntry::Contact { - contact: contact.clone(), - calling: active_call - .pending_invites() - .contains(&contact.user.id), - }); - } + for (matches, section) in [ + (online_contacts, Section::Online), + (offline_contacts, Section::Offline), + ] { + if !matches.is_empty() { + self.entries.push(ContactEntry::Header(section, 1)); + if !self.collapsed_sections.contains(§ion) { + let active_call = &ActiveCall::global(cx).read(cx); + for mat in matches { + let contact = &contacts[mat.candidate_id]; + self.entries.push(ContactEntry::Contact { + contact: contact.clone(), + calling: active_call.pending_invites().contains(&contact.user.id), + }); } } } @@ -940,13 +939,15 @@ impl CollabPanel { let can_collapse = depth > 0; let icon_size = (&theme.collab_panel).section_icon_size; MouseEventHandler::::new(section as usize, cx, |state, _| { - let header_style = if depth > 0 { - &theme.collab_panel.subheader_row + let header_style = if can_collapse { + theme + .collab_panel + .subheader_row + .in_state(is_selected) + .style_for(state) } else { &theme.collab_panel.header_row - } - .in_state(is_selected) - .style_for(state); + }; Flex::row() .with_children(if can_collapse { @@ -1209,13 +1210,15 @@ impl CollabPanel { } fn select_next(&mut self, _: &SelectNext, cx: &mut ViewContext) { - if let Some(ix) = self.selection { - if self.entries.len() > ix + 1 { - self.selection = Some(ix + 1); + let mut ix = self.selection.map_or(0, |ix| ix + 1); + while let Some(entry) = self.entries.get(ix) { + if entry.is_selectable() { + self.selection = Some(ix); + break; } - } else if !self.entries.is_empty() { - self.selection = Some(0); + ix += 1; } + self.list_state.reset(self.entries.len()); if let Some(ix) = self.selection { self.list_state.scroll_to(ListOffset { @@ -1227,13 +1230,18 @@ impl CollabPanel { } fn select_prev(&mut self, _: &SelectPrev, cx: &mut ViewContext) { - if let Some(ix) = self.selection { - if ix > 0 { - self.selection = Some(ix - 1); - } else { - self.selection = None; + if let Some(mut ix) = self.selection.take() { + while ix > 0 { + ix -= 1; + if let Some(entry) = self.entries.get(ix) { + if entry.is_selectable() { + self.selection = Some(ix); + break; + } + } } } + self.list_state.reset(self.entries.len()); if let Some(ix) = self.selection { self.list_state.scroll_to(ListOffset { @@ -1471,6 +1479,16 @@ impl Panel for CollabPanel { } } +impl ContactEntry { + fn is_selectable(&self) -> bool { + if let ContactEntry::Header(_, 0) = self { + false + } else { + true + } + } +} + impl PartialEq for ContactEntry { fn eq(&self, other: &Self) -> bool { match self { diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index c06a71d2dbbbdab1d186666a5f3ff27b0db53177..e13c8daafcc87cbc7bd3437d98d64d3bcebad489 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -225,7 +225,7 @@ pub struct CollabPanel { pub user_query_editor_height: f32, pub leave_call_button: IconButton, pub add_contact_button: IconButton, - pub header_row: Toggleable>, + pub header_row: ContainedText, pub subheader_row: Toggleable>, pub leave_call: Interactive, pub contact_row: Toggleable>, diff --git a/styles/src/style_tree/collab_panel.ts b/styles/src/style_tree/collab_panel.ts index 39ee9b610f5d7c8a60b418ec69afc293ffeaaa03..4f847081abbf7a769eb8f106956e5059798f4ce1 100644 --- a/styles/src/style_tree/collab_panel.ts +++ b/styles/src/style_tree/collab_panel.ts @@ -87,45 +87,18 @@ export default function contacts_panel(): any { }, row_height: 28, section_icon_size: 8, - header_row: toggleable({ - base: interactive({ - base: { - ...text(layer, "mono", { size: "sm", weight: "bold" }), - margin: { top: 14 }, - padding: { - left: side_padding, - right: side_padding, - }, - }, - state: { - hovered: { - background: background(layer, "hovered"), - }, - clicked: { - background: background(layer, "pressed"), - }, - }, - }), - state: { - active: { - default: { - ...text(layer, "mono", "active", { size: "sm" }), - background: background(layer, "active"), - }, - hovered: { - background: background(layer, "hovered"), - }, - clicked: { - background: background(layer, "pressed"), - }, - }, + header_row: { + ...text(layer, "mono", { size: "sm", weight: "bold" }), + margin: { top: 14 }, + padding: { + left: side_padding, + right: side_padding, }, - }), + }, subheader_row: toggleable({ base: interactive({ base: { ...text(layer, "mono", { size: "sm" }), - // margin: { top: 14 }, padding: { left: side_padding, right: side_padding,