feat: verify dm relays when open chat panel
This commit is contained in:
295
Cargo.lock
generated
295
Cargo.lock
generated
@@ -443,31 +443,6 @@ dependencies = [
|
|||||||
"arrayvec",
|
"arrayvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aws-lc-rs"
|
|
||||||
version = "1.12.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4c2b7ddaa2c56a367ad27a094ad8ef4faacf8a617c2575acb2ba88949df999ca"
|
|
||||||
dependencies = [
|
|
||||||
"aws-lc-sys",
|
|
||||||
"paste",
|
|
||||||
"zeroize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aws-lc-sys"
|
|
||||||
version = "0.25.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "54ac4f13dad353b209b34cbec082338202cbc01c8f00336b55c750c13ac91f8f"
|
|
||||||
dependencies = [
|
|
||||||
"bindgen 0.69.5",
|
|
||||||
"cc",
|
|
||||||
"cmake",
|
|
||||||
"dunce",
|
|
||||||
"fs_extra",
|
|
||||||
"paste",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.74"
|
version = "0.3.74"
|
||||||
@@ -501,29 +476,6 @@ version = "0.11.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d"
|
checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bindgen"
|
|
||||||
version = "0.69.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.8.0",
|
|
||||||
"cexpr",
|
|
||||||
"clang-sys",
|
|
||||||
"itertools 0.12.1",
|
|
||||||
"lazy_static",
|
|
||||||
"lazycell",
|
|
||||||
"log",
|
|
||||||
"prettyplease",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"regex",
|
|
||||||
"rustc-hash 1.1.0",
|
|
||||||
"shlex",
|
|
||||||
"syn 2.0.98",
|
|
||||||
"which",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bindgen"
|
name = "bindgen"
|
||||||
version = "0.70.1"
|
version = "0.70.1"
|
||||||
@@ -887,12 +839,6 @@ dependencies = [
|
|||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cesu8"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cexpr"
|
name = "cexpr"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@@ -1006,9 +952,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.29"
|
version = "4.5.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184"
|
checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -1016,9 +962,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.29"
|
version = "4.5.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9"
|
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -1044,15 +990,6 @@ version = "0.7.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cmake"
|
|
||||||
version = "0.1.54"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cocoa"
|
name = "cocoa"
|
||||||
version = "0.25.0"
|
version = "0.25.0"
|
||||||
@@ -1126,7 +1063,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collections"
|
name = "collections"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#7ba1492f0af820eb8d558ba4c6b3c4f780be0de0"
|
source = "git+https://github.com/zed-industries/zed#c1f162abc6cb41a0c765aa76c3af3e83a994ce18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.1",
|
||||||
@@ -1144,16 +1081,6 @@ version = "1.0.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "combine"
|
|
||||||
version = "4.6.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "common"
|
name = "common"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -1453,7 +1380,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#7ba1492f0af820eb8d558ba4c6b3c4f780be0de0"
|
source = "git+https://github.com/zed-industries/zed#c1f162abc6cb41a0c765aa76c3af3e83a994ce18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1734,9 +1661,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "filedescriptor"
|
name = "filedescriptor"
|
||||||
version = "0.8.3"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d"
|
checksum = "7199d965852c3bac31f779ef99cbb4537f80e952e2d6aa0ffeb30cce00f4f46e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
@@ -1914,12 +1841,6 @@ dependencies = [
|
|||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fs_extra"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futf"
|
name = "futf"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -2184,13 +2105,13 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui"
|
name = "gpui"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#7ba1492f0af820eb8d558ba4c6b3c4f780be0de0"
|
source = "git+https://github.com/zed-industries/zed#c1f162abc6cb41a0c765aa76c3af3e83a994ce18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"as-raw-xcb-connection",
|
"as-raw-xcb-connection",
|
||||||
"ashpd",
|
"ashpd",
|
||||||
"async-task",
|
"async-task",
|
||||||
"bindgen 0.70.1",
|
"bindgen",
|
||||||
"blade-graphics",
|
"blade-graphics",
|
||||||
"blade-macros",
|
"blade-macros",
|
||||||
"blade-util",
|
"blade-util",
|
||||||
@@ -2271,7 +2192,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#7ba1492f0af820eb8d558ba4c6b3c4f780be0de0"
|
source = "git+https://github.com/zed-industries/zed#c1f162abc6cb41a0c765aa76c3af3e83a994ce18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2281,7 +2202,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#7ba1492f0af820eb8d558ba4c6b3c4f780be0de0"
|
source = "git+https://github.com/zed-industries/zed#c1f162abc6cb41a0c765aa76c3af3e83a994ce18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gpui",
|
"gpui",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -2449,15 +2370,6 @@ dependencies = [
|
|||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "home"
|
|
||||||
version = "0.5.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
|
|
||||||
dependencies = [
|
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "html-escape"
|
name = "html-escape"
|
||||||
version = "0.2.13"
|
version = "0.2.13"
|
||||||
@@ -2504,7 +2416,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#7ba1492f0af820eb8d558ba4c6b3c4f780be0de0"
|
source = "git+https://github.com/zed-industries/zed#c1f162abc6cb41a0c765aa76c3af3e83a994ce18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -2512,8 +2424,6 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"http",
|
"http",
|
||||||
"log",
|
"log",
|
||||||
"rustls",
|
|
||||||
"rustls-platform-verifier",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"url",
|
"url",
|
||||||
@@ -2907,28 +2817,6 @@ version = "1.0.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jni"
|
|
||||||
version = "0.21.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
|
|
||||||
dependencies = [
|
|
||||||
"cesu8",
|
|
||||||
"cfg-if",
|
|
||||||
"combine",
|
|
||||||
"jni-sys",
|
|
||||||
"log",
|
|
||||||
"thiserror 1.0.69",
|
|
||||||
"walkdir",
|
|
||||||
"windows-sys 0.45.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jni-sys"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobserver"
|
name = "jobserver"
|
||||||
version = "0.1.32"
|
version = "0.1.32"
|
||||||
@@ -2989,12 +2877,6 @@ dependencies = [
|
|||||||
"spin",
|
"spin",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazycell"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lebe"
|
name = "lebe"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@@ -3192,10 +3074,10 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "media"
|
name = "media"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#7ba1492f0af820eb8d558ba4c6b3c4f780be0de0"
|
source = "git+https://github.com/zed-industries/zed#c1f162abc6cb41a0c765aa76c3af3e83a994ce18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bindgen 0.70.1",
|
"bindgen",
|
||||||
"core-foundation 0.9.4",
|
"core-foundation 0.9.4",
|
||||||
"ctor",
|
"ctor",
|
||||||
"foreign-types",
|
"foreign-types",
|
||||||
@@ -3272,9 +3154,9 @@ checksum = "6367d84fb54d4242af283086402907277715b8fe46976963af5ebf173f8efba3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.4"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b"
|
checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler2",
|
"adler2",
|
||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
@@ -3377,7 +3259,7 @@ checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr"
|
name = "nostr"
|
||||||
version = "0.39.0"
|
version = "0.39.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b390bcf7bf15aaab4b8417c410779b059842c364"
|
source = "git+https://github.com/rust-nostr/nostr#6caf231eca951f2c6909382c46f43edffbd6e730"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"base64",
|
"base64",
|
||||||
@@ -3405,7 +3287,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-connect"
|
name = "nostr-connect"
|
||||||
version = "0.39.0"
|
version = "0.39.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b390bcf7bf15aaab4b8417c410779b059842c364"
|
source = "git+https://github.com/rust-nostr/nostr#6caf231eca951f2c6909382c46f43edffbd6e730"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"nostr",
|
"nostr",
|
||||||
@@ -3417,7 +3299,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-database"
|
name = "nostr-database"
|
||||||
version = "0.39.0"
|
version = "0.39.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b390bcf7bf15aaab4b8417c410779b059842c364"
|
source = "git+https://github.com/rust-nostr/nostr#6caf231eca951f2c6909382c46f43edffbd6e730"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flatbuffers",
|
"flatbuffers",
|
||||||
"lru",
|
"lru",
|
||||||
@@ -3428,7 +3310,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-lmdb"
|
name = "nostr-lmdb"
|
||||||
version = "0.39.0"
|
version = "0.39.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b390bcf7bf15aaab4b8417c410779b059842c364"
|
source = "git+https://github.com/rust-nostr/nostr#6caf231eca951f2c6909382c46f43edffbd6e730"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"heed",
|
"heed",
|
||||||
@@ -3441,7 +3323,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-relay-pool"
|
name = "nostr-relay-pool"
|
||||||
version = "0.39.0"
|
version = "0.39.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b390bcf7bf15aaab4b8417c410779b059842c364"
|
source = "git+https://github.com/rust-nostr/nostr#6caf231eca951f2c6909382c46f43edffbd6e730"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"async-wsocket",
|
"async-wsocket",
|
||||||
@@ -3458,7 +3340,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-sdk"
|
name = "nostr-sdk"
|
||||||
version = "0.39.0"
|
version = "0.39.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b390bcf7bf15aaab4b8417c410779b059842c364"
|
source = "git+https://github.com/rust-nostr/nostr#6caf231eca951f2c6909382c46f43edffbd6e730"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"nostr",
|
"nostr",
|
||||||
@@ -4495,7 +4377,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "refineable"
|
name = "refineable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#7ba1492f0af820eb8d558ba4c6b3c4f780be0de0"
|
source = "git+https://github.com/zed-industries/zed#c1f162abc6cb41a0c765aa76c3af3e83a994ce18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_refineable",
|
"derive_refineable",
|
||||||
]
|
]
|
||||||
@@ -4628,7 +4510,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#7ba1492f0af820eb8d558ba4c6b3c4f780be0de0"
|
source = "git+https://github.com/zed-industries/zed#c1f162abc6cb41a0c765aa76c3af3e83a994ce18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -4762,12 +4644,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.23"
|
version = "0.23.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395"
|
checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-lc-rs",
|
|
||||||
"log",
|
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"ring",
|
"ring",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
@@ -4806,40 +4686,12 @@ dependencies = [
|
|||||||
"web-time",
|
"web-time",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustls-platform-verifier"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e012c45844a1790332c9386ed4ca3a06def221092eda277e6f079728f8ea99da"
|
|
||||||
dependencies = [
|
|
||||||
"core-foundation 0.10.0",
|
|
||||||
"core-foundation-sys",
|
|
||||||
"jni",
|
|
||||||
"log",
|
|
||||||
"once_cell",
|
|
||||||
"rustls",
|
|
||||||
"rustls-native-certs",
|
|
||||||
"rustls-platform-verifier-android",
|
|
||||||
"rustls-webpki",
|
|
||||||
"security-framework",
|
|
||||||
"security-framework-sys",
|
|
||||||
"webpki-root-certs",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustls-platform-verifier-android"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
version = "0.102.8"
|
version = "0.102.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
|
checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-lc-rs",
|
|
||||||
"ring",
|
"ring",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"untrusted",
|
"untrusted",
|
||||||
@@ -5008,7 +4860,7 @@ checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "semantic_version"
|
name = "semantic_version"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#7ba1492f0af820eb8d558ba4c6b3c4f780be0de0"
|
source = "git+https://github.com/zed-industries/zed#c1f162abc6cb41a0c765aa76c3af3e83a994ce18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -5333,7 +5185,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#7ba1492f0af820eb8d558ba4c6b3c4f780be0de0"
|
source = "git+https://github.com/zed-industries/zed#c1f162abc6cb41a0c765aa76c3af3e83a994ce18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"log",
|
"log",
|
||||||
@@ -6203,7 +6055,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "util"
|
name = "util"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#7ba1492f0af820eb8d558ba4c6b3c4f780be0de0"
|
source = "git+https://github.com/zed-industries/zed#c1f162abc6cb41a0c765aa76c3af3e83a994ce18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-fs",
|
"async-fs",
|
||||||
@@ -6551,15 +6403,6 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "webpki-root-certs"
|
|
||||||
version = "0.26.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "09aed61f5e8d2c18344b3faa33a4c837855fe56642757754775548fee21386c4"
|
|
||||||
dependencies = [
|
|
||||||
"rustls-pki-types",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webpki-roots"
|
name = "webpki-roots"
|
||||||
version = "0.26.8"
|
version = "0.26.8"
|
||||||
@@ -6575,18 +6418,6 @@ version = "0.1.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
|
checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "which"
|
|
||||||
version = "4.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"home",
|
|
||||||
"once_cell",
|
|
||||||
"rustix",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
@@ -6702,15 +6533,6 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.45.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.42.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
@@ -6738,21 +6560,6 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-targets"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm 0.42.2",
|
|
||||||
"windows_aarch64_msvc 0.42.2",
|
|
||||||
"windows_i686_gnu 0.42.2",
|
|
||||||
"windows_i686_msvc 0.42.2",
|
|
||||||
"windows_x86_64_gnu 0.42.2",
|
|
||||||
"windows_x86_64_gnullvm 0.42.2",
|
|
||||||
"windows_x86_64_msvc 0.42.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -6784,12 +6591,6 @@ dependencies = [
|
|||||||
"windows_x86_64_msvc 0.52.6",
|
"windows_x86_64_msvc 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -6802,12 +6603,6 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -6820,12 +6615,6 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -6844,12 +6633,6 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -6862,12 +6645,6 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -6880,12 +6657,6 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -6898,12 +6669,6 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ use common::{
|
|||||||
utils::{compare, nip96_upload},
|
utils::{compare, nip96_upload},
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, img, list, prelude::FluentBuilder, px, white, AnyElement, App, AppContext, Context,
|
div, img, list, prelude::FluentBuilder, px, relative, svg, white, AnyElement, App, AppContext,
|
||||||
Element, Entity, EventEmitter, Flatten, FocusHandle, Focusable, InteractiveElement,
|
Context, Element, Entity, EventEmitter, Flatten, FocusHandle, Focusable, InteractiveElement,
|
||||||
IntoElement, ListAlignment, ListState, ObjectFit, ParentElement, PathPromptOptions, Render,
|
IntoElement, ListAlignment, ListState, ObjectFit, ParentElement, PathPromptOptions, Render,
|
||||||
SharedString, StatefulInteractiveElement, Styled, StyledImage, Subscription, WeakEntity,
|
SharedString, StatefulInteractiveElement, Styled, StyledImage, Subscription, WeakEntity,
|
||||||
Window,
|
Window,
|
||||||
@@ -24,11 +24,15 @@ use ui::{
|
|||||||
button::{Button, ButtonRounded, ButtonVariants},
|
button::{Button, ButtonRounded, ButtonVariants},
|
||||||
dock_area::panel::{Panel, PanelEvent},
|
dock_area::panel::{Panel, PanelEvent},
|
||||||
input::{InputEvent, TextInput},
|
input::{InputEvent, TextInput},
|
||||||
|
notification::Notification,
|
||||||
popup_menu::PopupMenu,
|
popup_menu::PopupMenu,
|
||||||
theme::{scale::ColorScaleStep, ActiveTheme},
|
theme::{scale::ColorScaleStep, ActiveTheme},
|
||||||
v_flex, ContextModal, Icon, IconName, Sizable, StyledExt,
|
v_flex, ContextModal, Icon, IconName, Sizable, StyledExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ALERT: &str =
|
||||||
|
"This conversation is private. Only members of this chat can see each other's messages.";
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
id: &u64,
|
id: &u64,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
@@ -45,31 +49,34 @@ pub fn init(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Message {
|
#[derive(PartialEq, Eq)]
|
||||||
|
struct ChatItem {
|
||||||
profile: NostrProfile,
|
profile: NostrProfile,
|
||||||
content: SharedString,
|
content: SharedString,
|
||||||
ago: SharedString,
|
ago: SharedString,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Message {
|
#[derive(PartialEq, Eq)]
|
||||||
fn eq(&self, other: &Self) -> bool {
|
enum Message {
|
||||||
let content = self.content == other.content;
|
Item(Box<ChatItem>),
|
||||||
let member = self.profile == other.profile;
|
System(SharedString),
|
||||||
let ago = self.ago == other.ago;
|
Placeholder,
|
||||||
|
|
||||||
content && member && ago
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
pub fn new(profile: NostrProfile, content: SharedString, ago: SharedString) -> Self {
|
pub fn new(chat_message: ChatItem) -> Self {
|
||||||
Self {
|
Self::Item(Box::new(chat_message))
|
||||||
profile,
|
}
|
||||||
content,
|
|
||||||
ago,
|
pub fn system(content: SharedString) -> Self {
|
||||||
}
|
Self::System(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn placeholder() -> Self {
|
||||||
|
Self::Placeholder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Chat {
|
pub struct Chat {
|
||||||
// Panel
|
// Panel
|
||||||
id: SharedString,
|
id: SharedString,
|
||||||
@@ -95,7 +102,7 @@ impl Chat {
|
|||||||
let new_messages = model.read(cx).new_messages.downgrade();
|
let new_messages = model.read(cx).new_messages.downgrade();
|
||||||
|
|
||||||
cx.new(|cx| {
|
cx.new(|cx| {
|
||||||
let messages = cx.new(|_| Vec::new());
|
let messages = cx.new(|_| vec![Message::placeholder()]);
|
||||||
let attaches = cx.new(|_| None);
|
let attaches = cx.new(|_| None);
|
||||||
|
|
||||||
let input = cx.new(|cx| {
|
let input = cx.new(|cx| {
|
||||||
@@ -140,8 +147,12 @@ impl Chat {
|
|||||||
subscriptions,
|
subscriptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Verify messaging relays of all members
|
||||||
|
this.verify_messaging_relays(cx);
|
||||||
|
|
||||||
// Load all messages from database
|
// Load all messages from database
|
||||||
this.load_messages(cx);
|
this.load_messages(cx);
|
||||||
|
|
||||||
// Subscribe and load new messages
|
// Subscribe and load new messages
|
||||||
this.load_new_messages(cx);
|
this.load_new_messages(cx);
|
||||||
|
|
||||||
@@ -149,6 +160,62 @@ impl Chat {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn verify_messaging_relays(&self, cx: &mut Context<Self>) {
|
||||||
|
let Some(model) = self.room.upgrade() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let room = model.read(cx);
|
||||||
|
let pubkeys: Vec<PublicKey> = room.members.iter().map(|m| m.public_key()).collect();
|
||||||
|
let client = get_client();
|
||||||
|
let (tx, rx) = oneshot::channel::<Vec<(PublicKey, bool)>>();
|
||||||
|
|
||||||
|
cx.background_spawn(async move {
|
||||||
|
let mut result = Vec::new();
|
||||||
|
|
||||||
|
for pubkey in pubkeys.into_iter() {
|
||||||
|
let filter = Filter::new()
|
||||||
|
.kind(Kind::InboxRelays)
|
||||||
|
.author(pubkey)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
let is_ready = if let Ok(events) = client.database().query(filter).await {
|
||||||
|
events.first_owned().is_some()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
result.push((pubkey, is_ready));
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = tx.send(result);
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
|
||||||
|
cx.spawn(|this, cx| async move {
|
||||||
|
if let Ok(result) = rx.await {
|
||||||
|
_ = cx.update(|cx| {
|
||||||
|
_ = this.update(cx, |this, cx| {
|
||||||
|
for item in result.into_iter() {
|
||||||
|
if !item.1 {
|
||||||
|
let name = this
|
||||||
|
.room
|
||||||
|
.read_with(cx, |this, _| this.name())
|
||||||
|
.unwrap_or("Unnamed".into());
|
||||||
|
|
||||||
|
this.push_system_message(
|
||||||
|
format!("{} has not set up Messaging (DM) Relays, so they will NOT receive your messages.", name),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
fn load_messages(&self, cx: &mut Context<Self>) {
|
fn load_messages(&self, cx: &mut Context<Self>) {
|
||||||
let Some(model) = self.room.upgrade() else {
|
let Some(model) = self.room.upgrade() else {
|
||||||
return;
|
return;
|
||||||
@@ -199,11 +266,55 @@ impl Chat {
|
|||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn push_system_message(&self, content: String, cx: &mut Context<Self>) {
|
||||||
|
let old_len = self.messages.read(cx).len();
|
||||||
|
let message = Message::system(content.into());
|
||||||
|
|
||||||
|
cx.update_entity(&self.messages, |this, cx| {
|
||||||
|
this.extend(vec![message]);
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
|
||||||
|
self.list_state.splice(old_len..old_len, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_message(&self, content: String, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
let Some(model) = self.room.upgrade() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let old_len = self.messages.read(cx).len();
|
||||||
|
let room = model.read(cx);
|
||||||
|
let ago = LastSeen(Timestamp::now()).human_readable();
|
||||||
|
let message = Message::new(ChatItem {
|
||||||
|
profile: room.owner.clone(),
|
||||||
|
content: content.into(),
|
||||||
|
ago,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update message list
|
||||||
|
cx.update_entity(&self.messages, |this, cx| {
|
||||||
|
this.extend(vec![message]);
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reset message input
|
||||||
|
cx.update_entity(&self.input, |this, cx| {
|
||||||
|
this.set_loading(false, window, cx);
|
||||||
|
this.set_disabled(false, window, cx);
|
||||||
|
this.set_text("", window, cx);
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
|
||||||
|
self.list_state.splice(old_len..old_len, 1);
|
||||||
|
}
|
||||||
|
|
||||||
fn push_messages(&self, events: Events, cx: &mut Context<Self>) {
|
fn push_messages(&self, events: Events, cx: &mut Context<Self>) {
|
||||||
let Some(model) = self.room.upgrade() else {
|
let Some(model) = self.room.upgrade() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let old_len = self.messages.read(cx).len();
|
||||||
let room = model.read(cx);
|
let room = model.read(cx);
|
||||||
let pubkeys = room.pubkeys();
|
let pubkeys = room.pubkeys();
|
||||||
|
|
||||||
@@ -224,11 +335,11 @@ impl Chat {
|
|||||||
room.owner.to_owned()
|
room.owner.to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(Message::new(
|
Some(Message::new(ChatItem {
|
||||||
member,
|
profile: member,
|
||||||
ev.content.into(),
|
content: ev.content.into(),
|
||||||
LastSeen(ev.created_at).human_readable(),
|
ago: LastSeen(ev.created_at).human_readable(),
|
||||||
))
|
}))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -244,7 +355,7 @@ impl Chat {
|
|||||||
cx.notify();
|
cx.notify();
|
||||||
});
|
});
|
||||||
|
|
||||||
self.list_state.reset(total);
|
self.list_state.splice(old_len..old_len, total);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_new_messages(&mut self, cx: &mut Context<Self>) {
|
fn load_new_messages(&mut self, cx: &mut Context<Self>) {
|
||||||
@@ -266,11 +377,11 @@ impl Chat {
|
|||||||
.iter()
|
.iter()
|
||||||
.filter_map(|event| {
|
.filter_map(|event| {
|
||||||
if let Some(profile) = room.member(&event.pubkey) {
|
if let Some(profile) = room.member(&event.pubkey) {
|
||||||
let message = Message::new(
|
let message = Message::new(ChatItem {
|
||||||
profile,
|
profile,
|
||||||
event.content.clone().into(),
|
content: event.content.clone().into(),
|
||||||
LastSeen(event.created_at).human_readable(),
|
ago: LastSeen(event.created_at).human_readable(),
|
||||||
);
|
});
|
||||||
|
|
||||||
if !old_messages.iter().any(|old| old == &message) {
|
if !old_messages.iter().any(|old| old == &message) {
|
||||||
Some(message)
|
Some(message)
|
||||||
@@ -339,6 +450,7 @@ impl Chat {
|
|||||||
|
|
||||||
let client = get_client();
|
let client = get_client();
|
||||||
let window_handle = window.window_handle();
|
let window_handle = window.window_handle();
|
||||||
|
let (tx, rx) = oneshot::channel::<Vec<Error>>();
|
||||||
|
|
||||||
let room = model.read(cx);
|
let room = model.read(cx);
|
||||||
let pubkeys = room.pubkeys();
|
let pubkeys = room.pubkeys();
|
||||||
@@ -357,55 +469,43 @@ impl Chat {
|
|||||||
|
|
||||||
// Send message to all pubkeys
|
// Send message to all pubkeys
|
||||||
cx.background_spawn(async move {
|
cx.background_spawn(async move {
|
||||||
|
let mut errors = Vec::new();
|
||||||
|
|
||||||
for pubkey in pubkeys.iter() {
|
for pubkey in pubkeys.iter() {
|
||||||
if let Err(_e) = client
|
if let Err(e) = client
|
||||||
.send_private_msg(*pubkey, &async_content, tags.clone())
|
.send_private_msg(*pubkey, &async_content, tags.clone())
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
// TODO: handle error
|
errors.push(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = tx.send(errors);
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
_ = cx.update_window(window_handle, |_, window, cx| {
|
_ = cx.update_window(window_handle, |_, window, cx| {
|
||||||
_ = this.update(cx, |this, cx| {
|
_ = this.update(cx, |this, cx| {
|
||||||
this.force_push_message(content.clone(), window, cx);
|
this.push_message(content.clone(), window, cx);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if let Ok(errors) = rx.await {
|
||||||
|
_ = cx.update_window(window_handle, |_, window, cx| {
|
||||||
|
for error in errors.into_iter() {
|
||||||
|
window.push_notification(
|
||||||
|
Notification::error(error.to_string()).title("Message Failed to Send"),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn force_push_message(&self, content: String, window: &mut Window, cx: &mut Context<Self>) {
|
fn upload_media(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
let Some(model) = self.room.upgrade() else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let room = model.read(cx);
|
|
||||||
let ago = LastSeen(Timestamp::now()).human_readable();
|
|
||||||
let message = Message::new(room.owner.clone(), content.into(), ago);
|
|
||||||
let old_len = self.messages.read(cx).len();
|
|
||||||
|
|
||||||
// Update message list
|
|
||||||
cx.update_entity(&self.messages, |this, cx| {
|
|
||||||
this.extend(vec![message]);
|
|
||||||
cx.notify();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Reset message input
|
|
||||||
cx.update_entity(&self.input, |this, cx| {
|
|
||||||
this.set_loading(false, window, cx);
|
|
||||||
this.set_disabled(false, window, cx);
|
|
||||||
this.set_text("", window, cx);
|
|
||||||
cx.notify();
|
|
||||||
});
|
|
||||||
|
|
||||||
self.list_state.splice(old_len..old_len, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn upload(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
|
||||||
let window_handle = window.window_handle();
|
let window_handle = window.window_handle();
|
||||||
|
|
||||||
let paths = cx.prompt_for_paths(PathPromptOptions {
|
let paths = cx.prompt_for_paths(PathPromptOptions {
|
||||||
@@ -467,7 +567,7 @@ impl Chat {
|
|||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&mut self, url: &Url, _window: &mut Window, cx: &mut Context<Self>) {
|
fn remove_media(&mut self, url: &Url, _window: &mut Window, cx: &mut Context<Self>) {
|
||||||
self.attaches.update(cx, |model, cx| {
|
self.attaches.update(cx, |model, cx| {
|
||||||
if let Some(urls) = model.as_mut() {
|
if let Some(urls) = model.as_mut() {
|
||||||
let ix = urls.iter().position(|x| x == url).unwrap();
|
let ix = urls.iter().position(|x| x == url).unwrap();
|
||||||
@@ -496,46 +596,86 @@ impl Chat {
|
|||||||
.gap_3()
|
.gap_3()
|
||||||
.w_full()
|
.w_full()
|
||||||
.p_2()
|
.p_2()
|
||||||
.hover(|this| this.bg(cx.theme().accent.step(cx, ColorScaleStep::ONE)))
|
.map(|this| match message {
|
||||||
.child(
|
Message::Item(item) => this
|
||||||
div()
|
.hover(|this| this.bg(cx.theme().accent.step(cx, ColorScaleStep::ONE)))
|
||||||
.absolute()
|
.child(
|
||||||
.left_0()
|
div()
|
||||||
.top_0()
|
.absolute()
|
||||||
.w(px(2.))
|
.left_0()
|
||||||
.h_full()
|
.top_0()
|
||||||
.bg(cx.theme().transparent)
|
.w(px(2.))
|
||||||
.group_hover("", |this| {
|
.h_full()
|
||||||
this.bg(cx.theme().accent.step(cx, ColorScaleStep::NINE))
|
.bg(cx.theme().transparent)
|
||||||
}),
|
.group_hover("", |this| {
|
||||||
)
|
this.bg(cx.theme().accent.step(cx, ColorScaleStep::NINE))
|
||||||
.child(
|
}),
|
||||||
img(message.profile.avatar())
|
)
|
||||||
.size_8()
|
.child(
|
||||||
.rounded_full()
|
img(item.profile.avatar())
|
||||||
.flex_shrink_0(),
|
.size_8()
|
||||||
)
|
.rounded_full()
|
||||||
.child(
|
.flex_shrink_0(),
|
||||||
div()
|
)
|
||||||
.flex()
|
|
||||||
.flex_col()
|
|
||||||
.flex_initial()
|
|
||||||
.overflow_hidden()
|
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
.items_baseline()
|
.flex_col()
|
||||||
.gap_2()
|
.flex_initial()
|
||||||
.text_xs()
|
.overflow_hidden()
|
||||||
.child(div().font_semibold().child(message.profile.name()))
|
|
||||||
.child(
|
.child(
|
||||||
div().child(message.ago.clone()).text_color(
|
div()
|
||||||
cx.theme().base.step(cx, ColorScaleStep::ELEVEN),
|
.flex()
|
||||||
),
|
.items_baseline()
|
||||||
),
|
.gap_2()
|
||||||
|
.text_xs()
|
||||||
|
.child(div().font_semibold().child(item.profile.name()))
|
||||||
|
.child(div().child(item.ago.clone()).text_color(
|
||||||
|
cx.theme().base.step(cx, ColorScaleStep::ELEVEN),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.child(div().text_sm().child(item.content.clone())),
|
||||||
|
),
|
||||||
|
Message::System(content) => this
|
||||||
|
.items_center()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.absolute()
|
||||||
|
.left_0()
|
||||||
|
.top_0()
|
||||||
|
.w(px(2.))
|
||||||
|
.h_full()
|
||||||
|
.bg(cx.theme().transparent)
|
||||||
|
.group_hover("", |this| this.bg(cx.theme().danger)),
|
||||||
)
|
)
|
||||||
.child(div().text_sm().child(message.content.clone())),
|
.child(
|
||||||
)
|
img("brand/avatar.png")
|
||||||
|
.size_8()
|
||||||
|
.rounded_full()
|
||||||
|
.flex_shrink_0(),
|
||||||
|
)
|
||||||
|
.text_xs()
|
||||||
|
.text_color(cx.theme().danger)
|
||||||
|
.child(content.clone()),
|
||||||
|
Message::Placeholder => this
|
||||||
|
.w_full()
|
||||||
|
.h_32()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.items_center()
|
||||||
|
.justify_center()
|
||||||
|
.text_center()
|
||||||
|
.text_xs()
|
||||||
|
.text_color(cx.theme().base.step(cx, ColorScaleStep::ELEVEN))
|
||||||
|
.line_height(relative(1.))
|
||||||
|
.child(
|
||||||
|
svg()
|
||||||
|
.path("brand/coop.svg")
|
||||||
|
.size_8()
|
||||||
|
.text_color(cx.theme().base.step(cx, ColorScaleStep::THREE)),
|
||||||
|
)
|
||||||
|
.child(ALERT),
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
div()
|
div()
|
||||||
}
|
}
|
||||||
@@ -651,7 +791,7 @@ impl Render for Chat {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.on_click(cx.listener(move |this, _, window, cx| {
|
.on_click(cx.listener(move |this, _, window, cx| {
|
||||||
this.remove(&url, window, cx);
|
this.remove_media(&url, window, cx);
|
||||||
}))
|
}))
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
@@ -667,7 +807,7 @@ impl Render for Chat {
|
|||||||
.icon(Icon::new(IconName::Upload))
|
.icon(Icon::new(IconName::Upload))
|
||||||
.ghost()
|
.ghost()
|
||||||
.on_click(cx.listener(move |this, _, window, cx| {
|
.on_click(cx.listener(move |this, _, window, cx| {
|
||||||
this.upload(window, cx);
|
this.upload_media(window, cx);
|
||||||
}))
|
}))
|
||||||
.loading(self.is_uploading),
|
.loading(self.is_uploading),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use common::{profile::NostrProfile, qr::create_qr, utils::preload};
|
use common::{profile::NostrProfile, qr::create_qr, utils::preload};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, img, prelude::FluentBuilder, relative, svg, App, AppContext, ClipboardItem, Context, Div,
|
div, img, prelude::FluentBuilder, relative, svg, App, AppContext, ClipboardItem, Context, Div,
|
||||||
Entity, IntoElement, ParentElement, Render, Styled, Window,
|
Entity, IntoElement, ParentElement, Render, Styled, Subscription, Window,
|
||||||
};
|
};
|
||||||
use nostr_connect::prelude::*;
|
use nostr_connect::prelude::*;
|
||||||
use state::get_client;
|
use state::get_client;
|
||||||
@@ -17,7 +17,8 @@ use ui::{
|
|||||||
|
|
||||||
use super::app;
|
use super::app;
|
||||||
|
|
||||||
const ALPHA_MESSAGE: &str = "Coop is in the alpha stage; it doesn't store any credentials. You will need to log in again when you relaunch.";
|
const ALPHA_MESSAGE: &str =
|
||||||
|
"Coop is in the alpha stage of development; It may contain bugs, unfinished features, or unexpected behavior.";
|
||||||
const JOIN_URL: &str = "https://start.njump.me/";
|
const JOIN_URL: &str = "https://start.njump.me/";
|
||||||
|
|
||||||
pub fn init(window: &mut Window, cx: &mut App) -> Entity<Onboarding> {
|
pub fn init(window: &mut Window, cx: &mut App) -> Entity<Onboarding> {
|
||||||
@@ -32,6 +33,8 @@ pub struct Onboarding {
|
|||||||
use_connect: bool,
|
use_connect: bool,
|
||||||
use_privkey: bool,
|
use_privkey: bool,
|
||||||
is_loading: bool,
|
is_loading: bool,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
subscriptions: Vec<Subscription>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Onboarding {
|
impl Onboarding {
|
||||||
@@ -55,7 +58,7 @@ impl Onboarding {
|
|||||||
|
|
||||||
cx.new(|cx| {
|
cx.new(|cx| {
|
||||||
// Handle Enter event for nsec input
|
// Handle Enter event for nsec input
|
||||||
cx.subscribe_in(
|
let subscriptions = vec![cx.subscribe_in(
|
||||||
&nsec_input,
|
&nsec_input,
|
||||||
window,
|
window,
|
||||||
move |this: &mut Self, _, input_event, window, cx| {
|
move |this: &mut Self, _, input_event, window, cx| {
|
||||||
@@ -63,8 +66,7 @@ impl Onboarding {
|
|||||||
this.privkey_login(window, cx);
|
this.privkey_login(window, cx);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)];
|
||||||
.detach();
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
app_keys,
|
app_keys,
|
||||||
@@ -74,6 +76,7 @@ impl Onboarding {
|
|||||||
use_connect: false,
|
use_connect: false,
|
||||||
use_privkey: false,
|
use_privkey: false,
|
||||||
is_loading: false,
|
is_loading: false,
|
||||||
|
subscriptions,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
use chats::registry::ChatRegistry;
|
use chats::{registry::ChatRegistry, room::Room};
|
||||||
use common::{
|
use common::{
|
||||||
constants::FAKE_SIG,
|
|
||||||
profile::NostrProfile,
|
profile::NostrProfile,
|
||||||
utils::{random_name, signer_public_key},
|
utils::{random_name, signer_public_key},
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, img, impl_internal_actions, prelude::FluentBuilder, px, relative, uniform_list, App,
|
div, img, impl_internal_actions, prelude::FluentBuilder, px, relative, uniform_list, App,
|
||||||
AppContext, Context, Entity, FocusHandle, InteractiveElement, IntoElement, ParentElement,
|
AppContext, Context, Entity, FocusHandle, InteractiveElement, IntoElement, ParentElement,
|
||||||
Render, SharedString, StatefulInteractiveElement, Styled, TextAlign, Window,
|
Render, SharedString, StatefulInteractiveElement, Styled, Subscription, TextAlign, Window,
|
||||||
};
|
};
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use smol::Timer;
|
||||||
use state::get_client;
|
use state::get_client;
|
||||||
use std::{collections::HashSet, str::FromStr, time::Duration};
|
use std::{collections::HashSet, time::Duration};
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
use ui::{
|
use ui::{
|
||||||
button::{Button, ButtonRounded},
|
button::{Button, ButtonRounded},
|
||||||
@@ -21,6 +21,9 @@ use ui::{
|
|||||||
ContextModal, Icon, IconName, Sizable, Size, StyledExt,
|
ContextModal, Icon, IconName, Sizable, Size, StyledExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ALERT: &str =
|
||||||
|
"Start a conversation with someone using their npub or NIP-05 (like foo@bar.com).";
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
||||||
struct SelectContact(PublicKey);
|
struct SelectContact(PublicKey);
|
||||||
|
|
||||||
@@ -28,26 +31,23 @@ impl_internal_actions!(contacts, [SelectContact]);
|
|||||||
|
|
||||||
pub struct Compose {
|
pub struct Compose {
|
||||||
title_input: Entity<TextInput>,
|
title_input: Entity<TextInput>,
|
||||||
message_input: Entity<TextInput>,
|
|
||||||
user_input: Entity<TextInput>,
|
user_input: Entity<TextInput>,
|
||||||
contacts: Entity<Vec<NostrProfile>>,
|
contacts: Entity<Vec<NostrProfile>>,
|
||||||
selected: Entity<HashSet<PublicKey>>,
|
selected: Entity<HashSet<PublicKey>>,
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
is_loading: bool,
|
is_loading: bool,
|
||||||
is_submitting: bool,
|
is_submitting: bool,
|
||||||
|
error_message: Entity<Option<SharedString>>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
subscriptions: Vec<Subscription>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Compose {
|
impl Compose {
|
||||||
pub fn new(window: &mut Window, cx: &mut Context<'_, Self>) -> Self {
|
pub fn new(window: &mut Window, cx: &mut Context<'_, Self>) -> Self {
|
||||||
let contacts = cx.new(|_| Vec::new());
|
let contacts = cx.new(|_| Vec::new());
|
||||||
let selected = cx.new(|_| HashSet::new());
|
let selected = cx.new(|_| HashSet::new());
|
||||||
|
let error_message = cx.new(|_| None);
|
||||||
let user_input = cx.new(|cx| {
|
let mut subscriptions = Vec::new();
|
||||||
TextInput::new(window, cx)
|
|
||||||
.text_size(ui::Size::Small)
|
|
||||||
.small()
|
|
||||||
.placeholder("npub1...")
|
|
||||||
});
|
|
||||||
|
|
||||||
let title_input = cx.new(|cx| {
|
let title_input = cx.new(|cx| {
|
||||||
let name = random_name(2);
|
let name = random_name(2);
|
||||||
@@ -60,15 +60,15 @@ impl Compose {
|
|||||||
input
|
input
|
||||||
});
|
});
|
||||||
|
|
||||||
let message_input = cx.new(|cx| {
|
let user_input = cx.new(|cx| {
|
||||||
TextInput::new(window, cx)
|
TextInput::new(window, cx)
|
||||||
.appearance(false)
|
.text_size(ui::Size::Small)
|
||||||
.text_size(Size::XSmall)
|
.small()
|
||||||
.placeholder("Hello...")
|
.placeholder("npub1...")
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle Enter event for message input
|
// Handle Enter event for user input
|
||||||
cx.subscribe_in(
|
subscriptions.push(cx.subscribe_in(
|
||||||
&user_input,
|
&user_input,
|
||||||
window,
|
window,
|
||||||
move |this, _, input_event, window, cx| {
|
move |this, _, input_event, window, cx| {
|
||||||
@@ -76,155 +76,118 @@ impl Compose {
|
|||||||
this.add(window, cx);
|
this.add(window, cx);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
));
|
||||||
|
|
||||||
|
let client = get_client();
|
||||||
|
let (tx, rx) = oneshot::channel::<Vec<NostrProfile>>();
|
||||||
|
|
||||||
|
cx.background_spawn(async move {
|
||||||
|
if let Ok(public_key) = signer_public_key(client).await {
|
||||||
|
if let Ok(profiles) = client.database().contacts(public_key).await {
|
||||||
|
let members: Vec<NostrProfile> = profiles
|
||||||
|
.into_iter()
|
||||||
|
.map(|profile| NostrProfile::new(profile.public_key(), profile.metadata()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
_ = tx.send(members);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, cx| async move {
|
||||||
let (tx, rx) = oneshot::channel::<Vec<NostrProfile>>();
|
|
||||||
|
|
||||||
cx.background_executor()
|
|
||||||
.spawn(async move {
|
|
||||||
let client = get_client();
|
|
||||||
if let Ok(public_key) = signer_public_key(client).await {
|
|
||||||
if let Ok(profiles) = client.database().contacts(public_key).await {
|
|
||||||
let members: Vec<NostrProfile> = profiles
|
|
||||||
.into_iter()
|
|
||||||
.map(|profile| {
|
|
||||||
NostrProfile::new(profile.public_key(), profile.metadata())
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
_ = tx.send(members);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
|
|
||||||
if let Ok(contacts) = rx.await {
|
if let Ok(contacts) = rx.await {
|
||||||
if let Some(view) = this.upgrade() {
|
_ = cx.update(|cx| {
|
||||||
_ = cx.update_entity(&view, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
this.contacts.update(cx, |this, cx| {
|
this.contacts.update(cx, |this, cx| {
|
||||||
this.extend(contacts);
|
this.extend(contacts);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
});
|
});
|
||||||
cx.notify();
|
})
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
title_input,
|
title_input,
|
||||||
message_input,
|
|
||||||
user_input,
|
user_input,
|
||||||
contacts,
|
contacts,
|
||||||
selected,
|
selected,
|
||||||
|
error_message,
|
||||||
is_loading: false,
|
is_loading: false,
|
||||||
is_submitting: false,
|
is_submitting: false,
|
||||||
focus_handle: cx.focus_handle(),
|
focus_handle: cx.focus_handle(),
|
||||||
|
subscriptions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compose(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
pub fn compose(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
let selected = self.selected.read(cx).to_owned();
|
if self.selected.read(cx).is_empty() {
|
||||||
let message = self.message_input.read(cx).text();
|
self.set_error(Some("You need to add at least 1 receiver".into()), cx);
|
||||||
|
|
||||||
if selected.is_empty() {
|
|
||||||
window.push_notification("You need to add at least 1 receiver", cx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if message.is_empty() {
|
|
||||||
window.push_notification("Message is required", cx);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show loading spinner
|
// Show loading spinner
|
||||||
self.set_submitting(true, cx);
|
self.set_submitting(true, cx);
|
||||||
|
|
||||||
// Get message from user's input
|
|
||||||
let content = message.to_string();
|
|
||||||
|
|
||||||
// Get room title from user's input
|
|
||||||
let title = Tag::custom(
|
|
||||||
TagKind::Subject,
|
|
||||||
vec![self.title_input.read(cx).text().to_string()],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get all pubkeys
|
// Get all pubkeys
|
||||||
let mut pubkeys: Vec<PublicKey> = selected.iter().copied().collect();
|
let pubkeys: Vec<PublicKey> = self.selected.read(cx).iter().copied().collect();
|
||||||
|
|
||||||
// Convert selected pubkeys into Nostr tags
|
// Convert selected pubkeys into Nostr tags
|
||||||
let mut tag_list: Vec<Tag> = selected.iter().map(|pk| Tag::public_key(*pk)).collect();
|
let mut tag_list: Vec<Tag> = pubkeys.iter().map(|pk| Tag::public_key(*pk)).collect();
|
||||||
tag_list.push(title);
|
|
||||||
|
// Add subject if it is present
|
||||||
|
if !self.title_input.read(cx).text().is_empty() {
|
||||||
|
tag_list.push(Tag::custom(
|
||||||
|
TagKind::Subject,
|
||||||
|
vec![self.title_input.read(cx).text().to_string()],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let tags = Tags::new(tag_list);
|
let tags = Tags::new(tag_list);
|
||||||
|
let client = get_client();
|
||||||
let window_handle = window.window_handle();
|
let window_handle = window.window_handle();
|
||||||
|
let (tx, rx) = oneshot::channel::<Event>();
|
||||||
|
|
||||||
|
cx.background_spawn(async move {
|
||||||
|
let signer = client.signer().await.expect("Signer is required");
|
||||||
|
// [IMPORTANT]
|
||||||
|
// Make sure this event is never send,
|
||||||
|
// this event existed just use for convert to Coop's Chat Room later.
|
||||||
|
if let Ok(event) = EventBuilder::private_msg_rumor(*pubkeys.last().unwrap(), "")
|
||||||
|
.tags(tags)
|
||||||
|
.sign(&signer)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
_ = tx.send(event)
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
let (tx, rx) = oneshot::channel::<Event>();
|
|
||||||
|
|
||||||
cx.background_spawn(async move {
|
|
||||||
let client = get_client();
|
|
||||||
let public_key = signer_public_key(client).await.unwrap();
|
|
||||||
let mut event: Option<Event> = None;
|
|
||||||
|
|
||||||
pubkeys.push(public_key);
|
|
||||||
|
|
||||||
for pubkey in pubkeys.iter() {
|
|
||||||
if let Ok(output) = client
|
|
||||||
.send_private_msg(*pubkey, &content, tags.clone())
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
if pubkey == &public_key && event.is_none() {
|
|
||||||
if let Ok(Some(ev)) = client.database().event_by_id(&output.val).await {
|
|
||||||
if let Ok(UnwrappedGift { mut rumor, .. }) =
|
|
||||||
client.unwrap_gift_wrap(&ev).await
|
|
||||||
{
|
|
||||||
// Compute event id if not exist
|
|
||||||
rumor.ensure_id();
|
|
||||||
|
|
||||||
if let Some(id) = rumor.id {
|
|
||||||
let ev = Event::new(
|
|
||||||
id,
|
|
||||||
rumor.pubkey,
|
|
||||||
rumor.created_at,
|
|
||||||
rumor.kind,
|
|
||||||
rumor.tags,
|
|
||||||
rumor.content,
|
|
||||||
Signature::from_str(FAKE_SIG).unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
event = Some(ev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(event) = event {
|
|
||||||
_ = tx.send(event);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
|
|
||||||
if let Ok(event) = rx.await {
|
if let Ok(event) = rx.await {
|
||||||
_ = cx.update_window(window_handle, |_, window, cx| {
|
_ = cx.update_window(window_handle, |_, window, cx| {
|
||||||
if let Some(chats) = ChatRegistry::global(cx) {
|
|
||||||
chats.update(cx, |this, cx| {
|
|
||||||
this.push_message(event, cx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop loading spinner
|
// Stop loading spinner
|
||||||
_ = this.update(cx, |this, cx| {
|
_ = this.update(cx, |this, cx| {
|
||||||
this.set_submitting(false, cx);
|
this.set_submitting(false, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Close modal
|
if let Some(chats) = ChatRegistry::global(cx) {
|
||||||
window.close_modal(cx);
|
let room = Room::parse(&event, cx);
|
||||||
|
|
||||||
|
chats.update(cx, |state, cx| match state.new_room(room, cx) {
|
||||||
|
Ok(_) => {
|
||||||
|
// TODO: open chat panel
|
||||||
|
window.close_modal(cx);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
_ = this.update(cx, |this, cx| {
|
||||||
|
this.set_error(Some(e.to_string().into()), cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -303,10 +266,29 @@ impl Compose {
|
|||||||
.detach();
|
.detach();
|
||||||
} else {
|
} else {
|
||||||
self.set_loading(false, cx);
|
self.set_loading(false, cx);
|
||||||
window.push_notification("Public Key is not valid", cx);
|
self.set_error(Some("Public Key is not valid".into()), cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_error(&mut self, error: Option<SharedString>, cx: &mut Context<Self>) {
|
||||||
|
self.error_message.update(cx, |this, cx| {
|
||||||
|
*this = error;
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Dismiss error after 2 seconds
|
||||||
|
cx.spawn(|this, cx| async move {
|
||||||
|
Timer::after(Duration::from_secs(2)).await;
|
||||||
|
|
||||||
|
_ = cx.update(|cx| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
this.set_error(None, cx);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
fn set_loading(&mut self, status: bool, cx: &mut Context<Self>) {
|
fn set_loading(&mut self, status: bool, cx: &mut Context<Self>) {
|
||||||
self.is_loading = status;
|
self.is_loading = status;
|
||||||
cx.notify();
|
cx.notify();
|
||||||
@@ -336,9 +318,6 @@ impl Compose {
|
|||||||
|
|
||||||
impl Render for Compose {
|
impl Render for Compose {
|
||||||
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 msg =
|
|
||||||
"Start a conversation with someone using their npub or NIP-05 (like foo@bar.com).";
|
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.track_focus(&self.focus_handle)
|
.track_focus(&self.focus_handle)
|
||||||
.on_action(cx.listener(Self::on_action_select))
|
.on_action(cx.listener(Self::on_action_select))
|
||||||
@@ -350,36 +329,30 @@ impl Render for Compose {
|
|||||||
.px_2()
|
.px_2()
|
||||||
.text_xs()
|
.text_xs()
|
||||||
.text_color(cx.theme().base.step(cx, ColorScaleStep::ELEVEN))
|
.text_color(cx.theme().base.step(cx, ColorScaleStep::ELEVEN))
|
||||||
.child(msg),
|
.child(ALERT),
|
||||||
)
|
)
|
||||||
|
.when_some(self.error_message.read(cx).as_ref(), |this, msg| {
|
||||||
|
this.child(
|
||||||
|
div()
|
||||||
|
.px_2()
|
||||||
|
.text_xs()
|
||||||
|
.text_color(cx.theme().danger)
|
||||||
|
.child(msg.clone()),
|
||||||
|
)
|
||||||
|
})
|
||||||
.child(
|
.child(
|
||||||
div()
|
div().flex().flex_col().child(
|
||||||
.flex()
|
div()
|
||||||
.flex_col()
|
.h_10()
|
||||||
.child(
|
.px_2()
|
||||||
div()
|
.border_b_1()
|
||||||
.h_10()
|
.border_color(cx.theme().base.step(cx, ColorScaleStep::FIVE))
|
||||||
.px_2()
|
.flex()
|
||||||
.border_b_1()
|
.items_center()
|
||||||
.border_color(cx.theme().base.step(cx, ColorScaleStep::FIVE))
|
.gap_1()
|
||||||
.flex()
|
.child(div().text_xs().font_semibold().child("Title:"))
|
||||||
.items_center()
|
.child(self.title_input.clone()),
|
||||||
.gap_1()
|
),
|
||||||
.child(div().text_xs().font_semibold().child("Title:"))
|
|
||||||
.child(self.title_input.clone()),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
div()
|
|
||||||
.h_10()
|
|
||||||
.px_2()
|
|
||||||
.border_b_1()
|
|
||||||
.border_color(cx.theme().base.step(cx, ColorScaleStep::FIVE))
|
|
||||||
.flex()
|
|
||||||
.items_center()
|
|
||||||
.gap_1()
|
|
||||||
.child(div().text_xs().font_semibold().child("Message:"))
|
|
||||||
.child(self.message_input.clone()),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use anyhow::anyhow;
|
||||||
use async_utility::tokio::sync::oneshot;
|
use async_utility::tokio::sync::oneshot;
|
||||||
use common::utils::{compare, room_hash, signer_public_key};
|
use common::utils::{compare, room_hash, signer_public_key};
|
||||||
use gpui::{App, AppContext, Context, Entity, Global};
|
use gpui::{App, AppContext, Context, Entity, Global};
|
||||||
@@ -151,6 +152,21 @@ impl ChatRegistry {
|
|||||||
.cloned()
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_room(&mut self, room: Room, cx: &mut Context<Self>) -> Result<(), anyhow::Error> {
|
||||||
|
if !self
|
||||||
|
.rooms
|
||||||
|
.iter()
|
||||||
|
.any(|current| compare(¤t.read(cx).pubkeys(), &room.pubkeys()))
|
||||||
|
{
|
||||||
|
self.rooms.insert(0, cx.new(|_| room));
|
||||||
|
cx.notify();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("Room is existed"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn push_message(&mut self, event: Event, cx: &mut Context<Self>) {
|
pub fn push_message(&mut self, event: Event, cx: &mut Context<Self>) {
|
||||||
// Get all pubkeys from event's tags for comparision
|
// Get all pubkeys from event's tags for comparision
|
||||||
let mut pubkeys: Vec<_> = event.tags.public_keys().copied().collect();
|
let mut pubkeys: Vec<_> = event.tags.public_keys().copied().collect();
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ impl AsRef<Metadata> for NostrProfile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Eq for NostrProfile {}
|
||||||
|
|
||||||
impl PartialEq for NostrProfile {
|
impl PartialEq for NostrProfile {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.public_key() == other.public_key()
|
self.public_key() == other.public_key()
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ impl From<(NotificationType, SharedString)> for Notification {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct DefaultIdType;
|
struct DefaultIdType;
|
||||||
|
|
||||||
impl Notification {
|
impl Notification {
|
||||||
/// Create a new notification with the given content.
|
/// Create a new notification with the given content.
|
||||||
///
|
///
|
||||||
|
|||||||
Reference in New Issue
Block a user