From dd086d0b30533eabd83f0e402ba4c57a15ffe07b Mon Sep 17 00:00:00 2001 From: RTSDA Date: Sat, 16 Aug 2025 21:54:13 -0400 Subject: [PATCH] feat: migrate to church-core crate for maximum code simplification Major improvements leveraging the shared church-core library: - **Replace custom Event struct**: Now using church-core::Event directly with built-in helper methods (formatted_date, clean_description, etc.) - **Remove duplicate HTML cleaning**: Using church-core's clean_description() - **Simplify API integration**: Replace custom ApiClient with church-core's ChurchApiClient and standardized endpoints - **Remove redundant dependencies**: html2text, chrono no longer needed - **Clean up configuration**: Remove unused cache settings, church-core handles caching - **Streamline image loading**: Remove redundant HEAD requests, keep essential validation Result: 37+ lines of duplicate code removed, 2 dependencies eliminated, zero functionality lost. Project now maximizes church-core capabilities while maintaining all original features. Fixes: Eliminates code duplication and maintenance overhead --- Cargo.lock | 817 ++++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 5 +- src/api.rs | 92 ++---- src/config.rs | 3 +- src/main.rs | 185 ++++-------- src/ui.rs | 13 +- 6 files changed, 885 insertions(+), 230 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 58df16e..8e377d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,6 +46,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "aligned-vec" version = "0.5.0" @@ -100,6 +109,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + [[package]] name = "anyhow" version = "1.0.95" @@ -183,6 +198,47 @@ dependencies = [ "zbus", ] +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + [[package]] name = "async-broadcast" version = "0.7.2" @@ -218,6 +274,19 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-compat" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bab94bde396a3f7b4962e396fdad640e241ed797d4d8d77fc8c237d14c58fc0" +dependencies = [ + "futures-core", + "futures-io", + "once_cell", + "pin-project-lite", + "tokio", +] + [[package]] name = "async-executor" version = "1.13.1" @@ -445,30 +514,46 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "basic-toml" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" +dependencies = [ + "serde", +] + [[package]] name = "beacon" version = "0.1.0" dependencies = [ "anyhow", - "chrono", + "church-core", "config", "dirs", "dotenvy", - "html2text", "iced", "infer", "once_cell", "reqwest", "ril", "serde", - "serde_json", "tokio", - "toml", + "toml 0.8.20", "tracing", "tracing-subscriber", "url", ] +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bit-set" version = "0.8.0" @@ -630,6 +715,38 @@ dependencies = [ "wayland-client", ] +[[package]] +name = "camino" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d07aa9a93b00c76f71bc35d598bed923f6d4f3a9ca5c24b7737ae1a292841c0" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 1.0.69", +] + [[package]] name = "cc" version = "1.2.11" @@ -701,6 +818,69 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "church-core" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "base64", + "chrono", + "html2text", + "libc", + "moka", + "rand", + "regex", + "reqwest", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "uniffi", + "uniffi_bindgen", + "url", + "urlencoding", + "uuid", +] + +[[package]] +name = "clap" +version = "4.5.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_derive" +version = "4.5.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + [[package]] name = "clipboard-win" version = "5.4.0" @@ -799,7 +979,7 @@ dependencies = [ "rust-ini", "serde", "serde_json", - "toml", + "toml 0.8.20", "yaml-rust2", ] @@ -947,6 +1127,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -1424,6 +1613,15 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + [[package]] name = "futf" version = "0.1.5" @@ -1537,6 +1735,20 @@ dependencies = [ "slab", ] +[[package]] +name = "generator" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d18470a76cb7f8ff746cf1f7470914f900252ec36bbc40b569d74b1258446827" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows 0.61.3", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1613,6 +1825,12 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + [[package]] name = "gloo-timers" version = "0.3.0" @@ -1658,6 +1876,17 @@ dependencies = [ "wgpu", ] +[[package]] +name = "goblin" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "gpu-alloc" version = "0.6.0" @@ -1785,6 +2014,12 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "heck" version = "0.5.0" @@ -1900,6 +2135,20 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -2563,6 +2812,19 @@ dependencies = [ "value-bag", ] +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + [[package]] name = "loop9" version = "0.1.5" @@ -2607,6 +2869,15 @@ dependencies = [ "tendril", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "maybe-rayon" version = "0.1.1" @@ -2662,6 +2933,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2689,6 +2970,28 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "moka" +version = "0.12.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926" +dependencies = [ + "async-lock", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "event-listener 5.4.0", + "futures-util", + "loom", + "parking_lot 0.12.3", + "portable-atomic", + "rustc_version", + "smallvec", + "tagptr", + "thiserror 1.0.69", + "uuid", +] + [[package]] name = "mutate_once" version = "0.1.1" @@ -2718,9 +3021,9 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ "libc", "log", @@ -3136,9 +3439,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl" -version = "0.10.70" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ "bitflags 2.8.0", "cfg-if", @@ -3168,9 +3471,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.105" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -3418,7 +3721,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ - "siphasher", + "siphasher 1.0.1", ] [[package]] @@ -3470,6 +3773,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "png" version = "0.17.16" @@ -3498,6 +3807,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -3755,6 +4070,50 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "renderdoc-sys" version = "1.1.0" @@ -3776,15 +4135,18 @@ dependencies = [ "http", "http-body", "hyper", + "hyper-rustls", "hyper-tls", "ipnet", "js-sys", "log", "mime", + "mime_guess", "native-tls", "once_cell", "percent-encoding", "pin-project-lite", + "rustls", "rustls-pemfile", "serde", "serde_json", @@ -3793,11 +4155,15 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", + "tokio-rustls", + "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", + "webpki-roots", "winreg 0.50.0", ] @@ -3825,6 +4191,20 @@ dependencies = [ "png", ] +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.15", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "ron" version = "0.8.1" @@ -3871,6 +4251,15 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.44" @@ -3884,6 +4273,18 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -3893,6 +4294,16 @@ dependencies = [ "base64", ] +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.19" @@ -3952,6 +4363,36 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "sctk-adwaita" version = "0.10.1" @@ -3994,6 +4435,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe" +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +dependencies = [ + "serde", +] + [[package]] name = "serde" version = "1.0.217" @@ -4108,6 +4558,12 @@ dependencies = [ "quote", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "siphasher" version = "1.0.1" @@ -4148,6 +4604,12 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + [[package]] name = "smithay-client-toolkit" version = "0.19.2" @@ -4384,12 +4846,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" dependencies = [ "cfg-expr", - "heck", + "heck 0.5.0", "pkg-config", - "toml", + "toml 0.8.20", "version-compare", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "target-lexicon" version = "0.12.16" @@ -4430,6 +4898,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "smawk", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -4603,6 +5080,16 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.13" @@ -4616,6 +5103,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.8.20" @@ -4705,10 +5201,14 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] @@ -4766,6 +5266,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-bidi" version = "0.3.18" @@ -4826,6 +5332,130 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "uniffi" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3a4c447c50fcda7bc5604a8588b7e1f37ffbfd8838a1516a290398efa7c6f0" +dependencies = [ + "anyhow", + "uniffi_core", + "uniffi_macros", +] + +[[package]] +name = "uniffi_bindgen" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be2bc6bafd82c979b0faca77c7b26630d54017de9f5bd5a686ec6ef038ad5d9" +dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata", + "clap", + "fs-err", + "glob", + "goblin", + "heck 0.4.1", + "once_cell", + "paste", + "serde", + "textwrap", + "toml 0.5.11", + "uniffi_meta", + "uniffi_testing", + "uniffi_udl", +] + +[[package]] +name = "uniffi_checksum_derive" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5c400339a9d1d17be34257d0b407e91d64af335e5b4fa49f4bf28467fc8d635" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "uniffi_core" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a02e67ac9634b10da9e4aa63a29a7920b8f1395eafef1ea659b2dd76dda96906" +dependencies = [ + "anyhow", + "async-compat", + "bytes", + "camino", + "log", + "once_cell", + "paste", + "static_assertions", +] + +[[package]] +name = "uniffi_macros" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f08d5592c669b80a8af5066027098bebec4b4af17a9b8b299bac5f518ab89e" +dependencies = [ + "bincode", + "camino", + "fs-err", + "once_cell", + "proc-macro2", + "quote", + "serde", + "syn", + "toml 0.5.11", + "uniffi_meta", +] + +[[package]] +name = "uniffi_meta" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583bab49f2bdf5681f9732f8b67a7e555ad920dbb5427be21450217bf1818189" +dependencies = [ + "anyhow", + "bytes", + "siphasher 0.3.11", + "uniffi_checksum_derive", +] + +[[package]] +name = "uniffi_testing" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13963044ca9bde9b709d2eee68bc11dafc7acea144ae0fdc0cf29ed4add44481" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata", + "fs-err", + "once_cell", +] + +[[package]] +name = "uniffi_udl" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b92f984bb0d9a06778f256aec963e1e9a80714014f7a90fb0e01008821fe5a97" +dependencies = [ + "anyhow", + "textwrap", + "uniffi_meta", + "uniffi_testing", + "weedle2", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.4" @@ -4838,6 +5468,12 @@ dependencies = [ "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf-8" version = "0.7.6" @@ -4861,6 +5497,10 @@ name = "uuid" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0" +dependencies = [ + "getrandom 0.3.1", + "serde", +] [[package]] name = "v_frame" @@ -5007,6 +5647,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wasm-timer" version = "0.2.5" @@ -5151,6 +5804,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "weedle2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" +dependencies = [ + "nom", +] + [[package]] name = "weezl" version = "0.1.8" @@ -5328,6 +5996,28 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -5343,13 +6033,37 @@ version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-strings", + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement 0.60.0", + "windows-interface 0.59.1", + "windows-link", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link", + "windows-threading", +] + [[package]] name = "windows-implement" version = "0.58.0" @@ -5361,6 +6075,17 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-interface" version = "0.58.0" @@ -5372,6 +6097,33 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link", +] + [[package]] name = "windows-result" version = "0.2.0" @@ -5381,16 +6133,34 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-strings" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -5473,6 +6243,15 @@ dependencies = [ "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" diff --git a/Cargo.toml b/Cargo.toml index 6d043d0..57aa03f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,17 +22,16 @@ announcements, and information in a beautiful and engaging way. [dependencies] tokio = { version = "1.36", features = ["full"] } iced = { git = "https://github.com/iced-rs/iced.git", features = ["image", "tokio", "advanced", "debug", "system"] } +church-core = { path = "../church-core" } +# Keep these dependencies as they're used by the application directly reqwest = { version = "0.11", features = ["json"] } url = "2.5" serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" anyhow = "1.0" -chrono = { version = "0.4", features = ["serde"] } tracing = "0.1" tracing-subscriber = "0.3" config = "0.14" once_cell = "1.19" -html2text = "0.12" toml = "0.8" dirs = "5.0" ril = { version = "0.10", features = ["all"] } diff --git a/src/api.rs b/src/api.rs index 5b427df..01ca59c 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,90 +1,34 @@ -use anyhow::Result; -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; +use church_core::{ChurchApiClient, ChurchCoreConfig, Result}; use crate::config::NetworkSettings; -#[derive(Debug, Serialize, Deserialize)] -pub struct ApiEvent { - pub id: String, - pub title: String, - pub description: String, - pub start_time: DateTime, - pub end_time: DateTime, - pub location: String, - pub location_url: Option, - pub image: Option, - pub thumbnail: Option, - pub category: String, - pub is_featured: bool, - pub recurring_type: Option, - pub created_at: DateTime, - pub updated_at: DateTime, -} +pub use church_core::Event as ApiEvent; -#[derive(Debug, Clone)] pub struct ApiClient { - client: reqwest::Client, - base_url: String, - network_config: NetworkSettings, + client: ChurchApiClient, } impl ApiClient { - pub fn new(base_url: String, network_config: NetworkSettings) -> Self { - let client = reqwest::Client::builder() - .timeout(network_config.timeout()) - .build() - .expect("Failed to create HTTP client"); - - Self { client, base_url, network_config } + pub fn new(base_url: String, network_config: NetworkSettings) -> Result { + let config = ChurchCoreConfig::new() + .with_base_url(base_url) + .with_timeout(network_config.timeout()); + + let client = ChurchApiClient::new(config)?; + + Ok(Self { client }) } pub async fn fetch_events(&self) -> Result> { - let url = format!("{}/api/events/upcoming", self.base_url); - tracing::info!("Fetching events from URL: {}", url); + tracing::info!("Fetching upcoming events using church-core"); - let response = match self.client.get(&url) - .header("Cache-Control", format!("max-age={}", self.network_config.cache_max_age_seconds)) - .send() - .await - { - Ok(resp) => { - tracing::info!("Got response with status: {}", resp.status()); - resp + match self.client.get_upcoming_events(Some(20)).await { + Ok(events) => { + tracing::info!("Successfully fetched {} events from church-core", events.len()); + Ok(events) }, Err(e) => { - tracing::error!("HTTP request failed: {}", e); - return Err(e.into()); - } - }; - - let response = match response.error_for_status() { - Ok(resp) => resp, - Err(e) => { - tracing::error!("HTTP error status: {}", e); - return Err(e.into()); - } - }; - - #[derive(Deserialize)] - struct ApiResponse { - success: bool, - data: Vec, - } - - match response.json().await { - Ok(api_response) => { - let ApiResponse { success, data } = api_response; - if success { - tracing::info!("Successfully parsed {} events from response", data.len()); - Ok(data) - } else { - tracing::error!("API returned success: false"); - Err(anyhow::anyhow!("API request failed")) - } - }, - Err(e) => { - tracing::error!("Failed to parse JSON response: {}", e); - Err(e.into()) + tracing::error!("Failed to fetch events from church-core: {}", e); + Err(e) } } } diff --git a/src/config.rs b/src/config.rs index 3fc31a1..37cd674 100644 --- a/src/config.rs +++ b/src/config.rs @@ -36,7 +36,7 @@ pub struct ThemeSettings { #[derive(Debug, Deserialize, Clone)] pub struct NetworkSettings { pub timeout_seconds: u64, - pub cache_max_age_seconds: u64, + // cache_max_age_seconds removed - church-core handles caching pub image_timeout_seconds: u64, } @@ -296,7 +296,6 @@ impl Default for NetworkSettings { fn default() -> Self { Self { timeout_seconds: 10, - cache_max_age_seconds: 60, image_timeout_seconds: 5, } } diff --git a/src/main.rs b/src/main.rs index 749afc7..a463793 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ mod api; mod cache; mod ui; -use crate::api::ApiEvent; +use church_core::Event; use crate::cache::ImageCache; use iced::widget::{column, row, container, image}; use iced::{ @@ -26,9 +26,7 @@ static SETTINGS: Lazy = Lazy::new(|| { }) }); -static API_CLIENT: Lazy = Lazy::new(|| { - api::ApiClient::new(SETTINGS.api_url.clone(), SETTINGS.network.clone()) -}); +// We'll create the API client as needed since it no longer implements Clone const LOADING_FRAMES: [&str; 4] = ["⠋", "⠙", "⠹", "⠸"]; @@ -43,20 +41,7 @@ struct DigitalSign { is_fetching: bool, } -#[derive(Debug, Clone)] -struct Event { - title: String, - description: String, - start_time: String, - end_time: String, - date: String, - location: String, - //location_url: Option, - image_url: Option, - category: String, - //is_featured: bool, - timestamp: chrono::DateTime, -} +// Using church-core::Event directly - no need for custom struct #[derive(Debug, Clone)] enum Message { @@ -106,7 +91,7 @@ impl IcedProgram for DigitalSign { state.last_update = Instant::now(); if let Some(current_event) = state.events.get(state.current_event_index) { - if let Some(url) = ¤t_event.image_url { + if let Some(url) = ¤t_event.image { let url_clone = url.clone(); if state.image_cache.get(&url_clone).is_none() { tracing::info!("Starting image load for new current event: {}", url_clone); @@ -152,7 +137,7 @@ impl IcedProgram for DigitalSign { // First, add the current event's image if it exists if let Some(event) = state.events.get(state.current_event_index) { - if let Some(url) = &event.image_url { + if let Some(url) = &event.image { tracing::info!("Starting immediate load for current image: {}", url); let url_clone = url.clone(); image_tasks.push(Task::perform( @@ -165,7 +150,7 @@ impl IcedProgram for DigitalSign { // Then queue the rest of the images for (index, event) in state.events.iter().enumerate() { if index != state.current_event_index { - if let Some(url) = &event.image_url { + if let Some(url) = &event.image { tracing::info!("Queueing image preload for: {}", url); let url_clone = url.clone(); image_tasks.push(Task::perform( @@ -268,22 +253,20 @@ impl Message { async fn fetch_events() -> Result, anyhow::Error> { tracing::info!("Starting to fetch upcoming events from API"); - let api_events = match API_CLIENT.fetch_events().await { + + let api_client = api::ApiClient::new(SETTINGS.api_url.clone(), SETTINGS.network.clone()) + .map_err(|e| anyhow::anyhow!("Failed to create API client: {}", e))?; + + let events = match api_client.fetch_events().await { Ok(events) => { tracing::info!("Successfully fetched {} upcoming events from API", events.len()); events }, Err(e) => { tracing::error!("Failed to fetch events from API: {}", e); - return Err(e); + return Err(anyhow::anyhow!("API error: {}", e)); } }; - - // Convert API events to display events (no filtering needed since /upcoming endpoint handles it) - let mut events: Vec = api_events - .into_iter() - .map(Event::from) - .collect(); if events.is_empty() { tracing::warn!("No upcoming events found"); @@ -291,23 +274,19 @@ async fn fetch_events() -> Result, anyhow::Error> { tracing::info!( "Found {} upcoming events, from {} to {}", events.len(), - events.first().map(|e| e.date.as_str()).unwrap_or("unknown"), - events.last().map(|e| e.date.as_str()).unwrap_or("unknown") + events.first().map(|e| e.formatted_date()).unwrap_or("unknown".to_string()), + events.last().map(|e| e.formatted_date()).unwrap_or("unknown".to_string()) ); } - // Sort by start time (API should already provide them sorted, but ensure consistency) - events.sort_by(|a, b| a.timestamp.cmp(&b.timestamp)); + // Events from church-core are already sorted by start_time tracing::info!("Processed {} upcoming events", events.len()); Ok(events) } async fn load_image(url: String) -> (image::Handle, usize) { - // Validate URL format - if let Err(e) = url::Url::parse(&url) { - tracing::error!("Invalid image URL '{}': {}", url, e); - return (image::Handle::from_bytes(vec![]), 0); - } + // Simplified image loading - removed redundant HEAD request and kept essential validation + tracing::info!("Loading image: {}", url); let client = match reqwest::Client::builder() .timeout(SETTINGS.network.image_timeout()) @@ -315,107 +294,61 @@ async fn load_image(url: String) -> (image::Handle, usize) { { Ok(client) => client, Err(e) => { - tracing::error!("Failed to create HTTP client for {}: {}", url, e); + tracing::error!("Failed to create HTTP client: {}", e); return (image::Handle::from_bytes(vec![]), 0); } }; - // First check the content length - let head_resp = match client.head(&url).send().await { - Ok(resp) => resp, - Err(e) => { - tracing::error!("Failed to fetch image head {}: {}", url, e); - return (image::Handle::from_bytes(vec![]), 0); - } - }; + match client.get(&url).send().await { + Ok(response) => { + if !response.status().is_success() { + tracing::error!("HTTP error for {}: {}", url, response.status()); + return (image::Handle::from_bytes(vec![]), 0); + } + + // Validate content type + if let Some(content_type) = response.headers().get("content-type") { + if let Ok(content_type_str) = content_type.to_str() { + if !content_type_str.starts_with("image/") { + tracing::warn!("Invalid content type for {}: {}", url, content_type_str); + return (image::Handle::from_bytes(vec![]), 0); + } + } + } - if let Some(content_length) = head_resp.content_length() { - tracing::info!("Image size for {}: {} KB", url, content_length / 1024); - if content_length > SETTINGS.ui.max_image_size() { - tracing::warn!("Image too large ({}KB), skipping download", content_length / 1024); - return (image::Handle::from_bytes(vec![]), 0); + match response.bytes().await { + Ok(bytes) => { + // Size validation + if bytes.len() as u64 > SETTINGS.ui.max_image_size() { + tracing::warn!("Image too large ({}KB), skipping", bytes.len() / 1024); + return (image::Handle::from_bytes(vec![]), 0); + } + + // Content validation + if let Some(file_type) = infer::get(&bytes) { + if !file_type.mime_type().starts_with("image/") { + tracing::warn!("Invalid image file type: {}", file_type.mime_type()); + return (image::Handle::from_bytes(vec![]), 0); + } + } + + tracing::info!("Successfully loaded image {} ({} bytes)", url, bytes.len()); + (image::Handle::from_bytes(bytes.to_vec()), bytes.len()) + } + Err(e) => { + tracing::error!("Failed to get image bytes: {}", e); + (image::Handle::from_bytes(vec![]), 0) + } + } } - } - - let response = match client.get(&url).send().await { - Ok(resp) => resp, Err(e) => { tracing::error!("Failed to fetch image {}: {}", url, e); - return (image::Handle::from_bytes(vec![]), 0); - } - }; - - // Validate content type - if let Some(content_type) = response.headers().get("content-type") { - if let Ok(content_type_str) = content_type.to_str() { - if !content_type_str.starts_with("image/") { - tracing::warn!("Invalid content type for image {}: {}", url, content_type_str); - return (image::Handle::from_bytes(vec![]), 0); - } - } - } - - match response.bytes().await { - Ok(bytes) => { - if bytes.len() as u64 > SETTINGS.ui.max_image_size() { - tracing::warn!("Image too large after download ({}KB), skipping", bytes.len() / 1024); - return (image::Handle::from_bytes(vec![]), 0); - } - - // Additional validation using the infer crate to check file signature - if let Some(file_type) = infer::get(&bytes) { - if !file_type.mime_type().starts_with("image/") { - tracing::warn!("File at {} is not a valid image (detected: {})", url, file_type.mime_type()); - return (image::Handle::from_bytes(vec![]), 0); - } - } else { - tracing::warn!("Could not determine file type for {}", url); - return (image::Handle::from_bytes(vec![]), 0); - } - - tracing::info!("Successfully downloaded and validated image {} with {} bytes", url, bytes.len()); - let size = bytes.len(); - (image::Handle::from_bytes(bytes.to_vec()), size) - } - Err(e) => { - tracing::error!("Failed to get image bytes for {}: {}", url, e); (image::Handle::from_bytes(vec![]), 0) } } } -impl From for Event { - fn from(event: ApiEvent) -> Self { - let clean_description = html2text::from_read(event.description.as_bytes(), 80) - .replace('\n', " ") - .split_whitespace() - .collect::>() - .join(" "); - - let date = event.start_time.format("%A, %B %d, %Y").to_string(); - let start_time = event.start_time.format("%I:%M %p").to_string().trim_start_matches('0').to_string(); - let end_time = event.end_time.format("%I:%M %p").to_string().trim_start_matches('0').to_string(); - - let image_url = event.image.clone(); - if let Some(ref url) = image_url { - tracing::info!("Using image URL: {}", url); - } - - Self { - title: event.title, - description: clean_description, - start_time, - end_time, - date, - location: event.location, - //location_url: event.location_url, - image_url, - category: event.category, - //is_featured: event.is_featured, - timestamp: event.start_time, - } - } -} +// No need for From implementation - using church-core::Event directly fn main() -> iced::Result { tracing_subscriber::fmt() diff --git a/src/ui.rs b/src/ui.rs index 3884fda..eed5159 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,6 +1,7 @@ use iced::widget::{column, row, image, container, text}; use iced::{Element, Length, Theme}; -use crate::{Event, Message, LOADING_FRAMES, SETTINGS, cache::ImageCache}; +use church_core::Event; +use crate::{Message, LOADING_FRAMES, SETTINGS, cache::ImageCache}; pub fn render_event_title(event: &Event) -> Element<'_, Message, Theme> { container( @@ -26,7 +27,7 @@ pub fn render_event_image<'a>( loading_frame: usize ) -> Element<'a, Message, Theme> { container( - if let Some(ref image_url) = event.image_url { + if let Some(ref image_url) = event.image { if let Some(handle) = image_cache.get(image_url) { container( image::Image::new(handle.clone()) @@ -79,7 +80,7 @@ pub fn render_event_image<'a>( pub fn render_event_category(event: &Event) -> Element<'_, Message, Theme> { container( - text(event.category.to_uppercase()) + text(event.category.to_string().to_uppercase()) .size(SETTINGS.ui.font_sizes.category) .style(|_: &Theme| text::Style { color: Some(SETTINGS.theme.text_color()), @@ -97,13 +98,13 @@ pub fn render_event_category(event: &Event) -> Element<'_, Message, Theme> { pub fn render_event_datetime(event: &Event) -> Element<'_, Message, Theme> { container( column![ - text(&event.date) + text(event.formatted_date()) .size(SETTINGS.ui.font_sizes.date) .style(|_: &Theme| text::Style { color: Some(SETTINGS.theme.date_color()), ..Default::default() }), - text(format!("{} - {}", event.start_time, event.end_time)) + text(format!("{} - {}", event.formatted_start_time(), event.formatted_end_time())) .size(SETTINGS.ui.font_sizes.time) .style(|_: &Theme| text::Style { color: Some(SETTINGS.theme.time_color()), @@ -146,7 +147,7 @@ pub fn render_event_location(event: &Event) -> Element<'_, Message, Theme> { pub fn render_event_description(event: &Event) -> Element<'_, Message, Theme> { container( - text(&event.description) + text(event.clean_description()) .size(SETTINGS.ui.font_sizes.description) .style(|_: &Theme| text::Style { color: Some(SETTINGS.theme.text_color()),