forked from trinitrix/core
Compare commits
3 Commits
6aa8050b10
...
50d7948a2d
Author | SHA1 | Date |
---|---|---|
Benedikt Peetz | 50d7948a2d | |
Benedikt Peetz | 5e04ab49ee | |
Benedikt Peetz | 2905a0830a |
|
@ -4,9 +4,9 @@ version = 3
|
|||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.19.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
|
||||
checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
@ -138,20 +138,20 @@ version = "0.3.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.68"
|
||||
version = "0.1.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
|
||||
checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -191,9 +191,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.67"
|
||||
version = "0.3.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
|
||||
checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
|
@ -230,9 +230,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "729b71f35bd3fa1a4c86b85d32c8b9069ea7fe14f7a53cfabb65f62d4265b888"
|
||||
checksum = "199c42ab6972d92c9f8995f086273d25c42fc0f7b2a1fcefba465c1352d25ba5"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
|
@ -402,9 +402,9 @@ checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3"
|
|||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.2.6"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6"
|
||||
checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
|
@ -424,9 +424,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
|||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.8"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c"
|
||||
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
@ -538,7 +538,7 @@ checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
|
|||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"strsim",
|
||||
"syn 1.0.109",
|
||||
|
@ -593,7 +593,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
@ -640,9 +640,9 @@ version = "0.2.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -699,7 +699,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
|||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -839,9 +839,9 @@ version = "0.3.28"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -987,18 +987,9 @@ checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
|
||||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
|
@ -1191,9 +1182,9 @@ version = "1.0.11"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
||||
dependencies = [
|
||||
"hermit-abi 0.3.1",
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1213,9 +1204,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.6"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||
checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
|
@ -1495,9 +1486,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
|||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.6.2"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
@ -1511,7 +1502,7 @@ dependencies = [
|
|||
"libc",
|
||||
"log",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1543,19 +1534,19 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.15.0"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi 0.2.6",
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.30.4"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385"
|
||||
checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -1593,9 +1584,9 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1695,29 +1686,29 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
|||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.0"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead"
|
||||
checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.1.0"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07"
|
||||
checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
|
@ -1779,9 +1770,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.63"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
|
||||
checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
@ -1813,7 +1804,7 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
@ -1833,7 +1824,7 @@ version = "1.0.29"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2042,9 +2033,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.8.4"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
|
||||
checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -2053,9 +2056,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
|
||||
checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
|
@ -2185,7 +2188,7 @@ checksum = "0f82e91eb61cd86d9287303133ee55b54618eccb75a522cc22a42c15f5bda340"
|
|||
dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro-crate",
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"ruma-identifiers-validation",
|
||||
"serde",
|
||||
|
@ -2201,31 +2204,31 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.37.20"
|
||||
version = "0.37.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0"
|
||||
checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.13"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
||||
checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9"
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.21"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
|
||||
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
|
||||
dependencies = [
|
||||
"windows-sys 0.42.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2259,38 +2262,38 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.164"
|
||||
version = "1.0.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
|
||||
checksum = "bd51c3db8f9500d531e6c12dd0fd4ad13d133e9117f5aebac3cdbb8b6d9824b0"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_bytes"
|
||||
version = "0.11.9"
|
||||
version = "0.11.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294"
|
||||
checksum = "5a16be4fe5320ade08736447e3198294a5ea9a6d44dde6f35f0a5e06859c427a"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.164"
|
||||
version = "1.0.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
|
||||
checksum = "27738cfea0d944ab72c3ed01f3d5f23ec4322af8a1431e40ce630e4c01ea74fd"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.99"
|
||||
version = "1.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
|
||||
checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -2396,9 +2399,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
|
@ -2448,18 +2451,18 @@ version = "1.0.109"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.22"
|
||||
version = "2.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
|
||||
checksum = "36ccaf716a23c35ff908f91c971a86a9a71af5998c1d8f10e828d9f55f68ac00"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
@ -2475,27 +2478,27 @@ dependencies = [
|
|||
"fastrand",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.40"
|
||||
version = "1.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
|
||||
checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.40"
|
||||
version = "1.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
||||
checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2526,9 +2529,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.29.0"
|
||||
version = "1.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "374442f06ee49c3a28a8fc9f01a2596fed7559c6b99b31279c3261778e77d84f"
|
||||
checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"backtrace",
|
||||
|
@ -2539,7 +2542,7 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2548,9 +2551,9 @@ version = "2.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2594,9 +2597,9 @@ checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
|
|||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.11"
|
||||
version = "0.19.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7"
|
||||
checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78"
|
||||
dependencies = [
|
||||
"indexmap 2.0.0",
|
||||
"toml_datetime",
|
||||
|
@ -2627,9 +2630,9 @@ version = "0.1.26"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2648,7 +2651,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"cli-log",
|
||||
"crossterm",
|
||||
"indexmap 1.9.3",
|
||||
"indexmap 2.0.0",
|
||||
"matrix-sdk",
|
||||
"serde",
|
||||
"tokio",
|
||||
|
@ -2700,9 +2703,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
|
@ -2865,9 +2868,9 @@ dependencies = [
|
|||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.24",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -2899,9 +2902,9 @@ version = "0.2.87"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.24",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
@ -2974,21 +2977,6 @@ dependencies = [
|
|||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
|
@ -3004,93 +2992,51 @@ version = "0.48.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.0",
|
||||
"windows_aarch64_msvc 0.48.0",
|
||||
"windows_i686_gnu 0.48.0",
|
||||
"windows_i686_msvc 0.48.0",
|
||||
"windows_x86_64_gnu 0.48.0",
|
||||
"windows_x86_64_gnullvm 0.48.0",
|
||||
"windows_x86_64_msvc 0.48.0",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.0"
|
||||
|
@ -3099,9 +3045,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
|||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.4.7"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448"
|
||||
checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -3142,7 +3088,7 @@ version = "1.4.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"proc-macro2 1.0.64",
|
||||
"quote 1.0.29",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.24",
|
||||
]
|
||||
|
|
|
@ -8,12 +8,12 @@ license = "MIT"
|
|||
|
||||
[dependencies]
|
||||
tui = "0.19"
|
||||
tui-textarea = { version = "*" }
|
||||
crossterm = "*"
|
||||
tui-textarea = { version = "0.2", features = ["crossterm"] }
|
||||
crossterm = "0.25"
|
||||
matrix-sdk = "0.6"
|
||||
anyhow = "1.0"
|
||||
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
|
||||
tokio = { version = "1.29", features = ["macros", "rt-multi-thread"] }
|
||||
tokio-util = "0.7"
|
||||
serde = "1.0"
|
||||
cli-log = "2.0"
|
||||
indexmap = "*"
|
||||
indexmap = "2.0.0"
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
use std::fs;
|
||||
use matrix_sdk::{Client,
|
||||
config::SyncSettings,
|
||||
ruma::{user_id,
|
||||
events::room::message::SyncRoomMessageEvent,
|
||||
exports::serde_json},
|
||||
Session};
|
||||
use anyhow::{Error, Result};
|
||||
use cli_log::{error, info, warn};
|
||||
use matrix_sdk::{
|
||||
config::SyncSettings,
|
||||
ruma::{events::room::message::SyncRoomMessageEvent, exports::serde_json, user_id},
|
||||
Client, Session,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use cli_log::{error, warn, info};
|
||||
use std::fs;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Account {
|
||||
|
@ -33,7 +32,7 @@ pub struct AccountsManager {
|
|||
}
|
||||
|
||||
impl Account {
|
||||
pub fn name (&self) -> &String {
|
||||
pub fn name(&self) -> &String {
|
||||
&self.name
|
||||
}
|
||||
|
||||
|
@ -43,11 +42,12 @@ impl Account {
|
|||
}
|
||||
|
||||
impl AccountsManager {
|
||||
pub fn new(config:Option<String>) -> Self {
|
||||
pub fn new(config: Option<String>) -> Self {
|
||||
return match config {
|
||||
Some(s) => {
|
||||
info!("Loading serialized AccountsManager");
|
||||
let accounts_data:AccountsData = serde_json::from_str(&s).expect("failed to deserialize json");
|
||||
let accounts_data: AccountsData =
|
||||
serde_json::from_str(&s).expect("failed to deserialize json");
|
||||
let mut clients = Vec::new();
|
||||
clients.resize(accounts_data.accounts.len(), None);
|
||||
Self {
|
||||
|
@ -56,7 +56,7 @@ impl AccountsManager {
|
|||
accounts: accounts_data.accounts,
|
||||
clients,
|
||||
}
|
||||
},
|
||||
}
|
||||
None => {
|
||||
info!("Creating empty AccountsManager");
|
||||
Self {
|
||||
|
@ -66,7 +66,7 @@ impl AccountsManager {
|
|||
clients: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub async fn restore(&mut self) -> Result<()> {
|
||||
|
@ -74,7 +74,12 @@ impl AccountsManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn add(&mut self, homeserver: &String, username: &String, password: &String) -> Result<u32> {
|
||||
pub async fn add(
|
||||
&mut self,
|
||||
homeserver: &String,
|
||||
username: &String,
|
||||
password: &String,
|
||||
) -> Result<u32> {
|
||||
let id = self.num_accounts;
|
||||
self.num_accounts += 1;
|
||||
|
||||
|
@ -84,7 +89,8 @@ impl AccountsManager {
|
|||
.build()
|
||||
.await?;
|
||||
|
||||
client.login_username(username, password)
|
||||
client
|
||||
.login_username(username, password)
|
||||
.initial_device_display_name("Trinitrix")
|
||||
.send()
|
||||
.await?;
|
||||
|
@ -94,9 +100,13 @@ impl AccountsManager {
|
|||
let account = Account {
|
||||
homeserver: homeserver.to_string(),
|
||||
id,
|
||||
name: client.account().get_display_name().await?.expect("failed to fetch display name"),
|
||||
name: client
|
||||
.account()
|
||||
.get_display_name()
|
||||
.await?
|
||||
.expect("failed to fetch display name"),
|
||||
session: session.clone(),
|
||||
sync_token: None
|
||||
sync_token: None,
|
||||
};
|
||||
|
||||
self.logout().await?;
|
||||
|
@ -105,12 +115,16 @@ impl AccountsManager {
|
|||
self.clients.push(Some(client));
|
||||
self.save()?;
|
||||
|
||||
info!("Logged in as '{}' device ID: {}", session.user_id.to_string(), session.device_id.to_string());
|
||||
info!(
|
||||
"Logged in as '{}' device ID: {}",
|
||||
session.user_id.to_string(),
|
||||
session.device_id.to_string()
|
||||
);
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub async fn login(&mut self, account_id:u32) -> Result<()> {
|
||||
pub async fn login(&mut self, account_id: u32) -> Result<()> {
|
||||
self.logout().await?; // log out the current account
|
||||
|
||||
let account = if account_id >= self.num_accounts {
|
||||
|
@ -120,17 +134,28 @@ impl AccountsManager {
|
|||
self.get(account_id).expect("Account lookup failed")
|
||||
};
|
||||
|
||||
if self.clients.get(account_id as usize).expect("client lookup failed").is_none() {
|
||||
info!("No client cached for account: '{}' -> requesting a new one", &account.session.user_id);
|
||||
if self
|
||||
.clients
|
||||
.get(account_id as usize)
|
||||
.expect("client lookup failed")
|
||||
.is_none()
|
||||
{
|
||||
info!(
|
||||
"No client cached for account: '{}' -> requesting a new one",
|
||||
&account.session.user_id
|
||||
);
|
||||
let client = Client::builder()
|
||||
.homeserver_url(&account.homeserver)
|
||||
.sled_store(format!("userdata/{account_id}"), Some("supersecure")) ?
|
||||
.sled_store(format!("userdata/{account_id}"), Some("supersecure"))?
|
||||
.build()
|
||||
.await?;
|
||||
client.restore_login(account.session.clone()).await?;
|
||||
self.clients.insert(account_id as usize, Some(client));
|
||||
} else {
|
||||
info!("Using cached client for account: '{}'", &account.session.user_id);
|
||||
info!(
|
||||
"Using cached client for account: '{}'",
|
||||
&account.session.user_id
|
||||
);
|
||||
};
|
||||
|
||||
info!("Restored account");
|
||||
|
@ -156,7 +181,7 @@ impl AccountsManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn save(&self) -> Result<()>{
|
||||
pub fn save(&self) -> Result<()> {
|
||||
let accounts_data = AccountsData {
|
||||
current_account: self.current_account,
|
||||
accounts: self.accounts.clone(),
|
||||
|
@ -188,5 +213,7 @@ impl AccountsManager {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn num_accounts(&self) -> u32 { self.num_accounts }
|
||||
pub fn num_accounts(&self) -> u32 {
|
||||
self.num_accounts
|
||||
}
|
||||
}
|
322
src/app/event.rs
322
src/app/event.rs
|
@ -1,14 +1,22 @@
|
|||
use crate::app::{App, status::{Status, State}};
|
||||
use crate::app::{
|
||||
status::{State, Status},
|
||||
App,
|
||||
};
|
||||
use crate::ui;
|
||||
use anyhow::{Error, Result};
|
||||
use cli_log::{error, info, warn};
|
||||
use matrix_sdk::{
|
||||
config::SyncSettings,
|
||||
room::Room,
|
||||
ruma::events::room::{
|
||||
member::StrippedRoomMemberEvent,
|
||||
message::{MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent},
|
||||
},
|
||||
Client, LoopCtrl,
|
||||
};
|
||||
use tokio::sync::{broadcast, mpsc};
|
||||
use tokio::time::Duration;
|
||||
use tokio::sync::{mpsc, broadcast};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use anyhow::{Result, Error};
|
||||
use matrix_sdk::{Client, room::{Room}, config::SyncSettings, ruma::events::room::{
|
||||
member::StrippedRoomMemberEvent,
|
||||
message::{MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent},
|
||||
}, LoopCtrl};
|
||||
use cli_log::{error, warn, info};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EventStatus {
|
||||
|
@ -20,7 +28,7 @@ pub enum EventStatus {
|
|||
#[derive(Debug)]
|
||||
pub struct Event {
|
||||
input_event: Option<crossterm::event::Event>,
|
||||
matrix_event: Option<matrix_sdk::deserialized_responses::SyncResponse>
|
||||
matrix_event: Option<matrix_sdk::deserialized_responses::SyncResponse>,
|
||||
}
|
||||
|
||||
pub struct EventBuilder {
|
||||
|
@ -42,7 +50,6 @@ impl Default for EventBuilder {
|
|||
event: Event::default(),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl EventBuilder {
|
||||
|
@ -51,7 +58,10 @@ impl EventBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
fn matrix_event(&mut self, matrix_event: matrix_sdk::deserialized_responses::SyncResponse) -> &Self {
|
||||
fn matrix_event(
|
||||
&mut self,
|
||||
matrix_event: matrix_sdk::deserialized_responses::SyncResponse,
|
||||
) -> &Self {
|
||||
self.event.matrix_event = Some(matrix_event);
|
||||
self
|
||||
}
|
||||
|
@ -66,7 +76,6 @@ impl EventBuilder {
|
|||
|
||||
impl Event {
|
||||
pub async fn handle(&self, app: &mut App<'_>) -> Result<EventStatus> {
|
||||
|
||||
if self.matrix_event.is_some() {
|
||||
return self.handle_matrix(app).await;
|
||||
}
|
||||
|
@ -88,7 +97,11 @@ impl Event {
|
|||
None => continue,
|
||||
};
|
||||
for m_event in m_room.timeline.events.clone() {
|
||||
let event = m_event.event.deserialize().unwrap().into_full_event(m_room_id.clone());
|
||||
let event = m_event
|
||||
.event
|
||||
.deserialize()
|
||||
.unwrap()
|
||||
.into_full_event(m_room_id.clone());
|
||||
room.timeline_add(event);
|
||||
}
|
||||
}
|
||||
|
@ -99,99 +112,125 @@ impl Event {
|
|||
async fn handle_main(&self, app: &mut App<'_>) -> Result<EventStatus> {
|
||||
if self.input_event.is_some() {
|
||||
match tui_textarea::Input::from(self.input_event.clone().unwrap()) {
|
||||
tui_textarea::Input { key: tui_textarea::Key::Esc, .. } => return Ok(EventStatus::Terminate),
|
||||
tui_textarea::Input {
|
||||
key: tui_textarea::Key::Esc,
|
||||
..
|
||||
} => return Ok(EventStatus::Terminate),
|
||||
tui_textarea::Input {
|
||||
key: tui_textarea::Key::Tab,
|
||||
..
|
||||
} => {
|
||||
app.ui.cycle_main_input_position();
|
||||
}
|
||||
input => {
|
||||
match app.ui.input_position() {
|
||||
ui::MainInputPosition::MessageCompose => {
|
||||
match input {
|
||||
tui_textarea::Input {key: tui_textarea::Key::Enter, alt: true, ..} => {
|
||||
match app.status.room_mut() {
|
||||
Some(room) => {
|
||||
room.send(app.ui.message_compose.lines().join("\n")).await?;
|
||||
app.ui.message_compose_clear();
|
||||
},
|
||||
None => ()
|
||||
};
|
||||
}
|
||||
_ => { app.ui.message_compose.input(input); }
|
||||
};
|
||||
},
|
||||
ui::MainInputPosition::Rooms => {
|
||||
match input {
|
||||
tui_textarea::Input {key: tui_textarea::Key::Up, ..} => {
|
||||
let i = match app.ui.rooms_state.selected() {
|
||||
Some(i) => {
|
||||
if i > 0 { i - 1 }
|
||||
else { i }
|
||||
},
|
||||
None => 0,
|
||||
};
|
||||
app.ui.rooms_state.select(Some(i));
|
||||
app.status.set_room_by_index(i)?;
|
||||
},
|
||||
tui_textarea::Input {key: tui_textarea::Key::Down, ..} => {
|
||||
let i = match app.ui.rooms_state.selected() {
|
||||
Some(i) => {
|
||||
if i < app.status.rooms().len() { i + 1 }
|
||||
else { i }
|
||||
},
|
||||
None => 0,
|
||||
};
|
||||
app.ui.rooms_state.select(Some(i));
|
||||
app.status.set_room_by_index(i)?;
|
||||
},
|
||||
_ => ()
|
||||
};
|
||||
},
|
||||
ui::MainInputPosition::Messages => {
|
||||
match input {
|
||||
tui_textarea::Input {key: tui_textarea::Key::Up, ..} => {
|
||||
match app.status.room_mut(){
|
||||
Some(room) => {
|
||||
let len = room.timeline().len();
|
||||
let i = match room.view_scroll() {
|
||||
Some(i) => i+1,
|
||||
None => 0,
|
||||
};
|
||||
if i < len {
|
||||
room.set_view_scroll(Some(i))
|
||||
}
|
||||
if i <= len - 5 {
|
||||
room.poll_old_timeline().await?;
|
||||
}
|
||||
},
|
||||
None => (),
|
||||
};
|
||||
},
|
||||
tui_textarea::Input {key: tui_textarea::Key::Down, ..} => {
|
||||
match app.status.room_mut(){
|
||||
Some(room) => {
|
||||
match room.view_scroll() {
|
||||
Some(i) => {
|
||||
if i == 0 {
|
||||
room.set_view_scroll(None);
|
||||
} else {
|
||||
room.set_view_scroll(Some(i - 1));
|
||||
}
|
||||
}
|
||||
None => (),
|
||||
};
|
||||
},
|
||||
None => (),
|
||||
};
|
||||
},
|
||||
_ => ()
|
||||
};
|
||||
},
|
||||
_ => (),
|
||||
input => match app.ui.input_position() {
|
||||
ui::MainInputPosition::MessageCompose => {
|
||||
match input {
|
||||
tui_textarea::Input {
|
||||
key: tui_textarea::Key::Enter,
|
||||
alt: true,
|
||||
..
|
||||
} => {
|
||||
match app.status.room_mut() {
|
||||
Some(room) => {
|
||||
room.send(app.ui.message_compose.lines().join("\n"))
|
||||
.await?;
|
||||
app.ui.message_compose_clear();
|
||||
}
|
||||
None => (),
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
app.ui.message_compose.input(input);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
ui::MainInputPosition::Rooms => {
|
||||
match input {
|
||||
tui_textarea::Input {
|
||||
key: tui_textarea::Key::Up,
|
||||
..
|
||||
} => {
|
||||
let i = match app.ui.rooms_state.selected() {
|
||||
Some(i) => {
|
||||
if i > 0 {
|
||||
i - 1
|
||||
} else {
|
||||
i
|
||||
}
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
app.ui.rooms_state.select(Some(i));
|
||||
app.status.set_room_by_index(i)?;
|
||||
}
|
||||
tui_textarea::Input {
|
||||
key: tui_textarea::Key::Down,
|
||||
..
|
||||
} => {
|
||||
let i = match app.ui.rooms_state.selected() {
|
||||
Some(i) => {
|
||||
if i < app.status.rooms().len() {
|
||||
i + 1
|
||||
} else {
|
||||
i
|
||||
}
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
app.ui.rooms_state.select(Some(i));
|
||||
app.status.set_room_by_index(i)?;
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
ui::MainInputPosition::Messages => {
|
||||
match input {
|
||||
tui_textarea::Input {
|
||||
key: tui_textarea::Key::Up,
|
||||
..
|
||||
} => {
|
||||
match app.status.room_mut() {
|
||||
Some(room) => {
|
||||
let len = room.timeline().len();
|
||||
let i = match room.view_scroll() {
|
||||
Some(i) => i + 1,
|
||||
None => 0,
|
||||
};
|
||||
if i < len {
|
||||
room.set_view_scroll(Some(i))
|
||||
}
|
||||
if i <= len - 5 {
|
||||
room.poll_old_timeline().await?;
|
||||
}
|
||||
}
|
||||
None => (),
|
||||
};
|
||||
}
|
||||
tui_textarea::Input {
|
||||
key: tui_textarea::Key::Down,
|
||||
..
|
||||
} => {
|
||||
match app.status.room_mut() {
|
||||
Some(room) => {
|
||||
match room.view_scroll() {
|
||||
Some(i) => {
|
||||
if i == 0 {
|
||||
room.set_view_scroll(None);
|
||||
} else {
|
||||
room.set_view_scroll(Some(i - 1));
|
||||
}
|
||||
}
|
||||
None => (),
|
||||
};
|
||||
}
|
||||
None => (),
|
||||
};
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
};
|
||||
}
|
||||
Ok(EventStatus::Ok)
|
||||
|
@ -200,18 +239,21 @@ impl Event {
|
|||
async fn handle_setup(&self, app: &mut App<'_>) -> Result<EventStatus> {
|
||||
let ui = match &mut app.ui.setup_ui {
|
||||
Some(ui) => ui,
|
||||
None => return Err(Error::msg("SetupUI instance not found"))
|
||||
None => return Err(Error::msg("SetupUI instance not found")),
|
||||
};
|
||||
|
||||
if self.input_event.is_some() {
|
||||
match tui_textarea::Input::from(self.input_event.clone().unwrap()) {
|
||||
tui_textarea::Input { key: tui_textarea::Key::Esc, .. } => return Ok(EventStatus::Terminate),
|
||||
tui_textarea::Input {
|
||||
key: tui_textarea::Key::Esc,
|
||||
..
|
||||
} => return Ok(EventStatus::Terminate),
|
||||
tui_textarea::Input {
|
||||
key: tui_textarea::Key::Tab,
|
||||
..
|
||||
} => {
|
||||
ui.cycle_input_position();
|
||||
},
|
||||
}
|
||||
tui_textarea::Input {
|
||||
key: tui_textarea::Key::Enter,
|
||||
..
|
||||
|
@ -225,33 +267,40 @@ impl Event {
|
|||
if login.is_ok() {
|
||||
return Ok(EventStatus::Finished);
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => ui.cycle_input_position(),
|
||||
};
|
||||
},
|
||||
input => {
|
||||
match ui.input_position() {
|
||||
ui::SetupInputPosition::Homeserver => { ui.homeserver.input(input); },
|
||||
ui::SetupInputPosition::Username => { ui.username.input(input); },
|
||||
ui::SetupInputPosition::Password => {
|
||||
ui.password_data.input(input.clone());
|
||||
match input.key {
|
||||
tui_textarea::Key::Char(_) => {
|
||||
ui.password.input(tui_textarea::Input { key: tui_textarea::Key::Char('*'), ctrl: false, alt: false });
|
||||
},
|
||||
_ => { ui.password.input(input); },
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
input => match ui.input_position() {
|
||||
ui::SetupInputPosition::Homeserver => {
|
||||
ui.homeserver.input(input);
|
||||
}
|
||||
ui::SetupInputPosition::Username => {
|
||||
ui.username.input(input);
|
||||
}
|
||||
ui::SetupInputPosition::Password => {
|
||||
ui.password_data.input(input.clone());
|
||||
match input.key {
|
||||
tui_textarea::Key::Char(_) => {
|
||||
ui.password.input(tui_textarea::Input {
|
||||
key: tui_textarea::Key::Char('*'),
|
||||
ctrl: false,
|
||||
alt: false,
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
ui.password.input(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
};
|
||||
}
|
||||
Ok(EventStatus::Ok)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async fn poll_input_events_stage_2(channel: mpsc::Sender<Event>) -> Result<()> {
|
||||
loop {
|
||||
if crossterm::event::poll(Duration::from_millis(100))? {
|
||||
|
@ -266,7 +315,10 @@ async fn poll_input_events_stage_2(channel: mpsc::Sender<Event>) -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn poll_input_events(channel: mpsc::Sender<Event>, kill: CancellationToken) -> Result<()> {
|
||||
pub async fn poll_input_events(
|
||||
channel: mpsc::Sender<Event>,
|
||||
kill: CancellationToken,
|
||||
) -> Result<()> {
|
||||
tokio::select! {
|
||||
output = poll_input_events_stage_2(channel) => output,
|
||||
_ = kill.cancelled() => Err(Error::msg("received kill signal"))
|
||||
|
@ -275,26 +327,30 @@ pub async fn poll_input_events(channel: mpsc::Sender<Event>, kill: CancellationT
|
|||
|
||||
async fn poll_matrix_events_stage_2(channel: mpsc::Sender<Event>, client: Client) -> Result<()> {
|
||||
let sync_settings = SyncSettings::default();
|
||||
// .token(sync_token)
|
||||
// .timeout(Duration::from_secs(30));
|
||||
// .token(sync_token)
|
||||
// .timeout(Duration::from_secs(30));
|
||||
|
||||
let tx = &channel;
|
||||
|
||||
client.sync_with_callback(sync_settings, |response| async move {
|
||||
let event = EventBuilder::default()
|
||||
.matrix_event(response)
|
||||
.build();
|
||||
client
|
||||
.sync_with_callback(sync_settings, |response| async move {
|
||||
let event = EventBuilder::default().matrix_event(response).build();
|
||||
|
||||
match tx.send(event).await {
|
||||
Ok(_) => LoopCtrl::Continue,
|
||||
Err(_) => LoopCtrl::Break,
|
||||
}
|
||||
}).await?;
|
||||
match tx.send(event).await {
|
||||
Ok(_) => LoopCtrl::Continue,
|
||||
Err(_) => LoopCtrl::Break,
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn poll_matrix_events(channel: mpsc::Sender<Event>, kill: CancellationToken, client: Client) -> Result<()> {
|
||||
pub async fn poll_matrix_events(
|
||||
channel: mpsc::Sender<Event>,
|
||||
kill: CancellationToken,
|
||||
client: Client,
|
||||
) -> Result<()> {
|
||||
tokio::select! {
|
||||
output = poll_matrix_events_stage_2(channel, client) => output,
|
||||
_ = kill.cancelled() => Err(Error::msg("received kill signal")),
|
||||
|
|
|
@ -4,24 +4,27 @@ pub mod status;
|
|||
use crate::accounts;
|
||||
use crate::ui;
|
||||
|
||||
use std::path::Path;
|
||||
use matrix_sdk::{Client,
|
||||
room::{Room},
|
||||
config::SyncSettings,
|
||||
ruma::events::room::{
|
||||
member::StrippedRoomMemberEvent,
|
||||
message::{MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent},
|
||||
},
|
||||
event_handler::Ctx
|
||||
};
|
||||
use accounts::Account;
|
||||
use accounts::AccountsManager;
|
||||
use anyhow::{Result, Error};
|
||||
use cli_log::{error, warn, info};
|
||||
use tokio::{time::{sleep, Duration}, sync::{mpsc, broadcast}};
|
||||
use anyhow::{Error, Result};
|
||||
use cli_log::{error, info, warn};
|
||||
use matrix_sdk::{
|
||||
config::SyncSettings,
|
||||
event_handler::Ctx,
|
||||
room::Room,
|
||||
ruma::events::room::{
|
||||
member::StrippedRoomMemberEvent,
|
||||
message::{MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent},
|
||||
},
|
||||
Client,
|
||||
};
|
||||
use status::{State, Status};
|
||||
use std::path::Path;
|
||||
use tokio::{
|
||||
sync::{broadcast, mpsc},
|
||||
time::{sleep, Duration},
|
||||
};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use status::{Status, State};
|
||||
|
||||
|
||||
pub struct App<'a> {
|
||||
ui: ui::UI<'a>,
|
||||
|
@ -35,14 +38,12 @@ pub struct App<'a> {
|
|||
}
|
||||
|
||||
impl Drop for App<'_> {
|
||||
fn drop(&mut self) {
|
||||
|
||||
}
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
|
||||
impl App<'_> {
|
||||
pub fn new() -> Self {
|
||||
let path:&std::path::Path = Path::new("userdata/accounts.json");
|
||||
let path: &std::path::Path = Path::new("userdata/accounts.json");
|
||||
let config = if path.exists() {
|
||||
info!("Reading account config (userdata/accounts.json)");
|
||||
Some(std::fs::read_to_string(path).expect("failed to read accounts config"))
|
||||
|
@ -65,9 +66,11 @@ impl App<'_> {
|
|||
}
|
||||
|
||||
pub async fn run(&mut self) -> Result<()> {
|
||||
|
||||
// Spawn input event listener
|
||||
tokio::task::spawn(event::poll_input_events(self.channel_tx.clone(), self.input_listener_killer.clone()));
|
||||
tokio::task::spawn(event::poll_input_events(
|
||||
self.channel_tx.clone(),
|
||||
self.input_listener_killer.clone(),
|
||||
));
|
||||
|
||||
if self.account().is_err() {
|
||||
info!("No saved sessions found -> jumping into setup");
|
||||
|
@ -77,14 +80,13 @@ impl App<'_> {
|
|||
self.init_account().await?;
|
||||
}
|
||||
|
||||
|
||||
loop {
|
||||
self.status.set_state(State::Main);
|
||||
self.ui.update(&self.status).await?;
|
||||
|
||||
let event: event::Event = match self.channel_rx.recv().await {
|
||||
Some(e) => e,
|
||||
None => return Err(Error::msg("Event channel has no senders"))
|
||||
None => return Err(Error::msg("Event channel has no senders")),
|
||||
};
|
||||
|
||||
match event.handle(self).await? {
|
||||
|
@ -107,7 +109,7 @@ impl App<'_> {
|
|||
|
||||
let event: event::Event = match self.channel_rx.recv().await {
|
||||
Some(e) => e,
|
||||
None => return Err(Error::msg("Event channel has no senders"))
|
||||
None => return Err(Error::msg("Event channel has no senders")),
|
||||
};
|
||||
|
||||
match event.handle(self).await? {
|
||||
|
@ -121,14 +123,19 @@ impl App<'_> {
|
|||
pub async fn init_account(&mut self) -> Result<()> {
|
||||
let client = match self.client() {
|
||||
Some(c) => c,
|
||||
None => return Err(Error::msg("failed to get current client"))
|
||||
}.clone();
|
||||
None => return Err(Error::msg("failed to get current client")),
|
||||
}
|
||||
.clone();
|
||||
|
||||
self.matrix_listener_killer.cancel();
|
||||
self.matrix_listener_killer = CancellationToken::new();
|
||||
|
||||
// Spawn Matrix Event Listener
|
||||
tokio::task::spawn(event::poll_matrix_events(self.channel_tx.clone(), self.matrix_listener_killer.clone(), client.clone()));
|
||||
tokio::task::spawn(event::poll_matrix_events(
|
||||
self.channel_tx.clone(),
|
||||
self.matrix_listener_killer.clone(),
|
||||
client.clone(),
|
||||
));
|
||||
|
||||
// Reset Status
|
||||
self.status = Status::new(Some(client));
|
||||
|
@ -139,10 +146,11 @@ impl App<'_> {
|
|||
self.status.set_account_name(name);
|
||||
self.status.set_account_user_id(user_id);
|
||||
|
||||
|
||||
for (_, room) in self.status.rooms_mut() {
|
||||
room.update_name().await?;
|
||||
for _ in 0..3 { room.poll_old_timeline().await?; }
|
||||
for _ in 0..3 {
|
||||
room.poll_old_timeline().await?;
|
||||
}
|
||||
}
|
||||
|
||||
info!("Initializing client for the current account");
|
||||
|
@ -151,12 +159,18 @@ impl App<'_> {
|
|||
}
|
||||
|
||||
pub async fn switch_account(&mut self, account_id: u32) -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn login(&mut self, homeserver: &String, username: &String, password: &String) -> Result<()> {
|
||||
self.accounts_manager.add(homeserver, username, password).await?;
|
||||
pub async fn login(
|
||||
&mut self,
|
||||
homeserver: &String,
|
||||
username: &String,
|
||||
password: &String,
|
||||
) -> Result<()> {
|
||||
self.accounts_manager
|
||||
.add(homeserver, username, password)
|
||||
.await?;
|
||||
self.init_account().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -165,7 +179,7 @@ impl App<'_> {
|
|||
let account = self.accounts_manager.current();
|
||||
match account {
|
||||
None => Err(Error::msg("failed to resolve current account")),
|
||||
Some(a) => Ok(a)
|
||||
Some(a) => Ok(a),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
use std::any::Any;
|
||||
use anyhow::{Error, Result};
|
||||
use cli_log::{error, info, warn};
|
||||
use indexmap::IndexMap;
|
||||
use matrix_sdk::{Client,
|
||||
ruma::{events::{AnyTimelineEvent,
|
||||
room::message::RoomMessageEventContent,
|
||||
StateEventType},
|
||||
RoomId,
|
||||
TransactionId},
|
||||
room::MessagesOptions};
|
||||
use anyhow::{Result, Error};
|
||||
use cli_log::{error, warn, info};
|
||||
use matrix_sdk::{
|
||||
room::MessagesOptions,
|
||||
ruma::{
|
||||
events::{room::message::RoomMessageEventContent, AnyTimelineEvent, StateEventType},
|
||||
RoomId, TransactionId,
|
||||
},
|
||||
Client,
|
||||
};
|
||||
use std::any::Any;
|
||||
|
||||
pub enum State {
|
||||
None,
|
||||
|
@ -36,7 +37,7 @@ pub struct Status {
|
|||
}
|
||||
|
||||
impl Room {
|
||||
pub fn new (matrix_room: matrix_sdk::room::Joined) -> Self {
|
||||
pub fn new(matrix_room: matrix_sdk::room::Joined) -> Self {
|
||||
Self {
|
||||
matrix_room,
|
||||
name: "".to_string(),
|
||||
|
@ -50,26 +51,29 @@ impl Room {
|
|||
pub async fn poll_old_timeline(&mut self) -> Result<()> {
|
||||
if let Some(AnyTimelineEvent::State(event)) = &self.timeline.get(0) {
|
||||
if event.event_type() == StateEventType::RoomCreate {
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let mut messages_options = MessagesOptions::backward();
|
||||
messages_options = match &self.timeline_end {
|
||||
Some(end) => messages_options.from(end.as_str()),
|
||||
None => messages_options
|
||||
None => messages_options,
|
||||
};
|
||||
let events = self.matrix_room.messages(messages_options).await?;
|
||||
self.timeline_end = events.end;
|
||||
|
||||
for event in events.chunk.iter() {
|
||||
self.timeline.insert(0, match event.event.deserialize() {
|
||||
Ok(ev) => ev,
|
||||
Err(err) => {
|
||||
warn!("Failed to deserialize timeline event - {err}");
|
||||
continue;
|
||||
}
|
||||
});
|
||||
self.timeline.insert(
|
||||
0,
|
||||
match event.event.deserialize() {
|
||||
Ok(ev) => ev,
|
||||
Err(err) => {
|
||||
warn!("Failed to deserialize timeline event - {err}");
|
||||
continue;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -87,7 +91,9 @@ impl Room {
|
|||
self.timeline.push(event);
|
||||
}
|
||||
|
||||
pub fn timeline(&self) -> &Vec<AnyTimelineEvent> { &self.timeline }
|
||||
pub fn timeline(&self) -> &Vec<AnyTimelineEvent> {
|
||||
&self.timeline
|
||||
}
|
||||
|
||||
pub async fn send(&mut self, message: String) -> Result<()> {
|
||||
let content = RoomMessageEventContent::text_plain(message);
|
||||
|
@ -114,9 +120,7 @@ impl Status {
|
|||
let mut rooms = IndexMap::new();
|
||||
if let Some(c) = &client {
|
||||
for r in c.joined_rooms() {
|
||||
rooms.insert(
|
||||
r.room_id().to_string(),
|
||||
Room::new(r.clone()));
|
||||
rooms.insert(r.room_id().to_string(), Room::new(r.clone()));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -167,7 +171,10 @@ impl Status {
|
|||
self.current_room_id = room_id.to_string();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::msg(format!("failed to set room -> invalid room id {}", room_id.to_string())))
|
||||
Err(Error::msg(format!(
|
||||
"failed to set room -> invalid room id {}",
|
||||
room_id.to_string()
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,7 +183,10 @@ impl Status {
|
|||
self.current_room_id = room_id.clone();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::msg(format!("failed to set room -> invalid room index {}", room_index)))
|
||||
Err(Error::msg(format!(
|
||||
"failed to set room -> invalid room index {}",
|
||||
room_index
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
mod ui;
|
||||
mod accounts;
|
||||
mod app;
|
||||
mod ui;
|
||||
|
||||
use cli_log::{error, warn, info};
|
||||
use cli_log::{error, info, warn};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
|
|
326
src/ui/mod.rs
326
src/ui/mod.rs
|
@ -1,30 +1,38 @@
|
|||
use crate::app::status::Status;
|
||||
|
||||
use std::cmp;
|
||||
use crossterm::{
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, read},
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
style::{style},
|
||||
};
|
||||
use anyhow::{Error, Result};
|
||||
use std::io::Stdout;
|
||||
use cli_log::{error, info, warn};
|
||||
use crossterm::{
|
||||
event::{self, read, DisableMouseCapture, EnableMouseCapture, Event},
|
||||
execute,
|
||||
style::style,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use matrix_sdk::{
|
||||
room::MessagesOptions,
|
||||
ruma::events::{AnyMessageLikeEvent, AnyTimelineEvent},
|
||||
};
|
||||
use std::cmp;
|
||||
use std::io;
|
||||
use tui::{backend::CrosstermBackend, layout::{Constraint, Direction, Layout}, widgets::{Block, Borders, Widget}, Terminal, Frame};
|
||||
use std::io::Stdout;
|
||||
use tui::layout::{Alignment, Corner};
|
||||
use tui::style::{Color, Modifier, Style};
|
||||
use tui::text::{Spans, Span, Text};
|
||||
use tui::text::{Span, Spans, Text};
|
||||
use tui::widgets::{List, ListItem, ListState, Paragraph, Wrap};
|
||||
use tui::{
|
||||
backend::CrosstermBackend,
|
||||
layout::{Constraint, Direction, Layout},
|
||||
widgets::{Block, Borders, Widget},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use tui_textarea::{Input, Key, TextArea};
|
||||
use cli_log::{error, warn, info};
|
||||
use matrix_sdk::{room::MessagesOptions, ruma::events::{AnyTimelineEvent, AnyMessageLikeEvent}};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum SetupInputPosition {
|
||||
Homeserver,
|
||||
Username,
|
||||
Password,
|
||||
Ok
|
||||
Ok,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -33,7 +41,7 @@ pub enum MainInputPosition {
|
|||
Rooms,
|
||||
Messages,
|
||||
MessageCompose,
|
||||
RoomInfo
|
||||
RoomInfo,
|
||||
}
|
||||
|
||||
pub struct SetupUI<'a> {
|
||||
|
@ -54,7 +62,6 @@ pub struct UI<'a> {
|
|||
pub setup_ui: Option<SetupUI<'a>>,
|
||||
}
|
||||
|
||||
|
||||
fn terminal_prepare() -> Result<Stdout> {
|
||||
enable_raw_mode()?;
|
||||
let mut stdout = io::stdout();
|
||||
|
@ -80,9 +87,7 @@ pub fn textarea_inactivate(textarea: &mut TextArea) {
|
|||
.block()
|
||||
.cloned()
|
||||
.unwrap_or_else(|| Block::default().borders(Borders::ALL));
|
||||
textarea.set_block(
|
||||
b.style(Style::default().fg(Color::DarkGray))
|
||||
);
|
||||
textarea.set_block(b.style(Style::default().fg(Color::DarkGray)));
|
||||
}
|
||||
|
||||
impl Drop for UI<'_> {
|
||||
|
@ -94,7 +99,9 @@ impl Drop for UI<'_> {
|
|||
LeaveAlternateScreen,
|
||||
DisableMouseCapture
|
||||
).expect("While destructing UI -> Failed execute backend commands (LeaveAlternateScreen and DisableMouseCapture)");
|
||||
self.terminal.show_cursor().expect("While destructing UI -> Failed to re-enable cursor");
|
||||
self.terminal
|
||||
.show_cursor()
|
||||
.expect("While destructing UI -> Failed to re-enable cursor");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,18 +112,9 @@ impl SetupUI<'_> {
|
|||
let mut password = TextArea::default();
|
||||
let mut password_data = TextArea::default();
|
||||
|
||||
homeserver.set_block(
|
||||
Block::default()
|
||||
.title("Homeserver")
|
||||
.borders(Borders::ALL));
|
||||
username.set_block(
|
||||
Block::default()
|
||||
.title("Username")
|
||||
.borders(Borders::ALL));
|
||||
password.set_block(
|
||||
Block::default()
|
||||
.title("Password")
|
||||
.borders(Borders::ALL));
|
||||
homeserver.set_block(Block::default().title("Homeserver").borders(Borders::ALL));
|
||||
username.set_block(Block::default().title("Username").borders(Borders::ALL));
|
||||
password.set_block(Block::default().title("Password").borders(Borders::ALL));
|
||||
|
||||
textarea_activate(&mut homeserver);
|
||||
textarea_inactivate(&mut username);
|
||||
|
@ -138,68 +136,74 @@ impl SetupUI<'_> {
|
|||
textarea_activate(&mut self.username);
|
||||
textarea_inactivate(&mut self.password);
|
||||
SetupInputPosition::Username
|
||||
},
|
||||
}
|
||||
SetupInputPosition::Username => {
|
||||
textarea_inactivate(&mut self.homeserver);
|
||||
textarea_inactivate(&mut self.username);
|
||||
textarea_activate(&mut self.password);
|
||||
SetupInputPosition::Password
|
||||
},
|
||||
}
|
||||
SetupInputPosition::Password => {
|
||||
textarea_inactivate(&mut self.homeserver);
|
||||
textarea_inactivate(&mut self.username);
|
||||
textarea_inactivate(&mut self.password);
|
||||
SetupInputPosition::Ok
|
||||
},
|
||||
}
|
||||
SetupInputPosition::Ok => {
|
||||
textarea_activate(&mut self.homeserver);
|
||||
textarea_inactivate(&mut self.username);
|
||||
textarea_inactivate(&mut self.password);
|
||||
SetupInputPosition::Homeserver
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn input_position(&self) -> &SetupInputPosition { &self.input_position }
|
||||
pub fn input_position(&self) -> &SetupInputPosition {
|
||||
&self.input_position
|
||||
}
|
||||
|
||||
pub async fn update(&'_ mut self, terminal: &mut Terminal<CrosstermBackend<Stdout>>) -> Result<()> {
|
||||
pub async fn update(
|
||||
&'_ mut self,
|
||||
terminal: &mut Terminal<CrosstermBackend<Stdout>>,
|
||||
) -> Result<()> {
|
||||
let mut strings: Vec<String> = Vec::new();
|
||||
strings.resize(3, "".to_string());
|
||||
|
||||
let content_ok = match self.input_position {
|
||||
SetupInputPosition:: Ok => Span::styled("OK", Style::default().add_modifier(Modifier::UNDERLINED)),
|
||||
let content_ok = match self.input_position {
|
||||
SetupInputPosition::Ok => {
|
||||
Span::styled("OK", Style::default().add_modifier(Modifier::UNDERLINED))
|
||||
}
|
||||
_ => Span::styled("OK", Style::default().fg(Color::DarkGray)),
|
||||
};
|
||||
|
||||
let block = Block::default()
|
||||
.title("Login")
|
||||
.borders(Borders::ALL);
|
||||
|
||||
let mut ok = Paragraph::new(content_ok)
|
||||
.alignment(Alignment::Center);
|
||||
let block = Block::default().title("Login").borders(Borders::ALL);
|
||||
|
||||
let mut ok = Paragraph::new(content_ok).alignment(Alignment::Center);
|
||||
|
||||
// define a 32 * 6 chunk in the middle of the screen
|
||||
let mut chunk = terminal.size()?;
|
||||
chunk.x = (chunk.width / 2) - 16;
|
||||
chunk.y = (chunk.height / 2) - 5;
|
||||
chunk.x = (chunk.width / 2) - 16;
|
||||
chunk.y = (chunk.height / 2) - 5;
|
||||
chunk.height = 12;
|
||||
chunk.width = 32;
|
||||
chunk.width = 32;
|
||||
|
||||
let mut split_chunk = chunk.clone();
|
||||
split_chunk.x += 1;
|
||||
split_chunk.y += 1;
|
||||
split_chunk.x += 1;
|
||||
split_chunk.y += 1;
|
||||
split_chunk.height -= 1;
|
||||
split_chunk.width -= 2;
|
||||
split_chunk.width -= 2;
|
||||
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Length(3), // 0. Homserver:
|
||||
Constraint::Length(3), // 1. Username:
|
||||
Constraint::Length(3), // 2. Password:
|
||||
Constraint::Length(1) // 3. OK
|
||||
].as_ref())
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Length(3), // 0. Homserver:
|
||||
Constraint::Length(3), // 1. Username:
|
||||
Constraint::Length(3), // 2. Password:
|
||||
Constraint::Length(1), // 3. OK
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.split(split_chunk);
|
||||
|
||||
terminal.draw(|frame| {
|
||||
|
@ -226,7 +230,8 @@ impl UI<'_> {
|
|||
message_compose.set_block(
|
||||
Block::default()
|
||||
.title("Message Compose (send: <Alt>+<Enter>)")
|
||||
.borders(Borders::ALL));
|
||||
.borders(Borders::ALL),
|
||||
);
|
||||
|
||||
info!("Initialized UI");
|
||||
|
||||
|
@ -235,7 +240,7 @@ impl UI<'_> {
|
|||
input_position: MainInputPosition::Rooms,
|
||||
rooms_state: ListState::default(),
|
||||
message_compose,
|
||||
setup_ui: None
|
||||
setup_ui: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,14 +254,17 @@ impl UI<'_> {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn input_position(&self) -> &MainInputPosition { &self.input_position }
|
||||
pub fn input_position(&self) -> &MainInputPosition {
|
||||
&self.input_position
|
||||
}
|
||||
|
||||
pub fn message_compose_clear(&mut self) {
|
||||
self.message_compose = TextArea::default();
|
||||
self.message_compose.set_block(
|
||||
Block::default()
|
||||
.title("Message Compose (send: <Alt>+<Enter>)")
|
||||
.borders(Borders::ALL));
|
||||
.borders(Borders::ALL),
|
||||
);
|
||||
}
|
||||
|
||||
pub async fn update(&mut self, status: &Status) -> Result<()> {
|
||||
|
@ -264,7 +272,14 @@ impl UI<'_> {
|
|||
|
||||
let main_chunks = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([Constraint::Length(32), Constraint::Min(16), Constraint::Length(32)].as_ref())
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Length(32),
|
||||
Constraint::Min(16),
|
||||
Constraint::Length(32),
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.split(chunk);
|
||||
|
||||
let left_chunks = Layout::default()
|
||||
|
@ -274,7 +289,13 @@ impl UI<'_> {
|
|||
|
||||
let middle_chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([Constraint::Min(4), Constraint::Length(cmp::min(2 + self.message_compose.lines().len() as u16, 8))].as_ref())
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Min(4),
|
||||
Constraint::Length(cmp::min(2 + self.message_compose.lines().len() as u16, 8)),
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.split(main_chunks[1]);
|
||||
|
||||
let right_chunks = Layout::default()
|
||||
|
@ -282,15 +303,22 @@ impl UI<'_> {
|
|||
.constraints([Constraint::Min(4)].as_ref())
|
||||
.split(main_chunks[2]);
|
||||
|
||||
let mut status_content = Text::styled(status.account_name(), Style::default().add_modifier(Modifier::BOLD));
|
||||
let mut status_content = Text::styled(
|
||||
status.account_name(),
|
||||
Style::default().add_modifier(Modifier::BOLD),
|
||||
);
|
||||
status_content.extend(Text::styled(status.account_user_id(), Style::default()));
|
||||
status_content.extend(Text::styled("settings", Style::default().fg(Color::LightMagenta).add_modifier(Modifier::ITALIC | Modifier::UNDERLINED)));
|
||||
status_content.extend(Text::styled(
|
||||
"settings",
|
||||
Style::default()
|
||||
.fg(Color::LightMagenta)
|
||||
.add_modifier(Modifier::ITALIC | Modifier::UNDERLINED),
|
||||
));
|
||||
|
||||
let rooms_content = status.rooms()
|
||||
let rooms_content = status
|
||||
.rooms()
|
||||
.iter()
|
||||
.map(|(_, room)| {
|
||||
ListItem::new(Span::styled(room.name(), Style::default()))
|
||||
})
|
||||
.map(|(_, room)| ListItem::new(Span::styled(room.name(), Style::default())))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let messages_content = match status.room() {
|
||||
|
@ -300,7 +328,6 @@ impl UI<'_> {
|
|||
.rev()
|
||||
.map(|event| {
|
||||
match event {
|
||||
|
||||
// Message Like Events
|
||||
AnyTimelineEvent::MessageLike(message_like_event) => {
|
||||
let (content, color) = match &message_like_event {
|
||||
|
@ -312,30 +339,48 @@ impl UI<'_> {
|
|||
.body();
|
||||
|
||||
(message_content.to_string(), Color::White)
|
||||
},
|
||||
_ => ("~~~ not supported message like event ~~~".to_string(), Color::Red)
|
||||
}
|
||||
_ => (
|
||||
"~~~ not supported message like event ~~~".to_string(),
|
||||
Color::Red,
|
||||
),
|
||||
};
|
||||
let mut text = Text::styled(message_like_event.sender().to_string(),
|
||||
Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD));
|
||||
text.extend(Text::styled(content.to_string(),
|
||||
Style::default().fg(color)));
|
||||
let mut text = Text::styled(
|
||||
message_like_event.sender().to_string(),
|
||||
Style::default()
|
||||
.fg(Color::Cyan)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
);
|
||||
text.extend(Text::styled(
|
||||
content.to_string(),
|
||||
Style::default().fg(color),
|
||||
));
|
||||
ListItem::new(text)
|
||||
},
|
||||
}
|
||||
|
||||
// State Events
|
||||
AnyTimelineEvent::State(state) => {
|
||||
ListItem::new(vec![Spans::from(vec![
|
||||
Span::styled(state.sender().to_string(), Style::default().fg(Color::DarkGray)),
|
||||
Span::styled(
|
||||
state.sender().to_string(),
|
||||
Style::default().fg(Color::DarkGray),
|
||||
),
|
||||
Span::styled(": ", Style::default().fg(Color::DarkGray)),
|
||||
Span::styled(state.event_type().to_string(), Style::default().fg(Color::DarkGray))
|
||||
Span::styled(
|
||||
state.event_type().to_string(),
|
||||
Style::default().fg(Color::DarkGray),
|
||||
),
|
||||
])])
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
},
|
||||
}
|
||||
None => {
|
||||
vec![ListItem::new(Text::styled("No room selected!", Style::default().fg(Color::Red)))]
|
||||
vec![ListItem::new(Text::styled(
|
||||
"No room selected!",
|
||||
Style::default().fg(Color::Red),
|
||||
))]
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -347,78 +392,129 @@ impl UI<'_> {
|
|||
|
||||
room_info_content.extend(Text::styled(room.name(), Style::default().fg(Color::Cyan)));
|
||||
if room.encrypted() {
|
||||
room_info_content.extend(Text::styled("Encrypted", Style::default().fg(Color::Green)));
|
||||
room_info_content
|
||||
.extend(Text::styled("Encrypted", Style::default().fg(Color::Green)));
|
||||
} else {
|
||||
room_info_content.extend(Text::styled("Not Encrypted!", Style::default().fg(Color::Red)));
|
||||
room_info_content.extend(Text::styled(
|
||||
"Not Encrypted!",
|
||||
Style::default().fg(Color::Red),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
room_info_content.extend(Text::styled("No room selected!", Style::default().fg(Color::Red)));
|
||||
room_info_content.extend(Text::styled(
|
||||
"No room selected!",
|
||||
Style::default().fg(Color::Red),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
// calculate to widgets colors, based of which widget is currently selected
|
||||
let colors = match self.input_position {
|
||||
MainInputPosition::Status => {
|
||||
textarea_inactivate(&mut self.message_compose);
|
||||
vec![Color::White, Color::DarkGray, Color::DarkGray, Color::DarkGray, Color::DarkGray]
|
||||
},
|
||||
vec![
|
||||
Color::White,
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
]
|
||||
}
|
||||
MainInputPosition::Rooms => {
|
||||
textarea_inactivate(&mut self.message_compose);
|
||||
vec![Color::DarkGray, Color::White, Color::DarkGray, Color::DarkGray, Color::DarkGray]
|
||||
},
|
||||
vec![
|
||||
Color::DarkGray,
|
||||
Color::White,
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
]
|
||||
}
|
||||
MainInputPosition::Messages => {
|
||||
textarea_inactivate(&mut self.message_compose);
|
||||
vec![Color::DarkGray, Color::DarkGray, Color::White, Color::DarkGray, Color::DarkGray]
|
||||
},
|
||||
vec![
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
Color::White,
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
]
|
||||
}
|
||||
MainInputPosition::MessageCompose => {
|
||||
textarea_activate(&mut self.message_compose);
|
||||
vec![Color::DarkGray, Color::DarkGray, Color::DarkGray, Color::DarkGray, Color::DarkGray]
|
||||
},
|
||||
vec![
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
]
|
||||
}
|
||||
MainInputPosition::RoomInfo => {
|
||||
textarea_inactivate(&mut self.message_compose);
|
||||
vec![Color::DarkGray, Color::DarkGray, Color::DarkGray, Color::DarkGray, Color::White]
|
||||
},
|
||||
vec![
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
Color::DarkGray,
|
||||
Color::White,
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// initiate the widgets
|
||||
let status_panel = Paragraph::new(status_content)
|
||||
.block(Block::default()
|
||||
.title("Status")
|
||||
.borders(Borders::ALL)
|
||||
.style(Style::default().fg(colors[MainInputPosition::Status as usize])))
|
||||
.block(
|
||||
Block::default()
|
||||
.title("Status")
|
||||
.borders(Borders::ALL)
|
||||
.style(Style::default().fg(colors[MainInputPosition::Status as usize])),
|
||||
)
|
||||
.alignment(Alignment::Left);
|
||||
|
||||
let rooms_panel = List::new(rooms_content)
|
||||
.block(Block::default()
|
||||
.title("Rooms (navigate: arrow keys)")
|
||||
.borders(Borders::ALL)
|
||||
.style(Style::default().fg(colors[MainInputPosition::Rooms as usize])))
|
||||
.block(
|
||||
Block::default()
|
||||
.title("Rooms (navigate: arrow keys)")
|
||||
.borders(Borders::ALL)
|
||||
.style(Style::default().fg(colors[MainInputPosition::Rooms as usize])),
|
||||
)
|
||||
.style(Style::default().fg(Color::DarkGray))
|
||||
.highlight_style(Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD))
|
||||
.highlight_style(
|
||||
Style::default()
|
||||
.fg(Color::Cyan)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
)
|
||||
.highlight_symbol(">");
|
||||
|
||||
let messages_panel = List::new(messages_content)
|
||||
.block(Block::default()
|
||||
.title("Messages")
|
||||
.borders(Borders::ALL)
|
||||
.style(Style::default().fg(colors[MainInputPosition::Messages as usize])))
|
||||
.block(
|
||||
Block::default()
|
||||
.title("Messages")
|
||||
.borders(Borders::ALL)
|
||||
.style(Style::default().fg(colors[MainInputPosition::Messages as usize])),
|
||||
)
|
||||
.start_corner(Corner::BottomLeft)
|
||||
.highlight_symbol(">")
|
||||
.highlight_style(Style::default().fg(Color::LightMagenta).add_modifier(Modifier::BOLD));
|
||||
.highlight_style(
|
||||
Style::default()
|
||||
.fg(Color::LightMagenta)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
);
|
||||
|
||||
let room_info_panel = Paragraph::new(room_info_content)
|
||||
.block(Block::default()
|
||||
.title("Room Info")
|
||||
.borders(Borders::ALL)
|
||||
.style(Style::default().fg(colors[MainInputPosition::RoomInfo as usize])))
|
||||
.block(
|
||||
Block::default()
|
||||
.title("Room Info")
|
||||
.borders(Borders::ALL)
|
||||
.style(Style::default().fg(colors[MainInputPosition::RoomInfo as usize])),
|
||||
)
|
||||
.alignment(Alignment::Center);
|
||||
|
||||
|
||||
// render the widgets
|
||||
self.terminal.draw(|frame| {
|
||||
frame.render_widget(status_panel, left_chunks[0]);
|
||||
frame.render_stateful_widget(rooms_panel, left_chunks[1], &mut self.rooms_state);
|
||||
frame.render_stateful_widget(messages_panel, middle_chunks[0], & mut messages_state);
|
||||
frame.render_stateful_widget(messages_panel, middle_chunks[0], &mut messages_state);
|
||||
frame.render_widget(self.message_compose.widget(), middle_chunks[1]);
|
||||
frame.render_widget(room_info_panel, right_chunks[0]);
|
||||
})?;
|
||||
|
|
Loading…
Reference in New Issue