diff options
| author | 2025-04-22 18:23:29 +0100 | |
|---|---|---|
| committer | 2025-04-22 18:23:29 +0100 | |
| commit | 8d159c86349803658e2b531ea7ca8e0471a7cc9c (patch) | |
| tree | c7bcd671a00f1d5add7d1dbde10a13fda6984216 | |
| parent | 14f6aaf18a3311fee63b11d0ec9c12ba76b70fa1 (diff) | |
| download | macaw-8d159c86349803658e2b531ea7ca8e0471a7cc9c.tar.gz macaw-8d159c86349803658e2b531ea7ca8e0471a7cc9c.tar.bz2 macaw-8d159c86349803658e2b531ea7ca8e0471a7cc9c.zip | |
| -rw-r--r-- | .helix/languages.toml | 2 | ||||
| -rw-r--r-- | Cargo.lock | 749 | ||||
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | src/icons.rs | 93 | ||||
| -rw-r--r-- | src/main.rs | 8 | ||||
| -rw-r--r-- | src/message_view.rs | 194 | 
6 files changed, 493 insertions, 555 deletions
| diff --git a/.helix/languages.toml b/.helix/languages.toml index e828879..b6ba885 100644 --- a/.helix/languages.toml +++ b/.helix/languages.toml @@ -1,4 +1,4 @@  [language-server.rust-analyzer]  command = "rust-analyzer" -environment = { "DATABASE_URL" = "sqlite://filamento.db" } +# environment = { "DATABASE_URL" = "sqlite://filamento.db" }  # config = { cargo.features = ["stanza/rfc_6121", "stanza/xep_0203", "stanza/xep_0030", "stanza/xep_0060", "stanza/xep_0172", "stanza/xep_0390", "stanza/xep_0128", "stanza/xep_0115", "stanza/xep_0084", "sqlx/sqlite", "sqlx/runtime-tokio", "sqlx/uuid", "sqlx/chrono", "jid/sqlx", "uuid/v4", "tokio/full", "rsasl/provider_base64", "rsasl/plain", "rsasl/config_builder", "rsasl/scram-sha-1"] } @@ -19,6 +19,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"  [[package]] +name = "accessory" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb3791c4beae5b827e93558ac83a88e63a841aad61759a05d9b577ef16030470" +dependencies = [ + "macroific", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]]  name = "addr2line"  version = "0.24.2"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -113,9 +125,9 @@ dependencies = [  [[package]]  name = "anyhow" -version = "1.0.97" +version = "1.0.98"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"  [[package]]  name = "approx" @@ -314,15 +326,6 @@ dependencies = [  ]  [[package]] -name = "atoi" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" -dependencies = [ - "num-traits", -] - -[[package]]  name = "atomic-waker"  version = "1.1.2"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -379,12 +382,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"  [[package]] -name = "base64ct" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" - -[[package]]  name = "bit-set"  version = "0.5.3"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -416,9 +413,6 @@ name = "bitflags"  version = "2.9.0"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" -dependencies = [ - "serde", -]  [[package]]  name = "bitstream-io" @@ -547,9 +541,9 @@ dependencies = [  [[package]]  name = "cc" -version = "1.2.18" +version = "1.2.19"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"  dependencies = [   "jobserver",   "libc", @@ -739,12 +733,6 @@ dependencies = [  ]  [[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]]  name = "core-foundation"  version = "0.9.4"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -860,21 +848,6 @@ dependencies = [  ]  [[package]] -name = "crc" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]]  name = "crc32fast"  version = "1.4.2"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -903,15 +876,6 @@ dependencies = [  ]  [[package]] -name = "crossbeam-queue" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" -dependencies = [ - "crossbeam-utils", -] - -[[package]]  name = "crossbeam-utils"  version = "0.8.21"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -974,9 +938,9 @@ dependencies = [  [[package]]  name = "data-encoding" -version = "2.8.0" +version = "2.9.0"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"  [[package]]  name = "data-url" @@ -1015,14 +979,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "7046468a81e6a002061c01e6a7c83139daf91b11c30e66795b13217c2d885c8b"  [[package]] -name = "der" -version = "0.7.9" +name = "delegate-display" +version = "3.0.0"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "9926686c832494164c33a36bf65118f4bd6e704000b58c94681bf62e9ad67a74"  dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", + "impartial-ord", + "itoa", + "macroific", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", + "unicode-xid",  ]  [[package]] @@ -1038,7 +1026,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"  dependencies = [   "block-buffer", - "const-oid",   "crypto-common",   "subtle",  ] @@ -1138,12 +1125,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"  [[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - -[[package]]  name = "downcast-rs"  version = "1.2.1"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1199,9 +1180,6 @@ name = "either"  version = "1.15.0"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -dependencies = [ - "serde", -]  [[package]]  name = "endi" @@ -1275,17 +1253,6 @@ dependencies = [  ]  [[package]] -name = "etcetera" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" -dependencies = [ - "cfg-if", - "home", - "windows-sys 0.48.0", -] - -[[package]]  name = "euclid"  version = "0.22.11"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1331,6 +1298,30 @@ dependencies = [  ]  [[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "fancy_constructor" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac0fd7f4636276b4bd7b3148d0ba2c1c3fbede2b5214e47e7fedb70b02cde44" +dependencies = [ + "macroific", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]]  name = "fast-srgb8"  version = "1.0.0"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1362,15 +1353,18 @@ dependencies = [   "image 0.25.6",   "jid",   "lampada", + "rusqlite",   "sha1",   "sha2",   "sha3", - "sqlx",   "stanza",   "thiserror 2.0.12",   "tokio", + "tokio_with_wasm",   "tracing",   "uuid", + "wasm-bindgen", + "wasm-bindgen-futures",  ]  [[package]] @@ -1390,17 +1384,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"  [[package]] -name = "flume" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" -dependencies = [ - "futures-core", - "futures-sink", - "spin", -] - -[[package]]  name = "foldhash"  version = "0.1.5"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1504,6 +1487,12 @@ dependencies = [  ]  [[package]] +name = "fragile" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" + +[[package]]  name = "futures"  version = "0.3.31"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1547,17 +1536,6 @@ dependencies = [  ]  [[package]] -name = "futures-intrusive" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" -dependencies = [ - "futures-core", - "lock_api", - "parking_lot 0.12.3", -] - -[[package]]  name = "futures-io"  version = "0.3.31"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1644,8 +1622,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"  dependencies = [   "cfg-if", + "js-sys",   "libc",   "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen",  ]  [[package]] @@ -1811,8 +1791,6 @@ version = "0.15.2"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"  dependencies = [ - "allocator-api2", - "equivalent",   "foldhash",  ] @@ -1877,15 +1855,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"  [[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - -[[package]]  name = "hmac"  version = "0.12.1"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1895,15 +1864,6 @@ dependencies = [  ]  [[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]]  name = "hostname"  version = "0.4.1"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2336,6 +2296,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408"  [[package]] +name = "impartial-ord" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab604ee7085efba6efc65e4ebca0e9533e3aff6cb501d7d77b211e3a781c6d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "indexed_db_futures" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94eebf0199c01a1560770d964efb1fb09183a3afc0b1c1397fac1bfdbfa7d6cf" +dependencies = [ + "accessory", + "cfg-if", + "delegate-display", + "derive_more", + "fancy_constructor", + "indexed_db_futures_macros_internal", + "js-sys", + "sealed", + "smallvec", + "thiserror 2.0.12", + "tokio", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "indexed_db_futures_macros_internal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caeba94923b68f254abef921cea7e7698bf4675fdd89d7c58bf1ed885b49a27d" +dependencies = [ + "macroific", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]]  name = "indexmap"  version = "2.9.0"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2402,7 +2407,7 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"  name = "jid"  version = "0.1.0"  dependencies = [ - "sqlx", + "rusqlite",  ]  [[package]] @@ -2536,6 +2541,7 @@ dependencies = [   "stanza",   "thiserror 2.0.12",   "tokio", + "tokio_with_wasm",   "tracing",  ] @@ -2544,9 +2550,6 @@ name = "lazy_static"  version = "1.5.0"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -]  [[package]]  name = "lebe" @@ -2556,9 +2559,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"  [[package]]  name = "libc" -version = "0.2.171" +version = "0.2.172"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"  [[package]]  name = "libdbus-sys" @@ -2618,11 +2621,9 @@ dependencies = [  [[package]]  name = "libsqlite3-sys" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +version = "0.32.0" +source = "git+https://github.com/Spxg/rusqlite.git?branch=wasm-demo#4820de79e45d0604e0596641cbb5dd86aa53f0ed"  dependencies = [ - "cc",   "pkg-config",   "vcpkg",  ] @@ -2704,9 +2705,9 @@ dependencies = [   "async-recursion",   "async-trait",   "futures", + "getrandom 0.2.15",   "jid",   "lazy_static", - "nanoid",   "peanuts",   "pin-project",   "pin-project-lite", @@ -2719,6 +2720,9 @@ dependencies = [   "tracing",   "trust-dns-resolver",   "try_map", + "uuid", + "wasm-bindgen", + "web-sys",  ]  [[package]] @@ -2745,6 +2749,54 @@ dependencies = [  ]  [[package]] +name = "macroific" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89f276537b4b8f981bf1c13d79470980f71134b7bdcc5e6e911e910e556b0285" +dependencies = [ + "macroific_attr_parse", + "macroific_core", + "macroific_macro", +] + +[[package]] +name = "macroific_attr_parse" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad4023761b45fcd36abed8fb7ae6a80456b0a38102d55e89a57d9a594a236be9" +dependencies = [ + "proc-macro2", + "quote", + "sealed", + "syn 2.0.100", +] + +[[package]] +name = "macroific_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a7594d3c14916fa55bef7e9d18c5daa9ed410dd37504251e4b75bbdeec33e3" +dependencies = [ + "proc-macro2", + "quote", + "sealed", + "syn 2.0.100", +] + +[[package]] +name = "macroific_macro" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4da6f2ed796261b0a74e2b52b42c693bb6dee1effba3a482c49592659f824b3b" +dependencies = [ + "macroific_attr_parse", + "macroific_core", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]]  name = "malloc_buf"  version = "0.0.6"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2770,16 +2822,6 @@ dependencies = [  ]  [[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - -[[package]]  name = "memchr"  version = "2.7.4"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2872,15 +2914,6 @@ dependencies = [  ]  [[package]] -name = "nanoid" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" -dependencies = [ - "rand", -] - -[[package]]  name = "native-tls"  version = "0.2.14"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3006,23 +3039,6 @@ dependencies = [  ]  [[package]] -name = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "smallvec", - "zeroize", -] - -[[package]]  name = "num-complex"  version = "0.4.6"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3080,7 +3096,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"  dependencies = [   "autocfg", - "libm",  ]  [[package]] @@ -3541,26 +3556,20 @@ dependencies = [  [[package]]  name = "peanuts"  version = "0.1.0" -source = "git+https://bunny.garden/peanuts#92f4fd88295cb39bf865e10b0a28cc36acb5276a" +source = "git+https://bunny.garden/peanuts#a0cc279551267dfa7a17fe4b449dd1a1fcd3526f"  dependencies = [   "async-recursion",   "circular",   "futures",   "futures-util", + "js-sys",   "nom",   "pin-project",   "thiserror 2.0.12",   "tokio",   "tracing", -] - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", + "wasm-bindgen", + "web-sys",  ]  [[package]] @@ -3661,27 +3670,6 @@ dependencies = [  ]  [[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]]  name = "pkg-config"  version = "0.3.32"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3741,9 +3729,9 @@ dependencies = [  [[package]]  name = "proc-macro2" -version = "1.0.94" +version = "1.0.95"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"  dependencies = [   "unicode-ident",  ] @@ -3885,9 +3873,9 @@ dependencies = [  [[package]]  name = "ravif" -version = "0.11.11" +version = "0.11.12"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" +checksum = "d6a5f31fcf7500f9401fea858ea4ab5525c99f2322cfcee732c0e6c74208c0c6"  dependencies = [   "avif-serialize",   "imgref", @@ -4030,26 +4018,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"  [[package]] -name = "rsa" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core", - "signature", - "spki", - "subtle", - "zeroize", -] - -[[package]]  name = "rsasl"  version = "2.2.0"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4068,6 +4036,22 @@ dependencies = [  ]  [[package]] +name = "rusqlite" +version = "0.34.0" +source = "git+https://github.com/Spxg/rusqlite.git?branch=wasm-demo#4820de79e45d0604e0596641cbb5dd86aa53f0ed" +dependencies = [ + "bitflags 2.9.0", + "chrono", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", + "sqlite-wasm-rs", + "uuid", +] + +[[package]]  name = "rust-ini"  version = "0.18.0"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4194,6 +4178,17 @@ dependencies = [  ]  [[package]] +name = "sealed" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f968c5ea23d555e670b449c1c5e7b2fc399fdaec1d304a17cd48e288abc107" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]]  name = "security-framework"  version = "2.11.1"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4231,9 +4226,9 @@ dependencies = [  [[package]]  name = "self_cell" -version = "1.1.0" +version = "1.2.0"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe" +checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749"  [[package]]  name = "serde" @@ -4288,18 +4283,6 @@ dependencies = [  ]  [[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]]  name = "sha1"  version = "0.10.6"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4356,16 +4339,6 @@ dependencies = [  ]  [[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core", -] - -[[package]]  name = "simd-adler32"  version = "0.3.7"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4428,9 +4401,6 @@ name = "smallvec"  version = "1.15.0"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" -dependencies = [ - "serde", -]  [[package]]  name = "smithay-client-toolkit" @@ -4520,15 +4490,6 @@ dependencies = [  ]  [[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]]  name = "spirv"  version = "0.3.0+sdk-1.3.268.0"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4538,208 +4499,21 @@ dependencies = [  ]  [[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "sqlx" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f" -dependencies = [ - "sqlx-core", - "sqlx-macros", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", -] - -[[package]] -name = "sqlx-core" -version = "0.8.3" +name = "sqlite-wasm-rs" +version = "0.3.2"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0" +checksum = "a46f82f6a905a1fdc5abe7ee0869bee63f5320344c593fe55554f443b178bd75"  dependencies = [ - "bytes", - "chrono", - "crc", - "crossbeam-queue", - "either", - "event-listener", - "futures-core", - "futures-intrusive", - "futures-io", - "futures-util", - "hashbrown 0.15.2", - "hashlink", - "indexmap", - "log", - "memchr", + "fragile", + "indexed_db_futures", + "js-sys",   "once_cell", - "percent-encoding", - "serde", - "serde_json", - "sha2", - "smallvec", + "parking_lot 0.12.3",   "thiserror 2.0.12",   "tokio", - "tokio-stream", - "tracing", - "url", - "uuid", -] - -[[package]] -name = "sqlx-macros" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310" -dependencies = [ - "proc-macro2", - "quote", - "sqlx-core", - "sqlx-macros-core", - "syn 2.0.100", -] - -[[package]] -name = "sqlx-macros-core" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad" -dependencies = [ - "dotenvy", - "either", - "heck 0.5.0", - "hex", - "once_cell", - "proc-macro2", - "quote", - "serde", - "serde_json", - "sha2", - "sqlx-core", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", - "syn 2.0.100", - "tempfile", - "tokio", - "url", -] - -[[package]] -name = "sqlx-mysql" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233" -dependencies = [ - "atoi", - "base64", - "bitflags 2.9.0", - "byteorder", - "bytes", - "chrono", - "crc", - "digest", - "dotenvy", - "either", - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "generic-array", - "hex", - "hkdf", - "hmac", - "itoa", - "log", - "md-5", - "memchr", - "once_cell", - "percent-encoding", - "rand", - "rsa", - "serde", - "sha1", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror 2.0.12", - "tracing", - "uuid", - "whoami", -] - -[[package]] -name = "sqlx-postgres" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613" -dependencies = [ - "atoi", - "base64", - "bitflags 2.9.0", - "byteorder", - "chrono", - "crc", - "dotenvy", - "etcetera", - "futures-channel", - "futures-core", - "futures-util", - "hex", - "hkdf", - "hmac", - "home", - "itoa", - "log", - "md-5", - "memchr", - "once_cell", - "rand", - "serde", - "serde_json", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror 2.0.12", - "tracing", - "uuid", - "whoami", -] - -[[package]] -name = "sqlx-sqlite" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540" -dependencies = [ - "atoi", - "chrono", - "flume", - "futures-channel", - "futures-core", - "futures-executor", - "futures-intrusive", - "futures-util", - "libsqlite3-sys", - "log", - "percent-encoding", - "serde", - "serde_urlencoded", - "sqlx-core", - "tracing", - "url", - "uuid", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys",  ]  [[package]] @@ -4792,9 +4566,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"  [[package]]  name = "svg_fmt" -version = "0.4.4" +version = "0.4.5"  source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce5d813d71d82c4cbc1742135004e4a79fd870214c155443451c139c9470a0aa" +checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb"  [[package]]  name = "svgtypes" @@ -5041,9 +4815,7 @@ dependencies = [   "bytes",   "libc",   "mio", - "parking_lot 0.12.3",   "pin-project-lite", - "signal-hook-registry",   "socket2",   "tokio-macros",   "windows-sys 0.52.0", @@ -5082,6 +4854,30 @@ dependencies = [  ]  [[package]] +name = "tokio_with_wasm" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42d20f41cbfe26740d0c2fb320d44ce7dfa716be135cb663e99a48248a0e897" +dependencies = [ + "js-sys", + "tokio", + "tokio_with_wasm_proc", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "tokio_with_wasm_proc" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee80eb7e23abaa636caa9afe6042c6d8a8c0686165b8165f4fbf2988f0dd347f" +dependencies = [ + "quote", + "syn 2.0.100", +] + +[[package]]  name = "toml"  version = "0.8.20"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5121,7 +4917,6 @@ version = "0.1.41"  source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"  dependencies = [ - "log",   "pin-project-lite",   "tracing-attributes",   "tracing-core", @@ -5391,6 +5186,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"  checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"  dependencies = [   "getrandom 0.3.2", + "js-sys", + "wasm-bindgen",  ]  [[package]] @@ -5454,12 +5251,6 @@ dependencies = [  ]  [[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - -[[package]]  name = "wasm-bindgen"  version = "0.2.100"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5788,16 +5579,6 @@ dependencies = [  ]  [[package]] -name = "whoami" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" -dependencies = [ - "redox_syscall 0.5.11", - "wasite", -] - -[[package]]  name = "widestring"  version = "1.2.0"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6480,12 +6261,6 @@ dependencies = [  ]  [[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]]  name = "zerovec"  version = "0.10.4"  source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7,7 +7,7 @@ version = "0.1.0"  edition = "2021"  [dependencies] -iced = { version = "0.13.0", features = ["tokio", "image", "svg"] } +iced = { version = "0.13.0", features = ["tokio", "image", "svg", "advanced"] }  filamento = { version = "0.1.0", path = "../luz/filamento" }  jid = { version = "0.1.0", path = "../luz/jid" }  tokio = "1.43.0" diff --git a/src/icons.rs b/src/icons.rs index 934a0c8..63e7708 100644 --- a/src/icons.rs +++ b/src/icons.rs @@ -1,6 +1,7 @@ +use filamento::chat::Delivery;  use iced::widget::svg;  use iced::widget::{svg::Handle, Svg}; -use iced::Element; +use iced::{color, Element, Theme};  pub enum Icon {      AddContact24, @@ -23,6 +24,12 @@ pub enum Icon {      Sent16,  } +impl Icon { +    pub fn svg(self) -> Svg<'static> { +        self.into() +    } +} +  impl From<Icon> for Svg<'_> {      fn from(value: Icon) -> Self {          match value { @@ -30,17 +37,26 @@ impl From<Icon> for Svg<'_> {                  "../assets/icons/addcontact24.svg"              )))              .width(24) -            .height(24), +            .height(24) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),              Icon::Attachment24 => svg(Handle::from_memory(include_bytes!(                  "../assets/icons/attachment24.svg"              )))              .width(24) -            .height(24), +            .height(24) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),              Icon::Away16 => svg(Handle::from_memory(include_bytes!(                  "../assets/icons/away16.svg"              )))              .width(16) -            .height(16), +            .height(16) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),              Icon::Away16Color => svg(Handle::from_memory(include_bytes!(                  "../assets/icons/away16color.svg"              ))) @@ -50,7 +66,10 @@ impl From<Icon> for Svg<'_> {                  "../assets/icons/bubble16.svg"              )))              .width(16) -            .height(16), +            .height(16) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),              Icon::Bubble16Color => svg(Handle::from_memory(include_bytes!(                  "../assets/icons/bubble16color.svg"              ))) @@ -60,22 +79,34 @@ impl From<Icon> for Svg<'_> {                  "../assets/icons/bubble24.svg"              )))              .width(24) -            .height(24), +            .height(24) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),              Icon::Contact24 => svg(Handle::from_memory(include_bytes!(                  "../assets/icons/contact24.svg"              )))              .width(24) -            .height(24), +            .height(24) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),              Icon::Delivered16 => svg(Handle::from_memory(include_bytes!(                  "../assets/icons/delivered16.svg"              )))              .width(16) -            .height(16), +            .height(16) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),              Icon::Dnd16 => svg(Handle::from_memory(include_bytes!(                  "../assets/icons/dnd16.svg"              )))              .width(16) -            .height(16), +            .height(16) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),              Icon::Dnd16Color => svg(Handle::from_memory(include_bytes!(                  "../assets/icons/dnd16color.svg"              ))) @@ -90,32 +121,50 @@ impl From<Icon> for Svg<'_> {                  "../assets/icons/forward24.svg"              )))              .width(24) -            .height(24), +            .height(24) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),              Icon::Heart24 => svg(Handle::from_memory(include_bytes!(                  "../assets/icons/heart24.svg"              )))              .width(24) -            .height(24), +            .height(24) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),              Icon::NewBubble24 => svg(Handle::from_memory(include_bytes!(                  "../assets/icons/newbubble24.svg"              )))              .width(24) -            .height(24), +            .height(24) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),              Icon::Reply24 => svg(Handle::from_memory(include_bytes!(                  "../assets/icons/reply24.svg"              )))              .width(24) -            .height(24), +            .height(24) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),              Icon::Sending16 => svg(Handle::from_memory(include_bytes!(                  "../assets/icons/sending16.svg"              )))              .width(16) -            .height(16), +            .height(16) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),              Icon::Sent16 => svg(Handle::from_memory(include_bytes!(                  "../assets/icons/sent16.svg"              )))              .width(16) -            .height(16), +            .height(16) +            .style(|theme: &Theme, _status| svg::Style { +                color: Some(theme.extended_palette().background.base.text), +            }),          }      }  } @@ -125,3 +174,17 @@ impl<Message> From<Icon> for Element<'_, Message> {          Into::<Svg>::into(value).into()      }  } + +pub fn delivery_to_icon_svg(delivery: Delivery) -> Option<Svg<'static>> { +    match delivery { +        Delivery::Sending => Some(Icon::Sending16.into()), +        Delivery::Written => None, +        Delivery::Sent => Some(Icon::Sent16.into()), +        Delivery::Delivered => Some(Icon::Delivered16.into()), +        Delivery::Read => Some(Icon::Delivered16.svg().style(|_theme, _| svg::Style { +            color: Some(color!(0x52cf6e)), +        })), +        Delivery::Failed => Some(Icon::Error16Color.into()), +        Delivery::Queued => Some(Icon::Sending16.into()), +    } +} diff --git a/src/main.rs b/src/main.rs index b785562..8b50bef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -527,7 +527,7 @@ async fn main() -> iced::Result {              }          };          let mut font = Font::with_name("K2D"); -        font.weight = Weight::Medium; +        font.weight = Weight::Light;          // font.stretch = Stretch::Condensed;          iced::application("Macaw", Macaw::update, Macaw::view)              .font(include_bytes!("../assets/fonts/Diolce-Regular.ttf")) @@ -813,7 +813,7 @@ impl Macaw {                          }                      }                      if let Some(open_chat) = &mut self.open_chat { -                        if let Some(message) = open_chat.messages.get_mut(&id) { +                        if let Some((message, _)) = open_chat.messages.get_mut(&id) {                              message.delivery = Some(delivery)                          }                      } @@ -828,7 +828,7 @@ impl Macaw {                          chats_list_item.user.nick = nick.clone()                      }                      if let Some(open_chat) = &mut self.open_chat { -                        for (_, message) in &mut open_chat.messages { +                        for (_, (message, _)) in &mut open_chat.messages {                              if message.from.jid == jid {                                  message.from.nick = nick.clone()                              } @@ -849,7 +849,7 @@ impl Macaw {                      }                      if let Some(open_chat) = &mut self.open_chat {                          // TODO: consider using an indexmap with two keys for speeding this up? -                        for (_, message) in &mut open_chat.messages { +                        for (_, (message, _)) in &mut open_chat.messages {                              if message.from.jid == jid {                                  message.from.avatar = id.clone()                              } diff --git a/src/message_view.rs b/src/message_view.rs index f5319bd..742aac0 100644 --- a/src/message_view.rs +++ b/src/message_view.rs @@ -1,8 +1,10 @@  use std::{path::PathBuf, time::Duration};  use chrono::{NaiveDate, NaiveDateTime, TimeDelta}; -use iced::color; -use iced::widget::text_editor; +use filamento::chat::Delivery; +use iced::advanced::Overlay; +use iced::alignment::Vertical; +use iced::widget::{horizontal_space, mouse_area, text_editor, vertical_space, Container};  use iced::{      border::Radius,      font::{Style, Weight}, @@ -11,11 +13,13 @@ use iced::{      Length::{Fill, Shrink},      Theme,  }; +use iced::{color, overlay, Length, Padding};  use indexmap::IndexMap;  use jid::JID;  use serde::{Deserialize, Serialize};  use uuid::Uuid; +use crate::icons;  use crate::{icons::Icon, MacawChat, MacawMessage};  pub struct MessageView { @@ -23,7 +27,7 @@ pub struct MessageView {      // references chats, users      pub chat: MacawChat,      // references users, messages -    pub messages: IndexMap<Uuid, MacawMessage>, +    pub messages: IndexMap<Uuid, (MacawMessage, bool)>,      pub config: Config,      pub new_message: Content,      pub shift_pressed: bool, @@ -46,6 +50,9 @@ impl Default for Config {  pub enum Message {      MessageHistory(Vec<MacawMessage>),      Message(MacawMessage), +    MessageHovered(Uuid), +    MessageUnhovered(Uuid), +    MessageRightClicked(Uuid),      MessageCompose(text_editor::Action),      SendMessage(String),  } @@ -105,61 +112,80 @@ impl MessageView {                  if self.messages.is_empty() {                      self.messages = macaw_messages                          .into_iter() -                        .map(|message| (message.id, message)) +                        .map(|message| (message.id, (message, false)))                          .collect()                  } else {                      for message in macaw_messages {                          let index = match self                              .messages -                            .binary_search_by(|_, value| value.timestamp.cmp(&message.timestamp)) +                            .binary_search_by(|_, value| value.0.timestamp.cmp(&message.timestamp))                          {                              Ok(i) => i,                              Err(i) => i,                          }; -                        self.messages.insert_before(index, message.id, message); +                        self.messages +                            .insert_before(index, message.id, (message, false));                      }                  }                  Action::None              }              Message::Message(macaw_message) => {                  if let Some((_, last)) = self.messages.last() { -                    if last.timestamp < macaw_message.timestamp { -                        self.messages.insert(macaw_message.id, macaw_message); +                    if last.0.timestamp < macaw_message.timestamp { +                        self.messages +                            .insert(macaw_message.id, (macaw_message, false));                      } else {                          let index = match self.messages.binary_search_by(|_, value| { -                            value.timestamp.cmp(&macaw_message.timestamp) +                            value.0.timestamp.cmp(&macaw_message.timestamp)                          }) {                              Ok(i) => i,                              Err(i) => i,                          }; -                        self.messages -                            .insert_before(index, macaw_message.id, macaw_message); +                        self.messages.insert_before( +                            index, +                            macaw_message.id, +                            (macaw_message, false), +                        );                      }                  } else { -                    self.messages.insert(macaw_message.id, macaw_message); +                    self.messages +                        .insert(macaw_message.id, (macaw_message, false)); +                } +                Action::None +            } +            Message::MessageHovered(uuid) => { +                if let Some(message) = self.messages.get_mut(&uuid) { +                    message.1 = true;                  }                  Action::None              } +            Message::MessageUnhovered(uuid) => { +                if let Some(message) = self.messages.get_mut(&uuid) { +                    message.1 = false; +                } +                Action::None +            } +            Message::MessageRightClicked(uuid) => todo!(),          }      }      pub fn view(&self) -> Element<Message> { -        let mut messages_view = column![].spacing(8).padding(8); +        let mut messages_view = column![];          let mut last_timestamp = NaiveDateTime::MIN;          let mut last_user: Option<JID> = None;          for (_id, message) in &self.messages { -            let message_timestamp = message.timestamp.naive_local(); +            let message_timestamp = message.0.timestamp.naive_local();              if message_timestamp.date() > last_timestamp.date() {                  messages_view = messages_view.push(date(message_timestamp.date()));              } -            if last_user.as_ref() != Some(&message.from.jid) +            if last_user.as_ref() != Some(&message.0.from.jid)                  || message_timestamp - last_timestamp > TimeDelta::minutes(3)              { -                messages_view = messages_view.push(self.message(message, true)); +                messages_view = messages_view.push(self.message(&message.0, message.1, true));              } else { -                messages_view = messages_view.push(self.message(message, false)); +                messages_view = messages_view.push(self.message(&message.0, message.1, false));              } -            last_user = Some(message.from.jid.clone()); +            last_user = Some(message.0.from.jid.clone());              last_timestamp = message_timestamp;          }          let text_editor = text_editor(&self.new_message) @@ -227,11 +253,17 @@ impl MessageView {          .into()      } -    pub fn message<'a>(&'a self, message: &'a MacawMessage, major: bool) -> Element<'a, Message> { +    pub fn message<'a>( +        &'a self, +        message: &'a MacawMessage, +        hovered: bool, +        major: bool, +        // next_read: bool, +    ) -> Element<'a, Message> {          let timestamp = message.timestamp.naive_local();          let timestamp = timestamp.time().format("%H:%M").to_string(); -        if major { +        let container: Container<Message> = if major {              let nick: String = if let Some(nick) = &message.from.nick {                  nick.to_string()              } else { @@ -239,39 +271,107 @@ impl MessageView {              };              let mut bold = Font::with_name("K2D");              bold.weight = Weight::Bold; -            let mut header = row![text(nick).font(bold), text(timestamp)].spacing(8); -            if let Some(delivery) = message.delivery { -                let icon = match delivery { -                    filamento::chat::Delivery::Sending => Some(Icon::Sending16), -                    filamento::chat::Delivery::Written => None, -                    filamento::chat::Delivery::Sent => Some(Icon::Sent16), -                    filamento::chat::Delivery::Delivered => Some(Icon::Delivered16), -                    filamento::chat::Delivery::Read => Some(Icon::Delivered16), -                    filamento::chat::Delivery::Failed => Some(Icon::Error16Color), -                    filamento::chat::Delivery::Queued => Some(Icon::Sending16), -                }; -                if let Some(icon) = icon { -                    header = header.push(icon); -                } -            } +            let mut thin = Font::with_name("K2D"); +            thin.weight = Weight::Thin; +            let timestamp = text(timestamp).size(12).font(thin); +            let header = row![text(nick).font(bold), timestamp] +                .align_y(Vertical::Bottom) +                .spacing(8);              let message_right = column![header, text(&message.body.body)].spacing(8); -            let mut major_message = row([]); -            if let Some(avatar) = &message.from.avatar { +            let avatar = if let Some(avatar) = &message.from.avatar {                  let mut path = self.file_root.join(avatar);                  path.set_extension("jpg");                  // info!("got avatar: {:?}", path); -                major_message = major_message.push(container(image(path).width(48).height(48))); +                container(image(path).width(48).height(48)) +            } else { +                container("").width(48) +            }; +            let show_delivery = match message.delivery { +                Some(Delivery::Sending) => true, +                Some(Delivery::Failed) => true, +                // TODO: queued icon +                Some(Delivery::Queued) => true, +                _ => hovered, +            }; +            let delivery = if show_delivery { +                message +                    .delivery +                    .map(|delivery| icons::delivery_to_icon_svg(delivery)) +                    .unwrap_or_default() +            } else { +                None +            }; +            let delivery: Container<Message> = if let Some(delivery) = delivery { +                container(delivery) +            } else { +                container("")              } -            major_message = major_message.push(message_right); -            major_message.spacing(8).into() +            .width(16); +            let major_message = row![avatar, message_right, horizontal_space(), delivery]; +            container(major_message.spacing(8))          } else { -            row![ -                container(text(timestamp)).width(48), -                text(&message.body.body) -            ] -            .spacing(8) -            .into() -        } +            let timestamp = if hovered { +                let mut thin = Font::with_name("K2D"); +                thin.weight = Weight::Thin; +                let timestamp = text(timestamp).size(10).font(thin); +                container(timestamp).align_right(48) +            } else { +                container("").width(48) +            }; +            let show_delivery = match message.delivery { +                Some(Delivery::Sending) => true, +                Some(Delivery::Failed) => true, +                // TODO: queued icon +                Some(Delivery::Queued) => true, +                _ => hovered, +            }; +            let delivery = if show_delivery { +                message +                    .delivery +                    .map(|delivery| icons::delivery_to_icon_svg(delivery)) +                    .unwrap_or_default() +            } else { +                None +            }; +            let delivery: Container<Message> = if let Some(delivery) = delivery { +                container(delivery) +            } else { +                container("") +            } +            .width(16); +            container( +                row![ +                    timestamp, +                    text(&message.body.body), +                    horizontal_space(), +                    delivery +                ] +                .align_y(Vertical::Top) +                .spacing(8), +            ) +        }; +        // let overlay = overlay::Element::new(Box::new(Overlay {})); +        mouse_area( +            container +                .width(Length::Fill) +                .style(move |theme| { +                    if hovered { +                        container::Style::default() +                            .background(theme.extended_palette().background.weak.color) +                    } else { +                        container::Style::default() +                    } +                }) +                .padding(Padding { +                    top: 4., +                    right: 8., +                    bottom: 4., +                    left: 8., +                }), +        ) +        .on_enter(Message::MessageHovered(message.id)) +        .on_exit(Message::MessageUnhovered(message.id)) +        .into()      }  } | 
