From c62fbfe5102a52cc2cb0527154a2ed52c1a94e7f Mon Sep 17 00:00:00 2001 From: kieran Date: Tue, 22 Oct 2024 23:03:49 +0100 Subject: [PATCH] feat: ffmpeg image loader --- Cargo.lock | 763 +--------------------------------- Cargo.toml | 7 +- src/app.rs | 1 - src/lib.rs | 13 +- src/link.rs | 8 +- src/note_store.rs | 8 +- src/route/home.rs | 5 +- src/route/login.rs | 10 +- src/route/mod.rs | 5 +- src/route/stream.rs | 11 +- src/services/ffmpeg_loader.rs | 54 +++ src/services/image_cache.rs | 90 +++- src/services/mod.rs | 4 +- src/services/ndb_wrapper.rs | 9 +- src/services/query.rs | 41 +- src/stream_info.rs | 6 +- src/theme.rs | 2 +- src/widgets/avatar.rs | 14 +- src/widgets/button.rs | 10 +- src/widgets/chat.rs | 20 +- src/widgets/chat_message.rs | 36 +- src/widgets/header.rs | 5 +- src/widgets/mod.rs | 14 +- src/widgets/profile.rs | 5 +- src/widgets/stream_list.rs | 10 +- src/widgets/stream_player.rs | 4 +- src/widgets/stream_tile.rs | 62 ++- src/widgets/stream_title.rs | 22 +- src/widgets/username.rs | 2 +- src/widgets/write_chat.rs | 15 +- 30 files changed, 331 insertions(+), 925 deletions(-) create mode 100644 src/services/ffmpeg_loader.rs diff --git a/Cargo.lock b/Cargo.lock index a6e1cd3..7ff038c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,12 +27,6 @@ dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -82,12 +76,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "aligned-vec" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" - [[package]] name = "allocator-api2" version = "0.2.18" @@ -181,12 +169,6 @@ version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" -[[package]] -name = "arbitrary" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" - [[package]] name = "arboard" version = "3.4.1" @@ -202,17 +184,6 @@ dependencies = [ "x11rb", ] -[[package]] -name = "arg_enum_proc_macro" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.79", -] - [[package]] name = "arrayref" version = "0.3.9" @@ -313,29 +284,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "av1-grain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" -dependencies = [ - "anyhow", - "arrayvec", - "log", - "nom", - "num-rational", - "v_frame", -] - -[[package]] -name = "avif-serialize" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e335041290c43101ca215eed6f43ec437eb5a42125573f600fc3fa42b9bddd62" -dependencies = [ - "arrayvec", -] - [[package]] name = "backtrace" version = "0.3.74" @@ -345,7 +293,7 @@ dependencies = [ "addr2line", "cfg-if", "libc", - "miniz_oxide 0.8.0", + "miniz_oxide", "object", "rustc-demangle", "windows-targets 0.52.6", @@ -361,12 +309,6 @@ dependencies = [ "bitcoin_hashes 0.14.0", ] -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -452,12 +394,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22" -[[package]] -name = "bit_field" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" - [[package]] name = "bitcoin" version = "0.32.3" @@ -540,12 +476,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -[[package]] -name = "bitstream-io" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b81e1519b0d82120d2fd469d5bfb2919a9361c48b02d82d04befc1cdd2002452" - [[package]] name = "block" version = "0.1.6" @@ -579,12 +509,6 @@ dependencies = [ "objc2", ] -[[package]] -name = "built" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "236e6289eda5a812bc6b53c3b024039382a2895fbbeef2d748b2931546d392c4" - [[package]] name = "bumpalo" version = "3.16.0" @@ -690,16 +614,6 @@ dependencies = [ "nom", ] -[[package]] -name = "cfg-expr" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" -dependencies = [ - "smallvec", - "target-lexicon", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -816,12 +730,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - [[package]] name = "com" version = "0.6.0" @@ -983,37 +891,12 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - [[package]] name = "crypto-common" version = "0.1.6" @@ -1043,12 +926,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" -[[package]] -name = "data-url" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" - [[package]] name = "digest" version = "0.10.7" @@ -1159,7 +1036,7 @@ dependencies = [ [[package]] name = "egui-video" version = "0.8.0" -source = "git+https://github.com/v0l/egui-video.git?rev=396d0041b437d2354f7a5d4e61c8ce33a69eb3b2#396d0041b437d2354f7a5d4e61c8ce33a69eb3b2" +source = "git+https://github.com/v0l/egui-video.git?rev=eb2675dd5206d064afdd82ea72c0fac083596d86#eb2675dd5206d064afdd82ea72c0fac083596d86" dependencies = [ "anyhow", "atomic", @@ -1211,22 +1088,6 @@ dependencies = [ "winit", ] -[[package]] -name = "egui_extras" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf3c1f5cd8dfe2ade470a218696c66cf556fcfd701e7830fa2e9f4428292a2a1" -dependencies = [ - "ahash", - "egui", - "ehttp", - "enum-map", - "image", - "log", - "mime_guess2", - "resvg", -] - [[package]] name = "egui_glow" version = "0.29.1" @@ -1254,20 +1115,6 @@ dependencies = [ "parking_lot", ] -[[package]] -name = "ehttp" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a81c221a1e4dad06cb9c9deb19aea1193a5eea084e8cd42d869068132bf876" -dependencies = [ - "document-features", - "js-sys", - "ureq", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "either" version = "1.13.0" @@ -1283,27 +1130,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "enum-map" -version = "2.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" -dependencies = [ - "enum-map-derive", - "serde", -] - -[[package]] -name = "enum-map-derive" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.79", -] - [[package]] name = "env_filter" version = "0.1.2" @@ -1372,22 +1198,6 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" -[[package]] -name = "exr" -version = "1.72.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" -dependencies = [ - "bit_field", - "flume", - "half", - "lebe", - "miniz_oxide 0.7.4", - "rayon-core", - "smallvec", - "zune-inflate", -] - [[package]] name = "fdeflate" version = "0.3.5" @@ -1427,22 +1237,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", -] - -[[package]] -name = "float-cmp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" - -[[package]] -name = "flume" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" -dependencies = [ - "spin", + "miniz_oxide", ] [[package]] @@ -1591,16 +1386,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "gif" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" -dependencies = [ - "color_quant", - "weezl", -] - [[package]] name = "gimli" version = "0.31.1" @@ -1778,16 +1563,6 @@ dependencies = [ "bitflags 2.6.0", ] -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] - [[package]] name = "hashbrown" version = "0.14.5" @@ -1824,12 +1599,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - [[package]] name = "hermit-abi" version = "0.3.9" @@ -2025,49 +1794,16 @@ dependencies = [ [[package]] name = "image" -version = "0.25.3" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97eb9a8e0cd5b76afea91d7eecd5cf8338cd44ced04256cf1f800474b227c52" +checksum = "bc144d44a31d753b02ce64093d532f55ff8dc4ebf2ffb8a63c0dda691385acae" dependencies = [ "bytemuck", "byteorder-lite", - "color_quant", - "exr", - "gif", - "image-webp", "num-traits", "png", - "qoi", - "ravif", - "rayon", - "rgb", - "tiff", - "zune-core", - "zune-jpeg", ] -[[package]] -name = "image-webp" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f" -dependencies = [ - "byteorder-lite", - "quick-error", -] - -[[package]] -name = "imagesize" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" - -[[package]] -name = "imgref" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" - [[package]] name = "indexmap" version = "2.6.0" @@ -2100,17 +1836,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "interpolate_name" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.79", -] - [[package]] name = "ipnet" version = "2.10.1" @@ -2183,12 +1908,6 @@ dependencies = [ "libc", ] -[[package]] -name = "jpeg-decoder" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" - [[package]] name = "js-sys" version = "0.3.72" @@ -2215,15 +1934,6 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" -[[package]] -name = "kurbo" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd85a5776cd9500c2e2059c8c76c3b01528566b7fcbaf8098b55a33fc298849b" -dependencies = [ - "arrayvec", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -2236,29 +1946,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" -[[package]] -name = "lebe" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" - [[package]] name = "libc" version = "0.2.160" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0b21006cd1874ae9e650973c565615676dc4a274c965bb0a73796dac838ce4f" -[[package]] -name = "libfuzzer-sys" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" -dependencies = [ - "arbitrary", - "cc", - "once_cell", -] - [[package]] name = "libloading" version = "0.8.5" @@ -2320,15 +2013,6 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" -[[package]] -name = "loop9" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" -dependencies = [ - "imgref", -] - [[package]] name = "lru" version = "0.12.5" @@ -2356,15 +2040,6 @@ dependencies = [ "libc", ] -[[package]] -name = "maybe-rayon" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" -dependencies = [ - "cfg-if", -] - [[package]] name = "memchr" version = "2.7.4" @@ -2410,31 +2085,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess2" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a3333bb1609500601edc766a39b4c1772874a4ce26022f4d866854dc020c41" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -2543,12 +2199,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a88da9dd148bbcdce323dd6ac47d369b4769d4a3b78c6c52389b9269f77932" -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - [[package]] name = "nohash-hasher" version = "0.2.0" @@ -2565,12 +2215,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "noop_proc_macro" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" - [[package]] name = "nostr" version = "0.35.0" @@ -2578,7 +2222,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56db234b2e07901e372f34e9463f91590579cd8e6dbd34ed2ccc7e461e4ba639" dependencies = [ "aes", - "base64 0.22.1", + "base64", "bech32", "bip39", "bitcoin", @@ -2704,16 +2348,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - [[package]] name = "num-derive" version = "0.4.2" @@ -2725,26 +2359,6 @@ dependencies = [ "syn 2.0.79", ] -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -3131,12 +2745,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "pico-args" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" - [[package]] name = "pin-project" version = "1.1.6" @@ -3185,7 +2793,7 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -3284,34 +2892,6 @@ name = "profiling" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" -dependencies = [ - "profiling-procmacros", -] - -[[package]] -name = "profiling-procmacros" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" -dependencies = [ - "quote", - "syn 2.0.79", -] - -[[package]] -name = "qoi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" @@ -3409,87 +2989,12 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rav1e" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" -dependencies = [ - "arbitrary", - "arg_enum_proc_macro", - "arrayvec", - "av1-grain", - "bitstream-io", - "built", - "cfg-if", - "interpolate_name", - "itertools 0.12.1", - "libc", - "libfuzzer-sys", - "log", - "maybe-rayon", - "new_debug_unreachable", - "noop_proc_macro", - "num-derive", - "num-traits", - "once_cell", - "paste", - "profiling", - "rand", - "rand_chacha", - "simd_helpers", - "system-deps", - "thiserror", - "v_frame", - "wasm-bindgen", -] - -[[package]] -name = "ravif" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" -dependencies = [ - "avif-serialize", - "imgref", - "loop9", - "quick-error", - "rav1e", - "rgb", -] - [[package]] name = "raw-window-handle" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "rctree" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b42e27ef78c35d3998403c1d26f3efd9e135d3e5121b0a4845cc5cc27547f4f" - [[package]] name = "redox_syscall" version = "0.4.1" @@ -3549,7 +3054,7 @@ version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures-core", "futures-util", @@ -3587,29 +3092,6 @@ dependencies = [ "windows-registry", ] -[[package]] -name = "resvg" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadccb3d99a9efb8e5e00c16fbb732cbe400db2ec7fc004697ee7d97d86cf1f4" -dependencies = [ - "log", - "pico-args", - "rgb", - "svgtypes", - "tiny-skia", - "usvg", -] - -[[package]] -name = "rgb" -version = "0.8.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" -dependencies = [ - "bytemuck", -] - [[package]] name = "ring" version = "0.17.8" @@ -3635,12 +3117,6 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "roxmltree" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f" - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -3687,7 +3163,6 @@ version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ - "log", "once_cell", "ring", "rustls-pki-types", @@ -3888,15 +3363,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_spanned" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" -dependencies = [ - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3952,30 +3418,6 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" -[[package]] -name = "simd_helpers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" -dependencies = [ - "quote", -] - -[[package]] -name = "simplecss" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a11be7c62927d9427e9f40f3444d5499d868648e2edbc4e2116de69e7ec0e89d" -dependencies = [ - "log", -] - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - [[package]] name = "slab" version = "0.4.9" @@ -4060,9 +3502,6 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] [[package]] name = "spirv" @@ -4084,9 +3523,6 @@ name = "strict-num" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" -dependencies = [ - "float-cmp", -] [[package]] name = "subtle" @@ -4094,16 +3530,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "svgtypes" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e44e288cd960318917cbd540340968b90becc8bc81f171345d706e7a89d9d70" -dependencies = [ - "kurbo", - "siphasher", -] - [[package]] name = "syn" version = "1.0.109" @@ -4135,25 +3561,6 @@ dependencies = [ "futures-core", ] -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr", - "heck", - "pkg-config", - "toml", - "version-compare", -] - -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - [[package]] name = "termcolor" version = "1.4.1" @@ -4193,17 +3600,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "tiff" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" -dependencies = [ - "flate2", - "jpeg-decoder", - "weezl", -] - [[package]] name = "tiny-skia" version = "0.11.4" @@ -4215,7 +3611,6 @@ dependencies = [ "bytemuck", "cfg-if", "log", - "png", "tiny-skia-path", ] @@ -4322,26 +3717,11 @@ dependencies = [ "webpki-roots", ] -[[package]] -name = "toml" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] [[package]] name = "toml_edit" @@ -4350,8 +3730,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", - "serde", - "serde_spanned", "toml_datetime", "winnow", ] @@ -4466,15 +3844,6 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.17" @@ -4530,22 +3899,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "ureq" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" -dependencies = [ - "base64 0.22.1", - "flate2", - "log", - "once_cell", - "rustls", - "rustls-pki-types", - "url", - "webpki-roots", -] - [[package]] name = "url" version = "2.5.2" @@ -4558,50 +3911,6 @@ dependencies = [ "serde", ] -[[package]] -name = "usvg" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b0a51b72ab80ca511d126b77feeeb4fb1e972764653e61feac30adc161a756" -dependencies = [ - "base64 0.21.7", - "log", - "pico-args", - "usvg-parser", - "usvg-tree", - "xmlwriter", -] - -[[package]] -name = "usvg-parser" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd4e3c291f45d152929a31f0f6c819245e2921bfd01e7bd91201a9af39a2bdc" -dependencies = [ - "data-url", - "flate2", - "imagesize", - "kurbo", - "log", - "roxmltree", - "simplecss", - "siphasher", - "svgtypes", - "usvg-tree", -] - -[[package]] -name = "usvg-tree" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee3d202ebdb97a6215604b8f5b4d6ef9024efd623cf2e373a6416ba976ec7d3" -dependencies = [ - "rctree", - "strict-num", - "svgtypes", - "tiny-skia-path", -] - [[package]] name = "utf-8" version = "0.7.6" @@ -4617,17 +3926,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "v_frame" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" -dependencies = [ - "aligned-vec", - "num-traits", - "wasm-bindgen", -] - [[package]] name = "valuable" version = "0.1.0" @@ -4640,12 +3938,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "version-compare" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" - [[package]] name = "version_check" version = "0.9.5" @@ -4900,12 +4192,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "weezl" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" - [[package]] name = "wgpu" version = "22.1.0" @@ -5465,12 +4751,6 @@ version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" -[[package]] -name = "xmlwriter" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" - [[package]] name = "zap_stream_app" version = "0.1.0" @@ -5484,12 +4764,11 @@ dependencies = [ "eframe", "egui", "egui-video", - "egui_extras", "egui_inbox", - "image", "itertools 0.13.0", "libc", "log", + "lru", "nostr-sdk", "nostrdb", "pretty_env_logger", @@ -5526,27 +4805,3 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zune-core" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" - -[[package]] -name = "zune-inflate" -version = "0.2.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "zune-jpeg" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16099418600b4d8f028622f73ff6e3deaabdff330fb9a2a131dea781ee8b0768" -dependencies = [ - "zune-core", -] diff --git a/Cargo.toml b/Cargo.toml index 0191cbe..a3abd9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,6 @@ egui = { version = "0.29.1" } eframe = { version = "0.29.1", default-features = false, features = ["glow", "wgpu", "wayland", "x11", "android-native-activity"] } nostrdb = { git = "https://github.com/damus-io/nostrdb-rs", version = "0.3.4" } nostr-sdk = { version = "0.35.0", features = ["all-nips"] } -egui_extras = { version = "0.29.1", features = ["all_loaders"] } -image = { version = "0.25", features = ["jpeg", "png", "webp"] } log = "0.4.22" pretty_env_logger = "0.5.0" egui_inbox = "0.6.0" @@ -26,11 +24,12 @@ async-trait = "0.1.83" sha2 = "0.10.8" reqwest = { version = "0.12.7", default-features = false, features = ["rustls-tls-native-roots"] } itertools = "0.13.0" +lru = "0.12.5" -egui-video = { git = "https://github.com/v0l/egui-video.git", rev = "396d0041b437d2354f7a5d4e61c8ce33a69eb3b2" } +egui-video = { git = "https://github.com/v0l/egui-video.git", rev = "eb2675dd5206d064afdd82ea72c0fac083596d86" } #egui-video = { path = "../egui-video" } [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.14.1" android-activity = { version = "0.6.0", features = ["native-activity"] } -winit = { version = "0.30.5", features = ["android-native-activity"] } \ No newline at end of file +winit = { version = "0.30.5", features = ["android-native-activity"] } diff --git a/src/app.rs b/src/app.rs index a549329..00cdcb0 100644 --- a/src/app.rs +++ b/src/app.rs @@ -33,7 +33,6 @@ impl ZapStreamApp { .expect("Failed to add relay"); client_clone.connect().await; }); - egui_extras::install_image_loaders(&cc.egui_ctx); let ndb_path = data_path.join("ndb"); std::fs::create_dir_all(&ndb_path).expect("Failed to create ndb directory"); diff --git a/src/lib.rs b/src/lib.rs index 2ecdb77..b7462d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,15 @@ - pub mod app; mod link; +mod note_store; mod note_util; mod route; mod services; mod stream_info; -mod widgets; mod theme; -mod note_store; +mod widgets; -use eframe::Renderer; use crate::app::ZapStreamApp; +use eframe::Renderer; #[cfg(target_os = "android")] use winit::platform::android::activity::AndroidApp; @@ -22,7 +21,9 @@ use winit::platform::android::EventLoopBuilderExtAndroid; #[tokio::main] pub async fn android_main(app: AndroidApp) { std::env::set_var("RUST_BACKTRACE", "full"); - android_logger::init_once(android_logger::Config::default().with_max_level(log::LevelFilter::Info)); + android_logger::init_once( + android_logger::Config::default().with_max_level(log::LevelFilter::Info), + ); let mut options = eframe::NativeOptions::default(); options.renderer = Renderer::Glow; @@ -42,4 +43,4 @@ pub async fn android_main(app: AndroidApp) { options, Box::new(move |cc| Ok(Box::new(ZapStreamApp::new(cc, data_path)))), ); -} \ No newline at end of file +} diff --git a/src/link.rs b/src/link.rs index 8939a66..eb0b1c4 100644 --- a/src/link.rs +++ b/src/link.rs @@ -59,7 +59,13 @@ impl NostrLink { } pub fn from_note(note: &Note<'_>) -> Self { - if note.kind() >= 30_000 && note.kind() < 40_000 && note.get_tag_value("d").and_then(|v| v.variant().str()).is_some() { + if note.kind() >= 30_000 + && note.kind() < 40_000 + && note + .get_tag_value("d") + .and_then(|v| v.variant().str()) + .is_some() + { Self { hrp: NostrLinkType::Coordinate, id: IdOrStr::Str( diff --git a/src/note_store.rs b/src/note_store.rs index c483027..3eb883d 100644 --- a/src/note_store.rs +++ b/src/note_store.rs @@ -9,7 +9,7 @@ pub struct NoteStore<'a> { impl<'a> NoteStore<'a> { pub fn new() -> Self { Self { - events: HashMap::new() + events: HashMap::new(), } } @@ -36,12 +36,10 @@ impl<'a> NoteStore<'a> { } pub fn key(note: &Note<'a>) -> String { - NostrLink::from_note(note) - .to_tag_value() + NostrLink::from_note(note).to_tag_value() } - pub fn iter(&self) -> impl Iterator> { + pub fn iter(&self) -> impl Iterator> { self.events.values() } } - diff --git a/src/route/home.rs b/src/route/home.rs index c5fd8de..65b7230 100644 --- a/src/route/home.rs +++ b/src/route/home.rs @@ -42,8 +42,7 @@ impl NostrWidget for HomePage { let events = NoteStore::from_vec(events); ScrollArea::vertical() - .show(ui, |ui| { - widgets::StreamList::new(&events, services).ui(ui) - }).inner + .show(ui, |ui| widgets::StreamList::new(&events, services).ui(ui)) + .inner } } diff --git a/src/route/login.rs b/src/route/login.rs index 090a638..99bc19d 100644 --- a/src/route/login.rs +++ b/src/route/login.rs @@ -25,10 +25,7 @@ impl NostrWidget for LoginPage { ui.label(RichText::new("Login").size(32.)); ui.label("Pubkey"); ui.text_edit_singleline(&mut self.key); - if Button::new() - .show(ui, |ui| { - ui.label("Login") - }).clicked() { + if Button::new().show(ui, |ui| ui.label("Login")).clicked() { if let Ok(pk) = hex::decode(&self.key) { if let Ok(pk) = pk.as_slice().try_into() { services.action(RouteAction::LoginPubkey(pk)); @@ -41,6 +38,7 @@ impl NostrWidget for LoginPage { if let Some(e) = &self.error { ui.label(RichText::new(e).color(Color32::RED)); } - }).response + }) + .response } -} \ No newline at end of file +} diff --git a/src/route/mod.rs b/src/route/mod.rs index 7465fee..18959ed 100644 --- a/src/route/mod.rs +++ b/src/route/mod.rs @@ -14,8 +14,8 @@ use nostrdb::{Ndb, Transaction}; use std::path::PathBuf; mod home; -mod stream; mod login; +mod stream; #[derive(PartialEq)] pub enum Routes { @@ -123,7 +123,8 @@ impl Router { } else { ui.label("No widget") } - }).response + }) + .response } } diff --git a/src/route/stream.rs b/src/route/stream.rs index f642910..845221b 100644 --- a/src/route/stream.rs +++ b/src/route/stream.rs @@ -25,8 +25,7 @@ impl StreamPage { Self { link, sub, - event: events - .first().map(|n| OwnedNote(n.note_key.as_u64())), + event: events.first().map(|n| OwnedNote(n.note_key.as_u64())), chat: None, player: None, new_msg: WriteChat::new(), @@ -44,7 +43,8 @@ impl NostrWidget for StreamPage { let event = if let Some(k) = &self.event { services .ndb - .get_note_by_key(services.tx, NoteKey::new(k.0)).ok() + .get_note_by_key(services.tx, NoteKey::new(k.0)) + .ok() } else { None }; @@ -79,9 +79,8 @@ impl NostrWidget for StreamPage { // consume rest of space ui.add_space(ui.available_height()); }); - ui.allocate_ui(Vec2::new(w, chat_h), |ui| { - self.new_msg.render(ui, services) - }).response + ui.allocate_ui(Vec2::new(w, chat_h), |ui| self.new_msg.render(ui, services)) + .response } else { ui.label("Loading..") } diff --git a/src/services/ffmpeg_loader.rs b/src/services/ffmpeg_loader.rs new file mode 100644 index 0000000..8ea191f --- /dev/null +++ b/src/services/ffmpeg_loader.rs @@ -0,0 +1,54 @@ +use anyhow::Error; +use egui::ColorImage; +use std::path::PathBuf; + +pub struct FfmpegLoader {} + +impl FfmpegLoader { + pub fn new() -> Self { + Self {} + } + + pub fn load_image(&self, path: PathBuf) -> Result { + unsafe { + let mut demux = egui_video::ffmpeg::demux::Demuxer::new(path.to_str().unwrap()); + let info = demux.probe_input()?; + + let bv = info.best_video(); + if bv.is_none() { + anyhow::bail!("Not a video/image"); + } + let bv = bv.unwrap(); + let mut decode = egui_video::ffmpeg::decode::Decoder::new(); + let rgb = egui_video::ffmpeg_sys_the_third::AVPixelFormat::AV_PIX_FMT_RGB24; + let mut scaler = egui_video::ffmpeg::scale::Scaler::new(rgb); + + let mut n_pkt = 0; + loop { + let (mut pkt, stream) = demux.get_packet()?; + if (*stream).index as usize == bv.index { + let frames = decode.decode_pkt(pkt, stream)?; + if let Some((frame, _)) = frames.first() { + let mut frame = *frame; + let mut frame_rgb = scaler.process_frame( + frame, + (*frame).width as u16, + (*frame).height as u16, + )?; + egui_video::ffmpeg_sys_the_third::av_frame_free(&mut frame); + + let image = egui_video::ffmpeg::video_frame_to_image(frame_rgb); + egui_video::ffmpeg_sys_the_third::av_frame_free(&mut frame_rgb); + return Ok(image); + } + } + egui_video::ffmpeg_sys_the_third::av_packet_free(&mut pkt); + + n_pkt += 1; + if n_pkt > 10 { + anyhow::bail!("No image found"); + } + } + } + } +} diff --git a/src/services/image_cache.rs b/src/services/image_cache.rs index bf3a481..0baada0 100644 --- a/src/services/image_cache.rs +++ b/src/services/image_cache.rs @@ -1,27 +1,47 @@ -use egui::Image; +use crate::services::ffmpeg_loader::FfmpegLoader; +use crate::theme::NEUTRAL_800; +use anyhow::Error; +use eframe::epaint::Color32; +use egui::load::SizedTexture; +use egui::{ColorImage, Context, Image, ImageData, TextureHandle, TextureOptions}; +use itertools::Itertools; use log::{error, info}; +use lru::LruCache; use nostr_sdk::util::hex; use sha2::{Digest, Sha256}; use std::collections::HashSet; use std::fs; +use std::num::NonZeroUsize; +use std::ops::Deref; use std::path::PathBuf; -use std::sync::Arc; -use tokio::sync::Mutex; +use std::sync::{Arc, Mutex}; + +type ImageCacheStore = Arc>>; pub struct ImageCache { - ctx: egui::Context, + ctx: Context, dir: PathBuf, - fetch_lock: Arc>>, + placeholder: TextureHandle, + cache: ImageCacheStore, + fetch_cache: Arc>>, } impl ImageCache { - pub fn new(data_path: PathBuf, ctx: egui::Context) -> Self { + pub fn new(data_path: PathBuf, ctx: Context) -> Self { let out = data_path.join("cache/images"); fs::create_dir_all(&out).unwrap(); + + let placeholder = ctx.load_texture( + "placeholder", + ImageData::from(ColorImage::new([1, 1], NEUTRAL_800)), + TextureOptions::default(), + ); Self { ctx, dir: out, - fetch_lock: Arc::new(Mutex::new(HashSet::new())), + placeholder, + cache: Arc::new(Mutex::new(LruCache::new(NonZeroUsize::new(100).unwrap()))), + fetch_cache: Arc::new(Mutex::new(HashSet::new())), } } @@ -42,29 +62,61 @@ impl ImageCache { U: Into, { let u = url.into(); + if let Ok(mut c) = self.cache.lock() { + if let Some(i) = c.get(&u) { + return Image::from_texture(i); + } + } let path = self.find(&u); if !path.exists() && !u.is_empty() { let path = path.clone(); - let fl = self.fetch_lock.clone(); + let cache = self.cache.clone(); let ctx = self.ctx.clone(); + let fetch_cache = self.fetch_cache.clone(); + let placeholder = self.placeholder.clone(); tokio::spawn(async move { - if fl.lock().await.insert(u.clone()) { + if fetch_cache.lock().unwrap().insert(u.clone()) { info!("Fetching image: {}", &u); - if let Ok(data) = reqwest::get(&u) - .await { - tokio::fs::create_dir_all(path.parent().unwrap()).await.unwrap(); - if let Err(e) = tokio::fs::write(path, data.bytes().await.unwrap()).await { + if let Ok(data) = reqwest::get(&u).await { + tokio::fs::create_dir_all(path.parent().unwrap()) + .await + .unwrap(); + let img_data = data.bytes().await.unwrap(); + if let Err(e) = tokio::fs::write(path.clone(), img_data).await { error!("Failed to write file: {}", e); } - // forget cached url - for t in ctx.loaders().texture.lock().iter() { - t.forget(&u); - } + let t = Self::load_image(&ctx, path, &u) + .await + .unwrap_or(placeholder); + cache.lock().unwrap().put(u.clone(), t); ctx.request_repaint(); } } }); + } else if path.exists() { + let path = path.clone(); + let ctx = self.ctx.clone(); + let cache = self.cache.clone(); + let placeholder = self.placeholder.clone(); + tokio::spawn(async move { + let t = Self::load_image(&ctx, path, &u) + .await + .unwrap_or(placeholder); + cache.lock().unwrap().put(u.clone(), t); + ctx.request_repaint(); + }); } - Image::from_uri(format!("file://{}", path.to_str().unwrap())) + Image::from_texture(&self.placeholder) } -} \ No newline at end of file + + async fn load_image(ctx: &Context, path: PathBuf, key: &str) -> Option { + let mut loader = FfmpegLoader::new(); + match loader.load_image(path) { + Ok(i) => Some(ctx.load_texture(key, ImageData::from(i), TextureOptions::default())), + Err(e) => { + println!("Failed to load image: {}", e); + None + } + } + } +} diff --git a/src/services/mod.rs b/src/services/mod.rs index 686f46e..1142a8e 100644 --- a/src/services/mod.rs +++ b/src/services/mod.rs @@ -1,3 +1,5 @@ +pub mod image_cache; pub mod ndb_wrapper; pub mod query; -pub mod image_cache; \ No newline at end of file + +mod ffmpeg_loader; diff --git a/src/services/ndb_wrapper.rs b/src/services/ndb_wrapper.rs index 22f2f3a..97a38d5 100644 --- a/src/services/ndb_wrapper.rs +++ b/src/services/ndb_wrapper.rs @@ -144,11 +144,12 @@ impl NDBWrapper { // TODO: fix this shit if p.is_none() && self.profiles.lock().unwrap().insert(*pubkey) { - self.query_manager.queue_query("profile", &[ - nostr::Filter::new() + self.query_manager.queue_query( + "profile", + &[nostr::Filter::new() .kinds([Kind::Metadata]) - .authors([PublicKey::from_slice(pubkey).unwrap()]) - ]) + .authors([PublicKey::from_slice(pubkey).unwrap()])], + ) } let sub = None; (p, sub) diff --git a/src/services/query.rs b/src/services/query.rs index b398345..c694a84 100644 --- a/src/services/query.rs +++ b/src/services/query.rs @@ -65,21 +65,24 @@ impl Query { let id = Uuid::new_v4(); // remove filters already sent - next.retain(|f| self.traces.is_empty() || !self.traces.iter().all(|y| y.filters.iter().any(|z| z == f))); + next.retain(|f| { + self.traces.is_empty() || !self.traces.iter().all(|y| y.filters.iter().any(|z| z == f)) + }); // force profile queries into single filter - if next.iter().all(|f| if let Some(k) = &f.kinds { - k.len() == 1 && k.first().unwrap().as_u16() == 0 - } else { - false + if next.iter().all(|f| { + if let Some(k) = &f.kinds { + k.len() == 1 && k.first().unwrap().as_u16() == 0 + } else { + false + } }) { - next = vec![Filter::new() - .kinds([Metadata]) - .authors(next.iter().flat_map(|f| f.authors.as_ref().unwrap().clone())) - ] + next = vec![Filter::new().kinds([Metadata]).authors( + next.iter() + .flat_map(|f| f.authors.as_ref().unwrap().clone()), + )] } - if next.is_empty() { return None; } @@ -166,18 +169,24 @@ where where F: Into>, { - self.queue_into_queries.send(QueueDefer { - id: id.to_string(), - filters: filters.into(), - }).unwrap() + self.queue_into_queries + .send(QueueDefer { + id: id.to_string(), + filters: filters.into(), + }) + .unwrap() } } #[async_trait::async_trait] impl QueryClient for Client { async fn subscribe(&self, id: &str, filters: &[QueryFilter]) -> Result<(), Error> { - self.subscribe_with_id(SubscriptionId::new(id), filters.into(), Some(SubscribeAutoCloseOptions::default())) - .await?; + self.subscribe_with_id( + SubscriptionId::new(id), + filters.into(), + Some(SubscribeAutoCloseOptions::default()), + ) + .await?; Ok(()) } } diff --git a/src/stream_info.rs b/src/stream_info.rs index 0ba07d2..a33deba 100644 --- a/src/stream_info.rs +++ b/src/stream_info.rs @@ -74,11 +74,11 @@ impl<'a> StreamInfo for Note<'a> { } } - fn starts(&self) -> u64 { if let Some(s) = self.get_tag_value("starts") { - s.variant().str() - .map_or(self.created_at(), |v| v.parse::().unwrap_or(self.created_at())) + s.variant().str().map_or(self.created_at(), |v| { + v.parse::().unwrap_or(self.created_at()) + }) } else { self.created_at() } diff --git a/src/theme.rs b/src/theme.rs index 0a26a26..382675e 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -4,4 +4,4 @@ pub const FONT_SIZE: f32 = 13.0; pub const PRIMARY: Color32 = Color32::from_rgb(248, 56, 217); pub const NEUTRAL_500: Color32 = Color32::from_rgb(115, 115, 115); pub const NEUTRAL_800: Color32 = Color32::from_rgb(38, 38, 38); -pub const NEUTRAL_900: Color32 = Color32::from_rgb(23, 23, 23); \ No newline at end of file +pub const NEUTRAL_900: Color32 = Color32::from_rgb(23, 23, 23); diff --git a/src/widgets/avatar.rs b/src/widgets/avatar.rs index 585993d..04787e7 100644 --- a/src/widgets/avatar.rs +++ b/src/widgets/avatar.rs @@ -28,8 +28,7 @@ impl<'a> Avatar<'a> { } pub fn from_profile(p: &'a Option>, svc: &'a ImageCache) -> Self { - let img = p - .map_or(None, |f| f.picture().map(|f| svc.load(f))); + let img = p.map_or(None, |f| f.picture().map(|f| svc.load(f))); Self { image: img, sub: None, @@ -57,10 +56,17 @@ impl<'a> Widget for Avatar<'a> { let size_v = self.size.unwrap_or(40.); let size = Vec2::new(size_v, size_v); match self.image { - Some(img) => img.fit_to_exact_size(size).rounding(Rounding::same(size_v)).ui(ui), + Some(img) => img + .fit_to_exact_size(size) + .rounding(Rounding::same(size_v)) + .ui(ui), None => { let (response, painter) = ui.allocate_painter(size, Sense::click()); - painter.circle_filled(Pos2::new(size_v / 2., size_v / 2.), size_v / 2., Color32::from_rgb(200, 200, 200)); + painter.circle_filled( + Pos2::new(size_v / 2., size_v / 2.), + size_v / 2., + Color32::from_rgb(200, 200, 200), + ); response } } diff --git a/src/widgets/button.rs b/src/widgets/button.rs index bf82494..37db2b5 100644 --- a/src/widgets/button.rs +++ b/src/widgets/button.rs @@ -7,9 +7,7 @@ pub struct Button { impl Button { pub fn new() -> Self { - Self { - color: NEUTRAL_800 - } + Self { color: NEUTRAL_800 } } pub fn show(self, ui: &mut Ui, add_contents: F) -> Response @@ -24,9 +22,11 @@ impl Button { let id = r.response.id; ui.interact( - r.response.on_hover_and_drag_cursor(CursorIcon::PointingHand).rect, + r.response + .on_hover_and_drag_cursor(CursorIcon::PointingHand) + .rect, id, Sense::click(), ) } -} \ No newline at end of file +} diff --git a/src/widgets/chat.rs b/src/widgets/chat.rs index 71360df..741aa69 100644 --- a/src/widgets/chat.rs +++ b/src/widgets/chat.rs @@ -50,11 +50,13 @@ impl NostrWidget for Chat { .map_while(|n| { services .ndb - .get_note_by_key(services.tx, NoteKey::new(n.0)).ok() + .get_note_by_key(services.tx, NoteKey::new(n.0)) + .ok() }) .collect(); - let stream = services.ndb + let stream = services + .ndb .get_note_by_key(services.tx, NoteKey::new(self.stream.0)) .unwrap(); @@ -66,13 +68,17 @@ impl NostrWidget for Chat { .show(ui, |ui| { ui.vertical(|ui| { ui.spacing_mut().item_spacing.y = 8.0; - for ev in events.iter().sorted_by(|a, b| { - a.created_at().cmp(&b.created_at()) - }).tail(20) { + for ev in events + .iter() + .sorted_by(|a, b| a.created_at().cmp(&b.created_at())) + .tail(20) + { ChatMessage::new(&stream, ev, services).ui(ui); } }) - }).response - }).inner + }) + .response + }) + .inner } } diff --git a/src/widgets/chat_message.rs b/src/widgets/chat_message.rs index ea7db81..7b93679 100644 --- a/src/widgets/chat_message.rs +++ b/src/widgets/chat_message.rs @@ -16,8 +16,17 @@ pub struct ChatMessage<'a> { } impl<'a> ChatMessage<'a> { - pub fn new(stream: &'a Note<'a>, ev: &'a Note<'a>, services: &'a RouteServices<'a>) -> ChatMessage<'a> { - ChatMessage { stream, ev, services, profile: services.ndb.fetch_profile(services.tx, ev.pubkey()) } + pub fn new( + stream: &'a Note<'a>, + ev: &'a Note<'a>, + services: &'a RouteServices<'a>, + ) -> ChatMessage<'a> { + ChatMessage { + stream, + ev, + services, + profile: services.ndb.fetch_profile(services.tx, ev.pubkey()), + } } } @@ -29,17 +38,15 @@ impl<'a> Widget for ChatMessage<'a> { job.wrap.break_anywhere = true; let is_host = self.stream.host().eq(self.ev.pubkey()); - let profile = self.services.ndb.get_profile_by_pubkey(self.services.tx, self.ev.pubkey()) + let profile = self + .services + .ndb + .get_profile_by_pubkey(self.services.tx, self.ev.pubkey()) .map_or(None, |p| p.record().profile()); - let name = profile - .map_or("Nostrich", |f| f.name().map_or("Nostrich", |f| f)); + let name = profile.map_or("Nostrich", |f| f.name().map_or("Nostrich", |f| f)); - let name_color = if is_host { - PRIMARY - } else { - NEUTRAL_500 - }; + let name_color = if is_host { PRIMARY } else { NEUTRAL_500 }; let mut format = TextFormat::default(); format.line_height = Some(24.0); @@ -50,10 +57,9 @@ impl<'a> Widget for ChatMessage<'a> { format.color = Color32::WHITE; job.append(self.ev.content(), 5.0, format.clone()); - ui.add(Avatar::from_profile(&profile ,self.services.img_cache).size(24.)); - ui.add(Label::new(job) - .wrap_mode(TextWrapMode::Wrap) - ); - }).response + ui.add(Avatar::from_profile(&profile, self.services.img_cache).size(24.)); + ui.add(Label::new(job).wrap_mode(TextWrapMode::Wrap)); + }) + .response } } diff --git a/src/widgets/header.rs b/src/widgets/header.rs index 2b0f66b..39f95aa 100644 --- a/src/widgets/header.rs +++ b/src/widgets/header.rs @@ -37,10 +37,7 @@ impl NostrWidget for Header { ui.with_layout(Layout::right_to_left(Align::Center), |ui| { if let Some(pk) = services.login { ui.add(Avatar::pubkey(pk, services)); - } else if Button::new() - .show(ui, |ui| { - ui.label("Login") - }).clicked() { + } else if Button::new().show(ui, |ui| ui.label("Login")).clicked() { services.navigate(Routes::LoginPage); } }); diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index ef894f9..78051a7 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -1,16 +1,16 @@ mod avatar; +mod button; mod chat; mod chat_message; mod header; mod profile; -mod stream_tile; mod stream_list; mod stream_player; -mod video_placeholder; +mod stream_tile; mod stream_title; -mod write_chat; mod username; -mod button; +mod video_placeholder; +mod write_chat; use crate::route::RouteServices; use egui::{Response, Ui}; @@ -20,13 +20,13 @@ pub trait NostrWidget { } pub use self::avatar::Avatar; +pub use self::button::Button; pub use self::chat::Chat; pub use self::header::Header; pub use self::profile::Profile; pub use self::stream_list::StreamList; pub use self::stream_player::StreamPlayer; -pub use self::video_placeholder::VideoPlaceholder; pub use self::stream_title::StreamTitle; -pub use self::write_chat::WriteChat; pub use self::username::Username; -pub use self::button::Button; \ No newline at end of file +pub use self::video_placeholder::VideoPlaceholder; +pub use self::write_chat::WriteChat; diff --git a/src/widgets/profile.rs b/src/widgets/profile.rs index 3196761..78179c5 100644 --- a/src/widgets/profile.rs +++ b/src/widgets/profile.rs @@ -1,10 +1,10 @@ use crate::route::RouteServices; use crate::services::image_cache::ImageCache; use crate::services::ndb_wrapper::SubWrapper; +use crate::theme::FONT_SIZE; use crate::widgets::{Avatar, Username}; use egui::{Response, Ui, Widget}; use nostrdb::NdbProfile; -use crate::theme::FONT_SIZE; pub struct Profile<'a> { size: f32, @@ -39,6 +39,7 @@ impl<'a> Widget for Profile<'a> { ui.add(Avatar::from_profile(&self.profile, self.img_cache).size(self.size)); ui.add(Username::new(&self.profile, FONT_SIZE)) - }).response + }) + .response } } diff --git a/src/widgets/stream_list.rs b/src/widgets/stream_list.rs index f8f4862..fed3d6a 100644 --- a/src/widgets/stream_list.rs +++ b/src/widgets/stream_list.rs @@ -23,11 +23,11 @@ impl Widget for StreamList<'_> { .show(ui, |ui| { ui.vertical(|ui| { ui.style_mut().spacing.item_spacing = egui::vec2(0., 20.0); - for event in self.streams.iter() - .sorted_by(|a, b| { - a.status().cmp(&b.status()) - .then(a.starts().cmp(&b.starts()).reverse()) - }) { + for event in self.streams.iter().sorted_by(|a, b| { + a.status() + .cmp(&b.status()) + .then(a.starts().cmp(&b.starts()).reverse()) + }) { ui.add(StreamEvent::new(event, self.services)); } }) diff --git a/src/widgets/stream_player.rs b/src/widgets/stream_player.rs index a9fa3ac..eff4146 100644 --- a/src/widgets/stream_player.rs +++ b/src/widgets/stream_player.rs @@ -11,9 +11,7 @@ impl StreamPlayer { let mut p = Player::new(ctx, url); p.set_debug(true); p.start(); - Self { - player: Some(p) - } + Self { player: Some(p) } } } diff --git a/src/widgets/stream_tile.rs b/src/widgets/stream_tile.rs index a6aa733..3f99c29 100644 --- a/src/widgets/stream_tile.rs +++ b/src/widgets/stream_tile.rs @@ -1,13 +1,15 @@ use crate::link::NostrLink; use crate::route::{RouteServices, Routes}; use crate::stream_info::{StreamInfo, StreamStatus}; -use crate::theme::{NEUTRAL_500, NEUTRAL_900, PRIMARY}; +use crate::theme::{NEUTRAL_800, NEUTRAL_900, PRIMARY}; use crate::widgets::avatar::Avatar; use eframe::epaint::{Rounding, Vec2}; use egui::epaint::RectShape; use egui::load::TexturePoll; -use egui::{vec2, Color32, CursorIcon, FontId, Label, Pos2, Rect, Response, RichText, Sense, TextWrapMode, Ui, Widget}; -use image::Pixel; +use egui::{ + vec2, Color32, CursorIcon, FontId, Label, Pos2, Rect, Response, RichText, Sense, TextWrapMode, + Ui, Widget, +}; use nostrdb::Note; pub struct StreamEvent<'a> { @@ -17,10 +19,7 @@ pub struct StreamEvent<'a> { impl<'a> StreamEvent<'a> { pub fn new(event: &'a Note<'a>, services: &'a RouteServices) -> Self { - Self { - event, - services, - } + Self { event, services } } } impl Widget for StreamEvent<'_> { @@ -33,14 +32,14 @@ impl Widget for StreamEvent<'_> { let w = ui.available_width(); let h = (w / 16.0) * 9.0; - let cover = self.event.image() - .map(|p| self.services.img_cache.load(p)); + let cover = self.event.image().map(|p| self.services.img_cache.load(p)); let (response, painter) = ui.allocate_painter(Vec2::new(w, h), Sense::click()); - if let Some(cover) = cover.map(|c| + if let Some(cover) = cover.map(|c| { c.rounding(Rounding::same(12.)) - .load_for_size(painter.ctx(), Vec2::new(w, h))) { + .load_for_size(painter.ctx(), Vec2::new(w, h)) + }) { match cover { Ok(TexturePoll::Ready { texture }) => { painter.add(RectShape { @@ -54,11 +53,11 @@ impl Widget for StreamEvent<'_> { }); } _ => { - painter.rect_filled(response.rect, 12., NEUTRAL_500); + painter.rect_filled(response.rect, 12., NEUTRAL_800); } } } else { - painter.rect_filled(response.rect, 12., NEUTRAL_500); + painter.rect_filled(response.rect, 12., NEUTRAL_800); } let overlay_label_pad = Vec2::new(5., 5.); @@ -68,20 +67,41 @@ impl Widget for StreamEvent<'_> { } else { NEUTRAL_900 }; - let live_label = painter.layout_no_wrap(live_label_text, FontId::default(), Color32::WHITE); + let live_label = + painter.layout_no_wrap(live_label_text, FontId::default(), Color32::WHITE); let overlay_react = response.rect.shrink(8.0); - let live_label_pos = overlay_react.min + vec2(overlay_react.width() - live_label.rect.width() - (overlay_label_pad.x * 2.), 0.0); - let live_label_background = Rect::from_two_pos(live_label_pos, live_label_pos + live_label.size() + (overlay_label_pad * 2.)); + let live_label_pos = overlay_react.min + + vec2( + overlay_react.width() - live_label.rect.width() - (overlay_label_pad.x * 2.), + 0.0, + ); + let live_label_background = Rect::from_two_pos( + live_label_pos, + live_label_pos + live_label.size() + (overlay_label_pad * 2.), + ); painter.rect_filled(live_label_background, 8., live_label_color); - painter.galley(live_label_pos + overlay_label_pad, live_label, Color32::PLACEHOLDER); + painter.galley( + live_label_pos + overlay_label_pad, + live_label, + Color32::PLACEHOLDER, + ); if let Some(viewers) = self.event.viewers() { - let viewers_label = painter.layout_no_wrap(format!("{} viewers", viewers), FontId::default(), Color32::WHITE); - let rect_start = overlay_react.max - viewers_label.size() - (overlay_label_pad * 2.0); + let viewers_label = painter.layout_no_wrap( + format!("{} viewers", viewers), + FontId::default(), + Color32::WHITE, + ); + let rect_start = + overlay_react.max - viewers_label.size() - (overlay_label_pad * 2.0); let pos = Rect::from_two_pos(rect_start, overlay_react.max); painter.rect_filled(pos, 8., NEUTRAL_900); - painter.galley(rect_start + overlay_label_pad, viewers_label, Color32::PLACEHOLDER); + painter.galley( + rect_start + overlay_label_pad, + viewers_label, + Color32::PLACEHOLDER, + ); } let response = response.on_hover_and_drag_cursor(CursorIcon::PointingHand); if response.clicked() { @@ -98,6 +118,6 @@ impl Widget for StreamEvent<'_> { ui.add(Label::new(title).wrap_mode(TextWrapMode::Truncate)); }) }) - .response + .response } } diff --git a/src/widgets/stream_title.rs b/src/widgets/stream_title.rs index 7aa18d4..a958656 100644 --- a/src/widgets/stream_title.rs +++ b/src/widgets/stream_title.rs @@ -11,9 +11,7 @@ pub struct StreamTitle<'a> { impl<'a> StreamTitle<'a> { pub fn new(event: &'a Note<'a>) -> StreamTitle { - StreamTitle { - event - } + StreamTitle { event } } } @@ -28,15 +26,17 @@ impl<'a> NostrWidget for StreamTitle<'a> { .color(Color32::WHITE); ui.add(Label::new(title.strong()).wrap_mode(TextWrapMode::Truncate)); - Profile::new(self.event.host(), services) - .size(32.) - .ui(ui); + Profile::new(self.event.host(), services).size(32.).ui(ui); - if let Some(summary) = self.event.get_tag_value("summary").and_then(|r| r.variant().str()) { - let summary = RichText::new(summary) - .color(Color32::WHITE); + if let Some(summary) = self + .event + .get_tag_value("summary") + .and_then(|r| r.variant().str()) + { + let summary = RichText::new(summary).color(Color32::WHITE); ui.add(Label::new(summary).wrap_mode(TextWrapMode::Truncate)); } - }).response + }) + .response } -} \ No newline at end of file +} diff --git a/src/widgets/username.rs b/src/widgets/username.rs index f3d4be1..f755bb1 100644 --- a/src/widgets/username.rs +++ b/src/widgets/username.rs @@ -20,4 +20,4 @@ impl<'a> Widget for Username<'a> { let name = RichText::new(name).size(self.size).color(Color32::WHITE); ui.add(Label::new(name).wrap_mode(TextWrapMode::Truncate)) } -} \ No newline at end of file +} diff --git a/src/widgets/write_chat.rs b/src/widgets/write_chat.rs index 20db7f0..4d487af 100644 --- a/src/widgets/write_chat.rs +++ b/src/widgets/write_chat.rs @@ -10,9 +10,7 @@ pub struct WriteChat { impl WriteChat { pub fn new() -> Self { - Self { - msg: String::new(), - } + Self { msg: String::new() } } } @@ -30,18 +28,19 @@ impl NostrWidget for WriteChat { .inner_margin(Margin::symmetric(12., 12.)) .show(ui, |ui| { ui.horizontal(|ui| { - let editor = TextEdit::singleline(&mut self.msg) - .frame(false); + let editor = TextEdit::singleline(&mut self.msg).frame(false); ui.add(editor); if Image::from_bytes("send-03.svg", logo_bytes) .sense(Sense::click()) .ui(ui) - .clicked() { + .clicked() + { info!("Sending: {}", self.msg); self.msg.clear(); } }); }) - }).response + }) + .response } -} \ No newline at end of file +}