update profile panel
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m55s
Rust / build (ubuntu-latest, stable) (pull_request) Failing after 2m42s
Rust / build (macos-latest, stable) (push) Has been cancelled
Rust / build (windows-latest, stable) (push) Has been cancelled
Rust / build (macos-latest, stable) (pull_request) Has been cancelled
Rust / build (windows-latest, stable) (pull_request) Has been cancelled
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m55s
Rust / build (ubuntu-latest, stable) (pull_request) Failing after 2m42s
Rust / build (macos-latest, stable) (push) Has been cancelled
Rust / build (windows-latest, stable) (push) Has been cancelled
Rust / build (macos-latest, stable) (pull_request) Has been cancelled
Rust / build (windows-latest, stable) (pull_request) Has been cancelled
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.10352 4C7.42998 2.84575 8.49122 2 9.75 2H14.25C15.5088 2 16.57 2.84575 16.8965 4H18.25C19.7688 4 21 5.23122 21 6.75V19.25C21 20.7688 19.7688 22 18.25 22H5.75C4.23122 22 3 20.7688 3 19.25V6.75C3 5.23122 4.23122 4 5.75 4H7.10352ZM8.5 4.75V6.25C8.5 6.38807 8.61193 6.5 8.75 6.5H15.25C15.3881 6.5 15.5 6.38807 15.5 6.25V4.75C15.5 4.05964 14.9404 3.5 14.25 3.5H9.75C9.05964 3.5 8.5 4.05964 8.5 4.75Z" fill="currentColor"/>
|
||||
<path d="M8.75 8.75V4C8.75 3.30964 9.30964 2.75 10 2.75H20C20.6904 2.75 21.25 3.30964 21.25 4V14C21.25 14.6904 20.6904 15.25 20 15.25H15.25M14 8.75H4C3.30964 8.75 2.75 9.30964 2.75 10V20C2.75 20.6904 3.30964 21.25 4 21.25H14C14.6904 21.25 15.25 20.6904 15.25 20V10C15.25 9.30964 14.6904 8.75 14 8.75Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 550 B After Width: | Height: | Size: 472 B |
@@ -40,7 +40,7 @@ impl GreeterPanel {
|
||||
cx.update(|window, cx| {
|
||||
Workspace::add_panel(
|
||||
profile::init(public_key, window, cx),
|
||||
DockPlacement::Center,
|
||||
DockPlacement::Right,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
||||
@@ -296,7 +296,7 @@ impl Render for MessagingRelayPanel {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
v_flex()
|
||||
.p_3()
|
||||
.gap_2()
|
||||
.gap_3()
|
||||
.w_full()
|
||||
.child(
|
||||
div()
|
||||
@@ -367,9 +367,11 @@ impl Render for MessagingRelayPanel {
|
||||
})
|
||||
.child(
|
||||
Button::new("submit")
|
||||
.icon(IconName::CheckCircle)
|
||||
.label("Update")
|
||||
.primary()
|
||||
.small()
|
||||
.font_semibold()
|
||||
.loading(self.updating)
|
||||
.disabled(self.updating)
|
||||
.on_click(cx.listener(move |this, _ev, window, cx| {
|
||||
|
||||
@@ -20,7 +20,7 @@ use ui::button::{Button, ButtonVariants};
|
||||
use ui::dock_area::panel::{Panel, PanelEvent};
|
||||
use ui::input::{InputState, TextInput};
|
||||
use ui::notification::Notification;
|
||||
use ui::{divider, h_flex, v_flex, Disableable, IconName, Sizable, StyledExt, WindowExtension};
|
||||
use ui::{h_flex, v_flex, Disableable, IconName, Sizable, StyledExt, WindowExtension};
|
||||
|
||||
pub fn init(public_key: PublicKey, window: &mut Window, cx: &mut App) -> Entity<ProfilePanel> {
|
||||
cx.new(|cx| ProfilePanel::new(public_key, window, cx))
|
||||
@@ -51,6 +51,12 @@ pub struct ProfilePanel {
|
||||
|
||||
/// Copied states
|
||||
copied: bool,
|
||||
|
||||
/// Updating state
|
||||
updating: bool,
|
||||
|
||||
/// Tasks
|
||||
tasks: Vec<Task<Result<(), Error>>>,
|
||||
}
|
||||
|
||||
impl ProfilePanel {
|
||||
@@ -58,6 +64,7 @@ impl ProfilePanel {
|
||||
let name_input = cx.new(|cx| InputState::new(window, cx).placeholder("Alice"));
|
||||
let website_input = cx.new(|cx| InputState::new(window, cx).placeholder("alice.me"));
|
||||
let avatar_input = cx.new(|cx| InputState::new(window, cx).placeholder("alice.me/a.jpg"));
|
||||
|
||||
// Use multi-line input for bio
|
||||
let bio_input = cx.new(|cx| {
|
||||
InputState::new(window, cx)
|
||||
@@ -68,10 +75,7 @@ impl ProfilePanel {
|
||||
|
||||
// Get user's profile and update inputs
|
||||
cx.defer_in(window, move |this, window, cx| {
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let profile = persons.read(cx).get(&public_key, cx);
|
||||
// Set all input's values with current profile
|
||||
this.set_profile(profile, window, cx);
|
||||
this.set_profile(window, cx);
|
||||
});
|
||||
|
||||
Self {
|
||||
@@ -84,11 +88,15 @@ impl ProfilePanel {
|
||||
website_input,
|
||||
uploading: false,
|
||||
copied: false,
|
||||
updating: false,
|
||||
tasks: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn set_profile(&mut self, person: Person, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let metadata = person.metadata();
|
||||
fn set_profile(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let profile = persons.read(cx).get(&self.public_key, cx);
|
||||
let metadata = profile.metadata();
|
||||
|
||||
self.avatar_input.update(cx, |this, cx| {
|
||||
if let Some(avatar) = metadata.picture.as_ref() {
|
||||
@@ -205,6 +213,11 @@ impl ProfilePanel {
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn set_updating(&mut self, updating: bool, cx: &mut Context<Self>) {
|
||||
self.updating = updating;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Set the metadata for the current user
|
||||
fn publish(&self, metadata: &Metadata, cx: &App) -> Task<Result<(), Error>> {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
@@ -253,26 +266,34 @@ impl ProfilePanel {
|
||||
// Set the metadata
|
||||
let task = self.publish(&new_metadata, cx);
|
||||
|
||||
cx.spawn_in(window, async move |_this, cx| {
|
||||
// Set the updating state
|
||||
self.set_updating(true, cx);
|
||||
|
||||
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
|
||||
match task.await {
|
||||
Ok(_) => {
|
||||
cx.update(|window, cx| {
|
||||
this.update_in(cx, |this, window, cx| {
|
||||
// Update the registry
|
||||
persons.update(cx, |this, cx| {
|
||||
this.insert(Person::new(public_key, new_metadata), cx);
|
||||
});
|
||||
|
||||
// Update current panel
|
||||
this.set_updating(false, cx);
|
||||
this.set_profile(window, cx);
|
||||
|
||||
window.push_notification("Profile updated successfully", cx);
|
||||
})
|
||||
.ok();
|
||||
})?;
|
||||
}
|
||||
Err(e) => {
|
||||
cx.update(|window, cx| {
|
||||
window.push_notification(Notification::error(e.to_string()), cx);
|
||||
})
|
||||
.ok();
|
||||
})?;
|
||||
}
|
||||
};
|
||||
})
|
||||
.detach();
|
||||
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,123 +317,126 @@ impl Focusable for ProfilePanel {
|
||||
|
||||
impl Render for ProfilePanel {
|
||||
fn render(&mut self, _window: &mut gpui::Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let shorten_pkey = SharedString::from(shorten_pubkey(self.public_key, 8));
|
||||
let avatar_input = self.avatar_input.read(cx).value();
|
||||
|
||||
// Get the avatar
|
||||
let avatar_input = self.avatar_input.read(cx).value();
|
||||
let avatar = if avatar_input.is_empty() {
|
||||
"brand/avatar.png"
|
||||
} else {
|
||||
avatar_input.as_str()
|
||||
};
|
||||
|
||||
// Get the public key as short string
|
||||
let shorten_pkey = SharedString::from(shorten_pubkey(self.public_key, 8));
|
||||
|
||||
v_flex()
|
||||
.size_full()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.p_2()
|
||||
.p_3()
|
||||
.gap_3()
|
||||
.w_full()
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_2()
|
||||
.w_112()
|
||||
.h_40()
|
||||
.w_full()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.gap_4()
|
||||
.child(Avatar::new(avatar).size(rems(4.25)))
|
||||
.child(
|
||||
v_flex()
|
||||
.h_40()
|
||||
.w_full()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.gap_4()
|
||||
.child(Avatar::new(avatar).size(rems(4.25)))
|
||||
.child(
|
||||
Button::new("upload")
|
||||
.icon(IconName::PlusCircle)
|
||||
.label("Add an avatar")
|
||||
.xsmall()
|
||||
.ghost()
|
||||
.rounded()
|
||||
.disabled(self.uploading)
|
||||
.loading(self.uploading)
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.upload(window, cx);
|
||||
})),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_1()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(SharedString::from("What should people call you?"))
|
||||
.child(TextInput::new(&self.name_input).small()),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_1()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(SharedString::from("A short introduction about you:"))
|
||||
.child(TextInput::new(&self.bio_input).small()),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_1()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(SharedString::from("Website:"))
|
||||
.child(TextInput::new(&self.website_input).small()),
|
||||
)
|
||||
.child(divider(cx))
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_1()
|
||||
.child(
|
||||
div()
|
||||
.font_semibold()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_placeholder)
|
||||
.child(SharedString::from("Public Key:")),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.h_8()
|
||||
.w_full()
|
||||
.justify_center()
|
||||
.gap_2()
|
||||
.bg(cx.theme().surface_background)
|
||||
.rounded(cx.theme().radius)
|
||||
.text_sm()
|
||||
.child(shorten_pkey)
|
||||
.child(
|
||||
Button::new("copy")
|
||||
.icon({
|
||||
if self.copied {
|
||||
IconName::CheckCircle
|
||||
} else {
|
||||
IconName::Copy
|
||||
}
|
||||
})
|
||||
.xsmall()
|
||||
.ghost()
|
||||
.on_click(cx.listener(move |this, _ev, window, cx| {
|
||||
this.copy(
|
||||
this.public_key.to_bech32().unwrap(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
})),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(divider(cx))
|
||||
.child(
|
||||
Button::new("submit")
|
||||
.label("Update")
|
||||
.primary()
|
||||
Button::new("upload")
|
||||
.icon(IconName::PlusCircle)
|
||||
.label("Add an avatar")
|
||||
.xsmall()
|
||||
.ghost()
|
||||
.rounded()
|
||||
.disabled(self.uploading)
|
||||
.on_click(cx.listener(move |this, _ev, window, cx| {
|
||||
this.update(window, cx);
|
||||
.loading(self.uploading)
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.upload(window, cx);
|
||||
})),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_1p5()
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(SharedString::from("What should people call you?")),
|
||||
)
|
||||
.child(TextInput::new(&self.name_input).bordered(false).small()),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_1p5()
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(SharedString::from("A short introduction about you:")),
|
||||
)
|
||||
.child(TextInput::new(&self.bio_input).bordered(false).small()),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_1p5()
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(SharedString::from("Website:")),
|
||||
)
|
||||
.child(TextInput::new(&self.website_input).bordered(false).small()),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_1p5()
|
||||
.child(
|
||||
div()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(SharedString::from("Public Key:")),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.h_8()
|
||||
.w_full()
|
||||
.justify_center()
|
||||
.gap_3()
|
||||
.rounded(cx.theme().radius)
|
||||
.bg(cx.theme().secondary_background)
|
||||
.text_sm()
|
||||
.text_color(cx.theme().secondary_foreground)
|
||||
.child(shorten_pkey)
|
||||
.child(
|
||||
Button::new("copy")
|
||||
.icon({
|
||||
if self.copied {
|
||||
IconName::CheckCircle
|
||||
} else {
|
||||
IconName::Copy
|
||||
}
|
||||
})
|
||||
.xsmall()
|
||||
.secondary()
|
||||
.on_click(cx.listener(move |this, _ev, window, cx| {
|
||||
this.copy(this.public_key.to_bech32().unwrap(), window, cx);
|
||||
})),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
Button::new("submit")
|
||||
.icon(IconName::CheckCircle)
|
||||
.label("Update")
|
||||
.primary()
|
||||
.small()
|
||||
.font_semibold()
|
||||
.loading(self.updating)
|
||||
.disabled(self.updating)
|
||||
.on_click(cx.listener(move |this, _ev, window, cx| {
|
||||
this.update(window, cx);
|
||||
})),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ impl Render for RelayListPanel {
|
||||
v_flex()
|
||||
.on_action(cx.listener(Self::set_metadata))
|
||||
.p_3()
|
||||
.gap_2()
|
||||
.gap_3()
|
||||
.w_full()
|
||||
.child(
|
||||
div()
|
||||
@@ -426,9 +426,11 @@ impl Render for RelayListPanel {
|
||||
})
|
||||
.child(
|
||||
Button::new("submit")
|
||||
.icon(IconName::CheckCircle)
|
||||
.label("Update")
|
||||
.primary()
|
||||
.small()
|
||||
.font_semibold()
|
||||
.loading(self.updating)
|
||||
.disabled(self.updating)
|
||||
.on_click(cx.listener(move |this, _ev, window, cx| {
|
||||
|
||||
@@ -513,7 +513,7 @@ impl ButtonVariant {
|
||||
fn bg_color(&self, cx: &App) -> Hsla {
|
||||
match self {
|
||||
ButtonVariant::Primary => cx.theme().element_background,
|
||||
ButtonVariant::Secondary => cx.theme().elevated_surface_background,
|
||||
ButtonVariant::Secondary => cx.theme().secondary_background,
|
||||
ButtonVariant::Danger => cx.theme().danger_background,
|
||||
ButtonVariant::Warning => cx.theme().warning_background,
|
||||
ButtonVariant::Ghost { alt } => {
|
||||
@@ -531,7 +531,7 @@ impl ButtonVariant {
|
||||
fn text_color(&self, cx: &App) -> Hsla {
|
||||
match self {
|
||||
ButtonVariant::Primary => cx.theme().element_foreground,
|
||||
ButtonVariant::Secondary => cx.theme().text_muted,
|
||||
ButtonVariant::Secondary => cx.theme().secondary_foreground,
|
||||
ButtonVariant::Danger => cx.theme().danger_foreground,
|
||||
ButtonVariant::Warning => cx.theme().warning_foreground,
|
||||
ButtonVariant::Transparent => cx.theme().text_placeholder,
|
||||
|
||||
Reference in New Issue
Block a user