Continue redesign for the v1 stable release #5
78
Cargo.lock
generated
78
Cargo.lock
generated
@@ -601,9 +601,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "avif-serialize"
|
||||
version = "0.8.6"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f"
|
||||
checksum = "375082f007bd67184fb9c0374614b29f9aaa604ec301635f72338bb65386a53d"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
@@ -620,9 +620,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-sys"
|
||||
version = "0.37.0"
|
||||
version = "0.37.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c34dda4df7017c8db52132f0f8a2e0f8161649d15723ed63fc00c82d0f2081a"
|
||||
checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cmake",
|
||||
@@ -1142,9 +1142,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.57"
|
||||
version = "4.5.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a"
|
||||
checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -1152,9 +1152,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.57"
|
||||
version = "4.5.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238"
|
||||
checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -1176,9 +1176,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.7"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
|
||||
checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
@@ -1263,7 +1263,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "collections"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"rustc-hash 2.1.1",
|
||||
@@ -1708,7 +1708,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "derive_refineable"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2639,7 +2639,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gpui"
|
||||
version = "0.2.2"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"as-raw-xcb-connection",
|
||||
@@ -2741,7 +2741,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gpui_macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
@@ -2752,7 +2752,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "gpui_tokio"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"gpui",
|
||||
@@ -2987,7 +2987,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "http_client"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-compression",
|
||||
@@ -3012,7 +3012,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "http_client_tls"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"rustls-platform-verifier",
|
||||
@@ -3567,7 +3567,7 @@ checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"libc",
|
||||
"redox_syscall 0.7.0",
|
||||
"redox_syscall 0.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3780,7 +3780,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "media"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bindgen",
|
||||
@@ -4020,7 +4020,7 @@ checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
|
||||
[[package]]
|
||||
name = "nostr"
|
||||
version = "0.44.1"
|
||||
source = "git+https://github.com/rust-nostr/nostr#aeee536bdec863afffffe4819150230e20b8ad6b"
|
||||
source = "git+https://github.com/rust-nostr/nostr#b968620ae4b8c31ee1cbcdb8ef8ec9ccd87e1fc6"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"base64",
|
||||
@@ -4045,7 +4045,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "nostr-connect"
|
||||
version = "0.44.0"
|
||||
source = "git+https://github.com/rust-nostr/nostr#aeee536bdec863afffffe4819150230e20b8ad6b"
|
||||
source = "git+https://github.com/rust-nostr/nostr#b968620ae4b8c31ee1cbcdb8ef8ec9ccd87e1fc6"
|
||||
dependencies = [
|
||||
"async-utility",
|
||||
"futures-core",
|
||||
@@ -4058,7 +4058,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "nostr-database"
|
||||
version = "0.44.0"
|
||||
source = "git+https://github.com/rust-nostr/nostr#aeee536bdec863afffffe4819150230e20b8ad6b"
|
||||
source = "git+https://github.com/rust-nostr/nostr#b968620ae4b8c31ee1cbcdb8ef8ec9ccd87e1fc6"
|
||||
dependencies = [
|
||||
"btreecap",
|
||||
"flatbuffers",
|
||||
@@ -4070,7 +4070,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "nostr-gossip"
|
||||
version = "0.44.0"
|
||||
source = "git+https://github.com/rust-nostr/nostr#aeee536bdec863afffffe4819150230e20b8ad6b"
|
||||
source = "git+https://github.com/rust-nostr/nostr#b968620ae4b8c31ee1cbcdb8ef8ec9ccd87e1fc6"
|
||||
dependencies = [
|
||||
"nostr",
|
||||
]
|
||||
@@ -4078,7 +4078,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "nostr-gossip-memory"
|
||||
version = "0.44.0"
|
||||
source = "git+https://github.com/rust-nostr/nostr#aeee536bdec863afffffe4819150230e20b8ad6b"
|
||||
source = "git+https://github.com/rust-nostr/nostr#b968620ae4b8c31ee1cbcdb8ef8ec9ccd87e1fc6"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"lru",
|
||||
@@ -4090,7 +4090,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "nostr-lmdb"
|
||||
version = "0.44.0"
|
||||
source = "git+https://github.com/rust-nostr/nostr#aeee536bdec863afffffe4819150230e20b8ad6b"
|
||||
source = "git+https://github.com/rust-nostr/nostr#b968620ae4b8c31ee1cbcdb8ef8ec9ccd87e1fc6"
|
||||
dependencies = [
|
||||
"async-utility",
|
||||
"flume",
|
||||
@@ -4104,7 +4104,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "nostr-sdk"
|
||||
version = "0.44.1"
|
||||
source = "git+https://github.com/rust-nostr/nostr#aeee536bdec863afffffe4819150230e20b8ad6b"
|
||||
source = "git+https://github.com/rust-nostr/nostr#b968620ae4b8c31ee1cbcdb8ef8ec9ccd87e1fc6"
|
||||
dependencies = [
|
||||
"async-utility",
|
||||
"async-wsocket",
|
||||
@@ -4638,7 +4638,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
[[package]]
|
||||
name = "perf"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"collections",
|
||||
"serde",
|
||||
@@ -5258,9 +5258,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.7.0"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
|
||||
checksum = "35985aa610addc02e24fc232012c86fd11f14111180f902b67e2d5331f8ebf2b"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
]
|
||||
@@ -5299,7 +5299,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "refineable"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"derive_refineable",
|
||||
]
|
||||
@@ -5398,7 +5398,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "reqwest_client"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -5453,7 +5453,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rope"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"log",
|
||||
@@ -5715,7 +5715,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "scheduler"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"backtrace",
|
||||
@@ -6330,7 +6330,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
[[package]]
|
||||
name = "sum_tree"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"log",
|
||||
@@ -7297,7 +7297,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
[[package]]
|
||||
name = "util"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-fs",
|
||||
@@ -7335,7 +7335,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "util_macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"perf",
|
||||
"quote",
|
||||
@@ -8936,7 +8936,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "zlog"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@@ -8953,7 +8953,7 @@ checksum = "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7"
|
||||
[[package]]
|
||||
name = "ztracing"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
@@ -8964,7 +8964,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ztracing_macro"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zed-industries/zed#6cd7586c161b579ba7c1ecad7dea1b95ca3dd239"
|
||||
source = "git+https://github.com/zed-industries/zed#ee3f40fe25d206ca363b753e5b86e09ac6181eca"
|
||||
|
||||
[[package]]
|
||||
name = "zune-core"
|
||||
|
||||
@@ -16,9 +16,10 @@ gpui_tokio = { git = "https://github.com/zed-industries/zed" }
|
||||
reqwest_client = { git = "https://github.com/zed-industries/zed" }
|
||||
|
||||
# Nostr
|
||||
nostr = { git = "https://github.com/rust-nostr/nostr", features = [ "nip96", "nip59", "nip49", "nip44" ] }
|
||||
nostr-sdk = { git = "https://github.com/rust-nostr/nostr" }
|
||||
nostr-lmdb = { git = "https://github.com/rust-nostr/nostr" }
|
||||
nostr-connect = { git = "https://github.com/rust-nostr/nostr" }
|
||||
nostr-sdk = { git = "https://github.com/rust-nostr/nostr", features = [ "nip96", "nip59", "nip49", "nip44" ] }
|
||||
nostr-gossip-memory = { git = "https://github.com/rust-nostr/nostr" }
|
||||
|
||||
# Others
|
||||
|
||||
@@ -6,6 +6,7 @@ publish.workspace = true
|
||||
|
||||
[dependencies]
|
||||
gpui.workspace = true
|
||||
nostr.workspace = true
|
||||
nostr-sdk.workspace = true
|
||||
|
||||
anyhow.workspace = true
|
||||
@@ -19,4 +20,3 @@ log.workspace = true
|
||||
|
||||
dirs = "5.0"
|
||||
qrcode = "0.14.1"
|
||||
nostr = { git = "https://github.com/rust-nostr/nostr" }
|
||||
|
||||
@@ -32,10 +32,10 @@ impl GreeterPanel {
|
||||
|
||||
fn add_profile_panel(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let signer_pkey = nostr.read(cx).signer_pkey(cx);
|
||||
let signer = nostr.read(cx).signer();
|
||||
|
||||
if let Some(public_key) = signer.public_key() {
|
||||
cx.spawn_in(window, async move |_this, cx| {
|
||||
if let Ok(public_key) = signer_pkey.await {
|
||||
cx.update(|window, cx| {
|
||||
Workspace::add_panel(
|
||||
profile::init(public_key, window, cx),
|
||||
@@ -45,10 +45,10 @@ impl GreeterPanel {
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Panel for GreeterPanel {
|
||||
@@ -84,6 +84,8 @@ impl Render for GreeterPanel {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let nip65_state = nostr.read(cx).nip65_state();
|
||||
let nip17_state = nostr.read(cx).nip17_state();
|
||||
let signer = nostr.read(cx).signer();
|
||||
let owned = signer.owned();
|
||||
|
||||
let required_actions = nip65_state.read(cx) == &RelayState::NotConfigured
|
||||
|| nip17_state.read(cx) == &RelayState::NotConfigured;
|
||||
@@ -186,7 +188,7 @@ impl Render for GreeterPanel {
|
||||
),
|
||||
)
|
||||
})
|
||||
.when(!nostr.read(cx).owned_signer(), |this| {
|
||||
.when(!owned, |this| {
|
||||
this.child(
|
||||
v_flex()
|
||||
.gap_2()
|
||||
|
||||
@@ -321,13 +321,13 @@ impl Sidebar {
|
||||
let async_chat = chat.downgrade();
|
||||
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let signer_pkey = nostr.read(cx).signer_pkey(cx);
|
||||
let signer = nostr.read(cx).signer();
|
||||
|
||||
// Get all selected public keys
|
||||
let receivers = self.get_selected(cx);
|
||||
|
||||
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
|
||||
let public_key = signer_pkey.await?;
|
||||
let public_key = signer.get_public_key().await?;
|
||||
|
||||
// Create a new room and emit it
|
||||
async_chat.update_in(cx, |this, _window, cx| {
|
||||
|
||||
@@ -2,14 +2,13 @@ use std::sync::Arc;
|
||||
|
||||
use chat::{ChatEvent, ChatRegistry};
|
||||
use dock::dock::DockPlacement;
|
||||
use dock::panel::PanelView;
|
||||
use dock::panel::{PanelStyle, PanelView};
|
||||
use dock::{ClosePanel, DockArea, DockItem};
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
div, rems, App, AppContext, Axis, Context, Entity, InteractiveElement, IntoElement,
|
||||
ParentElement, Render, SharedString, Styled, Subscription, Window,
|
||||
};
|
||||
use nostr_sdk::prelude::*;
|
||||
use person::PersonRegistry;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use state::{NostrRegistry, RelayState};
|
||||
@@ -34,24 +33,15 @@ pub struct Workspace {
|
||||
/// App's Dock Area
|
||||
dock: Entity<DockArea>,
|
||||
|
||||
/// Current User
|
||||
current_user: Entity<Option<PublicKey>>,
|
||||
|
||||
/// Event subscriptions
|
||||
_subscriptions: SmallVec<[Subscription; 3]>,
|
||||
}
|
||||
|
||||
impl Workspace {
|
||||
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let titlebar = cx.new(|_| TitleBar::new());
|
||||
let dock =
|
||||
cx.new(|cx| DockArea::new(window, cx).panel_style(dock::panel::PanelStyle::TabBar));
|
||||
|
||||
let chat = ChatRegistry::global(cx);
|
||||
let current_user = cx.new(|_| None);
|
||||
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let nip65_state = nostr.read(cx).nip65_state();
|
||||
let titlebar = cx.new(|_| TitleBar::new());
|
||||
let dock = cx.new(|cx| DockArea::new(window, cx).style(PanelStyle::TabBar));
|
||||
|
||||
let mut subscriptions = smallvec![];
|
||||
|
||||
@@ -99,15 +89,6 @@ impl Workspace {
|
||||
}),
|
||||
);
|
||||
|
||||
subscriptions.push(
|
||||
// Observe the NIP-65 state
|
||||
cx.observe(&nip65_state, move |this, state, cx| {
|
||||
if state.read(cx).idle() || state.read(cx).checking() {
|
||||
this.get_current_user(cx);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
// Set the default layout for app's dock
|
||||
cx.defer_in(window, |this, window, cx| {
|
||||
this.set_layout(window, cx);
|
||||
@@ -116,7 +97,6 @@ impl Workspace {
|
||||
Self {
|
||||
titlebar,
|
||||
dock,
|
||||
current_user,
|
||||
_subscriptions: subscriptions,
|
||||
}
|
||||
}
|
||||
@@ -181,37 +161,19 @@ impl Workspace {
|
||||
});
|
||||
}
|
||||
|
||||
fn get_current_user(&self, cx: &mut Context<Self>) {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let client = nostr.read(cx).client();
|
||||
let current_user = self.current_user.downgrade();
|
||||
|
||||
cx.spawn(async move |_this, cx| {
|
||||
if let Some(signer) = client.signer() {
|
||||
if let Ok(public_key) = signer.get_public_key().await {
|
||||
current_user
|
||||
.update(cx, |this, cx| {
|
||||
*this = Some(public_key);
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn titlebar_left(&mut self, _window: &mut Window, cx: &Context<Self>) -> impl IntoElement {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let nip65 = nostr.read(cx).nip65_state();
|
||||
let nip17 = nostr.read(cx).nip17_state();
|
||||
let signer = nostr.read(cx).signer();
|
||||
let current_user = signer.public_key();
|
||||
|
||||
h_flex()
|
||||
.h(TITLEBAR_HEIGHT)
|
||||
.flex_shrink_0()
|
||||
.justify_between()
|
||||
.gap_2()
|
||||
.when_some(self.current_user.read(cx).as_ref(), |this, public_key| {
|
||||
.when_some(current_user.as_ref(), |this, public_key| {
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let profile = persons.read(cx).get(public_key, cx);
|
||||
|
||||
@@ -232,6 +194,19 @@ impl Workspace {
|
||||
}),
|
||||
)
|
||||
})
|
||||
.when(nostr.read(cx).creating_signer(), |this| {
|
||||
this.child(div().text_xs().text_color(cx.theme().text_muted).child(
|
||||
SharedString::from("Coop is creating a new identity for you..."),
|
||||
))
|
||||
})
|
||||
.when(!nostr.read(cx).connected(), |this| {
|
||||
this.child(
|
||||
div()
|
||||
.text_xs()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(SharedString::from("Connecting...")),
|
||||
)
|
||||
})
|
||||
.map(|this| match nip65.read(cx) {
|
||||
RelayState::Checking => this.child(
|
||||
div()
|
||||
@@ -247,7 +222,7 @@ impl Workspace {
|
||||
.text_xs()
|
||||
.text_color(cx.theme().warning_foreground)
|
||||
.bg(cx.theme().warning_background)
|
||||
.rounded_xs()
|
||||
.rounded_sm()
|
||||
.child(SharedString::from("User hasn't configured a relay list")),
|
||||
),
|
||||
_ => this,
|
||||
@@ -266,7 +241,7 @@ impl Workspace {
|
||||
.text_xs()
|
||||
.text_color(cx.theme().warning_foreground)
|
||||
.bg(cx.theme().warning_background)
|
||||
.rounded_xs()
|
||||
.rounded_sm()
|
||||
.child(SharedString::from(
|
||||
"User hasn't configured a messaging relay list",
|
||||
)),
|
||||
|
||||
@@ -351,7 +351,7 @@ impl DockArea {
|
||||
}
|
||||
|
||||
/// Set the panel style of the dock area.
|
||||
pub fn panel_style(mut self, style: PanelStyle) -> Self {
|
||||
pub fn style(mut self, style: PanelStyle) -> Self {
|
||||
self.panel_style = style;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -37,13 +37,12 @@ pub const USER_GIFTWRAP: &str = "user-gift-wraps";
|
||||
pub const WOT_RELAYS: [&str; 1] = ["wss://relay.vertexlab.io"];
|
||||
|
||||
/// Default search relays
|
||||
pub const SEARCH_RELAYS: [&str; 2] = ["wss://antiprimal.net", "wss://relay.noswhere.com"];
|
||||
pub const SEARCH_RELAYS: [&str; 1] = ["wss://antiprimal.net"];
|
||||
|
||||
/// Default bootstrap relays
|
||||
pub const BOOTSTRAP_RELAYS: [&str; 4] = [
|
||||
pub const BOOTSTRAP_RELAYS: [&str; 3] = [
|
||||
"wss://relay.damus.io",
|
||||
"wss://relay.primal.net",
|
||||
"wss://relay.nos.social",
|
||||
"wss://user.kindpag.es",
|
||||
];
|
||||
|
||||
|
||||
@@ -48,14 +48,15 @@ pub struct NostrRegistry {
|
||||
/// Nostr client
|
||||
client: Client,
|
||||
|
||||
/// Whether the bootstrapping relays is connected
|
||||
connected: bool,
|
||||
|
||||
/// Whether coop is creating a default signer
|
||||
creating_signer: bool,
|
||||
|
||||
/// Nostr signer
|
||||
signer: Arc<CoopSigner>,
|
||||
|
||||
/// By default, Coop generates a new signer for new users.
|
||||
///
|
||||
/// This flag indicates whether the signer is user-owned or Coop-generated.
|
||||
owned_signer: bool,
|
||||
|
||||
/// NIP-65 relay state
|
||||
nip65: Entity<RelayState>,
|
||||
|
||||
@@ -129,16 +130,17 @@ impl NostrRegistry {
|
||||
cx.defer(|cx| {
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
|
||||
// Connect to the bootstrapping relays
|
||||
nostr.update(cx, |this, cx| {
|
||||
this.connect(cx);
|
||||
this.get_identity(cx);
|
||||
});
|
||||
});
|
||||
|
||||
Self {
|
||||
client,
|
||||
connected: false,
|
||||
creating_signer: false,
|
||||
signer,
|
||||
owned_signer: false,
|
||||
nip65,
|
||||
nip17,
|
||||
app_keys,
|
||||
@@ -151,19 +153,29 @@ impl NostrRegistry {
|
||||
fn connect(&mut self, cx: &mut Context<Self>) {
|
||||
let client = self.client();
|
||||
|
||||
self.tasks.push(cx.background_spawn(async move {
|
||||
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
|
||||
// Add search relay to the relay pool
|
||||
for url in SEARCH_RELAYS.into_iter() {
|
||||
client.add_relay(url).await?;
|
||||
client.add_relay(url).and_connect().await?;
|
||||
}
|
||||
|
||||
// Add bootstrap relay to the relay pool
|
||||
for url in BOOTSTRAP_RELAYS.into_iter() {
|
||||
client.add_relay(url).await?;
|
||||
client.add_relay(url).and_connect().await?;
|
||||
}
|
||||
|
||||
// Connect to all added relays
|
||||
client.connect().await;
|
||||
Ok(())
|
||||
});
|
||||
|
||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||
// Wait for the task to complete
|
||||
task.await?;
|
||||
|
||||
// Update the state
|
||||
this.update(cx, |this, cx| {
|
||||
this.set_connected(cx);
|
||||
this.get_signer(cx);
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}));
|
||||
@@ -174,22 +186,16 @@ impl NostrRegistry {
|
||||
self.client.clone()
|
||||
}
|
||||
|
||||
/// Get the nostr signer
|
||||
pub fn signer(&self) -> Arc<CoopSigner> {
|
||||
self.signer.clone()
|
||||
}
|
||||
|
||||
/// Get the app keys
|
||||
pub fn app_keys(&self) -> &Keys {
|
||||
&self.app_keys
|
||||
}
|
||||
|
||||
/// Returns whether the current signer is owned by user
|
||||
pub fn owned_signer(&self) -> bool {
|
||||
self.owned_signer
|
||||
}
|
||||
|
||||
/// Set whether the current signer is owned by user
|
||||
pub fn set_owned_signer(&mut self, owned: bool, cx: &mut Context<Self>) {
|
||||
self.owned_signer = owned;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Get the NIP-65 state
|
||||
pub fn nip65_state(&self) -> Entity<RelayState> {
|
||||
self.nip65.clone()
|
||||
@@ -200,16 +206,26 @@ impl NostrRegistry {
|
||||
self.nip17.clone()
|
||||
}
|
||||
|
||||
/// Get current signer's public key
|
||||
pub fn signer_pkey(&self, cx: &App) -> Task<Result<PublicKey, Error>> {
|
||||
let client = self.client();
|
||||
/// Get the connected state
|
||||
pub fn connected(&self) -> bool {
|
||||
self.connected
|
||||
}
|
||||
|
||||
cx.background_spawn(async move {
|
||||
let signer = client.signer().context("Signer not found")?;
|
||||
let public_key = signer.get_public_key().await?;
|
||||
/// Set the connected state
|
||||
fn set_connected(&mut self, cx: &mut Context<Self>) {
|
||||
self.connected = true;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
Ok(public_key)
|
||||
})
|
||||
/// Get the creating signer status
|
||||
pub fn creating_signer(&self) -> bool {
|
||||
self.creating_signer
|
||||
}
|
||||
|
||||
/// Set the creating signer status
|
||||
fn set_creating_signer(&mut self, status: bool, cx: &mut Context<Self>) {
|
||||
self.creating_signer = status;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Get a relay hint (messaging relay) for a given public key
|
||||
@@ -290,18 +306,17 @@ impl NostrRegistry {
|
||||
T: NostrSigner + 'static,
|
||||
{
|
||||
let client = self.client();
|
||||
let signer = self.signer.clone();
|
||||
let signer = self.signer();
|
||||
|
||||
// Create a task to update the signer and verify the public key
|
||||
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
|
||||
// Update signer
|
||||
signer.switch(new).await;
|
||||
signer.switch(new, owned).await;
|
||||
|
||||
// Verify signer
|
||||
let signer = client.signer().context("Signer not found")?;
|
||||
let public_key = signer.get_public_key().await?;
|
||||
|
||||
log::info!("Signer's public key: {public_key}");
|
||||
log::info!("Signer's public key: {}", public_key);
|
||||
|
||||
Ok(())
|
||||
});
|
||||
@@ -313,8 +328,6 @@ impl NostrRegistry {
|
||||
// Update states
|
||||
this.update(cx, |this, cx| {
|
||||
this.reset_relay_states(cx);
|
||||
this.get_relay_list(cx);
|
||||
this.set_owned_signer(owned, cx);
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
@@ -615,83 +628,61 @@ impl NostrRegistry {
|
||||
})
|
||||
}
|
||||
|
||||
/// Get local stored identity
|
||||
fn get_identity(&mut self, cx: &mut Context<Self>) {
|
||||
let read_credential = cx.read_credentials(KEYRING);
|
||||
|
||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||
match read_credential.await {
|
||||
Ok(Some((_, secret))) => {
|
||||
let secret = SecretKey::from_slice(&secret)?;
|
||||
let keys = Keys::new(secret);
|
||||
|
||||
this.update(cx, |this, cx| {
|
||||
this.set_signer(keys, false, cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
_ => {
|
||||
this.update(cx, |this, cx| {
|
||||
this.get_bunker(cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
|
||||
/// Create a new identity
|
||||
fn create_identity(&mut self, cx: &mut Context<Self>) {
|
||||
fn set_default_signer(&mut self, cx: &mut Context<Self>) {
|
||||
let client = self.client();
|
||||
let keys = Keys::generate();
|
||||
let async_keys = keys.clone();
|
||||
|
||||
// Get write credential task
|
||||
// Create a write credential task
|
||||
let write_credential = cx.write_credentials(
|
||||
KEYRING,
|
||||
&keys.public_key().to_hex(),
|
||||
&keys.secret_key().to_secret_bytes(),
|
||||
);
|
||||
|
||||
// Update the signer
|
||||
self.set_signer(keys, false, cx);
|
||||
|
||||
// Set the creating signer status
|
||||
self.set_creating_signer(true, cx);
|
||||
|
||||
// Run async tasks in background
|
||||
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
|
||||
// Build and sign the relay list event
|
||||
let signer = client.signer().context("Signer not found")?;
|
||||
|
||||
// Get default relay list
|
||||
let relay_list = default_relay_list();
|
||||
let event = EventBuilder::relay_list(relay_list)
|
||||
.sign(&async_keys)
|
||||
.await?;
|
||||
|
||||
// Publish relay list event
|
||||
client.send_event(&event).await?;
|
||||
let event = EventBuilder::relay_list(relay_list).sign(signer).await?;
|
||||
let output = client.send_event(&event).broadcast().await?;
|
||||
log::info!("Published relay list event: {:?}", output.id());
|
||||
|
||||
// Build and sign the metadata event
|
||||
// Construct the default metadata
|
||||
let name = petname::petname(2, "-").unwrap_or("Cooper".to_string());
|
||||
let avatar = Url::parse(&format!("https://avatar.vercel.sh/{name}")).unwrap();
|
||||
let metadata = Metadata::new().display_name(&name).picture(avatar);
|
||||
let event = EventBuilder::metadata(&metadata).sign(&async_keys).await?;
|
||||
|
||||
// Publish metadata event
|
||||
client.send_event(&event).await?;
|
||||
let event = EventBuilder::metadata(&metadata).sign(signer).await?;
|
||||
let output = client.send_event(&event).broadcast().await?;
|
||||
log::info!("Published metadata event: {:?}", output.id());
|
||||
|
||||
// Build and sign the contact list event
|
||||
// Construct the default contact list
|
||||
let contacts = vec![Contact::new(PublicKey::parse(COOP_PUBKEY).unwrap())];
|
||||
let event = EventBuilder::contact_list(contacts)
|
||||
.sign(&async_keys)
|
||||
.await?;
|
||||
|
||||
// Publish contact list event
|
||||
client.send_event(&event).await?;
|
||||
let event = EventBuilder::contact_list(contacts).sign(signer).await?;
|
||||
let output = client.send_event(&event).broadcast().await?;
|
||||
log::info!("Published contact list event: {:?}", output.id());
|
||||
|
||||
// Build and sign the messaging relay list event
|
||||
// Construct the default messaging relay list
|
||||
let relays = default_messaging_relays();
|
||||
let event = EventBuilder::nip17_relay_list(relays)
|
||||
.sign(&async_keys)
|
||||
.await?;
|
||||
|
||||
// Publish messaging relay list event
|
||||
client.send_event(&event).await?;
|
||||
let event = EventBuilder::nip17_relay_list(relays).sign(signer).await?;
|
||||
let output = client.send_event(&event).to_nip65().await?;
|
||||
log::info!("Published messaging relay list event: {:?}", output.id());
|
||||
|
||||
// Write user's credentials to the system keyring
|
||||
write_credential.await?;
|
||||
@@ -703,10 +694,36 @@ impl NostrRegistry {
|
||||
// Wait for the task to complete
|
||||
task.await?;
|
||||
|
||||
// Update the signer
|
||||
this.update(cx, |this, cx| {
|
||||
this.set_creating_signer(false, cx);
|
||||
this.get_relay_list(cx);
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}));
|
||||
}
|
||||
|
||||
/// Get local stored signer
|
||||
fn get_signer(&mut self, cx: &mut Context<Self>) {
|
||||
let read_credential = cx.read_credentials(KEYRING);
|
||||
|
||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||
match read_credential.await {
|
||||
Ok(Some((_user, secret))) => {
|
||||
let secret = SecretKey::from_slice(&secret)?;
|
||||
let keys = Keys::new(secret);
|
||||
|
||||
this.update(cx, |this, cx| {
|
||||
this.set_signer(keys, false, cx);
|
||||
this.get_relay_list(cx);
|
||||
})?;
|
||||
}
|
||||
_ => {
|
||||
this.update(cx, |this, cx| {
|
||||
this.get_bunker(cx);
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}));
|
||||
@@ -741,6 +758,7 @@ impl NostrRegistry {
|
||||
Ok(signer) => {
|
||||
this.update(cx, |this, cx| {
|
||||
this.set_signer(signer, true, cx);
|
||||
this.get_relay_list(cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
@@ -748,7 +766,7 @@ impl NostrRegistry {
|
||||
log::warn!("Failed to get bunker: {e}");
|
||||
// Create a new identity if no stored bunker exists
|
||||
this.update(cx, |this, cx| {
|
||||
this.create_identity(cx);
|
||||
this.set_default_signer(cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::borrow::Cow;
|
||||
use std::result::Result;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use nostr_sdk::prelude::*;
|
||||
@@ -8,6 +9,17 @@ use smol::lock::RwLock;
|
||||
#[derive(Debug)]
|
||||
pub struct CoopSigner {
|
||||
signer: RwLock<Arc<dyn NostrSigner>>,
|
||||
|
||||
/// Signer's public key
|
||||
signer_pkey: RwLock<Option<PublicKey>>,
|
||||
|
||||
/// Whether coop is creating a new identity
|
||||
creating: AtomicBool,
|
||||
|
||||
/// By default, Coop generates a new signer for new users.
|
||||
///
|
||||
/// This flag indicates whether the signer is user-owned or Coop-generated.
|
||||
owned: AtomicBool,
|
||||
}
|
||||
|
||||
impl CoopSigner {
|
||||
@@ -17,6 +29,9 @@ impl CoopSigner {
|
||||
{
|
||||
Self {
|
||||
signer: RwLock::new(signer.into_nostr_signer()),
|
||||
signer_pkey: RwLock::new(None),
|
||||
creating: AtomicBool::new(false),
|
||||
owned: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +40,39 @@ impl CoopSigner {
|
||||
self.signer.read().await.clone()
|
||||
}
|
||||
|
||||
/// Get public key
|
||||
pub fn public_key(&self) -> Option<PublicKey> {
|
||||
self.signer_pkey.read_blocking().to_owned()
|
||||
}
|
||||
|
||||
/// Get the flag indicating whether the signer is creating a new identity.
|
||||
pub fn creating(&self) -> bool {
|
||||
self.creating.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
/// Get the flag indicating whether the signer is user-owned.
|
||||
pub fn owned(&self) -> bool {
|
||||
self.owned.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
/// Switch the current signer to a new signer.
|
||||
pub async fn switch<T>(&self, new: T)
|
||||
pub async fn switch<T>(&self, new: T, owned: bool)
|
||||
where
|
||||
T: IntoNostrSigner,
|
||||
{
|
||||
let new_signer = new.into_nostr_signer();
|
||||
let public_key = new_signer.get_public_key().await.ok();
|
||||
let mut signer = self.signer.write().await;
|
||||
*signer = new.into_nostr_signer();
|
||||
let mut signer_pkey = self.signer_pkey.write().await;
|
||||
|
||||
// Switch to the new signer
|
||||
*signer = new_signer;
|
||||
|
||||
// Update the public key
|
||||
*signer_pkey = public_key;
|
||||
|
||||
// Update the owned flag
|
||||
self.owned.store(owned, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user