clean up
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m47s
Rust / build (ubuntu-latest, stable) (pull_request) Failing after 1m40s

This commit is contained in:
2026-01-29 09:31:09 +07:00
parent 5d4481fb5f
commit a87111e138
8 changed files with 63 additions and 492 deletions

58
Cargo.lock generated
View File

@@ -1180,7 +1180,7 @@ dependencies = [
[[package]]
name = "collections"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"indexmap",
"rustc-hash 2.1.1",
@@ -1619,7 +1619,7 @@ dependencies = [
[[package]]
name = "derive_refineable"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"proc-macro2",
"quote",
@@ -2542,7 +2542,7 @@ dependencies = [
[[package]]
name = "gpui"
version = "0.2.2"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"anyhow",
"as-raw-xcb-connection",
@@ -2644,7 +2644,7 @@ dependencies = [
[[package]]
name = "gpui_macros"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"heck 0.5.0",
"proc-macro2",
@@ -2655,7 +2655,7 @@ dependencies = [
[[package]]
name = "gpui_tokio"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"anyhow",
"gpui",
@@ -2877,7 +2877,7 @@ dependencies = [
[[package]]
name = "http_client"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"anyhow",
"async-compression",
@@ -2902,7 +2902,7 @@ dependencies = [
[[package]]
name = "http_client_tls"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"rustls",
"rustls-platform-verifier",
@@ -2997,9 +2997,9 @@ dependencies = [
[[package]]
name = "iana-time-zone"
version = "0.1.64"
version = "0.1.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
dependencies = [
"android_system_properties",
"core-foundation-sys",
@@ -3663,7 +3663,7 @@ dependencies = [
[[package]]
name = "media"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"anyhow",
"bindgen",
@@ -4264,9 +4264,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "oneshot"
version = "0.1.12"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ce66197e99546da6c6d991285f605192e794ceae69686c17163844a7bf8fcc2"
checksum = "269bca4c2591a28585d6bf10d9ed0332b7d76900a1b02bec41bdc3a2cdcda107"
[[package]]
name = "oo7"
@@ -4502,7 +4502,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "perf"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"collections",
"serde",
@@ -5137,7 +5137,7 @@ dependencies = [
[[package]]
name = "refineable"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"derive_refineable",
]
@@ -5236,7 +5236,7 @@ dependencies = [
[[package]]
name = "reqwest_client"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"anyhow",
"bytes",
@@ -5290,7 +5290,7 @@ dependencies = [
[[package]]
name = "rope"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"arrayvec",
"log",
@@ -5569,7 +5569,7 @@ dependencies = [
[[package]]
name = "scheduler"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"async-task",
"backtrace",
@@ -5942,9 +5942,9 @@ dependencies = [
[[package]]
name = "siphasher"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
[[package]]
name = "skrifa"
@@ -6161,7 +6161,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "sum_tree"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"arrayvec",
"log",
@@ -7102,7 +7102,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "util"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"anyhow",
"async-fs",
@@ -7140,7 +7140,7 @@ dependencies = [
[[package]]
name = "util_macros"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"perf",
"quote",
@@ -8521,18 +8521,18 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524"
[[package]]
name = "zerocopy"
version = "0.8.33"
version = "0.8.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd"
checksum = "fdea86ddd5568519879b8187e1cf04e24fce28f7fe046ceecbce472ff19a2572"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.33"
version = "0.8.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1"
checksum = "0c15e1b46eff7c6c91195752e0eeed8ef040e391cdece7c25376957d5f15df22"
dependencies = [
"proc-macro2",
"quote",
@@ -8616,7 +8616,7 @@ dependencies = [
[[package]]
name = "zlog"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"anyhow",
"chrono",
@@ -8633,7 +8633,7 @@ checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439"
[[package]]
name = "ztracing"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
dependencies = [
"tracing",
"tracing-subscriber",
@@ -8644,7 +8644,7 @@ dependencies = [
[[package]]
name = "ztracing_macro"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
[[package]]
name = "zune-core"

View File

@@ -1,2 +1,3 @@
pub mod compose;
pub mod profile;
pub mod screening;

View File

@@ -9,7 +9,7 @@ use gpui::{
};
use gpui_tokio::Tokio;
use nostr_sdk::prelude::*;
use person::{Person, PersonRegistry};
use person::PersonRegistry;
use smallvec::{smallvec, SmallVec};
use state::NostrRegistry;
use theme::ActiveTheme;
@@ -17,13 +17,13 @@ use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants};
use ui::{h_flex, v_flex, Icon, IconName, Sizable, StyledExt};
pub fn init(public_key: PublicKey, window: &mut Window, cx: &mut App) -> Entity<ProfileViewer> {
cx.new(|cx| ProfileViewer::new(public_key, window, cx))
pub fn init(public_key: PublicKey, window: &mut Window, cx: &mut App) -> Entity<ProfileDialog> {
cx.new(|cx| ProfileDialog::new(public_key, window, cx))
}
#[derive(Debug)]
pub struct ProfileViewer {
profile: Person,
pub struct ProfileDialog {
public_key: PublicKey,
/// Follow status
followed: bool,
@@ -38,13 +38,13 @@ pub struct ProfileViewer {
_tasks: SmallVec<[Task<()>; 1]>,
}
impl ProfileViewer {
pub fn new(target: PublicKey, window: &mut Window, cx: &mut Context<Self>) -> Self {
impl ProfileDialog {
pub fn new(public_key: PublicKey, window: &mut Window, cx: &mut Context<Self>) -> Self {
let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client();
let persons = PersonRegistry::global(cx);
let profile = persons.read(cx).get(&target, cx);
let profile = persons.read(cx).get(&public_key, cx);
let mut tasks = smallvec![];
@@ -53,12 +53,12 @@ impl ProfileViewer {
let public_key = signer.get_public_key().await?;
let contact_list = client.database().contacts_public_keys(public_key).await?;
Ok(contact_list.contains(&target))
Ok(contact_list.contains(&public_key))
});
let verify_nip05 = if let Some(address) = profile.metadata().nip05 {
Some(Tokio::spawn(cx, async move {
nip05_verify(target, &address).await.unwrap_or(false)
nip05_verify(public_key, &address).await.unwrap_or(false)
}))
} else {
None
@@ -90,7 +90,7 @@ impl ProfileViewer {
);
Self {
profile,
public_key,
followed: false,
verified: false,
copied: false,
@@ -98,12 +98,18 @@ impl ProfileViewer {
}
}
fn address(&self, _cx: &Context<Self>) -> Option<String> {
self.profile.metadata().nip05
fn address(&self, cx: &Context<Self>) -> Option<String> {
let persons = PersonRegistry::global(cx);
let profile = persons.read(cx).get(&self.public_key, cx);
profile.metadata().nip05
}
fn copy_pubkey(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let Ok(bech32) = self.profile.public_key().to_bech32();
let persons = PersonRegistry::global(cx);
let profile = persons.read(cx).get(&self.public_key, cx);
let Ok(bech32) = profile.public_key().to_bech32();
let item = ClipboardItem::new_string(bech32);
cx.write_to_clipboard(item);
@@ -132,9 +138,11 @@ impl ProfileViewer {
}
}
impl Render for ProfileViewer {
impl Render for ProfileDialog {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let bech32 = shorten_pubkey(self.profile.public_key(), 16);
let persons = PersonRegistry::global(cx);
let profile = persons.read(cx).get(&self.public_key, cx);
let bech32 = shorten_pubkey(profile.public_key(), 16);
let shared_bech32 = SharedString::from(bech32);
v_flex()
@@ -146,14 +154,14 @@ impl Render for ProfileViewer {
.items_center()
.justify_center()
.text_center()
.child(Avatar::new(self.profile.avatar()).size(rems(4.)))
.child(Avatar::new(profile.avatar()).size(rems(4.)))
.child(
v_flex()
.child(
div()
.font_semibold()
.line_height(relative(1.25))
.child(self.profile.name()),
.child(profile.name()),
)
.when_some(self.address(cx), |this, address| {
this.child(
@@ -208,7 +216,7 @@ impl Render for ProfileViewer {
.rounded(cx.theme().radius)
.bg(cx.theme().elevated_surface_background)
.child(
self.profile
profile
.metadata()
.about
.map(SharedString::from)

View File

@@ -15,7 +15,6 @@ mod actions;
mod dialogs;
mod panels;
mod sidebar;
mod user;
mod workspace;
fn main() {

View File

@@ -140,7 +140,7 @@ impl Render for GreeterPanel {
.gap_2()
.when(relay_list_state == RelayState::NotSet, |this| {
this.child(
Button::new("connect")
Button::new("relaylist")
.icon(Icon::new(IconName::Door))
.label("Set up relay list")
.ghost()

View File

@@ -47,7 +47,7 @@ pub struct ImportPanel {
impl ImportPanel {
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
let key_input = cx.new(|cx| InputState::new(window, cx));
let key_input = cx.new(|cx| InputState::new(window, cx).masked(true));
let pass_input = cx.new(|cx| InputState::new(window, cx).masked(true));
let error = cx.new(|_| None);

View File

@@ -1,388 +0,0 @@
use std::str::FromStr;
use std::time::Duration;
use anyhow::{anyhow, Error};
use common::{nip96_upload, shorten_pubkey};
use gpui::prelude::FluentBuilder;
use gpui::{
div, img, App, AppContext, ClipboardItem, Context, Entity, IntoElement, ParentElement,
PathPromptOptions, Render, SharedString, Styled, Task, Window,
};
use gpui_tokio::Tokio;
use nostr_sdk::prelude::*;
use person::Person;
use settings::AppSettings;
use smallvec::{smallvec, SmallVec};
use smol::fs;
use state::NostrRegistry;
use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants};
use ui::input::{InputState, TextInput};
use ui::{h_flex, v_flex, Disableable, IconName, Sizable, StyledExt, WindowExtension};
pub mod viewer;
pub fn init(window: &mut Window, cx: &mut App) -> Entity<UserProfile> {
cx.new(|cx| UserProfile::new(window, cx))
}
#[derive(Debug)]
pub struct UserProfile {
/// User profile
profile: Option<Profile>,
/// User's name text input
name_input: Entity<InputState>,
/// User's avatar url text input
avatar_input: Entity<InputState>,
/// User's bio multi line input
bio_input: Entity<InputState>,
/// User's website url text input
website_input: Entity<InputState>,
/// Uploading state
uploading: bool,
/// Copied states
copied: bool,
/// Async operations
_tasks: SmallVec<[Task<()>; 1]>,
}
impl UserProfile {
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
let name_input = cx.new(|cx| InputState::new(window, cx).placeholder("Alice"));
let avatar_input = cx.new(|cx| InputState::new(window, cx).placeholder("alice.me/a.jpg"));
let website_input = cx.new(|cx| InputState::new(window, cx).placeholder("alice.me"));
// Use multi-line input for bio
let bio_input = cx.new(|cx| {
InputState::new(window, cx)
.multi_line()
.auto_grow(3, 8)
.placeholder("A short introduce about you.")
});
let get_profile = Self::get_profile(cx);
let mut tasks = smallvec![];
tasks.push(
// Get metadata in the background
cx.spawn_in(window, async move |this, cx| {
if let Ok(profile) = get_profile.await {
this.update_in(cx, |this, window, cx| {
this.set_profile(profile, window, cx);
})
.ok();
}
}),
);
Self {
profile: None,
name_input,
avatar_input,
bio_input,
website_input,
uploading: false,
copied: false,
_tasks: tasks,
}
}
fn get_profile(cx: &App) -> Task<Result<Profile, Error>> {
let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client();
cx.background_spawn(async move {
let signer = client.signer().await?;
let public_key = signer.get_public_key().await?;
let metadata = client
.database()
.metadata(public_key)
.await?
.unwrap_or_default();
Ok(Profile::new(public_key, metadata))
})
}
fn set_profile(&mut self, profile: Profile, window: &mut Window, cx: &mut Context<Self>) {
let metadata = profile.metadata();
self.avatar_input.update(cx, |this, cx| {
if let Some(avatar) = metadata.picture.as_ref() {
this.set_value(avatar, window, cx);
}
});
self.bio_input.update(cx, |this, cx| {
if let Some(bio) = metadata.about.as_ref() {
this.set_value(bio, window, cx);
}
});
self.name_input.update(cx, |this, cx| {
if let Some(display_name) = metadata.display_name.as_ref() {
this.set_value(display_name, window, cx);
}
});
self.website_input.update(cx, |this, cx| {
if let Some(website) = metadata.website.as_ref() {
this.set_value(website, window, cx);
}
});
self.profile = Some(profile);
cx.notify();
}
fn copy(&mut self, value: String, window: &mut Window, cx: &mut Context<Self>) {
let item = ClipboardItem::new_string(value);
cx.write_to_clipboard(item);
self.set_copied(true, window, cx);
}
fn set_copied(&mut self, status: bool, window: &mut Window, cx: &mut Context<Self>) {
self.copied = status;
cx.notify();
if status {
self._tasks.push(
// Reset the copied state after a delay
cx.spawn_in(window, async move |this, cx| {
cx.background_executor().timer(Duration::from_secs(2)).await;
cx.update(|window, cx| {
this.update(cx, |this, cx| {
this.set_copied(false, window, cx);
})
.ok();
})
.ok();
}),
);
}
}
fn uploading(&mut self, status: bool, cx: &mut Context<Self>) {
self.uploading = status;
cx.notify();
}
fn upload(&mut self, window: &mut Window, cx: &mut Context<Self>) {
self.uploading(true, cx);
let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client();
// Get the user's configured NIP96 server
let nip96_server = AppSettings::get_file_server(cx);
// Open native file dialog
let paths = cx.prompt_for_paths(PathPromptOptions {
files: true,
directories: false,
multiple: false,
prompt: None,
});
let task = Tokio::spawn(cx, async move {
match paths.await {
Ok(Ok(Some(mut paths))) => {
if let Some(path) = paths.pop() {
let file = fs::read(path).await?;
let url = nip96_upload(&client, &nip96_server, file).await?;
Ok(url)
} else {
Err(anyhow!("Path not found"))
}
}
_ => Err(anyhow!("Error")),
}
});
cx.spawn_in(window, async move |this, cx| {
let result = task.await;
this.update_in(cx, |this, window, cx| {
match result {
Ok(Ok(url)) => {
this.avatar_input.update(cx, |this, cx| {
this.set_value(url.to_string(), window, cx);
});
}
Ok(Err(e)) => {
window.push_notification(e.to_string(), cx);
}
Err(e) => {
log::warn!("Failed to upload avatar: {e}");
}
};
this.uploading(false, cx);
})
.expect("Entity has been released");
})
.detach();
}
pub fn set_metadata(&mut self, cx: &mut Context<Self>) -> Task<Result<Person, Error>> {
let avatar = self.avatar_input.read(cx).value().to_string();
let name = self.name_input.read(cx).value().to_string();
let bio = self.bio_input.read(cx).value().to_string();
let website = self.website_input.read(cx).value().to_string();
// Get the current profile metadata
let old_metadata = self
.profile
.as_ref()
.map(|profile| profile.metadata())
.unwrap_or_default();
// Construct the new metadata
let mut new_metadata = old_metadata.display_name(name).about(bio);
if let Ok(url) = Url::from_str(&avatar) {
new_metadata = new_metadata.picture(url);
};
if let Ok(url) = Url::from_str(&website) {
new_metadata = new_metadata.website(url);
}
let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client();
let public_key = nostr.read(cx).identity().read(cx).public_key();
let write_relays = nostr.read(cx).write_relays(&public_key, cx);
cx.background_spawn(async move {
let urls = write_relays.await;
let signer = client.signer().await?;
// Sign the new metadata event
let event = EventBuilder::metadata(&new_metadata).sign(&signer).await?;
// Send event to user's write relayss
client.send_event_to(urls, &event).await?;
// Return the updated profile
let metadata = Metadata::from_json(&event.content).unwrap_or_default();
let profile = Person::new(event.pubkey, metadata);
Ok(profile)
})
}
}
impl Render for UserProfile {
fn render(&mut self, _window: &mut gpui::Window, cx: &mut Context<Self>) -> impl IntoElement {
v_flex()
.gap_3()
.child(
v_flex()
.relative()
.w_full()
.h_32()
.items_center()
.justify_center()
.gap_2()
.bg(cx.theme().surface_background)
.rounded(cx.theme().radius)
.map(|this| {
let picture = self.avatar_input.read(cx).value();
let source = if picture.is_empty() {
"brand/avatar.png"
} else {
picture.as_str()
};
this.child(img(source).rounded_full().size_10().flex_shrink_0())
})
.child(
Button::new("upload")
.icon(IconName::Upload)
.label("Change")
.ghost()
.small()
.disabled(self.uploading)
.on_click(cx.listener(move |this, _, window, cx| {
this.upload(window, cx);
})),
),
)
.child(
v_flex()
.gap_1()
.text_sm()
.child(SharedString::from("Name:"))
.child(TextInput::new(&self.name_input).small()),
)
.child(
v_flex()
.gap_1()
.text_sm()
.child(SharedString::from("Bio:"))
.child(TextInput::new(&self.bio_input).small()),
)
.child(
v_flex()
.gap_1()
.text_sm()
.child(SharedString::from("Website:"))
.child(TextInput::new(&self.website_input).small()),
)
.when_some(self.profile.as_ref(), |this, profile| {
let public_key = profile.public_key();
let display = SharedString::from(shorten_pubkey(profile.public_key(), 8));
this.child(div().my_1().h_px().w_full().bg(cx.theme().border))
.child(
v_flex()
.gap_1()
.child(
div()
.text_xs()
.text_color(cx.theme().text_placeholder)
.font_semibold()
.child(SharedString::from("Public Key:")),
)
.child(
h_flex()
.gap_2()
.w_full()
.h_12()
.justify_center()
.bg(cx.theme().surface_background)
.rounded(cx.theme().radius)
.text_sm()
.child(display)
.child(
Button::new("copy")
.icon({
if self.copied {
IconName::CheckCircle
} else {
IconName::Copy
}
})
.xsmall()
.ghost()
.on_click(cx.listener(move |this, _e, window, cx| {
this.copy(
public_key.to_bech32().unwrap(),
window,
cx,
);
})),
),
),
)
})
}
}

View File

@@ -11,17 +11,16 @@ use gpui::{
IntoElement, ParentElement, Render, SharedString, Styled, Subscription, Window,
};
use nostr_connect::prelude::*;
use person::PersonRegistry;
use smallvec::{smallvec, SmallVec};
use theme::{ActiveTheme, Theme, ThemeRegistry};
use ui::button::{Button, ButtonVariants};
use ui::modal::ModalButtonProps;
use ui::{h_flex, v_flex, Root, Sizable, WindowExtension};
use crate::actions::{reset, KeyringPopup, Logout, Themes, ViewProfile};
use crate::actions::{reset, KeyringPopup, Logout, Themes};
use crate::dialogs::profile;
use crate::panels::greeter;
use crate::user::viewer;
use crate::{sidebar, user};
use crate::sidebar;
pub fn init(window: &mut Window, cx: &mut App) -> Entity<Workspace> {
cx.new(|cx| Workspace::new(window, cx))
@@ -150,53 +149,6 @@ impl Workspace {
});
}
fn on_profile(&mut self, _ev: &ViewProfile, window: &mut Window, cx: &mut Context<Self>) {
let view = user::init(window, cx);
let entity = view.downgrade();
window.open_modal(cx, move |modal, _window, _cx| {
let entity = entity.clone();
modal
.title("Profile")
.confirm()
.child(view.clone())
.button_props(ModalButtonProps::default().ok_text("Update"))
.on_ok(move |_, window, cx| {
entity
.update(cx, |this, cx| {
let persons = PersonRegistry::global(cx);
let set_metadata = this.set_metadata(cx);
cx.spawn_in(window, async move |this, cx| {
let result = set_metadata.await;
this.update_in(cx, |_, window, cx| {
match result {
Ok(person) => {
persons.update(cx, |this, cx| {
this.insert(person, cx);
// Close the edit profile modal
window.close_all_modals(cx);
});
}
Err(e) => {
window.push_notification(e.to_string(), cx);
}
};
})
.ok();
})
.detach();
})
.ok();
// false to keep the modal open
false
})
});
}
fn on_themes(&mut self, _ev: &Themes, window: &mut Window, cx: &mut Context<Self>) {
window.open_modal(cx, move |this, _window, cx| {
let registry = ThemeRegistry::global(cx);
@@ -255,7 +207,7 @@ impl Workspace {
fn on_open_pubkey(&mut self, ev: &OpenPublicKey, window: &mut Window, cx: &mut Context<Self>) {
let public_key = ev.0;
let view = viewer::init(public_key, window, cx);
let view = profile::init(public_key, window, cx);
window.open_modal(cx, move |this, _window, _cx| {
this.alert()
@@ -319,7 +271,6 @@ impl Render for Workspace {
div()
.id(SharedString::from("workspace"))
.on_action(cx.listener(Self::on_profile))
.on_action(cx.listener(Self::on_themes))
.on_action(cx.listener(Self::on_sign_out))
.on_action(cx.listener(Self::on_open_pubkey))