diff --git a/Cargo.lock b/Cargo.lock index f431833..2e0fa12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -730,12 +730,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "base64ct" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" - [[package]] name = "basic-toml" version = "0.1.10" @@ -832,6 +826,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + [[package]] name = "block2" version = "0.5.1" @@ -1159,6 +1162,12 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" + [[package]] name = "cocoa" version = "0.25.0" @@ -1237,12 +1246,6 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e57e3272f0190c3f1584272d613719ba5fc7df7f4942fe542e63d949cf3a649b" -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - [[package]] name = "core-foundation" version = "0.9.4" @@ -1578,6 +1581,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + [[package]] name = "css-color" version = "0.2.8" @@ -1628,6 +1640,15 @@ dependencies = [ "dtor", ] +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + [[package]] name = "cursor-icon" version = "1.2.0" @@ -1731,17 +1752,6 @@ dependencies = [ "libdbus-sys", ] -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - [[package]] name = "deranged" version = "0.5.8" @@ -1809,10 +1819,19 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.0", + "crypto-common 0.2.2", + "ctutils", ] [[package]] @@ -2101,13 +2120,12 @@ dependencies = [ [[package]] name = "etcetera" -version = "0.8.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96" dependencies = [ "cfg-if", - "home", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -2308,9 +2326,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" dependencies = [ "futures-core", "futures-sink", @@ -3086,8 +3104,6 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "allocator-api2", - "equivalent", "foldhash 0.1.5", ] @@ -3110,11 +3126,11 @@ checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "hashlink" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230" dependencies = [ - "hashbrown 0.15.5", + "hashbrown 0.16.1", ] [[package]] @@ -3149,20 +3165,20 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" [[package]] name = "hkdf" -version = "0.12.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" dependencies = [ "hmac", ] [[package]] name = "hmac" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" dependencies = [ - "digest", + "digest 0.11.3", ] [[package]] @@ -3232,6 +3248,15 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "hybrid-array" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "1.9.0" @@ -4199,9 +4224,6 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] [[package]] name = "leb128fmt" @@ -4562,12 +4584,12 @@ dependencies = [ [[package]] name = "md-5" -version = "0.10.6" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" dependencies = [ "cfg-if", - "digest", + "digest 0.11.3", ] [[package]] @@ -4909,22 +4931,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-bigint-dig" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" -dependencies = [ - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.6", - "smallvec", - "zeroize", -] - [[package]] name = "num-conv" version = "0.2.1" @@ -4951,17 +4957,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-rational" version = "0.4.2" @@ -5297,7 +5292,7 @@ dependencies = [ "serde_json", "serde_repr", "serde_with", - "sha2", + "sha2 0.10.9", "thiserror 2.0.18", "time", "tokio", @@ -5544,15 +5539,6 @@ dependencies = [ "rustc_version", ] -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - [[package]] name = "percent-encoding" version = "2.3.2" @@ -5705,27 +5691,6 @@ dependencies = [ "futures-io", ] -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - [[package]] name = "pkg-config" version = "0.3.33" @@ -6060,8 +6025,6 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ - "libc", - "rand_chacha 0.3.1", "rand_core 0.6.4", ] @@ -6071,7 +6034,7 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ - "rand_chacha 0.9.0", + "rand_chacha", "rand_core 0.9.5", ] @@ -6086,16 +6049,6 @@ dependencies = [ "rand_core 0.10.1", ] -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - [[package]] name = "rand_chacha" version = "0.9.0" @@ -6111,9 +6064,6 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.17", -] [[package]] name = "rand_core" @@ -6195,7 +6145,7 @@ dependencies = [ "paste", "profiling", "rand 0.9.4", - "rand_chacha 0.9.0", + "rand_chacha", "simd_helpers", "thiserror 2.0.18", "v_frame", @@ -6551,26 +6501,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "rsa" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core 0.6.4", - "signature", - "spki", - "subtle", - "zeroize", -] - [[package]] name = "rtrb" version = "0.3.4" @@ -6607,7 +6537,7 @@ version = "8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1" dependencies = [ - "sha2", + "sha2 0.10.9", "walkdir", ] @@ -7056,7 +6986,18 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -7067,7 +7008,18 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -7095,16 +7047,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core 0.6.4", -] - [[package]] name = "simd-adler32" version = "0.3.9" @@ -7291,21 +7233,11 @@ dependencies = [ "bitflags 2.11.1", ] -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - [[package]] name = "sqlx" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +checksum = "378620ccc25c62c89d8be1c819e76a88d59bdcc3304733330788948e619bfd71" dependencies = [ "sqlx-core", "sqlx-macros", @@ -7316,12 +7248,14 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +checksum = "05b44e85bf579a8eeb4ceaa77a3a523baf2bf0e9bac7e40f405d537b5d2d5ccb" dependencies = [ "base64 0.22.1", "bytes", + "cfg-if", + "chrono", "crc", "crossbeam-queue", "either", @@ -7330,16 +7264,15 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "hashlink", "indexmap 2.14.0", "log", "memchr", - "once_cell", "percent-encoding", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "thiserror 2.0.18", "tokio", @@ -7350,9 +7283,9 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +checksum = "bd2b84f2bc39a5705ef27ec785a11c934a41bbd4a24941e257927cddc26b60bf" dependencies = [ "proc-macro2", "quote", @@ -7363,81 +7296,68 @@ dependencies = [ [[package]] name = "sqlx-macros-core" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +checksum = "fb8d96de5fdc85a5c4ec813432b523ec637e80ba98f046555f75f7908ddac7c3" dependencies = [ + "cfg-if", "dotenvy", "either", "heck 0.5.0", "hex", - "once_cell", "proc-macro2", "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sqlx-core", "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", "syn", + "thiserror 2.0.18", "tokio", "url", ] [[package]] name = "sqlx-mysql" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +checksum = "90b8020fe17c5f2c245bfa2505d7ef59c5604839527c740266ad2214acebea27" dependencies = [ - "atoi", - "base64 0.22.1", "bitflags 2.11.1", "byteorder", "bytes", + "chrono", "crc", - "digest", + "digest 0.11.3", "dotenvy", "either", - "futures-channel", "futures-core", - "futures-io", "futures-util", "generic-array", - "hex", - "hkdf", - "hmac", - "itoa", "log", - "md-5", - "memchr", - "once_cell", "percent-encoding", - "rand 0.8.6", - "rsa", "serde", - "sha1", - "sha2", - "smallvec", + "sha1 0.11.0", + "sha2 0.11.0", "sqlx-core", - "stringprep", "thiserror 2.0.18", "tracing", - "whoami", ] [[package]] name = "sqlx-postgres" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +checksum = "87a2bdd6e83f6b3ea525ca9fee568030508b58355a43d0b2c1674d5f79dcd65e" dependencies = [ "atoi", "base64 0.22.1", "bitflags 2.11.1", "byteorder", + "chrono", "crc", "dotenvy", "etcetera", @@ -7447,16 +7367,14 @@ dependencies = [ "hex", "hkdf", "hmac", - "home", "itoa", "log", "md-5", "memchr", - "once_cell", - "rand 0.8.6", + "rand 0.10.1", "serde", "serde_json", - "sha2", + "sha2 0.11.0", "smallvec", "sqlx-core", "stringprep", @@ -7467,12 +7385,14 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +checksum = "488e99c397a62007e4229aec669a179816339afc6d2620ca6fa420dbee2e982c" dependencies = [ "atoi", + "chrono", "flume", + "form_urlencoded", "futures-channel", "futures-core", "futures-executor", @@ -7482,7 +7402,6 @@ dependencies = [ "log", "percent-encoding", "serde", - "serde_urlencoded", "sqlx-core", "thiserror 2.0.18", "tracing", @@ -8463,7 +8382,7 @@ dependencies = [ "httparse", "log", "rand 0.9.4", - "sha1", + "sha1 0.10.6", "thiserror 2.0.18", "utf-8", ] @@ -8811,12 +8730,6 @@ dependencies = [ "wit-bindgen 0.51.0", ] -[[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - [[package]] name = "wasm-bindgen" version = "0.2.121" @@ -9254,13 +9167,9 @@ dependencies = [ [[package]] name = "whoami" -version = "1.6.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" -dependencies = [ - "libredox", - "wasite", -] +checksum = "998767ef88740d1f5b0682a9c53c24431453923962269c2db68ee43788c5a40d" [[package]] name = "winapi" diff --git a/Cargo.toml b/Cargo.toml index 7db5aff..adbef75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ tracing-subscriber = { version = "0.3.18", features = ["fmt", "std", "chrono", " strum = "0.26.3" strum_macros = "0.26.4" ron = "0.8.1" -sqlx = { version = "0.8.2", features = ["sqlite", "runtime-tokio"] } +sqlx = { version = "0.9", features = ["sqlite", "sqlite-deserialize", "runtime-tokio", "chrono"] } dirs = "6.0.0" tokio = "1.41.1" crisp = { git = "https://git.tfcconnection.org/chris/crisp", version = "0.1.3" } diff --git a/migrations/20260527180153_access_time.sql b/migrations/20260527180153_access_time.sql new file mode 100644 index 0000000..e55fe93 --- /dev/null +++ b/migrations/20260527180153_access_time.sql @@ -0,0 +1,20 @@ +-- Add migration script here +ALTER TABLE songs +ADD COLUMN created_at INTEGER; +ALTER TABLE songs +ADD COLUMN accessed_at INTEGER; + +ALTER TABLE images +ADD COLUMN created_at INTEGER; +ALTER TABLE images +ADD COLUMN accessed_at INTEGER; + +ALTER TABLE videos +ADD COLUMN created_at INTEGER; +ALTER TABLE videos +ADD COLUMN accessed_at INTEGER; + +ALTER TABLE presentations +ADD COLUMN created_at INTEGER; +ALTER TABLE presentations +ADD COLUMN accessed_at INTEGER; diff --git a/rust-analyzer.toml b/rust-analyzer.toml index dd82a4d..f457f4a 100644 --- a/rust-analyzer.toml +++ b/rust-analyzer.toml @@ -1,5 +1,5 @@ -[lru] -capacity = 64 +# [lru] +# capacity = 64 [semanticHighlighting] operator.enable = false diff --git a/src/core/images.rs b/src/core/images.rs index be44eda..5025498 100644 --- a/src/core/images.rs +++ b/src/core/images.rs @@ -1,3 +1,4 @@ +use crate::core::model::Sort; use crate::{Background, Slide, SlideBuilder, TextAlignment}; use super::content::Content; @@ -8,7 +9,8 @@ use crisp::types::{Keyword, Symbol, Value}; use itertools::Itertools; use miette::{IntoDiagnostic, Result, miette}; use serde::{Deserialize, Serialize}; -use sqlx::{SqliteConnection, SqlitePool, query, query_as}; +use sqlx::types::chrono::{DateTime, Local}; +use sqlx::{AssertSqlSafe, SqliteConnection, SqlitePool, query, query_as}; use std::mem::replace; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -19,6 +21,10 @@ pub struct Image { pub id: i32, pub title: String, pub path: PathBuf, + #[serde(skip)] + pub created_at: DateTime, + #[serde(skip)] + pub accessed_at: DateTime, } impl From for Image { @@ -33,6 +39,8 @@ impl From for Image { id: 0, title, path: value.canonicalize().unwrap_or(value), + created_at: Local::now(), + accessed_at: Local::now(), } } } @@ -150,6 +158,7 @@ impl Model { let mut model = Self { items: vec![], kind: LibraryKind::Image, + sorting_method: Sort::AccessTime, }; let mut db = db.acquire().await.expect("probs"); @@ -161,7 +170,7 @@ impl Model { pub async fn load_from_db(&mut self, db: &mut SqliteConnection) { let result = query_as!( Image, - r#"SELECT title as "title!", file_path as "path!", id as "id: i32" from images"# + r#"SELECT title as "title!", file_path as "path!", id as "id: i32", accessed_at as "accessed_at!: DateTime", created_at as "created_at!: DateTime" from images"# ) .fetch_all(db) .await; @@ -176,6 +185,23 @@ impl Model { } } } + + pub fn sort(&mut self) { + match self.sorting_method { + Sort::AccessTime => { + self.items.sort_by(|a, b| b.accessed_at.cmp(&a.accessed_at)) + } + Sort::CreatedTime => todo!(), + Sort::Title => todo!(), + Sort::Secondary => todo!(), + } + } + + pub fn set_sort(mut self, method: Sort) -> Self { + self.sorting_method = method; + self.sort(); + self + } } pub async fn remove_images( @@ -193,7 +219,7 @@ pub async fn remove_images( ids.iter().map(ToString::to_string).join(", ") ); - query(&delete) + query(AssertSqlSafe(delete)) .execute(&*db) .await .into_diagnostic() @@ -280,7 +306,7 @@ pub async fn update_image( } pub async fn get_from_db(database_id: i32, db: &mut SqliteConnection) -> Result { - query_as!(Image, r#"SELECT title as "title!", file_path as "path!", id as "id: i32" from images where id = ?"#, database_id).fetch_one(db).await.into_diagnostic() + query_as!(Image, r#"SELECT title as "title!", file_path as "path!", id as "id: i32", accessed_at as "accessed_at!: DateTime", created_at as "created_at!: DateTime" from images where id = ?"#, database_id).fetch_one(db).await.into_diagnostic() } #[cfg(test)] @@ -301,6 +327,7 @@ mod test { let mut image_model: Model = Model { items: vec![], kind: LibraryKind::Image, + sorting_method: Sort::AccessTime, }; let mut db = add_db() .await @@ -323,6 +350,7 @@ mod test { let mut image_model: Model = Model { items: vec![], kind: LibraryKind::Image, + sorting_method: Sort::AccessTime, }; let result = image_model.add_item(image.clone()); let new_image = test_image("A newer image".into()); diff --git a/src/core/model.rs b/src/core/model.rs index 7482709..5417557 100644 --- a/src/core/model.rs +++ b/src/core/model.rs @@ -13,6 +13,7 @@ use tracing::debug; pub struct Model { pub items: Vec, pub kind: LibraryKind, + pub sorting_method: Sort, } #[derive(Debug, Clone, PartialEq, Eq, Copy, Hash, Serialize, Deserialize)] @@ -23,6 +24,14 @@ pub enum LibraryKind { Presentation, } +#[derive(Debug, Clone, Eq, PartialEq, Copy, Serialize, Deserialize)] +pub enum Sort { + AccessTime, + CreatedTime, + Title, + Secondary, // This can be author or file name +} + #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct KindWrapper(pub (LibraryKind, i32)); diff --git a/src/core/presentations.rs b/src/core/presentations.rs index 4429314..28f9efa 100644 --- a/src/core/presentations.rs +++ b/src/core/presentations.rs @@ -6,12 +6,14 @@ use mupdf::{Colorspace, Document, Matrix}; use serde::{Deserialize, Serialize}; use sqlx::prelude::FromRow; use sqlx::sqlite::SqliteRow; -use sqlx::{Row, SqliteConnection, SqlitePool, query}; +use sqlx::types::chrono::{DateTime, Local}; +use sqlx::{AssertSqlSafe, Row, SqliteConnection, SqlitePool, query}; use std::mem::replace; use std::path::{Path, PathBuf}; use std::sync::Arc; use tracing::{debug, error}; +use crate::core::model::Sort; use crate::{Background, Slide, SlideBuilder, TextAlignment}; use super::content::Content; @@ -36,6 +38,10 @@ pub struct Presentation { pub title: String, pub path: PathBuf, pub kind: PresKind, + #[serde(skip)] + pub created_at: DateTime, + #[serde(skip)] + pub accessed_at: DateTime, } impl Eq for Presentation {} @@ -89,6 +95,8 @@ impl From for Presentation { title, path: value.canonicalize().unwrap_or(value), kind, + created_at: Local::now(), + accessed_at: Local::now(), } } } @@ -280,6 +288,8 @@ impl FromRow<'_, SqliteRow> for Presentation { ending_index: row.try_get(5)?, } }, + created_at: Local::now(), + accessed_at: Local::now(), }) } } @@ -289,6 +299,7 @@ impl Model { let mut model = Self { items: vec![], kind: LibraryKind::Presentation, + sorting_method: Sort::AccessTime, }; model.load_from_db(db).await; model @@ -296,7 +307,7 @@ impl Model { pub async fn load_from_db(&mut self, db: Arc) { let result = query!( - r#"SELECT id as "id: i32", title, file_path as "path", html, starting_index, ending_index from presentations"# + r#"SELECT id as "id: i32", title, file_path as "path", html, starting_index, ending_index, accessed_at as "accessed_at!: DateTime", created_at as "created_at!: DateTime" from presentations"# ) .fetch_all(&*db) .await; @@ -341,12 +352,31 @@ impl Model { }, ) }, + created_at: presentation.created_at, + accessed_at: presentation.accessed_at, }); } } Err(e) => error!("There was an error in converting presentations: {e}"), } } + + pub fn sort(&mut self) { + match self.sorting_method { + Sort::AccessTime => { + self.items.sort_by(|a, b| b.accessed_at.cmp(&a.accessed_at)) + } + Sort::CreatedTime => todo!(), + Sort::Title => todo!(), + Sort::Secondary => todo!(), + } + } + + pub fn set_sort(mut self, method: Sort) -> Self { + self.sorting_method = method; + self.sort(); + self + } } pub async fn remove_presentations( @@ -364,7 +394,7 @@ pub async fn remove_presentations( ids.iter().map(ToString::to_string).join(", ") ); - query(&delete) + query(AssertSqlSafe(delete)) .execute(&*db) .await .into_diagnostic() @@ -480,7 +510,7 @@ pub async fn get_presentation_from_db( database_id: i32, db: &mut SqliteConnection, ) -> Result { - let row = query(r#"SELECT id as "id: i32", title, file_path as "path", html from presentations where id = $1"#).bind(database_id).fetch_one(db).await.into_diagnostic()?; + let row = query(r#"SELECT id as "id: i32", title, file_path as "path", html, accessed_at as "accessed_at!: DateTime", created_at as "created_at!: DateTime" from presentations where id = $1"#).bind(database_id).fetch_one(db).await.into_diagnostic()?; Presentation::from_row(&row).into_diagnostic() } @@ -498,6 +528,8 @@ mod test { starting_index: 0, ending_index: 67, }, + created_at: Local::now(), + accessed_at: Local::now(), } } @@ -517,6 +549,7 @@ mod test { let mut presentation_model: Model = Model { items: vec![], kind: LibraryKind::Presentation, + sorting_method: Sort::AccessTime, }; let db = Arc::new(add_db().await.expect("Getting db error")); presentation_model.load_from_db(db).await; diff --git a/src/core/service_items.rs b/src/core/service_items.rs index 5b89ebb..10fa1a5 100644 --- a/src/core/service_items.rs +++ b/src/core/service_items.rs @@ -374,6 +374,7 @@ mod test { use super::*; use pretty_assertions::assert_eq; + use sqlx::types::chrono::Local; fn test_song() -> Song { Song { @@ -390,6 +391,8 @@ mod test { "~/docs/notes/lessons/20240327T133649--12-isaiah-and-jesus__lesson_project_tfc.html", ), kind: PresKind::Html, + created_at: Local::now(), + accessed_at: Local::now(), } } diff --git a/src/core/settings.rs b/src/core/settings.rs index baf4ee4..820542e 100644 --- a/src/core/settings.rs +++ b/src/core/settings.rs @@ -7,6 +7,8 @@ use serde::{Deserialize, Serialize}; use std::collections::VecDeque; use std::path::PathBuf; +use crate::core::model::Sort; + pub const SETTINGS_VERSION: u64 = 1; #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -32,6 +34,10 @@ pub struct Settings { pub app_theme: AppTheme, pub obs_url: Option, pub genius_token: Option, + pub song_sort: Option, + pub image_sort: Option, + pub video_sort: Option, + pub presentation_sort: Option, } impl Default for Settings { @@ -40,6 +46,10 @@ impl Default for Settings { app_theme: AppTheme::System, obs_url: None, genius_token: None, + song_sort: None, + image_sort: None, + video_sort: None, + presentation_sort: None, } } } diff --git a/src/core/songs.rs b/src/core/songs.rs index 88e4ebb..aadc59a 100644 --- a/src/core/songs.rs +++ b/src/core/songs.rs @@ -13,12 +13,13 @@ use itertools::Itertools; use miette::{IntoDiagnostic, Result, miette}; use serde::{Deserialize, Serialize}; use sqlx::sqlite::SqliteRow; -use sqlx::{FromRow, Row, SqlitePool, query}; +use sqlx::types::chrono::{DateTime, Local}; +use sqlx::{AssertSqlSafe, FromRow, Row, SqlitePool, query}; use tracing::{debug, error}; use crate::core::content::Content; use crate::core::kinds::ServiceItemKind; -use crate::core::model::{LibraryKind, Model}; +use crate::core::model::{LibraryKind, Model, Sort}; use crate::core::service_items::ServiceTrait; use crate::core::slide::{self, Background, TextAlignment}; use crate::ui::text_svg::{Color, Font, Stroke, shadow, stroke}; @@ -49,6 +50,10 @@ pub struct Song { pub verse_map: Option>, pub lyric_video: Option, pub music_video: Option, + #[serde(skip)] + pub created_at: DateTime, + #[serde(skip)] + pub accessed_at: DateTime, } #[derive( @@ -379,6 +384,20 @@ impl FromRow<'_, SqliteRow> for Song { .try_get::("music_video") .map_or(None, |vid| Some(PathBuf::from(vid))); + let created_at = row + .try_get::, &str>("created_at") + .unwrap_or_else(|e| { + error!(?e); + Local::now() + }); + + let accessed_at = row + .try_get::, &str>("created_at") + .unwrap_or_else(|e| { + error!(?e); + Local::now() + }); + Ok(Self { id: row.try_get("id")?, title: row.try_get("title")?, @@ -428,6 +447,8 @@ impl FromRow<'_, SqliteRow> for Song { verse_map, lyric_video, music_video, + created_at, + accessed_at, ..Default::default() }) } @@ -646,6 +667,7 @@ impl Model { let mut model = Self { items: vec![], kind: LibraryKind::Song, + sorting_method: Sort::AccessTime, }; model.load_from_db(db).await; @@ -677,6 +699,23 @@ impl Model { } } } + + pub fn sort(&mut self) { + match self.sorting_method { + Sort::AccessTime => { + self.items.sort_by(|a, b| b.accessed_at.cmp(&a.accessed_at)) + } + Sort::CreatedTime => todo!(), + Sort::Title => todo!(), + Sort::Secondary => todo!(), + } + } + + pub fn set_sort(mut self, method: Sort) -> Self { + self.sorting_method = method; + self.sort(); + self + } } pub async fn remove_songs( @@ -694,7 +733,7 @@ pub async fn remove_songs( ids.iter().map(ToString::to_string).join(", ") ); - query(&delete) + query(AssertSqlSafe(delete)) .execute(&*db) .await .into_diagnostic() @@ -847,6 +886,8 @@ pub async fn update_song( let style = ron::ser::to_string(&song.font_style).into_diagnostic()?; let weight = ron::ser::to_string(&song.font_weight).into_diagnostic()?; + let accessed_at = song.accessed_at; + // debug!( // ?stroke_size, // ?stroke_color, @@ -857,7 +898,7 @@ pub async fn update_song( // ); let result = query!( - r#"UPDATE songs SET title = $2, lyrics = $3, author = $4, ccli = $5, verse_order = $6, audio = $7, font = $8, font_size = $9, background = $10, horizontal_text_alignment = $11, vertical_text_alignment = $12, stroke_color = $13, shadow_color = $14, stroke_size = $15, shadow_size = $16, shadow_offset_x = $17, shadow_offset_y = $18, style = $19, weight = $20, lyric_video = $21, music_video = $22 WHERE id = $1"#, + r#"UPDATE songs SET title = $2, lyrics = $3, author = $4, ccli = $5, verse_order = $6, audio = $7, font = $8, font_size = $9, background = $10, horizontal_text_alignment = $11, vertical_text_alignment = $12, stroke_color = $13, shadow_color = $14, stroke_size = $15, shadow_size = $16, shadow_offset_x = $17, shadow_offset_y = $18, style = $19, weight = $20, lyric_video = $21, music_video = $22, accessed_at = $23 WHERE id = $1"#, song.id, song.title, lyrics, @@ -879,7 +920,8 @@ pub async fn update_song( style, weight, lyric_video, - music_video + music_video, + accessed_at ) .execute(&*db) .await @@ -1273,6 +1315,7 @@ You saved my soul" let song_model: Model = Model { items: vec![], kind: LibraryKind::Song, + sorting_method: Sort::AccessTime, // db: crate::core::model::get_db().await, }; song_model diff --git a/src/core/videos.rs b/src/core/videos.rs index a4e4e7e..4f9ef24 100644 --- a/src/core/videos.rs +++ b/src/core/videos.rs @@ -1,3 +1,4 @@ +use crate::core::model::Sort; use crate::{Background, SlideBuilder, TextAlignment}; use super::content::Content; @@ -9,13 +10,14 @@ use crisp::types::{Keyword, Symbol, Value}; use itertools::Itertools; use miette::{IntoDiagnostic, Result, miette}; use serde::{Deserialize, Serialize}; -use sqlx::{SqliteConnection, SqlitePool, query, query_as}; +use sqlx::types::chrono::{DateTime, Local}; +use sqlx::{AssertSqlSafe, Decode, SqliteConnection, SqlitePool, query, query_as}; use std::mem::replace; use std::path::{Path, PathBuf}; use std::sync::Arc; use tracing::error; -#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, Decode)] pub struct Video { pub id: i32, pub title: String, @@ -23,6 +25,10 @@ pub struct Video { pub start_time: Option, pub end_time: Option, pub looping: bool, + #[serde(skip)] + pub accessed_at: DateTime, + #[serde(skip)] + pub created_at: DateTime, } impl From<&Video> for Value { @@ -178,13 +184,14 @@ impl Model