218 lines
6.7 KiB
Rust
218 lines
6.7 KiB
Rust
use super::{chat::ChatPanel, onboarding::Onboarding, sidebar::Sidebar, welcome::WelcomePanel};
|
|
use app_state::registry::AppRegistry;
|
|
use chat::registry::ChatRegistry;
|
|
use common::profile::NostrProfile;
|
|
use gpui::{
|
|
actions, div, img, impl_internal_actions, px, AppContext, Axis, BorrowAppContext, Context,
|
|
Edges, Entity, InteractiveElement, IntoElement, ObjectFit, ParentElement, Render, Styled,
|
|
StyledImage, Window,
|
|
};
|
|
use serde::Deserialize;
|
|
use state::get_client;
|
|
use std::sync::Arc;
|
|
use ui::{
|
|
button::{Button, ButtonVariants},
|
|
dock_area::{dock::DockPlacement, DockArea, DockItem},
|
|
notification::NotificationType,
|
|
popup_menu::PopupMenuExt,
|
|
ContextModal, Icon, IconName, Root, Sizable, TitleBar,
|
|
};
|
|
|
|
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
|
pub enum PanelKind {
|
|
Room(u64),
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
|
pub struct AddPanel {
|
|
pub panel: PanelKind,
|
|
pub position: DockPlacement,
|
|
}
|
|
|
|
// Dock actions
|
|
impl_internal_actions!(dock, [AddPanel]);
|
|
// Account actions
|
|
actions!(account, [OpenProfile, OpenContacts, OpenSettings, Logout]);
|
|
|
|
pub struct DockAreaTab {
|
|
id: &'static str,
|
|
version: usize,
|
|
}
|
|
|
|
pub const DOCK_AREA: DockAreaTab = DockAreaTab {
|
|
id: "dock",
|
|
version: 1,
|
|
};
|
|
|
|
pub struct AppView {
|
|
account: NostrProfile,
|
|
dock: Entity<DockArea>,
|
|
}
|
|
|
|
impl AppView {
|
|
pub fn new(account: NostrProfile, window: &mut Window, cx: &mut Context<'_, Self>) -> AppView {
|
|
let dock = cx.new(|cx| DockArea::new(DOCK_AREA.id, Some(DOCK_AREA.version), window, cx));
|
|
let weak_dock = dock.downgrade();
|
|
|
|
let left = DockItem::panel(Arc::new(Sidebar::new(window, cx)));
|
|
let center = DockItem::split_with_sizes(
|
|
Axis::Vertical,
|
|
vec![DockItem::tabs(
|
|
vec![Arc::new(WelcomePanel::new(window, cx))],
|
|
None,
|
|
&weak_dock,
|
|
window,
|
|
cx,
|
|
)],
|
|
vec![None],
|
|
&weak_dock,
|
|
window,
|
|
cx,
|
|
);
|
|
|
|
_ = weak_dock.update(cx, |view, cx| {
|
|
view.set_version(DOCK_AREA.version, window, cx);
|
|
view.set_left_dock(left, Some(px(240.)), true, window, cx);
|
|
view.set_center(center, window, cx);
|
|
view.set_dock_collapsible(
|
|
Edges {
|
|
left: false,
|
|
..Default::default()
|
|
},
|
|
window,
|
|
cx,
|
|
);
|
|
// TODO: support right dock?
|
|
// TODO: support bottom dock?
|
|
});
|
|
|
|
AppView { account, dock }
|
|
}
|
|
|
|
fn render_account(&self) -> impl IntoElement {
|
|
Button::new("account")
|
|
.ghost()
|
|
.xsmall()
|
|
.reverse()
|
|
.icon(Icon::new(IconName::ChevronDownSmall))
|
|
.child(
|
|
img(self.account.avatar())
|
|
.size_5()
|
|
.rounded_full()
|
|
.object_fit(ObjectFit::Cover),
|
|
)
|
|
.popup_menu(move |this, _, _cx| {
|
|
this.menu("Profile", Box::new(OpenProfile))
|
|
.menu("Contacts", Box::new(OpenContacts))
|
|
.menu("Settings", Box::new(OpenSettings))
|
|
.separator()
|
|
.menu("Change account", Box::new(Logout))
|
|
})
|
|
}
|
|
|
|
fn on_panel_action(&mut self, action: &AddPanel, window: &mut Window, cx: &mut Context<Self>) {
|
|
match &action.panel {
|
|
PanelKind::Room(id) => {
|
|
if let Some(weak_room) = cx.global::<ChatRegistry>().get_room(id, cx) {
|
|
if let Some(room) = weak_room.upgrade() {
|
|
let panel = Arc::new(ChatPanel::new(room, window, cx));
|
|
self.dock.update(cx, |dock_area, cx| {
|
|
dock_area.add_panel(panel, action.position, window, cx);
|
|
});
|
|
} else {
|
|
window.push_notification(
|
|
(
|
|
NotificationType::Error,
|
|
"System error. Cannot open this chat room.",
|
|
),
|
|
cx,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
fn on_profile_action(
|
|
&mut self,
|
|
_action: &OpenProfile,
|
|
_window: &mut Window,
|
|
_cx: &mut Context<Self>,
|
|
) {
|
|
// TODO
|
|
}
|
|
|
|
fn on_contacts_action(
|
|
&mut self,
|
|
_action: &OpenContacts,
|
|
_window: &mut Window,
|
|
_cx: &mut Context<Self>,
|
|
) {
|
|
// TODO
|
|
}
|
|
|
|
fn on_settings_action(
|
|
&mut self,
|
|
_action: &OpenSettings,
|
|
_window: &mut Window,
|
|
_cx: &mut Context<Self>,
|
|
) {
|
|
// TODO
|
|
}
|
|
|
|
fn on_logout_action(&mut self, _action: &Logout, window: &mut Window, cx: &mut Context<Self>) {
|
|
cx.update_global::<AppRegistry, _>(|this, cx| {
|
|
cx.background_executor()
|
|
.spawn(async move { get_client().reset().await })
|
|
.detach();
|
|
|
|
// Remove user
|
|
this.set_user(None);
|
|
|
|
// Update root view
|
|
if let Some(root) = this.root() {
|
|
cx.update_entity(&root, |this: &mut Root, cx| {
|
|
this.set_view(cx.new(|cx| Onboarding::new(window, cx)).into(), cx);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
impl Render for AppView {
|
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
let modal_layer = Root::render_modal_layer(window, cx);
|
|
let notification_layer = Root::render_notification_layer(window, cx);
|
|
|
|
div()
|
|
.relative()
|
|
.size_full()
|
|
.flex()
|
|
.flex_col()
|
|
// Main
|
|
.child(
|
|
TitleBar::new()
|
|
// Left side
|
|
.child(div())
|
|
// Right side
|
|
.child(
|
|
div()
|
|
.flex()
|
|
.items_center()
|
|
.justify_end()
|
|
.gap_1()
|
|
.px_2()
|
|
.child(self.render_account()),
|
|
),
|
|
)
|
|
.child(self.dock.clone())
|
|
.child(div().absolute().top_8().children(notification_layer))
|
|
.children(modal_layer)
|
|
.on_action(cx.listener(Self::on_panel_action))
|
|
.on_action(cx.listener(Self::on_logout_action))
|
|
.on_action(cx.listener(Self::on_profile_action))
|
|
.on_action(cx.listener(Self::on_contacts_action))
|
|
.on_action(cx.listener(Self::on_settings_action))
|
|
}
|
|
}
|