feat: refactor encryption panel #13
103
Cargo.lock
generated
103
Cargo.lock
generated
@@ -772,6 +772,15 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block2"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
|
||||||
|
dependencies = [
|
||||||
|
"objc2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blocking"
|
name = "blocking"
|
||||||
version = "1.6.2"
|
version = "1.6.2"
|
||||||
@@ -1189,7 +1198,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collections"
|
name = "collections"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.1",
|
||||||
@@ -1318,6 +1327,7 @@ dependencies = [
|
|||||||
"chat",
|
"chat",
|
||||||
"chat_ui",
|
"chat_ui",
|
||||||
"common",
|
"common",
|
||||||
|
"core-text",
|
||||||
"device",
|
"device",
|
||||||
"futures",
|
"futures",
|
||||||
"gpui",
|
"gpui",
|
||||||
@@ -1400,19 +1410,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "core-graphics"
|
|
||||||
version = "0.25.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.11.0",
|
|
||||||
"core-foundation 0.10.0",
|
|
||||||
"core-graphics-types 0.2.0",
|
|
||||||
"foreign-types",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-graphics-helmer-fork"
|
name = "core-graphics-helmer-fork"
|
||||||
version = "0.24.0"
|
version = "0.24.0"
|
||||||
@@ -1463,13 +1460,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-text"
|
name = "core-text"
|
||||||
version = "21.1.0"
|
version = "21.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fce32d657e17d6e4a8e70fe2ae6875218015f320620a78e5949d228bc76622bd"
|
checksum = "a593227b66cbd4007b2a050dfdd9e1d1318311409c8d600dc82ba1b15ca9c130"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation 0.10.0",
|
"core-foundation 0.10.0",
|
||||||
"core-graphics 0.25.0",
|
"core-graphics 0.24.0",
|
||||||
"foreign-types",
|
"foreign-types",
|
||||||
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1646,7 +1644,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#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1670,6 +1668,8 @@ dependencies = [
|
|||||||
"smallvec",
|
"smallvec",
|
||||||
"smol",
|
"smol",
|
||||||
"state",
|
"state",
|
||||||
|
"theme",
|
||||||
|
"ui",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1730,6 +1730,18 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
|
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dispatch2"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.0",
|
||||||
|
"block2",
|
||||||
|
"libc",
|
||||||
|
"objc2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "displaydoc"
|
name = "displaydoc"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
@@ -2587,7 +2599,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui"
|
name = "gpui"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-channel 2.5.0",
|
"async-channel 2.5.0",
|
||||||
@@ -2666,7 +2678,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui_linux"
|
name = "gpui_linux"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"as-raw-xcb-connection",
|
"as-raw-xcb-connection",
|
||||||
@@ -2714,11 +2726,10 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui_macos"
|
name = "gpui_macos"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-task",
|
"async-task",
|
||||||
"bindgen",
|
|
||||||
"block",
|
"block",
|
||||||
"cbindgen",
|
"cbindgen",
|
||||||
"cocoa 0.26.0",
|
"cocoa 0.26.0",
|
||||||
@@ -2730,6 +2741,7 @@ dependencies = [
|
|||||||
"core-video",
|
"core-video",
|
||||||
"ctor",
|
"ctor",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
|
"dispatch2",
|
||||||
"etagere",
|
"etagere",
|
||||||
"foreign-types",
|
"foreign-types",
|
||||||
"futures",
|
"futures",
|
||||||
@@ -2750,12 +2762,13 @@ dependencies = [
|
|||||||
"strum",
|
"strum",
|
||||||
"util",
|
"util",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
"zed-font-kit",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui_macros"
|
name = "gpui_macros"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -2766,7 +2779,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui_platform"
|
name = "gpui_platform"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"gpui",
|
"gpui",
|
||||||
@@ -2779,7 +2792,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#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"gpui",
|
"gpui",
|
||||||
@@ -2790,7 +2803,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui_util"
|
name = "gpui_util"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"log",
|
"log",
|
||||||
@@ -2799,7 +2812,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui_web"
|
name = "gpui_web"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
@@ -2822,7 +2835,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui_wgpu"
|
name = "gpui_wgpu"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
@@ -2850,7 +2863,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui_windows"
|
name = "gpui_windows"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"collections",
|
"collections",
|
||||||
@@ -3094,7 +3107,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#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-compression",
|
"async-compression",
|
||||||
@@ -3119,7 +3132,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#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls",
|
"rustls",
|
||||||
"rustls-platform-verifier",
|
"rustls-platform-verifier",
|
||||||
@@ -3880,7 +3893,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "media"
|
name = "media"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bindgen",
|
"bindgen",
|
||||||
@@ -4624,7 +4637,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#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"collections",
|
"collections",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -4742,9 +4755,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "piper"
|
name = "piper"
|
||||||
version = "0.2.4"
|
version = "0.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
|
checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"fastrand 2.3.0",
|
"fastrand 2.3.0",
|
||||||
@@ -5305,7 +5318,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "refineable"
|
name = "refineable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_refineable",
|
"derive_refineable",
|
||||||
]
|
]
|
||||||
@@ -5404,7 +5417,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#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -5459,7 +5472,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "rope"
|
name = "rope"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"log",
|
"log",
|
||||||
@@ -5721,7 +5734,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "scheduler"
|
name = "scheduler"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-task",
|
"async-task",
|
||||||
"backtrace",
|
"backtrace",
|
||||||
@@ -6315,7 +6328,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#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"log",
|
"log",
|
||||||
@@ -7258,7 +7271,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#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-fs",
|
"async-fs",
|
||||||
@@ -7297,7 +7310,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#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"perf",
|
"perf",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -9100,7 +9113,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "zlog"
|
name = "zlog"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -9117,7 +9130,7 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "ztracing"
|
name = "ztracing"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
@@ -9128,7 +9141,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "ztracing_macro"
|
name = "ztracing_macro"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#1123140e40f47ad7b12815c16de0d49e42e36617"
|
source = "git+https://github.com/zed-industries/zed#b06522e978b5ed24bcc2cf07a6de794179d69176"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zune-core"
|
name = "zune-core"
|
||||||
|
|||||||
@@ -9,17 +9,14 @@ edition = "2021"
|
|||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|
||||||
# GPUI
|
# GPUI
|
||||||
gpui = { git = "https://github.com/zed-industries/zed" }
|
gpui = { git = "https://github.com/zed-industries/zed" }
|
||||||
gpui_platform = { git = "https://github.com/zed-industries/zed", features = ["screen-capture", "x11", "wayland", "runtime_shaders"] }
|
gpui_platform = { git = "https://github.com/zed-industries/zed", features = ["font-kit", "screen-capture", "x11", "wayland", "runtime_shaders"] }
|
||||||
gpui_linux = { git = "https://github.com/zed-industries/zed" }
|
gpui_linux = { git = "https://github.com/zed-industries/zed" }
|
||||||
gpui_windows = { git = "https://github.com/zed-industries/zed" }
|
gpui_windows = { git = "https://github.com/zed-industries/zed" }
|
||||||
gpui_macos = { git = "https://github.com/zed-industries/zed" }
|
gpui_macos = { git = "https://github.com/zed-industries/zed" }
|
||||||
gpui_tokio = { git = "https://github.com/zed-industries/zed" }
|
gpui_tokio = { git = "https://github.com/zed-industries/zed" }
|
||||||
reqwest_client = { git = "https://github.com/zed-industries/zed" }
|
reqwest_client = { git = "https://github.com/zed-industries/zed" }
|
||||||
# TODO: remove after fixed, issue: https://github.com/zed-industries/zed/issues/47168
|
|
||||||
core-text = "=21.0.0"
|
|
||||||
|
|
||||||
# Nostr
|
# Nostr
|
||||||
nostr-lmdb = { git = "https://github.com/rust-nostr/nostr" }
|
nostr-lmdb = { git = "https://github.com/rust-nostr/nostr" }
|
||||||
|
|||||||
@@ -65,3 +65,7 @@ webbrowser.workspace = true
|
|||||||
|
|
||||||
indexset = "0.12.3"
|
indexset = "0.12.3"
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["fmt"] }
|
tracing-subscriber = { version = "0.3.18", features = ["fmt"] }
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
|
# Temporary workaround https://github.com/zed-industries/zed/issues/47168
|
||||||
|
core-text = "=21.0.0"
|
||||||
|
|||||||
@@ -1,292 +0,0 @@
|
|||||||
use anyhow::Error;
|
|
||||||
use device::DeviceRegistry;
|
|
||||||
use gpui::prelude::FluentBuilder;
|
|
||||||
use gpui::{
|
|
||||||
div, px, AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable,
|
|
||||||
IntoElement, ParentElement, Render, SharedString, Styled, Task, Window,
|
|
||||||
};
|
|
||||||
use nostr_sdk::prelude::*;
|
|
||||||
use person::{shorten_pubkey, PersonRegistry};
|
|
||||||
use state::Announcement;
|
|
||||||
use theme::ActiveTheme;
|
|
||||||
use ui::button::{Button, ButtonVariants};
|
|
||||||
use ui::dock_area::panel::{Panel, PanelEvent};
|
|
||||||
use ui::notification::Notification;
|
|
||||||
use ui::{divider, h_flex, v_flex, Disableable, IconName, Sizable, StyledExt, WindowExtension};
|
|
||||||
|
|
||||||
const MSG: &str =
|
|
||||||
"Encryption Key is a special key that used to encrypt and decrypt your messages. \
|
|
||||||
Your identity is completely decoupled from all encryption processes to protect your privacy.";
|
|
||||||
|
|
||||||
const NOTICE: &str = "By resetting your encryption key, you will lose access to \
|
|
||||||
all your encrypted messages before. This action cannot be undone.";
|
|
||||||
|
|
||||||
pub fn init(public_key: PublicKey, window: &mut Window, cx: &mut App) -> Entity<EncryptionPanel> {
|
|
||||||
cx.new(|cx| EncryptionPanel::new(public_key, window, cx))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct EncryptionPanel {
|
|
||||||
name: SharedString,
|
|
||||||
focus_handle: FocusHandle,
|
|
||||||
|
|
||||||
/// User's public key
|
|
||||||
public_key: PublicKey,
|
|
||||||
|
|
||||||
/// Whether the panel is loading
|
|
||||||
loading: bool,
|
|
||||||
|
|
||||||
/// Tasks
|
|
||||||
tasks: Vec<Task<Result<(), Error>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EncryptionPanel {
|
|
||||||
fn new(public_key: PublicKey, _window: &mut Window, cx: &mut Context<Self>) -> Self {
|
|
||||||
Self {
|
|
||||||
name: "Encryption".into(),
|
|
||||||
focus_handle: cx.focus_handle(),
|
|
||||||
public_key,
|
|
||||||
loading: false,
|
|
||||||
tasks: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_loading(&mut self, status: bool, cx: &mut Context<Self>) {
|
|
||||||
self.loading = status;
|
|
||||||
cx.notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn approve(&mut self, event: &Event, window: &mut Window, cx: &mut Context<Self>) {
|
|
||||||
let device = DeviceRegistry::global(cx);
|
|
||||||
let task = device.read(cx).approve(event, cx);
|
|
||||||
let id = event.id;
|
|
||||||
|
|
||||||
// Update loading status
|
|
||||||
self.set_loading(true, cx);
|
|
||||||
|
|
||||||
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
|
|
||||||
match task.await {
|
|
||||||
Ok(_) => {
|
|
||||||
this.update_in(cx, |this, window, cx| {
|
|
||||||
// Reset loading status
|
|
||||||
this.set_loading(false, cx);
|
|
||||||
|
|
||||||
// Remove request
|
|
||||||
device.update(cx, |this, cx| {
|
|
||||||
this.remove_request(&id, cx);
|
|
||||||
});
|
|
||||||
|
|
||||||
window.push_notification("Approved", cx);
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
this.update_in(cx, |this, window, cx| {
|
|
||||||
this.set_loading(false, cx);
|
|
||||||
window.push_notification(Notification::error(e.to_string()), cx);
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_requests(&mut self, cx: &mut Context<Self>) -> Vec<impl IntoElement> {
|
|
||||||
const TITLE: &str = "You've requested for the Encryption Key from:";
|
|
||||||
|
|
||||||
let device = DeviceRegistry::global(cx);
|
|
||||||
let requests = device.read(cx).requests.clone();
|
|
||||||
let mut items = Vec::new();
|
|
||||||
|
|
||||||
for event in requests.into_iter() {
|
|
||||||
let request = Announcement::from(&event);
|
|
||||||
let client_name = request.client_name();
|
|
||||||
let target = request.public_key();
|
|
||||||
|
|
||||||
items.push(
|
|
||||||
v_flex()
|
|
||||||
.gap_2()
|
|
||||||
.text_sm()
|
|
||||||
.child(SharedString::from(TITLE))
|
|
||||||
.child(
|
|
||||||
v_flex()
|
|
||||||
.h_12()
|
|
||||||
.items_center()
|
|
||||||
.justify_center()
|
|
||||||
.px_2()
|
|
||||||
.rounded(cx.theme().radius)
|
|
||||||
.bg(cx.theme().warning_background)
|
|
||||||
.text_color(cx.theme().warning_foreground)
|
|
||||||
.child(client_name.clone()),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
h_flex()
|
|
||||||
.h_7()
|
|
||||||
.w_full()
|
|
||||||
.px_2()
|
|
||||||
.rounded(cx.theme().radius)
|
|
||||||
.bg(cx.theme().elevated_surface_background)
|
|
||||||
.child(SharedString::from(target.to_hex())),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
h_flex().justify_end().gap_2().child(
|
|
||||||
Button::new("approve")
|
|
||||||
.label("Approve")
|
|
||||||
.ghost()
|
|
||||||
.small()
|
|
||||||
.disabled(self.loading)
|
|
||||||
.loading(self.loading)
|
|
||||||
.on_click(cx.listener(move |this, _ev, window, cx| {
|
|
||||||
this.approve(&event, window, cx);
|
|
||||||
})),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
items
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Panel for EncryptionPanel {
|
|
||||||
fn panel_id(&self) -> SharedString {
|
|
||||||
self.name.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn title(&self, _cx: &App) -> AnyElement {
|
|
||||||
self.name.clone().into_any_element()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EventEmitter<PanelEvent> for EncryptionPanel {}
|
|
||||||
|
|
||||||
impl Focusable for EncryptionPanel {
|
|
||||||
fn focus_handle(&self, _: &App) -> gpui::FocusHandle {
|
|
||||||
self.focus_handle.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Render for EncryptionPanel {
|
|
||||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
||||||
let device = DeviceRegistry::global(cx);
|
|
||||||
let state = device.read(cx).state();
|
|
||||||
let has_requests = device.read(cx).has_requests();
|
|
||||||
|
|
||||||
let persons = PersonRegistry::global(cx);
|
|
||||||
let profile = persons.read(cx).get(&self.public_key, cx);
|
|
||||||
|
|
||||||
let Some(announcement) = profile.announcement() else {
|
|
||||||
return div();
|
|
||||||
};
|
|
||||||
|
|
||||||
let pubkey = SharedString::from(shorten_pubkey(announcement.public_key(), 16));
|
|
||||||
let client_name = announcement.client_name();
|
|
||||||
|
|
||||||
v_flex()
|
|
||||||
.p_3()
|
|
||||||
.gap_3()
|
|
||||||
.w_full()
|
|
||||||
.child(
|
|
||||||
div()
|
|
||||||
.text_xs()
|
|
||||||
.text_color(cx.theme().text_muted)
|
|
||||||
.child(SharedString::from(MSG)),
|
|
||||||
)
|
|
||||||
.child(divider(cx))
|
|
||||||
.child(
|
|
||||||
v_flex()
|
|
||||||
.gap_3()
|
|
||||||
.text_sm()
|
|
||||||
.child(
|
|
||||||
v_flex()
|
|
||||||
.gap_1p5()
|
|
||||||
.child(
|
|
||||||
div()
|
|
||||||
.text_color(cx.theme().text_muted)
|
|
||||||
.child(SharedString::from("Device Name:")),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
h_flex()
|
|
||||||
.h_12()
|
|
||||||
.items_center()
|
|
||||||
.justify_center()
|
|
||||||
.rounded(cx.theme().radius)
|
|
||||||
.bg(cx.theme().elevated_surface_background)
|
|
||||||
.child(client_name.clone()),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
v_flex()
|
|
||||||
.gap_1p5()
|
|
||||||
.child(
|
|
||||||
div()
|
|
||||||
.text_color(cx.theme().text_muted)
|
|
||||||
.child(SharedString::from("Encryption Public Key:")),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
h_flex()
|
|
||||||
.h_7()
|
|
||||||
.w_full()
|
|
||||||
.px_2()
|
|
||||||
.rounded(cx.theme().radius)
|
|
||||||
.bg(cx.theme().elevated_surface_background)
|
|
||||||
.child(pubkey),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.when(has_requests, |this| {
|
|
||||||
this.child(divider(cx)).child(
|
|
||||||
v_flex()
|
|
||||||
.gap_1p5()
|
|
||||||
.w_full()
|
|
||||||
.child(
|
|
||||||
div()
|
|
||||||
.text_color(cx.theme().text_muted)
|
|
||||||
.child(SharedString::from("Requests:")),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
v_flex()
|
|
||||||
.gap_2()
|
|
||||||
.flex_1()
|
|
||||||
.w_full()
|
|
||||||
.children(self.render_requests(cx)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.child(divider(cx))
|
|
||||||
.when(state.requesting(), |this| {
|
|
||||||
this.child(
|
|
||||||
h_flex()
|
|
||||||
.h_8()
|
|
||||||
.justify_center()
|
|
||||||
.text_xs()
|
|
||||||
.text_center()
|
|
||||||
.text_color(cx.theme().text_accent)
|
|
||||||
.bg(cx.theme().elevated_surface_background)
|
|
||||||
.rounded(cx.theme().radius)
|
|
||||||
.child(SharedString::from(
|
|
||||||
"Please open other device and approve the request",
|
|
||||||
)),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.child(
|
|
||||||
v_flex()
|
|
||||||
.gap_1()
|
|
||||||
.child(
|
|
||||||
Button::new("reset")
|
|
||||||
.icon(IconName::Reset)
|
|
||||||
.label("Reset")
|
|
||||||
.warning()
|
|
||||||
.small()
|
|
||||||
.font_semibold(),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
div()
|
|
||||||
.italic()
|
|
||||||
.text_size(px(10.))
|
|
||||||
.text_color(cx.theme().text_muted)
|
|
||||||
.child(SharedString::from(NOTICE)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
pub mod backup;
|
pub mod backup;
|
||||||
pub mod connect;
|
pub mod connect;
|
||||||
pub mod contact_list;
|
pub mod contact_list;
|
||||||
pub mod encryption_key;
|
|
||||||
pub mod greeter;
|
pub mod greeter;
|
||||||
pub mod import;
|
pub mod import;
|
||||||
pub mod messaging_relays;
|
pub mod messaging_relays;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use ::settings::AppSettings;
|
use ::settings::AppSettings;
|
||||||
use chat::{ChatEvent, ChatRegistry, InboxState};
|
use chat::{ChatEvent, ChatRegistry, InboxState};
|
||||||
|
use device::DeviceRegistry;
|
||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, px, Action, App, AppContext, Axis, Context, Entity, InteractiveElement, IntoElement,
|
div, px, Action, App, AppContext, Axis, Context, Entity, InteractiveElement, IntoElement,
|
||||||
@@ -19,14 +20,20 @@ use ui::dock_area::dock::DockPlacement;
|
|||||||
use ui::dock_area::panel::PanelView;
|
use ui::dock_area::panel::PanelView;
|
||||||
use ui::dock_area::{ClosePanel, DockArea, DockItem};
|
use ui::dock_area::{ClosePanel, DockArea, DockItem};
|
||||||
use ui::menu::{DropdownMenu, PopupMenuItem};
|
use ui::menu::{DropdownMenu, PopupMenuItem};
|
||||||
|
use ui::notification::Notification;
|
||||||
use ui::{h_flex, v_flex, IconName, Root, Sizable, WindowExtension};
|
use ui::{h_flex, v_flex, IconName, Root, Sizable, WindowExtension};
|
||||||
|
|
||||||
use crate::dialogs::settings;
|
use crate::dialogs::settings;
|
||||||
use crate::panels::{
|
use crate::panels::{backup, contact_list, greeter, messaging_relays, profile, relay_list};
|
||||||
backup, contact_list, encryption_key, greeter, messaging_relays, profile, relay_list,
|
|
||||||
};
|
|
||||||
use crate::sidebar;
|
use crate::sidebar;
|
||||||
|
|
||||||
|
const ENC_MSG: &str =
|
||||||
|
"Encryption Key is a special key that used to encrypt and decrypt your messages. \
|
||||||
|
Your identity is completely decoupled from all encryption processes to protect your privacy.";
|
||||||
|
|
||||||
|
const ENC_WARN: &str = "By resetting your encryption key, you will lose access to \
|
||||||
|
all your encrypted messages before. This action cannot be undone.";
|
||||||
|
|
||||||
pub fn init(window: &mut Window, cx: &mut App) -> Entity<Workspace> {
|
pub fn init(window: &mut Window, cx: &mut App) -> Entity<Workspace> {
|
||||||
cx.new(|cx| Workspace::new(window, cx))
|
cx.new(|cx| Workspace::new(window, cx))
|
||||||
}
|
}
|
||||||
@@ -36,12 +43,13 @@ pub fn init(window: &mut Window, cx: &mut App) -> Entity<Workspace> {
|
|||||||
enum Command {
|
enum Command {
|
||||||
ToggleTheme,
|
ToggleTheme,
|
||||||
|
|
||||||
|
RefreshEncryption,
|
||||||
RefreshRelayList,
|
RefreshRelayList,
|
||||||
RefreshMessagingRelays,
|
RefreshMessagingRelays,
|
||||||
|
ResetEncryption,
|
||||||
|
|
||||||
ShowRelayList,
|
ShowRelayList,
|
||||||
ShowMessaging,
|
ShowMessaging,
|
||||||
ShowEncryption,
|
|
||||||
ShowProfile,
|
ShowProfile,
|
||||||
ShowSettings,
|
ShowSettings,
|
||||||
ShowBackup,
|
ShowBackup,
|
||||||
@@ -238,21 +246,6 @@ impl Workspace {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Command::ShowEncryption => {
|
|
||||||
let nostr = NostrRegistry::global(cx);
|
|
||||||
let signer = nostr.read(cx).signer();
|
|
||||||
|
|
||||||
if let Some(public_key) = signer.public_key() {
|
|
||||||
self.dock.update(cx, |this, cx| {
|
|
||||||
this.add_panel(
|
|
||||||
Arc::new(encryption_key::init(public_key, window, cx)),
|
|
||||||
DockPlacement::Right,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Command::ShowMessaging => {
|
Command::ShowMessaging => {
|
||||||
self.dock.update(cx, |this, cx| {
|
self.dock.update(cx, |this, cx| {
|
||||||
this.add_panel(
|
this.add_panel(
|
||||||
@@ -273,12 +266,21 @@ impl Workspace {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Command::RefreshEncryption => {
|
||||||
|
let device = DeviceRegistry::global(cx);
|
||||||
|
device.update(cx, |this, cx| {
|
||||||
|
this.get_announcement(cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
Command::RefreshRelayList => {
|
Command::RefreshRelayList => {
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
nostr.update(cx, |this, cx| {
|
nostr.update(cx, |this, cx| {
|
||||||
this.ensure_relay_list(cx);
|
this.ensure_relay_list(cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Command::ResetEncryption => {
|
||||||
|
self.confirm_reset_encryption(window, cx);
|
||||||
|
}
|
||||||
Command::RefreshMessagingRelays => {
|
Command::RefreshMessagingRelays => {
|
||||||
let chat = ChatRegistry::global(cx);
|
let chat = ChatRegistry::global(cx);
|
||||||
chat.update(cx, |this, cx| {
|
chat.update(cx, |this, cx| {
|
||||||
@@ -291,6 +293,54 @@ impl Workspace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn confirm_reset_encryption(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
window.open_modal(cx, |this, _window, cx| {
|
||||||
|
this.confirm()
|
||||||
|
.show_close(true)
|
||||||
|
.title("Reset Encryption Keys")
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.gap_1()
|
||||||
|
.text_sm()
|
||||||
|
.child(SharedString::from(ENC_MSG))
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.italic()
|
||||||
|
.text_color(cx.theme().warning_active)
|
||||||
|
.child(SharedString::from(ENC_WARN)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.on_ok(move |_ev, window, cx| {
|
||||||
|
let device = DeviceRegistry::global(cx);
|
||||||
|
let task = device.read(cx).create_encryption(cx);
|
||||||
|
|
||||||
|
window
|
||||||
|
.spawn(cx, async move |cx| {
|
||||||
|
let result = task.await;
|
||||||
|
|
||||||
|
cx.update(|window, cx| match result {
|
||||||
|
Ok(keys) => {
|
||||||
|
device.update(cx, |this, cx| {
|
||||||
|
this.set_signer(keys, cx);
|
||||||
|
this.listen_request(cx);
|
||||||
|
});
|
||||||
|
window.close_modal(cx);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
window
|
||||||
|
.push_notification(Notification::error(e.to_string()), cx);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
|
||||||
|
// false to keep modal open
|
||||||
|
false
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn theme_selector(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
fn theme_selector(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
window.open_modal(cx, move |this, _window, cx| {
|
window.open_modal(cx, move |this, _window, cx| {
|
||||||
let registry = ThemeRegistry::global(cx);
|
let registry = ThemeRegistry::global(cx);
|
||||||
@@ -471,8 +521,39 @@ impl Workspace {
|
|||||||
.tooltip("Decoupled encryption key")
|
.tooltip("Decoupled encryption key")
|
||||||
.small()
|
.small()
|
||||||
.ghost()
|
.ghost()
|
||||||
.on_click(|_ev, window, cx| {
|
.dropdown_menu(move |this, _window, cx| {
|
||||||
window.dispatch_action(Box::new(Command::ShowEncryption), cx);
|
let device = DeviceRegistry::global(cx);
|
||||||
|
let state = device.read(cx).state();
|
||||||
|
|
||||||
|
this.min_w(px(260.))
|
||||||
|
.item(PopupMenuItem::element(move |_window, _cx| {
|
||||||
|
h_flex()
|
||||||
|
.px_1()
|
||||||
|
.w_full()
|
||||||
|
.gap_2()
|
||||||
|
.text_sm()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.size_1p5()
|
||||||
|
.rounded_full()
|
||||||
|
.when(state.set(), |this| this.bg(gpui::green()))
|
||||||
|
.when(state.requesting(), |this| {
|
||||||
|
this.bg(gpui::yellow())
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.child(SharedString::from(state.to_string()))
|
||||||
|
}))
|
||||||
|
.separator()
|
||||||
|
.menu_with_icon(
|
||||||
|
"Reload",
|
||||||
|
IconName::Refresh,
|
||||||
|
Box::new(Command::RefreshEncryption),
|
||||||
|
)
|
||||||
|
.menu_with_icon(
|
||||||
|
"Reset",
|
||||||
|
IconName::Warning,
|
||||||
|
Box::new(Command::ResetEncryption),
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ publish.workspace = true
|
|||||||
common = { path = "../common" }
|
common = { path = "../common" }
|
||||||
state = { path = "../state" }
|
state = { path = "../state" }
|
||||||
person = { path = "../person" }
|
person = { path = "../person" }
|
||||||
|
ui = { path = "../ui" }
|
||||||
|
theme = { path = "../theme" }
|
||||||
|
|
||||||
gpui.workspace = true
|
gpui.workspace = true
|
||||||
nostr-sdk.workspace = true
|
nostr-sdk.workspace = true
|
||||||
|
|||||||
@@ -1,16 +1,28 @@
|
|||||||
|
use std::cell::Cell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use anyhow::{anyhow, Context as AnyhowContext, Error};
|
use anyhow::{anyhow, Context as AnyhowContext, Error};
|
||||||
use gpui::{App, AppContext, Context, Entity, Global, Subscription, Task, Window};
|
use gpui::{
|
||||||
|
div, App, AppContext, Context, Entity, Global, IntoElement, ParentElement, SharedString,
|
||||||
|
Styled, Subscription, Task, Window,
|
||||||
|
};
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use person::PersonRegistry;
|
use person::PersonRegistry;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use state::{
|
use state::{
|
||||||
app_name, Announcement, DeviceState, NostrRegistry, RelayState, DEVICE_GIFTWRAP, TIMEOUT,
|
app_name, Announcement, DeviceState, NostrRegistry, RelayState, DEVICE_GIFTWRAP, TIMEOUT,
|
||||||
};
|
};
|
||||||
|
use theme::ActiveTheme;
|
||||||
|
use ui::avatar::Avatar;
|
||||||
|
use ui::button::{Button, ButtonVariants};
|
||||||
|
use ui::notification::Notification;
|
||||||
|
use ui::{h_flex, v_flex, Disableable, IconName, Sizable, WindowExtension};
|
||||||
|
|
||||||
const IDENTIFIER: &str = "coop:device";
|
const IDENTIFIER: &str = "coop:device";
|
||||||
|
const MSG: &str = "You've requested an encryption key from another device. \
|
||||||
|
Approve to allow Coop to share with it.";
|
||||||
|
|
||||||
pub fn init(window: &mut Window, cx: &mut App) {
|
pub fn init(window: &mut Window, cx: &mut App) {
|
||||||
DeviceRegistry::set_global(cx.new(|cx| DeviceRegistry::new(window, cx)), cx);
|
DeviceRegistry::set_global(cx.new(|cx| DeviceRegistry::new(window, cx)), cx);
|
||||||
@@ -25,9 +37,6 @@ impl Global for GlobalDeviceRegistry {}
|
|||||||
/// NIP-4e: https://github.com/nostr-protocol/nips/blob/per-device-keys/4e.md
|
/// NIP-4e: https://github.com/nostr-protocol/nips/blob/per-device-keys/4e.md
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DeviceRegistry {
|
pub struct DeviceRegistry {
|
||||||
/// Request for encryption key from other devices
|
|
||||||
pub requests: Vec<Event>,
|
|
||||||
|
|
||||||
/// Device state
|
/// Device state
|
||||||
state: DeviceState,
|
state: DeviceState,
|
||||||
|
|
||||||
@@ -64,19 +73,18 @@ impl DeviceRegistry {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Run at the end of current cycle
|
// Run at the end of current cycle
|
||||||
cx.defer_in(window, |this, _window, cx| {
|
cx.defer_in(window, |this, window, cx| {
|
||||||
this.handle_notifications(cx);
|
this.handle_notifications(window, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
requests: vec![],
|
|
||||||
state: DeviceState::default(),
|
state: DeviceState::default(),
|
||||||
tasks: vec![],
|
tasks: vec![],
|
||||||
_subscriptions: subscriptions,
|
_subscriptions: subscriptions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_notifications(&mut self, cx: &mut Context<Self>) {
|
fn handle_notifications(&mut self, 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 (tx, rx) = flume::bounded::<Event>(100);
|
let (tx, rx) = flume::bounded::<Event>(100);
|
||||||
@@ -117,17 +125,19 @@ impl DeviceRegistry {
|
|||||||
|
|
||||||
self.tasks.push(
|
self.tasks.push(
|
||||||
// Update GPUI states
|
// Update GPUI states
|
||||||
cx.spawn(async move |this, cx| {
|
cx.spawn_in(window, async move |this, cx| {
|
||||||
while let Ok(event) = rx.recv_async().await {
|
while let Ok(event) = rx.recv_async().await {
|
||||||
match event.kind {
|
match event.kind {
|
||||||
|
// New request event
|
||||||
Kind::Custom(4454) => {
|
Kind::Custom(4454) => {
|
||||||
this.update(cx, |this, cx| {
|
this.update_in(cx, |this, window, cx| {
|
||||||
this.add_request(event, cx);
|
this.ask_for_approval(event, window, cx);
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
// New response event
|
||||||
Kind::Custom(4455) => {
|
Kind::Custom(4455) => {
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
this.parse_response(event, cx);
|
this.extract_encryption(event, cx);
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -151,7 +161,7 @@ impl DeviceRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set the decoupled encryption key for the current user
|
/// Set the decoupled encryption key for the current user
|
||||||
fn set_signer<S>(&mut self, new: S, cx: &mut Context<Self>)
|
pub fn set_signer<S>(&mut self, new: S, cx: &mut Context<Self>)
|
||||||
where
|
where
|
||||||
S: NostrSigner + 'static,
|
S: NostrSigner + 'static,
|
||||||
{
|
{
|
||||||
@@ -174,27 +184,9 @@ impl DeviceRegistry {
|
|||||||
/// Reset the device state
|
/// Reset the device state
|
||||||
fn reset(&mut self, cx: &mut Context<Self>) {
|
fn reset(&mut self, cx: &mut Context<Self>) {
|
||||||
self.state = DeviceState::Idle;
|
self.state = DeviceState::Idle;
|
||||||
self.requests.clear();
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a request for device keys
|
|
||||||
fn add_request(&mut self, request: Event, cx: &mut Context<Self>) {
|
|
||||||
self.requests.push(request);
|
|
||||||
cx.notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove a request for device keys
|
|
||||||
pub fn remove_request(&mut self, id: &EventId, cx: &mut Context<Self>) {
|
|
||||||
self.requests.retain(|r| r.id != *id);
|
|
||||||
cx.notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if there are any pending requests
|
|
||||||
pub fn has_requests(&self) -> bool {
|
|
||||||
!self.requests.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get all messages for encryption keys
|
/// Get all messages for encryption keys
|
||||||
fn get_messages(&mut self, cx: &mut Context<Self>) {
|
fn get_messages(&mut self, cx: &mut Context<Self>) {
|
||||||
let task = self.subscribe_to_giftwrap_events(cx);
|
let task = self.subscribe_to_giftwrap_events(cx);
|
||||||
@@ -242,7 +234,7 @@ impl DeviceRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get device announcement for current user
|
/// Get device announcement for current user
|
||||||
fn get_announcement(&mut self, cx: &mut Context<Self>) {
|
pub fn get_announcement(&mut self, 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();
|
||||||
|
|
||||||
@@ -307,8 +299,8 @@ impl DeviceRegistry {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new device signer and announce it
|
/// Create new encryption keys
|
||||||
fn announce(&mut self, cx: &mut Context<Self>) {
|
pub fn create_encryption(&self, cx: &App) -> Task<Result<Keys, Error>> {
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
let client = nostr.read(cx).client();
|
let client = nostr.read(cx).client();
|
||||||
|
|
||||||
@@ -323,7 +315,7 @@ impl DeviceRegistry {
|
|||||||
let secret = keys.secret_key().to_secret_hex();
|
let secret = keys.secret_key().to_secret_hex();
|
||||||
let n = keys.public_key();
|
let n = keys.public_key();
|
||||||
|
|
||||||
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
|
cx.background_spawn(async move {
|
||||||
let urls = write_relays.await;
|
let urls = write_relays.await;
|
||||||
|
|
||||||
// Construct an announcement event
|
// Construct an announcement event
|
||||||
@@ -340,23 +332,29 @@ impl DeviceRegistry {
|
|||||||
// Save device keys to the database
|
// Save device keys to the database
|
||||||
set_keys(&client, &secret).await?;
|
set_keys(&client, &secret).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(keys)
|
||||||
});
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new device signer and announce it
|
||||||
|
fn announce(&mut self, cx: &mut Context<Self>) {
|
||||||
|
let task = self.create_encryption(cx);
|
||||||
|
|
||||||
self.tasks.push(cx.spawn(async move |this, cx| {
|
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||||
if task.await.is_ok() {
|
let keys = task.await?;
|
||||||
this.update(cx, |this, cx| {
|
|
||||||
this.set_signer(keys, cx);
|
// Update signer
|
||||||
this.listen_request(cx);
|
this.update(cx, |this, cx| {
|
||||||
})?;
|
this.set_signer(keys, cx);
|
||||||
}
|
this.listen_request(cx);
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize device signer (decoupled encryption key) for the current user
|
/// Initialize device signer (decoupled encryption key) for the current user
|
||||||
fn new_signer(&mut self, event: &Event, cx: &mut Context<Self>) {
|
pub fn new_signer(&mut self, event: &Event, 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();
|
||||||
|
|
||||||
@@ -375,31 +373,29 @@ impl DeviceRegistry {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.spawn(async move |this, cx| {
|
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||||
match task.await {
|
match task.await {
|
||||||
Ok(keys) => {
|
Ok(keys) => {
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
this.set_signer(keys, cx);
|
this.set_signer(keys, cx);
|
||||||
this.listen_request(cx);
|
this.listen_request(cx);
|
||||||
})
|
})?;
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
log::warn!("Failed to initialize device signer: {e}");
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
this.request(cx);
|
this.request(cx);
|
||||||
this.listen_approval(cx);
|
this.listen_approval(cx);
|
||||||
})
|
})?;
|
||||||
.ok();
|
|
||||||
|
|
||||||
log::warn!("Failed to initialize device signer: {e}");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
|
||||||
.detach();
|
Ok(())
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Listen for device key requests on user's write relays
|
/// Listen for device key requests on user's write relays
|
||||||
fn listen_request(&mut self, cx: &mut Context<Self>) {
|
pub fn listen_request(&mut self, 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();
|
||||||
|
|
||||||
@@ -518,30 +514,29 @@ impl DeviceRegistry {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.spawn(async move |this, cx| {
|
self.tasks.push(cx.spawn(async move |this, cx| {
|
||||||
match task.await {
|
match task.await {
|
||||||
Ok(Some(keys)) => {
|
Ok(Some(keys)) => {
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
this.set_signer(keys, cx);
|
this.set_signer(keys, cx);
|
||||||
})
|
})?;
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
this.set_state(DeviceState::Requesting, cx);
|
this.set_state(DeviceState::Requesting, cx);
|
||||||
})
|
})?;
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to request the encryption key: {e}");
|
log::error!("Failed to request the encryption key: {e}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
|
||||||
.detach();
|
Ok(())
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse the response event for device keys from other devices
|
/// Parse the response event for device keys from other devices
|
||||||
fn parse_response(&mut self, event: Event, cx: &mut Context<Self>) {
|
fn extract_encryption(&mut self, event: Event, cx: &mut Context<Self>) {
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
let app_keys = nostr.read(cx).app_keys().clone();
|
let app_keys = nostr.read(cx).app_keys().clone();
|
||||||
|
|
||||||
@@ -575,7 +570,7 @@ impl DeviceRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Approve requests for device keys from other devices
|
/// Approve requests for device keys from other devices
|
||||||
pub fn approve(&self, event: &Event, cx: &App) -> Task<Result<(), Error>> {
|
fn approve(&mut self, event: &Event, 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();
|
||||||
|
|
||||||
@@ -586,8 +581,9 @@ impl DeviceRegistry {
|
|||||||
// Get user's write relays
|
// Get user's write relays
|
||||||
let write_relays = nostr.read(cx).write_relays(&public_key, cx);
|
let write_relays = nostr.read(cx).write_relays(&public_key, cx);
|
||||||
let event = event.clone();
|
let event = event.clone();
|
||||||
|
let id: SharedString = event.id.to_hex().into();
|
||||||
|
|
||||||
cx.background_spawn(async move {
|
let task: Task<Result<(), Error>> = cx.background_spawn(async move {
|
||||||
let urls = write_relays.await;
|
let urls = write_relays.await;
|
||||||
|
|
||||||
// Get device keys
|
// Get device keys
|
||||||
@@ -609,18 +605,145 @@ impl DeviceRegistry {
|
|||||||
//
|
//
|
||||||
// P tag: the current device's public key
|
// P tag: the current device's public key
|
||||||
// p tag: the requester's public key
|
// p tag: the requester's public key
|
||||||
let event = client
|
let builder = EventBuilder::new(Kind::Custom(4455), payload).tags(vec![
|
||||||
.sign_event_builder(EventBuilder::new(Kind::Custom(4455), payload).tags(vec![
|
Tag::custom(TagKind::custom("P"), vec![keys.public_key()]),
|
||||||
Tag::custom(TagKind::custom("P"), vec![keys.public_key()]),
|
Tag::public_key(target),
|
||||||
Tag::public_key(target),
|
]);
|
||||||
]))
|
|
||||||
.await?;
|
// Sign the builder
|
||||||
|
let event = client.sign_event_builder(builder).await?;
|
||||||
|
|
||||||
// Send the response event to the user's relay list
|
// Send the response event to the user's relay list
|
||||||
client.send_event(&event).to(urls).await?;
|
client.send_event(&event).to(urls).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.spawn_in(window, async move |_this, cx| {
|
||||||
|
match task.await {
|
||||||
|
Ok(_) => {
|
||||||
|
cx.update(|window, cx| {
|
||||||
|
window.clear_notification(id, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
cx.update(|window, cx| {
|
||||||
|
window.push_notification(Notification::error(e.to_string()), cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
};
|
||||||
})
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle encryption request
|
||||||
|
fn ask_for_approval(&mut self, event: Event, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
|
let notification = self.notification(event, cx);
|
||||||
|
|
||||||
|
cx.spawn_in(window, async move |_this, cx| {
|
||||||
|
cx.update(|window, cx| {
|
||||||
|
window.push_notification(notification, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build a notification for the encryption request.
|
||||||
|
fn notification(&self, event: Event, cx: &Context<Self>) -> Notification {
|
||||||
|
let request = Announcement::from(&event);
|
||||||
|
let persons = PersonRegistry::global(cx);
|
||||||
|
let profile = persons.read(cx).get(&request.public_key(), cx);
|
||||||
|
|
||||||
|
let entity = cx.entity().downgrade();
|
||||||
|
let loading = Rc::new(Cell::new(false));
|
||||||
|
|
||||||
|
Notification::new()
|
||||||
|
.custom_id(SharedString::from(event.id.to_hex()))
|
||||||
|
.autohide(false)
|
||||||
|
.icon(IconName::UserKey)
|
||||||
|
.title(SharedString::from("New request"))
|
||||||
|
.content(move |_window, cx| {
|
||||||
|
v_flex()
|
||||||
|
.gap_2()
|
||||||
|
.text_sm()
|
||||||
|
.child(SharedString::from(MSG))
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.gap_2()
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.gap_1()
|
||||||
|
.text_sm()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.text_xs()
|
||||||
|
.text_color(cx.theme().text_muted)
|
||||||
|
.child(SharedString::from("Requester:")),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.h_7()
|
||||||
|
.w_full()
|
||||||
|
.px_2()
|
||||||
|
.rounded(cx.theme().radius)
|
||||||
|
.bg(cx.theme().elevated_surface_background)
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.gap_2()
|
||||||
|
.child(Avatar::new(profile.avatar()).xsmall())
|
||||||
|
.child(profile.name()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.gap_1()
|
||||||
|
.text_sm()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.text_xs()
|
||||||
|
.text_color(cx.theme().text_muted)
|
||||||
|
.child(SharedString::from("Client:")),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.h_7()
|
||||||
|
.w_full()
|
||||||
|
.px_2()
|
||||||
|
.rounded(cx.theme().radius)
|
||||||
|
.bg(cx.theme().elevated_surface_background)
|
||||||
|
.child(request.client_name()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.into_any_element()
|
||||||
|
})
|
||||||
|
.action(move |_window, _cx| {
|
||||||
|
let view = entity.clone();
|
||||||
|
let event = event.clone();
|
||||||
|
|
||||||
|
Button::new("approve")
|
||||||
|
.label("Approve")
|
||||||
|
.small()
|
||||||
|
.primary()
|
||||||
|
.loading(loading.get())
|
||||||
|
.disabled(loading.get())
|
||||||
|
.on_click({
|
||||||
|
let loading = Rc::clone(&loading);
|
||||||
|
move |_ev, window, cx| {
|
||||||
|
// Set loading state to true
|
||||||
|
loading.set(true);
|
||||||
|
// Process to approve the request
|
||||||
|
view.update(cx, |this, cx| {
|
||||||
|
this.approve(&event, window, cx);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -343,8 +343,8 @@ impl RelayAuth {
|
|||||||
.px_1p5()
|
.px_1p5()
|
||||||
.rounded_sm()
|
.rounded_sm()
|
||||||
.text_xs()
|
.text_xs()
|
||||||
.bg(cx.theme().warning_background)
|
.bg(cx.theme().elevated_surface_background)
|
||||||
.text_color(cx.theme().warning_foreground)
|
.text_color(cx.theme().text_accent)
|
||||||
.child(url.clone()),
|
.child(url.clone()),
|
||||||
)
|
)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
@@ -361,11 +361,9 @@ impl RelayAuth {
|
|||||||
.disabled(loading.get())
|
.disabled(loading.get())
|
||||||
.on_click({
|
.on_click({
|
||||||
let loading = Rc::clone(&loading);
|
let loading = Rc::clone(&loading);
|
||||||
|
|
||||||
move |_ev, window, cx| {
|
move |_ev, window, cx| {
|
||||||
// Set loading state to true
|
// Set loading state to true
|
||||||
loading.set(true);
|
loading.set(true);
|
||||||
|
|
||||||
// Process to approve the request
|
// Process to approve the request
|
||||||
view.update(cx, |this, cx| {
|
view.update(cx, |this, cx| {
|
||||||
this.response(&req, window, cx);
|
this.response(&req, window, cx);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
use gpui::SharedString;
|
use gpui::SharedString;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
|
|
||||||
@@ -9,6 +11,16 @@ pub enum DeviceState {
|
|||||||
Set,
|
Set,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for DeviceState {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
DeviceState::Idle => write!(f, "Idle"),
|
||||||
|
DeviceState::Requesting => write!(f, "Wait for approval"),
|
||||||
|
DeviceState::Set => write!(f, "Encryption Key is ready"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl DeviceState {
|
impl DeviceState {
|
||||||
pub fn idle(&self) -> bool {
|
pub fn idle(&self) -> bool {
|
||||||
matches!(self, DeviceState::Idle)
|
matches!(self, DeviceState::Idle)
|
||||||
|
|||||||
Reference in New Issue
Block a user