chore: refactor dialogs to render custom footer buttons
This commit is contained in:
@@ -10,7 +10,7 @@ use state::{CoopAuthUrlHandler, NostrRegistry, USER_KEYRING};
|
||||
use theme::ActiveTheme;
|
||||
use ui::button::{Button, ButtonVariants};
|
||||
use ui::input::{Input, InputEvent, InputState};
|
||||
use ui::{Disableable, StyledExt, WindowExtension, divider, v_flex};
|
||||
use ui::{Disableable, StyledExt, WindowExtension, v_flex};
|
||||
|
||||
pub fn open(window: &mut Window, cx: &mut App) {
|
||||
let import = cx.new(|cx| ImportIdentity::new(window, cx));
|
||||
@@ -20,7 +20,7 @@ pub fn open(window: &mut Window, cx: &mut App) {
|
||||
.show_close(false)
|
||||
.overlay_closable(false)
|
||||
.keyboard(false)
|
||||
.title("Get Started")
|
||||
.title("Continue with your Nostr Identity")
|
||||
.child(import.clone())
|
||||
});
|
||||
}
|
||||
@@ -29,20 +29,13 @@ pub fn open(window: &mut Window, cx: &mut App) {
|
||||
pub struct ImportIdentity {
|
||||
/// Secret key input
|
||||
key_input: Entity<InputState>,
|
||||
|
||||
/// Password input (if required)
|
||||
pass_input: Entity<InputState>,
|
||||
|
||||
/// Error message
|
||||
error: Entity<Option<SharedString>>,
|
||||
|
||||
/// Whether the user is currently loading
|
||||
loading: bool,
|
||||
|
||||
/// Async tasks
|
||||
tasks: Vec<Task<Result<(), Error>>>,
|
||||
|
||||
/// Input subscription
|
||||
_subscription: Option<Subscription>,
|
||||
}
|
||||
|
||||
@@ -230,7 +223,7 @@ impl Render for ImportIdentity {
|
||||
|
||||
v_flex()
|
||||
.size_full()
|
||||
.gap_4()
|
||||
.gap_2()
|
||||
.text_sm()
|
||||
.child(
|
||||
v_flex()
|
||||
@@ -279,12 +272,11 @@ impl Render for ImportIdentity {
|
||||
this.login(window, cx);
|
||||
})),
|
||||
)
|
||||
.child(divider(cx))
|
||||
.when(!is_wasm, |this| {
|
||||
this.child(
|
||||
Button::new("proxy")
|
||||
.label("Connect via Web Extension (Experimental)")
|
||||
.ghost_alt()
|
||||
.ghost()
|
||||
.loading(self.loading)
|
||||
.disabled(self.loading)
|
||||
.on_click(cx.listener(move |this, _ev, _window, cx| {
|
||||
|
||||
@@ -1,35 +1,75 @@
|
||||
use gpui::{App, AppContext, ParentElement, Styled, Window, px};
|
||||
use std::rc::Rc;
|
||||
|
||||
use gpui::{App, AppContext, ClickEvent, ParentElement, Styled, Window, px};
|
||||
use nip29::{GroupReference, GroupsRegistry};
|
||||
use ui::WindowExtension;
|
||||
use ui::button::{Button, ButtonVariants};
|
||||
use ui::input::{Input, InputState};
|
||||
use ui::notification::Notification;
|
||||
use ui::{IconName, StyledExt, WindowExtension, h_flex, v_flex};
|
||||
|
||||
type SubmitFn = Rc<dyn Fn(&ClickEvent, &mut Window, &mut App) -> bool>;
|
||||
|
||||
pub fn open(window: &mut Window, cx: &mut App) {
|
||||
let input = cx.new(|cx| InputState::new(window, cx).placeholder("naddr1…"));
|
||||
|
||||
window.open_dialog(cx, move |this, _window, _cx| {
|
||||
let join: SubmitFn = {
|
||||
let input = input.clone();
|
||||
Rc::new(move |_, window, cx| {
|
||||
let groups = GroupsRegistry::global(cx);
|
||||
|
||||
let reference = match GroupReference::parse(input.read(cx).value().trim()) {
|
||||
Ok(reference) => reference,
|
||||
Err(error) => {
|
||||
window.push_notification(Notification::error(error.to_string()), cx);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
groups.update(cx, |registry, cx| {
|
||||
registry.join(reference, cx);
|
||||
});
|
||||
|
||||
true
|
||||
})
|
||||
};
|
||||
|
||||
window.open_dialog(cx, move |this, _window, _cx| {
|
||||
this.width(px(380.))
|
||||
.confirm()
|
||||
.title("Join Group")
|
||||
.child(Input::new(&input).cleanable(true).flex_1().text_sm())
|
||||
.on_ok(move |_event, window, cx| {
|
||||
let groups = GroupsRegistry::global(cx);
|
||||
|
||||
let reference = match GroupReference::parse(input.read(cx).value().trim()) {
|
||||
Ok(reference) => reference,
|
||||
Err(error) => {
|
||||
window.push_notification(Notification::error(error.to_string()), cx);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
groups.update(cx, |registry, cx| {
|
||||
registry.join(reference, cx);
|
||||
});
|
||||
|
||||
true
|
||||
.on_ok({
|
||||
let join = join.clone();
|
||||
move |event, window, cx| join(event, window, cx)
|
||||
})
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_3()
|
||||
.child(Input::new(&input).cleanable(true).text_sm())
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.justify_end()
|
||||
.child(
|
||||
Button::new("cancel")
|
||||
.label("Cancel")
|
||||
.ghost()
|
||||
.on_click(|_, window, cx| window.close_dialog(cx)),
|
||||
)
|
||||
.child(
|
||||
Button::new("join")
|
||||
.icon(IconName::CheckCircle)
|
||||
.label("Join")
|
||||
.primary()
|
||||
.font_semibold()
|
||||
.on_click({
|
||||
let join = join.clone();
|
||||
move |event, window, cx| {
|
||||
if join(event, window, cx) {
|
||||
window.close_dialog(cx);
|
||||
}
|
||||
}
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,11 +16,10 @@ use state::NostrRegistry;
|
||||
use theme::ActiveTheme;
|
||||
use ui::avatar::Avatar;
|
||||
use ui::button::{Button, ButtonVariants};
|
||||
use ui::dialog::DialogButtonProps;
|
||||
use ui::dock::{DockArea, DockPlacement, PanelHandle};
|
||||
use ui::input::{Input, InputEvent, InputState};
|
||||
use ui::nav::Nav;
|
||||
use ui::{Disableable, IconName, Sizable, WindowExtension, h_flex, v_flex};
|
||||
use ui::{Disableable, IconName, Sizable, StyledExt, WindowExtension, h_flex, v_flex};
|
||||
|
||||
/// Maximum number of members a chat can have.
|
||||
const MAX_MEMBERS: usize = 3;
|
||||
@@ -30,21 +29,7 @@ pub fn open(dock: WeakEntity<DockArea>, window: &mut Window, cx: &mut App) {
|
||||
|
||||
window.open_dialog(cx, {
|
||||
let view = view.clone();
|
||||
move |this, _window, _cx| {
|
||||
this.width(px(420.))
|
||||
.title("New chat")
|
||||
.confirm()
|
||||
.button_props(
|
||||
DialogButtonProps::default()
|
||||
.cancel_text("Cancel")
|
||||
.ok_text("Start"),
|
||||
)
|
||||
.on_ok({
|
||||
let view = view.clone();
|
||||
move |_, window, cx| view.update(cx, |this, cx| this.start_chat(window, cx))
|
||||
})
|
||||
.child(view.clone())
|
||||
}
|
||||
move |this, _window, _cx| this.width(px(420.)).title("New chat").child(view.clone())
|
||||
});
|
||||
}
|
||||
|
||||
@@ -452,5 +437,28 @@ impl Render for NewChat {
|
||||
)
|
||||
.h_80(),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.justify_end()
|
||||
.child(
|
||||
Button::new("cancel")
|
||||
.label("Cancel")
|
||||
.ghost()
|
||||
.on_click(|_, window, cx| window.close_dialog(cx)),
|
||||
)
|
||||
.child(
|
||||
Button::new("start")
|
||||
.icon(IconName::CheckCircle)
|
||||
.label("Start")
|
||||
.primary()
|
||||
.font_semibold()
|
||||
.on_click(cx.listener(move |this, _event, window, cx| {
|
||||
if this.start_chat(window, cx) {
|
||||
window.close_dialog(cx);
|
||||
}
|
||||
})),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,33 @@
|
||||
use gpui::{App, AppContext, Div, Entity, ParentElement, Styled, Window, px};
|
||||
use std::rc::Rc;
|
||||
|
||||
use gpui::{App, AppContext, ClickEvent, Div, Entity, ParentElement, Styled, Window, px};
|
||||
use nip29::{GroupId, GroupKey, GroupMetadata, GroupsRegistry};
|
||||
use nostr_sdk::prelude::*;
|
||||
use theme::ActiveTheme;
|
||||
use ui::button::{Button, ButtonVariants};
|
||||
use ui::input::{Input, InputState};
|
||||
use ui::notification::Notification;
|
||||
use ui::{WindowExtension, v_flex};
|
||||
use ui::{IconName, StyledExt, WindowExtension, h_flex, v_flex};
|
||||
|
||||
type SubmitFn = Rc<dyn Fn(&ClickEvent, &mut Window, &mut App) -> bool>;
|
||||
|
||||
pub fn open(window: &mut Window, cx: &mut App) {
|
||||
let name = cx.new(|cx| InputState::new(window, cx).placeholder("Group name"));
|
||||
let id = cx.new(|cx| InputState::new(window, cx).placeholder("Group id"));
|
||||
let relay = cx.new(|cx| InputState::new(window, cx).placeholder("wss://relay.example.com"));
|
||||
|
||||
window.open_dialog(cx, move |this, _window, cx| {
|
||||
let name = name.clone();
|
||||
let id = id.clone();
|
||||
let relay = relay.clone();
|
||||
let submit: SubmitFn = {
|
||||
let (name, id, relay) = (name.clone(), id.clone(), relay.clone());
|
||||
Rc::new(move |_, window, cx| create(&name, &id, &relay, window, cx))
|
||||
};
|
||||
|
||||
window.open_dialog(cx, move |this, _window, cx| {
|
||||
this.width(px(380.))
|
||||
.confirm()
|
||||
.title("New group")
|
||||
.on_ok({
|
||||
let submit = submit.clone();
|
||||
move |event, window, cx| submit(event, window, cx)
|
||||
})
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_3()
|
||||
@@ -26,7 +35,32 @@ pub fn open(window: &mut Window, cx: &mut App) {
|
||||
.child(field("Group id", &id, cx))
|
||||
.child(field("Relay", &relay, cx)),
|
||||
)
|
||||
.on_ok(move |_event, window, cx| create(&name, &id, &relay, window, cx))
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.justify_end()
|
||||
.child(
|
||||
Button::new("cancel")
|
||||
.label("Cancel")
|
||||
.ghost()
|
||||
.on_click(|_, window, cx| window.close_dialog(cx)),
|
||||
)
|
||||
.child(
|
||||
Button::new("create")
|
||||
.icon(IconName::CheckCircle)
|
||||
.label("Create")
|
||||
.primary()
|
||||
.font_semibold()
|
||||
.on_click({
|
||||
let submit = submit.clone();
|
||||
move |event, window, cx| {
|
||||
if submit(event, window, cx) {
|
||||
window.close_dialog(cx);
|
||||
}
|
||||
}
|
||||
}),
|
||||
),
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ use nostr_sdk::prelude::*;
|
||||
use theme::ActiveTheme;
|
||||
use ui::button::{Button, ButtonVariants};
|
||||
use ui::input::{Input, InputEvent, InputState};
|
||||
use ui::{WindowExtension, v_flex};
|
||||
use ui::{IconName, StyledExt, WindowExtension, h_flex, v_flex};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RestoreEncryption {
|
||||
@@ -99,7 +99,7 @@ impl Render for RestoreEncryption {
|
||||
fn render(&mut self, _window: &mut gpui::Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
v_flex()
|
||||
.size_full()
|
||||
.gap_2()
|
||||
.gap_3()
|
||||
.text_sm()
|
||||
.child(
|
||||
v_flex()
|
||||
@@ -110,12 +110,16 @@ impl Render for RestoreEncryption {
|
||||
.child(Input::new(&self.key_input)),
|
||||
)
|
||||
.child(
|
||||
Button::new("restore")
|
||||
.label("Restore")
|
||||
.primary()
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.restore(window, cx);
|
||||
})),
|
||||
h_flex().gap_1().justify_end().child(
|
||||
Button::new("restore")
|
||||
.icon(IconName::CheckCircle)
|
||||
.label("Restore")
|
||||
.primary()
|
||||
.font_semibold()
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.restore(window, cx);
|
||||
})),
|
||||
),
|
||||
)
|
||||
.when_some(self.error.read(cx).as_ref(), |this, error| {
|
||||
this.child(
|
||||
|
||||
@@ -22,27 +22,18 @@ pub fn init(public_key: PublicKey, window: &mut Window, cx: &mut App) -> Entity<
|
||||
cx.new(|cx| Screening::new(public_key, window, cx))
|
||||
}
|
||||
|
||||
/// Screening
|
||||
pub struct Screening {
|
||||
/// Public Key of the person being screened.
|
||||
public_key: PublicKey,
|
||||
|
||||
/// Whether the person's address is verified.
|
||||
verified: bool,
|
||||
|
||||
/// Whether the person is followed by current user.
|
||||
followed: bool,
|
||||
|
||||
/// Last time the person was active.
|
||||
last_active: Option<Timestamp>,
|
||||
|
||||
/// All mutual contacts of the person being screened.
|
||||
mutual_contacts: Vec<PublicKey>,
|
||||
|
||||
/// Async tasks
|
||||
tasks: SmallVec<[Task<()>; 3]>,
|
||||
|
||||
/// Subscriptions
|
||||
_subscriptions: SmallVec<[Subscription; 1]>,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user