Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
273ddabde5 | ||
|
|
7ba289440b | ||
|
|
6510e45e4e |
Generated
+194
-105
@@ -987,9 +987,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.4.6"
|
version = "1.4.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3eb0f42d6c360dc3f8a821f6bf2fdea7f72bfd36b3076eb0e6d1e9e0752fff4"
|
checksum = "54413ede23c2daf518f35156dfde027feb2374004d63bd497f983c8db9c0e313"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
@@ -1339,7 +1339,7 @@ dependencies = [
|
|||||||
"hmac 0.12.1",
|
"hmac 0.12.1",
|
||||||
"nostr",
|
"nostr",
|
||||||
"nostr-sdk",
|
"nostr-sdk",
|
||||||
"rand 0.10.2",
|
"rand 0.10.3",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2 0.10.9",
|
"sha2 0.10.9",
|
||||||
@@ -2190,9 +2190,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
version = "0.1.12"
|
version = "0.1.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d"
|
checksum = "ef25905e51abafe4dcea6c15fec58c57b601cdbd0ee53d22ea1d3016c587d39b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fixedbitset"
|
name = "fixedbitset"
|
||||||
@@ -2711,14 +2711,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-base"
|
name = "gpui-base"
|
||||||
version = "0.6.1"
|
version = "0.6.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9d45dcaaeac889bf1e7757db1beb26c9043c8ea3156651facc11c6be56bb6722"
|
checksum = "c9e904ee0d351f4e85b967e26ae986d3aa195a8d9d35fcd18184a2c40989694e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"ashpd",
|
||||||
"async-channel",
|
"async-channel",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"data-url",
|
||||||
"futures",
|
"futures",
|
||||||
"gpui-pre",
|
"gpui-pre",
|
||||||
"gpui-pre-macros",
|
"gpui-pre-macros",
|
||||||
@@ -2742,13 +2744,14 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"web-time",
|
"web-time",
|
||||||
|
"windows 0.58.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre"
|
name = "gpui-pre"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2a9ca98fdcad06276de623c2f48ebd710f1e7724eebef2f2673c583e85dc8335"
|
checksum = "a0437c0b83e636a92bd1a39fa1d05fb632ae671289537497b35871ffbe231b84"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -2774,7 +2777,6 @@ dependencies = [
|
|||||||
"gpui-pre-sum-tree",
|
"gpui-pre-sum-tree",
|
||||||
"gpui-pre-util",
|
"gpui-pre-util",
|
||||||
"gpui-pre-util-macros",
|
"gpui-pre-util-macros",
|
||||||
"gpui-pre-ztracing",
|
|
||||||
"heapless 0.9.3",
|
"heapless 0.9.3",
|
||||||
"image",
|
"image",
|
||||||
"inventory",
|
"inventory",
|
||||||
@@ -2782,6 +2784,8 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"lyon",
|
"lyon",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
|
"objc2-core-foundation",
|
||||||
|
"objc2-core-video",
|
||||||
"parking",
|
"parking",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
@@ -2802,7 +2806,6 @@ dependencies = [
|
|||||||
"strum",
|
"strum",
|
||||||
"taffy",
|
"taffy",
|
||||||
"thiserror 2.0.20",
|
"thiserror 2.0.20",
|
||||||
"tracing",
|
|
||||||
"ttf-parser",
|
"ttf-parser",
|
||||||
"url",
|
"url",
|
||||||
"usvg",
|
"usvg",
|
||||||
@@ -2816,9 +2819,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-apple"
|
name = "gpui-pre-apple"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d3fc4da82c5c2dbb25443655cfbc4305a2e2d1380bc0b815e80664fdfbf4cfdb"
|
checksum = "3af534f0746eb9e014114bcc0ee00dc250c4b8d75df2e437180c403aa65649c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"block",
|
"block",
|
||||||
@@ -2830,7 +2833,6 @@ dependencies = [
|
|||||||
"etagere",
|
"etagere",
|
||||||
"foreign-types",
|
"foreign-types",
|
||||||
"gpui-pre",
|
"gpui-pre",
|
||||||
"gpui-pre-collections",
|
|
||||||
"image",
|
"image",
|
||||||
"log",
|
"log",
|
||||||
"metal",
|
"metal",
|
||||||
@@ -2841,9 +2843,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-collections"
|
name = "gpui-pre-collections"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "626a09f683ff6f3b2f708341bdcea9d479af5b14a6a2fccec9cff935ec0751b7"
|
checksum = "15e7a65204039187d1f4b3d4c2e0233eeac54d4acb0b13f9dc1a3b5adad26c1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gpui-pre-util",
|
"gpui-pre-util",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
@@ -2852,9 +2854,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-derive-refineable"
|
name = "gpui-pre-derive-refineable"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "56d06116a2b857588f6ea7bfb447b3554ba985e780b5995ae47780252da152f3"
|
checksum = "79dfb4a05f3cd9893d7768dbf5dba1bbbe99cab7394e89b360ccb3b2bcb6b34e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2863,9 +2865,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-http-client"
|
name = "gpui-pre-http-client"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b0d2071c582c1a0f71b8c7c00607a3b9cd18f81fb3510d41845db3447b2a11c9"
|
checksum = "cfd5a7542c77887a5aff997d78c95884119c8463409569b63fcf060956da1682"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-compression",
|
"async-compression",
|
||||||
@@ -2884,9 +2886,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-http-client-tls"
|
name = "gpui-pre-http-client-tls"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b6f3936802580259d5af9bcb2ab37fb0d7002caeed449eaabb007c62aea7341"
|
checksum = "72aed510adb5e7723f8f57b9751007e3451d46a84edb59b92227178cf59cc19c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"rustls",
|
"rustls",
|
||||||
@@ -2896,9 +2898,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-linux"
|
name = "gpui-pre-linux"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6b427589681ec1fed27951fd82edc70a7e288bb2487ede26dbbd07c2ce23d4f"
|
checksum = "aab655cda1d6dcd549ac869e8678babc84cf573ab6794a1fe1a39c6c70c60b48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_unix",
|
"accesskit_unix",
|
||||||
@@ -2943,15 +2945,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-macos"
|
name = "gpui-pre-macos"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "806eac0cb5c0eebc0b032c6450c11d283264f9ac05754dda83fc80d0b86b4ee8"
|
checksum = "951d17e41a72067ad2d35c60e08a62e8ad7fa9400b41c802e26cfb459f6c05da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_macos",
|
"accesskit_macos",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-task",
|
"async-task",
|
||||||
"block",
|
|
||||||
"block2 0.6.2",
|
"block2 0.6.2",
|
||||||
"cocoa 0.26.1",
|
"cocoa 0.26.1",
|
||||||
"core-foundation 0.10.1",
|
"core-foundation 0.10.1",
|
||||||
@@ -2965,17 +2966,17 @@ dependencies = [
|
|||||||
"gpui-pre",
|
"gpui-pre",
|
||||||
"gpui-pre-apple",
|
"gpui-pre-apple",
|
||||||
"gpui-pre-collections",
|
"gpui-pre-collections",
|
||||||
"gpui-pre-media",
|
|
||||||
"gpui-pre-util",
|
"gpui-pre-util",
|
||||||
"image",
|
"image",
|
||||||
"itertools 0.14.0",
|
"itertools 0.14.0",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"mach2",
|
"mach2",
|
||||||
"metal",
|
|
||||||
"objc",
|
"objc",
|
||||||
"objc2 0.6.4",
|
"objc2 0.6.4",
|
||||||
"objc2-app-kit 0.3.2",
|
"objc2-app-kit 0.3.2",
|
||||||
|
"objc2-core-graphics",
|
||||||
|
"objc2-core-media",
|
||||||
"objc2-foundation 0.3.2",
|
"objc2-foundation 0.3.2",
|
||||||
"objc2-screen-capture-kit",
|
"objc2-screen-capture-kit",
|
||||||
"objc2-user-notifications",
|
"objc2-user-notifications",
|
||||||
@@ -2991,9 +2992,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-macros"
|
name = "gpui-pre-macros"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c06139051bf1db51949bfbb4ee338208bd64b4c35340d8c1a6a8200744e28fe1"
|
checksum = "6324092b40ea8ec7c327a4a28427e366a489b4d5d23b5d1bd0243fc2f4ca7a9e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
@@ -3002,26 +3003,11 @@ dependencies = [
|
|||||||
"syn 2.0.119",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gpui-pre-media"
|
|
||||||
version = "0.3.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "500acb13f818ff234021c1b9eae8592b0cbe017a64e26908c736b7421b1c6213"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"bindgen",
|
|
||||||
"core-foundation 0.10.1",
|
|
||||||
"core-video",
|
|
||||||
"foreign-types",
|
|
||||||
"metal",
|
|
||||||
"objc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-perf"
|
name = "gpui-pre-perf"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b0973bbb02bf46940ac0861d9dce0fc03a3109634172b69108d1bc13fa29d76c"
|
checksum = "b94bff26ccd8105f6206144f8dab16a2dc02e7a68f39dada02cdf492f0afd940"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gpui-pre-collections",
|
"gpui-pre-collections",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -3030,9 +3016,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-platform"
|
name = "gpui-pre-platform"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b613512e29f1e7b825bfa7e50a447388ff1347044350a475e4c98a892a985c8d"
|
checksum = "8423d1e0a693d2f9f16c0326bb01b5e81ec0531854d596a18476934ac6880478"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"gpui-pre",
|
"gpui-pre",
|
||||||
@@ -3044,9 +3030,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-refineable"
|
name = "gpui-pre-refineable"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "428f23703ead5601618ffea73c137897b98a94ce8d30e257f22be947732dfbf9"
|
checksum = "93b4b0a8d296a3ee5beb1136bc48f8167a6028eb1e243b56851dcd8c9fc6d7a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gpui-pre-derive-refineable",
|
"gpui-pre-derive-refineable",
|
||||||
]
|
]
|
||||||
@@ -3103,9 +3089,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-reqwest-client"
|
name = "gpui-pre-reqwest-client"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d05d4e3d2eb2ab777597879e46047247447b9d93cef568e63d545c9deb1b3e57"
|
checksum = "8f32ccea5d1a7c8d2868d7b346c2c1f76aa3f86ec9e0575c4e7340af3afd9e9d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -3121,9 +3107,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-scheduler"
|
name = "gpui-pre-scheduler"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6dd1b7ff2e7bf43302ae982cd786a22c16c52e16682e67b66cfbe2cb2bc3a72d"
|
checksum = "ff7b10b3d2fc3fda24847a04436eca9531612c8414874a37ddc005f20e521e12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-task",
|
"async-task",
|
||||||
"backtrace",
|
"backtrace",
|
||||||
@@ -3138,9 +3124,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-shared-string"
|
name = "gpui-pre-shared-string"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "424a4dd6a570473d57acf1df2bfb9f3028d4b568abcaeb9252e0f13047b50c03"
|
checksum = "fe17f81bd98a0253140ea79f7f76442d7499bd8d17db302861af8e46c11d38df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -3149,9 +3135,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-sum-tree"
|
name = "gpui-pre-sum-tree"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4855718e82630d29198b515d2b027361ef63dd19b6021cefe945789dcff82372"
|
checksum = "0a6d35e998a51d24248dad731de1f09d386cbbf46a04edde3b67f469b2ce3f16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gpui-pre-ztracing",
|
"gpui-pre-ztracing",
|
||||||
"heapless 0.9.3",
|
"heapless 0.9.3",
|
||||||
@@ -3162,9 +3148,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-util"
|
name = "gpui-pre-util"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e973148165346c0f9b3f5072b321d7c2f33807c93daea67fe298c005c0e0c2a8"
|
checksum = "6a026a30c578930d20974fd8c3d77de36223ac7ba193bd4259e7238929bc8806"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"log",
|
"log",
|
||||||
@@ -3173,9 +3159,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-util-macros"
|
name = "gpui-pre-util-macros"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4f71f6212d3772a70988c7d64627c7284dec73c17992ac4f9f0cdfdd46cbb677"
|
checksum = "5cbf79627a6afc626d4e887dad9d2d92bb069413e8cc692ba3e90bff219eb7a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gpui-pre-perf",
|
"gpui-pre-perf",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -3184,9 +3170,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-web"
|
name = "gpui-pre-web"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4f0daada903f106be946d87e25f5bc85ad6cf60d6d82cb8f8aed945417a9c1a3"
|
checksum = "34be433b9fcb370b1fe9a1c7fe911f0eb6058791ef8167dcf6c5a5deb624975c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
@@ -3213,9 +3199,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-wgpu"
|
name = "gpui-pre-wgpu"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "640b666a16ddf9504e2eb3e7a997acb2b2adfaa7859925bdd36fc3acfd8f30a7"
|
checksum = "05515b32799b1767d69300921c1b562cd53104965211a0e8905acdc7aa18e693"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
@@ -3240,9 +3226,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-windows"
|
name = "gpui-pre-windows"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c12c7d84ec422feb2f064117d572447998381e5c219fcad69fe19f10d0b7aaea"
|
checksum = "27662e65bfcf4445d2cccfad91f1570ec07f4b1b5de98400a9f207fd19c464cf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_windows",
|
"accesskit_windows",
|
||||||
@@ -3269,9 +3255,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-zlog"
|
name = "gpui-pre-zlog"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "98352858fac3d4d05b46d6014ad04bad313652a691d4e21dc55fa96fb4acb7cf"
|
checksum = "f3a5af0b734a391a84872eb770b3ee9830091ec2487b79d06371fe14eefb2b5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -3281,9 +3267,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-ztracing"
|
name = "gpui-pre-ztracing"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d63a3c7276875b4d7e6d3961e92a138e9233e86a591bf318f2e54df4ad58102"
|
checksum = "a24cb19f78c5bc3aab8ddf1e8e0bd6b402fbcb9c7f112f64ddbedef8f8768a59"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gpui-pre-zlog",
|
"gpui-pre-zlog",
|
||||||
"gpui-pre-ztracing-macro",
|
"gpui-pre-ztracing-macro",
|
||||||
@@ -3293,9 +3279,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-pre-ztracing-macro"
|
name = "gpui-pre-ztracing-macro"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84e2a5ff79002223edfcfa76c6f9f79f4f60f6ec545ccc27832f12bd46348b39"
|
checksum = "a1bb25850ad31b88bbdef454afb93ec4cdb81f5e200ba5b3f1a0368111780d2c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui-updater-core"
|
name = "gpui-updater-core"
|
||||||
@@ -3621,9 +3607,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-rustls"
|
name = "hyper-rustls"
|
||||||
version = "0.27.9"
|
version = "0.27.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
|
checksum = "dfa8e654703247911e29c23fbeaa261834bd9bb74efba2f9acddc37bfb127f53"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"hyper",
|
"hyper",
|
||||||
@@ -4131,9 +4117,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.24"
|
version = "0.1.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6480ccc157a1389bb2e4891b24751b0f798ba640d22386f23143fbcc89da195a"
|
checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -4617,8 +4603,8 @@ checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr"
|
name = "nostr"
|
||||||
version = "0.45.4"
|
version = "0.45.5"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b230cecf9dbb38e0228e6fff4544ed9d261326fc"
|
source = "git+https://github.com/rust-nostr/nostr#01f1950c671b35f3d1186ca907373dd86ee3b336"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
@@ -4630,7 +4616,7 @@ dependencies = [
|
|||||||
"chacha20poly1305",
|
"chacha20poly1305",
|
||||||
"faster-hex",
|
"faster-hex",
|
||||||
"opaquerr 0.2.0",
|
"opaquerr 0.2.0",
|
||||||
"rand 0.10.2",
|
"rand 0.10.3",
|
||||||
"scrypt",
|
"scrypt",
|
||||||
"secp256k1",
|
"secp256k1",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -4643,8 +4629,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-blossom"
|
name = "nostr-blossom"
|
||||||
version = "0.45.0"
|
version = "0.45.1"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b230cecf9dbb38e0228e6fff4544ed9d261326fc"
|
source = "git+https://github.com/rust-nostr/nostr#01f1950c671b35f3d1186ca907373dd86ee3b336"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bitcoin_hashes 1.2.0",
|
"bitcoin_hashes 1.2.0",
|
||||||
@@ -4656,8 +4642,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-connect"
|
name = "nostr-connect"
|
||||||
version = "0.45.1"
|
version = "0.45.2"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b230cecf9dbb38e0228e6fff4544ed9d261326fc"
|
source = "git+https://github.com/rust-nostr/nostr#01f1950c671b35f3d1186ca907373dd86ee3b336"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@@ -4670,8 +4656,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-database"
|
name = "nostr-database"
|
||||||
version = "0.45.1"
|
version = "0.45.2"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b230cecf9dbb38e0228e6fff4544ed9d261326fc"
|
source = "git+https://github.com/rust-nostr/nostr#01f1950c671b35f3d1186ca907373dd86ee3b336"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nostr",
|
"nostr",
|
||||||
"opaquerr 0.2.0",
|
"opaquerr 0.2.0",
|
||||||
@@ -4679,8 +4665,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-gossip"
|
name = "nostr-gossip"
|
||||||
version = "0.45.0"
|
version = "0.45.1"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b230cecf9dbb38e0228e6fff4544ed9d261326fc"
|
source = "git+https://github.com/rust-nostr/nostr#01f1950c671b35f3d1186ca907373dd86ee3b336"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nostr",
|
"nostr",
|
||||||
"opaquerr 0.2.0",
|
"opaquerr 0.2.0",
|
||||||
@@ -4688,8 +4674,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-gossip-memory"
|
name = "nostr-gossip-memory"
|
||||||
version = "0.45.0"
|
version = "0.45.1"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b230cecf9dbb38e0228e6fff4544ed9d261326fc"
|
source = "git+https://github.com/rust-nostr/nostr#01f1950c671b35f3d1186ca907373dd86ee3b336"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"lru",
|
"lru",
|
||||||
@@ -4700,8 +4686,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-lmdb"
|
name = "nostr-lmdb"
|
||||||
version = "0.45.2"
|
version = "0.45.3"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b230cecf9dbb38e0228e6fff4544ed9d261326fc"
|
source = "git+https://github.com/rust-nostr/nostr#01f1950c671b35f3d1186ca907373dd86ee3b336"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"flatbuffers",
|
"flatbuffers",
|
||||||
@@ -4715,8 +4701,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-memory"
|
name = "nostr-memory"
|
||||||
version = "0.45.1"
|
version = "0.45.2"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b230cecf9dbb38e0228e6fff4544ed9d261326fc"
|
source = "git+https://github.com/rust-nostr/nostr#01f1950c671b35f3d1186ca907373dd86ee3b336"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"btreecap",
|
"btreecap",
|
||||||
"nostr",
|
"nostr",
|
||||||
@@ -4726,8 +4712,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-sdk"
|
name = "nostr-sdk"
|
||||||
version = "0.45.2"
|
version = "0.45.4"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#b230cecf9dbb38e0228e6fff4544ed9d261326fc"
|
source = "git+https://github.com/rust-nostr/nostr#01f1950c671b35f3d1186ca907373dd86ee3b336"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"async-wsocket",
|
"async-wsocket",
|
||||||
@@ -4739,7 +4725,7 @@ dependencies = [
|
|||||||
"nostr-database",
|
"nostr-database",
|
||||||
"nostr-gossip",
|
"nostr-gossip",
|
||||||
"opaquerr 0.2.0",
|
"opaquerr 0.2.0",
|
||||||
"rand 0.10.2",
|
"rand 0.10.3",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -4990,6 +4976,28 @@ dependencies = [
|
|||||||
"objc2-foundation 0.3.2",
|
"objc2-foundation 0.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-core-audio"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1eebcea8b0dbff5f7c8504f3107c68fc061a3eb44932051c8cf8a68d969c3b2"
|
||||||
|
dependencies = [
|
||||||
|
"dispatch2",
|
||||||
|
"objc2 0.6.4",
|
||||||
|
"objc2-core-audio-types",
|
||||||
|
"objc2-core-foundation",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-core-audio-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.13.2",
|
||||||
|
"objc2 0.6.4",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-core-data"
|
name = "objc2-core-data"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -5069,6 +5077,21 @@ dependencies = [
|
|||||||
"objc2-foundation 0.3.2",
|
"objc2-foundation 0.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-core-media"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05ec576860167a15dd9fce7fbee7512beb4e31f532159d3482d1f9c6caedf31d"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.13.2",
|
||||||
|
"dispatch2",
|
||||||
|
"objc2 0.6.4",
|
||||||
|
"objc2-core-audio",
|
||||||
|
"objc2-core-audio-types",
|
||||||
|
"objc2-core-foundation",
|
||||||
|
"objc2-core-video",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-core-text"
|
name = "objc2-core-text"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
@@ -5193,8 +5216,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "74b7c5390f477482f001bc354d6571a70db7e4f8d5288e860c45521fbce11394"
|
checksum = "74b7c5390f477482f001bc354d6571a70db7e4f8d5288e860c45521fbce11394"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block2 0.6.2",
|
"block2 0.6.2",
|
||||||
|
"dispatch2",
|
||||||
"objc2 0.6.4",
|
"objc2 0.6.4",
|
||||||
"objc2-core-graphics",
|
"objc2-core-graphics",
|
||||||
|
"objc2-core-media",
|
||||||
"objc2-foundation 0.3.2",
|
"objc2-foundation 0.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5902,7 +5927,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
"lru-slab",
|
"lru-slab",
|
||||||
"rand 0.10.2",
|
"rand 0.10.3",
|
||||||
"rand_pcg",
|
"rand_pcg",
|
||||||
"ring",
|
"ring",
|
||||||
"rustc-hash 2.1.3",
|
"rustc-hash 2.1.3",
|
||||||
@@ -5973,9 +5998,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.10.2"
|
version = "0.10.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
|
checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chacha20 0.10.2",
|
"chacha20 0.10.2",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
@@ -8004,9 +8029,9 @@ checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-id"
|
name = "unicode-id"
|
||||||
version = "0.3.6"
|
version = "0.3.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "70ba288e709927c043cbe476718d37be306be53fb1fafecd0dbe36d072be2580"
|
checksum = "65dd75ab2d9d379dbe86d4059e91d8b5a6e7054865eaba1ddbfc7a817ff96392"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
@@ -8790,6 +8815,16 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.58.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
|
||||||
|
dependencies = [
|
||||||
|
"windows-core 0.58.0",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows"
|
name = "windows"
|
||||||
version = "0.61.3"
|
version = "0.61.3"
|
||||||
@@ -8858,6 +8893,19 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-core"
|
||||||
|
version = "0.58.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
|
||||||
|
dependencies = [
|
||||||
|
"windows-implement 0.58.0",
|
||||||
|
"windows-interface 0.58.0",
|
||||||
|
"windows-result 0.2.0",
|
||||||
|
"windows-strings 0.1.0",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-core"
|
name = "windows-core"
|
||||||
version = "0.61.2"
|
version = "0.61.2"
|
||||||
@@ -8917,6 +8965,17 @@ dependencies = [
|
|||||||
"syn 2.0.119",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-implement"
|
||||||
|
version = "0.58.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.119",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-implement"
|
name = "windows-implement"
|
||||||
version = "0.60.2"
|
version = "0.60.2"
|
||||||
@@ -8939,6 +8998,17 @@ dependencies = [
|
|||||||
"syn 2.0.119",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-interface"
|
||||||
|
version = "0.58.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.119",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-interface"
|
name = "windows-interface"
|
||||||
version = "0.59.3"
|
version = "0.59.3"
|
||||||
@@ -9013,6 +9083,15 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-result"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-result"
|
name = "windows-result"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
@@ -9031,6 +9110,16 @@ dependencies = [
|
|||||||
"windows-link 0.2.1",
|
"windows-link 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-strings"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||||
|
dependencies = [
|
||||||
|
"windows-result 0.2.0",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-strings"
|
name = "windows-strings"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
||||||
|
<path d="M2.75 12C2.75 17.1086 6.89137 21.25 12 21.25C17.1086 21.25 21.25 17.1086 21.25 12C21.25 6.89137 17.1086 2.75 12 2.75C6.89137 2.75 2.75 6.89137 2.75 12Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M15.25 13L12 16.25L8.75 13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M12 7.75V15.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 571 B |
+5
-30
@@ -9,7 +9,7 @@ use fuzzy_matcher::FuzzyMatcher;
|
|||||||
use fuzzy_matcher::skim::SkimMatcherV2;
|
use fuzzy_matcher::skim::SkimMatcherV2;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
App, AppContext, Context, Entity, EventEmitter, Global, SharedString, Subscription, Task,
|
App, AppContext, Context, Entity, EventEmitter, Global, SharedString, Subscription, Task,
|
||||||
WeakEntity, Window,
|
WeakEntity,
|
||||||
};
|
};
|
||||||
use instant::Duration;
|
use instant::Duration;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
@@ -37,15 +37,8 @@ impl Global for GlobalChatRegistry {}
|
|||||||
/// Chat event.
|
/// Chat event.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum ChatEvent {
|
pub enum ChatEvent {
|
||||||
/// An event to open a room by its ID
|
|
||||||
OpenRoom(u64),
|
|
||||||
/// An event to close a room by its ID
|
|
||||||
CloseRoom(u64),
|
|
||||||
/// An event to notify UI about a new chat request
|
|
||||||
Ping,
|
Ping,
|
||||||
/// No Inbox Relays found, the app is not ready to subscribe messages
|
|
||||||
InboxRelayNotFound,
|
InboxRelayNotFound,
|
||||||
/// An error occurred
|
|
||||||
Error(String),
|
Error(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,34 +536,16 @@ impl ChatRegistry {
|
|||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit an open room event.
|
/// Track a room so it is listed and can be looked up by id.
|
||||||
///
|
pub fn track_room(&mut self, room: &Entity<Room>, cx: &mut Context<Self>) {
|
||||||
/// If the room is new, add it to the registry.
|
|
||||||
pub fn emit_room(&mut self, room: &Entity<Room>, window: &mut Window, cx: &mut Context<Self>) {
|
|
||||||
// Get the room's ID.
|
|
||||||
let id = room.read(cx).id;
|
let id = room.read(cx).id;
|
||||||
|
|
||||||
// If the room is new, add it to the registry and index.
|
|
||||||
if let hash_map::Entry::Vacant(e) = self.room_index.entry(id) {
|
if let hash_map::Entry::Vacant(e) = self.room_index.entry(id) {
|
||||||
let entity = room.to_owned();
|
let entity = room.to_owned();
|
||||||
e.insert(entity.clone());
|
e.insert(entity.clone());
|
||||||
|
|
||||||
self.rooms.insert(0, entity);
|
self.rooms.insert(0, entity);
|
||||||
}
|
cx.notify();
|
||||||
|
|
||||||
// Emit the open room event deferred to avoid re-entrant reads
|
|
||||||
cx.defer_in(window, move |_this, _window, cx| {
|
|
||||||
cx.emit(ChatEvent::OpenRoom(id));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Close a room.
|
|
||||||
pub fn close_room(&mut self, id: u64, window: &mut Window, cx: &mut Context<Self>) {
|
|
||||||
if self.room_index.contains_key(&id) {
|
|
||||||
self.room_index.remove(&id);
|
|
||||||
self.rooms.retain(|r| r.read(cx).id != id);
|
|
||||||
cx.defer_in(window, move |_this, _window, cx| {
|
|
||||||
cx.emit(ChatEvent::CloseRoom(id));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -107,8 +107,6 @@ impl SubscriptionKey {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum CommunityEvent {
|
pub enum CommunityEvent {
|
||||||
Updated(CommunityId),
|
Updated(CommunityId),
|
||||||
Open(CommunityId),
|
|
||||||
Close(CommunityId),
|
|
||||||
Channel(CommunityId, ChannelId),
|
Channel(CommunityId, ChannelId),
|
||||||
/// History exists here that no held key can open.
|
/// History exists here that no held key can open.
|
||||||
Unreadable(CommunityId),
|
Unreadable(CommunityId),
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ pub use concord::cord03::{ChatMessage, ReplyRef};
|
|||||||
use concord::state::CommunityState;
|
use concord::state::CommunityState;
|
||||||
pub use concord::{ChannelId, CommunityId, Epoch};
|
pub use concord::{ChannelId, CommunityId, Epoch};
|
||||||
use futures::future::{Either, select};
|
use futures::future::{Either, select};
|
||||||
use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, Subscription, Task, Window};
|
use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, Subscription, Task};
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
use state::NostrRegistry;
|
use state::NostrRegistry;
|
||||||
@@ -225,27 +225,6 @@ impl CommunityRegistry {
|
|||||||
self.index.get(id).cloned()
|
self.index.get(id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ask the workspace to open a community's panel.
|
|
||||||
pub fn emit_community(
|
|
||||||
&mut self,
|
|
||||||
community: &Entity<Community>,
|
|
||||||
window: &mut Window,
|
|
||||||
cx: &mut Context<Self>,
|
|
||||||
) {
|
|
||||||
let id = community.read(cx).id();
|
|
||||||
|
|
||||||
cx.defer_in(window, move |_this, _window, cx| {
|
|
||||||
cx.emit(CommunityEvent::Open(id));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ask the workspace to close a community's panel.
|
|
||||||
pub fn emit_close(&mut self, id: CommunityId, window: &mut Window, cx: &mut Context<Self>) {
|
|
||||||
cx.defer_in(window, move |_this, _window, cx| {
|
|
||||||
cx.emit(CommunityEvent::Close(id));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a community owned by the current account and begin tracking it.
|
/// Create a community owned by the current account and begin tracking it.
|
||||||
pub fn create(&mut self, metadata: CommunityMetadata, cx: &mut Context<Self>) {
|
pub fn create(&mut self, metadata: CommunityMetadata, cx: &mut Context<Self>) {
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
|
|||||||
@@ -145,21 +145,19 @@ impl CommunityPanel {
|
|||||||
window,
|
window,
|
||||||
|_this, _community, event, window, cx| {
|
|_this, _community, event, window, cx| {
|
||||||
match event {
|
match event {
|
||||||
CommunityEvent::Updated(_)
|
|
||||||
| CommunityEvent::Unreadable(_)
|
|
||||||
| CommunityEvent::Failed(_) => {
|
|
||||||
cx.defer_in(window, |this, window, cx| this.reload(window, cx));
|
|
||||||
}
|
|
||||||
CommunityEvent::Channel(..) => {
|
CommunityEvent::Channel(..) => {
|
||||||
cx.defer_in(window, |this, window, cx| this.load(window, cx));
|
cx.defer_in(window, |this, window, cx| {
|
||||||
|
this.load(window, cx);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
CommunityEvent::Error(error) => {
|
CommunityEvent::Error(error) => {
|
||||||
window.push_notification(
|
window.push_notification(Notification::error(error.clone()), cx);
|
||||||
Notification::error(error.clone()).autohide(false),
|
}
|
||||||
cx,
|
_ => {
|
||||||
);
|
cx.defer_in(window, |this, window, cx| {
|
||||||
|
this.reload(window, cx);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
CommunityEvent::Open(_) | CommunityEvent::Close(_) => {}
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|||||||
+14
-15
@@ -14,7 +14,7 @@ use gpui::{
|
|||||||
pub use gpui_base::dock::{DockArea, DockLayout, DockPlacement};
|
pub use gpui_base::dock::{DockArea, DockLayout, DockPlacement};
|
||||||
use gpui_base::dock::{
|
use gpui_base::dock::{
|
||||||
DockAreaRenderer, DockContext, DragPanel, DropIndicator, InsertTarget, NodeId, PaneNode,
|
DockAreaRenderer, DockContext, DragPanel, DropIndicator, InsertTarget, NodeId, PaneNode,
|
||||||
PaneRef, PanelId, TabGroupContext, TabGroupRenderer, TileContext, TilesRenderer,
|
PaneRef, PanelId, TabGroupContext, TabGroupRenderer,
|
||||||
};
|
};
|
||||||
use gpui_base::{Placement, ResizeHandleContext, Side};
|
use gpui_base::{Placement, ResizeHandleContext, Side};
|
||||||
use theme::{ActiveTheme, TABBAR_HEIGHT};
|
use theme::{ActiveTheme, TABBAR_HEIGHT};
|
||||||
@@ -95,6 +95,19 @@ pub fn add_panel(
|
|||||||
area.add_panel_view(Arc::new(panel), placement, None, window, cx);
|
area.add_panel_view(Arc::new(panel), placement, None, window, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a panel to a dock reached through a weak handle.
|
||||||
|
pub fn add_panel_to(
|
||||||
|
dock: &WeakEntity<DockArea>,
|
||||||
|
panel: PanelHandle,
|
||||||
|
placement: DockPlacement,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut App,
|
||||||
|
) {
|
||||||
|
let _ = dock.update(cx, |area, cx| {
|
||||||
|
add_panel(area, panel, placement, window, cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// The panel in any region of `area` whose logical id is `key`.
|
/// The panel in any region of `area` whose logical id is `key`.
|
||||||
fn find_panel(area: &DockArea, key: &SharedString, cx: &App) -> Option<(PanelId, NodeId, usize)> {
|
fn find_panel(area: &DockArea, key: &SharedString, cx: &App) -> Option<(PanelId, NodeId, usize)> {
|
||||||
let placements = [
|
let placements = [
|
||||||
@@ -167,7 +180,6 @@ fn left_top_group(node: &PaneNode) -> Option<NodeId> {
|
|||||||
match node.kind() {
|
match node.kind() {
|
||||||
PaneRef::Tabs { .. } => Some(node.id()),
|
PaneRef::Tabs { .. } => Some(node.id()),
|
||||||
PaneRef::Split { children, .. } => children.first().and_then(left_top_group),
|
PaneRef::Split { children, .. } => children.first().and_then(left_top_group),
|
||||||
PaneRef::Tiles { .. } => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +194,6 @@ fn right_top_group(node: &PaneNode) -> Option<NodeId> {
|
|||||||
};
|
};
|
||||||
child.and_then(right_top_group)
|
child.and_then(right_top_group)
|
||||||
}
|
}
|
||||||
PaneRef::Tiles { .. } => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,18 +274,6 @@ impl DockAreaRenderer for DockSkin {
|
|||||||
fn tab_group_renderer(&self) -> Rc<dyn TabGroupRenderer> {
|
fn tab_group_renderer(&self) -> Rc<dyn TabGroupRenderer> {
|
||||||
Rc::new(TabGroupSkin::new(self.shared.clone()))
|
Rc::new(TabGroupSkin::new(self.shared.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tiles_renderer(&self) -> Rc<dyn TilesRenderer> {
|
|
||||||
Rc::new(NoTiles)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct NoTiles;
|
|
||||||
|
|
||||||
impl TilesRenderer for NoTiles {
|
|
||||||
fn render_drag_bar(&self, _: &TileContext, _: &mut Window, _: &mut App) -> AnyElement {
|
|
||||||
Empty.into_any_element()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The payload a dock's resize handle drags; the handle is the affordance.
|
/// The payload a dock's resize handle drags; the handle is the affordance.
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ pub enum PanelEvent {
|
|||||||
|
|
||||||
pub trait Panel: EventEmitter<PanelEvent> + Render + Focusable {
|
pub trait Panel: EventEmitter<PanelEvent> + Render + Focusable {
|
||||||
/// The name of the panel used to serialize, deserialize and identify the panel.
|
/// The name of the panel used to serialize, deserialize and identify the panel.
|
||||||
///
|
|
||||||
/// This is used to identify the panel when deserializing the panel.
|
|
||||||
/// Once you have defined a panel id, this must not be changed.
|
|
||||||
fn panel_id(&self) -> SharedString;
|
fn panel_id(&self) -> SharedString;
|
||||||
|
|
||||||
/// The title of the panel
|
/// The title of the panel
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ impl<T: IconNamed> From<T> for Icon {
|
|||||||
pub enum IconName {
|
pub enum IconName {
|
||||||
ArrowLeft,
|
ArrowLeft,
|
||||||
ArrowRight,
|
ArrowRight,
|
||||||
|
ArrowDownCircle,
|
||||||
Boom,
|
Boom,
|
||||||
Book,
|
Book,
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
@@ -99,6 +100,7 @@ impl IconNamed for IconName {
|
|||||||
match self {
|
match self {
|
||||||
Self::ArrowLeft => "icons/arrow-left.svg",
|
Self::ArrowLeft => "icons/arrow-left.svg",
|
||||||
Self::ArrowRight => "icons/arrow-right.svg",
|
Self::ArrowRight => "icons/arrow-right.svg",
|
||||||
|
Self::ArrowDownCircle => "icons/arrow-down-circle.svg",
|
||||||
Self::Boom => "icons/boom.svg",
|
Self::Boom => "icons/boom.svg",
|
||||||
Self::Book => "icons/book.svg",
|
Self::Book => "icons/book.svg",
|
||||||
Self::ChevronDown => "icons/chevron-down.svg",
|
Self::ChevronDown => "icons/chevron-down.svg",
|
||||||
|
|||||||
@@ -2,17 +2,18 @@ use chat::{ChatRegistry, Room, RoomKind};
|
|||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
App, AppContext, Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled,
|
App, AppContext, Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled,
|
||||||
Subscription, Window, div, px,
|
Subscription, WeakEntity, Window, div, px,
|
||||||
};
|
};
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use state::NostrRegistry;
|
use state::NostrRegistry;
|
||||||
use theme::ActiveTheme;
|
use theme::ActiveTheme;
|
||||||
use ui::button::{Button, ButtonVariants};
|
use ui::button::{Button, ButtonVariants};
|
||||||
|
use ui::dock::{DockArea, DockPlacement, PanelHandle};
|
||||||
use ui::input::{Input, InputEvent, InputState};
|
use ui::input::{Input, InputEvent, InputState};
|
||||||
use ui::{StyledExt, WindowExtension, v_flex};
|
use ui::{StyledExt, WindowExtension, v_flex};
|
||||||
|
|
||||||
pub fn open(window: &mut Window, cx: &mut App) {
|
pub fn open(dock: WeakEntity<DockArea>, window: &mut Window, cx: &mut App) {
|
||||||
let view = cx.new(|cx| NewChat::new(window, cx));
|
let view = cx.new(|cx| NewChat::new(dock, window, cx));
|
||||||
|
|
||||||
window.open_modal(cx, move |this, _window, _cx| {
|
window.open_modal(cx, move |this, _window, _cx| {
|
||||||
this.width(px(420.)).title("New chat").child(view.clone())
|
this.width(px(420.)).title("New chat").child(view.clone())
|
||||||
@@ -20,6 +21,9 @@ pub fn open(window: &mut Window, cx: &mut App) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct NewChat {
|
pub struct NewChat {
|
||||||
|
/// The dock a started chat opens in
|
||||||
|
dock: WeakEntity<DockArea>,
|
||||||
|
|
||||||
/// Public key input
|
/// Public key input
|
||||||
input: Entity<InputState>,
|
input: Entity<InputState>,
|
||||||
|
|
||||||
@@ -31,7 +35,7 @@ pub struct NewChat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NewChat {
|
impl NewChat {
|
||||||
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
fn new(dock: WeakEntity<DockArea>, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||||
let input = cx.new(|cx| InputState::new(window, cx).placeholder("npub"));
|
let input = cx.new(|cx| InputState::new(window, cx).placeholder("npub"));
|
||||||
|
|
||||||
let subscription = cx.subscribe_in(&input, window, |this, _input, event, window, cx| {
|
let subscription = cx.subscribe_in(&input, window, |this, _input, event, window, cx| {
|
||||||
@@ -41,6 +45,7 @@ impl NewChat {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
dock,
|
||||||
input,
|
input,
|
||||||
error: None,
|
error: None,
|
||||||
_subscription: Some(subscription),
|
_subscription: Some(subscription),
|
||||||
@@ -56,6 +61,8 @@ impl NewChat {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
|
let chat = ChatRegistry::global(cx);
|
||||||
|
|
||||||
let Some(current_user) = nostr.read(cx).current_user() else {
|
let Some(current_user) = nostr.read(cx).current_user() else {
|
||||||
self.set_error("You are not signed in", cx);
|
self.set_error("You are not signed in", cx);
|
||||||
return;
|
return;
|
||||||
@@ -70,12 +77,20 @@ impl NewChat {
|
|||||||
.organize(¤t_user)
|
.organize(¤t_user)
|
||||||
.kind(RoomKind::Ongoing);
|
.kind(RoomKind::Ongoing);
|
||||||
|
|
||||||
let chat = ChatRegistry::global(cx);
|
let room = chat.update(cx, |chat, cx| {
|
||||||
chat.update(cx, |chat, cx| {
|
|
||||||
let room = cx.new(|_| room);
|
let room = cx.new(|_| room);
|
||||||
chat.emit_room(&room, window, cx);
|
chat.track_room(&room, cx);
|
||||||
|
room
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ui::dock::add_panel_to(
|
||||||
|
&self.dock,
|
||||||
|
PanelHandle::new(chat_ui::init(room.downgrade(), window, cx)),
|
||||||
|
DockPlacement::Center,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
|
||||||
window.close_modal(cx);
|
window.close_modal(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+16
-266
@@ -1,4 +1,3 @@
|
|||||||
use std::rc::Rc;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ::settings::AppSettings;
|
use ::settings::AppSettings;
|
||||||
@@ -6,25 +5,20 @@ use anyhow::Error;
|
|||||||
use auto_update::AutoUpdater;
|
use auto_update::AutoUpdater;
|
||||||
use chat::{ChatEvent, ChatRegistry};
|
use chat::{ChatEvent, ChatRegistry};
|
||||||
use common::download_dir;
|
use common::download_dir;
|
||||||
use community::{CommunityEvent, CommunityRegistry};
|
|
||||||
use community_ui::CommunityPanel;
|
|
||||||
use device::{DeviceEvent, DeviceRegistry};
|
use device::{DeviceEvent, DeviceRegistry};
|
||||||
use gpui::prelude::FluentBuilder;
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
Action, AnyElement, App, AppContext, Context, Entity, InteractiveElement, IntoElement,
|
Action, App, AppContext, Context, Entity, InteractiveElement, IntoElement, ParentElement,
|
||||||
ParentElement, Render, SharedString, Styled, Subscription, Task, WeakEntity, Window, div, px,
|
Render, SharedString, Styled, Subscription, Task, Window, div, px,
|
||||||
};
|
};
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use person::{PersonRegistry, shorten_pubkey};
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use smallvec::{SmallVec, smallvec};
|
use smallvec::{SmallVec, smallvec};
|
||||||
use state::{NostrRegistry, StateEvent};
|
use state::{NostrRegistry, StateEvent};
|
||||||
use theme::{ActiveTheme, SIDEBAR_WIDTH, Theme, ThemeRegistry};
|
use theme::{ActiveTheme, SIDEBAR_WIDTH, Theme, ThemeRegistry};
|
||||||
use ui::button::{Button, ButtonVariants};
|
use ui::button::{Button, ButtonVariants};
|
||||||
use ui::dock::{self, ClosePanel, DockArea, DockLayout, DockPlacement, Panel, PanelHandle};
|
use ui::dock::{self, DockArea, DockLayout, DockPlacement, Panel, PanelHandle};
|
||||||
use ui::menu::{DropdownMenu, PopupMenuItem};
|
|
||||||
use ui::notification::{Notification, NotificationKind};
|
use ui::notification::{Notification, NotificationKind};
|
||||||
use ui::{Icon, IconName, Root, Sizable, WindowExtension, h_flex, v_flex};
|
use ui::{IconName, Root, Sizable, WindowExtension, h_flex, v_flex};
|
||||||
|
|
||||||
use crate::dialogs::restore::RestoreEncryption;
|
use crate::dialogs::restore::RestoreEncryption;
|
||||||
use crate::dialogs::{new_chat, new_community, settings};
|
use crate::dialogs::{new_chat, new_community, settings};
|
||||||
@@ -71,9 +65,6 @@ enum Command {
|
|||||||
|
|
||||||
pub struct Workspace {
|
pub struct Workspace {
|
||||||
dock: Entity<DockArea>,
|
dock: Entity<DockArea>,
|
||||||
title_bar_chrome: Rc<dock::TitleBarChrome>,
|
|
||||||
/// The community panel currently docked, if any
|
|
||||||
community_panel: Option<WeakEntity<CommunityPanel>>,
|
|
||||||
/// Async tasks
|
/// Async tasks
|
||||||
tasks: Vec<Task<Result<(), Error>>>,
|
tasks: Vec<Task<Result<(), Error>>>,
|
||||||
/// Event subscriptions
|
/// Event subscriptions
|
||||||
@@ -83,12 +74,11 @@ pub struct Workspace {
|
|||||||
impl Workspace {
|
impl Workspace {
|
||||||
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||||
let chat = ChatRegistry::global(cx);
|
let chat = ChatRegistry::global(cx);
|
||||||
let communities = CommunityRegistry::global(cx);
|
|
||||||
let device = DeviceRegistry::global(cx);
|
let device = DeviceRegistry::global(cx);
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
|
|
||||||
let sidebar = cx.new(|cx| Sidebar::new(window, cx));
|
let (dock, _) = dock::dock_area("coop", window, cx);
|
||||||
let (dock, title_bar_chrome) = dock::dock_area("coop", window, cx);
|
let sidebar = cx.new(|cx| Sidebar::new(window, dock.downgrade(), cx));
|
||||||
|
|
||||||
let mut subscriptions = smallvec![];
|
let mut subscriptions = smallvec![];
|
||||||
|
|
||||||
@@ -164,7 +154,7 @@ impl Workspace {
|
|||||||
|
|
||||||
subscriptions.push(
|
subscriptions.push(
|
||||||
// Observe all events emitted by the chat registry
|
// Observe all events emitted by the chat registry
|
||||||
cx.subscribe_in(&chat, window, move |this, chat, ev, window, cx| {
|
cx.subscribe_in(&chat, window, move |_this, _chat, ev, window, cx| {
|
||||||
match ev {
|
match ev {
|
||||||
ChatEvent::InboxRelayNotFound => {
|
ChatEvent::InboxRelayNotFound => {
|
||||||
const MSG: &str = "Messaging Relays not found. Cannot receive messages.";
|
const MSG: &str = "Messaging Relays not found. Cannot receive messages.";
|
||||||
@@ -187,28 +177,6 @@ impl Workspace {
|
|||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ChatEvent::OpenRoom(id) => {
|
|
||||||
if let Some(room) = chat.read(cx).room(id, cx) {
|
|
||||||
this.add_panel_to_dock(
|
|
||||||
chat_ui::init(room, window, cx),
|
|
||||||
DockPlacement::Center,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ChatEvent::CloseRoom(..) => {
|
|
||||||
this.dock.update(cx, |area, cx| {
|
|
||||||
// Force focus to the tab panel
|
|
||||||
ui::dock::focus_tab_panel(area, window, cx);
|
|
||||||
|
|
||||||
// Dispatch the close panel action
|
|
||||||
cx.defer_in(window, |_, window, cx| {
|
|
||||||
window.dispatch_action(Box::new(ClosePanel), cx);
|
|
||||||
window.close_all_modals(cx);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ChatEvent::Error(error) => {
|
ChatEvent::Error(error) => {
|
||||||
window.push_notification(Notification::error(error).autohide(false), cx);
|
window.push_notification(Notification::error(error).autohide(false), cx);
|
||||||
}
|
}
|
||||||
@@ -217,71 +185,23 @@ impl Workspace {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
subscriptions.push(
|
|
||||||
// Observe all events emitted by the community registry
|
|
||||||
cx.subscribe_in(
|
|
||||||
&communities,
|
|
||||||
window,
|
|
||||||
move |this, communities, event, window, cx| match event {
|
|
||||||
CommunityEvent::Open(id) => {
|
|
||||||
if let Some(community) = communities.read(cx).community(id) {
|
|
||||||
let panel = community_ui::init(community, window, cx);
|
|
||||||
|
|
||||||
this.community_panel = Some(panel.downgrade());
|
|
||||||
this.add_panel_to_dock(panel, DockPlacement::Center, window, cx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CommunityEvent::Close(_) => {
|
|
||||||
let Some(panel) = this
|
|
||||||
.community_panel
|
|
||||||
.take()
|
|
||||||
.and_then(|panel| panel.upgrade())
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.dock.update(cx, |area, cx| {
|
|
||||||
ui::dock::add_panel(
|
|
||||||
area,
|
|
||||||
PanelHandle::new(panel),
|
|
||||||
DockPlacement::Center,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
ui::dock::focus_tab_panel(area, window, cx);
|
|
||||||
|
|
||||||
cx.defer_in(window, |_, window, cx| {
|
|
||||||
window.dispatch_action(Box::new(ClosePanel), cx);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
cx.defer_in(window, move |this, window, cx| {
|
cx.defer_in(window, move |this, window, cx| {
|
||||||
let sidebar = PanelHandle::new(sidebar);
|
let sidebar = PanelHandle::new(sidebar);
|
||||||
|
|
||||||
this.dock.update(cx, |area, cx| {
|
|
||||||
let left = DockLayout::tabs().panel_view(Arc::new(sidebar), cx);
|
|
||||||
area.set_dock(DockPlacement::Left, left, window, cx);
|
|
||||||
area.set_dock_size(DockPlacement::Left, SIDEBAR_WIDTH, window, cx);
|
|
||||||
});
|
|
||||||
|
|
||||||
let greeter = PanelHandle::new(greeter::init(window, cx));
|
let greeter = PanelHandle::new(greeter::init(window, cx));
|
||||||
|
|
||||||
|
this.dock.update(cx, |this, cx| {
|
||||||
|
let left = DockLayout::tabs().panel_view(Arc::new(sidebar), cx);
|
||||||
let center = DockLayout::v_split()
|
let center = DockLayout::v_split()
|
||||||
.child(DockLayout::tabs().panel_view(Arc::new(greeter), cx), None);
|
.child(DockLayout::tabs().panel_view(Arc::new(greeter), cx), None);
|
||||||
|
|
||||||
this.dock.update(cx, |area, cx| {
|
this.set_dock(DockPlacement::Left, left, window, cx);
|
||||||
area.set_center(center, window, cx);
|
this.set_dock_size(DockPlacement::Left, SIDEBAR_WIDTH, window, cx);
|
||||||
|
this.set_center(center, window, cx);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
dock,
|
dock,
|
||||||
title_bar_chrome,
|
|
||||||
community_panel: None,
|
|
||||||
tasks: vec![],
|
tasks: vec![],
|
||||||
_subscriptions: subscriptions,
|
_subscriptions: subscriptions,
|
||||||
}
|
}
|
||||||
@@ -365,10 +285,11 @@ impl Workspace {
|
|||||||
self.add_panel_to_dock(browse::init(window, cx), DockPlacement::Center, window, cx);
|
self.add_panel_to_dock(browse::init(window, cx), DockPlacement::Center, window, cx);
|
||||||
}
|
}
|
||||||
Command::ShowSearch => {
|
Command::ShowSearch => {
|
||||||
self.add_panel_to_dock(search::init(window, cx), DockPlacement::Center, window, cx);
|
let panel = search::init(self.dock.downgrade(), window, cx);
|
||||||
|
self.add_panel_to_dock(panel, DockPlacement::Center, window, cx);
|
||||||
}
|
}
|
||||||
Command::NewChat => {
|
Command::NewChat => {
|
||||||
new_chat::open(window, cx);
|
new_chat::open(self.dock.downgrade(), window, cx);
|
||||||
}
|
}
|
||||||
Command::NewCommunity => {
|
Command::NewCommunity => {
|
||||||
new_community::open(window, cx);
|
new_community::open(window, cx);
|
||||||
@@ -583,174 +504,6 @@ impl Workspace {
|
|||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn titlebar_right(_window: &mut Window, cx: &mut App) -> AnyElement {
|
|
||||||
let auto_updater = AutoUpdater::try_global(cx);
|
|
||||||
let chat = ChatRegistry::global(cx);
|
|
||||||
let nip4e_enabled = AppSettings::get_nip4e(cx);
|
|
||||||
let nostr = NostrRegistry::global(cx);
|
|
||||||
|
|
||||||
let Some(public_key) = nostr.read(cx).current_user() else {
|
|
||||||
return div().into_any_element();
|
|
||||||
};
|
|
||||||
|
|
||||||
let persons = PersonRegistry::global(cx);
|
|
||||||
let profile = persons.read(cx).get(&public_key, cx);
|
|
||||||
let announcement = profile.announcement();
|
|
||||||
|
|
||||||
let updater_status = auto_updater.as_ref().and_then(|updater| {
|
|
||||||
let updater = updater.read(cx);
|
|
||||||
(!updater.idle()).then(|| updater.status())
|
|
||||||
});
|
|
||||||
|
|
||||||
let staged_update = auto_updater
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|updater| updater.read(cx).staged());
|
|
||||||
|
|
||||||
h_flex()
|
|
||||||
.when(!cx.theme().platform.is_mac(), |this| this.pr_2())
|
|
||||||
.gap_2()
|
|
||||||
.when_some(updater_status, |this, status| {
|
|
||||||
this.child(div().text_xs().italic().child(status))
|
|
||||||
})
|
|
||||||
.when(staged_update, |this| {
|
|
||||||
this.child(
|
|
||||||
Button::new("restart-to-update")
|
|
||||||
.label("Restart to Update")
|
|
||||||
.tooltip("Quit and relaunch into the installed update")
|
|
||||||
.small()
|
|
||||||
.ghost()
|
|
||||||
.on_click(|_event, _window, cx| {
|
|
||||||
if let Some(auto_updater) = AutoUpdater::try_global(cx) {
|
|
||||||
auto_updater.update(cx, |this, cx| this.restart(cx));
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.when(nip4e_enabled, |this| {
|
|
||||||
this.child(
|
|
||||||
Button::new("key")
|
|
||||||
.icon(IconName::UserKey)
|
|
||||||
.tooltip("Decoupled encryption key")
|
|
||||||
.small()
|
|
||||||
.ghost()
|
|
||||||
.dropdown_menu(move |this, _window, _cx| {
|
|
||||||
this.min_w(px(260.))
|
|
||||||
.label("Encryption Key")
|
|
||||||
.when_some(announcement.as_ref(), |this, announcement| {
|
|
||||||
let name = announcement.client_name();
|
|
||||||
let pkey = shorten_pubkey(announcement.public_key(), 8);
|
|
||||||
|
|
||||||
this.item(PopupMenuItem::element(move |_window, cx| {
|
|
||||||
h_flex()
|
|
||||||
.gap_1()
|
|
||||||
.text_sm()
|
|
||||||
.child(
|
|
||||||
Icon::new(IconName::Device)
|
|
||||||
.small()
|
|
||||||
.text_color(cx.theme().icon_muted),
|
|
||||||
)
|
|
||||||
.child(name.clone())
|
|
||||||
}))
|
|
||||||
.item(
|
|
||||||
PopupMenuItem::element(move |_window, cx| {
|
|
||||||
h_flex()
|
|
||||||
.gap_1()
|
|
||||||
.text_sm()
|
|
||||||
.child(
|
|
||||||
Icon::new(IconName::UserKey)
|
|
||||||
.small()
|
|
||||||
.text_color(cx.theme().icon_muted),
|
|
||||||
)
|
|
||||||
.child(SharedString::from(pkey.clone()))
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.separator()
|
|
||||||
.menu_with_icon(
|
|
||||||
"Backup",
|
|
||||||
IconName::Shield,
|
|
||||||
Box::new(Command::BackupEncryption),
|
|
||||||
)
|
|
||||||
.menu_with_icon(
|
|
||||||
"Restore from secret key",
|
|
||||||
IconName::Usb,
|
|
||||||
Box::new(Command::ImportEncryption),
|
|
||||||
)
|
|
||||||
.separator()
|
|
||||||
.menu_with_icon(
|
|
||||||
"Reload",
|
|
||||||
IconName::Refresh,
|
|
||||||
Box::new(Command::RefreshEncryption),
|
|
||||||
)
|
|
||||||
.menu_with_icon(
|
|
||||||
"Reset",
|
|
||||||
IconName::Warning,
|
|
||||||
Box::new(Command::ResetEncryption),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.child(
|
|
||||||
Button::new("inbox")
|
|
||||||
.icon(IconName::Inbox)
|
|
||||||
.small()
|
|
||||||
.ghost()
|
|
||||||
.dropdown_menu(move |this, _window, cx| {
|
|
||||||
let urls: Vec<(SharedString, SharedString)> = profile
|
|
||||||
.messaging_relays()
|
|
||||||
.iter()
|
|
||||||
.map(|url| {
|
|
||||||
(
|
|
||||||
SharedString::from(url.to_string()),
|
|
||||||
chat.read(cx).count_messages(url).to_string().into(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Header
|
|
||||||
let menu = this.min_w(px(260.)).label("Messaging Relays");
|
|
||||||
|
|
||||||
// Content
|
|
||||||
let menu = urls.into_iter().fold(menu, |this, (url, count)| {
|
|
||||||
this.item(PopupMenuItem::element(move |_window, cx| {
|
|
||||||
h_flex()
|
|
||||||
.px_1()
|
|
||||||
.w_full()
|
|
||||||
.text_sm()
|
|
||||||
.justify_between()
|
|
||||||
.child(url.clone())
|
|
||||||
.child(
|
|
||||||
div()
|
|
||||||
.text_xs()
|
|
||||||
.text_color(cx.theme().text_muted)
|
|
||||||
.child(count.clone()),
|
|
||||||
)
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
|
|
||||||
// Footer
|
|
||||||
menu.separator()
|
|
||||||
.menu_with_icon(
|
|
||||||
"Manage gossip relays",
|
|
||||||
IconName::Relay,
|
|
||||||
Box::new(Command::ShowRelayList),
|
|
||||||
)
|
|
||||||
.menu_with_icon(
|
|
||||||
"Manage messaging relays",
|
|
||||||
IconName::Relay,
|
|
||||||
Box::new(Command::ShowMessaging),
|
|
||||||
)
|
|
||||||
.separator()
|
|
||||||
.menu_with_icon(
|
|
||||||
"Reload",
|
|
||||||
IconName::Refresh,
|
|
||||||
Box::new(Command::RefreshMessagingRelays),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.into_any_element()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for Workspace {
|
impl Render for Workspace {
|
||||||
@@ -758,9 +511,6 @@ impl Render for Workspace {
|
|||||||
let modal_layer = Root::render_modal_layer(window, cx);
|
let modal_layer = Root::render_modal_layer(window, cx);
|
||||||
let notification_layer = Root::render_notification_layer(window, cx);
|
let notification_layer = Root::render_notification_layer(window, cx);
|
||||||
|
|
||||||
// Render the title bar chrome
|
|
||||||
self.title_bar_chrome.set_trailing(Self::titlebar_right);
|
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.id("workspace")
|
.id("workspace")
|
||||||
.on_action(cx.listener(Self::on_command))
|
.on_action(cx.listener(Self::on_command))
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ use common::DebouncedDelay;
|
|||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AnyElement, App, AppContext, Context, ElementId, Entity, EventEmitter, FocusHandle, Focusable,
|
AnyElement, App, AppContext, Context, ElementId, Entity, EventEmitter, FocusHandle, Focusable,
|
||||||
IntoElement, ParentElement, Render, SharedString, Styled, Subscription, Task, Window, div,
|
IntoElement, ParentElement, Render, SharedString, Styled, Subscription, Task, WeakEntity,
|
||||||
uniform_list,
|
Window, div, uniform_list,
|
||||||
};
|
};
|
||||||
use instant::Duration;
|
use instant::Duration;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
@@ -17,7 +17,7 @@ use smallvec::{SmallVec, smallvec};
|
|||||||
use state::{FIND_DELAY, NostrRegistry};
|
use state::{FIND_DELAY, NostrRegistry};
|
||||||
use theme::ActiveTheme;
|
use theme::ActiveTheme;
|
||||||
use ui::button::{Button, ButtonVariants};
|
use ui::button::{Button, ButtonVariants};
|
||||||
use ui::dock::{Panel, PanelEvent};
|
use ui::dock::{DockArea, DockPlacement, Panel, PanelEvent, PanelHandle};
|
||||||
use ui::input::{Input, InputEvent, InputState};
|
use ui::input::{Input, InputEvent, InputState};
|
||||||
use ui::notification::Notification;
|
use ui::notification::Notification;
|
||||||
use ui::{Icon, IconName, Selectable, Sizable, StyledExt, WindowExtension, h_flex, v_flex};
|
use ui::{Icon, IconName, Selectable, Sizable, StyledExt, WindowExtension, h_flex, v_flex};
|
||||||
@@ -26,13 +26,15 @@ use crate::sidebar::{TreeRow, TreeRowKind};
|
|||||||
|
|
||||||
const INPUT_PLACEHOLDER: &str = "Find or start a conversation";
|
const INPUT_PLACEHOLDER: &str = "Find or start a conversation";
|
||||||
|
|
||||||
pub fn init(window: &mut Window, cx: &mut App) -> Entity<SearchPanel> {
|
pub fn init(dock: WeakEntity<DockArea>, window: &mut Window, cx: &mut App) -> Entity<SearchPanel> {
|
||||||
cx.new(|cx| SearchPanel::new(window, cx))
|
cx.new(|cx| SearchPanel::new(dock, window, cx))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SearchPanel {
|
pub struct SearchPanel {
|
||||||
name: SharedString,
|
name: SharedString,
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
|
/// The dock a started chat opens in
|
||||||
|
dock: WeakEntity<DockArea>,
|
||||||
|
|
||||||
/// Find input state
|
/// Find input state
|
||||||
find_input: Entity<InputState>,
|
find_input: Entity<InputState>,
|
||||||
@@ -63,7 +65,7 @@ pub struct SearchPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SearchPanel {
|
impl SearchPanel {
|
||||||
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
fn new(dock: WeakEntity<DockArea>, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||||
let contact_list = cx.new(|_| None);
|
let contact_list = cx.new(|_| None);
|
||||||
let selected_pkeys = cx.new(|_| HashSet::new());
|
let selected_pkeys = cx.new(|_| HashSet::new());
|
||||||
let find_results = cx.new(|_| None);
|
let find_results = cx.new(|_| None);
|
||||||
@@ -107,6 +109,7 @@ impl SearchPanel {
|
|||||||
Self {
|
Self {
|
||||||
name: "Search".into(),
|
name: "Search".into(),
|
||||||
focus_handle: cx.focus_handle(),
|
focus_handle: cx.focus_handle(),
|
||||||
|
dock,
|
||||||
find_input,
|
find_input,
|
||||||
find_debouncer: DebouncedDelay::new(),
|
find_debouncer: DebouncedDelay::new(),
|
||||||
find_results,
|
find_results,
|
||||||
@@ -285,6 +288,7 @@ impl SearchPanel {
|
|||||||
fn create_room(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
fn create_room(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
let chat = ChatRegistry::global(cx);
|
let chat = ChatRegistry::global(cx);
|
||||||
let async_chat = chat.downgrade();
|
let async_chat = chat.downgrade();
|
||||||
|
let dock = self.dock.clone();
|
||||||
|
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
let Some(public_key) = nostr.read(cx).current_user() else {
|
let Some(public_key) = nostr.read(cx).current_user() else {
|
||||||
@@ -295,14 +299,26 @@ impl SearchPanel {
|
|||||||
let receivers = self.get_selected(cx);
|
let receivers = self.get_selected(cx);
|
||||||
|
|
||||||
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
|
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
|
||||||
// Create a new room and emit it
|
// Create a new room and register it
|
||||||
async_chat.update_in(cx, |this, _window, cx| {
|
let room = async_chat.update_in(cx, |chat, _window, cx| {
|
||||||
let room = cx.new(|_| {
|
let room = cx.new(|_| {
|
||||||
Room::new(public_key, receivers)
|
Room::new(public_key, receivers)
|
||||||
.organize(&public_key)
|
.organize(&public_key)
|
||||||
.kind(RoomKind::Ongoing)
|
.kind(RoomKind::Ongoing)
|
||||||
});
|
});
|
||||||
this.emit_room(&room, _window, cx);
|
chat.track_room(&room, cx);
|
||||||
|
room
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Open it in the dock
|
||||||
|
cx.update(|window, cx| {
|
||||||
|
ui::dock::add_panel_to(
|
||||||
|
&dock,
|
||||||
|
PanelHandle::new(chat_ui::init(room.downgrade(), window, cx)),
|
||||||
|
DockPlacement::Center,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Reset the find panel
|
// Reset the find panel
|
||||||
|
|||||||
+400
-342
@@ -2,15 +2,15 @@ use std::ops::Range;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use auto_update::AutoUpdater;
|
use auto_update::AutoUpdater;
|
||||||
use chat::{ChatEvent, ChatRegistry, RoomKind};
|
use chat::{ChatEvent, ChatRegistry, Room, RoomKind};
|
||||||
use common::TimestampExt;
|
use common::TimestampExt;
|
||||||
use community::{ChannelId, Community, CommunityEvent, CommunityRegistry};
|
use community::{ChannelId, Community, CommunityEvent, CommunityRegistry};
|
||||||
use gpui::prelude::FluentBuilder;
|
use gpui::prelude::FluentBuilder;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AnyElement, App, Context, ElementId, Entity, EventEmitter, FocusHandle, Focusable,
|
AnyElement, App, Context, Div, ElementId, Entity, EventEmitter, FocusHandle, Focusable,
|
||||||
InteractiveElement, IntoElement, ObjectFit, ParentElement, Render, ScrollHandle, SharedString,
|
InteractiveElement, IntoElement, ObjectFit, ParentElement, Render, ScrollHandle, SharedString,
|
||||||
StatefulInteractiveElement, Styled, StyledImage, Subscription, UniformListScrollHandle,
|
Stateful, StatefulInteractiveElement, Styled, StyledImage, Subscription,
|
||||||
WeakEntity, Window, div, img, px, retain_all, uniform_list,
|
UniformListScrollHandle, WeakEntity, Window, div, img, px, retain_all, uniform_list,
|
||||||
};
|
};
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use person::PersonRegistry;
|
use person::PersonRegistry;
|
||||||
@@ -20,7 +20,7 @@ use state::NostrRegistry;
|
|||||||
use theme::{ActiveTheme, TABBAR_HEIGHT};
|
use theme::{ActiveTheme, TABBAR_HEIGHT};
|
||||||
use ui::avatar::Avatar;
|
use ui::avatar::Avatar;
|
||||||
use ui::button::{Button, ButtonVariants};
|
use ui::button::{Button, ButtonVariants};
|
||||||
use ui::dock::{Panel, PanelEvent};
|
use ui::dock::{DockArea, DockPlacement, Panel, PanelEvent, PanelHandle};
|
||||||
use ui::indicator::Indicator;
|
use ui::indicator::Indicator;
|
||||||
use ui::menu::{DropdownMenu, PopupMenuItem};
|
use ui::menu::{DropdownMenu, PopupMenuItem};
|
||||||
use ui::nav_item::NavItem;
|
use ui::nav_item::NavItem;
|
||||||
@@ -32,8 +32,8 @@ use ui::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::Command;
|
use crate::Command;
|
||||||
|
use crate::dialogs::import;
|
||||||
|
|
||||||
mod onboarding;
|
|
||||||
mod tab;
|
mod tab;
|
||||||
mod tree;
|
mod tree;
|
||||||
|
|
||||||
@@ -46,23 +46,22 @@ pub struct Sidebar {
|
|||||||
scroll_handles: [UniformListScrollHandle; 3],
|
scroll_handles: [UniformListScrollHandle; 3],
|
||||||
/// Scroll state of the channel and member lists
|
/// Scroll state of the channel and member lists
|
||||||
community_scroll: ScrollHandle,
|
community_scroll: ScrollHandle,
|
||||||
|
/// The dock the sidebar opens its panels in
|
||||||
|
dock: WeakEntity<DockArea>,
|
||||||
active_tab: SidebarTab,
|
active_tab: SidebarTab,
|
||||||
/// The community the sidebar is browsing, if any
|
/// The community the sidebar is browsing, if any
|
||||||
community: Option<WeakEntity<Community>>,
|
community: Option<WeakEntity<Community>>,
|
||||||
/// Expanded state of the community's sections
|
|
||||||
channels_open: bool,
|
channels_open: bool,
|
||||||
admins_open: bool,
|
admins_open: bool,
|
||||||
members_open: bool,
|
members_open: bool,
|
||||||
/// Whether there are new chat requests
|
|
||||||
new_requests: bool,
|
new_requests: bool,
|
||||||
_subscriptions: SmallVec<[Subscription; 4]>,
|
_subscriptions: SmallVec<[Subscription; 4]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sidebar {
|
impl Sidebar {
|
||||||
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
pub fn new(window: &mut Window, dock: WeakEntity<DockArea>, cx: &mut Context<Self>) -> Self {
|
||||||
let chat = ChatRegistry::global(cx);
|
let chat = ChatRegistry::global(cx);
|
||||||
let communities = CommunityRegistry::global(cx);
|
let communities = CommunityRegistry::global(cx);
|
||||||
let nostr = NostrRegistry::global(cx);
|
|
||||||
|
|
||||||
let mut subscriptions = smallvec![];
|
let mut subscriptions = smallvec![];
|
||||||
|
|
||||||
@@ -80,16 +79,11 @@ impl Sidebar {
|
|||||||
window,
|
window,
|
||||||
|_this, _communities, event, window, cx| {
|
|_this, _communities, event, window, cx| {
|
||||||
if let CommunityEvent::Error(error) = event {
|
if let CommunityEvent::Error(error) = event {
|
||||||
window
|
window.push_notification(Notification::error(error.clone()), cx);
|
||||||
.push_notification(Notification::error(error.clone()).autohide(false), cx);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
subscriptions.push(cx.observe(&nostr, |_this, _nostr, cx| cx.notify()));
|
|
||||||
|
|
||||||
subscriptions.push(cx.observe(&communities, |_this, _communities, cx| cx.notify()));
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
focus_handle: cx.focus_handle(),
|
focus_handle: cx.focus_handle(),
|
||||||
scroll_handles: [
|
scroll_handles: [
|
||||||
@@ -98,6 +92,7 @@ impl Sidebar {
|
|||||||
UniformListScrollHandle::new(),
|
UniformListScrollHandle::new(),
|
||||||
],
|
],
|
||||||
community_scroll: ScrollHandle::default(),
|
community_scroll: ScrollHandle::default(),
|
||||||
|
dock,
|
||||||
active_tab: SidebarTab::Recents,
|
active_tab: SidebarTab::Recents,
|
||||||
community: None,
|
community: None,
|
||||||
channels_open: true,
|
channels_open: true,
|
||||||
@@ -112,7 +107,6 @@ impl Sidebar {
|
|||||||
if self.active_tab == tab {
|
if self.active_tab == tab {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.active_tab = tab;
|
self.active_tab = tab;
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
@@ -130,33 +124,42 @@ impl Sidebar {
|
|||||||
settings.record_recent_community(id, cx);
|
settings.record_recent_community(id, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
CommunityRegistry::global(cx).update(cx, |registry, cx| {
|
|
||||||
registry.emit_community(&community, window, cx);
|
|
||||||
});
|
|
||||||
|
|
||||||
self.community = Some(community.downgrade());
|
self.community = Some(community.downgrade());
|
||||||
|
|
||||||
|
ui::dock::add_panel_to(
|
||||||
|
&self.dock,
|
||||||
|
PanelHandle::new(community_ui::init(community, window, cx)),
|
||||||
|
DockPlacement::Center,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_community(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
fn open_room(&mut self, room: Entity<Room>, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
let Some(community) = self.community.take() else {
|
ui::dock::add_panel_to(
|
||||||
|
&self.dock,
|
||||||
|
PanelHandle::new(chat_ui::init(room.downgrade(), window, cx)),
|
||||||
|
DockPlacement::Center,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Leave the community view, returning the sidebar to its tab list.
|
||||||
|
fn reset_community(&mut self, cx: &mut Context<Self>) {
|
||||||
|
if self.community.take().is_none() {
|
||||||
return;
|
return;
|
||||||
};
|
|
||||||
|
|
||||||
if let Ok(id) = community.read_with(cx, |community, _cx| community.id()) {
|
|
||||||
CommunityRegistry::global(cx).update(cx, |registry, cx| {
|
|
||||||
registry.emit_close(id, window, cx);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_user(&self, window: &mut Window, cx: &mut Context<Self>) -> AnyElement {
|
fn render_user(&self, cx: &mut Context<Self>) -> Stateful<Div> {
|
||||||
let nostr = NostrRegistry::global(cx);
|
let nostr = NostrRegistry::global(cx);
|
||||||
let current_user = nostr.read(cx).current_user();
|
let current_user = nostr.read(cx).current_user();
|
||||||
|
|
||||||
let mut row = h_flex()
|
h_flex()
|
||||||
.id("sidebar-user")
|
.id("sidebar-user")
|
||||||
.w_full()
|
.w_full()
|
||||||
.h(TABBAR_HEIGHT)
|
.h(TABBAR_HEIGHT)
|
||||||
@@ -166,16 +169,15 @@ impl Sidebar {
|
|||||||
.px_2()
|
.px_2()
|
||||||
.when(cfg!(target_os = "macos"), |this| {
|
.when(cfg!(target_os = "macos"), |this| {
|
||||||
this.pl(px(TRAFFIC_LIGHT_PADDING))
|
this.pl(px(TRAFFIC_LIGHT_PADDING))
|
||||||
});
|
})
|
||||||
|
.when_some(current_user.as_ref(), |this, public_key| {
|
||||||
if let Some(public_key) = current_user.as_ref() {
|
|
||||||
let persons = PersonRegistry::global(cx);
|
let persons = PersonRegistry::global(cx);
|
||||||
let profile = persons.read(cx).get(public_key, cx);
|
let profile = persons.read(cx).get(public_key, cx);
|
||||||
let avatar = profile.avatar();
|
let avatar = profile.avatar();
|
||||||
let avatar_seed = profile.avatar_seed();
|
let avatar_seed = profile.avatar_seed();
|
||||||
let name = profile.name();
|
let name = profile.name();
|
||||||
|
|
||||||
row = row.child(
|
this.child(
|
||||||
Button::new("current-user")
|
Button::new("current-user")
|
||||||
.child(
|
.child(
|
||||||
Avatar::new(avatar.clone())
|
Avatar::new(avatar.clone())
|
||||||
@@ -205,7 +207,11 @@ impl Sidebar {
|
|||||||
.child(name.clone())
|
.child(name.clone())
|
||||||
}))
|
}))
|
||||||
.separator()
|
.separator()
|
||||||
.menu_with_icon("Inbox", IconName::Inbox, Box::new(Command::ShowInbox))
|
.menu_with_icon(
|
||||||
|
"Inbox",
|
||||||
|
IconName::Inbox,
|
||||||
|
Box::new(Command::ShowInbox),
|
||||||
|
)
|
||||||
.menu_with_icon(
|
.menu_with_icon(
|
||||||
"Search",
|
"Search",
|
||||||
IconName::Search,
|
IconName::Search,
|
||||||
@@ -226,7 +232,11 @@ impl Sidebar {
|
|||||||
IconName::UserKey,
|
IconName::UserKey,
|
||||||
Box::new(Command::ShowBackup),
|
Box::new(Command::ShowBackup),
|
||||||
)
|
)
|
||||||
.menu_with_icon("Themes", IconName::Sun, Box::new(Command::ToggleTheme))
|
.menu_with_icon(
|
||||||
|
"Themes",
|
||||||
|
IconName::Sun,
|
||||||
|
Box::new(Command::ToggleTheme),
|
||||||
|
)
|
||||||
.when(AutoUpdater::is_available(cx), |this| {
|
.when(AutoUpdater::is_available(cx), |this| {
|
||||||
this.separator().menu_with_icon(
|
this.separator().menu_with_icon(
|
||||||
"Check for Updates",
|
"Check for Updates",
|
||||||
@@ -240,315 +250,58 @@ impl Sidebar {
|
|||||||
Box::new(Command::ShowSettings),
|
Box::new(Command::ShowSettings),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
);
|
)
|
||||||
}
|
})
|
||||||
|
.child(div().flex_1())
|
||||||
if self.community.is_some() {
|
.when_some(AutoUpdater::try_global(cx), |this, updater| {
|
||||||
row = row.child(div().flex_1()).child(
|
this.child(self.render_updater(updater, cx))
|
||||||
|
})
|
||||||
|
.when(self.community.is_some(), |this| {
|
||||||
|
this.child(
|
||||||
Button::new("sidebar-back")
|
Button::new("sidebar-back")
|
||||||
.icon(IconName::ArrowLeft)
|
.icon(IconName::ArrowLeft)
|
||||||
.tooltip("Back")
|
.tooltip("Back")
|
||||||
.ghost()
|
.ghost()
|
||||||
.small()
|
.small()
|
||||||
.on_click(cx.listener(|this, _event, window, cx| {
|
.on_click(cx.listener(|this, _event, _window, cx| {
|
||||||
this.close_community(window, cx);
|
this.reset_community(cx);
|
||||||
})),
|
})),
|
||||||
);
|
)
|
||||||
}
|
|
||||||
|
|
||||||
title_bar_drag_handlers(row, window, cx).into_any_element()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recent_communities(cx: &App) -> Vec<Entity<Community>> {
|
|
||||||
const LIMIT: usize = 3;
|
|
||||||
|
|
||||||
let registry = CommunityRegistry::global(cx);
|
|
||||||
let communities = registry.read(cx).communities();
|
|
||||||
let recent = AppSettings::get_recent_communities(cx);
|
|
||||||
|
|
||||||
let mut rows: Vec<Entity<Community>> = recent
|
|
||||||
.iter()
|
|
||||||
.filter_map(|id| {
|
|
||||||
communities
|
|
||||||
.iter()
|
|
||||||
.find(|community| community.read(cx).id().to_hex() == *id)
|
|
||||||
})
|
})
|
||||||
.take(LIMIT)
|
|
||||||
.cloned()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if rows.is_empty() {
|
|
||||||
rows = communities.iter().take(LIMIT).cloned().collect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rows
|
fn render_updater(&self, updater: Entity<AutoUpdater>, cx: &mut App) -> AnyElement {
|
||||||
}
|
let status = updater.read(cx).status();
|
||||||
|
let staged = updater.read(cx).staged();
|
||||||
|
|
||||||
fn rows_for(tab: SidebarTab, cx: &App) -> Vec<SidebarRow> {
|
h_flex()
|
||||||
match tab {
|
|
||||||
SidebarTab::Recents => {
|
|
||||||
let chat = ChatRegistry::global(cx);
|
|
||||||
let rooms = chat.read(cx).rooms(&RoomKind::Ongoing, cx);
|
|
||||||
let registry = CommunityRegistry::global(cx);
|
|
||||||
let community_count = registry.read(cx).communities().len();
|
|
||||||
let communities = recent_communities(cx);
|
|
||||||
|
|
||||||
if communities.is_empty() && rooms.is_empty() {
|
|
||||||
return vec![SidebarRow::Hint {
|
|
||||||
text: "Nothing recent yet".into(),
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut rows = Vec::new();
|
|
||||||
|
|
||||||
if !communities.is_empty() {
|
|
||||||
rows.push(SidebarRow::Section {
|
|
||||||
label: "Communities".into(),
|
|
||||||
count: community_count,
|
|
||||||
});
|
|
||||||
rows.extend(
|
|
||||||
communities
|
|
||||||
.into_iter()
|
|
||||||
.map(|community| SidebarRow::Community { community }),
|
|
||||||
);
|
|
||||||
rows.push(SidebarRow::Action {
|
|
||||||
label: "Show all communities".into(),
|
|
||||||
tab: SidebarTab::Communities,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if !rooms.is_empty() {
|
|
||||||
rows.push(SidebarRow::Section {
|
|
||||||
label: "Chats".into(),
|
|
||||||
count: rooms.len(),
|
|
||||||
});
|
|
||||||
rows.extend(
|
|
||||||
rooms
|
|
||||||
.into_iter()
|
|
||||||
.take(5)
|
|
||||||
.map(|room| SidebarRow::Room { room }),
|
|
||||||
);
|
|
||||||
rows.push(SidebarRow::Action {
|
|
||||||
label: "Show all chats".into(),
|
|
||||||
tab: SidebarTab::Chats,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
rows
|
|
||||||
}
|
|
||||||
SidebarTab::Chats => {
|
|
||||||
let chat = ChatRegistry::global(cx);
|
|
||||||
let chat = chat.read(cx);
|
|
||||||
let messages = chat.rooms(&RoomKind::Ongoing, cx);
|
|
||||||
|
|
||||||
let mut rows = vec![SidebarRow::Section {
|
|
||||||
label: "Chats".into(),
|
|
||||||
count: messages.len(),
|
|
||||||
}];
|
|
||||||
|
|
||||||
if messages.is_empty() {
|
|
||||||
rows.push(SidebarRow::Hint {
|
|
||||||
text: "No conversations yet".into(),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
rows.extend(messages.into_iter().map(|room| SidebarRow::Room { room }));
|
|
||||||
}
|
|
||||||
|
|
||||||
rows
|
|
||||||
}
|
|
||||||
SidebarTab::Communities => {
|
|
||||||
let registry = CommunityRegistry::global(cx);
|
|
||||||
let communities = registry.read(cx).communities();
|
|
||||||
|
|
||||||
let mut rows = vec![SidebarRow::Section {
|
|
||||||
label: "Communities".into(),
|
|
||||||
count: communities.len(),
|
|
||||||
}];
|
|
||||||
|
|
||||||
if communities.is_empty() {
|
|
||||||
rows.push(SidebarRow::Hint {
|
|
||||||
text: "No communities yet".into(),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
rows.extend(
|
|
||||||
communities
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.map(|community| SidebarRow::Community { community }),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
rows
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_rows(range: Range<usize>, rows: &[SidebarRow], cx: &Context<Sidebar>) -> Vec<AnyElement> {
|
|
||||||
rows.get(range.clone())
|
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(offset, row)| {
|
|
||||||
let index = range.start + offset;
|
|
||||||
|
|
||||||
match row {
|
|
||||||
SidebarRow::Section { label, count } => TreeRow::new(
|
|
||||||
ElementId::NamedInteger("tree-row".into(), index as u64),
|
|
||||||
TreeRowKind::Section,
|
|
||||||
label.clone(),
|
|
||||||
)
|
|
||||||
.count(*count)
|
|
||||||
.into_any_element(),
|
|
||||||
SidebarRow::Room { room } => {
|
|
||||||
let name = room.read(cx).display_name(cx);
|
|
||||||
let picture = room.read(cx).display_image(cx);
|
|
||||||
let seed = room.read(cx).display_image_seed(cx);
|
|
||||||
let created_at = room.read(cx).created_at.to_ago();
|
|
||||||
let room_clone = room.clone();
|
|
||||||
|
|
||||||
let handler = cx.listener(move |_this, _event, window, cx| {
|
|
||||||
ChatRegistry::global(cx).update(cx, |chat, cx| {
|
|
||||||
chat.emit_room(&room_clone, window, cx);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
TreeRow::new(
|
|
||||||
ElementId::NamedInteger("tree-row".into(), index as u64),
|
|
||||||
TreeRowKind::Room,
|
|
||||||
name,
|
|
||||||
)
|
|
||||||
.avatar(seed)
|
|
||||||
.picture(picture)
|
|
||||||
.created_at(created_at)
|
|
||||||
.on_click(handler)
|
|
||||||
.into_any_element()
|
|
||||||
}
|
|
||||||
SidebarRow::Community { community } => {
|
|
||||||
let name = community.read(cx).name();
|
|
||||||
let seed = community.read(cx).id().to_hex();
|
|
||||||
let picture = community.read(cx).icon();
|
|
||||||
let community = community.clone();
|
|
||||||
|
|
||||||
TreeRow::new(
|
|
||||||
ElementId::NamedInteger("tree-row".into(), index as u64),
|
|
||||||
TreeRowKind::Community,
|
|
||||||
name,
|
|
||||||
)
|
|
||||||
.avatar(seed)
|
|
||||||
.picture(picture)
|
|
||||||
.on_click(cx.listener(move |this, _event, window, cx| {
|
|
||||||
this.open_community(community.clone(), window, cx);
|
|
||||||
}))
|
|
||||||
.into_any_element()
|
|
||||||
}
|
|
||||||
SidebarRow::Action { label, tab } => {
|
|
||||||
let tab = *tab;
|
|
||||||
|
|
||||||
TreeRow::new(
|
|
||||||
ElementId::NamedInteger("tree-row".into(), index as u64),
|
|
||||||
TreeRowKind::Action,
|
|
||||||
label.clone(),
|
|
||||||
)
|
|
||||||
.icon(IconName::ArrowRight)
|
|
||||||
.on_click(cx.listener(move |this, _event, _window, cx| {
|
|
||||||
this.select_tab(tab, cx);
|
|
||||||
}))
|
|
||||||
.into_any_element()
|
|
||||||
}
|
|
||||||
SidebarRow::Hint { text } => TreeRow::new(
|
|
||||||
ElementId::NamedInteger("tree-row".into(), index as u64),
|
|
||||||
TreeRowKind::Hint,
|
|
||||||
text.clone(),
|
|
||||||
)
|
|
||||||
.into_any_element(),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Panel for Sidebar {
|
|
||||||
fn panel_id(&self) -> SharedString {
|
|
||||||
"Sidebar".into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn title(&self, _cx: &App) -> AnyElement {
|
|
||||||
SharedString::from("Sidebar").into_any_element()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn closable(&self, _cx: &App) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn zoomable(&self, _cx: &App) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EventEmitter<PanelEvent> for Sidebar {}
|
|
||||||
|
|
||||||
impl Focusable for Sidebar {
|
|
||||||
fn focus_handle(&self, _: &App) -> gpui::FocusHandle {
|
|
||||||
self.focus_handle.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Render for Sidebar {
|
|
||||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
||||||
let (logged_in, ready) = {
|
|
||||||
let nostr = NostrRegistry::global(cx);
|
|
||||||
(
|
|
||||||
nostr.read(cx).current_user().is_some(),
|
|
||||||
nostr.read(cx).ready(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !logged_in {
|
|
||||||
if !ready {
|
|
||||||
return v_flex()
|
|
||||||
.size_full()
|
|
||||||
.bg(cx.theme().surface_background)
|
|
||||||
.border_r_1()
|
|
||||||
.border_color(cx.theme().border_variant)
|
|
||||||
.into_any_element();
|
|
||||||
}
|
|
||||||
return onboarding::render(window, cx).into_any_element();
|
|
||||||
}
|
|
||||||
|
|
||||||
let community = self
|
|
||||||
.community
|
|
||||||
.clone()
|
|
||||||
.and_then(|community| community.upgrade());
|
|
||||||
|
|
||||||
if community.is_none() {
|
|
||||||
self.community = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
v_flex()
|
|
||||||
.image_cache(retain_all("sidebar"))
|
|
||||||
.size_full()
|
|
||||||
.relative()
|
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.bg(cx.theme().surface_background)
|
.text_xs()
|
||||||
.border_r_1()
|
.child(status)
|
||||||
.border_color(cx.theme().border_variant)
|
.when(staged, |this| {
|
||||||
.child(self.render_user(window, cx))
|
this.child(
|
||||||
.map(|this| match community {
|
Button::new("restart-to-update")
|
||||||
Some(community) => this.child(self.render_community(community, cx)),
|
.icon(IconName::ArrowDownCircle)
|
||||||
None => this.child(self.render_tabs(cx)),
|
.tooltip("Quit and relaunch into the installed update")
|
||||||
|
.small()
|
||||||
|
.ghost()
|
||||||
|
.on_click(move |_, _window, cx| {
|
||||||
|
updater.update(cx, |this, cx| {
|
||||||
|
this.restart(cx);
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Sidebar {
|
|
||||||
fn render_tabs(&mut self, cx: &mut Context<Self>) -> AnyElement {
|
fn render_tabs(&mut self, cx: &mut Context<Self>) -> AnyElement {
|
||||||
let chat = ChatRegistry::global(cx);
|
let chat = ChatRegistry::global(cx);
|
||||||
let loading = chat.read(cx).loading();
|
let loading = chat.read(cx).loading();
|
||||||
|
|
||||||
let sidebar = cx.entity().downgrade();
|
let sidebar = cx.entity().downgrade();
|
||||||
let active_tab = self.active_tab;
|
let active_tab = self.active_tab;
|
||||||
let rows = Rc::new(rows_for(active_tab, cx));
|
let rows = Rc::new(self.rows_for(active_tab, cx));
|
||||||
let scroll_handle = &self.scroll_handles[active_tab.index()];
|
let scroll_handle = &self.scroll_handles[active_tab.index()];
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
@@ -643,8 +396,8 @@ impl Sidebar {
|
|||||||
uniform_list(
|
uniform_list(
|
||||||
active_tab.list_id(),
|
active_tab.list_id(),
|
||||||
rows.len(),
|
rows.len(),
|
||||||
cx.processor(move |_this, range, _window, cx| {
|
cx.processor(move |this, range, _window, cx| {
|
||||||
render_rows(range, rows.as_slice(), cx)
|
this.render_rows(range, rows.as_slice(), cx)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.track_scroll(scroll_handle)
|
.track_scroll(scroll_handle)
|
||||||
@@ -732,7 +485,7 @@ impl Sidebar {
|
|||||||
.pb_2()
|
.pb_2()
|
||||||
.track_scroll(&self.community_scroll)
|
.track_scroll(&self.community_scroll)
|
||||||
.overflow_y_scroll()
|
.overflow_y_scroll()
|
||||||
.child(section_row(
|
.child(self.section_row(
|
||||||
"channels",
|
"channels",
|
||||||
"Channels",
|
"Channels",
|
||||||
channels.len(),
|
channels.len(),
|
||||||
@@ -742,10 +495,10 @@ impl Sidebar {
|
|||||||
))
|
))
|
||||||
.when(self.channels_open, |this| {
|
.when(self.channels_open, |this| {
|
||||||
this.children(channels.into_iter().map(|(id, name, private)| {
|
this.children(channels.into_iter().map(|(id, name, private)| {
|
||||||
channel_row(id, name, private, active == Some(id), &community, cx)
|
self.channel_row(id, name, private, active == Some(id), &community, cx)
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
.child(section_row(
|
.child(self.section_row(
|
||||||
"admins",
|
"admins",
|
||||||
"Admins",
|
"Admins",
|
||||||
admins.len(),
|
admins.len(),
|
||||||
@@ -757,10 +510,10 @@ impl Sidebar {
|
|||||||
this.children(
|
this.children(
|
||||||
admins
|
admins
|
||||||
.iter()
|
.iter()
|
||||||
.map(|public_key| member_row("community-admin", *public_key, cx)),
|
.map(|public_key| self.member_row("community-admin", *public_key, cx)),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.child(section_row(
|
.child(self.section_row(
|
||||||
"members",
|
"members",
|
||||||
"Members",
|
"Members",
|
||||||
members.len(),
|
members.len(),
|
||||||
@@ -772,7 +525,7 @@ impl Sidebar {
|
|||||||
this.children(
|
this.children(
|
||||||
members
|
members
|
||||||
.iter()
|
.iter()
|
||||||
.map(|public_key| member_row("member", *public_key, cx)),
|
.map(|public_key| self.member_row("member", *public_key, cx)),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -796,16 +549,226 @@ impl Sidebar {
|
|||||||
.child(Scrollbar::vertical(&self.community_scroll))
|
.child(Scrollbar::vertical(&self.community_scroll))
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn section_row(
|
fn recent_communities(&self, cx: &App) -> Vec<Entity<Community>> {
|
||||||
|
const LIMIT: usize = 3;
|
||||||
|
|
||||||
|
let registry = CommunityRegistry::global(cx);
|
||||||
|
let communities = registry.read(cx).communities();
|
||||||
|
let recent = AppSettings::get_recent_communities(cx);
|
||||||
|
|
||||||
|
let mut rows: Vec<Entity<Community>> = recent
|
||||||
|
.iter()
|
||||||
|
.filter_map(|id| {
|
||||||
|
communities
|
||||||
|
.iter()
|
||||||
|
.find(|community| community.read(cx).id().to_hex() == *id)
|
||||||
|
})
|
||||||
|
.take(LIMIT)
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if rows.is_empty() {
|
||||||
|
rows = communities.iter().take(LIMIT).cloned().collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
rows
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rows_for(&self, tab: SidebarTab, cx: &App) -> Vec<SidebarRow> {
|
||||||
|
match tab {
|
||||||
|
SidebarTab::Recents => {
|
||||||
|
let chat = ChatRegistry::global(cx);
|
||||||
|
let rooms = chat.read(cx).rooms(&RoomKind::Ongoing, cx);
|
||||||
|
let registry = CommunityRegistry::global(cx);
|
||||||
|
let community_count = registry.read(cx).communities().len();
|
||||||
|
let communities = self.recent_communities(cx);
|
||||||
|
|
||||||
|
if communities.is_empty() && rooms.is_empty() {
|
||||||
|
return vec![SidebarRow::Hint {
|
||||||
|
text: "Nothing recent yet".into(),
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rows = Vec::new();
|
||||||
|
|
||||||
|
if !communities.is_empty() {
|
||||||
|
rows.push(SidebarRow::Section {
|
||||||
|
label: "Communities".into(),
|
||||||
|
count: community_count,
|
||||||
|
});
|
||||||
|
rows.extend(
|
||||||
|
communities
|
||||||
|
.into_iter()
|
||||||
|
.map(|community| SidebarRow::Community { community }),
|
||||||
|
);
|
||||||
|
rows.push(SidebarRow::Action {
|
||||||
|
label: "Show all communities".into(),
|
||||||
|
tab: SidebarTab::Communities,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if !rooms.is_empty() {
|
||||||
|
rows.push(SidebarRow::Section {
|
||||||
|
label: "Chats".into(),
|
||||||
|
count: rooms.len(),
|
||||||
|
});
|
||||||
|
rows.extend(
|
||||||
|
rooms
|
||||||
|
.into_iter()
|
||||||
|
.take(5)
|
||||||
|
.map(|room| SidebarRow::Room { room }),
|
||||||
|
);
|
||||||
|
rows.push(SidebarRow::Action {
|
||||||
|
label: "Show all chats".into(),
|
||||||
|
tab: SidebarTab::Chats,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
rows
|
||||||
|
}
|
||||||
|
SidebarTab::Chats => {
|
||||||
|
let chat = ChatRegistry::global(cx);
|
||||||
|
let chat = chat.read(cx);
|
||||||
|
let messages = chat.rooms(&RoomKind::Ongoing, cx);
|
||||||
|
|
||||||
|
let mut rows = vec![SidebarRow::Section {
|
||||||
|
label: "Chats".into(),
|
||||||
|
count: messages.len(),
|
||||||
|
}];
|
||||||
|
|
||||||
|
if messages.is_empty() {
|
||||||
|
rows.push(SidebarRow::Hint {
|
||||||
|
text: "No conversations yet".into(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
rows.extend(messages.into_iter().map(|room| SidebarRow::Room { room }));
|
||||||
|
}
|
||||||
|
|
||||||
|
rows
|
||||||
|
}
|
||||||
|
SidebarTab::Communities => {
|
||||||
|
let registry = CommunityRegistry::global(cx);
|
||||||
|
let communities = registry.read(cx).communities();
|
||||||
|
|
||||||
|
let mut rows = vec![SidebarRow::Section {
|
||||||
|
label: "Communities".into(),
|
||||||
|
count: communities.len(),
|
||||||
|
}];
|
||||||
|
|
||||||
|
if communities.is_empty() {
|
||||||
|
rows.push(SidebarRow::Hint {
|
||||||
|
text: "No communities yet".into(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
rows.extend(
|
||||||
|
communities
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|community| SidebarRow::Community { community }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
rows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_rows(
|
||||||
|
&self,
|
||||||
|
range: Range<usize>,
|
||||||
|
rows: &[SidebarRow],
|
||||||
|
cx: &Context<Sidebar>,
|
||||||
|
) -> Vec<AnyElement> {
|
||||||
|
rows.get(range.clone())
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(offset, row)| {
|
||||||
|
let index = range.start + offset;
|
||||||
|
|
||||||
|
match row {
|
||||||
|
SidebarRow::Section { label, count } => TreeRow::new(
|
||||||
|
ElementId::NamedInteger("tree-row".into(), index as u64),
|
||||||
|
TreeRowKind::Section,
|
||||||
|
label.clone(),
|
||||||
|
)
|
||||||
|
.count(*count)
|
||||||
|
.into_any_element(),
|
||||||
|
SidebarRow::Room { room } => {
|
||||||
|
let name = room.read(cx).display_name(cx);
|
||||||
|
let picture = room.read(cx).display_image(cx);
|
||||||
|
let seed = room.read(cx).display_image_seed(cx);
|
||||||
|
let created_at = room.read(cx).created_at.to_ago();
|
||||||
|
let room_clone = room.clone();
|
||||||
|
|
||||||
|
let handler = cx.listener(move |this, _event, window, cx| {
|
||||||
|
this.open_room(room_clone.clone(), window, cx);
|
||||||
|
});
|
||||||
|
|
||||||
|
TreeRow::new(
|
||||||
|
ElementId::NamedInteger("tree-row".into(), index as u64),
|
||||||
|
TreeRowKind::Room,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
.avatar(seed)
|
||||||
|
.picture(picture)
|
||||||
|
.created_at(created_at)
|
||||||
|
.on_click(handler)
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
SidebarRow::Community { community } => {
|
||||||
|
let name = community.read(cx).name();
|
||||||
|
let seed = community.read(cx).id().to_hex();
|
||||||
|
let picture = community.read(cx).icon();
|
||||||
|
let community = community.clone();
|
||||||
|
|
||||||
|
TreeRow::new(
|
||||||
|
ElementId::NamedInteger("tree-row".into(), index as u64),
|
||||||
|
TreeRowKind::Community,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
.avatar(seed)
|
||||||
|
.picture(picture)
|
||||||
|
.on_click(cx.listener(move |this, _event, window, cx| {
|
||||||
|
this.open_community(community.clone(), window, cx);
|
||||||
|
}))
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
SidebarRow::Action { label, tab } => {
|
||||||
|
let tab = *tab;
|
||||||
|
|
||||||
|
TreeRow::new(
|
||||||
|
ElementId::NamedInteger("tree-row".into(), index as u64),
|
||||||
|
TreeRowKind::Action,
|
||||||
|
label.clone(),
|
||||||
|
)
|
||||||
|
.icon(IconName::ArrowRight)
|
||||||
|
.on_click(cx.listener(move |this, _event, _window, cx| {
|
||||||
|
this.select_tab(tab, cx);
|
||||||
|
}))
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
SidebarRow::Hint { text } => TreeRow::new(
|
||||||
|
ElementId::NamedInteger("tree-row".into(), index as u64),
|
||||||
|
TreeRowKind::Hint,
|
||||||
|
text.clone(),
|
||||||
|
)
|
||||||
|
.into_any_element(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn section_row(
|
||||||
|
&self,
|
||||||
id: &'static str,
|
id: &'static str,
|
||||||
label: &'static str,
|
label: &'static str,
|
||||||
count: usize,
|
count: usize,
|
||||||
open: bool,
|
open: bool,
|
||||||
toggle: impl Fn(&mut Sidebar) + 'static,
|
toggle: impl Fn(&mut Sidebar) + 'static,
|
||||||
cx: &mut Context<Sidebar>,
|
cx: &mut Context<Sidebar>,
|
||||||
) -> AnyElement {
|
) -> AnyElement {
|
||||||
div()
|
div()
|
||||||
.flex_shrink_0()
|
.flex_shrink_0()
|
||||||
.child(
|
.child(
|
||||||
@@ -822,16 +785,17 @@ fn section_row(
|
|||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn channel_row(
|
fn channel_row(
|
||||||
|
&self,
|
||||||
id: ChannelId,
|
id: ChannelId,
|
||||||
name: String,
|
name: String,
|
||||||
private: bool,
|
private: bool,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
community: &Entity<Community>,
|
community: &Entity<Community>,
|
||||||
cx: &mut Context<Sidebar>,
|
cx: &mut Context<Sidebar>,
|
||||||
) -> AnyElement {
|
) -> AnyElement {
|
||||||
let community = community.clone();
|
let community = community.clone();
|
||||||
|
|
||||||
div()
|
div()
|
||||||
@@ -858,9 +822,9 @@ fn channel_row(
|
|||||||
)
|
)
|
||||||
.when(selected, |this| this.bg(cx.theme().ghost_element_active))
|
.when(selected, |this| this.bg(cx.theme().ghost_element_active))
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn member_row(prefix: &str, public_key: PublicKey, cx: &App) -> AnyElement {
|
fn member_row(&self, prefix: &str, public_key: PublicKey, cx: &App) -> AnyElement {
|
||||||
let persons = PersonRegistry::global(cx);
|
let persons = PersonRegistry::global(cx);
|
||||||
let person = persons.read(cx).get(&public_key, cx);
|
let person = persons.read(cx).get(&public_key, cx);
|
||||||
|
|
||||||
@@ -879,4 +843,98 @@ fn member_row(prefix: &str, public_key: PublicKey, cx: &App) -> AnyElement {
|
|||||||
.picture(person.avatar()),
|
.picture(person.avatar()),
|
||||||
)
|
)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Panel for Sidebar {
|
||||||
|
fn panel_id(&self) -> SharedString {
|
||||||
|
"Sidebar".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn title(&self, _cx: &App) -> AnyElement {
|
||||||
|
SharedString::from("Sidebar").into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn closable(&self, _cx: &App) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zoomable(&self, _cx: &App) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventEmitter<PanelEvent> for Sidebar {}
|
||||||
|
|
||||||
|
impl Focusable for Sidebar {
|
||||||
|
fn focus_handle(&self, _: &App) -> gpui::FocusHandle {
|
||||||
|
self.focus_handle.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for Sidebar {
|
||||||
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
let nostr = NostrRegistry::global(cx);
|
||||||
|
let logged_in = { nostr.read(cx).current_user().is_some() };
|
||||||
|
|
||||||
|
let community = self
|
||||||
|
.community
|
||||||
|
.clone()
|
||||||
|
.and_then(|community| community.upgrade());
|
||||||
|
|
||||||
|
v_flex()
|
||||||
|
.image_cache(retain_all("sidebar"))
|
||||||
|
.size_full()
|
||||||
|
.relative()
|
||||||
|
.gap_2()
|
||||||
|
.bg(cx.theme().surface_background)
|
||||||
|
.border_r_1()
|
||||||
|
.border_color(cx.theme().border_variant)
|
||||||
|
.when(!logged_in, |this| {
|
||||||
|
this.relative()
|
||||||
|
.child(title_bar_drag_handlers(
|
||||||
|
div()
|
||||||
|
.id("onboarding-drag")
|
||||||
|
.absolute()
|
||||||
|
.top_0()
|
||||||
|
.left_0()
|
||||||
|
.h(TABBAR_HEIGHT)
|
||||||
|
.w_full(),
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
))
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.size_full()
|
||||||
|
.justify_end()
|
||||||
|
.gap_4()
|
||||||
|
.p_4()
|
||||||
|
.child(
|
||||||
|
v_flex().child(div().font_semibold().child("Coop")).child(
|
||||||
|
div()
|
||||||
|
.text_xs()
|
||||||
|
.text_color(cx.theme().text_muted)
|
||||||
|
.child("TODO"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Button::new("import-identity")
|
||||||
|
.label("Import identity")
|
||||||
|
.primary()
|
||||||
|
.font_semibold()
|
||||||
|
.h_8()
|
||||||
|
.w_full()
|
||||||
|
.on_click(|_, window, cx| {
|
||||||
|
import::open(window, cx);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.child(title_bar_drag_handlers(self.render_user(cx), window, cx))
|
||||||
|
.map(|this| match community {
|
||||||
|
Some(community) => this.child(self.render_community(community, cx)),
|
||||||
|
None => this.child(self.render_tabs(cx)),
|
||||||
|
})
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
use gpui::{App, InteractiveElement, IntoElement, ParentElement, Styled, Window, div, svg};
|
|
||||||
use theme::{ActiveTheme, TABBAR_HEIGHT};
|
|
||||||
use ui::button::{Button, ButtonVariants};
|
|
||||||
use ui::{StyledExt, h_flex, title_bar_drag_handlers, v_flex};
|
|
||||||
|
|
||||||
use crate::dialogs::import;
|
|
||||||
|
|
||||||
const TITLE: &str = "Welcome to Coop!";
|
|
||||||
const DESCRIPTION: &str = "Chat Freely, Stay Private on Nostr.";
|
|
||||||
|
|
||||||
pub(super) fn render(window: &mut Window, cx: &mut App) -> impl IntoElement {
|
|
||||||
v_flex()
|
|
||||||
.size_full()
|
|
||||||
.relative()
|
|
||||||
.bg(cx.theme().surface_background)
|
|
||||||
.child(title_bar_drag_handlers(
|
|
||||||
div()
|
|
||||||
.id("onboarding-drag")
|
|
||||||
.absolute()
|
|
||||||
.top_0()
|
|
||||||
.left_0()
|
|
||||||
.h(TABBAR_HEIGHT)
|
|
||||||
.w_full(),
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
))
|
|
||||||
.child(
|
|
||||||
v_flex()
|
|
||||||
.size_full()
|
|
||||||
.justify_end()
|
|
||||||
.gap_4()
|
|
||||||
.p_4()
|
|
||||||
.child(
|
|
||||||
h_flex()
|
|
||||||
.gap_2()
|
|
||||||
.child(
|
|
||||||
svg()
|
|
||||||
.path("brand/coop.svg")
|
|
||||||
.size_8()
|
|
||||||
.text_color(cx.theme().icon_muted),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
v_flex().child(div().font_semibold().child(TITLE)).child(
|
|
||||||
div()
|
|
||||||
.text_xs()
|
|
||||||
.text_color(cx.theme().text_muted)
|
|
||||||
.child(DESCRIPTION),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
v_flex()
|
|
||||||
.gap_2()
|
|
||||||
.w_full()
|
|
||||||
.child(
|
|
||||||
Button::new("join-now")
|
|
||||||
.label("Join now")
|
|
||||||
.primary()
|
|
||||||
.font_semibold()
|
|
||||||
.h_8()
|
|
||||||
.w_full(),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
Button::new("import-identity")
|
|
||||||
.label("Import identity")
|
|
||||||
.secondary()
|
|
||||||
.font_semibold()
|
|
||||||
.h_8()
|
|
||||||
.w_full()
|
|
||||||
.on_click(|_event, window, cx| import::open(window, cx)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user