update sidebar for onboarding
This commit is contained in:
+25
-1
@@ -87,6 +87,9 @@ pub struct NostrRegistry {
|
|||||||
/// Current user's public key
|
/// Current user's public key
|
||||||
current_user: Option<PublicKey>,
|
current_user: Option<PublicKey>,
|
||||||
|
|
||||||
|
/// Whether the initial credential check has concluded
|
||||||
|
ready: bool,
|
||||||
|
|
||||||
/// Tasks for asynchronous operations
|
/// Tasks for asynchronous operations
|
||||||
tasks: Vec<Task<Result<(), Error>>>,
|
tasks: Vec<Task<Result<(), Error>>>,
|
||||||
}
|
}
|
||||||
@@ -140,6 +143,7 @@ impl NostrRegistry {
|
|||||||
this.connect_bootstrap_relays(cx);
|
this.connect_bootstrap_relays(cx);
|
||||||
|
|
||||||
if cfg!(target_arch = "wasm32") {
|
if cfg!(target_arch = "wasm32") {
|
||||||
|
this.mark_ready(cx);
|
||||||
cx.emit(StateEvent::NoSigner);
|
cx.emit(StateEvent::NoSigner);
|
||||||
} else if let Some(secret) = cli_key {
|
} else if let Some(secret) = cli_key {
|
||||||
// Use CLI-provided key -- same path as get_user_credential
|
// Use CLI-provided key -- same path as get_user_credential
|
||||||
@@ -156,6 +160,7 @@ impl NostrRegistry {
|
|||||||
client,
|
client,
|
||||||
signer,
|
signer,
|
||||||
current_user: None,
|
current_user: None,
|
||||||
|
ready: false,
|
||||||
tasks: vec![],
|
tasks: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,6 +180,20 @@ impl NostrRegistry {
|
|||||||
self.current_user
|
self.current_user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the initial credential check has concluded
|
||||||
|
pub fn ready(&self) -> bool {
|
||||||
|
self.ready
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_ready(&mut self, cx: &mut Context<Self>) {
|
||||||
|
if self.ready {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ready = true;
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
|
||||||
/// Update the signer
|
/// Update the signer
|
||||||
pub fn set_signer<T>(&mut self, new_signer: T, cx: &mut Context<Self>)
|
pub fn set_signer<T>(&mut self, new_signer: T, cx: &mut Context<Self>)
|
||||||
where
|
where
|
||||||
@@ -189,6 +208,7 @@ impl NostrRegistry {
|
|||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
this.signer.swap_inner(new_signer);
|
this.signer.swap_inner(new_signer);
|
||||||
this.current_user = Some(public_key);
|
this.current_user = Some(public_key);
|
||||||
|
this.mark_ready(cx);
|
||||||
cx.emit(StateEvent::SignerChanged);
|
cx.emit(StateEvent::SignerChanged);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
})?;
|
})?;
|
||||||
@@ -275,12 +295,16 @@ impl NostrRegistry {
|
|||||||
} else if content == "proxy" {
|
} else if content == "proxy" {
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
|
this.mark_ready(cx);
|
||||||
this.connect_proxy(cx);
|
this.connect_proxy(cx);
|
||||||
})?;
|
})?;
|
||||||
|
} else {
|
||||||
|
this.update(cx, |this, cx| this.mark_ready(cx))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
this.update(cx, |_, cx| {
|
this.update(cx, |this, cx| {
|
||||||
|
this.mark_ready(cx);
|
||||||
cx.emit(StateEvent::NoSigner);
|
cx.emit(StateEvent::NoSigner);
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use anyhow::{Error, anyhow};
|
use anyhow::{Error, anyhow};
|
||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AppContext, Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled,
|
App, AppContext, Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled,
|
||||||
Subscription, Task, Window, div,
|
Subscription, Task, Window, div, px,
|
||||||
};
|
};
|
||||||
use instant::Duration;
|
use instant::Duration;
|
||||||
use nostr_connect::prelude::*;
|
use nostr_connect::prelude::*;
|
||||||
@@ -12,6 +12,19 @@ use ui::button::{Button, ButtonVariants};
|
|||||||
use ui::input::{Input, InputEvent, InputState};
|
use ui::input::{Input, InputEvent, InputState};
|
||||||
use ui::{Disableable, StyledExt, WindowExtension, divider, v_flex};
|
use ui::{Disableable, StyledExt, WindowExtension, divider, v_flex};
|
||||||
|
|
||||||
|
pub fn open(window: &mut Window, cx: &mut App) {
|
||||||
|
let import = cx.new(|cx| ImportIdentity::new(window, cx));
|
||||||
|
|
||||||
|
window.open_modal(cx, move |this, _window, _cx| {
|
||||||
|
this.width(px(450.))
|
||||||
|
.show_close(false)
|
||||||
|
.overlay_closable(false)
|
||||||
|
.keyboard(false)
|
||||||
|
.title("Onboarding")
|
||||||
|
.child(import.clone())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ImportIdentity {
|
pub struct ImportIdentity {
|
||||||
/// Secret key input
|
/// Secret key input
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ 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};
|
||||||
|
|
||||||
use crate::dialogs::import::ImportIdentity;
|
|
||||||
use crate::dialogs::restore::RestoreEncryption;
|
use crate::dialogs::restore::RestoreEncryption;
|
||||||
use crate::dialogs::{new_chat, new_community, settings};
|
use crate::dialogs::{new_chat, new_community, settings};
|
||||||
use crate::panels::{
|
use crate::panels::{
|
||||||
@@ -97,16 +96,10 @@ impl Workspace {
|
|||||||
|
|
||||||
subscriptions.push(
|
subscriptions.push(
|
||||||
// Subscribe to the nostr events
|
// Subscribe to the nostr events
|
||||||
cx.subscribe_in(&nostr, window, move |this, _state, event, window, cx| {
|
cx.subscribe_in(&nostr, window, move |_this, _state, event, window, cx| {
|
||||||
match event {
|
if let StateEvent::SignerChanged = event {
|
||||||
StateEvent::SignerChanged => {
|
window.close_all_modals(cx);
|
||||||
window.close_all_modals(cx);
|
}
|
||||||
}
|
|
||||||
StateEvent::NoSigner => {
|
|
||||||
this.import_identity(window, cx);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -463,19 +456,6 @@ impl Workspace {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_identity(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
|
||||||
let import = cx.new(|cx| ImportIdentity::new(window, cx));
|
|
||||||
|
|
||||||
window.open_modal(cx, move |this, _window, _cx| {
|
|
||||||
this.width(px(450.))
|
|
||||||
.show_close(false)
|
|
||||||
.overlay_closable(false)
|
|
||||||
.keyboard(false)
|
|
||||||
.title("Onboarding")
|
|
||||||
.child(import.clone())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn theme_selector(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
fn theme_selector(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
window.open_modal(cx, move |this, _window, cx| {
|
window.open_modal(cx, move |this, _window, cx| {
|
||||||
let registry = ThemeRegistry::global(cx);
|
let registry = ThemeRegistry::global(cx);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ use ui::{
|
|||||||
|
|
||||||
use crate::Command;
|
use crate::Command;
|
||||||
|
|
||||||
|
mod onboarding;
|
||||||
mod tab;
|
mod tab;
|
||||||
mod tree;
|
mod tree;
|
||||||
|
|
||||||
@@ -44,13 +45,14 @@ pub struct Sidebar {
|
|||||||
active_tab: SidebarTab,
|
active_tab: SidebarTab,
|
||||||
/// Whether there are new chat requests
|
/// Whether there are new chat requests
|
||||||
new_requests: bool,
|
new_requests: bool,
|
||||||
_subscriptions: SmallVec<[Subscription; 2]>,
|
_subscriptions: SmallVec<[Subscription; 3]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sidebar {
|
impl Sidebar {
|
||||||
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
pub 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 communities = CommunityRegistry::global(cx);
|
||||||
|
let nostr = NostrRegistry::global(cx);
|
||||||
|
|
||||||
let mut subscriptions = smallvec![];
|
let mut subscriptions = smallvec![];
|
||||||
|
|
||||||
@@ -74,6 +76,8 @@ impl Sidebar {
|
|||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
|
subscriptions.push(cx.observe(&nostr, |_this, _nostr, cx| cx.notify()));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
focus_handle: cx.focus_handle(),
|
focus_handle: cx.focus_handle(),
|
||||||
scroll_handles: [
|
scroll_handles: [
|
||||||
@@ -441,10 +445,26 @@ impl Focusable for Sidebar {
|
|||||||
impl Render for Sidebar {
|
impl Render for Sidebar {
|
||||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
let logged_in = nostr.read(cx).current_user().is_some();
|
let (logged_in, ready) = {
|
||||||
|
let nostr = nostr.read(cx);
|
||||||
|
(nostr.current_user().is_some(), nostr.ready())
|
||||||
|
};
|
||||||
|
|
||||||
|
if !logged_in {
|
||||||
|
if !ready {
|
||||||
|
return v_flex()
|
||||||
|
.size_full()
|
||||||
|
.bg(cx.theme().surface_background)
|
||||||
|
.border_r_1()
|
||||||
|
.border_color(cx.theme().border_variant)
|
||||||
|
.into_any_element();
|
||||||
|
}
|
||||||
|
|
||||||
|
return onboarding::render(window, cx).into_any_element();
|
||||||
|
}
|
||||||
|
|
||||||
let chat = ChatRegistry::global(cx);
|
let chat = ChatRegistry::global(cx);
|
||||||
let loading = chat.read(cx).loading() && logged_in;
|
let loading = chat.read(cx).loading();
|
||||||
|
|
||||||
let sidebar = cx.entity().downgrade();
|
let sidebar = cx.entity().downgrade();
|
||||||
let active_tab = self.active_tab;
|
let active_tab = self.active_tab;
|
||||||
@@ -592,5 +612,6 @@ impl Render for Sidebar {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
.into_any_element()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
use gpui::{App, InteractiveElement, IntoElement, ParentElement, Styled, Window, div, svg};
|
||||||
|
use theme::{ActiveTheme, TABBAR_HEIGHT};
|
||||||
|
use ui::button::{Button, ButtonVariants};
|
||||||
|
use ui::{StyledExt, h_flex, title_bar_drag_handlers, v_flex};
|
||||||
|
|
||||||
|
use crate::dialogs::import;
|
||||||
|
|
||||||
|
const TITLE: &str = "Welcome to Coop!";
|
||||||
|
const DESCRIPTION: &str = "Chat Freely, Stay Private on Nostr.";
|
||||||
|
|
||||||
|
pub(super) fn render(window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
|
v_flex()
|
||||||
|
.size_full()
|
||||||
|
.relative()
|
||||||
|
.bg(cx.theme().surface_background)
|
||||||
|
.child(title_bar_drag_handlers(
|
||||||
|
div()
|
||||||
|
.id("onboarding-drag")
|
||||||
|
.absolute()
|
||||||
|
.top_0()
|
||||||
|
.left_0()
|
||||||
|
.h(TABBAR_HEIGHT)
|
||||||
|
.w_full(),
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
))
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.size_full()
|
||||||
|
.justify_end()
|
||||||
|
.gap_4()
|
||||||
|
.p_4()
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.gap_2()
|
||||||
|
.child(
|
||||||
|
svg()
|
||||||
|
.path("brand/coop.svg")
|
||||||
|
.size_8()
|
||||||
|
.text_color(cx.theme().icon_muted),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
v_flex().child(div().font_semibold().child(TITLE)).child(
|
||||||
|
div()
|
||||||
|
.text_xs()
|
||||||
|
.text_color(cx.theme().text_muted)
|
||||||
|
.child(DESCRIPTION),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.gap_2()
|
||||||
|
.w_full()
|
||||||
|
.child(
|
||||||
|
Button::new("join-now")
|
||||||
|
.label("Join now")
|
||||||
|
.primary()
|
||||||
|
.font_semibold()
|
||||||
|
.h_8()
|
||||||
|
.w_full(),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Button::new("import-identity")
|
||||||
|
.label("Import identity")
|
||||||
|
.secondary()
|
||||||
|
.font_semibold()
|
||||||
|
.h_8()
|
||||||
|
.w_full()
|
||||||
|
.on_click(|_event, window, cx| import::open(window, cx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -48,10 +48,6 @@ impl SidebarTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recents(self) -> bool {
|
|
||||||
matches!(self, Self::Recents)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn chat(self) -> bool {
|
pub fn chat(self) -> bool {
|
||||||
matches!(self, Self::Chats)
|
matches!(self, Self::Chats)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user