refactor panel open flow
This commit is contained in:
+5
-30
@@ -9,7 +9,7 @@ use fuzzy_matcher::FuzzyMatcher;
|
|||||||
use fuzzy_matcher::skim::SkimMatcherV2;
|
use fuzzy_matcher::skim::SkimMatcherV2;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
App, AppContext, Context, Entity, EventEmitter, Global, SharedString, Subscription, Task,
|
App, AppContext, Context, Entity, EventEmitter, Global, SharedString, Subscription, Task,
|
||||||
WeakEntity, Window,
|
WeakEntity,
|
||||||
};
|
};
|
||||||
use instant::Duration;
|
use instant::Duration;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
@@ -37,15 +37,8 @@ impl Global for GlobalChatRegistry {}
|
|||||||
/// Chat event.
|
/// Chat event.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum ChatEvent {
|
pub enum ChatEvent {
|
||||||
/// An event to open a room by its ID
|
|
||||||
OpenRoom(u64),
|
|
||||||
/// An event to close a room by its ID
|
|
||||||
CloseRoom(u64),
|
|
||||||
/// An event to notify UI about a new chat request
|
|
||||||
Ping,
|
Ping,
|
||||||
/// No Inbox Relays found, the app is not ready to subscribe messages
|
|
||||||
InboxRelayNotFound,
|
InboxRelayNotFound,
|
||||||
/// An error occurred
|
|
||||||
Error(String),
|
Error(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,34 +536,16 @@ impl ChatRegistry {
|
|||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit an open room event.
|
/// Track a room so it is listed and can be looked up by id.
|
||||||
///
|
pub fn track_room(&mut self, room: &Entity<Room>, cx: &mut Context<Self>) {
|
||||||
/// If the room is new, add it to the registry.
|
|
||||||
pub fn emit_room(&mut self, room: &Entity<Room>, window: &mut Window, cx: &mut Context<Self>) {
|
|
||||||
// Get the room's ID.
|
|
||||||
let id = room.read(cx).id;
|
let id = room.read(cx).id;
|
||||||
|
|
||||||
// If the room is new, add it to the registry and index.
|
|
||||||
if let hash_map::Entry::Vacant(e) = self.room_index.entry(id) {
|
if let hash_map::Entry::Vacant(e) = self.room_index.entry(id) {
|
||||||
let entity = room.to_owned();
|
let entity = room.to_owned();
|
||||||
e.insert(entity.clone());
|
e.insert(entity.clone());
|
||||||
|
|
||||||
self.rooms.insert(0, entity);
|
self.rooms.insert(0, entity);
|
||||||
}
|
cx.notify();
|
||||||
|
|
||||||
// Emit the open room event deferred to avoid re-entrant reads
|
|
||||||
cx.defer_in(window, move |_this, _window, cx| {
|
|
||||||
cx.emit(ChatEvent::OpenRoom(id));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Close a room.
|
|
||||||
pub fn close_room(&mut self, id: u64, window: &mut Window, cx: &mut Context<Self>) {
|
|
||||||
if self.room_index.contains_key(&id) {
|
|
||||||
self.room_index.remove(&id);
|
|
||||||
self.rooms.retain(|r| r.read(cx).id != id);
|
|
||||||
cx.defer_in(window, move |_this, _window, cx| {
|
|
||||||
cx.emit(ChatEvent::CloseRoom(id));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -107,8 +107,6 @@ impl SubscriptionKey {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum CommunityEvent {
|
pub enum CommunityEvent {
|
||||||
Updated(CommunityId),
|
Updated(CommunityId),
|
||||||
Open(CommunityId),
|
|
||||||
Close(CommunityId),
|
|
||||||
Channel(CommunityId, ChannelId),
|
Channel(CommunityId, ChannelId),
|
||||||
/// History exists here that no held key can open.
|
/// History exists here that no held key can open.
|
||||||
Unreadable(CommunityId),
|
Unreadable(CommunityId),
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ pub use concord::cord03::{ChatMessage, ReplyRef};
|
|||||||
use concord::state::CommunityState;
|
use concord::state::CommunityState;
|
||||||
pub use concord::{ChannelId, CommunityId, Epoch};
|
pub use concord::{ChannelId, CommunityId, Epoch};
|
||||||
use futures::future::{Either, select};
|
use futures::future::{Either, select};
|
||||||
use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, Subscription, Task, Window};
|
use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, Subscription, Task};
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
use state::NostrRegistry;
|
use state::NostrRegistry;
|
||||||
@@ -225,27 +225,6 @@ impl CommunityRegistry {
|
|||||||
self.index.get(id).cloned()
|
self.index.get(id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ask the workspace to open a community's panel.
|
|
||||||
pub fn emit_community(
|
|
||||||
&mut self,
|
|
||||||
community: &Entity<Community>,
|
|
||||||
window: &mut Window,
|
|
||||||
cx: &mut Context<Self>,
|
|
||||||
) {
|
|
||||||
let id = community.read(cx).id();
|
|
||||||
|
|
||||||
cx.defer_in(window, move |_this, _window, cx| {
|
|
||||||
cx.emit(CommunityEvent::Open(id));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ask the workspace to close a community's panel.
|
|
||||||
pub fn emit_close(&mut self, id: CommunityId, window: &mut Window, cx: &mut Context<Self>) {
|
|
||||||
cx.defer_in(window, move |_this, _window, cx| {
|
|
||||||
cx.emit(CommunityEvent::Close(id));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a community owned by the current account and begin tracking it.
|
/// Create a community owned by the current account and begin tracking it.
|
||||||
pub fn create(&mut self, metadata: CommunityMetadata, cx: &mut Context<Self>) {
|
pub fn create(&mut self, metadata: CommunityMetadata, cx: &mut Context<Self>) {
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
|
|||||||
@@ -145,21 +145,19 @@ impl CommunityPanel {
|
|||||||
window,
|
window,
|
||||||
|_this, _community, event, window, cx| {
|
|_this, _community, event, window, cx| {
|
||||||
match event {
|
match event {
|
||||||
CommunityEvent::Updated(_)
|
|
||||||
| CommunityEvent::Unreadable(_)
|
|
||||||
| CommunityEvent::Failed(_) => {
|
|
||||||
cx.defer_in(window, |this, window, cx| this.reload(window, cx));
|
|
||||||
}
|
|
||||||
CommunityEvent::Channel(..) => {
|
CommunityEvent::Channel(..) => {
|
||||||
cx.defer_in(window, |this, window, cx| this.load(window, cx));
|
cx.defer_in(window, |this, window, cx| {
|
||||||
|
this.load(window, cx);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
CommunityEvent::Error(error) => {
|
CommunityEvent::Error(error) => {
|
||||||
window.push_notification(
|
window.push_notification(Notification::error(error.clone()), cx);
|
||||||
Notification::error(error.clone()).autohide(false),
|
}
|
||||||
cx,
|
_ => {
|
||||||
);
|
cx.defer_in(window, |this, window, cx| {
|
||||||
|
this.reload(window, cx);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
CommunityEvent::Open(_) | CommunityEvent::Close(_) => {}
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -95,6 +95,19 @@ pub fn add_panel(
|
|||||||
area.add_panel_view(Arc::new(panel), placement, None, window, cx);
|
area.add_panel_view(Arc::new(panel), placement, None, window, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a panel to a dock reached through a weak handle.
|
||||||
|
pub fn add_panel_to(
|
||||||
|
dock: &WeakEntity<DockArea>,
|
||||||
|
panel: PanelHandle,
|
||||||
|
placement: DockPlacement,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut App,
|
||||||
|
) {
|
||||||
|
let _ = dock.update(cx, |area, cx| {
|
||||||
|
add_panel(area, panel, placement, window, cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// The panel in any region of `area` whose logical id is `key`.
|
/// The panel in any region of `area` whose logical id is `key`.
|
||||||
fn find_panel(area: &DockArea, key: &SharedString, cx: &App) -> Option<(PanelId, NodeId, usize)> {
|
fn find_panel(area: &DockArea, key: &SharedString, cx: &App) -> Option<(PanelId, NodeId, usize)> {
|
||||||
let placements = [
|
let placements = [
|
||||||
|
|||||||
@@ -2,17 +2,18 @@ use chat::{ChatRegistry, Room, RoomKind};
|
|||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
App, AppContext, Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled,
|
App, AppContext, Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled,
|
||||||
Subscription, Window, div, px,
|
Subscription, WeakEntity, Window, div, px,
|
||||||
};
|
};
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use state::NostrRegistry;
|
use state::NostrRegistry;
|
||||||
use theme::ActiveTheme;
|
use theme::ActiveTheme;
|
||||||
use ui::button::{Button, ButtonVariants};
|
use ui::button::{Button, ButtonVariants};
|
||||||
|
use ui::dock::{DockArea, DockPlacement, PanelHandle};
|
||||||
use ui::input::{Input, InputEvent, InputState};
|
use ui::input::{Input, InputEvent, InputState};
|
||||||
use ui::{StyledExt, WindowExtension, v_flex};
|
use ui::{StyledExt, WindowExtension, v_flex};
|
||||||
|
|
||||||
pub fn open(window: &mut Window, cx: &mut App) {
|
pub fn open(dock: WeakEntity<DockArea>, window: &mut Window, cx: &mut App) {
|
||||||
let view = cx.new(|cx| NewChat::new(window, cx));
|
let view = cx.new(|cx| NewChat::new(dock, window, cx));
|
||||||
|
|
||||||
window.open_modal(cx, move |this, _window, _cx| {
|
window.open_modal(cx, move |this, _window, _cx| {
|
||||||
this.width(px(420.)).title("New chat").child(view.clone())
|
this.width(px(420.)).title("New chat").child(view.clone())
|
||||||
@@ -20,6 +21,9 @@ pub fn open(window: &mut Window, cx: &mut App) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct NewChat {
|
pub struct NewChat {
|
||||||
|
/// The dock a started chat opens in
|
||||||
|
dock: WeakEntity<DockArea>,
|
||||||
|
|
||||||
/// Public key input
|
/// Public key input
|
||||||
input: Entity<InputState>,
|
input: Entity<InputState>,
|
||||||
|
|
||||||
@@ -31,7 +35,7 @@ pub struct NewChat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NewChat {
|
impl NewChat {
|
||||||
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
fn new(dock: WeakEntity<DockArea>, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||||
let input = cx.new(|cx| InputState::new(window, cx).placeholder("npub"));
|
let input = cx.new(|cx| InputState::new(window, cx).placeholder("npub"));
|
||||||
|
|
||||||
let subscription = cx.subscribe_in(&input, window, |this, _input, event, window, cx| {
|
let subscription = cx.subscribe_in(&input, window, |this, _input, event, window, cx| {
|
||||||
@@ -41,6 +45,7 @@ impl NewChat {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
dock,
|
||||||
input,
|
input,
|
||||||
error: None,
|
error: None,
|
||||||
_subscription: Some(subscription),
|
_subscription: Some(subscription),
|
||||||
@@ -56,6 +61,8 @@ impl NewChat {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
|
let chat = ChatRegistry::global(cx);
|
||||||
|
|
||||||
let Some(current_user) = nostr.read(cx).current_user() else {
|
let Some(current_user) = nostr.read(cx).current_user() else {
|
||||||
self.set_error("You are not signed in", cx);
|
self.set_error("You are not signed in", cx);
|
||||||
return;
|
return;
|
||||||
@@ -70,12 +77,20 @@ impl NewChat {
|
|||||||
.organize(¤t_user)
|
.organize(¤t_user)
|
||||||
.kind(RoomKind::Ongoing);
|
.kind(RoomKind::Ongoing);
|
||||||
|
|
||||||
let chat = ChatRegistry::global(cx);
|
let room = chat.update(cx, |chat, cx| {
|
||||||
chat.update(cx, |chat, cx| {
|
|
||||||
let room = cx.new(|_| room);
|
let room = cx.new(|_| room);
|
||||||
chat.emit_room(&room, window, cx);
|
chat.track_room(&room, cx);
|
||||||
|
room
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ui::dock::add_panel_to(
|
||||||
|
&self.dock,
|
||||||
|
PanelHandle::new(chat_ui::init(room.downgrade(), window, cx)),
|
||||||
|
DockPlacement::Center,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
|
||||||
window.close_modal(cx);
|
window.close_modal(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-88
@@ -6,13 +6,11 @@ use anyhow::Error;
|
|||||||
use auto_update::AutoUpdater;
|
use auto_update::AutoUpdater;
|
||||||
use chat::{ChatEvent, ChatRegistry};
|
use chat::{ChatEvent, ChatRegistry};
|
||||||
use common::download_dir;
|
use common::download_dir;
|
||||||
use community::{CommunityEvent, CommunityRegistry};
|
|
||||||
use community_ui::CommunityPanel;
|
|
||||||
use device::{DeviceEvent, DeviceRegistry};
|
use device::{DeviceEvent, DeviceRegistry};
|
||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
Action, AnyElement, App, AppContext, Context, Entity, InteractiveElement, IntoElement,
|
Action, AnyElement, App, AppContext, Context, Entity, InteractiveElement, IntoElement,
|
||||||
ParentElement, Render, SharedString, Styled, Subscription, Task, WeakEntity, Window, div, px,
|
ParentElement, Render, SharedString, Styled, Subscription, Task, Window, div, px,
|
||||||
};
|
};
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use person::{PersonRegistry, shorten_pubkey};
|
use person::{PersonRegistry, shorten_pubkey};
|
||||||
@@ -21,7 +19,7 @@ use smallvec::{SmallVec, smallvec};
|
|||||||
use state::{NostrRegistry, StateEvent};
|
use state::{NostrRegistry, StateEvent};
|
||||||
use theme::{ActiveTheme, SIDEBAR_WIDTH, Theme, ThemeRegistry};
|
use theme::{ActiveTheme, SIDEBAR_WIDTH, Theme, ThemeRegistry};
|
||||||
use ui::button::{Button, ButtonVariants};
|
use ui::button::{Button, ButtonVariants};
|
||||||
use ui::dock::{self, ClosePanel, DockArea, DockLayout, DockPlacement, Panel, PanelHandle};
|
use ui::dock::{self, DockArea, DockLayout, DockPlacement, Panel, PanelHandle};
|
||||||
use ui::menu::{DropdownMenu, PopupMenuItem};
|
use ui::menu::{DropdownMenu, PopupMenuItem};
|
||||||
use ui::notification::{Notification, NotificationKind};
|
use ui::notification::{Notification, NotificationKind};
|
||||||
use ui::{Icon, IconName, Root, Sizable, WindowExtension, h_flex, v_flex};
|
use ui::{Icon, IconName, Root, Sizable, WindowExtension, h_flex, v_flex};
|
||||||
@@ -72,8 +70,6 @@ enum Command {
|
|||||||
pub struct Workspace {
|
pub struct Workspace {
|
||||||
dock: Entity<DockArea>,
|
dock: Entity<DockArea>,
|
||||||
title_bar_chrome: Rc<dock::TitleBarChrome>,
|
title_bar_chrome: Rc<dock::TitleBarChrome>,
|
||||||
/// The community panel currently docked, if any
|
|
||||||
community_panel: Option<WeakEntity<CommunityPanel>>,
|
|
||||||
/// Async tasks
|
/// Async tasks
|
||||||
tasks: Vec<Task<Result<(), Error>>>,
|
tasks: Vec<Task<Result<(), Error>>>,
|
||||||
/// Event subscriptions
|
/// Event subscriptions
|
||||||
@@ -83,12 +79,11 @@ pub struct Workspace {
|
|||||||
impl Workspace {
|
impl Workspace {
|
||||||
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||||
let chat = ChatRegistry::global(cx);
|
let chat = ChatRegistry::global(cx);
|
||||||
let communities = CommunityRegistry::global(cx);
|
|
||||||
let device = DeviceRegistry::global(cx);
|
let device = DeviceRegistry::global(cx);
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
|
|
||||||
let sidebar = cx.new(|cx| Sidebar::new(window, cx));
|
|
||||||
let (dock, title_bar_chrome) = dock::dock_area("coop", window, cx);
|
let (dock, title_bar_chrome) = dock::dock_area("coop", window, cx);
|
||||||
|
let sidebar = cx.new(|cx| Sidebar::new(window, dock.downgrade(), cx));
|
||||||
|
|
||||||
let mut subscriptions = smallvec![];
|
let mut subscriptions = smallvec![];
|
||||||
|
|
||||||
@@ -164,7 +159,7 @@ impl Workspace {
|
|||||||
|
|
||||||
subscriptions.push(
|
subscriptions.push(
|
||||||
// Observe all events emitted by the chat registry
|
// Observe all events emitted by the chat registry
|
||||||
cx.subscribe_in(&chat, window, move |this, chat, ev, window, cx| {
|
cx.subscribe_in(&chat, window, move |_this, _chat, ev, window, cx| {
|
||||||
match ev {
|
match ev {
|
||||||
ChatEvent::InboxRelayNotFound => {
|
ChatEvent::InboxRelayNotFound => {
|
||||||
const MSG: &str = "Messaging Relays not found. Cannot receive messages.";
|
const MSG: &str = "Messaging Relays not found. Cannot receive messages.";
|
||||||
@@ -187,28 +182,6 @@ impl Workspace {
|
|||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ChatEvent::OpenRoom(id) => {
|
|
||||||
if let Some(room) = chat.read(cx).room(id, cx) {
|
|
||||||
this.add_panel_to_dock(
|
|
||||||
chat_ui::init(room, window, cx),
|
|
||||||
DockPlacement::Center,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ChatEvent::CloseRoom(..) => {
|
|
||||||
this.dock.update(cx, |area, cx| {
|
|
||||||
// Force focus to the tab panel
|
|
||||||
ui::dock::focus_tab_panel(area, window, cx);
|
|
||||||
|
|
||||||
// Dispatch the close panel action
|
|
||||||
cx.defer_in(window, |_, window, cx| {
|
|
||||||
window.dispatch_action(Box::new(ClosePanel), cx);
|
|
||||||
window.close_all_modals(cx);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ChatEvent::Error(error) => {
|
ChatEvent::Error(error) => {
|
||||||
window.push_notification(Notification::error(error).autohide(false), cx);
|
window.push_notification(Notification::error(error).autohide(false), cx);
|
||||||
}
|
}
|
||||||
@@ -217,71 +190,24 @@ impl Workspace {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
subscriptions.push(
|
|
||||||
// Observe all events emitted by the community registry
|
|
||||||
cx.subscribe_in(
|
|
||||||
&communities,
|
|
||||||
window,
|
|
||||||
move |this, communities, event, window, cx| match event {
|
|
||||||
CommunityEvent::Open(id) => {
|
|
||||||
if let Some(community) = communities.read(cx).community(id) {
|
|
||||||
let panel = community_ui::init(community, window, cx);
|
|
||||||
|
|
||||||
this.community_panel = Some(panel.downgrade());
|
|
||||||
this.add_panel_to_dock(panel, DockPlacement::Center, window, cx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CommunityEvent::Close(_) => {
|
|
||||||
let Some(panel) = this
|
|
||||||
.community_panel
|
|
||||||
.take()
|
|
||||||
.and_then(|panel| panel.upgrade())
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.dock.update(cx, |area, cx| {
|
|
||||||
ui::dock::add_panel(
|
|
||||||
area,
|
|
||||||
PanelHandle::new(panel),
|
|
||||||
DockPlacement::Center,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
ui::dock::focus_tab_panel(area, window, cx);
|
|
||||||
|
|
||||||
cx.defer_in(window, |_, window, cx| {
|
|
||||||
window.dispatch_action(Box::new(ClosePanel), cx);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
cx.defer_in(window, move |this, window, cx| {
|
cx.defer_in(window, move |this, window, cx| {
|
||||||
let sidebar = PanelHandle::new(sidebar);
|
let sidebar = PanelHandle::new(sidebar);
|
||||||
|
|
||||||
this.dock.update(cx, |area, cx| {
|
|
||||||
let left = DockLayout::tabs().panel_view(Arc::new(sidebar), cx);
|
|
||||||
area.set_dock(DockPlacement::Left, left, window, cx);
|
|
||||||
area.set_dock_size(DockPlacement::Left, SIDEBAR_WIDTH, window, cx);
|
|
||||||
});
|
|
||||||
|
|
||||||
let greeter = PanelHandle::new(greeter::init(window, cx));
|
let greeter = PanelHandle::new(greeter::init(window, cx));
|
||||||
let center = DockLayout::v_split()
|
|
||||||
.child(DockLayout::tabs().panel_view(Arc::new(greeter), cx), None);
|
|
||||||
|
|
||||||
this.dock.update(cx, |area, cx| {
|
this.dock.update(cx, |this, cx| {
|
||||||
area.set_center(center, window, cx);
|
let left = DockLayout::tabs().panel_view(Arc::new(sidebar), cx);
|
||||||
|
let center = DockLayout::v_split()
|
||||||
|
.child(DockLayout::tabs().panel_view(Arc::new(greeter), cx), None);
|
||||||
|
|
||||||
|
this.set_dock(DockPlacement::Left, left, window, cx);
|
||||||
|
this.set_dock_size(DockPlacement::Left, SIDEBAR_WIDTH, window, cx);
|
||||||
|
this.set_center(center, window, cx);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
dock,
|
dock,
|
||||||
title_bar_chrome,
|
title_bar_chrome,
|
||||||
community_panel: None,
|
|
||||||
tasks: vec![],
|
tasks: vec![],
|
||||||
_subscriptions: subscriptions,
|
_subscriptions: subscriptions,
|
||||||
}
|
}
|
||||||
@@ -365,10 +291,11 @@ impl Workspace {
|
|||||||
self.add_panel_to_dock(browse::init(window, cx), DockPlacement::Center, window, cx);
|
self.add_panel_to_dock(browse::init(window, cx), DockPlacement::Center, window, cx);
|
||||||
}
|
}
|
||||||
Command::ShowSearch => {
|
Command::ShowSearch => {
|
||||||
self.add_panel_to_dock(search::init(window, cx), DockPlacement::Center, window, cx);
|
let panel = search::init(self.dock.downgrade(), window, cx);
|
||||||
|
self.add_panel_to_dock(panel, DockPlacement::Center, window, cx);
|
||||||
}
|
}
|
||||||
Command::NewChat => {
|
Command::NewChat => {
|
||||||
new_chat::open(window, cx);
|
new_chat::open(self.dock.downgrade(), window, cx);
|
||||||
}
|
}
|
||||||
Command::NewCommunity => {
|
Command::NewCommunity => {
|
||||||
new_community::open(window, cx);
|
new_community::open(window, cx);
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ use common::DebouncedDelay;
|
|||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AnyElement, App, AppContext, Context, ElementId, Entity, EventEmitter, FocusHandle, Focusable,
|
AnyElement, App, AppContext, Context, ElementId, Entity, EventEmitter, FocusHandle, Focusable,
|
||||||
IntoElement, ParentElement, Render, SharedString, Styled, Subscription, Task, Window, div,
|
IntoElement, ParentElement, Render, SharedString, Styled, Subscription, Task, WeakEntity,
|
||||||
uniform_list,
|
Window, div, uniform_list,
|
||||||
};
|
};
|
||||||
use instant::Duration;
|
use instant::Duration;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
@@ -17,7 +17,7 @@ use smallvec::{SmallVec, smallvec};
|
|||||||
use state::{FIND_DELAY, NostrRegistry};
|
use state::{FIND_DELAY, NostrRegistry};
|
||||||
use theme::ActiveTheme;
|
use theme::ActiveTheme;
|
||||||
use ui::button::{Button, ButtonVariants};
|
use ui::button::{Button, ButtonVariants};
|
||||||
use ui::dock::{Panel, PanelEvent};
|
use ui::dock::{DockArea, DockPlacement, Panel, PanelEvent, PanelHandle};
|
||||||
use ui::input::{Input, InputEvent, InputState};
|
use ui::input::{Input, InputEvent, InputState};
|
||||||
use ui::notification::Notification;
|
use ui::notification::Notification;
|
||||||
use ui::{Icon, IconName, Selectable, Sizable, StyledExt, WindowExtension, h_flex, v_flex};
|
use ui::{Icon, IconName, Selectable, Sizable, StyledExt, WindowExtension, h_flex, v_flex};
|
||||||
@@ -26,13 +26,15 @@ use crate::sidebar::{TreeRow, TreeRowKind};
|
|||||||
|
|
||||||
const INPUT_PLACEHOLDER: &str = "Find or start a conversation";
|
const INPUT_PLACEHOLDER: &str = "Find or start a conversation";
|
||||||
|
|
||||||
pub fn init(window: &mut Window, cx: &mut App) -> Entity<SearchPanel> {
|
pub fn init(dock: WeakEntity<DockArea>, window: &mut Window, cx: &mut App) -> Entity<SearchPanel> {
|
||||||
cx.new(|cx| SearchPanel::new(window, cx))
|
cx.new(|cx| SearchPanel::new(dock, window, cx))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SearchPanel {
|
pub struct SearchPanel {
|
||||||
name: SharedString,
|
name: SharedString,
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
|
/// The dock a started chat opens in
|
||||||
|
dock: WeakEntity<DockArea>,
|
||||||
|
|
||||||
/// Find input state
|
/// Find input state
|
||||||
find_input: Entity<InputState>,
|
find_input: Entity<InputState>,
|
||||||
@@ -63,7 +65,7 @@ pub struct SearchPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SearchPanel {
|
impl SearchPanel {
|
||||||
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
fn new(dock: WeakEntity<DockArea>, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||||
let contact_list = cx.new(|_| None);
|
let contact_list = cx.new(|_| None);
|
||||||
let selected_pkeys = cx.new(|_| HashSet::new());
|
let selected_pkeys = cx.new(|_| HashSet::new());
|
||||||
let find_results = cx.new(|_| None);
|
let find_results = cx.new(|_| None);
|
||||||
@@ -107,6 +109,7 @@ impl SearchPanel {
|
|||||||
Self {
|
Self {
|
||||||
name: "Search".into(),
|
name: "Search".into(),
|
||||||
focus_handle: cx.focus_handle(),
|
focus_handle: cx.focus_handle(),
|
||||||
|
dock,
|
||||||
find_input,
|
find_input,
|
||||||
find_debouncer: DebouncedDelay::new(),
|
find_debouncer: DebouncedDelay::new(),
|
||||||
find_results,
|
find_results,
|
||||||
@@ -285,6 +288,7 @@ impl SearchPanel {
|
|||||||
fn create_room(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
fn create_room(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
let chat = ChatRegistry::global(cx);
|
let chat = ChatRegistry::global(cx);
|
||||||
let async_chat = chat.downgrade();
|
let async_chat = chat.downgrade();
|
||||||
|
let dock = self.dock.clone();
|
||||||
|
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
let Some(public_key) = nostr.read(cx).current_user() else {
|
let Some(public_key) = nostr.read(cx).current_user() else {
|
||||||
@@ -295,14 +299,26 @@ impl SearchPanel {
|
|||||||
let receivers = self.get_selected(cx);
|
let receivers = self.get_selected(cx);
|
||||||
|
|
||||||
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
|
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
|
||||||
// Create a new room and emit it
|
// Create a new room and register it
|
||||||
async_chat.update_in(cx, |this, _window, cx| {
|
let room = async_chat.update_in(cx, |chat, _window, cx| {
|
||||||
let room = cx.new(|_| {
|
let room = cx.new(|_| {
|
||||||
Room::new(public_key, receivers)
|
Room::new(public_key, receivers)
|
||||||
.organize(&public_key)
|
.organize(&public_key)
|
||||||
.kind(RoomKind::Ongoing)
|
.kind(RoomKind::Ongoing)
|
||||||
});
|
});
|
||||||
this.emit_room(&room, _window, cx);
|
chat.track_room(&room, cx);
|
||||||
|
room
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Open it in the dock
|
||||||
|
cx.update(|window, cx| {
|
||||||
|
ui::dock::add_panel_to(
|
||||||
|
&dock,
|
||||||
|
PanelHandle::new(chat_ui::init(room.downgrade(), window, cx)),
|
||||||
|
DockPlacement::Center,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Reset the find panel
|
// Reset the find panel
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::ops::Range;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use auto_update::AutoUpdater;
|
use auto_update::AutoUpdater;
|
||||||
use chat::{ChatEvent, ChatRegistry, RoomKind};
|
use chat::{ChatEvent, ChatRegistry, Room, RoomKind};
|
||||||
use common::TimestampExt;
|
use common::TimestampExt;
|
||||||
use community::{ChannelId, Community, CommunityEvent, CommunityRegistry};
|
use community::{ChannelId, Community, CommunityEvent, CommunityRegistry};
|
||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
@@ -20,7 +20,7 @@ use state::NostrRegistry;
|
|||||||
use theme::{ActiveTheme, TABBAR_HEIGHT};
|
use theme::{ActiveTheme, TABBAR_HEIGHT};
|
||||||
use ui::avatar::Avatar;
|
use ui::avatar::Avatar;
|
||||||
use ui::button::{Button, ButtonVariants};
|
use ui::button::{Button, ButtonVariants};
|
||||||
use ui::dock::{Panel, PanelEvent};
|
use ui::dock::{DockArea, DockPlacement, Panel, PanelEvent, PanelHandle};
|
||||||
use ui::indicator::Indicator;
|
use ui::indicator::Indicator;
|
||||||
use ui::menu::{DropdownMenu, PopupMenuItem};
|
use ui::menu::{DropdownMenu, PopupMenuItem};
|
||||||
use ui::nav_item::NavItem;
|
use ui::nav_item::NavItem;
|
||||||
@@ -46,6 +46,8 @@ pub struct Sidebar {
|
|||||||
scroll_handles: [UniformListScrollHandle; 3],
|
scroll_handles: [UniformListScrollHandle; 3],
|
||||||
/// Scroll state of the channel and member lists
|
/// Scroll state of the channel and member lists
|
||||||
community_scroll: ScrollHandle,
|
community_scroll: ScrollHandle,
|
||||||
|
/// The dock the sidebar opens its panels in
|
||||||
|
dock: WeakEntity<DockArea>,
|
||||||
active_tab: SidebarTab,
|
active_tab: SidebarTab,
|
||||||
/// The community the sidebar is browsing, if any
|
/// The community the sidebar is browsing, if any
|
||||||
community: Option<WeakEntity<Community>>,
|
community: Option<WeakEntity<Community>>,
|
||||||
@@ -59,7 +61,7 @@ pub struct Sidebar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Sidebar {
|
impl Sidebar {
|
||||||
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
pub fn new(window: &mut Window, dock: WeakEntity<DockArea>, cx: &mut Context<Self>) -> Self {
|
||||||
let chat = ChatRegistry::global(cx);
|
let chat = ChatRegistry::global(cx);
|
||||||
let communities = CommunityRegistry::global(cx);
|
let communities = CommunityRegistry::global(cx);
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
@@ -98,6 +100,7 @@ impl Sidebar {
|
|||||||
UniformListScrollHandle::new(),
|
UniformListScrollHandle::new(),
|
||||||
],
|
],
|
||||||
community_scroll: ScrollHandle::default(),
|
community_scroll: ScrollHandle::default(),
|
||||||
|
dock,
|
||||||
active_tab: SidebarTab::Recents,
|
active_tab: SidebarTab::Recents,
|
||||||
community: None,
|
community: None,
|
||||||
channels_open: true,
|
channels_open: true,
|
||||||
@@ -130,25 +133,34 @@ impl Sidebar {
|
|||||||
settings.record_recent_community(id, cx);
|
settings.record_recent_community(id, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
CommunityRegistry::global(cx).update(cx, |registry, cx| {
|
|
||||||
registry.emit_community(&community, window, cx);
|
|
||||||
});
|
|
||||||
|
|
||||||
self.community = Some(community.downgrade());
|
self.community = Some(community.downgrade());
|
||||||
|
|
||||||
|
ui::dock::add_panel_to(
|
||||||
|
&self.dock,
|
||||||
|
PanelHandle::new(community_ui::init(community, window, cx)),
|
||||||
|
DockPlacement::Center,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_community(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
fn open_room(&mut self, room: Entity<Room>, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
let Some(community) = self.community.take() else {
|
ui::dock::add_panel_to(
|
||||||
|
&self.dock,
|
||||||
|
PanelHandle::new(chat_ui::init(room.downgrade(), window, cx)),
|
||||||
|
DockPlacement::Center,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Leave the community view, returning the sidebar to its tab list.
|
||||||
|
fn reset_community(&mut self, cx: &mut Context<Self>) {
|
||||||
|
if self.community.take().is_none() {
|
||||||
return;
|
return;
|
||||||
};
|
|
||||||
|
|
||||||
if let Ok(id) = community.read_with(cx, |community, _cx| community.id()) {
|
|
||||||
CommunityRegistry::global(cx).update(cx, |registry, cx| {
|
|
||||||
registry.emit_close(id, window, cx);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,8 +262,8 @@ impl Sidebar {
|
|||||||
.tooltip("Back")
|
.tooltip("Back")
|
||||||
.ghost()
|
.ghost()
|
||||||
.small()
|
.small()
|
||||||
.on_click(cx.listener(|this, _event, window, cx| {
|
.on_click(cx.listener(|this, _event, _window, cx| {
|
||||||
this.close_community(window, cx);
|
this.reset_community(cx);
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -407,10 +419,8 @@ fn render_rows(range: Range<usize>, rows: &[SidebarRow], cx: &Context<Sidebar>)
|
|||||||
let created_at = room.read(cx).created_at.to_ago();
|
let created_at = room.read(cx).created_at.to_ago();
|
||||||
let room_clone = room.clone();
|
let room_clone = room.clone();
|
||||||
|
|
||||||
let handler = cx.listener(move |_this, _event, window, cx| {
|
let handler = cx.listener(move |this, _event, window, cx| {
|
||||||
ChatRegistry::global(cx).update(cx, |chat, cx| {
|
this.open_room(room_clone.clone(), window, cx);
|
||||||
chat.emit_room(&room_clone, window, cx);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
TreeRow::new(
|
TreeRow::new(
|
||||||
|
|||||||
Reference in New Issue
Block a user