Add disclosable components into channels

Rename components to more closely match their purpose
This commit is contained in:
Mikayla 2023-08-19 05:18:53 -07:00
parent 2d37128693
commit bd3ab82dac
No known key found for this signature in database
10 changed files with 359 additions and 194 deletions

View file

@ -16,9 +16,9 @@ use fuzzy::{match_strings, StringMatchCandidate};
use gpui::{
actions,
elements::{
Canvas, ChildView, Empty, Flex, GeneralComponent, GeneralStyleableComponent, Image, Label,
List, ListOffset, ListState, MouseEventHandler, Orientation, OverlayPositionMode, Padding,
ParentElement, Stack, Svg,
Canvas, ChildView, Component, Empty, Flex, Image, Label, List, ListOffset, ListState,
MouseEventHandler, Orientation, OverlayPositionMode, Padding, ParentElement, Stack,
StyleableComponent, Svg,
},
geometry::{
rect::RectF,
@ -36,7 +36,7 @@ use serde_derive::{Deserialize, Serialize};
use settings::SettingsStore;
use staff_mode::StaffMode;
use std::{borrow::Cow, mem, sync::Arc};
use theme::IconButton;
use theme::{components::ComponentExt, IconButton};
use util::{iife, ResultExt, TryFutureExt};
use workspace::{
dock::{DockPosition, Panel},
@ -44,10 +44,7 @@ use workspace::{
Workspace,
};
use crate::{
collab_panel::components::{DisclosureExt, DisclosureStyle},
face_pile::FacePile,
};
use crate::face_pile::FacePile;
use channel_modal::ChannelModal;
use self::contact_finder::ContactFinder;
@ -57,6 +54,11 @@ struct RemoveChannel {
channel_id: u64,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
struct ToggleCollapsed {
channel_id: u64,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
struct NewChannel {
channel_id: u64,
@ -86,7 +88,8 @@ impl_actions!(
NewChannel,
InviteMembers,
ManageMembers,
RenameChannel
RenameChannel,
ToggleCollapsed
]
);
@ -109,6 +112,7 @@ pub fn init(_client: Arc<Client>, cx: &mut AppContext) {
cx.add_action(CollabPanel::manage_members);
cx.add_action(CollabPanel::rename_selected_channel);
cx.add_action(CollabPanel::rename_channel);
cx.add_action(CollabPanel::toggle_channel_collapsed);
}
#[derive(Debug)]
@ -151,6 +155,7 @@ pub struct CollabPanel {
list_state: ListState<Self>,
subscriptions: Vec<Subscription>,
collapsed_sections: Vec<Section>,
collapsed_channels: Vec<ChannelId>,
workspace: WeakViewHandle<Workspace>,
context_menu_on_selected: bool,
}
@ -402,6 +407,7 @@ impl CollabPanel {
subscriptions: Vec::default(),
match_candidates: Vec::default(),
collapsed_sections: vec![Section::Offline],
collapsed_channels: Vec::default(),
workspace: workspace.weak_handle(),
client: workspace.app_state().client.clone(),
context_menu_on_selected: true,
@ -661,10 +667,24 @@ impl CollabPanel {
self.entries.push(ListEntry::ChannelEditor { depth: 0 });
}
}
let mut collapse_depth = None;
for mat in matches {
let (depth, channel) =
channel_store.channel_at_index(mat.candidate_id).unwrap();
if collapse_depth.is_none() && self.is_channel_collapsed(channel.id) {
collapse_depth = Some(depth);
} else if let Some(collapsed_depth) = collapse_depth {
if depth > collapsed_depth {
continue;
}
if self.is_channel_collapsed(channel.id) {
collapse_depth = Some(depth);
} else {
collapse_depth = None;
}
}
match &self.channel_editing_state {
Some(ChannelEditingState::Create { parent_id, .. })
if *parent_id == Some(channel.id) =>
@ -1483,6 +1503,11 @@ impl CollabPanel {
cx: &AppContext,
) -> AnyElement<Self> {
Flex::row()
.with_child(
Empty::new()
.constrained()
.with_width(theme.collab_panel.disclosure.button_space()),
)
.with_child(
Svg::new("icons/hash.svg")
.with_color(theme.collab_panel.channel_hash.color)
@ -1541,6 +1566,10 @@ impl CollabPanel {
cx: &mut ViewContext<Self>,
) -> AnyElement<Self> {
let channel_id = channel.id;
let has_children = self.channel_store.read(cx).has_children(channel_id);
let disclosed =
has_children.then(|| !self.collapsed_channels.binary_search(&channel_id).is_ok());
let is_active = iife!({
let call_channel = ActiveCall::global(cx)
.read(cx)
@ -1554,7 +1583,7 @@ impl CollabPanel {
const FACEPILE_LIMIT: usize = 3;
MouseEventHandler::new::<Channel, _>(channel.id as usize, cx, |state, cx| {
Flex::row()
Flex::<Self>::row()
.with_child(
Svg::new("icons/hash.svg")
.with_color(theme.channel_hash.color)
@ -1603,6 +1632,14 @@ impl CollabPanel {
}
})
.align_children_center()
.styleable_component()
.disclosable(
disclosed,
Box::new(ToggleCollapsed { channel_id }),
channel_id as usize,
)
.with_style(theme.disclosure.clone())
.element()
.constrained()
.with_height(theme.row_height)
.contained()
@ -1619,17 +1656,6 @@ impl CollabPanel {
this.deploy_channel_context_menu(Some(e.position), channel_id, cx);
})
.with_cursor_style(CursorStyle::PointingHand)
.dynamic_component()
.stylable()
.disclosable(true, Box::new(RemoveChannel { channel_id: 0 }))
.with_style({
fn style() -> DisclosureStyle<()> {
todo!()
}
style()
})
.element()
.into_any()
}
@ -2024,6 +2050,24 @@ impl CollabPanel {
self.update_entries(false, cx);
}
fn toggle_channel_collapsed(&mut self, action: &ToggleCollapsed, cx: &mut ViewContext<Self>) {
let channel_id = action.channel_id;
match self.collapsed_channels.binary_search(&channel_id) {
Ok(ix) => {
self.collapsed_channels.remove(ix);
}
Err(ix) => {
self.collapsed_channels.insert(ix, channel_id);
}
};
self.update_entries(false, cx);
cx.notify();
}
fn is_channel_collapsed(&self, channel: ChannelId) -> bool {
self.collapsed_channels.binary_search(&channel).is_ok()
}
fn leave_call(cx: &mut ViewContext<Self>) {
ActiveCall::global(cx)
.update(cx, |call, cx| call.hang_up(cx))
@ -2537,87 +2581,3 @@ fn render_icon_button(style: &IconButton, svg_path: &'static str) -> impl Elemen
.contained()
.with_style(style.container)
}
mod components {
use gpui::{
elements::{Empty, Flex, GeneralComponent, GeneralStyleableComponent, ParentElement},
Action, Element,
};
use theme::components::{
action_button::ActionButton, svg::Svg, ComponentExt, ToggleIconButtonStyle,
};
#[derive(Clone)]
pub struct DisclosureStyle<S> {
disclosure: ToggleIconButtonStyle,
spacing: f32,
content: S,
}
pub struct Disclosable<C, S> {
disclosed: bool,
action: Box<dyn Action>,
content: C,
style: S,
}
impl Disclosable<(), ()> {
fn new<C>(disclosed: bool, content: C, action: Box<dyn Action>) -> Disclosable<C, ()> {
Disclosable {
disclosed,
content,
action,
style: (),
}
}
}
impl<C: GeneralStyleableComponent> GeneralStyleableComponent for Disclosable<C, ()> {
type Style = DisclosureStyle<C::Style>;
type Output = Disclosable<C, Self::Style>;
fn with_style(self, style: Self::Style) -> Self::Output {
Disclosable {
disclosed: self.disclosed,
action: self.action,
content: self.content,
style,
}
}
}
impl<C: GeneralStyleableComponent> GeneralComponent for Disclosable<C, DisclosureStyle<C::Style>> {
fn render<V: gpui::View>(
self,
v: &mut V,
cx: &mut gpui::ViewContext<V>,
) -> gpui::AnyElement<V> {
Flex::row()
.with_child(
ActionButton::new_dynamic(self.action)
.with_contents(Svg::new("path"))
.toggleable(self.disclosed)
.with_style(self.style.disclosure)
.element(),
)
.with_child(Empty::new().constrained().with_width(self.style.spacing))
.with_child(self.content.with_style(self.style.content).render(v, cx))
.align_children_center()
.into_any()
}
}
pub trait DisclosureExt {
fn disclosable(self, disclosed: bool, action: Box<dyn Action>) -> Disclosable<Self, ()>
where
Self: Sized;
}
impl<C: GeneralStyleableComponent> DisclosureExt for C {
fn disclosable(self, disclosed: bool, action: Box<dyn Action>) -> Disclosable<Self, ()> {
Disclosable::new(disclosed, self, action)
}
}
}