clean up
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 1m47s
Rust / build (ubuntu-latest, stable) (pull_request) Failing after 1m40s
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:
58
Cargo.lock
generated
58
Cargo.lock
generated
@@ -1180,7 +1180,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collections"
|
name = "collections"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.1",
|
||||||
@@ -1619,7 +1619,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_refineable"
|
name = "derive_refineable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2542,7 +2542,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui"
|
name = "gpui"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"as-raw-xcb-connection",
|
"as-raw-xcb-connection",
|
||||||
@@ -2644,7 +2644,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui_macros"
|
name = "gpui_macros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -2655,7 +2655,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui_tokio"
|
name = "gpui_tokio"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"gpui",
|
"gpui",
|
||||||
@@ -2877,7 +2877,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "http_client"
|
name = "http_client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-compression",
|
"async-compression",
|
||||||
@@ -2902,7 +2902,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "http_client_tls"
|
name = "http_client_tls"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls",
|
"rustls",
|
||||||
"rustls-platform-verifier",
|
"rustls-platform-verifier",
|
||||||
@@ -2997,9 +2997,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.64"
|
version = "0.1.65"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
|
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android_system_properties",
|
"android_system_properties",
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
@@ -3663,7 +3663,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "media"
|
name = "media"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bindgen",
|
"bindgen",
|
||||||
@@ -4264,9 +4264,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oneshot"
|
name = "oneshot"
|
||||||
version = "0.1.12"
|
version = "0.1.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3ce66197e99546da6c6d991285f605192e794ceae69686c17163844a7bf8fcc2"
|
checksum = "269bca4c2591a28585d6bf10d9ed0332b7d76900a1b02bec41bdc3a2cdcda107"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oo7"
|
name = "oo7"
|
||||||
@@ -4502,7 +4502,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "perf"
|
name = "perf"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"collections",
|
"collections",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -5137,7 +5137,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "refineable"
|
name = "refineable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_refineable",
|
"derive_refineable",
|
||||||
]
|
]
|
||||||
@@ -5236,7 +5236,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest_client"
|
name = "reqwest_client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -5290,7 +5290,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "rope"
|
name = "rope"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"log",
|
"log",
|
||||||
@@ -5569,7 +5569,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "scheduler"
|
name = "scheduler"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-task",
|
"async-task",
|
||||||
"backtrace",
|
"backtrace",
|
||||||
@@ -5942,9 +5942,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "1.0.1"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "skrifa"
|
name = "skrifa"
|
||||||
@@ -6161,7 +6161,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "sum_tree"
|
name = "sum_tree"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"log",
|
"log",
|
||||||
@@ -7102,7 +7102,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "util"
|
name = "util"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-fs",
|
"async-fs",
|
||||||
@@ -7140,7 +7140,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "util_macros"
|
name = "util_macros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"perf",
|
"perf",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -8521,18 +8521,18 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.33"
|
version = "0.8.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd"
|
checksum = "fdea86ddd5568519879b8187e1cf04e24fce28f7fe046ceecbce472ff19a2572"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.8.33"
|
version = "0.8.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1"
|
checksum = "0c15e1b46eff7c6c91195752e0eeed8ef040e391cdece7c25376957d5f15df22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -8616,7 +8616,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "zlog"
|
name = "zlog"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -8633,7 +8633,7 @@ checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "ztracing"
|
name = "ztracing"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
@@ -8644,7 +8644,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "ztracing_macro"
|
name = "ztracing_macro"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#aceff52f8a93a31009d6f5284253f0b334a043dc"
|
source = "git+https://github.com/zed-industries/zed#1870425b2b262e3f28c90931782aba435afd5b99"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zune-core"
|
name = "zune-core"
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
pub mod compose;
|
pub mod compose;
|
||||||
|
pub mod profile;
|
||||||
pub mod screening;
|
pub mod screening;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use gpui::{
|
|||||||
};
|
};
|
||||||
use gpui_tokio::Tokio;
|
use gpui_tokio::Tokio;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use person::{Person, PersonRegistry};
|
use person::PersonRegistry;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use state::NostrRegistry;
|
use state::NostrRegistry;
|
||||||
use theme::ActiveTheme;
|
use theme::ActiveTheme;
|
||||||
@@ -17,13 +17,13 @@ use ui::avatar::Avatar;
|
|||||||
use ui::button::{Button, ButtonVariants};
|
use ui::button::{Button, ButtonVariants};
|
||||||
use ui::{h_flex, v_flex, Icon, IconName, Sizable, StyledExt};
|
use ui::{h_flex, v_flex, Icon, IconName, Sizable, StyledExt};
|
||||||
|
|
||||||
pub fn init(public_key: PublicKey, window: &mut Window, cx: &mut App) -> Entity<ProfileViewer> {
|
pub fn init(public_key: PublicKey, window: &mut Window, cx: &mut App) -> Entity<ProfileDialog> {
|
||||||
cx.new(|cx| ProfileViewer::new(public_key, window, cx))
|
cx.new(|cx| ProfileDialog::new(public_key, window, cx))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ProfileViewer {
|
pub struct ProfileDialog {
|
||||||
profile: Person,
|
public_key: PublicKey,
|
||||||
|
|
||||||
/// Follow status
|
/// Follow status
|
||||||
followed: bool,
|
followed: bool,
|
||||||
@@ -38,13 +38,13 @@ pub struct ProfileViewer {
|
|||||||
_tasks: SmallVec<[Task<()>; 1]>,
|
_tasks: SmallVec<[Task<()>; 1]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProfileViewer {
|
impl ProfileDialog {
|
||||||
pub fn new(target: PublicKey, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
pub fn new(public_key: PublicKey, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
let client = nostr.read(cx).client();
|
let client = nostr.read(cx).client();
|
||||||
|
|
||||||
let persons = PersonRegistry::global(cx);
|
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![];
|
let mut tasks = smallvec![];
|
||||||
|
|
||||||
@@ -53,12 +53,12 @@ impl ProfileViewer {
|
|||||||
let public_key = signer.get_public_key().await?;
|
let public_key = signer.get_public_key().await?;
|
||||||
let contact_list = client.database().contacts_public_keys(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 {
|
let verify_nip05 = if let Some(address) = profile.metadata().nip05 {
|
||||||
Some(Tokio::spawn(cx, async move {
|
Some(Tokio::spawn(cx, async move {
|
||||||
nip05_verify(target, &address).await.unwrap_or(false)
|
nip05_verify(public_key, &address).await.unwrap_or(false)
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -90,7 +90,7 @@ impl ProfileViewer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
profile,
|
public_key,
|
||||||
followed: false,
|
followed: false,
|
||||||
verified: false,
|
verified: false,
|
||||||
copied: false,
|
copied: false,
|
||||||
@@ -98,12 +98,18 @@ impl ProfileViewer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn address(&self, _cx: &Context<Self>) -> Option<String> {
|
fn address(&self, cx: &Context<Self>) -> Option<String> {
|
||||||
self.profile.metadata().nip05
|
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>) {
|
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);
|
let item = ClipboardItem::new_string(bech32);
|
||||||
cx.write_to_clipboard(item);
|
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 {
|
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);
|
let shared_bech32 = SharedString::from(bech32);
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
@@ -146,14 +154,14 @@ impl Render for ProfileViewer {
|
|||||||
.items_center()
|
.items_center()
|
||||||
.justify_center()
|
.justify_center()
|
||||||
.text_center()
|
.text_center()
|
||||||
.child(Avatar::new(self.profile.avatar()).size(rems(4.)))
|
.child(Avatar::new(profile.avatar()).size(rems(4.)))
|
||||||
.child(
|
.child(
|
||||||
v_flex()
|
v_flex()
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.font_semibold()
|
.font_semibold()
|
||||||
.line_height(relative(1.25))
|
.line_height(relative(1.25))
|
||||||
.child(self.profile.name()),
|
.child(profile.name()),
|
||||||
)
|
)
|
||||||
.when_some(self.address(cx), |this, address| {
|
.when_some(self.address(cx), |this, address| {
|
||||||
this.child(
|
this.child(
|
||||||
@@ -208,7 +216,7 @@ impl Render for ProfileViewer {
|
|||||||
.rounded(cx.theme().radius)
|
.rounded(cx.theme().radius)
|
||||||
.bg(cx.theme().elevated_surface_background)
|
.bg(cx.theme().elevated_surface_background)
|
||||||
.child(
|
.child(
|
||||||
self.profile
|
profile
|
||||||
.metadata()
|
.metadata()
|
||||||
.about
|
.about
|
||||||
.map(SharedString::from)
|
.map(SharedString::from)
|
||||||
@@ -15,7 +15,6 @@ mod actions;
|
|||||||
mod dialogs;
|
mod dialogs;
|
||||||
mod panels;
|
mod panels;
|
||||||
mod sidebar;
|
mod sidebar;
|
||||||
mod user;
|
|
||||||
mod workspace;
|
mod workspace;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ impl Render for GreeterPanel {
|
|||||||
.gap_2()
|
.gap_2()
|
||||||
.when(relay_list_state == RelayState::NotSet, |this| {
|
.when(relay_list_state == RelayState::NotSet, |this| {
|
||||||
this.child(
|
this.child(
|
||||||
Button::new("connect")
|
Button::new("relaylist")
|
||||||
.icon(Icon::new(IconName::Door))
|
.icon(Icon::new(IconName::Door))
|
||||||
.label("Set up relay list")
|
.label("Set up relay list")
|
||||||
.ghost()
|
.ghost()
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ pub struct ImportPanel {
|
|||||||
|
|
||||||
impl ImportPanel {
|
impl ImportPanel {
|
||||||
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
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 pass_input = cx.new(|cx| InputState::new(window, cx).masked(true));
|
||||||
|
|
||||||
let error = cx.new(|_| None);
|
let error = cx.new(|_| None);
|
||||||
|
|||||||
@@ -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,
|
|
||||||
);
|
|
||||||
})),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,17 +11,16 @@ use gpui::{
|
|||||||
IntoElement, ParentElement, Render, SharedString, Styled, Subscription, Window,
|
IntoElement, ParentElement, Render, SharedString, Styled, Subscription, Window,
|
||||||
};
|
};
|
||||||
use nostr_connect::prelude::*;
|
use nostr_connect::prelude::*;
|
||||||
use person::PersonRegistry;
|
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use theme::{ActiveTheme, Theme, ThemeRegistry};
|
use theme::{ActiveTheme, Theme, ThemeRegistry};
|
||||||
use ui::button::{Button, ButtonVariants};
|
use ui::button::{Button, ButtonVariants};
|
||||||
use ui::modal::ModalButtonProps;
|
use ui::modal::ModalButtonProps;
|
||||||
use ui::{h_flex, v_flex, Root, Sizable, WindowExtension};
|
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::panels::greeter;
|
||||||
use crate::user::viewer;
|
use crate::sidebar;
|
||||||
use crate::{sidebar, user};
|
|
||||||
|
|
||||||
pub fn init(window: &mut Window, cx: &mut App) -> Entity<Workspace> {
|
pub fn init(window: &mut Window, cx: &mut App) -> Entity<Workspace> {
|
||||||
cx.new(|cx| Workspace::new(window, cx))
|
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>) {
|
fn on_themes(&mut self, _ev: &Themes, 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);
|
||||||
@@ -255,7 +207,7 @@ impl Workspace {
|
|||||||
|
|
||||||
fn on_open_pubkey(&mut self, ev: &OpenPublicKey, window: &mut Window, cx: &mut Context<Self>) {
|
fn on_open_pubkey(&mut self, ev: &OpenPublicKey, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
let public_key = ev.0;
|
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| {
|
window.open_modal(cx, move |this, _window, _cx| {
|
||||||
this.alert()
|
this.alert()
|
||||||
@@ -319,7 +271,6 @@ impl Render for Workspace {
|
|||||||
|
|
||||||
div()
|
div()
|
||||||
.id(SharedString::from("workspace"))
|
.id(SharedString::from("workspace"))
|
||||||
.on_action(cx.listener(Self::on_profile))
|
|
||||||
.on_action(cx.listener(Self::on_themes))
|
.on_action(cx.listener(Self::on_themes))
|
||||||
.on_action(cx.listener(Self::on_sign_out))
|
.on_action(cx.listener(Self::on_sign_out))
|
||||||
.on_action(cx.listener(Self::on_open_pubkey))
|
.on_action(cx.listener(Self::on_open_pubkey))
|
||||||
|
|||||||
Reference in New Issue
Block a user