feat: refine the search bar (#207)

* update deps

* refactor the search cancellation

* .

* .
This commit is contained in:
reya
2025-11-22 07:25:08 +07:00
committed by GitHub
parent a6e00b47d8
commit 14c36e4731
11 changed files with 271 additions and 344 deletions

144
Cargo.lock generated
View File

@@ -504,15 +504,15 @@ dependencies = [
[[package]] [[package]]
name = "async_zip" name = "async_zip"
version = "0.0.17" version = "0.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b9f7252833d5ed4b00aa9604b563529dd5e11de9c23615de2dcdf91eb87b52" checksum = "0d8c50d65ce1b0e0cb65a785ff615f78860d7754290647d3b983208daa4f85e6"
dependencies = [ dependencies = [
"async-compression", "async-compression",
"crc32fast", "crc32fast",
"futures-lite 2.6.1", "futures-lite 2.6.1",
"pin-project", "pin-project",
"thiserror 1.0.69", "thiserror 2.0.17",
] ]
[[package]] [[package]]
@@ -602,9 +602,9 @@ dependencies = [
[[package]] [[package]]
name = "aws-lc-rs" name = "aws-lc-rs"
version = "1.15.0" version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5932a7d9d28b0d2ea34c6b3779d35e3dd6f6345317c34e73438c4f1f29144151" checksum = "6b5ce75405893cd713f9ab8e297d8e438f624dde7d706108285f7e17a25a180f"
dependencies = [ dependencies = [
"aws-lc-sys", "aws-lc-sys",
"zeroize", "zeroize",
@@ -612,11 +612,10 @@ dependencies = [
[[package]] [[package]]
name = "aws-lc-sys" name = "aws-lc-sys"
version = "0.33.0" version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1826f2e4cfc2cd19ee53c42fbf68e2f81ec21108e0b7ecf6a71cf062137360fc" checksum = "179c3777a8b5e70e90ea426114ffc565b2c1a9f82f6c4a0c5a34aa6ef5e781b6"
dependencies = [ dependencies = [
"bindgen 0.72.1",
"cc", "cc",
"cmake", "cmake",
"dunce", "dunce",
@@ -667,26 +666,6 @@ dependencies = [
"syn 2.0.110", "syn 2.0.110",
] ]
[[package]]
name = "bindgen"
version = "0.72.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
dependencies = [
"bitflags 2.10.0",
"cexpr",
"clang-sys",
"itertools 0.13.0",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash 2.1.1",
"shlex",
"syn 2.0.110",
]
[[package]] [[package]]
name = "bip39" name = "bip39"
version = "2.2.0" version = "2.2.0"
@@ -890,6 +869,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "btreecap"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6160c957d8aa33d0a8ba1dbab98e3cb57023ad9374c501441e88559f99e6c4c9"
[[package]] [[package]]
name = "built" name = "built"
version = "0.8.0" version = "0.8.0"
@@ -942,26 +927,25 @@ checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
[[package]] [[package]]
name = "calloop" name = "calloop"
version = "0.13.0" version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" checksum = "cb9f6e1368bd4621d2c86baa7e37de77a938adf5221e5dd3d6133340101b309e"
dependencies = [ dependencies = [
"bitflags 2.10.0", "bitflags 2.10.0",
"log",
"polling", "polling",
"rustix 0.38.44", "rustix 1.1.2",
"slab", "slab",
"thiserror 1.0.69", "tracing",
] ]
[[package]] [[package]]
name = "calloop-wayland-source" name = "calloop-wayland-source"
version = "0.3.0" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa"
dependencies = [ dependencies = [
"calloop", "calloop",
"rustix 0.38.44", "rustix 1.1.2",
"wayland-backend", "wayland-backend",
"wayland-client", "wayland-client",
] ]
@@ -995,9 +979,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.46" version = "1.2.47"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36" checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07"
dependencies = [ dependencies = [
"find-msvc-tools", "find-msvc-tools",
"jobserver", "jobserver",
@@ -1242,7 +1226,7 @@ dependencies = [
[[package]] [[package]]
name = "collections" name = "collections"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"rustc-hash 2.1.1", "rustc-hash 2.1.1",
@@ -1674,7 +1658,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#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -2614,13 +2598,13 @@ dependencies = [
[[package]] [[package]]
name = "gpui" name = "gpui"
version = "0.2.2" version = "0.2.2"
source = "git+https://github.com/zed-industries/zed#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"as-raw-xcb-connection", "as-raw-xcb-connection",
"ashpd 0.11.0", "ashpd 0.11.0",
"async-task", "async-task",
"bindgen 0.71.1", "bindgen",
"bitflags 2.10.0", "bitflags 2.10.0",
"blade-graphics", "blade-graphics",
"blade-macros", "blade-macros",
@@ -2713,7 +2697,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#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
@@ -2724,7 +2708,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#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"gpui", "gpui",
@@ -2795,9 +2779,9 @@ dependencies = [
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.16.0" version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]] [[package]]
name = "heck" name = "heck"
@@ -2953,7 +2937,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#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-compression", "async-compression",
@@ -2979,7 +2963,7 @@ dependencies = [
[[package]] [[package]]
name = "http_client_tls" name = "http_client_tls"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"rustls", "rustls",
"rustls-platform-verifier", "rustls-platform-verifier",
@@ -3269,12 +3253,12 @@ checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.12.0" version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.16.0", "hashbrown 0.16.1",
"serde", "serde",
"serde_core", "serde_core",
] ]
@@ -3775,10 +3759,10 @@ dependencies = [
[[package]] [[package]]
name = "media" name = "media"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bindgen 0.71.1", "bindgen",
"core-foundation 0.10.0", "core-foundation 0.10.0",
"core-video", "core-video",
"ctor", "ctor",
@@ -4025,7 +4009,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr" name = "nostr"
version = "0.44.1" version = "0.44.1"
source = "git+https://github.com/rust-nostr/nostr#aa01f9fb8cd1ddbcc66e2b4ef58eeedbc0d54f56" source = "git+https://github.com/rust-nostr/nostr#8ab324a972145713466145e5daaf1e8351e6d7e7"
dependencies = [ dependencies = [
"aes", "aes",
"base64", "base64",
@@ -4049,7 +4033,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-connect" name = "nostr-connect"
version = "0.44.0" version = "0.44.0"
source = "git+https://github.com/rust-nostr/nostr#aa01f9fb8cd1ddbcc66e2b4ef58eeedbc0d54f56" source = "git+https://github.com/rust-nostr/nostr#8ab324a972145713466145e5daaf1e8351e6d7e7"
dependencies = [ dependencies = [
"async-utility", "async-utility",
"nostr", "nostr",
@@ -4061,8 +4045,9 @@ dependencies = [
[[package]] [[package]]
name = "nostr-database" name = "nostr-database"
version = "0.44.0" version = "0.44.0"
source = "git+https://github.com/rust-nostr/nostr#aa01f9fb8cd1ddbcc66e2b4ef58eeedbc0d54f56" source = "git+https://github.com/rust-nostr/nostr#8ab324a972145713466145e5daaf1e8351e6d7e7"
dependencies = [ dependencies = [
"btreecap",
"flatbuffers", "flatbuffers",
"lru", "lru",
"nostr", "nostr",
@@ -4072,7 +4057,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-gossip" name = "nostr-gossip"
version = "0.44.0" version = "0.44.0"
source = "git+https://github.com/rust-nostr/nostr#aa01f9fb8cd1ddbcc66e2b4ef58eeedbc0d54f56" source = "git+https://github.com/rust-nostr/nostr#8ab324a972145713466145e5daaf1e8351e6d7e7"
dependencies = [ dependencies = [
"nostr", "nostr",
] ]
@@ -4080,7 +4065,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-lmdb" name = "nostr-lmdb"
version = "0.44.0" version = "0.44.0"
source = "git+https://github.com/rust-nostr/nostr#aa01f9fb8cd1ddbcc66e2b4ef58eeedbc0d54f56" source = "git+https://github.com/rust-nostr/nostr#8ab324a972145713466145e5daaf1e8351e6d7e7"
dependencies = [ dependencies = [
"async-utility", "async-utility",
"flume", "flume",
@@ -4094,7 +4079,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-relay-pool" name = "nostr-relay-pool"
version = "0.44.0" version = "0.44.0"
source = "git+https://github.com/rust-nostr/nostr#aa01f9fb8cd1ddbcc66e2b4ef58eeedbc0d54f56" source = "git+https://github.com/rust-nostr/nostr#8ab324a972145713466145e5daaf1e8351e6d7e7"
dependencies = [ dependencies = [
"async-utility", "async-utility",
"async-wsocket", "async-wsocket",
@@ -4111,7 +4096,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-sdk" name = "nostr-sdk"
version = "0.44.1" version = "0.44.1"
source = "git+https://github.com/rust-nostr/nostr#aa01f9fb8cd1ddbcc66e2b4ef58eeedbc0d54f56" source = "git+https://github.com/rust-nostr/nostr#8ab324a972145713466145e5daaf1e8351e6d7e7"
dependencies = [ dependencies = [
"async-utility", "async-utility",
"nostr", "nostr",
@@ -4628,7 +4613,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]] [[package]]
name = "perf" name = "perf"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"collections", "collections",
"serde", "serde",
@@ -5254,7 +5239,7 @@ dependencies = [
[[package]] [[package]]
name = "refineable" name = "refineable"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"derive_refineable", "derive_refineable",
] ]
@@ -5352,7 +5337,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#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@@ -5406,7 +5391,7 @@ dependencies = [
[[package]] [[package]]
name = "rope" name = "rope"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"log", "log",
@@ -5872,7 +5857,7 @@ checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33"
[[package]] [[package]]
name = "semantic_version" name = "semantic_version"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"serde", "serde",
@@ -6327,7 +6312,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#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"log", "log",
@@ -6978,6 +6963,7 @@ version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [ dependencies = [
"log",
"pin-project-lite", "pin-project-lite",
"tracing-attributes", "tracing-attributes",
"tracing-core", "tracing-core",
@@ -7295,7 +7281,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]] [[package]]
name = "util" name = "util"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-fs", "async-fs",
@@ -7331,7 +7317,7 @@ dependencies = [
[[package]] [[package]]
name = "util_macros" name = "util_macros"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#1e2f15a3d70258ab366e9ac9309605749d5b0a27" source = "git+https://github.com/zed-industries/zed#de58a496efd3379dd787326c678b931ffff4213f"
dependencies = [ dependencies = [
"perf", "perf",
"quote", "quote",
@@ -7370,9 +7356,9 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]] [[package]]
name = "value-bag" name = "value-bag"
version = "1.11.1" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0"
dependencies = [ dependencies = [
"value-bag-serde1", "value-bag-serde1",
"value-bag-sval2", "value-bag-sval2",
@@ -7380,20 +7366,20 @@ dependencies = [
[[package]] [[package]]
name = "value-bag-serde1" name = "value-bag-serde1"
version = "1.11.1" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35540706617d373b118d550d41f5dfe0b78a0c195dc13c6815e92e2638432306" checksum = "16530907bfe2999a1773ca5900a65101e092c70f642f25cc23ca0c43573262c5"
dependencies = [ dependencies = [
"erased-serde", "erased-serde",
"serde", "serde_core",
"serde_fmt", "serde_fmt",
] ]
[[package]] [[package]]
name = "value-bag-sval2" name = "value-bag-sval2"
version = "1.11.1" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fe7e140a2658cc16f7ee7a86e413e803fc8f9b5127adc8755c19f9fefa63a52" checksum = "d00ae130edd690eaa877e4f40605d534790d1cf1d651e7685bd6a144521b251f"
dependencies = [ dependencies = [
"sval", "sval",
"sval_buffer", "sval_buffer",
@@ -8723,18 +8709,18 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524"
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.8.27" version = "0.8.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90"
dependencies = [ dependencies = [
"zerocopy-derive", "zerocopy-derive",
] ]
[[package]] [[package]]
name = "zerocopy-derive" name = "zerocopy-derive"
version = "0.8.27" version = "0.8.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View File

@@ -11,7 +11,11 @@ pub const BOOTSTRAP_RELAYS: [&str; 5] = [
]; ];
/// Search Relays. /// Search Relays.
pub const SEARCH_RELAYS: [&str; 1] = ["wss://relay.nostr.band"]; pub const SEARCH_RELAYS: [&str; 3] = [
"wss://relay.nostr.band",
"wss://search.nos.today",
"wss://relay.noswhere.com",
];
/// Default relay for Nostr Connect /// Default relay for Nostr Connect
pub const NOSTR_CONNECT_RELAY: &str = "wss://relay.nsec.app"; pub const NOSTR_CONNECT_RELAY: &str = "wss://relay.nsec.app";

View File

@@ -35,8 +35,8 @@ use ui::{h_flex, v_flex, ContextModal, IconName, Root, Sizable, StyledExt};
use crate::actions::{reset, DarkMode, KeyringPopup, Logout, Settings, ViewProfile, ViewRelays}; use crate::actions::{reset, DarkMode, KeyringPopup, Logout, Settings, ViewProfile, ViewRelays};
use crate::user::viewer; use crate::user::viewer;
use crate::views::compose::compose_button; use crate::views::compose::compose_button;
use crate::views::{onboarding, preferences, setup_relay, sidebar, startup, welcome}; use crate::views::{onboarding, preferences, setup_relay, startup, welcome};
use crate::{login, new_identity, user}; use crate::{login, new_identity, sidebar, user};
pub fn init(window: &mut Window, cx: &mut App) -> Entity<ChatSpace> { pub fn init(window: &mut Window, cx: &mut App) -> Entity<ChatSpace> {
cx.new(|cx| ChatSpace::new(window, cx)) cx.new(|cx| ChatSpace::new(window, cx))

View File

@@ -111,7 +111,7 @@ impl Login {
} }
fn login_with_bunker(&mut self, content: &str, window: &mut Window, cx: &mut Context<Self>) { fn login_with_bunker(&mut self, content: &str, window: &mut Window, cx: &mut Context<Self>) {
let Ok(uri) = NostrConnectURI::parse(content) else { let Ok(uri) = NostrConnectUri::parse(content) else {
self.set_error(t!("login.bunker_invalid"), cx); self.set_error(t!("login.bunker_invalid"), cx);
return; return;
}; };
@@ -165,7 +165,7 @@ impl Login {
fn save_connection( fn save_connection(
&mut self, &mut self,
keys: &Keys, keys: &Keys,
uri: &NostrConnectURI, uri: &NostrConnectUri,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {

View File

@@ -15,6 +15,7 @@ mod actions;
mod chatspace; mod chatspace;
mod login; mod login;
mod new_identity; mod new_identity;
mod sidebar;
mod user; mod user;
mod views; mod views;

View File

@@ -1,7 +1,7 @@
use std::collections::BTreeSet;
use std::ops::Range; use std::ops::Range;
use std::time::Duration; use std::time::Duration;
use account::Account;
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
use chat::{ChatEvent, ChatRegistry, Room, RoomKind}; use chat::{ChatEvent, ChatRegistry, Room, RoomKind};
use common::{DebouncedDelay, RenderedTimestamp, TextUtils, BOOTSTRAP_RELAYS, SEARCH_RELAYS}; use common::{DebouncedDelay, RenderedTimestamp, TextUtils, BOOTSTRAP_RELAYS, SEARCH_RELAYS};
@@ -13,7 +13,6 @@ use gpui::{
}; };
use gpui_tokio::Tokio; use gpui_tokio::Tokio;
use i18n::{shared_t, t}; use i18n::{shared_t, t};
use itertools::Itertools;
use list_item::RoomListItem; use list_item::RoomListItem;
use nostr_sdk::prelude::*; use nostr_sdk::prelude::*;
use settings::AppSettings; use settings::AppSettings;
@@ -31,42 +30,43 @@ use crate::actions::{RelayStatus, Reload};
mod list_item; mod list_item;
const FIND_DELAY: u64 = 600; const FIND_DELAY: u64 = 600;
const FIND_LIMIT: usize = 10; const FIND_LIMIT: usize = 20;
pub fn init(window: &mut Window, cx: &mut App) -> Entity<Sidebar> { pub fn init(window: &mut Window, cx: &mut App) -> Entity<Sidebar> {
Sidebar::new(window, cx) cx.new(|cx| Sidebar::new(window, cx))
} }
pub struct Sidebar { pub struct Sidebar {
name: SharedString, name: SharedString,
// Search
/// Focus handle for the sidebar
focus_handle: FocusHandle,
/// Image cache
image_cache: Entity<RetainAllImageCache>,
/// Search results
search_results: Entity<Option<Vec<Entity<Room>>>>,
/// Async search operation
search_task: Option<Task<()>>,
find_input: Entity<InputState>, find_input: Entity<InputState>,
find_debouncer: DebouncedDelay<Self>, find_debouncer: DebouncedDelay<Self>,
finding: bool, finding: bool,
cancel_handle: Entity<Option<smol::channel::Sender<()>>>,
local_result: Entity<Option<Vec<Entity<Room>>>>,
global_result: Entity<Option<Vec<Entity<Room>>>>,
// Rooms
indicator: Entity<Option<RoomKind>>, indicator: Entity<Option<RoomKind>>,
active_filter: Entity<RoomKind>, active_filter: Entity<RoomKind>,
// GPUI
focus_handle: FocusHandle, /// Event subscriptions
image_cache: Entity<RetainAllImageCache>, _subscriptions: SmallVec<[Subscription; 3]>,
#[allow(dead_code)]
subscriptions: SmallVec<[Subscription; 3]>,
} }
impl Sidebar { impl Sidebar {
pub fn new(window: &mut Window, cx: &mut App) -> Entity<Self> { fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
cx.new(|cx| Self::view(window, cx))
}
fn view(window: &mut Window, cx: &mut Context<Self>) -> Self {
let active_filter = cx.new(|_| RoomKind::Ongoing); let active_filter = cx.new(|_| RoomKind::Ongoing);
let indicator = cx.new(|_| None); let indicator = cx.new(|_| None);
let local_result = cx.new(|_| None); let search_results = cx.new(|_| None);
let global_result = cx.new(|_| None);
let cancel_handle = cx.new(|_| None);
let find_input = let find_input =
cx.new(|cx| InputState::new(window, cx).placeholder(t!("sidebar.search_label"))); cx.new(|cx| InputState::new(window, cx).placeholder(t!("sidebar.search_label")));
@@ -99,11 +99,13 @@ impl Sidebar {
// Subscribe for find input events // Subscribe for find input events
cx.subscribe_in(&find_input, window, |this, state, event, window, cx| { cx.subscribe_in(&find_input, window, |this, state, event, window, cx| {
match event { match event {
InputEvent::PressEnter { .. } => this.search(window, cx), InputEvent::PressEnter { .. } => {
this.search(window, cx);
}
InputEvent::Change => { InputEvent::Change => {
// Clear the result when input is empty // Clear the result when input is empty
if state.read(cx).value().is_empty() { if state.read(cx).value().is_empty() {
this.clear_search_results(window, cx); this.clear(window, cx);
} else { } else {
// Run debounced search // Run debounced search
this.find_debouncer.fire_new( this.find_debouncer.fire_new(
@@ -125,62 +127,65 @@ impl Sidebar {
image_cache: RetainAllImageCache::new(cx), image_cache: RetainAllImageCache::new(cx),
find_debouncer: DebouncedDelay::new(), find_debouncer: DebouncedDelay::new(),
finding: false, finding: false,
cancel_handle,
indicator, indicator,
active_filter, active_filter,
find_input, find_input,
local_result, search_results,
global_result, search_task: None,
subscriptions, _subscriptions: subscriptions,
} }
} }
async fn request_metadata(client: &Client, public_key: PublicKey) -> Result<(), Error> { async fn nip50(client: &Client, query: &str) -> Result<Vec<Event>, Error> {
let opts = SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE);
let kinds = vec![Kind::Metadata, Kind::ContactList];
let filter = Filter::new().author(public_key).kinds(kinds).limit(10);
client
.subscribe_to(BOOTSTRAP_RELAYS, filter, Some(opts))
.await?;
Ok(())
}
async fn nip50(client: &Client, query: &str) -> Result<BTreeSet<Room>, Error> {
let signer = client.signer().await?; let signer = client.signer().await?;
let public_key = signer.get_public_key().await?; let public_key = signer.get_public_key().await?;
let timeout = Duration::from_secs(2);
let mut rooms: BTreeSet<Room> = BTreeSet::new();
let filter = Filter::new() let filter = Filter::new()
.kind(Kind::Metadata) .kind(Kind::Metadata)
.search(query.to_lowercase()) .search(query.to_lowercase())
.limit(FIND_LIMIT); .limit(FIND_LIMIT);
if let Ok(events) = client let mut stream = client
.fetch_events_from(SEARCH_RELAYS, filter, timeout) .stream_events_from(SEARCH_RELAYS, filter, Duration::from_secs(3))
.await .await?;
{
// Process to verify the search results let mut results: Vec<Event> = Vec::with_capacity(FIND_LIMIT);
for event in events.into_iter().unique_by(|event| event.pubkey) {
while let Some(event) = stream.next().await {
// Skip if author is match current user // Skip if author is match current user
if event.pubkey == public_key { if event.pubkey == public_key {
continue; continue;
} }
// Request metadata event's author // Skip if the event has already been added
Self::request_metadata(client, event.pubkey).await?; if results.iter().any(|this| this.pubkey == event.pubkey) {
continue;
// Construct room
let room = Room::new(None, public_key, vec![event.pubkey]);
rooms.insert(room);
}
} }
Ok(rooms) results.push(event);
}
if results.is_empty() {
return Err(anyhow!("No results for query {query}"));
}
// Get all public keys
let public_keys: Vec<PublicKey> = results.iter().map(|event| event.pubkey).collect();
// Fetch metadata and contact lists if public keys is not empty
if !public_keys.is_empty() {
let opts = SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE);
let filter = Filter::new()
.kinds(vec![Kind::Metadata, Kind::ContactList])
.limit(public_keys.len() * 2)
.authors(public_keys);
client
.subscribe_to(BOOTSTRAP_RELAYS, filter, Some(opts))
.await?;
}
Ok(results)
} }
fn debounced_search(&self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> { fn debounced_search(&self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
@@ -192,63 +197,38 @@ impl Sidebar {
}) })
} }
fn search_by_nip50( fn search_by_nip50(&mut self, query: &str, window: &mut Window, cx: &mut Context<Self>) {
&mut self, let account = Account::global(cx);
query: &str, let public_key = account.read(cx).public_key();
rx: smol::channel::Receiver<()>,
window: &mut Window,
cx: &mut Context<Self>,
) {
let nostr = NostrRegistry::global(cx); let nostr = NostrRegistry::global(cx);
let client = nostr.read(cx).client(); let client = nostr.read(cx).client();
let query = query.to_owned(); let query = query.to_owned();
let query_cloned = query.clone();
let task = smol::future::or( self.search_task = Some(cx.spawn_in(window, async move |this, cx| {
Tokio::spawn(cx, async move { Self::nip50(&client, &query).await.ok() }), let result = Self::nip50(&client, &query).await;
Tokio::spawn(cx, async move {
let _ = rx.recv().await.is_ok();
None
}),
);
cx.spawn_in(window, async move |this, cx| {
match task.await {
Ok(Some(results)) => {
this.update_in(cx, |this, window, cx| { this.update_in(cx, |this, window, cx| {
let msg = t!("sidebar.empty", query = query_cloned); match result {
let rooms = results.into_iter().map(|r| cx.new(|_| r)).collect_vec(); Ok(results) => {
let rooms = results
.into_iter()
.map(|event| {
cx.new(|_| Room::new(None, public_key, vec![event.pubkey]))
})
.collect();
if rooms.is_empty() { this.set_results(rooms, cx);
window.push_notification(msg, cx);
} }
this.results(rooms, true, window, cx);
})
.ok();
}
// User cancelled the search
Ok(None) => {
cx.update(|window, cx| {
this.update(cx, |this, cx| {
this.set_finding(false, window, cx);
this.set_cancel_handle(None, cx);
})
})
.ok();
}
// Async task failed
Err(e) => { Err(e) => {
this.update_in(cx, |this, window, cx| {
window.push_notification(e.to_string(), cx); window.push_notification(e.to_string(), cx);
this.set_finding(false, window, cx);
this.set_cancel_handle(None, cx);
})
.ok();
} }
}; };
this.set_finding(false, window, cx);
}) })
.detach(); .ok();
}));
} }
fn search_by_nip05(&mut self, query: &str, window: &mut Window, cx: &mut Context<Self>) { fn search_by_nip05(&mut self, query: &str, window: &mut Window, cx: &mut Context<Self>) {
@@ -261,7 +241,8 @@ impl Sidebar {
Ok(profile) => { Ok(profile) => {
let signer = client.signer().await?; let signer = client.signer().await?;
let public_key = signer.get_public_key().await?; let public_key = signer.get_public_key().await?;
let room = Room::new(None, public_key, vec![profile.public_key]); let receivers = vec![profile.public_key];
let room = Room::new(None, public_key, receivers);
Ok(room) Ok(room)
} }
@@ -269,40 +250,25 @@ impl Sidebar {
} }
}); });
cx.spawn_in(window, async move |this, cx| { self.search_task = Some(cx.spawn_in(window, async move |this, cx| {
match task.await { let result = task.await;
this.update_in(cx, |this, window, cx| {
match result {
Ok(Ok(room)) => { Ok(Ok(room)) => {
cx.update(|window, cx| { this.set_results(vec![cx.new(|_| room)], cx);
this.update(cx, |this, cx| {
this.results(vec![cx.new(|_| room)], true, window, cx);
})
.ok();
})
.ok();
} }
Ok(Err(e)) => { Ok(Err(e)) => {
cx.update(|window, cx| {
this.update(cx, |this, cx| {
window.push_notification(e.to_string(), cx); window.push_notification(e.to_string(), cx);
this.set_cancel_handle(None, cx);
this.set_finding(false, window, cx);
})
})
.ok();
} }
Err(e) => { Err(e) => {
cx.update(|window, cx| {
this.update(cx, |this, cx| {
window.push_notification(e.to_string(), cx); window.push_notification(e.to_string(), cx);
this.set_cancel_handle(None, cx); }
}
this.set_finding(false, window, cx); this.set_finding(false, window, cx);
}) })
})
.ok(); .ok();
} }));
};
})
.detach();
} }
fn search_by_pubkey(&mut self, query: &str, window: &mut Window, cx: &mut Context<Self>) { fn search_by_pubkey(&mut self, query: &str, window: &mut Window, cx: &mut Context<Self>) {
@@ -310,7 +276,7 @@ impl Sidebar {
let client = nostr.read(cx).client(); let client = nostr.read(cx).client();
let Ok(public_key) = query.to_public_key() else { let Ok(public_key) = query.to_public_key() else {
window.push_notification(t!("common.pubkey_invalid"), cx); window.push_notification("Public Key is invalid", cx);
self.set_finding(false, window, cx); self.set_finding(false, window, cx);
return; return;
}; };
@@ -318,46 +284,49 @@ impl Sidebar {
let task: Task<Result<Room, Error>> = cx.background_spawn(async move { let task: Task<Result<Room, Error>> = cx.background_spawn(async move {
let signer = client.signer().await?; let signer = client.signer().await?;
let author = signer.get_public_key().await?; let author = signer.get_public_key().await?;
let room = Room::new(None, author, vec![public_key]);
Self::request_metadata(&client, public_key).await?; let opts = SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE);
let receivers = vec![public_key];
let room = Room::new(None, author, receivers);
let filter = Filter::new()
.kinds(vec![Kind::Metadata, Kind::ContactList])
.author(public_key)
.limit(2);
client
.subscribe_to(BOOTSTRAP_RELAYS, filter, Some(opts))
.await?;
Ok(room) Ok(room)
}); });
cx.spawn_in(window, async move |this, cx| { self.search_task = Some(cx.spawn_in(window, async move |this, cx| {
match task.await { let result = task.await;
Ok(room) => {
cx.update(|window, cx| {
this.update(cx, |this, cx| {
let chat = ChatRegistry::global(cx);
let result = chat.read(cx).search_by_public_key(public_key, cx);
if !result.is_empty() { this.update_in(cx, |this, window, cx| {
this.results(result, false, window, cx); match result {
Ok(room) => {
let chat = ChatRegistry::global(cx);
let local_results = chat.read(cx).search_by_public_key(public_key, cx);
if !local_results.is_empty() {
this.set_results(local_results, cx);
} else { } else {
this.results(vec![cx.new(|_| room)], true, window, cx); this.set_results(vec![cx.new(|_| room)], cx);
} }
})
.ok();
})
.ok();
} }
Err(e) => { Err(e) => {
cx.update(|window, cx| {
window.push_notification(e.to_string(), cx); window.push_notification(e.to_string(), cx);
})
.ok();
} }
}; };
this.set_finding(false, window, cx);
}) })
.detach(); .ok();
}));
} }
fn search(&mut self, window: &mut Window, cx: &mut Context<Self>) { fn search(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let (tx, rx) = smol::channel::bounded::<()>(1);
let tx_clone = tx.clone();
// Return if the query is empty // Return if the query is empty
if self.find_input.read(cx).value().is_empty() { if self.find_input.read(cx).value().is_empty() {
return; return;
@@ -365,15 +334,12 @@ impl Sidebar {
// Return if search is in progress // Return if search is in progress
if self.finding { if self.finding {
if self.cancel_handle.read(cx).is_none() { if self.search_task.is_none() {
window.push_notification(t!("sidebar.search_in_progress"), cx); window.push_notification("There is another search in progress", cx);
return; return;
} else { } else {
// This is a hack to cancel ongoing search request // Cancel ongoing search request
cx.background_spawn(async move { self.search_task = None;
tx.send(()).await.ok();
})
.detach();
} }
} }
@@ -398,48 +364,25 @@ impl Sidebar {
} }
} }
let chat = ChatRegistry::global(cx);
// Get all local results with current query // Get all local results with current query
let chat = ChatRegistry::global(cx);
let local_results = chat.read(cx).search(&query, cx); let local_results = chat.read(cx).search(&query, cx);
if !local_results.is_empty() {
// Try to update with local results first // Try to update with local results first
self.results(local_results, false, window, cx); if !local_results.is_empty() {
} else { self.set_results(local_results, cx);
return;
};
// If no local results, try global search via NIP-50 // If no local results, try global search via NIP-50
self.set_cancel_handle(Some(tx_clone), cx); self.search_by_nip50(&query, window, cx);
self.search_by_nip50(&query, rx, window, cx);
}
} }
fn results( fn set_results(&mut self, rooms: Vec<Entity<Room>>, cx: &mut Context<Self>) {
&mut self, self.search_results.update(cx, |this, cx| {
rooms: Vec<Entity<Room>>,
global: bool,
window: &mut Window,
cx: &mut Context<Self>,
) {
if self.finding {
self.set_finding(false, window, cx);
}
if self.cancel_handle.read(cx).is_some() {
self.set_cancel_handle(None, cx);
}
if !rooms.is_empty() {
if global {
self.global_result.update(cx, |this, cx| {
*this = Some(rooms); *this = Some(rooms);
cx.notify(); cx.notify();
}); });
} else {
self.local_result.update(cx, |this, cx| {
*this = Some(rooms);
cx.notify();
});
}
}
} }
fn set_finding(&mut self, status: bool, _window: &mut Window, cx: &mut Context<Self>) { fn set_finding(&mut self, status: bool, _window: &mut Window, cx: &mut Context<Self>) {
@@ -453,31 +396,14 @@ impl Sidebar {
cx.notify(); cx.notify();
} }
fn set_cancel_handle( fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
&mut self,
handle: Option<smol::channel::Sender<()>>,
cx: &mut Context<Self>,
) {
self.cancel_handle.update(cx, |this, cx| {
*this = handle;
cx.notify();
});
}
fn clear_search_results(&mut self, window: &mut Window, cx: &mut Context<Self>) {
// Reset the input state // Reset the input state
if self.finding { if self.finding {
self.set_finding(false, window, cx); self.set_finding(false, window, cx);
} }
// Clear all local results // Clear all local results
self.local_result.update(cx, |this, cx| { self.search_results.update(cx, |this, cx| {
*this = None;
cx.notify();
});
// Clear all global results
self.global_result.update(cx, |this, cx| {
*this = None; *this = None;
cx.notify(); cx.notify();
}); });
@@ -499,10 +425,11 @@ impl Sidebar {
} }
fn open_room(&mut self, id: u64, window: &mut Window, cx: &mut Context<Self>) { fn open_room(&mut self, id: u64, window: &mut Window, cx: &mut Context<Self>) {
let room = if let Some(room) = ChatRegistry::global(cx).read(cx).room(&id, cx) { let chat = ChatRegistry::global(cx);
let room = if let Some(room) = chat.read(cx).room(&id, cx) {
room room
} else { } else {
let Some(result) = self.global_result.read(cx).as_ref() else { let Some(result) = self.search_results.read(cx).as_ref() else {
window.push_notification(t!("common.room_error"), cx); window.push_notification(t!("common.room_error"), cx);
return; return;
}; };
@@ -513,12 +440,12 @@ impl Sidebar {
}; };
// Clear all search results // Clear all search results
self.clear_search_results(window, cx); self.clear(window, cx);
room room
}; };
ChatRegistry::global(cx).update(cx, |this, cx| { chat.update(cx, |this, cx| {
this.push_room(room, cx); this.push_room(room, cx);
}); });
} }
@@ -673,12 +600,10 @@ impl Render for Sidebar {
let loading = chat.read(cx).loading; let loading = chat.read(cx).loading;
// Get rooms from either search results or the chat registry // Get rooms from either search results or the chat registry
let rooms = if let Some(results) = self.local_result.read(cx).as_ref() { let rooms = if let Some(results) = self.search_results.read(cx).as_ref() {
results.to_owned()
} else if let Some(results) = self.global_result.read(cx).as_ref() {
results.to_owned() results.to_owned()
} else { } else {
#[allow(clippy::collapsible_else_if)] // Filter rooms based on the active filter
if self.active_filter.read(cx) == &RoomKind::Ongoing { if self.active_filter.read(cx) == &RoomKind::Ongoing {
chat.read(cx).ongoing_rooms(cx) chat.read(cx).ongoing_rooms(cx)
} else { } else {
@@ -717,13 +642,19 @@ impl Render for Sidebar {
.cleanable() .cleanable()
.appearance(true) .appearance(true)
.text_xs() .text_xs()
.suffix( .map(|this| {
if !self.find_input.read(cx).loading {
this.suffix(
Button::new("find") Button::new("find")
.icon(IconName::Search) .icon(IconName::Search)
.tooltip(t!("sidebar.search_tooltip")) .tooltip(t!("sidebar.search_tooltip"))
.transparent() .transparent()
.small(), .small(),
), )
} else {
this
}
}),
), ),
) )
// Chat Rooms // Chat Rooms

View File

@@ -3,6 +3,5 @@ pub mod onboarding;
pub mod preferences; pub mod preferences;
pub mod screening; pub mod screening;
pub mod setup_relay; pub mod setup_relay;
pub mod sidebar;
pub mod startup; pub mod startup;
pub mod welcome; pub mod welcome;

View File

@@ -78,7 +78,7 @@ impl Onboarding {
let timeout = Duration::from_secs(NOSTR_CONNECT_TIMEOUT); let timeout = Duration::from_secs(NOSTR_CONNECT_TIMEOUT);
let relay = RelayUrl::parse(NOSTR_CONNECT_RELAY).unwrap(); let relay = RelayUrl::parse(NOSTR_CONNECT_RELAY).unwrap();
let uri = NostrConnectURI::client(app_keys.public_key(), vec![relay], CLIENT_NAME); let uri = NostrConnectUri::client(app_keys.public_key(), vec![relay], CLIENT_NAME);
let qr_code = uri.to_string().to_qr(); let qr_code = uri.to_string().to_qr();
// NIP46: https://github.com/nostr-protocol/nips/blob/master/46.md // NIP46: https://github.com/nostr-protocol/nips/blob/master/46.md
@@ -119,7 +119,7 @@ impl Onboarding {
fn save_connection( fn save_connection(
&mut self, &mut self,
uri: &NostrConnectURI, uri: &NostrConnectUri,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {

View File

@@ -76,7 +76,7 @@ impl Startup {
// Try to login with bunker // Try to login with bunker
if secret.starts_with("bunker://") { if secret.starts_with("bunker://") {
match NostrConnectURI::parse(secret) { match NostrConnectUri::parse(secret) {
Ok(uri) => { Ok(uri) => {
self.login_with_bunker(uri, window, cx); self.login_with_bunker(uri, window, cx);
} }
@@ -102,7 +102,7 @@ impl Startup {
fn login_with_bunker( fn login_with_bunker(
&mut self, &mut self,
uri: NostrConnectURI, uri: NostrConnectUri,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {

View File

@@ -69,9 +69,15 @@ impl NostrRegistry {
timeout: Duration::from_secs(600), timeout: Duration::from_secs(600),
}); });
// Construct the nostr client // Construct the lmdb
let lmdb = cx.background_executor().block(async move {
let path = config_dir().join("nostr"); let path = config_dir().join("nostr");
let lmdb = NostrLMDB::open(path).expect("Failed to initialize database"); NostrLMDB::open(path)
.await
.expect("Failed to initialize database")
});
// Construct the nostr client
let client = ClientBuilder::default().database(lmdb).opts(opts).build(); let client = ClientBuilder::default().database(lmdb).opts(opts).build();
let tracker = Arc::new(RwLock::new(EventTracker::default())); let tracker = Arc::new(RwLock::new(EventTracker::default()));