From eafe8d2fd8d20791185732b434f3e3791742fe59 Mon Sep 17 00:00:00 2001 From: Kubat <maelle.martin@proton.me> Date: Wed, 25 Sep 2024 18:46:40 +0200 Subject: [PATCH] AMADEUS: A clean & new implementation of amadeus - Use libcosmic (which is based on iced) for amadeus - Cargo update + clippy - logger updates - Update badges & Readme --- .gitignore | 1 + Cargo.lock | 3844 ++++++--- Cargo.toml | 92 +- README.md | 15 +- amadeus/Cargo.toml | 53 +- amadeus/amadeus.excalidraw | 7442 ----------------- amadeus/amadeus.png | Bin 130065 -> 143472 bytes amadeus/build.rs | 16 + amadeus/i18n.toml | 4 + amadeus/i18n/en/amadeus.ftl | 43 + amadeus/i18n/es-ES/amadeus.ftl | 43 + amadeus/src/app.rs | 1189 +-- amadeus/src/app/about_page.rs | 76 + amadeus/src/app/config_page.rs | 83 + amadeus/src/app/context_page.rs | 20 + amadeus/src/app/history_page.rs | 19 + amadeus/src/app/home_page.rs | 18 + amadeus/src/app/main_page.rs | 58 + amadeus/src/app/menu_bar.rs | 141 + amadeus/src/app/playlist_page.rs | 18 + amadeus/src/app/playlists_page.rs | 18 + amadeus/src/app/queue_page.rs | 18 + amadeus/src/app/search_page.rs | 18 + amadeus/src/components/bottombar.rs | 32 - amadeus/src/components/config/loglevel.rs | 35 - amadeus/src/components/config/mod.rs | 585 -- amadeus/src/components/config/theme.rs | 56 - amadeus/src/components/kara.rs | 122 - amadeus/src/components/karalist.rs | 65 - amadeus/src/components/mainpanel/history.rs | 66 - amadeus/src/components/mainpanel/mod.rs | 172 - amadeus/src/components/mainpanel/playlists.rs | 224 - amadeus/src/components/mainpanel/queue.rs | 162 - .../src/components/mainpanel/search/filter.rs | 81 - .../src/components/mainpanel/search/mod.rs | 133 - amadeus/src/components/mod.rs | 67 - amadeus/src/components/modal/helper.rs | 302 - amadeus/src/components/modal/karainfos.rs | 139 - amadeus/src/components/modal/mod.rs | 50 - .../src/components/modal/playlistselect.rs | 66 - amadeus/src/components/sidebar.rs | 150 - amadeus/src/components/topbar.rs | 92 - amadeus/src/config.rs | 150 + amadeus/src/i18n.rs | 45 + amadeus/src/icons.rs | 58 + amadeus/src/links.rs | 6 - amadeus/src/main.rs | 103 +- amadeus/src/message.rs | 396 - amadeus/src/store.rs | 76 - amadeus/src/style_sheet/badge/mod.rs | 5 - amadeus/src/style_sheet/badge/rounded.rs | 30 - amadeus/src/style_sheet/badge/squared.rs | 27 - amadeus/src/style_sheet/bar.rs | 22 - amadeus/src/style_sheet/bottombar.rs | 20 - amadeus/src/style_sheet/button/mod.rs | 7 - amadeus/src/style_sheet/button/plain.rs | 42 - amadeus/src/style_sheet/button/rounded.rs | 97 - amadeus/src/style_sheet/button/squared.rs | 43 - amadeus/src/style_sheet/context_menu.rs | 26 - amadeus/src/style_sheet/mod.rs | 59 - amadeus/src/style_sheet/modal.rs | 26 - amadeus/src/style_sheet/sizes.rs | 20 - amadeus/src/style_sheet/split.rs | 41 - amadeus/src/style_sheet/tooltip.rs | 26 - amadeus/src/subscriptions.rs | 1 + amadeus/src/subscriptions/lektord.rs | 39 + lektor_lib/Cargo.toml | 1 + lektor_lib/src/config.rs | 15 +- lektor_lib/src/requests.rs | 186 +- lektor_mpris/Cargo.toml | 27 +- lektor_mpris/src/server.rs | 1 - lektor_mpris/src/trait.rs | 1 - lektor_nkdb/Cargo.toml | 1 + lektor_nkdb/src/database/pool.rs | 16 +- lektor_nkdb/src/database/update.rs | 76 +- lektor_nkdb/src/lib.rs | 2 +- lektor_nkdb/src/playlist/infos.rs | 68 +- lektor_nkdb/src/playlist/register.rs | 52 +- lektor_nkdb/src/playlist/values.rs | 4 +- lektor_nkdb/src/queue/mod.rs | 7 +- lektor_nkdb/src/search/kara_by.rs | 8 +- lektor_nkdb/src/storage/disk_storage.rs | 43 +- lektor_payloads/src/lib.rs | 29 +- lektor_procmacros/src/getset/generate.rs | 141 - lektor_procmacros/src/getset/mod.rs | 234 - lektor_procmacros/src/lib.rs | 46 - lektor_procmacros/tests/copy_getters.rs | 149 - lektor_procmacros/tests/getset.rs | 121 - lektor_procmacros/tests/getters.rs | 147 - lektor_procmacros/tests/mut_getters.rs | 118 - lektor_procmacros/tests/raw_identifiers.rs | 57 - lektor_procmacros/tests/setters.rs | 129 - lektor_procmacros/tests/skip.rs | 50 - lektor_repo/Cargo.toml | 1 + lektor_repo/src/downloader.rs | 4 +- lektor_repo/src/lib.rs | 5 +- lektor_utils/src/config/base.rs | 10 + lektor_utils/src/iterator.rs | 2 +- lektor_utils/src/lib.rs | 1 - lektor_utils/src/log.rs | 1 - lektor_utils/src/logger.rs | 96 +- lektor_utils/src/pathdiff.rs | 2 +- lektor_utils/src/pushvec.rs | 1 - lektord/Cargo.toml | 1 + lektord/build.rs | 4 + lektord/src/app/mod.rs | 35 +- lektord/src/app/mpris.rs | 2 +- lektord/src/app/routes.rs | 90 +- lektord/src/c_wrapper/commands.rs | 71 +- lektord/src/c_wrapper/loging.rs | 18 +- lektord/src/c_wrapper/mod.rs | 67 +- lektord/src/c_wrapper/playstate.rs | 2 +- lektord/src/config.rs | 3 +- lektord/src/error.rs | 6 +- lektord/src/main.rs | 26 +- lkt/Cargo.toml | 1 + lkt/src/config.rs | 29 +- lkt/src/main.rs | 54 +- 118 files changed, 4767 insertions(+), 14687 deletions(-) delete mode 100644 amadeus/amadeus.excalidraw create mode 100644 amadeus/build.rs create mode 100644 amadeus/i18n.toml create mode 100644 amadeus/i18n/en/amadeus.ftl create mode 100644 amadeus/i18n/es-ES/amadeus.ftl create mode 100644 amadeus/src/app/about_page.rs create mode 100644 amadeus/src/app/config_page.rs create mode 100644 amadeus/src/app/context_page.rs create mode 100644 amadeus/src/app/history_page.rs create mode 100644 amadeus/src/app/home_page.rs create mode 100644 amadeus/src/app/main_page.rs create mode 100644 amadeus/src/app/menu_bar.rs create mode 100644 amadeus/src/app/playlist_page.rs create mode 100644 amadeus/src/app/playlists_page.rs create mode 100644 amadeus/src/app/queue_page.rs create mode 100644 amadeus/src/app/search_page.rs delete mode 100644 amadeus/src/components/bottombar.rs delete mode 100644 amadeus/src/components/config/loglevel.rs delete mode 100644 amadeus/src/components/config/mod.rs delete mode 100644 amadeus/src/components/config/theme.rs delete mode 100644 amadeus/src/components/kara.rs delete mode 100644 amadeus/src/components/karalist.rs delete mode 100644 amadeus/src/components/mainpanel/history.rs delete mode 100644 amadeus/src/components/mainpanel/mod.rs delete mode 100644 amadeus/src/components/mainpanel/playlists.rs delete mode 100644 amadeus/src/components/mainpanel/queue.rs delete mode 100644 amadeus/src/components/mainpanel/search/filter.rs delete mode 100644 amadeus/src/components/mainpanel/search/mod.rs delete mode 100644 amadeus/src/components/mod.rs delete mode 100644 amadeus/src/components/modal/helper.rs delete mode 100644 amadeus/src/components/modal/karainfos.rs delete mode 100644 amadeus/src/components/modal/mod.rs delete mode 100644 amadeus/src/components/modal/playlistselect.rs delete mode 100644 amadeus/src/components/sidebar.rs delete mode 100644 amadeus/src/components/topbar.rs create mode 100644 amadeus/src/config.rs create mode 100644 amadeus/src/i18n.rs create mode 100644 amadeus/src/icons.rs delete mode 100644 amadeus/src/links.rs delete mode 100644 amadeus/src/message.rs delete mode 100644 amadeus/src/store.rs delete mode 100644 amadeus/src/style_sheet/badge/mod.rs delete mode 100644 amadeus/src/style_sheet/badge/rounded.rs delete mode 100644 amadeus/src/style_sheet/badge/squared.rs delete mode 100644 amadeus/src/style_sheet/bar.rs delete mode 100644 amadeus/src/style_sheet/bottombar.rs delete mode 100644 amadeus/src/style_sheet/button/mod.rs delete mode 100644 amadeus/src/style_sheet/button/plain.rs delete mode 100644 amadeus/src/style_sheet/button/rounded.rs delete mode 100644 amadeus/src/style_sheet/button/squared.rs delete mode 100644 amadeus/src/style_sheet/context_menu.rs delete mode 100644 amadeus/src/style_sheet/mod.rs delete mode 100644 amadeus/src/style_sheet/modal.rs delete mode 100644 amadeus/src/style_sheet/sizes.rs delete mode 100644 amadeus/src/style_sheet/split.rs delete mode 100644 amadeus/src/style_sheet/tooltip.rs create mode 100644 amadeus/src/subscriptions.rs create mode 100644 amadeus/src/subscriptions/lektord.rs delete mode 100644 lektor_procmacros/src/getset/generate.rs delete mode 100644 lektor_procmacros/src/getset/mod.rs delete mode 100644 lektor_procmacros/tests/copy_getters.rs delete mode 100644 lektor_procmacros/tests/getset.rs delete mode 100644 lektor_procmacros/tests/getters.rs delete mode 100644 lektor_procmacros/tests/mut_getters.rs delete mode 100644 lektor_procmacros/tests/raw_identifiers.rs delete mode 100644 lektor_procmacros/tests/setters.rs delete mode 100644 lektor_procmacros/tests/skip.rs delete mode 100644 lektor_utils/src/log.rs diff --git a/.gitignore b/.gitignore index 220942fa..6f4fd879 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ target/ # Files .ccls +.gdb_history *.ccls *.ycm_extra_conf.py *.vimrc diff --git a/Cargo.lock b/Cargo.lock index 4a9003e8..57711d89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ab_glyph" -version = "0.2.27" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c3a1cbc201cc13ed06cf875efb781f2249b3677f5c74571b67d817877f9d697" +checksum = "79faae4620f45232f599d9bc7b290f88247a0834162c4495ab2f02d60004adfb" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -18,11 +18,80 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" +[[package]] +name = "accesskit" +version = "0.12.2" +source = "git+https://github.com/wash2/accesskit.git?branch=winit-0.29#26f729169cd849970af02be62289606c63572d2d" + +[[package]] +name = "accesskit_consumer" +version = "0.17.0" +source = "git+https://github.com/wash2/accesskit.git?branch=winit-0.29#26f729169cd849970af02be62289606c63572d2d" +dependencies = [ + "accesskit", +] + +[[package]] +name = "accesskit_macos" +version = "0.11.0" +source = "git+https://github.com/wash2/accesskit.git?branch=winit-0.29#26f729169cd849970af02be62289606c63572d2d" +dependencies = [ + "accesskit", + "accesskit_consumer", + "icrate 0.1.2", + "objc2 0.5.2", + "once_cell", +] + +[[package]] +name = "accesskit_unix" +version = "0.7.1" +source = "git+https://github.com/wash2/accesskit.git?branch=winit-0.29#26f729169cd849970af02be62289606c63572d2d" +dependencies = [ + "accesskit", + "accesskit_consumer", + "async-channel", + "async-executor", + "async-task", + "atspi", + "futures-lite 1.13.0", + "futures-util", + "once_cell", + "serde", + "zbus 3.15.2", +] + +[[package]] +name = "accesskit_windows" +version = "0.16.0" +source = "git+https://github.com/wash2/accesskit.git?branch=winit-0.29#26f729169cd849970af02be62289606c63572d2d" +dependencies = [ + "accesskit", + "accesskit_consumer", + "once_cell", + "paste", + "static_assertions", + "windows 0.48.0", +] + +[[package]] +name = "accesskit_winit" +version = "0.18.1" +source = "git+https://github.com/wash2/accesskit.git?branch=winit-0.29#26f729169cd849970af02be62289606c63572d2d" +dependencies = [ + "accesskit", + "accesskit_macos", + "accesskit_unix", + "accesskit_windows", + "raw-window-handle", + "winit", +] + [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] @@ -33,6 +102,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "ahash" version = "0.8.11" @@ -40,6 +115,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", + "getrandom", "once_cell", "version_check", "zerocopy", @@ -66,24 +142,35 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "almost" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aa2999eb46af81abb65c2d30d446778d7e613b60bbf4e174a027e80f90a3c14" + [[package]] name = "amadeus" -version = "3.0.1" +version = "0.0.1" dependencies = [ "anyhow", "async-trait", "chrono", + "derive_more", "futures", - "hashbrown 0.14.5", - "iced", - "iced_aw", - "image", + "futures-util", + "hashbrown", + "i18n-embed", + "i18n-embed-fl", "lektor_lib", "lektor_mpris", "lektor_payloads", "lektor_procmacros", "lektor_utils", + "libcosmic", + "log", + "open", "reqwest", + "rust-embed", "serde", "serde_json", "tokio", @@ -91,20 +178,23 @@ dependencies = [ [[package]] name = "android-activity" -version = "0.4.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64529721f27c2314ced0890ce45e469574a73e5e6fdd6e9da1860eb29285f5e0" +checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" dependencies = [ "android-properties", - "bitflags 1.3.2", + "bitflags 2.6.0", "cc", + "cesu8", + "jni", "jni-sys", "libc", "log", "ndk", "ndk-context", "ndk-sys", - "num_enum 0.6.1", + "num_enum", + "thiserror", ] [[package]] @@ -130,15 +220,21 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" + +[[package]] +name = "apply" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47b57fc4521e3cae26a4d45b5227f8fadee4c345be0fefd8d5d1711afb8aeb9" [[package]] name = "approx" @@ -149,17 +245,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" [[package]] name = "ash" @@ -170,13 +278,59 @@ dependencies = [ "libloading 0.7.4", ] +[[package]] +name = "ashpd" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd884d7c72877a94102c3715f3b1cd09ff4fac28221add3e57cfbe25c236d093" +dependencies = [ + "async-fs 2.1.2", + "async-net", + "enumflags2", + "futures-channel", + "futures-util", + "rand", + "serde", + "serde_repr", + "tokio", + "url", + "zbus 4.4.0", +] + +[[package]] +name = "ashpd" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfe7e0dd0ac5a401dc116ed9f9119cf9decc625600474cb41f0fc0a0050abc9a" +dependencies = [ + "enumflags2", + "futures-channel", + "futures-util", + "rand", + "serde", + "serde_repr", + "tokio", + "url", + "zbus 4.4.0", +] + +[[package]] +name = "async-broadcast" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" +dependencies = [ + "event-listener 2.5.3", + "futures-core", +] + [[package]] name = "async-broadcast" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" dependencies = [ - "event-listener", + "event-listener 5.3.1", "event-listener-strategy", "futures-core", "pin-project-lite", @@ -194,23 +348,88 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand 2.1.1", + "futures-lite 2.3.0", + "slab", +] + +[[package]] +name = "async-fs" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "blocking", + "futures-lite 1.13.0", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock 3.4.0", + "blocking", + "futures-lite 2.3.0", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.27", + "slab", + "socket2 0.4.10", + "waker-fn", +] + [[package]] name = "async-io" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ - "async-lock", + "async-lock 3.4.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite", + "futures-lite 2.3.0", "parking", - "polling", - "rustix", + "polling 3.7.3", + "rustix 0.38.37", "slab", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", ] [[package]] @@ -219,29 +438,56 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener", + "event-listener 5.3.1", "event-listener-strategy", "pin-project-lite", ] +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io 2.3.4", + "blocking", + "futures-lite 2.3.0", +] + +[[package]] +name = "async-process" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +dependencies = [ + "async-io 1.13.0", + "async-lock 2.8.0", + "async-signal", + "blocking", + "cfg-if", + "event-listener 3.1.0", + "futures-lite 1.13.0", + "rustix 0.38.37", + "windows-sys 0.48.0", +] + [[package]] name = "async-process" -version = "2.2.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" dependencies = [ "async-channel", - "async-io", - "async-lock", + "async-io 2.3.4", + "async-lock 3.4.0", "async-signal", "async-task", "blocking", "cfg-if", - "event-listener", - "futures-lite", - "rustix", + "event-listener 5.3.1", + "futures-lite 2.3.0", + "rustix 0.38.37", "tracing", - "windows-sys 0.52.0", ] [[package]] @@ -252,25 +498,25 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] name = "async-signal" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ - "async-io", - "async-lock", + "async-io 2.3.4", + "async-lock 3.4.0", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix", + "rustix 0.38.37", "signal-hook-registry", "slab", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -281,13 +527,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] @@ -296,6 +542,64 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atomicwrites" +version = "0.4.2" +source = "git+https://github.com/jackpot51/rust-atomicwrites#043ab4859d53ffd3d55334685303d8df39c9f768" +dependencies = [ + "rustix 0.38.37", + "tempfile", + "windows-sys 0.48.0", +] + +[[package]] +name = "atspi" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6059f350ab6f593ea00727b334265c4dfc7fd442ee32d264794bd9bdc68e87ca" +dependencies = [ + "atspi-common", + "atspi-connection", + "atspi-proxies", +] + +[[package]] +name = "atspi-common" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92af95f966d2431f962bc632c2e68eda7777330158bf640c4af4249349b2cdf5" +dependencies = [ + "enumflags2", + "serde", + "static_assertions", + "zbus 3.15.2", + "zbus_names 2.6.1", + "zvariant 3.15.2", +] + +[[package]] +name = "atspi-connection" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c65e7d70f86d4c0e3b2d585d9bf3f979f0b19d635a336725a88d279f76b939" +dependencies = [ + "atspi-common", + "atspi-proxies", + "futures-lite 1.13.0", + "zbus 3.15.2", +] + +[[package]] +name = "atspi-proxies" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6495661273703e7a229356dcbe8c8f38223d697aacfaf0e13590a9ac9977bb52" +dependencies = [ + "atspi-common", + "serde", + "zbus 3.15.2", +] + [[package]] name = "autocfg" version = "1.3.0" @@ -304,9 +608,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec" dependencies = [ "async-trait", "axum-core", @@ -321,7 +625,7 @@ dependencies = [ "itoa", "matchit", "memchr", - "mime", + "mime 0.3.17", "percent-encoding", "pin-project-lite", "rustversion", @@ -330,16 +634,16 @@ dependencies = [ "serde_path_to_error", "sync_wrapper 1.0.1", "tokio", - "tower", + "tower 0.5.1", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "5e6b8ba012a258d63c9adfa28b9ddcf66149da6f986c5b5452e629d5ee64bf00" dependencies = [ "async-trait", "bytes", @@ -347,47 +651,61 @@ dependencies = [ "http", "http-body", "http-body-util", - "mime", + "mime 0.3.17", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", ] [[package]] name = "axum-macros" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" +checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ - "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.8.0", "object", "rustc-demangle", + "windows-targets 0.52.6", ] +[[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -420,6 +738,9 @@ name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] [[package]] name = "block" @@ -438,21 +759,31 @@ dependencies = [ [[package]] name = "block-sys" -version = "0.1.0-beta.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146" +checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" dependencies = [ "objc-sys", ] [[package]] name = "block2" -version = "0.2.0-alpha.6" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" +dependencies = [ + "block-sys", + "objc2 0.4.1", +] + +[[package]] +name = "block2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" +checksum = "e58aa60e59d8dbfcc36138f5f18be5f24394d33b38b24f7fd0b1caa33095f22f" dependencies = [ "block-sys", - "objc2-encode", + "objc2 0.5.2", ] [[package]] @@ -464,7 +795,7 @@ dependencies = [ "async-channel", "async-task", "futures-io", - "futures-lite", + "futures-lite 2.3.0", "piper", ] @@ -482,22 +813,22 @@ checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" [[package]] name = "bytemuck" -version = "1.16.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" +checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] @@ -508,34 +839,34 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "calloop" -version = "0.10.6" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e0d00eb1ea24371a97d2da6201c6747a633dc6dc1988ef503403b4c59504a8" +checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "log", - "nix 0.25.1", - "slotmap", + "polling 3.7.3", + "rustix 0.38.37", + "slab", "thiserror", - "vec_map", ] [[package]] name = "calloop" -version = "0.12.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ "bitflags 2.6.0", "log", - "polling", - "rustix", + "polling 3.7.3", + "rustix 0.38.37", "slab", "thiserror", ] @@ -547,25 +878,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" dependencies = [ "calloop 0.12.4", - "rustix", - "wayland-backend 0.3.4", - "wayland-client 0.31.3", + "rustix 0.38.37", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "calloop 0.13.0", + "rustix 0.38.37", + "wayland-backend", + "wayland-client", ] [[package]] name = "cc" -version = "1.0.104" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" dependencies = [ "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" @@ -589,15 +938,17 @@ checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", - "windows-targets 0.52.5", + "wasm-bindgen", + "windows-targets 0.52.6", ] [[package]] name = "clap" -version = "4.5.8" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" +checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" dependencies = [ "clap_builder", "clap_derive", @@ -605,9 +956,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.8" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" +checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" dependencies = [ "anstyle", "clap_lex", @@ -616,47 +967,44 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.7" +version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d598e88f6874d4b888ed40c71efbcbf4076f1dfbae128a08a8c9e45f710605d" +checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.8" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "clipboard-win" -version = "4.5.0" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" dependencies = [ "error-code", - "str-buf", - "winapi", ] [[package]] name = "clipboard_macos" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145a7f9e9b89453bc0a5e32d166456405d389cea5b578f57f1274b1397588a95" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-8#7c59b07b9172d8e0401f7e06609e1050575309c9" dependencies = [ "objc", "objc-foundation", @@ -666,27 +1014,27 @@ dependencies = [ [[package]] name = "clipboard_wayland" version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003f886bc4e2987729d10c1db3424e7f80809f3fc22dbc16c685738887cb37b8" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-8#7c59b07b9172d8e0401f7e06609e1050575309c9" dependencies = [ + "dnd", + "mime 0.1.0", "smithay-clipboard", ] [[package]] name = "clipboard_x11" version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4274ea815e013e0f9f04a2633423e14194e408a0576c943ce3d14ca56c50031c" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-8#7c59b07b9172d8e0401f7e06609e1050575309c9" dependencies = [ "thiserror", - "x11rb 0.13.1", + "x11rb", ] [[package]] name = "cocoa" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" +checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" dependencies = [ "bitflags 1.3.2", "block", @@ -729,10 +1077,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] -name = "com-rs" -version = "0.2.1" +name = "com" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf43edc576402991846b093a7ca18a3477e0ef9c588cde84964b5d3e43016642" +checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" +dependencies = [ + "com_macros", +] + +[[package]] +name = "com_macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" +dependencies = [ + "com_macros_support", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "com_macros_support" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] [[package]] name = "concurrent-queue" @@ -743,6 +1126,35 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -755,15 +1167,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core-graphics" -version = "0.22.3" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -783,31 +1195,90 @@ dependencies = [ "libc", ] +[[package]] +name = "cosmic-config" +version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" +dependencies = [ + "atomicwrites", + "cosmic-config-derive", + "cosmic-settings-daemon", + "dirs", + "futures-util", + "iced_futures", + "known-folders", + "notify", + "once_cell", + "ron", + "serde", + "tokio", + "tracing", + "xdg", + "zbus 4.4.0", +] + +[[package]] +name = "cosmic-config-derive" +version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cosmic-settings-daemon" +version = "0.1.0" +source = "git+https://github.com/pop-os/dbus-settings-bindings#8059e6bdaa35fecd70d228a999ca342fb00d313b" +dependencies = [ + "zbus 4.4.0", +] + [[package]] name = "cosmic-text" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0b68966c2543609f8d92f9d33ac3b719b2a67529b0c6c0b3e025637b477eef9" +version = "0.12.1" +source = "git+https://github.com/pop-os/cosmic-text.git#4fe90bb6126c22f589b46768d7754d65ae300c5e" dependencies = [ - "aliasable", + "bitflags 2.6.0", "fontdb", - "libm", "log", "rangemap", - "rustybuzz", + "rayon", + "rustc-hash 1.1.0", + "rustybuzz 0.14.1", + "self_cell 1.0.4", + "smol_str", "swash", "sys-locale", + "ttf-parser 0.21.1", "unicode-bidi", "unicode-linebreak", "unicode-script", "unicode-segmentation", ] +[[package]] +name = "cosmic-theme" +version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" +dependencies = [ + "almost", + "cosmic-config", + "csscolorparser", + "dirs", + "lazy_static", + "palette", + "ron", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -821,6 +1292,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -862,6 +1342,28 @@ dependencies = [ "typenum", ] +[[package]] +name = "css-color" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42aaeae719fd78ce501d77c6cdf01f7e96f26bcd5617a4903a1c2b97e388543a" + +[[package]] +name = "csscolorparser" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a7d3066da2de787b7f032c736763eb7ae5d355f81a68bab2675a96008b0bf" +dependencies = [ + "phf", + "serde", +] + +[[package]] +name = "ctor-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f791803201ab277ace03903de1594460708d2d54df6053f2d9e82f592b19e3b" + [[package]] name = "cursor-icon" version = "1.1.0" @@ -870,15 +1372,114 @@ checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" [[package]] name = "d3d12" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8f0de2f5a8e7bd4a9eec0e3c781992a4ce1724f68aec7d7a3715344de8b39da" +version = "0.19.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=20fda69#20fda698341efbdc870b8027d6d49f5bf3f36109" dependencies = [ - "bitflags 1.3.2", - "libloading 0.7.4", + "bitflags 2.6.0", + "libloading 0.8.5", "winapi", ] +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.77", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "data-url" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn 2.0.77", + "unicode-xid", +] + +[[package]] +name = "derive_setters" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "digest" version = "0.10.7" @@ -916,13 +1517,45 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "dlib" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.4", + "libloading 0.8.5", +] + +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + +[[package]] +name = "dnd" +version = "0.1.0" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-8#7c59b07b9172d8e0401f7e06609e1050575309c9" +dependencies = [ + "bitflags 2.6.0", + "mime 0.1.0", + "raw-window-handle", + "smithay-client-toolkit 0.19.2", + "smithay-clipboard", ] [[package]] @@ -931,6 +1564,45 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "drm" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde" +dependencies = [ + "bitflags 2.6.0", + "bytemuck", + "drm-ffi", + "drm-fourcc", + "rustix 0.38.37", +] + +[[package]] +name = "drm-ffi" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41334f8405792483e32ad05fbb9c5680ff4e84491883d2947a4757dc54cb2ac6" +dependencies = [ + "drm-sys", + "rustix 0.38.37", +] + +[[package]] +name = "drm-fourcc" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" + +[[package]] +name = "drm-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d09ff881f92f118b11105ba5e34ff8f4adf27b30dae8f12e28c193af1c83176" +dependencies = [ + "libc", + "linux-raw-sys 0.6.5", +] + [[package]] name = "either" version = "1.13.0" @@ -961,7 +1633,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] @@ -982,13 +1654,9 @@ dependencies = [ [[package]] name = "error-code" -version = "2.3.1" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" -dependencies = [ - "libc", - "str-buf", -] +checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" [[package]] name = "etagere" @@ -1002,13 +1670,30 @@ dependencies = [ [[package]] name = "euclid" -version = "0.22.10" +version = "0.22.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f0eb73b934648cd7a4a61f1b15391cd95dab0b4da6e2e66c2a072c144b4a20" +checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48" dependencies = [ "num-traits", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + [[package]] name = "event-listener" version = "5.3.1" @@ -1026,7 +1711,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener", + "event-listener 5.3.1", "pin-project-lite", ] @@ -1040,7 +1725,7 @@ dependencies = [ "flume", "half", "lebe", - "miniz_oxide", + "miniz_oxide 0.7.4", "rayon-core", "smallvec", "zune-inflate", @@ -1063,9 +1748,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fdeflate" @@ -1076,14 +1761,91 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox 0.1.3", + "windows-sys 0.59.0", +] + +[[package]] +name = "find-crate" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2" +dependencies = [ + "toml 0.5.11", +] + [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", - "miniz_oxide", + "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 = "float_next_after" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" + +[[package]] +name = "fluent" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb74634707bebd0ce645a981148e8fb8c7bccd4c33c652aeffd28bf2f96d555a" +dependencies = [ + "fluent-bundle", + "unic-langid", +] + +[[package]] +name = "fluent-bundle" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493" +dependencies = [ + "fluent-langneg", + "fluent-syntax", + "intl-memoizer", + "intl_pluralrules", + "rustc-hash 1.1.0", + "self_cell 0.10.3", + "smallvec", + "unic-langid", +] + +[[package]] +name = "fluent-langneg" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "fluent-syntax" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" +dependencies = [ + "thiserror", ] [[package]] @@ -1103,40 +1865,62 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "font-types" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34fd7136aca682873d859ef34494ab1a7d3f57ecd485ed40eb6437ee8c85aa29" +checksum = "8f0189ccb084f77c5523e08288d418cbaa09c451a08515678a0aa265df9a8b60" dependencies = [ "bytemuck", ] +[[package]] +name = "fontconfig-parser" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7" +dependencies = [ + "roxmltree 0.20.0", +] + [[package]] name = "fontdb" -version = "0.14.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af8d8cbea8f21307d7e84bca254772981296f058a1d36b461bf4d83a7499fc9e" +checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3" dependencies = [ + "fontconfig-parser", "log", - "memmap2 0.6.2", + "memmap2 0.9.5", "slotmap", "tinyvec", - "ttf-parser 0.19.2", + "ttf-parser 0.20.0", ] [[package]] name = "foreign-types" -version = "0.3.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ + "foreign-types-macros", "foreign-types-shared", ] +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "foreign-types-shared" -version = "0.1.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "form_urlencoded" @@ -1147,6 +1931,38 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fraction" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f158e3ff0a1b334408dc9fb811cd99b446986f4d8b741bb08f9df1604085ae7" +dependencies = [ + "lazy_static", + "num", +] + +[[package]] +name = "freedesktop-icons" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8ef34245e0540c9a3ce7a28340b98d2c12b75da0d446da4e8224923fcaa0c16" +dependencies = [ + "dirs", + "once_cell", + "rust-ini", + "thiserror", + "xdg", +] + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + [[package]] name = "futures" version = "0.3.30" @@ -1196,13 +2012,28 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "futures-lite" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-core", "futures-io", "parking", @@ -1217,7 +2048,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] @@ -1260,16 +2091,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "gethostname" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "gethostname" version = "0.4.3" @@ -1291,6 +2112,16 @@ dependencies = [ "wasi", ] +[[package]] +name = "gif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gif" version = "0.13.1" @@ -1302,10 +2133,21 @@ dependencies = [ ] [[package]] -name = "gimli" -version = "0.29.0" +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" + +[[package]] +name = "gl_generator" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] [[package]] name = "glam" @@ -1315,9 +2157,9 @@ checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" [[package]] name = "glow" -version = "0.12.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0fe580e4b60a8ab24a868bc08e2f03cbcb20d3d676601fa909386713333728" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" dependencies = [ "js-sys", "slotmap", @@ -1326,10 +2168,18 @@ dependencies = [ ] [[package]] -name = "glyphon" -version = "0.3.0" +name = "glutin_wgl_sys" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e87caa7459145f5e5f167bf34db4532901404c679e62339fb712a0e3ccf722a" +checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "glyphon" +version = "0.5.0" +source = "git+https://github.com/pop-os/glyphon.git?tag=v0.5.0#1b0646ff8f74da92d3be704dfc2257d7f4d7eed8" dependencies = [ "cosmic-text", "etagere", @@ -1339,34 +2189,34 @@ dependencies = [ [[package]] name = "gpu-alloc" -version = "0.5.4" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22beaafc29b38204457ea030f6fb7a84c9e4dd1b86e311ba0542533453d87f62" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "gpu-alloc-types", ] [[package]] name = "gpu-alloc-types" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", ] [[package]] name = "gpu-allocator" -version = "0.22.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce95f9e2e11c2c6fadfce42b5af60005db06576f231f5c92550fdded43c423e8" +checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884" dependencies = [ - "backtrace", "log", + "presser", "thiserror", "winapi", - "windows", + "windows 0.52.0", ] [[package]] @@ -1377,7 +2227,7 @@ checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" dependencies = [ "bitflags 2.6.0", "gpu-descriptor-types", - "hashbrown 0.14.5", + "hashbrown", ] [[package]] @@ -1389,6 +2239,12 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "grid" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df00eed8d1f0db937f6be10e46e8072b0671accb504cf0f959c5c52c679f5b9" + [[package]] name = "guillotiere" version = "0.6.2" @@ -1401,9 +2257,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", "bytes", @@ -1411,7 +2267,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.2.6", + "indexmap", "slab", "tokio", "tokio-util", @@ -1428,12 +2284,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.5" @@ -1447,14 +2297,14 @@ dependencies = [ [[package]] name = "hassle-rs" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1397650ee315e8891a0df210707f0fc61771b0cc518c3023896064c5407cb3b0" +checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" dependencies = [ - "bitflags 1.3.2", - "com-rs", + "bitflags 2.6.0", + "com", "libc", - "libloading 0.7.4", + "libloading 0.8.5", "thiserror", "widestring", "winapi", @@ -1509,9 +2359,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", @@ -1544,9 +2394,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4fe55fb7a772d59a5ff1dfbff4fe0258d19b89fec4b233e75d35d5d2316badc" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", @@ -1565,9 +2415,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http", @@ -1583,9 +2433,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" dependencies = [ "bytes", "futures-channel", @@ -1594,18 +2444,88 @@ dependencies = [ "http-body", "hyper", "pin-project-lite", - "socket2", + "socket2 0.5.7", "tokio", - "tower", + "tower 0.4.13", "tower-service", "tracing", ] +[[package]] +name = "i18n-config" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e88074831c0be5b89181b05e6748c4915f77769ecc9a4c372f88b169a8509c9" +dependencies = [ + "basic-toml", + "log", + "serde", + "serde_derive", + "thiserror", + "unic-langid", +] + +[[package]] +name = "i18n-embed" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e901c87176ac0b615033c81dbe927c230f74700abfd60ed953a6f547c87bbe6d" +dependencies = [ + "arc-swap", + "fluent", + "fluent-langneg", + "fluent-syntax", + "i18n-embed-impl", + "intl-memoizer", + "lazy_static", + "locale_config", + "log", + "parking_lot 0.12.3", + "rust-embed", + "thiserror", + "unic-langid", + "walkdir", +] + +[[package]] +name = "i18n-embed-fl" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d73fe51b9655599147183495551696628b335f75b2dbfa225196b16d69d7288e" +dependencies = [ + "dashmap", + "find-crate", + "fluent", + "fluent-syntax", + "i18n-config", + "i18n-embed", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.77", + "unic-langid", +] + +[[package]] +name = "i18n-embed-impl" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81093c4701672f59416582fe3145676126fd23ba5db910acad0793c1108aaa58" +dependencies = [ + "find-crate", + "i18n-config", + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1626,47 +2546,55 @@ dependencies = [ [[package]] name = "iced" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c708807ec86f99dd729dc4d42db5239acf118cec14d3c5f57679dcfdbbc472b1" +version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" dependencies = [ + "dnd", + "iced_accessibility", "iced_core", "iced_futures", "iced_renderer", "iced_widget", "iced_winit", "image", + "mime 0.1.0", "thiserror", + "window_clipboard", ] [[package]] -name = "iced_aw" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c51860ce7be5be6f6104c4e13b14e56662ebbd7c96c50e10069d59f8c3d892" +name = "iced_accessibility" +version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" dependencies = [ - "iced_widget", + "accesskit", + "accesskit_winit", ] [[package]] name = "iced_core" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d0bc4fbf018576d08d93f838e6058cc6f10bbc05e04ae249a2a44dffb4ebc8" +version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" dependencies = [ - "bitflags 1.3.2", - "instant", + "bitflags 2.6.0", + "dnd", "log", + "mime 0.1.0", + "num-traits", "palette", + "raw-window-handle", + "serde", + "smol_str", "thiserror", - "twox-hash", + "web-time", + "window_clipboard", + "xxhash-rust", ] [[package]] name = "iced_futures" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dab0054a9c7a1cbce227a8cd9ee4a094497b3d06094551ac6c1488d563802e" +version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" dependencies = [ "futures", "iced_core", @@ -1678,52 +2606,56 @@ dependencies = [ [[package]] name = "iced_graphics" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ff14447a221e9e9205a13d84d7bbdf0636a3b1daa02cfca690ed09689c4d2b" +version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "bytemuck", + "cosmic-text", "glam", "half", "iced_core", + "iced_futures", "image", "kamadak-exif", "log", + "lyon_path", + "once_cell", "raw-window-handle", + "rustc-hash 1.1.0", "thiserror", + "unicode-segmentation", + "xxhash-rust", ] [[package]] name = "iced_renderer" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1033385b0db0099a0d13178c9ff93c1ce11e7d0177522acf578bf79febdb2af8" +version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" dependencies = [ "iced_graphics", "iced_tiny_skia", "iced_wgpu", "log", - "raw-window-handle", "thiserror", ] [[package]] name = "iced_runtime" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c6c89853e1250c6fac82c5015fa2144517be9b33d4b8e456f10e198b23e28bd" +version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" dependencies = [ + "dnd", "iced_core", "iced_futures", "thiserror", + "window_clipboard", ] [[package]] name = "iced_style" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d85c47d9d13e2281f75ddf98c865daf2101632bd2b855c401dd0b1c8b81a31a0" +version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" dependencies = [ "iced_core", "once_cell", @@ -1732,29 +2664,28 @@ dependencies = [ [[package]] name = "iced_tiny_skia" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7715f6222c9470bbbd75a39f70478fa0d1bdfb81a377a34fd1b090ffccc480b" +version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" dependencies = [ "bytemuck", "cosmic-text", "iced_graphics", "kurbo", "log", - "raw-window-handle", - "rustc-hash", + "resvg", + "rustc-hash 1.1.0", "softbuffer", - "tiny-skia 0.10.0", - "twox-hash", + "tiny-skia", + "xxhash-rust", ] [[package]] name = "iced_wgpu" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f7c5de46b997ed7b18e05ec67059dcdf3beeac51e917c21071b021bb848b9" +version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" dependencies = [ - "bitflags 1.3.2", + "as-raw-xcb-connection", + "bitflags 2.6.0", "bytemuck", "futures", "glam", @@ -1762,46 +2693,82 @@ dependencies = [ "guillotiere", "iced_graphics", "log", + "lyon", "once_cell", "raw-window-handle", - "rustc-hash", - "twox-hash", + "resvg", + "rustix 0.38.37", + "smithay-client-toolkit 0.19.2", + "tiny-xlib", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.32.4", + "wayland-sys", "wgpu", + "x11rb", ] [[package]] name = "iced_widget" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a177219ae51c3ba08f228ab932354b360cc669e94aec50c01e7c9b675f074c7c" +version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" dependencies = [ + "dnd", "iced_renderer", "iced_runtime", "iced_style", "num-traits", + "ouroboros", "thiserror", "unicode-segmentation", + "window_clipboard", ] [[package]] name = "iced_winit" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0c884bcb14722a57192b40a5ef6b5e170fa2f01fe2ff28d6cdd9efe37acf70" +version = "0.12.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" dependencies = [ + "dnd", "iced_graphics", "iced_runtime", "iced_style", "log", - "raw-window-handle", - "sysinfo", "thiserror", + "tracing", "web-sys", "winapi", "window_clipboard", "winit", ] +[[package]] +name = "icrate" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" +dependencies = [ + "block2 0.3.0", + "dispatch", + "objc2 0.4.1", +] + +[[package]] +name = "icrate" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb69199826926eb864697bddd27f73d9fddcffc004f5733131e15b465e30642" +dependencies = [ + "block2 0.4.0", + "objc2 0.5.2", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.5.0" @@ -1822,7 +2789,7 @@ dependencies = [ "byteorder", "color_quant", "exr", - "gif", + "gif 0.13.1", "jpeg-decoder", "num-traits", "png", @@ -1830,24 +2797,40 @@ dependencies = [ "tiff", ] +[[package]] +name = "imagesize" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" + [[package]] name = "indexmap" -version = "1.9.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ - "autocfg", - "hashbrown 0.12.3", + "equivalent", + "hashbrown", ] [[package]] -name = "indexmap" -version = "2.2.6" +name = "inotify" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" dependencies = [ - "equivalent", - "hashbrown 0.14.5", + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", ] [[package]] @@ -1857,9 +2840,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", +] + +[[package]] +name = "intl-memoizer" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe22e020fce238ae18a6d5d8c502ee76a52a6e880d99477657e6acc30ec57bda" +dependencies = [ + "type-map", + "unic-langid", +] + +[[package]] +name = "intl_pluralrules" +version = "7.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972" +dependencies = [ + "unic-langid", ] [[package]] @@ -1875,9 +2874,28 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" + +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] [[package]] name = "itoa" @@ -1885,6 +2903,22 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + [[package]] name = "jni-sys" version = "0.3.0" @@ -1893,9 +2927,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] @@ -1911,9 +2945,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -1929,15 +2963,50 @@ dependencies = [ [[package]] name = "khronos-egl" -version = "4.1.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading 0.7.4", + "libloading 0.8.5", "pkg-config", ] +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "known-folders" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d9a1740cc8b46e259a0eb787d79d855e79ff10b9855a5eba58868d5da7927c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "kurbo" version = "0.9.5" @@ -1949,9 +3018,9 @@ dependencies = [ [[package]] name = "kurisu_api" -version = "3.0.1" +version = "8.0.1" dependencies = [ - "hashbrown 0.14.5", + "hashbrown", "lektor_utils", "serde", "serde_json", @@ -1972,13 +3041,14 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "lektor_lib" -version = "3.0.1" +version = "8.0.1" dependencies = [ "anyhow", "async-trait", "futures", "lektor_payloads", "lektor_utils", + "log", "reqwest", "serde", "serde_json", @@ -1987,28 +3057,31 @@ dependencies = [ [[package]] name = "lektor_mpris" -version = "3.0.1" +version = "8.0.1" dependencies = [ - "hashbrown 0.14.5", + "derive_more", + "hashbrown", "lektor_procmacros", "lektor_utils", + "log", "serde", "tokio", - "zbus", + "zbus 4.4.0", ] [[package]] name = "lektor_nkdb" -version = "3.0.1" +version = "8.0.1" dependencies = [ "anyhow", "async-trait", "chrono", "futures", - "hashbrown 0.14.5", + "hashbrown", "kurisu_api", "lektor_procmacros", "lektor_utils", + "log", "rand", "regex", "serde", @@ -2021,7 +3094,7 @@ dependencies = [ [[package]] name = "lektor_payloads" -version = "3.0.1" +version = "8.0.1" dependencies = [ "anyhow", "async-trait", @@ -2035,24 +3108,25 @@ dependencies = [ [[package]] name = "lektor_procmacros" -version = "3.0.1" +version = "8.0.1" dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] name = "lektor_repo" -version = "3.0.1" +version = "8.0.1" dependencies = [ "anyhow", "futures", - "hashbrown 0.14.5", + "hashbrown", "kurisu_api", "lektor_nkdb", "lektor_utils", + "log", "reqwest", "serde", "serde_json", @@ -2061,10 +3135,10 @@ dependencies = [ [[package]] name = "lektor_utils" -version = "3.0.1" +version = "8.0.1" dependencies = [ "anyhow", - "base64", + "base64 0.22.1", "chrono", "dirs", "libc", @@ -2072,19 +3146,19 @@ dependencies = [ "serde", "serde_json", "tokio", - "toml", + "toml 0.8.19", ] [[package]] name = "lektord" -version = "3.0.1" +version = "8.0.1" dependencies = [ "anyhow", "async-trait", "axum", "clap", "futures", - "hashbrown 0.14.5", + "hashbrown", "hyper", "hyper-util", "lektor_mpris", @@ -2092,20 +3166,61 @@ dependencies = [ "lektor_payloads", "lektor_repo", "lektor_utils", + "log", "rand", "serde", "serde_json", "tokio", - "tokio-stream", - "tower", + "tokio-stream", + "tower 0.5.1", +] + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "libcosmic" +version = "0.1.0" +source = "git+https://github.com/pop-os/libcosmic.git#701638009df09a254b7d077ddc4d1076cd87a147" +dependencies = [ + "apply", + "ashpd 0.9.1", + "chrono", + "cosmic-config", + "cosmic-settings-daemon", + "cosmic-theme", + "css-color", + "derive_setters", + "fraction", + "freedesktop-icons", + "iced", + "iced_core", + "iced_futures", + "iced_renderer", + "iced_runtime", + "iced_style", + "iced_tiny_skia", + "iced_wgpu", + "iced_widget", + "iced_winit", + "lazy_static", + "palette", + "rfd", + "ron", + "serde", + "slotmap", + "taffy", + "thiserror", + "tokio", + "tracing", + "unicode-segmentation", + "url", + "zbus 4.4.0", ] -[[package]] -name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - [[package]] name = "libloading" version = "0.7.4" @@ -2118,12 +3233,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -2151,17 +3266,30 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", + "redox_syscall 0.5.4", ] +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "linux-raw-sys" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" + [[package]] name = "lkt" -version = "3.0.1" +version = "8.0.1" dependencies = [ "anyhow", "async-trait", @@ -2172,6 +3300,7 @@ dependencies = [ "lektor_lib", "lektor_payloads", "lektor_utils", + "log", "reqwest", "roff", "serde", @@ -2179,6 +3308,19 @@ dependencies = [ "tokio", ] +[[package]] +name = "locale_config" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934" +dependencies = [ + "lazy_static", + "objc", + "objc-foundation", + "regex", + "winapi", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -2197,11 +3339,63 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.11.1" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "lyon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7f9cda98b5430809e63ca5197b06c7d191bf7e26dfc467d5a3f0290e2a74f" +dependencies = [ + "lyon_algorithms", + "lyon_tessellation", +] + +[[package]] +name = "lyon_algorithms" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3bca95f9a4955b3e4a821fbbcd5edfbd9be2a9a50bb5758173e5358bfb4c623" +dependencies = [ + "lyon_path", + "num-traits", +] + +[[package]] +name = "lyon_geom" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edecfb8d234a2b0be031ab02ebcdd9f3b9ee418fb35e265f7a540a48d197bff9" +dependencies = [ + "arrayvec", + "euclid", + "num-traits", +] + +[[package]] +name = "lyon_path" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c08a606c7a59638d6c6aa18ac91a06aa9fb5f765a7efb27e6a4da58700740d7" +dependencies = [ + "lyon_geom", + "num-traits", +] + +[[package]] +name = "lyon_tessellation" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" +checksum = "579d42360a4b09846eff2feef28f538696c7d6c7439bfa65874ff3cbe0951b2c" dependencies = [ - "hashbrown 0.14.5", + "float_next_after", + "lyon_path", + "num-traits", ] [[package]] @@ -2227,40 +3421,22 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" -dependencies = [ - "libc", -] - -[[package]] -name = "memmap2" -version = "0.6.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872" +checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed" dependencies = [ "libc", ] [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.7.1" @@ -2281,16 +3457,25 @@ dependencies = [ [[package]] name = "metal" -version = "0.24.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de11355d1f6781482d027a3b4d4de7825dcedb197bf573e0596d00008402d060" +checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "block", "core-graphics-types", "foreign-types", "log", "objc", + "paste", +] + +[[package]] +name = "mime" +version = "0.1.0" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-8#7c59b07b9172d8e0401f7e06609e1050575309c9" +dependencies = [ + "smithay-clipboard", ] [[package]] @@ -2309,6 +3494,15 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "0.8.11" @@ -2321,6 +3515,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "mutate_once" version = "0.1.1" @@ -2329,18 +3535,18 @@ checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b" [[package]] name = "naga" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbcc2e0513220fd2b598e6068608d4462db20322c0e77e47f6f488dfcfc279cb" +version = "0.19.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=20fda69#20fda698341efbdc870b8027d6d49f5bf3f36109" dependencies = [ + "arrayvec", "bit-set", - "bitflags 1.3.2", + "bitflags 2.6.0", "codespan-reporting", "hexf-parse", - "indexmap 1.9.3", + "indexmap", "log", "num-traits", - "rustc-hash", + "rustc-hash 1.1.0", "spirv", "termcolor", "thiserror", @@ -2349,14 +3555,15 @@ dependencies = [ [[package]] name = "ndk" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "jni-sys", + "log", "ndk-sys", - "num_enum 0.5.11", + "num_enum", "raw-window-handle", "thiserror", ] @@ -2369,132 +3576,160 @@ checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-sys" -version = "0.4.1+23.1.7779620" +version = "0.5.0+25.2.9519653" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" dependencies = [ "jni-sys", ] [[package]] name = "nix" -version = "0.24.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", - "memoffset 0.6.5", + "memoffset 0.7.1", ] [[package]] name = "nix" -version = "0.25.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "autocfg", - "bitflags 1.3.2", + "bitflags 2.6.0", "cfg-if", + "cfg_aliases 0.2.1", "libc", - "memoffset 0.6.5", + "memoffset 0.9.1", ] [[package]] -name = "nix" -version = "0.26.4" +name = "notify" +version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 1.3.2", - "cfg-if", + "bitflags 2.6.0", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", "libc", - "memoffset 0.7.1", - "pin-utils", + "log", + "mio 0.8.11", + "walkdir", + "windows-sys 0.48.0", ] [[package]] -name = "nix" -version = "0.29.0" +name = "num" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "cfg_aliases 0.2.1", - "libc", - "memoffset 0.9.1", + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", ] [[package]] -name = "ntapi" -version = "0.4.1" +name = "num-bigint" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "winapi", + "num-integer", + "num-traits", ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "num-complex" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[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-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_cpus" -version = "1.16.0" +name = "num-rational" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "hermit-abi 0.3.9", - "libc", + "num-bigint", + "num-integer", + "num-traits", ] [[package]] -name = "num_enum" -version = "0.5.11" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "num_enum_derive 0.5.11", + "autocfg", + "libm", ] [[package]] -name = "num_enum" -version = "0.6.1" +name = "num_cpus" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "num_enum_derive 0.6.1", + "hermit-abi 0.3.9", + "libc", ] [[package]] -name = "num_enum_derive" -version = "0.5.11" +name = "num_enum" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", + "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.6.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] @@ -2520,30 +3755,42 @@ dependencies = [ [[package]] name = "objc-sys" -version = "0.2.0-beta.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" [[package]] name = "objc2" -version = "0.3.0-beta.3.patch-leaks.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468" +checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" dependencies = [ - "block2", "objc-sys", - "objc2-encode", + "objc2-encode 3.0.0", ] [[package]] -name = "objc2-encode" -version = "2.0.0-pre.2" +name = "objc2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" dependencies = [ "objc-sys", + "objc2-encode 4.0.3", ] +[[package]] +name = "objc2-encode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" + +[[package]] +name = "objc2-encode" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" + [[package]] name = "objc_exception" version = "0.1.2" @@ -2564,9 +3811,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.1" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] @@ -2577,6 +3824,17 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "open" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3" +dependencies = [ + "is-wsl", + "libc", + "pathdiff", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -2592,6 +3850,16 @@ dependencies = [ "libredox 0.0.2", ] +[[package]] +name = "ordered-multimap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" +dependencies = [ + "dlv-list", + "hashbrown", +] + [[package]] name = "ordered-stream" version = "0.2.0" @@ -2602,13 +3870,37 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "ouroboros" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2ba07320d39dfea882faa70554b4bd342a5f273ed59ba7c1c6b4c840492c954" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" +dependencies = [ + "heck 0.4.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "owned_ttf_parser" -version = "0.21.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b41438d2fc63c46c74a2203bf5ccd82c41ba04347b2fcf5754f230b167067d5" +checksum = "490d3a563d3122bf7c911a59b0add9389e5ec0f5f0c3ac6b91ff235a0e6a7f90" dependencies = [ - "ttf-parser 0.21.1", + "ttf-parser 0.24.1", ] [[package]] @@ -2621,6 +3913,7 @@ dependencies = [ "fast-srgb8", "palette_derive", "phf", + "serde", ] [[package]] @@ -2632,14 +3925,14 @@ dependencies = [ "by_address", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -2684,11 +3977,23 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.2", + "redox_syscall 0.5.4", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2725,7 +4030,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] @@ -2737,6 +4042,12 @@ dependencies = [ "siphasher", ] +[[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.5" @@ -2754,7 +4065,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] @@ -2771,20 +4082,20 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-io", ] [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "png" @@ -2796,29 +4107,60 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.7.4", +] + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", ] [[package]] name = "polling" -version = "3.7.2" +version = "3.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", - "rustix", + "rustix 0.38.37", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] +[[package]] +name = "pollster" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" + [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "presser" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" [[package]] name = "proc-macro-crate" @@ -2832,11 +4174,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.1", + "toml_edit 0.22.21", ] [[package]] @@ -2848,6 +4190,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", + "syn 1.0.109", "version_check", ] @@ -2888,34 +4231,26 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.28.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" -dependencies = [ - "memchr", -] - -[[package]] -name = "quick-xml" -version = "0.31.0" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" dependencies = [ "memchr", ] [[package]] name = "quinn" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 2.0.0", "rustls", + "socket2 0.5.7", "thiserror", "tokio", "tracing", @@ -2923,14 +4258,14 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.3" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand", "ring", - "rustc-hash", + "rustc-hash 2.0.0", "rustls", "slab", "thiserror", @@ -2940,22 +4275,22 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" dependencies = [ "libc", "once_cell", - "socket2", + "socket2 0.5.7", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -3004,9 +4339,9 @@ checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" [[package]] name = "raw-window-handle" -version = "0.5.2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "rayon" @@ -3028,11 +4363,17 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rctree" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b42e27ef78c35d3998403c1d26f3efd9e135d3e5121b0a4845cc5cc27547f4f" + [[package]] name = "read-fonts" -version = "0.19.3" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8b8af39d1f23869711ad4cea5e7835a20daa987f80232f7f2a2374d648ca64d" +checksum = "8c141b9980e1150201b2a3a32879001c8f975fe313ec3df5471a9b5c79a880cd" dependencies = [ "bytemuck", "font-types", @@ -3067,18 +4408,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox 0.1.3", @@ -3087,9 +4428,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -3122,11 +4463,11 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-core", "futures-util", @@ -3139,7 +4480,7 @@ dependencies = [ "ipnet", "js-sys", "log", - "mime", + "mime 0.3.17", "once_cell", "percent-encoding", "pin-project-lite", @@ -3159,7 +4500,56 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "webpki-roots", - "winreg", + "windows-registry", +] + +[[package]] +name = "resvg" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadccb3d99a9efb8e5e00c16fbb732cbe400db2ec7fc004697ee7d97d86cf1f4" +dependencies = [ + "gif 0.12.0", + "jpeg-decoder", + "log", + "pico-args", + "png", + "rgb", + "svgtypes", + "tiny-skia", + "usvg", +] + +[[package]] +name = "rfd" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a73a7337fc24366edfca76ec521f51877b114e42dab584008209cca6719251" +dependencies = [ + "ashpd 0.8.1", + "block", + "dispatch", + "js-sys", + "log", + "objc", + "objc-foundation", + "objc_id", + "pollster", + "raw-window-handle", + "urlencoding", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rgb" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +dependencies = [ + "bytemuck", ] [[package]] @@ -3179,9 +4569,77 @@ dependencies = [ [[package]] name = "roff" -version = "0.2.1" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3" + +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags 2.6.0", + "serde", + "serde_derive", +] + +[[package]] +name = "roxmltree" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f" + +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + +[[package]] +name = "rust-embed" +version = "8.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn 2.0.77", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d" +dependencies = [ + "sha2", + "walkdir", +] + +[[package]] +name = "rust-ini" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" +checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a" +dependencies = [ + "cfg-if", + "ordered-multimap", +] [[package]] name = "rustc-demangle" @@ -3195,24 +4653,44 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.14", "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.23.10" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "once_cell", "ring", @@ -3224,25 +4702,25 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ - "base64", + "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" -version = "0.102.5" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -3257,18 +4735,34 @@ checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rustybuzz" -version = "0.8.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82eea22c8f56965eeaf3a209b3d24508256c7b920fb3b6211b8ba0f7c0583250" +checksum = "f0ae5692c5beaad6a9e22830deeed7874eae8a4e3ba4076fb48e12c56856222c" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", + "bytemuck", + "smallvec", + "ttf-parser 0.20.0", + "unicode-bidi-mirroring 0.1.0", + "unicode-ccc 0.1.2", + "unicode-properties", + "unicode-script", +] + +[[package]] +name = "rustybuzz" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c" +dependencies = [ + "bitflags 2.6.0", "bytemuck", "libm", "smallvec", - "ttf-parser 0.19.2", - "unicode-bidi-mirroring", - "unicode-ccc", - "unicode-general-category", + "ttf-parser 0.21.1", + "unicode-bidi-mirroring 0.2.0", + "unicode-ccc 0.2.0", + "unicode-properties", "unicode-script", ] @@ -3278,6 +4772,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -3292,45 +4795,61 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sctk-adwaita" -version = "0.5.4" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda4e97be1fd174ccc2aae81c8b694e803fa99b34e8fd0f057a9d70698e3ed09" +checksum = "70b31447ca297092c5a9916fc3b955203157b37c19ca8edde4f52e9843e602c7" dependencies = [ "ab_glyph", "log", - "memmap2 0.5.10", - "smithay-client-toolkit 0.16.1", - "tiny-skia 0.8.4", + "memmap2 0.9.5", + "smithay-client-toolkit 0.18.1", + "tiny-skia", +] + +[[package]] +name = "self_cell" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" +dependencies = [ + "self_cell 1.0.4", ] +[[package]] +name = "self_cell" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" + [[package]] name = "serde" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ - "indexmap 2.2.6", + "indexmap", "itoa", + "memchr", "ryu", "serde", ] @@ -3353,14 +4872,14 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -3412,6 +4931,12 @@ dependencies = [ "tokio", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -3427,6 +4952,15 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[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" @@ -3435,9 +4969,9 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "skrifa" -version = "0.19.3" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab45fb68b53576a43d4fc0e9ec8ea64e29a4d2cc7f44506964cb75f288222e9" +checksum = "abea4738067b1e628c6ce28b2c216c19e9ea95715cdb332680e821c3bec2ef23" dependencies = [ "bytemuck", "read-fonts", @@ -3469,57 +5003,85 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smithay-client-toolkit" -version = "0.16.1" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870427e30b8f2cbe64bf43ec4b86e88fe39b0a84b3f15efd9c9c2d020bc86eb9" +checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" dependencies = [ - "bitflags 1.3.2", - "calloop 0.10.6", - "dlib", - "lazy_static", + "bitflags 2.6.0", + "calloop 0.12.4", + "calloop-wayland-source 0.2.0", + "cursor-icon", + "libc", "log", - "memmap2 0.5.10", - "nix 0.24.3", - "pkg-config", - "wayland-client 0.29.5", - "wayland-cursor 0.29.5", - "wayland-protocols 0.29.5", + "memmap2 0.9.5", + "rustix 0.38.37", + "thiserror", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols 0.31.2", + "wayland-protocols-wlr 0.2.0", + "wayland-scanner", + "xkeysym", ] [[package]] name = "smithay-client-toolkit" -version = "0.18.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ "bitflags 2.6.0", - "calloop 0.12.4", - "calloop-wayland-source", + "bytemuck", + "calloop 0.13.0", + "calloop-wayland-source 0.3.0", "cursor-icon", "libc", "log", - "memmap2 0.9.4", - "rustix", + "memmap2 0.9.5", + "pkg-config", + "rustix 0.38.37", "thiserror", - "wayland-backend 0.3.4", - "wayland-client 0.31.3", + "wayland-backend", + "wayland-client", "wayland-csd-frame", - "wayland-cursor 0.31.3", - "wayland-protocols 0.31.2", - "wayland-protocols-wlr", - "wayland-scanner 0.31.2", + "wayland-cursor", + "wayland-protocols 0.32.4", + "wayland-protocols-wlr 0.3.4", + "wayland-scanner", + "xkbcommon", "xkeysym", ] [[package]] name = "smithay-clipboard" -version = "0.7.1" +version = "0.8.0" +source = "git+https://github.com/pop-os/smithay-clipboard?tag=pop-dnd-5#5a3007def49eb678d1144850c9ee04b80707c56a" +dependencies = [ + "libc", + "raw-window-handle", + "smithay-client-toolkit 0.19.2", + "wayland-backend", +] + +[[package]] +name = "smol_str" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c091e7354ea8059d6ad99eace06dd13ddeedbb0ac72d40a9a6e7ff790525882d" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", - "smithay-client-toolkit 0.18.1", - "wayland-backend 0.3.4", + "winapi", ] [[package]] @@ -3534,30 +5096,32 @@ dependencies = [ [[package]] name = "softbuffer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2b953f6ba7285f0af131eb748aabd8ddaf53e0b81dda3ba5d803b0847d6559f" +version = "0.4.1" +source = "git+https://github.com/pop-os/softbuffer?tag=cosmic-4.0#6e75b1ad7e98397d37cb187886d05969bc480995" dependencies = [ + "as-raw-xcb-connection", "bytemuck", - "cfg_aliases 0.1.1", + "cfg_aliases 0.2.1", "cocoa", "core-graphics", - "fastrand 1.9.0", + "drm", + "fastrand 2.1.1", "foreign-types", + "js-sys", "log", - "nix 0.26.4", + "memmap2 0.9.5", "objc", "raw-window-handle", - "redox_syscall 0.3.5", - "thiserror", + "redox_syscall 0.4.1", + "rustix 0.38.37", + "tiny-xlib", "wasm-bindgen", - "wayland-backend 0.1.2", - "wayland-client 0.30.2", - "wayland-sys 0.30.1", + "wayland-backend", + "wayland-client", + "wayland-sys", "web-sys", - "windows-sys 0.48.0", - "x11-dl", - "x11rb 0.11.1", + "windows-sys 0.52.0", + "x11rb", ] [[package]] @@ -3571,12 +5135,11 @@ dependencies = [ [[package]] name = "spirv" -version = "0.2.0+1.5.4" +version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 1.3.2", - "num-traits", + "bitflags 2.6.0", ] [[package]] @@ -3586,16 +5149,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] -name = "str-buf" -version = "1.0.6" +name = "strict-num" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] [[package]] -name = "strict-num" -version = "0.1.1" +name = "strsim" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" @@ -3609,11 +5175,21 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20e16a0f46cf5fd675563ef54f26e83e20f2366bcf027bcb3cc3ed2b98aaf2ca" +[[package]] +name = "svgtypes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e44e288cd960318917cbd540340968b90becc8bc81f171345d706e7a89d9d70" +dependencies = [ + "kurbo", + "siphasher", +] + [[package]] name = "swash" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d7773d67fe3373048cf840bfcc54ec3207cfc1e95c526b287ef2eb5eff9faf6" +checksum = "93cdc334a50fcc2aa3f04761af3b28196280a6aaadb1ef11215c478ae32615ac" dependencies = [ "skrifa", "yazi", @@ -3633,9 +5209,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.68" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -3653,6 +5229,9 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "sys-locale" @@ -3664,30 +5243,27 @@ dependencies = [ ] [[package]] -name = "sysinfo" -version = "0.28.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c2f3ca6693feb29a89724516f016488e9aafc7f37264f898593ee4b942f31b" +name = "taffy" +version = "0.3.11" +source = "git+https://github.com/DioxusLabs/taffy?rev=7781c70#7781c70241f7f572130c13106f2a869a9cf80885" dependencies = [ - "cfg-if", - "core-foundation-sys", - "libc", - "ntapi", - "once_cell", - "rayon", - "winapi", + "arrayvec", + "grid", + "num-traits", + "slotmap", ] [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", - "fastrand 2.1.0", - "rustix", - "windows-sys 0.52.0", + "fastrand 2.1.1", + "once_cell", + "rustix 0.38.37", + "windows-sys 0.59.0", ] [[package]] @@ -3705,28 +5281,28 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix", + "rustix 0.38.37", "windows-sys 0.48.0", ] [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] @@ -3741,24 +5317,19 @@ dependencies = [ ] [[package]] -name = "tiny-skia" -version = "0.8.4" +name = "tiny-keccak" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" dependencies = [ - "arrayref", - "arrayvec", - "bytemuck", - "cfg-if", - "png", - "tiny-skia-path 0.8.4", + "crunchy", ] [[package]] name = "tiny-skia" -version = "0.10.0" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db11798945fa5c3e5490c794ccca7c6de86d3afdd54b4eb324109939c6f37bc" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" dependencies = [ "arrayref", "arrayvec", @@ -3766,14 +5337,14 @@ dependencies = [ "cfg-if", "log", "png", - "tiny-skia-path 0.10.0", + "tiny-skia-path", ] [[package]] name = "tiny-skia-path" -version = "0.8.4" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adbfb5d3f3dd57a0e11d12f4f13d4ebbbc1b5c15b7ab0a156d030b21da5f677c" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" dependencies = [ "arrayref", "bytemuck", @@ -3781,21 +5352,32 @@ dependencies = [ ] [[package]] -name = "tiny-skia-path" -version = "0.10.0" +name = "tiny-xlib" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f60aa35c89ac2687ace1a2556eaaea68e8c0d47408a2e3e7f5c98a489e7281c" +checksum = "1d52f22673960ad13af14ff4025997312def1223bfa7c8e4949d099e6b3d5d1c" dependencies = [ - "arrayref", - "bytemuck", - "strict-num", + "as-raw-xcb-connection", + "ctor-lite", + "libloading 0.8.5", + "pkg-config", + "tracing", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", ] [[package]] name = "tinyvec" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -3808,32 +5390,32 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", - "mio", - "num_cpus", + "mio 1.0.2", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.7", "tokio-macros", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] @@ -3849,9 +5431,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -3860,9 +5442,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -3873,59 +5455,56 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.14" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "indexmap 2.2.6", "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.22.14", ] [[package]] -name = "toml_datetime" -version = "0.6.6" +name = "toml" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.21", ] [[package]] -name = "toml_edit" -version = "0.19.15" +name = "toml_datetime" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ - "indexmap 2.2.6", - "toml_datetime", - "winnow 0.5.40", + "serde", ] [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.6", + "indexmap", "toml_datetime", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.14" +version = "0.22.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" dependencies = [ - "indexmap 2.2.6", + "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.13", + "winnow 0.6.18", ] [[package]] @@ -3941,20 +5520,34 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing", +] + +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tokio", + "tower-layer", + "tower-service", ] [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -3962,7 +5555,6 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3976,7 +5568,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] @@ -3996,9 +5588,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "ttf-parser" -version = "0.19.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49d64318d8311fc2668e48b63969f4343e0a85c4a109aa8460d6672e364b8bd1" +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" [[package]] name = "ttf-parser" @@ -4007,14 +5599,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" [[package]] -name = "twox-hash" -version = "1.6.3" +name = "ttf-parser" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a" + +[[package]] +name = "type-map" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" dependencies = [ - "cfg-if", - "rand", - "static_assertions", + "rustc-hash 1.1.0", ] [[package]] @@ -4034,6 +5630,25 @@ dependencies = [ "winapi", ] +[[package]] +name = "unic-langid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44" +dependencies = [ + "unic-langid-impl", +] + +[[package]] +name = "unic-langid-impl" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5" +dependencies = [ + "serde", + "tinystr", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -4046,6 +5661,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694" +[[package]] +name = "unicode-bidi-mirroring" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cb788ffebc92c5948d0e997106233eeb1d8b9512f93f41651f52b6c5f5af86" + [[package]] name = "unicode-ccc" version = "0.1.2" @@ -4053,16 +5674,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1" [[package]] -name = "unicode-general-category" -version = "0.6.0" +name = "unicode-ccc" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7" +checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-linebreak" @@ -4072,36 +5693,48 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-properties" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" + [[package]] name = "unicode-script" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8d71f5726e5f285a935e9fe8edfd53f0491eb6e9a5774097fdabee7cd8c9cd" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-vo" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" @@ -4118,19 +5751,97 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[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-text-layout", + "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 0.19.0", + "simplecss", + "siphasher", + "svgtypes", + "usvg-tree", +] + +[[package]] +name = "usvg-text-layout" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d383a3965de199d7f96d4e11a44dd859f46e86de7f3dca9a39bf82605da0a37c" +dependencies = [ + "fontdb", + "kurbo", + "log", + "rustybuzz 0.12.1", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "usvg-tree", ] [[package]] -name = "vec_map" -version = "0.8.2" +name = "usvg-tree" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "8ee3d202ebdb97a6215604b8f5b4d6ef9024efd623cf2e373a6416ba976ec7d3" +dependencies = [ + "rctree", + "strict-num", + "svgtypes", + "tiny-skia-path", +] [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + +[[package]] +name = "walkdir" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] [[package]] name = "want" @@ -4149,34 +5860,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -4186,9 +5898,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4196,22 +5908,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-timer" @@ -4230,83 +5942,28 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b48e27457e8da3b2260ac60d0a94512f5cba36448679f3747c0865b7893ed8" -dependencies = [ - "cc", - "downcast-rs", - "io-lifetimes", - "nix 0.26.4", - "scoped-tls", - "smallvec", - "wayland-sys 0.30.1", -] - -[[package]] -name = "wayland-backend" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34e9e6b6d4a2bb4e7e69433e0b35c7923b95d4dc8503a84d25ec917a4bbfdf07" +checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" dependencies = [ "cc", "downcast-rs", - "rustix", + "rustix 0.38.37", "scoped-tls", "smallvec", - "wayland-sys 0.31.2", -] - -[[package]] -name = "wayland-client" -version = "0.29.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" -dependencies = [ - "bitflags 1.3.2", - "downcast-rs", - "libc", - "nix 0.24.3", - "scoped-tls", - "wayland-commons", - "wayland-scanner 0.29.5", - "wayland-sys 0.29.5", -] - -[[package]] -name = "wayland-client" -version = "0.30.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489c9654770f674fc7e266b3c579f4053d7551df0ceb392f153adb1f9ed06ac8" -dependencies = [ - "bitflags 1.3.2", - "nix 0.26.4", - "wayland-backend 0.1.2", - "wayland-scanner 0.30.1", + "wayland-sys", ] [[package]] name = "wayland-client" -version = "0.31.3" +version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e63801c85358a431f986cffa74ba9599ff571fc5774ac113ed3b490c19a1133" +checksum = "e3f45d1222915ef1fd2057220c1d9d9624b7654443ea35c3877f7a52bd0a5a2d" dependencies = [ "bitflags 2.6.0", - "rustix", - "wayland-backend 0.3.4", - "wayland-scanner 0.31.2", -] - -[[package]] -name = "wayland-commons" -version = "0.29.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" -dependencies = [ - "nix 0.24.3", - "once_cell", - "smallvec", - "wayland-sys 0.29.5", + "rustix 0.38.37", + "wayland-backend", + "wayland-scanner", ] [[package]] @@ -4317,53 +5974,55 @@ checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ "bitflags 2.6.0", "cursor-icon", - "wayland-backend 0.3.4", + "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.29.5" +version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" +checksum = "3a94697e66e76c85923b0d28a0c251e8f0666f58fc47d316c0f4da6da75d37cb" dependencies = [ - "nix 0.24.3", - "wayland-client 0.29.5", + "rustix 0.38.37", + "wayland-client", "xcursor", ] [[package]] -name = "wayland-cursor" -version = "0.31.3" +name = "wayland-protocols" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a206e8b2b53b1d3fcb9428fec72bc278ce539e2fa81fe2bfc1ab27703d5187b9" +checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" dependencies = [ - "rustix", - "wayland-client 0.31.3", - "xcursor", + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", ] [[package]] name = "wayland-protocols" -version = "0.29.5" +version = "0.32.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" +checksum = "2b5755d77ae9040bb872a25026555ce4cb0ae75fd923e90d25fba07d81057de0" dependencies = [ - "bitflags 1.3.2", - "wayland-client 0.29.5", - "wayland-commons", - "wayland-scanner 0.29.5", + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", ] [[package]] -name = "wayland-protocols" -version = "0.31.2" +name = "wayland-protocols-plasma" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" +checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" dependencies = [ "bitflags 2.6.0", - "wayland-backend 0.3.4", - "wayland-client 0.31.3", - "wayland-scanner 0.31.2", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.31.2", + "wayland-scanner", ] [[package]] @@ -4373,85 +6032,63 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" dependencies = [ "bitflags 2.6.0", - "wayland-backend 0.3.4", - "wayland-client 0.31.3", + "wayland-backend", + "wayland-client", "wayland-protocols 0.31.2", - "wayland-scanner 0.31.2", -] - -[[package]] -name = "wayland-scanner" -version = "0.29.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" -dependencies = [ - "proc-macro2", - "quote", - "xml-rs", + "wayland-scanner", ] [[package]] -name = "wayland-scanner" -version = "0.30.1" +name = "wayland-protocols-wlr" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9b873b257fbc32ec909c0eb80dea312076a67014e65e245f5eb69a6b8ab330e" +checksum = "dad87b5fd1b1d3ca2f792df8f686a2a11e3fe1077b71096f7a175ab699f89109" dependencies = [ - "proc-macro2", - "quick-xml 0.28.2", - "quote", + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.32.4", + "wayland-scanner", ] [[package]] name = "wayland-scanner" -version = "0.31.2" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67da50b9f80159dec0ea4c11c13e24ef9e7574bd6ce24b01860a175010cea565" +checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" dependencies = [ "proc-macro2", - "quick-xml 0.31.0", + "quick-xml", "quote", ] [[package]] name = "wayland-sys" -version = "0.29.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" -dependencies = [ - "dlib", - "lazy_static", - "pkg-config", -] - -[[package]] -name = "wayland-sys" -version = "0.30.1" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b2a02ac608e07132978689a6f9bf4214949c85998c247abadd4f4129b1aa06" +checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" dependencies = [ "dlib", - "lazy_static", "log", + "once_cell", "pkg-config", ] [[package]] -name = "wayland-sys" -version = "0.31.2" +name = "web-sys" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "105b1842da6554f91526c14a2a2172897b7f745a805d62af4ce698706be79c12" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ - "dlib", - "log", - "once_cell", - "pkg-config", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "web-sys" -version = "0.3.69" +name = "web-time" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" dependencies = [ "js-sys", "wasm-bindgen", @@ -4459,9 +6096,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -4474,12 +6111,12 @@ checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" [[package]] name = "wgpu" -version = "0.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "480c965c9306872eb6255fa55e4b4953be55a8b64d57e61d7ff840d3dcc051cd" +version = "0.19.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=20fda69#20fda698341efbdc870b8027d6d49f5bf3f36109" dependencies = [ "arrayvec", "cfg-if", + "cfg_aliases 0.1.1", "js-sys", "log", "naga", @@ -4498,20 +6135,22 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f478237b4bf0d5b70a39898a66fa67ca3a007d79f2520485b8b0c3dfc46f8c2" +version = "0.19.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=20fda69#20fda698341efbdc870b8027d6d49f5bf3f36109" dependencies = [ "arrayvec", "bit-vec", "bitflags 2.6.0", + "cfg_aliases 0.1.1", "codespan-reporting", + "indexmap", "log", "naga", + "once_cell", "parking_lot 0.12.3", "profiling", "raw-window-handle", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", "thiserror", "web-sys", @@ -4521,9 +6160,8 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecb3258078e936deee14fd4e0febe1cfe9bbb5ffef165cb60218d2ee5eb4448" +version = "0.19.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=20fda69#20fda698341efbdc870b8027d6d49f5bf3f36109" dependencies = [ "android_system_properties", "arrayvec", @@ -4531,10 +6169,11 @@ dependencies = [ "bit-set", "bitflags 2.6.0", "block", + "cfg_aliases 0.1.1", "core-graphics-types", "d3d12", - "foreign-types", "glow", + "glutin_wgl_sys", "gpu-alloc", "gpu-allocator", "gpu-descriptor", @@ -4542,17 +6181,18 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.8.4", + "libloading 0.8.5", "log", "metal", "naga", "objc", + "once_cell", "parking_lot 0.12.3", "profiling", "range-alloc", "raw-window-handle", "renderdoc-sys", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", "thiserror", "wasm-bindgen", @@ -4563,9 +6203,8 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c153280bb108c2979eb5c7391cb18c56642dd3c072e55f52065e13e2a1252a" +version = "0.19.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=20fda69#20fda698341efbdc870b8027d6d49f5bf3f36109" dependencies = [ "bitflags 2.6.0", "js-sys", @@ -4596,20 +6235,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "winapi-wsapoll" -version = "0.1.2" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eafc5f679c576995526e81635d0cf9695841736712b4e892f87abbe6fed3f28" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -4620,25 +6250,38 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "window_clipboard" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63287c9c4396ccf5346d035a9b0fcaead9e18377637f5eaa78b7ac65c873ff7d" +version = "0.4.1" +source = "git+https://github.com/pop-os/window_clipboard.git?tag=pop-dnd-8#7c59b07b9172d8e0401f7e06609e1050575309c9" dependencies = [ "clipboard-win", "clipboard_macos", "clipboard_wayland", "clipboard_x11", + "dnd", + "mime 0.1.0", "raw-window-handle", "thiserror", ] [[package]] name = "windows" -version = "0.44.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.42.2", + "windows-implement", + "windows-interface", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets 0.52.6", ] [[package]] @@ -4647,7 +6290,59 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2ee588991b9e7e6c8338edf3333fbe4da35dc72092643958ebb43f0ab2c49c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "windows-interface" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6fb8df20c9bcaa8ad6ab513f7b40104840c8867d5751126e4df3b08388d0cc7" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", ] [[package]] @@ -4674,7 +6369,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -4709,18 +6413,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -4737,9 +6441,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -4755,9 +6459,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -4773,15 +6477,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -4797,9 +6501,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -4815,9 +6519,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -4833,9 +6537,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -4851,43 +6555,55 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.28.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9596d90b45384f5281384ab204224876e8e8bf7d58366d9b795ad99aa9894b94" +version = "0.29.10" +source = "git+https://github.com/pop-os/winit.git?branch=winit-0.29#bdc66109acc85c912264c9e4b864520345bdb45f" dependencies = [ + "ahash", "android-activity", - "bitflags 1.3.2", + "atomic-waker", + "bitflags 2.6.0", + "bytemuck", + "calloop 0.12.4", "cfg_aliases 0.1.1", "core-foundation", "core-graphics", - "dispatch", - "instant", + "cursor-icon", + "icrate 0.0.4", + "js-sys", "libc", "log", - "mio", + "memmap2 0.9.5", "ndk", - "objc2", + "ndk-sys", + "objc2 0.4.1", "once_cell", "orbclient", "percent-encoding", "raw-window-handle", "redox_syscall 0.3.5", + "rustix 0.38.37", "sctk-adwaita", - "smithay-client-toolkit 0.16.1", + "smithay-client-toolkit 0.18.1", + "smol_str", + "unicode-segmentation", "wasm-bindgen", - "wayland-client 0.29.5", - "wayland-commons", - "wayland-protocols 0.29.5", - "wayland-scanner 0.29.5", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.31.2", + "wayland-protocols-plasma", "web-sys", - "windows-sys 0.45.0", + "web-time", + "windows-sys 0.48.0", "x11-dl", + "x11rb", + "xkbcommon-dl", ] [[package]] @@ -4901,23 +6617,13 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.13" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "x11-dl" version = "2.21.0" @@ -4931,60 +6637,69 @@ dependencies = [ [[package]] name = "x11rb" -version = "0.11.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf3c79412dd91bae7a7366b8ad1565a85e35dd049affc3a6a2c549e97419617" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ - "gethostname 0.2.3", + "as-raw-xcb-connection", + "gethostname", "libc", - "libloading 0.7.4", - "nix 0.25.1", + "libloading 0.8.5", "once_cell", - "winapi", - "winapi-wsapoll", - "x11rb-protocol 0.11.1", + "rustix 0.38.37", + "x11rb-protocol", ] [[package]] -name = "x11rb" +name = "x11rb-protocol" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" -dependencies = [ - "gethostname 0.4.3", - "rustix", - "x11rb-protocol 0.13.1", -] +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] -name = "x11rb-protocol" -version = "0.11.1" +name = "xcursor" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0b1513b141123073ce54d5bb1d33f801f17508fbd61e02060b1214e96d39c56" -dependencies = [ - "nix 0.25.1", -] +checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" [[package]] -name = "x11rb-protocol" -version = "0.13.1" +name = "xdg" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" +checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" [[package]] -name = "xcursor" -version = "0.3.5" +name = "xdg-home" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911" +checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] [[package]] -name = "xdg-home" -version = "1.2.0" +name = "xkbcommon" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca91dcf8f93db085f3a0a29358cd0b9d670915468f4290e8b85d118a34211ab8" +checksum = "13867d259930edc7091a6c41b4ce6eee464328c6ff9659b7e4c668ca20d4c91e" dependencies = [ "libc", - "windows-sys 0.52.0", + "memmap2 0.8.0", + "xkeysym", +] + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.6.0", + "dlib", + "log", + "once_cell", + "xkeysym", ] [[package]] @@ -4992,12 +6707,27 @@ name = "xkeysym" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" +dependencies = [ + "bytemuck", +] [[package]] name = "xml-rs" -version = "0.8.20" +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 = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + +[[package]] +name = "xxhash-rust" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984" [[package]] name = "yazi" @@ -5007,16 +6737,63 @@ checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1" [[package]] name = "zbus" -version = "4.3.1" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "675d170b632a6ad49804c8cf2105d7c31eddd3312555cffd4b740e08e97c25e6" +dependencies = [ + "async-broadcast 0.5.1", + "async-executor", + "async-fs 1.6.0", + "async-io 1.13.0", + "async-lock 2.8.0", + "async-process 1.8.1", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "byteorder", + "derivative", + "enumflags2", + "event-listener 2.5.3", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix 0.26.4", + "once_cell", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "winapi", + "xdg-home", + "zbus_macros 3.15.2", + "zbus_names 2.6.1", + "zvariant 3.15.2", +] + +[[package]] +name = "zbus" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "851238c133804e0aa888edf4a0229481c753544ca12a60fd1c3230c8a500fe40" +checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" dependencies = [ - "async-broadcast", - "async-process", + "async-broadcast 0.7.1", + "async-executor", + "async-fs 2.1.2", + "async-io 2.3.4", + "async-lock 3.4.0", + "async-process 2.3.0", "async-recursion", + "async-task", "async-trait", + "blocking", "enumflags2", - "event-listener", + "event-listener 5.3.1", "futures-core", "futures-sink", "futures-util", @@ -5033,22 +6810,47 @@ dependencies = [ "uds_windows", "windows-sys 0.52.0", "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", + "zbus_macros 4.4.0", + "zbus_names 3.0.0", + "zvariant 4.2.0", +] + +[[package]] +name = "zbus_macros" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7131497b0f887e8061b430c530240063d33bf9455fa34438f388a245da69e0a5" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "zvariant_utils 1.0.1", ] [[package]] name = "zbus_macros" -version = "4.3.1" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5a3f12c20bd473be3194af6b49d50d7bb804ef3192dc70eddedb26b85d9da7" +checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.68", - "zvariant_utils", + "syn 2.0.77", + "zvariant_utils 2.1.0", +] + +[[package]] +name = "zbus_names" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "437d738d3750bed6ca9b8d423ccc7a8eb284f6b1d6d4e225a0e4e6258d864c8d" +dependencies = [ + "serde", + "static_assertions", + "zvariant 3.15.2", ] [[package]] @@ -5059,7 +6861,7 @@ checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" dependencies = [ "serde", "static_assertions", - "zvariant", + "zvariant 4.2.0", ] [[package]] @@ -5074,6 +6876,7 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -5085,7 +6888,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] [[package]] @@ -5105,37 +6908,76 @@ dependencies = [ [[package]] name = "zvariant" -version = "4.1.2" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eef2be88ba09b358d3b58aca6e41cd853631d44787f319a1383ca83424fb2db" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive 3.15.2", +] + +[[package]] +name = "zvariant" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1724a2b330760dc7d2a8402d841119dc869ef120b139d29862d6980e9c75bfc9" +checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" dependencies = [ "endi", "enumflags2", "serde", "static_assertions", - "zvariant_derive", + "url", + "zvariant_derive 4.2.0", +] + +[[package]] +name = "zvariant_derive" +version = "3.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c24dc0bed72f5f90d1f8bb5b07228cbf63b3c6e9f82d82559d4bae666e7ed9" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", + "zvariant_utils 1.0.1", ] [[package]] name = "zvariant_derive" -version = "4.1.2" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55025a7a518ad14518fb243559c058a2e5b848b015e31f1d90414f36e3317859" +checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.68", - "zvariant_utils", + "syn 2.0.77", + "zvariant_utils 2.1.0", ] [[package]] name = "zvariant_utils" -version = "2.0.0" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "zvariant_utils" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc242db087efc22bd9ade7aa7809e4ba828132edc312871584a6b4391bdf8786" +checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" dependencies = [ "proc-macro2", "quote", - "syn 2.0.68", + "syn 2.0.77", ] diff --git a/Cargo.toml b/Cargo.toml index 43cd9834..4c9cd820 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,48 +21,58 @@ authors = [ "Étienne BRATEAU <etienne.brateau@gmail.com>", "Tristan DEROUET <tristan.derouet@gmail.com>", ] -rust-version = "1.76" -version = "3.0.1" -license = "MIT" +rust-version = '1.80' +version = '8.0.1' +license = 'MIT' [profile.release] -strip = true -debug = false -lto = true -opt-level = "s" +strip = true +debug = false +lto = true +opt-level = 's' codegen-units = 1 -panic = 'unwind' +panic = 'unwind' [profile.dev] -debug = true -opt-level = "s" -panic = 'unwind' +debug = true +opt-level = 's' +panic = 'unwind' [workspace.dependencies] -url = { version = "*", default-features = false } -zbus = { version = "*", default-features = false, features = ["tokio"] } +url = { version = "*", default-features = false } +zbus = { version = "*", default-features = false, features = ["tokio"] } chrono = { version = "*", default-features = false, features = ["clock"] } sha256 = { version = "*", default-features = false, features = ["async"] } anyhow = { version = "*", default-features = false, features = ["std"] } -regex = { version = "*", default-features = false, features = ["std", "perf"] } -log = "*" -rand = "*" +regex = { version = "*", default-features = false, features = ["std", "perf"] } +log = "*" +rand = "*" base64 = "*" -dirs = "*" +dirs = "*" +open = "*" + +derive_more = { version = "*", features = ["full"] } + +i18n-embed-fl = "0.9.1" +rust-embed = "8.5.0" +i18n-embed = { version = "*", features = ["fluent-system", "desktop-requester"] } + +# Local crates +lektor_lib = { path = "lektor_lib" } +lektor_utils = { path = "lektor_utils" } +lektor_mpris = { path = "lektor_mpris" } +lektor_payloads = { path = "lektor_payloads" } +lektor_procmacros = { path = "lektor_procmacros" } # Data Structures hashbrown = { version = "*", features = ["serde"] } # Serialization & Deserialization +toml = "*" serde_json = { version = "*", default-features = false, features = [ "std", "preserve_order", ] } -toml = { version = "*", default-features = false, features = [ - "preserve_order", - "display", - "parse", -] } serde = { version = "*", default-features = false, features = [ "rc", "std", @@ -71,17 +81,12 @@ serde = { version = "*", default-features = false, features = [ # Async stuff async-trait = "*" +futures-util = "*" futures = { version = "*", default-features = false, features = [ "std", "async-await", ] } -tokio = { version = "*", default-features = false, features = [ - "macros", - "rt-multi-thread", - "sync", - "fs", - "signal", -] } +tokio = { version = "*", features = [ "full" ] } tokio-stream = { version = "*", default-features = false, features = ["net"] } # Web stuff @@ -113,20 +118,19 @@ clap = { version = "*", default-features = false, features = [ "derive", ] } -# GUI, keep in mind that we must use the same version of image as ixed! -image = { version = "0.24", default-features = false, features = ["png"] } -iced = { version = "*", features = ["tokio", "system", "advanced", "image"] } -iced_aw = { version = "*", default-features = false, features = [ - "split", - "wrap", - "badge", - "icon_text", - "spinner", - "context_menu", -] } - # Proc macro things -syn = "*" -quote = { version = "*", default-features = false } -proc-macro2 = { version = "*", default-features = false } +syn = "*" +quote = { version = "*", default-features = false } +proc-macro2 = { version = "*", default-features = false } proc-macro-error = { version = "*", default-features = false } + +# GUI, we use libcosmic because most of the eavy lifting is done for us. +# Some things are still a bit bothering: +# - the icons can't be vendored inside the binary on linux, needs to be +# installed in a standard way.... +# - clicking on buttons on the header can drag the window... +[workspace.dependencies.libcosmic] +git = "https://github.com/pop-os/libcosmic.git" +default-features = false +features = [ "dbus-config", "tokio", "winit", "wgpu", "single-instance" ] + diff --git a/README.md b/README.md index cfe0e74b..626c2116 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,12 @@ [](https://git.iiens.net/martin2018/lektor/-/commits/master) [](https://matrix.to/#/#baka-dev-lektor:iiens.net) -[](https://git.iiens.net/martin2018/lektor/-/commits/master) -[](https://git.iiens.net/martin2018/lektor/-/tags) +[](https://git.iiens.net/martin2018/lektor/-/commits/master) +[](https://git.iiens.net/martin2018/lektor/-/tags) +[](https://git.iiens.net/martin2018/lektor/-/tags) +<a href="https://github.com/iced-rs/iced"> + <img src="https://gist.githubusercontent.com/hecrj/ad7ecd38f6e47ff3688a38c79fd108f0/raw/74384875ecbad02ae2a926425e9bcafd0695bade/color.svg" width="100px"> +</a> A Karaoke player made to replace the old bash scripts on Sakura. @@ -30,6 +34,7 @@ The lektord and related binaries and source code are under the MIT license. Plea - C++ compiler with [C++17 support](https://en.cppreference.com/w/cpp/17) - [mpv](https://mpv.io/) development library - [Qt6](https://www.qt.io/) development library: QtCore, QtWidgets, QtOpenGL, QtOpenGLWidgets. +- [Cosmic icons](https://github.com/pop-os/cosmic-icons) are required for amadeus, on archlinux: `yay -Sy cosmic-icons-git` To visualize dependencies of the rust part of lektor, you can call the script [print-cargo-deps.bash](/utils/scripts/print-cargo-deps.bash) from the workspaces. You will also @@ -126,7 +131,5 @@ Lektor uses a single configuration file per tool, you will find those files in t The default configuration file will be created on the first launch of the tool. In this configuration folder the lektord program will store its configuration in `lektord.toml`, lkt in -`lkt.toml`, amadeus in `amadeus.toml`, etc. - -For amadeus, you can edit its configuration file in the settings section. - +`lkt.toml`. For amadeus, you can edit its configuration file in the settings section. The files will +be stored in `$HOME/.config/cosmic/fr.iiens.baka.Amadeus`. diff --git a/amadeus/Cargo.toml b/amadeus/Cargo.toml index de5b3c6a..272ba469 100644 --- a/amadeus/Cargo.toml +++ b/amadeus/Cargo.toml @@ -1,31 +1,42 @@ [package] -name = "amadeus" -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true -rust-version.workspace = true +name = "amadeus" description = "Amadeus-RS, graphical interface for lektord" +version = "0.0.1" + +rust-version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true [dependencies] -serde.workspace = true +lektor_lib.workspace = true +lektor_utils.workspace = true +lektor_mpris.workspace = true +lektor_payloads.workspace = true +lektor_procmacros.workspace = true + +serde.workspace = true serde_json.workspace = true -chrono.workspace = true -anyhow.workspace = true -hashbrown.workspace = true +log.workspace = true +chrono.workspace = true +anyhow.workspace = true +hashbrown.workspace = true +derive_more.workspace = true + +libcosmic.workspace = true +open.workspace = true -image.workspace = true -iced.workspace = true -iced_aw.workspace = true +futures-util.workspace = true +tokio.workspace = true +reqwest.workspace = true +futures.workspace = true +async-trait.workspace = true -tokio.workspace = true -reqwest.workspace = true -futures.workspace = true -async-trait.workspace = true +i18n-embed-fl.workspace = true +rust-embed.workspace = true +i18n-embed.workspace = true -lektor_lib = { path = "../lektor_lib" } +[build-dependencies] +anyhow.workspace = true lektor_utils = { path = "../lektor_utils" } -lektor_mpris = { path = "../lektor_mpris" } -lektor_payloads = { path = "../lektor_payloads" } -lektor_procmacros = { path = "../lektor_procmacros" } diff --git a/amadeus/amadeus.excalidraw b/amadeus/amadeus.excalidraw deleted file mode 100644 index 2c8ce85a..00000000 --- a/amadeus/amadeus.excalidraw +++ /dev/null @@ -1,7442 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "rectangle", - "version": 532, - "versionNonce": 1774342663, - "isDeleted": false, - "id": "GrLbO23Ixjb7s7sS93JsY", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4655.071238015048, - "y": 560.7305966188939, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 388.3237592191491, - "height": 366.20519245638934, - "seed": 786909986, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 531, - "versionNonce": 1204352489, - "isDeleted": false, - "id": "VYgCmnYpyDh_3oITa89zD", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1415.3431312926114, - "y": 1322, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 694.9999999999999, - "height": 43.999999999999964, - "seed": 188294271, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 476, - "versionNonce": 769161511, - "isDeleted": false, - "id": "GOQrsKAkNW5XeOitDmIl2", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 629.3431312926114, - "y": 1314, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 694.9999999999999, - "height": 43.999999999999964, - "seed": 1247216177, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 453, - "versionNonce": 350507209, - "isDeleted": false, - "id": "E9i3hgQ1N8N_CJxjImjz2", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1415.3431312926114, - "y": 851, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 694.9999999999999, - "height": 43.999999999999964, - "seed": 1054077297, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 414, - "versionNonce": 1457306695, - "isDeleted": false, - "id": "o90u_y8m0jhLuR5roHO6n", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 632.3431312926114, - "y": 841, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 694.9999999999999, - "height": 43.999999999999964, - "seed": 456386961, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 198, - "versionNonce": 529616809, - "isDeleted": false, - "id": "L-rZ4RlIPYuEy5R86y86H", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 807, - "y": 270, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 694.9999999999999, - "height": 361.99999999999994, - "seed": 530763340, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 235, - "versionNonce": 1487641447, - "isDeleted": false, - "id": "muFnIsgZG4cniRf5Mz3na", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 617, - "y": 594, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffec99", - "width": 852, - "height": 35, - "seed": 570559692, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "Ztje-dZ_cmlGuWnz_uX4k" - } - ], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 125, - "versionNonce": 234582665, - "isDeleted": false, - "id": "Ztje-dZ_cmlGuWnz_uX4k", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 981.533332824707, - "y": 599, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffec99", - "width": 122.93333435058594, - "height": 25, - "seed": 377568884, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "progress bar", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "muFnIsgZG4cniRf5Mz3na", - "originalText": "progress bar", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 98, - "versionNonce": 2006029959, - "isDeleted": false, - "id": "ctBfNFtt3iNT8wta6mnTW", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 616, - "y": 199, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 189, - "height": 391, - "seed": 370865780, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 40, - "versionNonce": 886978921, - "isDeleted": false, - "id": "GAVDEfTh0Uw_DZwCgHfSN", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 624.4931633360684, - "y": 211, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 82.18035888671875, - "height": 35, - "seed": 1105582540, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "Queue", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Queue", - "lineHeight": 1.25, - "baseline": 25 - }, - { - "type": "text", - "version": 53, - "versionNonce": 978005415, - "isDeleted": false, - "id": "JYlDutEmRt1TMreMuLe8t", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 624.4931633360684, - "y": 248, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 93.26838684082031, - "height": 35, - "seed": 1859111412, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "History", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "History", - "lineHeight": 1.25, - "baseline": 25 - }, - { - "type": "line", - "version": 223, - "versionNonce": 1166353481, - "isDeleted": false, - "id": "prhsfsR4Ie8UPiSPPcZMp", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 615, - "y": 538, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 191, - "height": 1, - "seed": 1267746892, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 191, - -1 - ] - ] - }, - { - "type": "text", - "version": 70, - "versionNonce": 470081735, - "isDeleted": false, - "id": "f0S2WA6FxZH3eH0PoDkUV", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 624.4931633360684, - "y": 333, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 117.40444946289062, - "height": 35, - "seed": 1751812556, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "Playlists", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Playlists", - "lineHeight": 1.25, - "baseline": 25 - }, - { - "type": "text", - "version": 93, - "versionNonce": 1003205417, - "isDeleted": false, - "id": "TEV8rgbyV8pPuQMYYQkK2", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 649, - "y": 389.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 55.4560546875, - "height": 60, - "seed": 430525516, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "plt 1\nplt 2\n... ... ...", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "plt 1\nplt 2\n... ... ...", - "lineHeight": 1.25, - "baseline": 54 - }, - { - "type": "freedraw", - "version": 30, - "versionNonce": 2119905255, - "isDeleted": false, - "id": "d7xzBEnv4gvYAKmx6Vd9n", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 637, - "y": 397, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 0.0001, - "height": 0.0001, - "seed": 1129920116, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0.0001, - 0.0001 - ] - ], - "lastCommittedPoint": null, - "simulatePressure": true, - "pressures": [] - }, - { - "type": "freedraw", - "version": 30, - "versionNonce": 203253257, - "isDeleted": false, - "id": "tx7oaNG8Nuq8ldt2VNf0l", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 639, - "y": 424, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 0.0001, - "height": 0.0001, - "seed": 1244650228, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0.0001, - 0.0001 - ] - ], - "lastCommittedPoint": null, - "simulatePressure": true, - "pressures": [] - }, - { - "type": "rectangle", - "version": 157, - "versionNonce": 1532664583, - "isDeleted": false, - "id": "QjBiPxclyWcRn0dCOguU-", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 807, - "y": 198, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 694, - "height": 72, - "seed": 1696528460, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 175, - "versionNonce": 292928745, - "isDeleted": false, - "id": "odXu9DRP34o0poFXzMAhm", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 982, - "y": 214.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 179.2567596435547, - "height": 35, - "seed": 1627470836, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "Current kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Current kara", - "lineHeight": 1.25, - "baseline": 25 - }, - { - "type": "line", - "version": 63, - "versionNonce": 931111463, - "isDeleted": false, - "id": "-wNbwNcgvJcWZTpoyAI72", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1465, - "y": 594, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 38, - "height": 0, - "seed": 1715983180, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 38, - 0 - ] - ] - }, - { - "type": "diamond", - "version": 83, - "versionNonce": 996161481, - "isDeleted": false, - "id": "t6sFN641DvL_thhF8kyye", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 810.3431312926114, - "y": 217.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 2129830361, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 84, - "versionNonce": 1404486983, - "isDeleted": false, - "id": "Mr46KoSlFZEvfeSQXBVHx", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 847.3431312926114, - "y": 217.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 173326233, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 83, - "versionNonce": 2079872681, - "isDeleted": false, - "id": "_Gm0ptgH6c1_FnUo6YdUN", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 886.3431312926114, - "y": 217.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 1117416793, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 90, - "versionNonce": 526156903, - "isDeleted": false, - "id": "840SPsOMv0QY3rJO-p9hu", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 923.3431312926114, - "y": 217.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 1344252697, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "arrow", - "version": 134, - "versionNonce": 1978243465, - "isDeleted": false, - "id": "Rq30Q7Ja1XEt6DYJfxC7D", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 921.8431312926114, - "y": 156.28647455615254, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 56, - "height": 64.71352544384746, - "seed": 61591991, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "startBinding": { - "elementId": "Bph6AHnzQ1S1bVfMupI9k", - "focus": 0.8965645665443911, - "gap": 11 - }, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -56, - 64.71352544384746 - ] - ] - }, - { - "type": "text", - "version": 82, - "versionNonce": 1782407047, - "isDeleted": false, - "id": "Bph6AHnzQ1S1bVfMupI9k", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 932.8431312926114, - "y": 132, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 172.03981018066406, - "height": 25, - "seed": 1605477495, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "Rq30Q7Ja1XEt6DYJfxC7D", - "type": "arrow" - } - ], - "updated": 1697796327633, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Playback controls", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Playback controls", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 70, - "versionNonce": 1785692265, - "isDeleted": false, - "id": "fm4eA-Hblv7tYlcohWVcw", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 624.4931633360684, - "y": 281.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 90.94439697265625, - "height": 35, - "seed": 1048830935, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "Search", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Search", - "lineHeight": 1.25, - "baseline": 25 - }, - { - "type": "line", - "version": 144, - "versionNonce": 1452660391, - "isDeleted": false, - "id": "NzNWnLXriI72BUJ2QyMnc", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 818.8431312926114, - "y": 339, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 669, - "height": 2, - "seed": 444750713, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 669, - 2 - ] - ] - }, - { - "type": "text", - "version": 35, - "versionNonce": 1733659465, - "isDeleted": false, - "id": "gRExy9LL5jxglMt8LV-_8", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 830.8431312926114, - "y": 292, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 131.7685546875, - "height": 35, - "seed": 1814183319, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "View name", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "View name", - "lineHeight": 1.25, - "baseline": 25 - }, - { - "type": "diamond", - "version": 147, - "versionNonce": 185756103, - "isDeleted": false, - "id": "cwqQJDmGYHYlDfnk94s6t", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1335.8431312926114, - "y": 295, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 257275153, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 147, - "versionNonce": 888617513, - "isDeleted": false, - "id": "yucx1QO3jhiAJwOZvEiDq", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1372.8431312926114, - "y": 295, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 501148401, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 146, - "versionNonce": 617584871, - "isDeleted": false, - "id": "c7CkILyiBKJlc_21L1LFK", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1411.8431312926114, - "y": 295, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 1434870993, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327633, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 154, - "versionNonce": 71306505, - "isDeleted": false, - "id": "_IRHpotg2X_jFCOcmMS4r", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1448.8431312926114, - "y": 295, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 31695537, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "hnF7hx3YyVFRNFdr8HZEd", - "type": "arrow" - } - ], - "updated": 1697796327634, - "link": null, - "locked": false - }, - { - "type": "arrow", - "version": 88, - "versionNonce": 1767498759, - "isDeleted": false, - "id": "hnF7hx3YyVFRNFdr8HZEd", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1579.8431312926114, - "y": 264, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 95, - "height": 43, - "seed": 1021597855, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "startBinding": { - "elementId": "EIgL9CR1t23YRBuZB1Bkb", - "focus": 0.6272787827479138, - "gap": 5 - }, - "endBinding": { - "elementId": "_IRHpotg2X_jFCOcmMS4r", - "focus": 0.4362976406533575, - "gap": 3.858256069310727 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -95, - 43 - ] - ] - }, - { - "type": "text", - "version": 66, - "versionNonce": 1554744297, - "isDeleted": false, - "id": "EIgL9CR1t23YRBuZB1Bkb", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1584.8431312926114, - "y": 239, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 159.07981872558594, - "height": 50, - "seed": 275879615, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "hnF7hx3YyVFRNFdr8HZEd", - "type": "arrow" - } - ], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Specific controls\nfor the view", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Specific controls\nfor the view", - "lineHeight": 1.25, - "baseline": 43 - }, - { - "type": "text", - "version": 116, - "versionNonce": 950913831, - "isDeleted": false, - "id": "JY6SAm9hvWSimkLwl9Xkl", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 624.4931633360684, - "y": 545.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 80.29991149902344, - "height": 25, - "seed": 1942363839, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Settings", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Settings", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 385, - "versionNonce": 1246043849, - "isDeleted": false, - "id": "OcS1J1js6Dl83so6sFHTD", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 630.3431312926114, - "y": 888, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 694.9999999999999, - "height": 316.99999999999994, - "seed": 670969937, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 28, - "versionNonce": 1060621895, - "isDeleted": false, - "id": "ZvU0_gIKBrfrO06A0gFdC", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 644.8431312926114, - "y": 852, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 58.69993591308594, - "height": 25, - "seed": 57150847, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Queue", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Queue", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 491, - "versionNonce": 1269325225, - "isDeleted": false, - "id": "7dp7eL5eCpEGY5TU-M0pY", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1414.3431312926114, - "y": 895, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 694.9999999999999, - "height": 316.99999999999994, - "seed": 1181363679, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 145, - "versionNonce": 1741974887, - "isDeleted": false, - "id": "H3OI_VelC2YL7K_Ad65Wm", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1428.8431312926114, - "y": 860, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 66.61991882324219, - "height": 25, - "seed": 768023039, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "History", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "History", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 498, - "versionNonce": 49289, - "isDeleted": false, - "id": "gwutIc4AQChE-D06Xh1Hx", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 629.3431312926114, - "y": 1362, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 694.9999999999999, - "height": 316.99999999999994, - "seed": 618644703, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 153, - "versionNonce": 231745671, - "isDeleted": false, - "id": "2qosxBYLRg4oacXyCWvAM", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 632.8431312926114, - "y": 1327, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 215.09976196289062, - "height": 25, - "seed": 2003947775, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Playlist <$name> view", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Playlist <$name> view", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 428, - "versionNonce": 352962409, - "isDeleted": false, - "id": "DznFxG13WKWqxBd_KbwL5", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1415.3431312926114, - "y": 1366, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 694.9999999999999, - "height": 316.99999999999994, - "seed": 1836704319, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 59, - "versionNonce": 1860665255, - "isDeleted": false, - "id": "K1U0-0qJxQ0H0DA8pO7el", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1422.8431312926114, - "y": 1331, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 64.95993041992188, - "height": 25, - "seed": 1436631647, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Search", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Search", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "line", - "version": 93, - "versionNonce": 1963913801, - "isDeleted": false, - "id": "YfU9msJFsZvKT9P8exxfN", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 631.8431312926114, - "y": 971, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 696, - "height": 2, - "seed": 741196447, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 696, - 2 - ] - ] - }, - { - "type": "text", - "version": 23, - "versionNonce": 1564930759, - "isDeleted": false, - "id": "Mk30knKffPW1le8c-lCWo", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 654.6531898863614, - "y": 933, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 1037559167, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 51, - "versionNonce": 887865641, - "isDeleted": false, - "id": "uQkGGlaZwIwKy3CnX-2GP", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 654.6531898863614, - "y": 1013.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 933527121, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 53, - "versionNonce": 831193575, - "isDeleted": false, - "id": "bcpEErf-B71EsIEVDKh1m", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 654.6531898863614, - "y": 1055.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 153345553, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 38, - "versionNonce": 1108063241, - "isDeleted": false, - "id": "coE57hoaAeRnZXMMi4THV", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 654.6531898863614, - "y": 1099.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 1855868369, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 60, - "versionNonce": 2092969223, - "isDeleted": false, - "id": "WHu1ndOoYdaJH46xiRQgm", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 654.6531898863614, - "y": 1140.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 1526678623, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 52, - "versionNonce": 1349143273, - "isDeleted": false, - "id": "PN6DBY9PmU6_tp2CQCkm0", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1146.8431312926114, - "y": 905.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 84.57991027832031, - "height": 25, - "seed": 482276639, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Enforced", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Enforced", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 40, - "versionNonce": 2053305383, - "isDeleted": false, - "id": "30pWu9wb3Nz1AHNfNIY14", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1165.8431312926114, - "y": 990.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 58.199951171875, - "height": 25, - "seed": 135834687, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Added", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Added", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 104, - "versionNonce": 143853001, - "isDeleted": false, - "id": "qVcXrnid8S6kTOIzDwPv5", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1452.1531898863614, - "y": 954, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 1018089087, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 105, - "versionNonce": 1113577287, - "isDeleted": false, - "id": "PK3SWoqsZX1nR5bOfXiIR", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1452.1531898863614, - "y": 995, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 2146346655, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327634, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 90, - "versionNonce": 1973511337, - "isDeleted": false, - "id": "Fk8Z0OzoVt0JhEjPz8VeK", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1452.1531898863614, - "y": 1039, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 1505655487, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 112, - "versionNonce": 991123047, - "isDeleted": false, - "id": "jcI030-6e9D4R_jIz5EDf", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1452.1531898863614, - "y": 1080, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 1857997535, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 133, - "versionNonce": 859891593, - "isDeleted": false, - "id": "v_3nDtsxr37Te5gcWlvgj", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1452.1531898863614, - "y": 1117, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 83303185, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 139, - "versionNonce": 1263137159, - "isDeleted": false, - "id": "sPKOYqwzPewuFi0Am2RoL", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1452.1531898863614, - "y": 1163, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 1717801201, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 55, - "versionNonce": 1538068073, - "isDeleted": false, - "id": "NEVVM2JFvkWv7028PeK-C", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 643.4950325377285, - "y": 905.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 69.10417175292969, - "height": 20, - "seed": 2042786417, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "widEVKr9h4nSl3NgA5YYi", - "type": "arrow" - } - ], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "# 1 kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "# 1 kara", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "text", - "version": 74, - "versionNonce": 1279273127, - "isDeleted": false, - "id": "NljPQnL78x7fIGD_mhw2O", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 643.4950325377285, - "y": 985, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 83.69619750976562, - "height": 20, - "seed": 529090097, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "# 4 karas", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "# 4 karas", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "line", - "version": 182, - "versionNonce": 900815177, - "isDeleted": false, - "id": "keAQwhvV_Ar8m5_glXG4g", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 630.1977077003568, - "y": 1462.2300471688436, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 696, - "height": 2, - "seed": 1611854225, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 696, - 2 - ] - ] - }, - { - "type": "text", - "version": 154, - "versionNonce": 1000504263, - "isDeleted": false, - "id": "k3Bl71dy_mVWT-gMoJpbT", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1432.8431312926114, - "y": 915.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 85.58419799804688, - "height": 20, - "seed": 74606591, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "#56 karas", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "#56 karas", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "diamond", - "version": 153, - "versionNonce": 581519401, - "isDeleted": false, - "id": "5tKWNxNLrIpPVTxVzSJ69", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1284.3431312926114, - "y": 849, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 275432753, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "LmjKSZUtJ6vJhI64gXg1I", - "type": "arrow" - } - ], - "updated": 1697796327637, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 160, - "versionNonce": 764242663, - "isDeleted": false, - "id": "XDRcnWEN-KOnFuA4Uh-3m", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1240.3431312926114, - "y": 849, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 778956017, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "LmjKSZUtJ6vJhI64gXg1I", - "type": "arrow" - } - ], - "updated": 1697796327637, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 152, - "versionNonce": 1283480329, - "isDeleted": false, - "id": "iDTZEA49Tx3ndM8egoSnJ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 2067.3431312926114, - "y": 859.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 239330545, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "jmnZZXHALwaGDHLV1RPRX", - "type": "arrow" - } - ], - "updated": 1697796327637, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 159, - "versionNonce": 2123200007, - "isDeleted": false, - "id": "P3TfVQmz5_mxRRza79RSu", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1278.3431312926114, - "y": 1322.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 731501759, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 154, - "versionNonce": 330437097, - "isDeleted": false, - "id": "3zvLFdHNemk8FWOxJqM4U", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1232.3431312926114, - "y": 1319.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 609364511, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 161, - "versionNonce": 1168055591, - "isDeleted": false, - "id": "deK85JO84LxmqovW8tWlQ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 2060.3431312926114, - "y": 1326.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 683793041, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "TPSbdmCn-jFu5EOIcyQfY", - "type": "arrow" - } - ], - "updated": 1697796327637, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 56, - "versionNonce": 1028254921, - "isDeleted": false, - "id": "xWZD2ZcO_5GbIGnM4nzjQ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 645.2910454161465, - "y": 1374, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 83.69619750976562, - "height": 20, - "seed": 489289105, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "# 6 karas", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "# 6 karas", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "text", - "version": 125, - "versionNonce": 103735367, - "isDeleted": false, - "id": "PcEw6h-yftjqcawCVJDl7", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 648.1531898863614, - "y": 1395.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 661.5994262695312, - "height": 50, - "seed": 2126201873, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Owner: Sakura\nCreated at: 6 october 2021 | Last modified at: 9 november 2022", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Owner: Sakura\nCreated at: 6 october 2021 | Last modified at: 9 november 2022", - "lineHeight": 1.25, - "baseline": 43 - }, - { - "type": "text", - "version": 117, - "versionNonce": 1625516969, - "isDeleted": false, - "id": "DPlUraaG8ttcYj6PRdK1W", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 662.1531898863614, - "y": 1481, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 1175952977, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 119, - "versionNonce": 572079975, - "isDeleted": false, - "id": "ctICfoNe8EHCT3rMRqyDZ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 662.1531898863614, - "y": 1523, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 252816433, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 104, - "versionNonce": 380243593, - "isDeleted": false, - "id": "miBQNqN1stGi1L3jy_XKH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 662.1531898863614, - "y": 1567, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 760151569, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 126, - "versionNonce": 195738247, - "isDeleted": false, - "id": "rnVLmfIt4R5ThRO65ulV_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 662.1531898863614, - "y": 1608, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 101.3798828125, - "height": 25, - "seed": 533140465, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Next kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Next kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "arrow", - "version": 63, - "versionNonce": 1700353385, - "isDeleted": false, - "id": "jmnZZXHALwaGDHLV1RPRX", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2168.8431312926114, - "y": 822, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 69, - "height": 43, - "seed": 1912393233, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": { - "elementId": "iDTZEA49Tx3ndM8egoSnJ", - "focus": 0.06696651674162918, - "gap": 6.4304267821845436 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -69, - 43 - ] - ] - }, - { - "type": "text", - "version": 22, - "versionNonce": 933220775, - "isDeleted": false, - "id": "FAd3sgnqICjpgaxxkswl0", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2175.8431312926114, - "y": 815, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 134.89630126953125, - "height": 20, - "seed": 366024447, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Clear the history", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Clear the history", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "arrow", - "version": 94, - "versionNonce": 1883029577, - "isDeleted": false, - "id": "TPSbdmCn-jFu5EOIcyQfY", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2162.0737361471174, - "y": 1293.5069318354315, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 69, - "height": 43, - "seed": 1754002385, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "startBinding": { - "elementId": "kE7lQlxdzJztMGV-FZGHq", - "focus": 0.812502399269981, - "gap": 3.769395145493945 - }, - "endBinding": { - "elementId": "deK85JO84LxmqovW8tWlQ", - "focus": 0.3877004551609524, - "gap": 3.1972034207747306 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -69, - 43 - ] - ] - }, - { - "type": "text", - "version": 45, - "versionNonce": 1327826119, - "isDeleted": false, - "id": "kE7lQlxdzJztMGV-FZGHq", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2165.8431312926114, - "y": 1277, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 210.24044799804688, - "height": 20, - "seed": 1857777617, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "TPSbdmCn-jFu5EOIcyQfY", - "type": "arrow" - } - ], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Update lektord from repos", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Update lektord from repos", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "line", - "version": 56, - "versionNonce": 1697632041, - "isDeleted": false, - "id": "g5ZRg1SANotn8fGbghe6T", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 586.8431312926114, - "y": 982, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 1, - "height": 213, - "seed": 753718623, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 1, - 213 - ] - ] - }, - { - "type": "text", - "version": 175, - "versionNonce": 567727079, - "isDeleted": false, - "id": "TokHjPa8na3dCPPNhmBxe", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 453.8481374345288, - "y": 1019.5694717950997, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 109.96823120117188, - "height": 80, - "seed": 317009233, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "One visible div\nper level of\npriority in the\nqueue", - "textAlign": "right", - "verticalAlign": "top", - "containerId": null, - "originalText": "One visible div\nper level of\npriority in the\nqueue", - "lineHeight": 1.25, - "baseline": 74 - }, - { - "type": "line", - "version": 83, - "versionNonce": 714998281, - "isDeleted": false, - "id": "tQrwW-tQpU3We-aDyh4f3", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 606.0209835464786, - "y": 1373.8002706278114, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 5, - "height": 74, - "seed": 1703424959, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -5, - 74 - ] - ] - }, - { - "type": "line", - "version": 70, - "versionNonce": 1472315143, - "isDeleted": false, - "id": "UUZ_lX3xRjVH-6D9jXShZ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 598.7260542462112, - "y": 1470.528297944963, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 1, - "height": 213, - "seed": 1180830591, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 1, - 213 - ] - ] - }, - { - "type": "text", - "version": 73, - "versionNonce": 1300420841, - "isDeleted": false, - "id": "KrW30BB3GP9UuTjvES2UB", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 424.9708015806973, - "y": 1392, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 151.87232971191406, - "height": 40, - "seed": 1328230751, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Informations about\nthe playlist", - "textAlign": "right", - "verticalAlign": "top", - "containerId": null, - "originalText": "Informations about\nthe playlist", - "lineHeight": 1.25, - "baseline": 34 - }, - { - "type": "text", - "version": 73, - "versionNonce": 1667384871, - "isDeleted": false, - "id": "dFRgwEyPEP1DkbqCvEU9N", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 484.4668953306973, - "y": 1519, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 97.37623596191406, - "height": 80, - "seed": 748777233, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "The list of\nkaras in the\nselected\nplaylist", - "textAlign": "right", - "verticalAlign": "top", - "containerId": null, - "originalText": "The list of\nkaras in the\nselected\nplaylist", - "lineHeight": 1.25, - "baseline": 74 - }, - { - "type": "diamond", - "version": 154, - "versionNonce": 795464649, - "isDeleted": false, - "id": "HVqJMqRoOKaKTOFH_RRJ_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1283.3431312926114, - "y": 903.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 838636575, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 162, - "versionNonce": 866445639, - "isDeleted": false, - "id": "Vw1c1cUfaaVHkbAE4hf7k", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1279.3431312926114, - "y": 988.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 1968134239, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 164, - "versionNonce": 1953395369, - "isDeleted": false, - "id": "7m_Mk7wJ3NDb8b2Afgm_n", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1245.3431312926114, - "y": 903.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 18460671, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false - }, - { - "type": "diamond", - "version": 161, - "versionNonce": 635840615, - "isDeleted": false, - "id": "xCssNfD3HEXcMp8crmnhs", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1238.3431312926114, - "y": 988.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 543909055, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false - }, - { - "type": "arrow", - "version": 468, - "versionNonce": 826029449, - "isDeleted": false, - "id": "LmjKSZUtJ6vJhI64gXg1I", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1249.2879050204551, - "y": 788.0800982706791, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 22.41675651056812, - "height": 65.48347972167187, - "seed": 257567281, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "startBinding": { - "elementId": "JbcK8bdx0iv4OuIDJ6wAE", - "focus": -0.8519141594015996, - "gap": 12 - }, - "endBinding": { - "elementId": "XDRcnWEN-KOnFuA4Uh-3m", - "focus": 1.10685059185678, - "gap": 6.382313604384667 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 22.41675651056812, - 65.48347972167187 - ] - ] - }, - { - "type": "text", - "version": 241, - "versionNonce": 938640263, - "isDeleted": false, - "id": "JbcK8bdx0iv4OuIDJ6wAE", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 944.3460313597116, - "y": 736.0800982706791, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 311.13665771484375, - "height": 40, - "seed": 1586824113, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "LmjKSZUtJ6vJhI64gXg1I", - "type": "arrow" - } - ], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Clear or shuffle the queue\nSame thing for each level of the queue", - "textAlign": "right", - "verticalAlign": "top", - "containerId": null, - "originalText": "Clear or shuffle the queue\nSame thing for each level of the queue", - "lineHeight": 1.25, - "baseline": 34 - }, - { - "type": "text", - "version": 101, - "versionNonce": 1494129769, - "isDeleted": false, - "id": "EkckFavHGlglCgk_bVvop", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 5.948498082552324, - "x": 1029.18706439808, - "y": 435.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 235.65606689453125, - "height": 45, - "seed": 1657627295, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "fontSize": 36, - "fontFamily": 1, - "text": "Selected view", - "textAlign": "right", - "verticalAlign": "top", - "containerId": null, - "originalText": "Selected view", - "lineHeight": 1.25, - "baseline": 32 - }, - { - "type": "arrow", - "version": 515, - "versionNonce": 2047244967, - "isDeleted": false, - "id": "fo05TIn0zK4RQfSd_Flkf", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1295.8431312926114, - "y": 440.36919597807906, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 438.701171614503, - "height": 337.53011158208943, - "seed": 2039794609, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327637, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 438.701171614503, - -28.893858185147906 - ], - [ - 382.00214299675486, - 308.6362533969415 - ] - ] - }, - { - "type": "text", - "version": 185, - "versionNonce": 1806772041, - "isDeleted": false, - "id": "Rqvwb6uJDguRGtDBzhk3_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1607.5711128599942, - "y": 360, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 201.6197509765625, - "height": 25, - "seed": 1589121905, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "See for specific view", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "See for specific view", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "arrow", - "version": 128, - "versionNonce": 1087278535, - "isDeleted": false, - "id": "QRe2crXgFfafwW2SDoIYm", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1575.8431312926114, - "y": 1051, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 1163, - "height": 37, - "seed": 1853655857, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 1163, - -37 - ] - ] - }, - { - "type": "text", - "version": 87, - "versionNonce": 1669289513, - "isDeleted": false, - "id": "cazvBJfCyQ0Uy89sXkhyv", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2348.8431312926114, - "y": 1034, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 218.11973571777344, - "height": 50, - "seed": 565668543, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "For each list of kara,\nwe do the following", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "For each list of kara,\nwe do the following", - "lineHeight": 1.25, - "baseline": 43 - }, - { - "type": "rectangle", - "version": 556, - "versionNonce": 392641767, - "isDeleted": false, - "id": "yq4UBUcwNvXCoXyCEcEDS", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 2780.3431312926114, - "y": 849.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 311.9999999999999, - "height": 379.99999999999994, - "seed": 1534010815, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 67, - "versionNonce": 1667541257, - "isDeleted": false, - "id": "AMOhzoD5R4Mca2Jww7JZa", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2822.0731575377285, - "y": 1030, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 47.539947509765625, - "height": 25, - "seed": 847168863, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 62, - "versionNonce": 1901922311, - "isDeleted": false, - "id": "eKBiUDB5iAZSmhQ3xF9Gx", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2822.0731575377285, - "y": 1067.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 47.539947509765625, - "height": 25, - "seed": 529749567, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 64, - "versionNonce": 618438633, - "isDeleted": false, - "id": "bkrlbo11D-u9Zpz0x_d-c", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2822.0731575377285, - "y": 1105.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 47.539947509765625, - "height": 25, - "seed": 1198789247, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 129, - "versionNonce": 481062695, - "isDeleted": false, - "id": "1Imb9Yc-a1vX866ySpwJ1", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2822.0731575377285, - "y": 921.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 47.539947509765625, - "height": 25, - "seed": 1055403903, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "3qe1R5HWKb2Vwb76CM4bO", - "type": "arrow" - } - ], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 119, - "versionNonce": 636664521, - "isDeleted": false, - "id": "pcP5fDK4-2kxVAgAaA4-J", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2822.0731575377285, - "y": 957.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 47.539947509765625, - "height": 25, - "seed": 374597535, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 118, - "versionNonce": 1942090311, - "isDeleted": false, - "id": "GDFuiIw-HcQlFIVuU_CAj", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2822.0731575377285, - "y": 994.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 47.539947509765625, - "height": 25, - "seed": 1406376895, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 108, - "versionNonce": 390232489, - "isDeleted": false, - "id": "wG5vMP9vTKXwfm8mgsciN", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2822.0731575377285, - "y": 1137.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 47.539947509765625, - "height": 25, - "seed": 99938577, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "line", - "version": 186, - "versionNonce": 1333399911, - "isDeleted": false, - "id": "WPzQNm7KzKq0zW2h18mKY", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3129.020983546479, - "y": 854.8002706278116, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 2, - "height": 369, - "seed": 1484120433, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -2, - 369 - ] - ] - }, - { - "type": "text", - "version": 262, - "versionNonce": 167206025, - "isDeleted": false, - "id": "SSpiiDIeXL7IGe0oX3H8G", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3161.8590156920254, - "y": 991, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 132.38427734375, - "height": 80, - "seed": 1347989905, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "G4fthOMtxM_i5zPmx2HKY", - "type": "arrow" - } - ], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Scroll thingy\nwe get imediate\nview over a part\nof the kara list", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Scroll thingy\nwe get imediate\nview over a part\nof the kara list", - "lineHeight": 1.25, - "baseline": 74 - }, - { - "type": "line", - "version": 585, - "versionNonce": 958483591, - "isDeleted": false, - "id": "MLKTEfS41ZZGGZcYObpFI", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 782.8431312926114, - "y": 1546, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 1210, - "height": 509, - "seed": 792230353, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 563, - -49 - ], - [ - 626, - -261 - ], - [ - 1210, - -509 - ] - ] - }, - { - "type": "line", - "version": 325, - "versionNonce": 1573708649, - "isDeleted": false, - "id": "LG0V2wWxedCqB-HRH0lSc", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 767.8431312926114, - "y": 1077, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 750, - "height": 150, - "seed": 404362865, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 357, - 149 - ], - [ - 750, - 150 - ] - ] - }, - { - "type": "line", - "version": 364, - "versionNonce": 1551115175, - "isDeleted": false, - "id": "tqQgVsIOVNf9OsUyEU0Zp", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1648.8431312926114, - "y": 1644, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 1053, - "height": 632, - "seed": 2059185649, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 586, - -4 - ], - [ - 842, - -337 - ], - [ - 969, - -592 - ], - [ - 1053, - -632 - ] - ] - }, - { - "type": "text", - "version": 115, - "versionNonce": 1863224905, - "isDeleted": false, - "id": "zt0GsEyx_n-8so6z1yuqV", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1461.0731575377285, - "y": 1510.75, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 47.539947509765625, - "height": 25, - "seed": 2060382897, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 110, - "versionNonce": 966727367, - "isDeleted": false, - "id": "rH8cUdpWCRqhK2-jpbg60", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1461.0731575377285, - "y": 1548.25, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 47.539947509765625, - "height": 25, - "seed": 1855943825, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 112, - "versionNonce": 77061417, - "isDeleted": false, - "id": "fuG4vE6QGm2QdJVGNYXUG", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1461.0731575377285, - "y": 1586.25, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 47.539947509765625, - "height": 25, - "seed": 2093267569, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 156, - "versionNonce": 389981671, - "isDeleted": false, - "id": "lWa9BooktSUK0thM0z6Jf", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1461.0731575377285, - "y": 1618.25, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 47.539947509765625, - "height": 25, - "seed": 101074001, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kara", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kara", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "line", - "version": 210, - "versionNonce": 2111066121, - "isDeleted": false, - "id": "7e9J48dXD78ZAgcccFqZ_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1416.9708777664137, - "y": 1502.7227978872231, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 696, - "height": 2, - "seed": 435838097, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 696, - 2 - ] - ] - }, - { - "type": "line", - "version": 138, - "versionNonce": 878661895, - "isDeleted": false, - "id": "12kwzm5Ci6fis3B3X-fmF", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2148.5561468955134, - "y": 1509.2602450317145, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 7, - "height": 173, - "seed": 1197218001, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -7, - 173 - ] - ] - }, - { - "type": "text", - "version": 363, - "versionNonce": 1086285545, - "isDeleted": false, - "id": "GvE1ZB2OhWVbShraDrEZ1", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2167.6509926207364, - "y": 1520, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 149.15231323242188, - "height": 100, - "seed": 1407921151, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Search results\nwe can add to the\nqueue, remove,\nadd to a playlist\netc", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Search results\nwe can add to the\nqueue, remove,\nadd to a playlist\netc", - "lineHeight": 1.25, - "baseline": 94 - }, - { - "type": "line", - "version": 184, - "versionNonce": 981309479, - "isDeleted": false, - "id": "9uahk8wCukhpqZufPHlfW", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2133.227831578059, - "y": 1383.41534939589, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 3, - "height": 100, - "seed": 1285769631, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -3, - 100 - ] - ] - }, - { - "type": "text", - "version": 457, - "versionNonce": 1743036873, - "isDeleted": false, - "id": "dl8-kYoOyYUoYlDfYUPfl", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2154.2669746764004, - "y": 1406, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 188.3203887939453, - "height": 60, - "seed": 256737279, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "0N75jERibqskpCAMMBEjv", - "type": "arrow" - } - ], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Search controls\ntext enter, source/type\ncontrols, etc", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Search controls\ntext enter, source/type\ncontrols, etc", - "lineHeight": 1.25, - "baseline": 54 - }, - { - "type": "rectangle", - "version": 104, - "versionNonce": 1871051591, - "isDeleted": false, - "id": "wZ-z9c8UV7RrWUzKxXdtE", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1436.8431312926114, - "y": 1399, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 248, - "height": 55, - "seed": 1854607761, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 34, - "versionNonce": 811565225, - "isDeleted": false, - "id": "6F8gIId_bwR033mfgJ6Cg", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1454.8431312926114, - "y": 1414, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 119.7398681640625, - "height": 25, - "seed": 854641855, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Search text", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Search text", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 56, - "versionNonce": 668269159, - "isDeleted": false, - "id": "5Iwbrj6_zSPLSBAysARke", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1727.8431312926114, - "y": 1403, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 68, - "height": 49, - "seed": 642293983, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "jCeyA90sqkHp4gQvCrwmP" - } - ], - "updated": 1697796327638, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 6, - "versionNonce": 668697481, - "isDeleted": false, - "id": "jCeyA90sqkHp4gQvCrwmP", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1747.303145635873, - "y": 1415, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 29.079971313476562, - "height": 25, - "seed": 974945407, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "ED", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "5Iwbrj6_zSPLSBAysARke", - "originalText": "ED", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 87, - "versionNonce": 2016875911, - "isDeleted": false, - "id": "7r3Bkx-Imuasr3LhVdtsV", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1830.8431312926114, - "y": 1407.5, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 86.99999999999997, - "height": 40, - "seed": 1418347903, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "hxnr8CaJBpmJ8RZ4XpGBq" - } - ], - "updated": 1697796327638, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 7, - "versionNonce": 445917801, - "isDeleted": false, - "id": "hxnr8CaJBpmJ8RZ4XpGBq", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1858.6231453306973, - "y": 1415, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 31.439971923828125, - "height": 25, - "seed": 1126324305, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "cdg", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "7r3Bkx-Imuasr3LhVdtsV", - "originalText": "cdg", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 63, - "versionNonce": 669568167, - "isDeleted": false, - "id": "Qeq-G-PvDr7s95XN8IV5j", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1942.1398844720693, - "y": 1404.3409102752305, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 145.49353184900747, - "height": 57.40561120573079, - "seed": 633885695, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 26, - "versionNonce": 1096086857, - "isDeleted": false, - "id": "kZCrWReI_X3VmyjiNdKGH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1962.4297987775433, - "y": 1423.641072663364, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 66.73992919921875, - "height": 25, - "seed": 299584415, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Tags...", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Tags...", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 113, - "versionNonce": 1654038471, - "isDeleted": false, - "id": "GTXp9vH8pY8hgvbpeg5fv", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2893.544911561464, - "y": 1568.9198303866049, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 570.8288406180361, - "height": 194.12377851900118, - "seed": 597016927, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "0N75jERibqskpCAMMBEjv", - "type": "arrow" - } - ], - "updated": 1697796327638, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 38, - "versionNonce": 796484649, - "isDeleted": false, - "id": "gfpAVv130ZvC0obTucKBB", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3325.863812911888, - "y": 1538.4896164565998, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 135.5198516845703, - "height": 25, - "seed": 192491327, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "flex container", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "flex container", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 78, - "versionNonce": 710741735, - "isDeleted": false, - "id": "GGBu9bSLjLecOJxqi-rOQ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2917.6792191611235, - "y": 1604.5966329252324, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 176.28537724968734, - "height": 62.95906330345975, - "seed": 857716735, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 40, - "versionNonce": 15529737, - "isDeleted": false, - "id": "PMzaiClrfK29k2qnGZzoM", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2929.221714100091, - "y": 1609.8432215338544, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 120.03987121582031, - "height": 50, - "seed": 717594111, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "pending text\nzone", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "pending text\nzone", - "lineHeight": 1.25, - "baseline": 43 - }, - { - "type": "rectangle", - "version": 67, - "versionNonce": 164141575, - "isDeleted": false, - "id": "WjBrbuALz8Kr_dCI1n0lu", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3143.282529331854, - "y": 1607.7445860904056, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 123.81949116347145, - "height": 61.90974558173548, - "seed": 539358385, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "wrSYTpEgY2tJ76RCH7A7H" - } - ], - "updated": 1697796327638, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 52, - "versionNonce": 1210789353, - "isDeleted": false, - "id": "wrSYTpEgY2tJ76RCH7A7H", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3159.3023289297034, - "y": 1626.1994588812734, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 91.77989196777344, - "height": 25, - "seed": 900907089, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "validated", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "WjBrbuALz8Kr_dCI1n0lu", - "originalText": "validated", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 89, - "versionNonce": 97894695, - "isDeleted": false, - "id": "O6o3wg9WTFZK73sGigJgX", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3295.433598981882, - "y": 1609.3185626729921, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 123.81949116347145, - "height": 61.90974558173548, - "seed": 1374383601, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "liZxPiItQStXcydHbKDHe" - }, - { - "id": "vYaeG3wI4fKD0XgIUjAmX", - "type": "arrow" - } - ], - "updated": 1697796327638, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 74, - "versionNonce": 1010796745, - "isDeleted": false, - "id": "liZxPiItQStXcydHbKDHe", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3311.453398579731, - "y": 1627.7734354638599, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 91.77989196777344, - "height": 25, - "seed": 2064287697, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "validated", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "O6o3wg9WTFZK73sGigJgX", - "originalText": "validated", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 78, - "versionNonce": 1341195335, - "isDeleted": false, - "id": "0gvbIdc0izJwqwdckQY5b", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2931.3203495435396, - "y": 1684.8694386371442, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 123.81949116347145, - "height": 61.90974558173548, - "seed": 9521919, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "UnK-LiH2WDtH00e4-J5XP" - }, - { - "id": "NI5c0sPzWjEdXm6vLjQzU", - "type": "arrow" - } - ], - "updated": 1697796327638, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 63, - "versionNonce": 650479529, - "isDeleted": false, - "id": "UnK-LiH2WDtH00e4-J5XP", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2947.340149141389, - "y": 1703.324311428012, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 91.77989196777344, - "height": 25, - "seed": 189633311, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "validated", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "0gvbIdc0izJwqwdckQY5b", - "originalText": "validated", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 83, - "versionNonce": 938926951, - "isDeleted": false, - "id": "R1tjADb3cewPQnv2fLamM", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3084.5207369152918, - "y": 1680.6721677502464, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 123.81949116347145, - "height": 61.90974558173548, - "seed": 1473871825, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "lJG8zCMhd19m22PLBuCD_" - } - ], - "updated": 1697796327638, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 69, - "versionNonce": 300460681, - "isDeleted": false, - "id": "lJG8zCMhd19m22PLBuCD_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3100.540536513141, - "y": 1699.1270405411142, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 91.77989196777344, - "height": 25, - "seed": 555441585, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "validated", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "R1tjADb3cewPQnv2fLamM", - "originalText": "validated", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 90, - "versionNonce": 1580457607, - "isDeleted": false, - "id": "APka79mzdHpdW87DeE72s", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3236.6718065653195, - "y": 1681.7214854719707, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 123.81949116347145, - "height": 61.90974558173548, - "seed": 729093599, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "GyQUs7TvrSxZEdMzk2-DU" - } - ], - "updated": 1697796327638, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 76, - "versionNonce": 912552297, - "isDeleted": false, - "id": "GyQUs7TvrSxZEdMzk2-DU", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3252.6916061631687, - "y": 1700.1763582628384, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 91.77989196777344, - "height": 25, - "seed": 20251135, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "validated", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "APka79mzdHpdW87DeE72s", - "originalText": "validated", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "arrow", - "version": 475, - "versionNonce": 627340711, - "isDeleted": false, - "id": "vYaeG3wI4fKD0XgIUjAmX", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3496.902601552954, - "y": 1627.1946305896424, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 68.20565191208152, - "height": 5.746562886707125, - "seed": 711822271, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327638, - "link": null, - "locked": false, - "startBinding": { - "elementId": "1F4bLy-D8PpYoessJ1pi3", - "focus": 0.43449341369714994, - "gap": 7.3452240520705345 - }, - "endBinding": { - "elementId": "O6o3wg9WTFZK73sGigJgX", - "focus": -0.03650586701434069, - "gap": 9.443859495519291 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -68.20565191208152, - 5.746562886707125 - ] - ] - }, - { - "type": "text", - "version": 255, - "versionNonce": 696540233, - "isDeleted": false, - "id": "1F4bLy-D8PpYoessJ1pi3", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3504.2478256050244, - "y": 1568.9198303866056, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 343.1195983886719, - "height": 175, - "seed": 1475909233, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "vYaeG3wI4fKD0XgIUjAmX", - "type": "arrow" - } - ], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Validate zone on enter key;\n- no \":\" => simple text component\n- ED/OP => song type\n- anime/cdg/autres => source type\n- @author\n- #playlist\n- tag:value", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Validate zone on enter key;\n- no \":\" => simple text component\n- ED/OP => song type\n- anime/cdg/autres => source type\n- @author\n- #playlist\n- tag:value", - "lineHeight": 1.25, - "baseline": 168 - }, - { - "type": "arrow", - "version": 29, - "versionNonce": 1689594055, - "isDeleted": false, - "id": "NI5c0sPzWjEdXm6vLjQzU", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2797.007681162825, - "y": 1822.8547190438935, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 136.41130382416304, - "height": 74.50155824242756, - "seed": 1843822431, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": { - "elementId": "0gvbIdc0izJwqwdckQY5b", - "focus": 0.0021186440678052374, - "gap": 1.5739765825862833 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 136.41130382416304, - -74.50155824242756 - ] - ] - }, - { - "type": "text", - "version": 135, - "versionNonce": 1260645161, - "isDeleted": false, - "id": "pEhDzyMQO29aJp1SjgM1h", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2774.972009006614, - "y": 1841.7424380349316, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 430.49951171875, - "height": 100, - "seed": 143252159, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "On click we delete the filder\n- by default, green badges\n- on hover: red badges\n=> so that we can anticipate what it does", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "On click we delete the filder\n- by default, green badges\n- on hover: red badges\n=> so that we can anticipate what it does", - "lineHeight": 1.25, - "baseline": 93 - }, - { - "type": "rectangle", - "version": 163, - "versionNonce": 1505916903, - "isDeleted": false, - "id": "WXLLoEZUScAJxYOVe1ukP", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -147.4474451129813, - "y": -237.26110021966008, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 5229.2448518072, - "height": 3169.957952493858, - "seed": 1470442463, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 31, - "versionNonce": 1940823561, - "isDeleted": false, - "id": "WHk6qK-RgmhmiZY8-gkg2", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": -126.61961275094484, - "y": -215.0195794626336, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 106.092041015625, - "height": 45, - "seed": 1675930623, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 36, - "fontFamily": 1, - "text": "Board", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Board", - "lineHeight": 1.25, - "baseline": 32 - }, - { - "type": "arrow", - "version": 373, - "versionNonce": 1519969031, - "isDeleted": false, - "id": "3qe1R5HWKb2Vwb76CM4bO", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3160.4534527011224, - "y": 768.9849587314742, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 298.49815742476676, - "height": 149.6578591872343, - "seed": 1553728986, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "startBinding": { - "elementId": "E9aW6QsE1e-zFvSztLI1M", - "focus": 0.6117094529525562, - "gap": 4.974969290412446 - }, - "endBinding": { - "elementId": "1Imb9Yc-a1vX866ySpwJ1", - "focus": -0.13852747804599597, - "gap": 3.107182081291512 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -113.4292998214114, - 17.32367606225455 - ], - [ - -298.49815742476676, - 149.6578591872343 - ] - ] - }, - { - "type": "text", - "version": 134, - "versionNonce": 1646261481, - "isDeleted": false, - "id": "E9aW6QsE1e-zFvSztLI1M", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3165.4284219915344, - "y": 749.4938620446741, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 304.33966064453125, - "height": 50, - "seed": 1747840986, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "3qe1R5HWKb2Vwb76CM4bO", - "type": "arrow" - } - ], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "On right click open a context\nmenu and have multiple actions", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "On right click open a context\nmenu and have multiple actions", - "lineHeight": 1.25, - "baseline": 43 - }, - { - "type": "arrow", - "version": 229, - "versionNonce": 1203038759, - "isDeleted": false, - "id": "widEVKr9h4nSl3NgA5YYi", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 541.6296182278377, - "y": 914.1844315665651, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 95.5194103759253, - "height": 1.1147312480532037, - "seed": 358309530, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "startBinding": { - "elementId": "IWSOm7Lt1WDOUUYinhItJ", - "focus": -0.10715590472777425, - "gap": 8.904898562357516 - }, - "endBinding": { - "elementId": "NEVVM2JFvkWv7028PeK-C", - "focus": -0.02657366707539659, - "gap": 6.346003933965562 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 95.5194103759253, - 1.1147312480532037 - ] - ] - }, - { - "type": "text", - "version": 116, - "versionNonce": 1778610121, - "isDeleted": false, - "id": "IWSOm7Lt1WDOUUYinhItJ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 345.3049351195817, - "y": 890.7829898923977, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 187.41978454589844, - "height": 50, - "seed": 783204442, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "widEVKr9h4nSl3NgA5YYi", - "type": "arrow" - } - ], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "click to fold/unfold\nthe section", - "textAlign": "right", - "verticalAlign": "top", - "containerId": null, - "originalText": "click to fold/unfold\nthe section", - "lineHeight": 1.25, - "baseline": 43 - }, - { - "type": "arrow", - "version": 160, - "versionNonce": 1040387399, - "isDeleted": false, - "id": "0N75jERibqskpCAMMBEjv", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2358.488403086583, - "y": 1452.954519709042, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 522.3717754933409, - "height": 186.0638514614377, - "seed": 1402107526, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [ - { - "type": "text", - "id": "YB2vEEhCjBZ5f_AeNe0aN" - } - ], - "updated": 1697796327639, - "link": null, - "locked": false, - "startBinding": { - "elementId": "dl8-kYoOyYUoYlDfYUPfl", - "focus": -0.35015118402003065, - "gap": 15.901039616237085 - }, - "endBinding": { - "elementId": "GTXp9vH8pY8hgvbpeg5fv", - "focus": -0.3986273201972507, - "gap": 12.684732981540037 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 522.3717754933409, - 186.0638514614377 - ] - ] - }, - { - "type": "text", - "version": 29, - "versionNonce": 1635028649, - "isDeleted": false, - "id": "YB2vEEhCjBZ5f_AeNe0aN", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2548.294369873781, - "y": 1520.9864454397607, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 142.7598419189453, - "height": 50, - "seed": 271623002, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "See how we do\nthat .....", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "0N75jERibqskpCAMMBEjv", - "originalText": "See how we do\nthat .....", - "lineHeight": 1.25, - "baseline": 43 - }, - { - "type": "line", - "version": 37, - "versionNonce": 148884583, - "isDeleted": false, - "id": "ng9kLuilDp_vViITSqJ_6", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1204.2955277108213, - "y": 847.0032601367659, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 0.9949938580825801, - "height": 33.82979117480693, - "seed": 1570293446, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - -0.9949938580825801, - 33.82979117480693 - ] - ] - }, - { - "type": "diamond", - "version": 163, - "versionNonce": 1327419785, - "isDeleted": false, - "id": "zyV-A1aCy5--4pcFC4-bn", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 2, - "opacity": 100, - "angle": 0, - "x": 1146.0057856713538, - "y": 848.423161866087, - "strokeColor": "#1e1e1e", - "backgroundColor": "#eebefa", - "width": 33, - "height": 29, - "seed": 1519471174, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "zI3m7oVwz_inEw1EMjXqk", - "type": "arrow" - } - ], - "updated": 1697796327639, - "link": null, - "locked": false - }, - { - "type": "arrow", - "version": 209, - "versionNonce": 1410836359, - "isDeleted": false, - "id": "zI3m7oVwz_inEw1EMjXqk", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 1104.7961419025655, - "y": 809.677684133807, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 48.387159535896444, - "height": 41.50793538565233, - "seed": 630893318, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "startBinding": { - "elementId": "4HZksVwunPxewqa4mi8CJ", - "focus": -0.9790506505839353, - "gap": 8.954944722743221 - }, - "endBinding": { - "elementId": "zyV-A1aCy5--4pcFC4-bn", - "focus": 0.25796137061398816, - "gap": 4.078846799784715 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 48.387159535896444, - 41.50793538565233 - ] - ] - }, - { - "type": "text", - "version": 127, - "versionNonce": 1480439913, - "isDeleted": false, - "id": "4HZksVwunPxewqa4mi8CJ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 707.4416305294317, - "y": 798.2485610907207, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 388.3995666503906, - "height": 25, - "seed": 756313926, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "zI3m7oVwz_inEw1EMjXqk", - "type": "arrow" - } - ], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Fold/Unfold all the levels of the queue", - "textAlign": "right", - "verticalAlign": "top", - "containerId": null, - "originalText": "Fold/Unfold all the levels of the queue", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "arrow", - "version": 47, - "versionNonce": 501685927, - "isDeleted": false, - "id": "G4fthOMtxM_i5zPmx2HKY", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3417.161868086424, - "y": 954.4625968096816, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 107.45933667291592, - "height": 44.77472361371497, - "seed": 1139781123, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "startBinding": { - "elementId": "8dRlmb3jeSafIY9cuNLGD", - "focus": 0.8795161830231478, - "gap": 16.379690232311077 - }, - "endBinding": { - "elementId": "SSpiiDIeXL7IGe0oX3H8G", - "focus": 0.03342298899409853, - "gap": 15.459238377732618 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -107.45933667291592, - 44.77472361371497 - ] - ] - }, - { - "type": "text", - "version": 400, - "versionNonce": 1855767369, - "isDeleted": false, - "id": "8dRlmb3jeSafIY9cuNLGD", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 3433.541558318735, - "y": 922.6227933510398, - "strokeColor": "#1971c2", - "backgroundColor": "transparent", - "width": 636.5792846679688, - "height": 150, - "seed": 1364634915, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "G4fthOMtxM_i5zPmx2HKY", - "type": "arrow" - } - ], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Two modes:\n1. The list has to handle the scrolling (for history and playlist)\n2. The list don't have to handle the scrolling because it will\n already be handled by the parent component, for the queue\n for example => we have 4 lists one above the other and\n we will scroll throu the 4 at the same time in the main panel", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Two modes:\n1. The list has to handle the scrolling (for history and playlist)\n2. The list don't have to handle the scrolling because it will\n already be handled by the parent component, for the queue\n for example => we have 4 lists one above the other and\n we will scroll throu the 4 at the same time in the main panel", - "lineHeight": 1.25, - "baseline": 143 - }, - { - "type": "text", - "version": 238, - "versionNonce": 1761259975, - "isDeleted": false, - "id": "ejvIUgZB_7v8dOa0IX7P6", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2563.8875721919535, - "y": 31.72515250642971, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 976.4389038085938, - "height": 75, - "seed": 1262821699, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Popups: very simple\n- KaraInfo: display each information on a single line, for tags do a box to display them\n- Playlist picker: in a box, a vertical scroller where each playlist is a button, we align the borders", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Popups: very simple\n- KaraInfo: display each information on a single line, for tags do a box to display them\n- Playlist picker: in a box, a vertical scroller where each playlist is a button, we align the borders", - "lineHeight": 1.25, - "baseline": 68 - }, - { - "type": "text", - "version": 151, - "versionNonce": 1050112553, - "isDeleted": false, - "id": "6Pn7aJwM0G6E3WBMJ207i", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 2564.572555693238, - "y": 155.35021447683778, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "width": 740.819091796875, - "height": 75, - "seed": 1527980365, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Settings:\n- By catégory, misc, amadeus, remote, host system informations\n- Do simple things, not detailed here because they are subject to changes", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Settings:\n- By catégory, misc, amadeus, remote, host system informations\n- Do simple things, not detailed here because they are subject to changes", - "lineHeight": 1.25, - "baseline": 68 - }, - { - "type": "rectangle", - "version": 388, - "versionNonce": 779018471, - "isDeleted": false, - "id": "hX7T2AYCZ9PalNtjDSGPO", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4665.1373384847875, - "y": -60.28674415866493, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 388.3237592191491, - "height": 504.61903895051574, - "seed": 270751842, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "ZJaYn3iTMnKduqQLc9rv2", - "type": "arrow" - } - ], - "updated": 1697796327639, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 218, - "versionNonce": 1561937161, - "isDeleted": false, - "id": "Jv_-yeGZow0ejtizJEzfF", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4533.571771368234, - "y": -213.38878196601104, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 535.6993408203125, - "height": 75, - "seed": 624657634, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Popup: the content of amadeus is darkened, we do a\nbox at the center of the window to show the content\nof the popup.", - "textAlign": "right", - "verticalAlign": "top", - "containerId": null, - "originalText": "Popup: the content of amadeus is darkened, we do a\nbox at the center of the window to show the content\nof the popup.", - "lineHeight": 1.25, - "baseline": 68 - }, - { - "type": "text", - "version": 173, - "versionNonce": 265300999, - "isDeleted": false, - "id": "cQn8zeiOP7KBMIvpacihO", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4765.751381280062, - "y": 581.6712009465882, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 174.53977966308594, - "height": 25, - "seed": 238206882, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Choose a playlist:", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Choose a playlist:", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 191, - "versionNonce": 899529705, - "isDeleted": false, - "id": "Xde-cIZHHJSfFY9utFkgG", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4747.39654747168, - "y": 675.778199830414, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffec99", - "width": 199.42994988284772, - "height": 41.58326614578539, - "seed": 1511713086, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 214, - "versionNonce": 1226511143, - "isDeleted": false, - "id": "Bq9ljOPMRVGp2sdnKJSta", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4746.972228429375, - "y": 726.2721658645819, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffec99", - "width": 199.42994988284772, - "height": 41.58326614578539, - "seed": 1841985122, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 260, - "versionNonce": 942692041, - "isDeleted": false, - "id": "_-S51F7HmygE_nhiT0Qux", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4748.669504598592, - "y": 830.6546502713493, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffec99", - "width": 199.42994988284772, - "height": 41.58326614578539, - "seed": 1469134818, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 224, - "versionNonce": 1656493639, - "isDeleted": false, - "id": "qiIy4aeIjKPY0Gmbc85RV", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4746.972228429375, - "y": 778.0390890256617, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffec99", - "width": 199.42994988284772, - "height": 41.58326614578539, - "seed": 1985900642, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 214, - "versionNonce": 1198298537, - "isDeleted": false, - "id": "ehk_aKtYE44vhgInuL4ih", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4751.60684420042, - "y": 685.1132187611005, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 188.27976989746094, - "height": 175, - "seed": 181235106, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "eM6gmAbdhRRbXYsDy2Jyp", - "type": "arrow" - } - ], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Playlist 1\n\nPlaylist 2\n\nSome other playlist\n\n... ... ...", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "Playlist 1\n\nPlaylist 2\n\nSome other playlist\n\n... ... ...", - "lineHeight": 1.25, - "baseline": 168 - }, - { - "type": "arrow", - "version": 795, - "versionNonce": 596620647, - "isDeleted": false, - "id": "eM6gmAbdhRRbXYsDy2Jyp", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4527.964174737097, - "y": 729.1574624285631, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffec99", - "width": 204.65671761812155, - "height": 49.7465367071477, - "seed": 1216067106, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "startBinding": { - "elementId": "sCArDqUNdGkMcdUvvDVsp", - "focus": 0.42383583982585316, - "gap": 5.007660528537599 - }, - "endBinding": { - "elementId": "ehk_aKtYE44vhgInuL4ih", - "focus": -0.3061038781347698, - "gap": 18.98595184520184 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 204.65671761812155, - 49.7465367071477 - ] - ] - }, - { - "type": "text", - "version": 465, - "versionNonce": 1719531657, - "isDeleted": false, - "id": "sCArDqUNdGkMcdUvvDVsp", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4339.62945637071, - "y": 649.1498019000255, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffec99", - "width": 272.0596923828125, - "height": 75, - "seed": 687868194, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "eM6gmAbdhRRbXYsDy2Jyp", - "type": "arrow" - } - ], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "The text is centered and\nthe borders of the buttons\nare aligned", - "textAlign": "right", - "verticalAlign": "top", - "containerId": null, - "originalText": "The text is centered and\nthe borders of the buttons\nare aligned", - "lineHeight": 1.25, - "baseline": 68 - }, - { - "type": "line", - "version": 169, - "versionNonce": 1122136199, - "isDeleted": false, - "id": "9vkHzverECgQWfoXtUGIw", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4655.694943241225, - "y": 619.4342474679986, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffec99", - "width": 387.6645906633812, - "height": 3.016845063528251, - "seed": 1204854014, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 387.6645906633812, - -3.016845063528251 - ] - ] - }, - { - "type": "line", - "version": 87, - "versionNonce": 656408425, - "isDeleted": false, - "id": "fKylv-07IoYkvVlofsjHS", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4666.304541951369, - "y": -3.0915158413243944, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffec99", - "width": 386.9103793974982, - "height": 0.754211265882077, - "seed": 1745049214, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 386.9103793974982, - 0.754211265882077 - ] - ] - }, - { - "type": "text", - "version": 110, - "versionNonce": 1517340583, - "isDeleted": false, - "id": "ctAffl4eP4qUSNSeDmUg6", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4778.146426312691, - "y": -45.00575521072483, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 173.6197967529297, - "height": 25, - "seed": 491167102, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kara informations", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kara informations", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 128, - "versionNonce": 1469983305, - "isDeleted": false, - "id": "inNp2xs0tyGMInVmCETwS", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4698.69362364345, - "y": 12.32272352807621, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffec99", - "width": 181.539794921875, - "height": 50, - "seed": 1700300514, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Kara Source Name\nKara Title", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Kara Source Name\nKara Title", - "lineHeight": 1.25, - "baseline": 43 - }, - { - "type": "rectangle", - "version": 140, - "versionNonce": 409418439, - "isDeleted": false, - "id": "LnrNQ7ldyfXXH-6yzDsOv", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4702.506682713708, - "y": 70.39699100099506, - "strokeColor": "#1e1e1e", - "backgroundColor": "#b2f2bb", - "width": 42.23583088939631, - "height": 35, - "seed": 945678398, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "bsIZDml-F75tjL-tBdDGP" - } - ], - "updated": 1697796327639, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 95, - "versionNonce": 1892940073, - "isDeleted": false, - "id": "bsIZDml-F75tjL-tBdDGP", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4707.904612196492, - "y": 75.39699100099506, - "strokeColor": "#1e1e1e", - "backgroundColor": "#b2f2bb", - "width": 31.439971923828125, - "height": 25, - "seed": 577720254, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "cdg", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "LnrNQ7ldyfXXH-6yzDsOv", - "originalText": "cdg", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 130, - "versionNonce": 828525031, - "isDeleted": false, - "id": "ZcUjs4Hf6wCdr4R0WB0HE", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4757.564105123099, - "y": 73.03673043158241, - "strokeColor": "#1e1e1e", - "backgroundColor": "#b2f2bb", - "width": 42.23583088939631, - "height": 35, - "seed": 845165630, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "oJqSJL5vT59o4b-mrhV_D" - } - ], - "updated": 1697796327639, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 74, - "versionNonce": 1143794697, - "isDeleted": false, - "id": "oJqSJL5vT59o4b-mrhV_D", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4764.812033080004, - "y": 78.03673043158241, - "strokeColor": "#1e1e1e", - "backgroundColor": "#b2f2bb", - "width": 27.739974975585938, - "height": 25, - "seed": 1124919934, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327639, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "OP", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "ZcUjs4Hf6wCdr4R0WB0HE", - "originalText": "OP", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 224, - "versionNonce": 994732199, - "isDeleted": false, - "id": "eZnc4JPqmgfZqerwrszQ0", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4914.506682713707, - "y": 72.06237101036112, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 42.23583088939631, - "height": 35, - "seed": 2084911038, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "wPLFVYS3Oiqyc5gudj2Px" - } - ], - "updated": 1697796372804, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 180, - "versionNonce": 1332001735, - "isDeleted": false, - "id": "wPLFVYS3Oiqyc5gudj2Px", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4925.484606398151, - "y": 77.06237101036112, - "strokeColor": "#1e1e1e", - "backgroundColor": "#b2f2bb", - "width": 20.279983520507812, - "height": 25, - "seed": 1619234814, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796372804, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "en", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "eZnc4JPqmgfZqerwrszQ0", - "originalText": "en", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 230, - "versionNonce": 582446855, - "isDeleted": false, - "id": "0oNFAJFNsWTGhWdGAoCX7", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4862.284626261925, - "y": 72.30815974447904, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 42.23583088939631, - "height": 35, - "seed": 2029243134, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "IP672kntgLu6gZwgE-Sto" - } - ], - "updated": 1697796368221, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 190, - "versionNonce": 606205479, - "isDeleted": false, - "id": "IP672kntgLu6gZwgE-Sto", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4874.242553303303, - "y": 77.30815974447904, - "strokeColor": "#1e1e1e", - "backgroundColor": "#b2f2bb", - "width": 18.319976806640625, - "height": 25, - "seed": 1216199486, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796368221, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "fr", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "0oNFAJFNsWTGhWdGAoCX7", - "originalText": "fr", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 237, - "versionNonce": 1510607399, - "isDeleted": false, - "id": "ULBaWHt2M3u8fwCQTXQyr", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4811.325203607786, - "y": 71.799737212715, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 42.23583088939631, - "height": 35, - "seed": 1989641726, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "jnYjfZXj3vZnEP4WB3QWM" - } - ], - "updated": 1697796364788, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 197, - "versionNonce": 146025799, - "isDeleted": false, - "id": "jnYjfZXj3vZnEP4WB3QWM", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4824.233127597406, - "y": 76.799737212715, - "strokeColor": "#1e1e1e", - "backgroundColor": "#b2f2bb", - "width": 16.41998291015625, - "height": 25, - "seed": 1878136382, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796364788, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "jp", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "ULBaWHt2M3u8fwCQTXQyr", - "originalText": "jp", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 152, - "versionNonce": 29089255, - "isDeleted": false, - "id": "MxrqmybnwaQaqAlARjpaV", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4913.507055697194, - "y": 126.01374411622118, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 97.29325329878611, - "height": 30, - "seed": 1612222334, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "4fqyvppjtDP11Be8-j3Tw" - } - ], - "updated": 1697796387354, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 78, - "versionNonce": 1249216775, - "isDeleted": false, - "id": "4fqyvppjtDP11Be8-j3Tw", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4926.441615696196, - "y": 131.01374411622118, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 71.42413330078125, - "height": 20, - "seed": 1947830526, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796387354, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "valueless", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "MxrqmybnwaQaqAlARjpaV", - "originalText": "valueless", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "rectangle", - "version": 138, - "versionNonce": 1405776999, - "isDeleted": false, - "id": "09SKVfYO-HlChxGaOqMoC", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4797.015105245472, - "y": 122.14506101504418, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 97.29325329878611, - "height": 30, - "seed": 865386942, - "groupIds": [ - "MGbWnEKUYWd7snLU1jzEG" - ], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [], - "updated": 1697796380255, - "link": null, - "locked": false - }, - { - "type": "line", - "version": 128, - "versionNonce": 997019527, - "isDeleted": false, - "id": "WthwKkuIC1SsWEanI4RqY", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4844.530414996042, - "y": 124.40769481269041, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 2.262633797646231, - "height": 24.888971774108086, - "seed": 395795326, - "groupIds": [ - "MGbWnEKUYWd7snLU1jzEG" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796380255, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 2.262633797646231, - 24.888971774108086 - ] - ] - }, - { - "type": "text", - "version": 101, - "versionNonce": 1548207783, - "isDeleted": false, - "id": "SUb20ygvdbCdwIBC-rwBZ", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4809.082485499585, - "y": 125.91611734445445, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 27.728073120117188, - "height": 20, - "seed": 1755536162, - "groupIds": [ - "MGbWnEKUYWd7snLU1jzEG" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796380255, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "tag", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "tag", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "text", - "version": 139, - "versionNonce": 1694915015, - "isDeleted": false, - "id": "7hSVzzZoHAaeD9VAZrCFd", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4856.597795250155, - "y": 125.91611734445445, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 23.248046875, - "height": 20, - "seed": 1890957374, - "groupIds": [ - "MGbWnEKUYWd7snLU1jzEG" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796380255, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "val", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "val", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "rectangle", - "version": 154, - "versionNonce": 693331911, - "isDeleted": false, - "id": "d1nLB497SE5Fm1uRcgPk2", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4696.129577080767, - "y": 165.97353975384527, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 97.29325329878611, - "height": 30, - "seed": 1005583650, - "groupIds": [ - "WBJp5geCPoLrqF6FPXBsT" - ], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [], - "updated": 1697796389938, - "link": null, - "locked": false - }, - { - "type": "line", - "version": 147, - "versionNonce": 239130343, - "isDeleted": false, - "id": "vGojOYFaF9a_pnJnrQlQe", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4743.6448868313355, - "y": 168.2361735514915, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 2.262633797646231, - "height": 24.888971774108086, - "seed": 150472930, - "groupIds": [ - "WBJp5geCPoLrqF6FPXBsT" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796389938, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 2.262633797646231, - 24.888971774108086 - ] - ] - }, - { - "type": "text", - "version": 120, - "versionNonce": 1307795975, - "isDeleted": false, - "id": "rxdCP7GTvdUCI1GKFCCGo", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4708.196957334881, - "y": 169.74459608325554, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 27.728073120117188, - "height": 20, - "seed": 1485348002, - "groupIds": [ - "WBJp5geCPoLrqF6FPXBsT" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796389938, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "tag", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "tag", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "text", - "version": 158, - "versionNonce": 157780263, - "isDeleted": false, - "id": "JA5BIfbR9coGIaJJ68w7v", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4755.712267085449, - "y": 169.74459608325554, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "width": 23.248046875, - "height": 20, - "seed": 1481685090, - "groupIds": [ - "WBJp5geCPoLrqF6FPXBsT" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796389938, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "val", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "val", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "line", - "version": 68, - "versionNonce": 791478919, - "isDeleted": false, - "id": "0O55kKQwVRFouWzDuDMuU", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4666.18148352587, - "y": 345.24003894012367, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 386.9149848510233, - "height": 1.2875706650616507, - "seed": 961100706, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327640, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 386.9149848510233, - -1.2875706650616507 - ] - ] - }, - { - "type": "arrow", - "version": 441, - "versionNonce": 1744801129, - "isDeleted": false, - "id": "ZJaYn3iTMnKduqQLc9rv2", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4529.055207696805, - "y": 442.63041146394926, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 130.68842250375656, - "height": 48.164124941675595, - "seed": 1022910526, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1697796327640, - "link": null, - "locked": false, - "startBinding": { - "elementId": "BgZlZDTw-TzAlh8bfgxCp", - "gap": 3.862711995186146, - "focus": 0.7840719929159973 - }, - "endBinding": { - "elementId": "hX7T2AYCZ9PalNtjDSGPO", - "gap": 5.393708284225795, - "focus": -0.3980006131791407 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 130.68842250375656, - -48.164124941675595 - ] - ] - }, - { - "type": "text", - "version": 244, - "versionNonce": 1134107047, - "isDeleted": false, - "id": "BgZlZDTw-TzAlh8bfgxCp", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4110.215658543416, - "y": 407.04343086308245, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 414.9768371582031, - "height": 60, - "seed": 106636158, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "ZJaYn3iTMnKduqQLc9rv2", - "type": "arrow" - } - ], - "updated": 1697796327640, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Auxiliary informations, size/length of kara\ndb epoch, etc. Do this in an even smaller font, same\nas for the \"langage\"/\"tag\" category titles?", - "textAlign": "right", - "verticalAlign": "top", - "containerId": null, - "originalText": "Auxiliary informations, size/length of kara\ndb epoch, etc. Do this in an even smaller font, same\nas for the \"langage\"/\"tag\" category titles?", - "lineHeight": 1.25, - "baseline": 54 - }, - { - "type": "text", - "version": 42, - "versionNonce": 828110921, - "isDeleted": false, - "id": "Tq05tpoBzg85EcLft_jwb", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4691.014520226153, - "y": 355.54060426061676, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 118.88027954101562, - "height": 20, - "seed": 1454500286, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327640, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Duration: 1'30''", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Duration: 1'30''", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "text", - "version": 32, - "versionNonce": 481643719, - "isDeleted": false, - "id": "YwNcwEg9W2F3_ap2o8Van", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4690.001540829509, - "y": 380.004446896788, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 122.14427185058594, - "height": 20, - "seed": 1623884990, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327640, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "File size: 30Mio", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "File size: 30Mio", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "text", - "version": 38, - "versionNonce": 765986601, - "isDeleted": false, - "id": "gUCK-93JGKoiaO9YW6PwD", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4690.001540829511, - "y": 407.6872161956133, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 240.49652099609375, - "height": 20, - "seed": 1637189630, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796327640, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "File hash: 1265128defaae5665", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "File hash: 1265128defaae5665", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "rectangle", - "version": 227, - "versionNonce": 1838989705, - "isDeleted": false, - "id": "P5Qv3qO-gWT4KIZi8trKv", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4705.308492312169, - "y": 117.4804205373664, - "strokeColor": "#1e1e1e", - "backgroundColor": "#b2f2bb", - "width": 71.23583088939633, - "height": 35, - "seed": 37208743, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "type": "text", - "id": "zEk_JqjJ-uzBG0qf_8zlp" - }, - { - "id": "8GXZZA7iX9Ur-O1ZCdA_E", - "type": "arrow" - } - ], - "updated": 1697796398732, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 205, - "versionNonce": 822366119, - "isDeleted": false, - "id": "zEk_JqjJ-uzBG0qf_8zlp", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 4721.056435527863, - "y": 122.4804205373664, - "strokeColor": "#1e1e1e", - "backgroundColor": "#b2f2bb", - "width": 39.73994445800781, - "height": 25, - "seed": 1133958599, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1697796376137, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Elliu", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "P5Qv3qO-gWT4KIZi8trKv", - "originalText": "Elliu", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "id": "8GXZZA7iX9Ur-O1ZCdA_E", - "type": "arrow", - "x": 4613.426407756868, - "y": 164.4747085532678, - "width": 88, - "height": 19.36526428013414, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1203153767, - "version": 315, - "versionNonce": 1856075943, - "isDeleted": false, - "boundElements": null, - "updated": 1697796428021, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 88, - -19.36526428013414 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "78PNiwel7g9ZLUSaHMEWI", - "focus": 0.2016924250566111, - "gap": 11.800048828125 - }, - "endBinding": { - "elementId": "P5Qv3qO-gWT4KIZi8trKv", - "focus": -0.05669968834241344, - "gap": 3.882084555300935 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "id": "78PNiwel7g9ZLUSaHMEWI", - "type": "text", - "x": 4317.166703167024, - "y": 161.9804205373664, - "width": 284.45965576171875, - "height": 50, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 1183826375, - "version": 220, - "versionNonce": 334251047, - "isDeleted": false, - "boundElements": [ - { - "id": "8GXZZA7iX9Ur-O1ZCdA_E", - "type": "arrow" - } - ], - "updated": 1697796427973, - "link": null, - "locked": false, - "text": "Just toss everything here\nin badges of different colors", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "right", - "verticalAlign": "top", - "baseline": 43, - "containerId": null, - "originalText": "Just toss everything here\nin badges of different colors", - "lineHeight": 1.25 - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - }, - "files": {} -} \ No newline at end of file diff --git a/amadeus/amadeus.png b/amadeus/amadeus.png index e72ea5935e918f2525c6f3578fe35c52d7a4d289..70380352d6b18418543989fdde4d0bcc9f29ada1 100644 GIT binary patch literal 143472 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	>BM<Q&;84Gc68x=V--Nm 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	DG6Qb!(&uDcJ-sI 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 literal 130065 zcmeFYWl&_zvM$`XySvLkBaOSe3^2IUxVyW{;4ru|%rLmSyTiaRxV!7%c6r~u&p!La zcmJG-@BZ5z(b2W4GM~(RDy!D26`fJaAEi+c2@wGR0E(=P#3uj%;=Kt0fQNkl`GqbF z0sweBz16f_KY=~S9i1J_t!&N6UA-L5$jv;h%mDz;rEeYDsV6*1W=~TpJLr+A-Htz< zDl$b;x^BN4+{wkq#DBh9>2omo{v8pLvKRv%eg0wn?YQIhxa*a%e{Lyd?3Z=b&0gM$ zOMHlM{nOply+4Y_tN+V!-o^fWfbYxWQ+(n&R#)*lx6aG8YJi{M^S0d?>%HoOgTw4x zp2K*6|JVKX^O~12qJedX5sZiZm;KnsJZ`zmyV#3;l)>|wv!&(hbuw`7`uS58oL$!& zbHK=HUf(NOKtOtj{(Uy~wk*Z!bLLDQ1ofM|CZT_b;R6y2a*40u$hziH9=D0u>#D%Z zi;{&zmH5Qlt>l|h+0A@jWq^JK@mo9f%NX^1SHN47VVBrLnnO{SFx~5&(&Xtm>%-9e zd2X+v)1UaoyRN&{)0f<gV*D1i-#1g@FE{k-d7i5~RL=+Qpn7lNXHC!O{imjD2dYxM zg6eZOrC0reh~d(9iU<-Z&%OtLLoleHcnXK?6@B~j;ghkv(uvczCtcoG6bIi=O8lG} zPJUy#s?R>a&8G$bs^h2nLAvv9d6SI^NZ~88H=mbc;fv1iV(=bMK9%^IF(0}59Cx2n z(rPF-U)W1_vo^Y3U*-e!=KB$GEf%p46;7Tz27sGyl%kKge3!kw=Uv3eQ?J*s3K(Si z_zE)RfHEnKP{K31K{{yK+8U9Nf}t<lrZ8e3oY;rcRZGhiqy0IAuR_ni)kt*uUb=P1 zq|ldqk7ziws@CGg+u9$A#V4dm(UU9L{ZR3T&APNDRp(e0X5g}j&QQtg=vv_PaLTe| zS3}1RZDDcwpoUJQ?$1)*n)kWMMMj7R>GPir7?W|HU*mOpb(0p2i~CxkQ=?_&t+~H7 z3{8e|xbAC?{oR-S;;~Q*T(3S9=kC}4n({<w;MRBWAJbjmw{r*>S}(h`(0&{0dh00- z6E4H;O1TP~S}z;a%-gSOg71}en$W8D-0l7>%nSiRqF>h*mi?7+KXa9&U!I0-cq{XC z<8w{$L#Wo;#r%@~Wm940%3GCNTkdnbTlAZu=9%;1YhTJ!-tq0ZhMm0lv2KkaE?<cU z<�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 Y5A<hqpJn@RNB{r;07*qoM6N<$f?s5;h5!Hn diff --git a/amadeus/build.rs b/amadeus/build.rs new file mode 100644 index 00000000..7b669d71 --- /dev/null +++ b/amadeus/build.rs @@ -0,0 +1,16 @@ +use std::path::*; + +fn main() -> anyhow::Result<()> { + let git_version = lektor_utils::git_version(); + let out_dir = std::env::var_os("OUT_DIR").expect("failed to get OUT_DIR"); + let src_file = Path::new(&out_dir).join("amadeus_build_infos.rs"); + + let build_infos = format!( + r#" +pub const fn version() -> &'static str {{ "{git_version}" }} + "# + ); + std::fs::write(src_file, build_infos).expect("failed to write the build info file"); + + Ok(()) +} diff --git a/amadeus/i18n.toml b/amadeus/i18n.toml new file mode 100644 index 00000000..76f7c310 --- /dev/null +++ b/amadeus/i18n.toml @@ -0,0 +1,4 @@ +fallback_language = "en" + +[fluent] +assets_dir = "i18n" diff --git a/amadeus/i18n/en/amadeus.ftl b/amadeus/i18n/en/amadeus.ftl new file mode 100644 index 00000000..41c1e50a --- /dev/null +++ b/amadeus/i18n/en/amadeus.ftl @@ -0,0 +1,43 @@ +app-title = Amadeus + +unimplemented = Need to implement { $what }! +error-found = An error happened! + +about = About +edit = Edit +view = View +history = History +welcome = Welcome +settings = Settings +playback = Playback +page-id = Page { $num } + +next-kara = Next kara +prev-kara = Previous kara +toggle-playback = Play/Pause +play-playback = Play +pause-playback = Pause +stop-playback = Stop +playback-shuffle = Shuffle +playback-crop = Crop +playback-clear = Clear +menu-queue = Queue + +home = Home +queue = Queue +search = Search +playlists = Playlists +playlist = Playlist { $name } + +app-config = Application configuration +remote-config = Remote instance configuration +log-level = Log level +icon-theme = Icon theme +dark-theme = Dark theme +instance-addr = Address +instance-port = Port +instance-scheme = Scheme +kurisu-token = Kurisu token +open-url = Open URL { $url } +token = Token +port = Port diff --git a/amadeus/i18n/es-ES/amadeus.ftl b/amadeus/i18n/es-ES/amadeus.ftl new file mode 100644 index 00000000..6a104b11 --- /dev/null +++ b/amadeus/i18n/es-ES/amadeus.ftl @@ -0,0 +1,43 @@ +app-title = Amadeus + +unimplemented = ¡Necesita implemenar { $what }! +error-found = ¡Ocurió an error! + +about = Acerca de +edit = Editar +view = Vista +history = Escuchado recientemente +welcome = ¡Hola! +settings = Ajustes +playback = Reproducción +page-id = Pagina { $num } + +next-kara = Póxima kara +prev-kara = Previo kara +toggle-playback = Alternar reprod. +play-playback = Reproducir +pause-playback = Pausar +stop-playback = Detener +playback-shuffle = Mezclar +playback-crop = Recortar +playback-clear = Vaciar +menu-queue = Cola de reprod. + +home = Inicio +queue = Cola de reproducción +search = Buscar +playlists = Listas de reproducción +playlist = Lista { $name } + +app-config = Ajustes de la aplicación +remote-config = Ajustes de la instancia remota +log-level = Nivel de registro +icon-theme = Tema de icono +dark-theme = Tema oscuro +instance-addr = Dirección IP +instance-port = Puerto IP +instance-scheme = Esquema +kurisu-token = Token por Kurisu +open-url = Abrir URL { $url } +token = Token +port = Puerto diff --git a/amadeus/src/app.rs b/amadeus/src/app.rs index 1392f672..8e544f6a 100644 --- a/amadeus/src/app.rs +++ b/amadeus/src/app.rs @@ -1,895 +1,450 @@ -//! Definition of the amadeus application +mod about_page; +mod config_page; +mod context_page; +mod history_page; +mod home_page; +mod main_page; +mod menu_bar; +mod playlist_page; +mod playlists_page; +mod queue_page; +mod search_page; use crate::{ - components::{ + app::{ + context_page::ContextPage, + main_page::Page, + menu_bar::{MenuAction, MenuHeaderCentralCommands}, + }, + config::{Config, LogLevel}, + fl, subscriptions, +}; +use cosmic::{ + app::{Command, Core}, + iced::{ + alignment::{Horizontal, Vertical}, + Alignment, Length, Subscription, + }, + prelude::CollectionWidget as _, + theme, + widget::{ self, - config::AmadeusConfig, - mainpanel::{history, playlists, queue, search}, - modal::*, - *, + menu::{self, Action}, + nav_bar, }, - links::*, - message::*, - store::KaraStore, - style_sheet::{sizes::*, ModalStyleSheet, SideBarSplit}, + Application, ApplicationExt, Apply, Element, }; -use anyhow::{anyhow, Result}; -use futures::{stream, StreamExt, TryStreamExt}; -use iced::{ - keyboard::{Event as KbdEvent, KeyCode}, - widget::{column, container, horizontal_rule, horizontal_space, row, text}, - Application, Command, Element, Event, Length, Renderer, +use lektor_lib::ConnectConfig; +use lektor_utils::config::SocketScheme; +use std::{ + collections::HashMap, + mem, + net::{IpAddr, Ipv4Addr, SocketAddr}, + sync::Arc, }; -use iced_aw::{native::Split, split}; -use lektor_lib::{requests::*, ConnectConfig, ConnectConfigPtr}; -use lektor_payloads::{Infos, KId, Kara, KaraFilter, PlayState, PlayStateWithCurrent, Priority}; -use lektor_utils::{config::UserConfig, either, log}; -use std::{future::Future, sync::Arc}; - -/// The main application. -pub struct Amadeus { - /// Was the config loaded for the first time? - is_init: bool, - - /// Is amadeus connected to lektord - is_connected: bool, +use tokio::sync::RwLock; - /// The last recieved instant, to calculate the delta and maybe time some animations. - last_instant: iced::time::Instant, +pub const APP_ICON: &[u8] = include_bytes!("../amadeus.png"); +pub const APP_ID: &str = "fr.iiens.baka.Amadeus"; - /// The last database epoch found. - last_epoch: Option<u64>, +/// The application model stores app-specific state used to describe its interface and +/// drive its logic. +pub struct AppModel { + /// Application state which is managed by the COSMIC runtime. + core: Core, - /// The configuration, can be edited with the settings modal. - config: config::State, + /// Display a context drawer with the designated page if defined. + context_page: ContextPage, - /// The config to pass to the connect functions, updated when needed. - connect_config: ConnectConfigPtr, + /// The central buttons to command the playback. + header_controls: MenuHeaderCentralCommands, - /// The store where we try to cache the karas to not always query lektord. We will need to - /// invalidate it on some events. - kara_store: Arc<KaraStore>, + /// Contains items assigned to the nav bar panel. + nav: nav_bar::Model, - /// Side bar to select what to display in the main panel. - sidebar: sidebar::State, + /// Key bindings for the application's menu bar. + key_binds: HashMap<menu::KeyBind, MenuAction>, - /// The size of the sidebar. - sidebar_size: Option<u16>, + /// Configuration data that persists between application runs. + config: Config, - /// The bottom bar to display the progress of the current kara. - bottombar: bottombar::State, + /// The handle to save the configuration. + cosmic_config: cosmic::cosmic_config::Config, - /// The top bar to display informations about the current kara and some controls for the - /// application, the search button and the playback controls. - topbar: topbar::State, + /// The config used to make requests to the lektord instance. + connect_config: Arc<RwLock<ConnectConfig>>, - /// The main panel, displays the queue, history, etc. - mainpanel: mainpanel::State, + /// Informations about the lektord server. + lektord_state: LektordState, - /// Whever to show the main panel or not, if we don't show the mainpanel, then we show the - /// config panel. - show_main_panel: bool, - - /// Currently playing kara, for the title. - current_kara: Option<Arc<Kara>>, - - /// The current playback state of the player. - playback_state: PlayState, + // Temporary things for the remote instance + tmp_remote_addr: String, + tmp_remote_port: String, + tmp_remote_valid: bool, + tmp_remote_user: String, + tmp_remote_token: String, +} - /// The modal to display. - modal: Option<WhichModal>, +#[derive(Debug, Clone, Default)] +enum LektordState { + #[default] + Disconnected, + Connected { + version: String, + last_epoch: Option<u64>, + state: Option<lektor_payloads::PlayStateWithCurrent>, + }, } -/// Send a command to lektord and the return must be () here... Extremly specific, but handy. -fn send(future: impl Future<Output = Result<()>> + 'static + Send) -> Command<Message> { - Command::perform(future, |res| { - if let Err(err) = res { - log::error!("{err}") - } - Message::None - }) +/// A command to send to the lektord instance. +#[derive(Debug, Clone, Copy)] +#[non_exhaustive] +pub enum LektordCommand { + PlaybackToggle, + PlaybackPlay, + PlaybackPause, + PlaybackStop, + PlaybackNext, + PlaybackPrevious, + + QueueShuffle, + QueueClear, + QueueCrop, } -impl Default for Amadeus { - fn default() -> Self { - Self { - // Manual defaults. - last_instant: iced::time::Instant::now(), - kara_store: Arc::new(KaraStore::new()), - sidebar_size: Some(300), - show_main_panel: false, - is_connected: false, - is_init: false, - last_epoch: None, - - // Has default. - connect_config: Default::default(), - config: Default::default(), - sidebar: Default::default(), - bottombar: Default::default(), - topbar: Default::default(), - mainpanel: Default::default(), - current_kara: Default::default(), - playback_state: Default::default(), - modal: Default::default(), - } - } +/// Messages emitted by the application and its widgets. +#[derive(Debug, Clone)] +pub enum Message { + OpenUrl(&'static str), + ToggleContextPage(ContextPage), + + UpdateConfig(Config), + ChangeTheme(theme::Theme), + ChangeLogLevel(LogLevel), + ChangeKurisuToken(String), + ChangeURLScheme(SocketScheme), + ChangeRemoteAddr(String), + ChangeRemotePort(String), + ChangeUserName(String), + ChangeUserToken(String), + + LektordDisconnected, + LektordConnected(lektor_payloads::Infos), + LektordUpdate(lektor_payloads::PlayStateWithCurrent), + + /// A button in the header is clicked. + HeaderCommand(widget::segmented_button::Entity), + + /// Send a command to the lektord instance. + SendCommand(LektordCommand), } -impl Amadeus { - /// Get a kara from the store or request it from lektord. If we got a kara then we pass it to - /// the callback, otherwise we returns a [Message::None]. - fn with_kara( - &self, - id: KId, - cb: impl FnOnce(Arc<Kara>) -> Message + 'static + Send, - ) -> Command<Message> { - Command::perform(KaraStore::into_get(self.kara_store.clone(), id), |kara| { - kara.map(cb).into() - }) - } +/// Create a COSMIC application from the app model +impl Application for AppModel { + type Executor = cosmic::executor::Default; + type Flags = (Config, cosmic::cosmic_config::Config); + type Message = Message; + const APP_ID: &'static str = APP_ID; - /// Commands to issue to clear data from the [Amadeus] application. - fn clear() -> Command<Message> { - Message::from_iter([ - Message::Config(config::Message::Infos(None)), - Message::MainPanel(mainpanel::Message::Queue(queue::Message::Clear)), - Message::MainPanel(mainpanel::Message::History(history::Message::Clear)), - Message::MainPanel(mainpanel::Message::Playlists(playlists::Message::Clear)), - Message::Sidebar(sidebar::Message::ClearPlaylists), - ]) - .perform() + fn core(&self) -> &Core { + &self.core } - fn get_history(&self) -> impl Future<Output = Option<Vec<Arc<Kara>>>> { - let cfg = self.connect_config.clone(); - let store = self.kara_store.clone(); - async move { - stream::iter(get_history(cfg).await.unwrap_or_default()) - .then(|id| KaraStore::into_get(store.clone(), id)) - .try_collect() - .await - .ok() - } + fn core_mut(&mut self) -> &mut Core { + &mut self.core } - fn get_playlist_content(&self, plt: Arc<str>) -> impl Future<Output = Option<Vec<Arc<Kara>>>> { - let cfg = self.connect_config.clone(); - let store = self.kara_store.clone(); - async move { - stream::iter(get_playlist_content(cfg, plt).await.unwrap_or_default()) - .then(|id| KaraStore::into_get(store.clone(), id)) - .try_collect() - .await - .ok() - } + /// Initializes the application with any given flags and startup commands. + fn init( + mut core: Core, + (config, cosmic_config): Self::Flags, + ) -> (Self, Command<Self::Message>) { + core.window.show_maximize = false; + core.window.show_minimize = false; + let host = config.host().1; + + let mut app = AppModel { + nav: main_page::nav_bar_model(), + key_binds: Default::default(), + context_page: Default::default(), + header_controls: Default::default(), + + lektord_state: LektordState::Disconnected, + + tmp_remote_addr: host.ip().to_string(), + tmp_remote_port: host.port().to_string(), + tmp_remote_valid: true, + tmp_remote_user: config.user().user.clone(), + tmp_remote_token: config.user().token.clone(), + + connect_config: Arc::new(RwLock::new(config.get_connect_config())), + cosmic_config, + config, + core, + }; + + let command = app.update_title(); + (app, command) } - fn get_queue(&self) -> impl Future<Output = Option<Vec<(Priority, Arc<Kara>)>>> { - let cfg = self.connect_config.clone(); - let store = self.kara_store.clone(); - async move { - stream::iter(get_queue(cfg).await.unwrap_or_default()) - .then(move |(p, id)| { - let store = store.clone(); - async move { store.get(id).await.map(|kara| (p, kara)) } - }) - .try_collect() - .await - .ok() - } + /// Elements to pack at the start of the header bar. + fn header_start(&self) -> Vec<Element<Self::Message>> { + vec![menu_bar::header_menu(&self.key_binds)] } - /// Get a mut reference to the config, clone the thingy if necessary, so other threads can - /// continue a bit with the old configuration. - fn config_mut(&mut self) -> &mut ConnectConfig { - Arc::make_mut(&mut self.connect_config) - } - - /// Handle a config message. This is ugly so we put it in another function. - fn handle_config_message(&mut self, config: config::Message) -> Command<Message> { - if let config::Message::TryConnect = config { - return Command::perform(get_infos(self.connect_config.clone()), |res| { - Message::from_err_ors( - res.map(|info| { - Message::from_iter([ - Message::Config(config::Message::Infos(Some(info))), - Message::ConnectionStatus(true), - ]) - }), - [ - Message::Config(config::Message::Infos(None)), - Message::ConnectionStatus(false), - ], - ) - }); - } else if match &config { - config::Message::HostChanged(host) => host - .as_str() - .parse() - .map(|host| self.config_mut().host = host) - .is_ok(), - config::Message::UserChanged(user) => { - self.config_mut().user = user.as_str().into(); - true - } - config::Message::TokenChanged(token) => { - self.config_mut().token = token.as_str().into(); - true - } - config::Message::SchemeChanged(scheme) => scheme - .parse() - .map(|scheme| self.config_mut().scheme = scheme) - .is_ok(), - config::Message::LoadConfig(config) => { - let UserConfig { user, token, .. } = &config.connect.user; - let cfg = self.config_mut(); - (cfg.host, cfg.scheme) = (config.connect.host, config.connect.scheme); - (cfg.user, cfg.token) = (user.as_str().into(), token.as_str().into()); - true - } - _ => false, - } { - self.kara_store.update(self.connect_config.clone()) - } - self.config.update(config).map(Message::from) + /// Elements to place at the center of the header bar. + fn header_center(&self) -> Vec<Element<Self::Message>> { + vec![ + widget::horizontal_space(Length::Fill).into(), + self.header_controls.view(), + widget::horizontal_space(Length::Fill).into(), + ] } - /// Handle requests from the main panel. - /// - /// This is where we send commands to lektord. - fn handle_main_panel_request( - &mut self, - req: mainpanel::Request, - ) -> Command<<Self as Application>::Message> { - let cfg = self.connect_config.clone(); - match req { - // Queue - mainpanel::Request::Queue(req) => match req { - queue::Request::ShuffleQueueLevel(prio) => send(shuffle_level_queue(cfg, prio)) - .map(move |_| RefreshRequest::QueueLevel(prio).into()), - queue::Request::ClearQueueLevel(prio) => Command::batch([ - self.mainpanel - .update(queue::Message::ClearLevel(prio).into()) - .map(Message::from), - send(remove_level_from_queue(cfg, prio)), - ]), - queue::Request::ClearQueue => Command::batch([ - self.mainpanel - .update(queue::Message::Clear.into()) - .map(Message::from), - send(remove_range_from_queue(cfg, ..)), - ]), - queue::Request::ShuffleQueue => { - send(shuffle_queue(cfg)).map(|_| RefreshRequest::Queue.into()) - } - queue::Request::RefreshQueue => self.handle_refresh_request(RefreshRequest::Queue), - queue::Request::RefreshQueueLevel(lvl) => { - self.handle_refresh_request(RefreshRequest::QueueLevel(lvl)) - } - queue::Request::InnerQueueEvent(karalist::Request(req)) => { - self.handle_kara_request(req, None) - } - queue::Request::ToggleQueueLevel(prio, show) => self - .mainpanel - .update(queue::Message::ToggleLevel(prio, show).into()) - .map(Message::from), - }, - - // History - mainpanel::Request::History(req) => match req { - history::Request::Clear => Command::batch([ - self.mainpanel - .update(history::Message::Clear.into()) - .map(Message::from), - send(remove_range_from_history(cfg, ..)), - ]), - history::Request::Refresh => self.handle_refresh_request(RefreshRequest::History), - history::Request::Inner(karalist::Request(req)) => { - self.handle_kara_request(req, None) - } - }, - - // Playlist - mainpanel::Request::Playlists(req) => match req { - playlists::Request::Refresh(plt) => { - self.handle_refresh_request(RefreshRequest::Playlist(plt)) - } - playlists::Request::Delete(plt) => Command::batch([ - self.sidebar - .update(sidebar::Message::DeletePlaylist(plt.clone())), - self.mainpanel - .update(playlists::Message::DeletePlaylist(plt.clone()).into()) - .map(Message::from), - send(delete_playlist(cfg, plt)), - ]), - playlists::Request::Inner(plt, karalist::Request(req)) => { - self.handle_kara_request(req, Some(plt)) - } - playlists::Request::AddTo(name, id) => { - send(add_to_playlist(cfg, name, KaraFilter::KId(id))) - } - playlists::Request::RemoveFrom(name, id) => { - send(remove_from_playlist(cfg, name, KaraFilter::KId(id))) - } - playlists::Request::ChangeView => { - Message::MainPanelDisplay(either!(self.is_connected => MainPanelDisplay::MainPanel(mainpanel::Show::Queue); MainPanelDisplay::Config)) - .perform() - } - }, - - // Search/Database - mainpanel::Request::Search(req) => match req { - search::Request::Kara(req) => self.handle_kara_request(req, None), - search::Request::Search => { - let filters: Vec<_> = self.mainpanel.search_filters().into_iter().collect(); - log::error!("implement the search thing with filters: {filters:#?}",); - Command::none() - } - search::Request::UpdateFromRepo => send(update_from_repo(cfg)), - search::Request::Message(msg) => { - self.mainpanel.update(msg.into()).map(Message::from) - } - }, - } + /// Enables the COSMIC application to create a nav bar with this model. + fn nav_model(&self) -> Option<&nav_bar::Model> { + Some(&self.nav) } - /// Handle requests from individual karas. - /// - /// When deleting something we send the command and - /// perform the action in our representation of the database. This means that we may not be in - /// sync, see latter how we can sync lektord and amadeus... - /// - /// It's in this function that we make calls to lektord. - fn handle_kara_request( - &mut self, - req: kara::Request, - plt: Option<Arc<str>>, - ) -> Command<<Self as Application>::Message> { - use crate::components::kara::Request::*; - let cfg = self.connect_config.clone(); - match (plt, req) { - (_, AddToQueue(prio, id)) => Command::batch([ - send(add_kid_to_queue(cfg, prio, id.clone())), - self.with_kara(id, move |kara| queue::Message::AddKara(prio, kara).into()), - ]), - (_, RemoveFromQueue(id)) => Command::batch([ - self.mainpanel - .update(queue::Message::RemoveKara(id.clone()).into()) - .map(Message::from), - send(remove_kid_from_queue(cfg, id)), - ]), - (_, RemoveFromHistory(id)) => Command::batch([ - self.mainpanel - .update(history::Message::RemoveKara(id.clone()).into()) - .map(Message::from), - send(remove_kid_from_history(cfg, id)), - ]), - - // Don't need a modal as we already knwo the playlist to delete from. - (Some(plt), RemoveFromPlaylist(id)) => Command::batch([ - self.mainpanel - .update( - playlists::Message::RemoveKaraFromPlaylist(plt.clone(), id.clone()).into(), - ) - .map(Message::from), - send(remove_kid_from_playlist(cfg, plt, id)), - ]), - - // Need to open a modal to take decision. - (None, RemoveFromPlaylist(id)) => { - let plts = self.playlist_list().to_vec(); - let callback = OnPlaylistSelectCallback::new(move |name| { - Message::from_iter([ - playlists::Request::RemoveFrom(name.clone(), id.clone()).into(), - playlists::Message::RemoveKaraFromPlaylist(name, id.clone()).into(), - ]) - }); - Message::from(ShowModal::ChoosePlaylist(plts, callback)).perform() - } - (Some(plt), AddToPlaylist(id)) => { - let plts = self.playlist_list().to_vec(); - self.with_kara(id.clone(), |kara| { - let cb = OnPlaylistSelectCallback::new(move |name| { - Message::from_iter([ - playlists::Request::AddTo(name.clone(), id.clone()).into(), - playlists::Message::AddKaraToPlaylist(name, kara.clone()).into(), - ]) - }); - ShowModal::ChoosePlaylistExpect(plt, plts, cb).into() - }) - } - (None, AddToPlaylist(id)) => { - let plts = self.playlist_list().to_vec(); - self.with_kara(id.clone(), |kara| { - let cb = OnPlaylistSelectCallback::new(move |name| { - Message::from_iter([ - playlists::Request::AddTo(name.clone(), id.clone()).into(), - playlists::Message::AddKaraToPlaylist(name, kara.clone()).into(), - ]) - }); - ShowModal::ChoosePlaylist(plts, cb).into() - }) - } - - // Need to open a modal to display. - (_, OpenInformation(id)) => self.update(ShowModal::KaraInfoById(id).into()), - } + /// Display a context drawer if the context page is requested. + fn context_drawer(&self) -> Option<Element<Self::Message>> { + (self.core.window.show_context).then(|| match self.context_page { + ContextPage::About => about_page::view(self), + ContextPage::Settings => config_page::view(self), + }) } - /// Handle the requests to make to lektord. - /// - /// This is where the commands are sent to lektord. - fn handle_playback_request( - &mut self, - req: PlaybackRequest, - ) -> Command<<Self as Application>::Message> { - use crate::message::PlaybackRequest::*; - let cfg = self.connect_config.clone(); - match req { - ChangePlayback(state) => send(set_playback_state(cfg, state)), - TogglePlaybackState => send(toggle_playback_state(self.connect_config.clone())), - PlayNext => send(play_next(cfg)), - PlayPrevious => send(play_previous(cfg)), + /// Describes the interface based on the current state of the application model. + fn view(&self) -> Element<Self::Message> { + match self.nav.active_data::<Page>() { + Some(Page::Home) => home_page::view(), + Some(Page::Queue) => queue_page::view(), + Some(Page::History) => history_page::view(), + Some(Page::Search) => search_page::view(), + Some(Page::Playlists) => playlists_page::view(), + Some(Page::Playlist(name)) => playlist_page::view(name), + + // A page was not implemented, or nothing is selected, which is rare. + page => widget::column() + .push(widget::text::title1(fl!("error-found"))) + .push_maybe(page.map(|page| { + widget::text::title3(fl!("unimplemented", what = page.to_string())) + })) + .align_items(Alignment::Center) + .apply(widget::container) + .width(Length::Fill) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .into(), } } - /// Perform the init ping if needed - fn command_init_ping(&mut self) -> Command<<Self as Application>::Message> { - if self.is_init { - log::error!("try to send init ping multiple times"); - return Command::none(); - } - self.is_init = true; - let flag = self.config.amadeus.open_config_if_init_ping_failed; - Command::perform(get_infos(self.connect_config.clone()), move |res| { - Message::from_err_or_elses( - res.map(|infos| { - Message::from_iter([ - Message::Config(config::Message::Infos(Some(infos))), - Message::ConnectionStatus(true), - ]) - }), - || { - [Message::Config(config::Message::Infos(None))] - .into_iter() - .chain(flag.then_some(Message::MainPanelDisplay(MainPanelDisplay::Config))) + /// Register subscriptions for this application. + fn subscription(&self) -> Subscription<Self::Message> { + Subscription::batch([ + theme::subscription(theme::is_dark()).map(Message::ChangeTheme), + self.core().watch_config::<Config>(Self::APP_ID).map( + |cosmic::cosmic_config::Update { errors, config, .. }| { + (errors.into_iter()).for_each(|e| log::error!("config error: {e}")); + Message::UpdateConfig(config) }, - ) - }) - } - - /// Handle the refresh requests. - /// - /// This is where the commands are sent to lektord. - fn handle_refresh_request( - &mut self, - req: RefreshRequest, - ) -> Command<<Self as Application>::Message> { - match req { - RefreshRequest::Playlists => { - Command::perform(get_playlists(self.connect_config.clone()), |res| { - res.map(|plts| { - let main_keep = Message::from(playlists::Message::KeepPlaylists( - plts.iter().map(|(name, _)| name.as_ref().into()).collect(), - )); - let side_keep = - sidebar::Message::from_iter(plts.iter().map(|(name, _)| name.clone())) - .into(); - let update_each = plts.into_iter().map(|(name, infos)| { - let name = name.as_ref().into(); - Message::from(playlists::Message::UpdatePlaylistInfos(name, infos)) - }); - Message::from_iter([main_keep, side_keep].into_iter().chain(update_each)) - }) - .into() - }) - } - - RefreshRequest::Playlist(plt) => { - Command::perform(self.get_playlist_content(plt.clone()), move |k| { - k.map(|k| Message::from(playlists::Message::Reload(plt, k))) - .unwrap_or_default() - }) - } - - RefreshRequest::History => Command::perform(self.get_history(), |k| { - k.map(|k| Message::from(history::Message::Reload(k))) - .unwrap_or_default() - }), - - // Fow now we always update the whole queue, see later to only update one part of the - // queue as an optimization. - RefreshRequest::Queue | RefreshRequest::QueueLevel(_) => { - Command::perform(self.get_queue(), |k| { - k.map(|k| Message::from(queue::Message::Reload(k))) - .unwrap_or_default() - }) + ), + subscriptions::lektord::Suscription { + config: self.connect_config.clone(), } - } - } - - fn playlist_list(&self) -> &[Arc<str>] { - self.sidebar.playlist_list() - } -} - -impl Application for Amadeus { - type Message = Message; - type Executor = iced::executor::Default; - type Theme = iced::Theme; - type Flags = AmadeusConfig; - - /// Create a new [Amadeus] application from the configs. - fn new(config: Self::Flags) -> (Self, Command<Self::Message>) { - let init_events = Command::batch([ - iced::font::load(iced_aw::graphics::icons::ICON_FONT_BYTES).map(|res| { - res.map_err(|err| anyhow!("load icon font err: {err:?}")) - .into() - }), - Message::from(config::Message::LoadConfig(config)).perform(), - iced::system::fetch_information(config::Message::SystemInformations).map(Message::from), - ]); - (Default::default(), init_events) - } - - /// Display the current kara as the title of the window. - fn title(&self) -> String { - match self.current_kara.as_ref() { - Some(current) => format!("Amadeus [{}] - {current}", self.playback_state.as_ref()), - None => format!("Amadeus [{}]", self.playback_state.as_ref()), - } + .run(), + ]) } - /// Update the internal state and handle the changes to re-dispatch the messages. + /// Handles messages emitted by the application and its widgets. fn update(&mut self, message: Self::Message) -> Command<Self::Message> { - match message { - // Some special messages. - Message::None => Command::none(), - Message::Multiple(messages) => { - Command::batch(messages.into_iter().map(|message| self.update(message))) - } - - // Launch or close MPRIS. - Message::ToggleMprisServer(true) => { - log::error!("should launch the mpris server, ignore for now"); - Command::none() - } - Message::ToggleMprisServer(false) => { - log::error!("should shutdown the mpris server, ignore for now"); - Command::none() - } - - // Open modal or close it. - Message::CloseModal => { - self.modal = None; - Command::none() - } - Message::DisplayModal(show) => match show { - ShowModal::KaraInfo(kara_ptr) => { - self.modal = Some(WhichModal::KaraInfo(karainfos::State::new(kara_ptr))); - Command::none() - } - ShowModal::KaraInfoById(id) => { - self.with_kara(id, |kara| Message::DisplayModal(ShowModal::KaraInfo(kara))) - } - ShowModal::ChoosePlaylist(plts, callback) => { - self.modal = Some(WhichModal::PlaylistSelect( - playlistselect::State::new(plts), - callback, - )); - Command::none() + macro_rules! save_config { + ($setter:ident ($arg:expr) => $on_ok:expr) => { + match self.config.$setter(&self.cosmic_config, $arg) { + Ok(_) => $on_ok, + Err(err) => { + log::error!("failed to save config: {err}"); + Command::none() + } } - ShowModal::ChoosePlaylistExpect(expect, plts, callback) => { - self.modal = Some(WhichModal::PlaylistSelect( - playlistselect::State::new_without(plts, expect), - callback, - )); - Command::none() + }; + } + macro_rules! update_remote_addr { + ($pre_update:stmt) => {{ + $pre_update + match (self.tmp_remote_addr.parse::<Ipv4Addr>(), self.tmp_remote_port.parse::<u16>()) { + (Ok(addr), Ok(port)) => { + self.tmp_remote_valid = true; + save_config!(set_host(SocketAddr::new(IpAddr::V4(addr), port).into()) => { + self.update_connect_config() + }) + } + _ => { + self.tmp_remote_valid = false; + Command::none() + } } - }, - - // Toggle fullscreen. - Message::SetWindowMode(mode) => iced::window::change_mode(mode), - Message::ToggleFullScreen => { - use iced::window::Mode::*; - iced::window::fetch_mode(|mode| match mode { - Fullscreen => Message::SetWindowMode(Windowed), - _ => Message::SetWindowMode(Fullscreen), - }) - } - - // Open a link. - Message::OpenLinkInBrowser(link) => Message::into_perform( - lektor_utils::open::that(link) - .map_err(|err| anyhow!("failed to open {link}: {err:?}")), - ), + }}; + } - // Kill lektord & exit the application - Message::ExitApplication => iced::window::close(), - Message::ShutdownLektord => send(shutdown_lektord(self.connect_config.clone())) - .map(|_| Message::ExitApplication), - - // Update on connection status... - Message::ConnectionStatus(true) if !self.is_connected => { - self.is_connected = true; - Command::batch([ - self.handle_refresh_request(RefreshRequest::Playlists), - self.update(Message::MainPanelDisplay(MainPanelDisplay::MainPanel( - mainpanel::Show::Queue, - ))), - ]) - } - Message::ConnectionStatus(false) if self.is_connected => { - self.is_connected = false; - let flag = self.config.amadeus.open_config_if_init_ping_failed; - Command::batch([ - flag.then(|| self.update(Message::MainPanelDisplay(MainPanelDisplay::Config))) - .unwrap_or_else(Command::none), - Amadeus::clear(), - ]) - } - Message::ConnectionStatus(_) => Command::none(), - - // Messages got from subscriptions. - Message::BigTick(instant) => { - self.last_instant = self.last_instant.max(instant); - Command::perform(get_infos(self.connect_config.clone()), |res| match res { - Ok(Infos { - last_epoch: Some(epoch), - version, - }) => Message::from_iter([ - Message::ConnectionStatus(true), - Message::DatabaseEpoch(epoch), - Message::RefreshRequest(RefreshRequest::Playlists), - Message::Config(config::Message::Infos(Some(Infos { - version, - last_epoch: Some(epoch), - }))), - ]), - Ok(infos) => Message::from_iter([ - Message::ConnectionStatus(true), - Message::RefreshRequest(RefreshRequest::Playlists), - Message::Config(config::Message::Infos(Some(infos))), - ]), - Err(_) => Message::ConnectionStatus(false), - }) - } - Message::SmollTick(instant) => { - self.last_instant = self.last_instant.max(instant); - - let queue = Command::perform(self.get_queue(), |res| { - res.map(|queue| { - Message::MainPanel(mainpanel::Message::Queue(queue::Message::Reload(queue))) - }) - .unwrap_or(Message::ConnectionStatus(false)) - }); - - let history = Command::perform(self.get_history(), |res| { - res.map(|history| { - Message::MainPanel(mainpanel::Message::History(history::Message::Reload( - history, - ))) - }) - .unwrap_or(Message::ConnectionStatus(false)) - }); - - let status = - Command::perform(get_status(self.connect_config.clone()), |res| match res { - Ok(PlayStateWithCurrent { - state: s @ PlayState::Play | s @ PlayState::Pause, - current: Some((id, elapsed, duration)), - }) => Message::from_iter([ - Message::ChangedPlayback(s), - Message::ChangedKaraId(id), - Message::TimeUpdate(elapsed, duration), - ]), - Ok(PlayStateWithCurrent { - state: PlayState::Stop, - current: None, - }) => Message::ChangedPlayback(PlayState::Stop), - Ok(state) => { - log::error!("got incoherent state from the server: {state:?}"); - Message::ChangedPlayback(PlayState::Stop) - } - Err(_) => Message::ConnectionStatus(false), - }); - - Command::batch([queue, history, status]) + match message { + // Misc config updates. + Message::UpdateConfig(config) => { + self.tmp_remote_addr = config.host().1.ip().to_string(); + self.tmp_remote_port = config.host().1.port().to_string(); + self.tmp_remote_user = config.user().user.clone(); + self.tmp_remote_token = config.user().token.clone(); + self.tmp_remote_valid = true; + self.config = config; + lektor_utils::logger::set_level(self.config.log_level()); + self.update_connect_config() } - - // Config changed - Message::Config(config) => self.handle_config_message(config), - Message::ConfigLoaded => self.command_init_ping(), - Message::ReconnectToLektord => Command::batch([ - send(KaraStore::into_clear(self.kara_store.clone())), - Amadeus::clear(), - ]), - Message::DatabaseEpoch(epoch) => match self.last_epoch.take() { - Some(last_epoch) if last_epoch != epoch => { - self.last_epoch = Some(last_epoch.max(epoch)); - Message::ReconnectToLektord.perform() - } - _ => { - self.last_epoch = Some(epoch); + Message::ChangeTheme(arg) => cosmic::app::command::set_theme(arg), + Message::ChangeRemoteAddr(arg) => update_remote_addr!(self.tmp_remote_addr = arg), + Message::ChangeRemotePort(arg) => match arg.is_empty() { + true => update_remote_addr!(self.tmp_remote_port = "0".to_string()), + false => update_remote_addr!(self.tmp_remote_port = arg), + }, + Message::ChangeUserName(arg) => save_config! { + set_user(self.config.user().clone().with_user(arg)) => self.update_connect_config() + }, + Message::ChangeUserToken(arg) => save_config! { + set_user(self.config.user().clone().with_token(arg)) => self.update_connect_config() + }, + Message::ChangeKurisuToken(arg) => save_config! { + set_kurisu_token((!arg.is_empty()).then_some(arg)) => Command::none() + }, + Message::ChangeURLScheme(arg) => save_config! { set_scheme(arg) => Command::none() }, + Message::ChangeLogLevel(arg) => save_config! { + set_log_level(arg) => { + lektor_utils::logger::set_level(arg.into()); Command::none() } }, - // Change what the main panel displays + We have informations to pass to it - Message::MainPanel(message) => self.mainpanel.update(message).map(Message::from), - Message::MainPanelDisplay(MainPanelDisplay::Config) => { - self.show_main_panel = false; - Command::none() - } - Message::MainPanelDisplay(MainPanelDisplay::MainPanel(show)) => { - self.show_main_panel = true; - self.mainpanel - .update(mainpanel::Message::Show(show)) - .map(Message::from) - } - - // A message for the side panel. - Message::Sidebar(message) => self.sidebar.update(message), - Message::SideBarResize(size) => { - self.sidebar_size = Some(size); + // Messages from the lektord suscription. + Message::LektordDisconnected => { + if let LektordState::Connected { .. } = mem::take(&mut self.lektord_state) { + log::error!("disconnected from lektord instance"); + } Command::none() } - - // Refresh from lektord. - Message::TimeUpdate(elapsed, duration) => { - self.bottombar.update(bottombar::Message(elapsed, duration)); + Message::LektordConnected(lektor_payloads::Infos { + version, + last_epoch, + }) => { + log::info!("connected to lektord instance"); + self.lektord_state = LektordState::Connected { + version, + last_epoch, + state: None, + }; Command::none() } - Message::ChangedPlayback(PlayState::Stop) => { - self.playback_state = PlayState::Stop; - self.current_kara = None; - self.bottombar.update(Default::default()); - self.topbar.update(topbar::Message::ChangedKara(None)); - self.topbar - .update(topbar::Message::ChangedPlayback(PlayState::Stop)); + Message::LektordUpdate(state) => { + if let LektordState::Connected { state: ptr, .. } = &mut self.lektord_state { + *ptr = Some(state) + } Command::none() } - Message::ChangedPlayback(x) => { - self.playback_state = x; - self.topbar.update(topbar::Message::ChangedPlayback(x)); + + // Open an URL... + Message::OpenUrl(url) => { + match open::that_detached(url) { + Err(err) => log::error!("failed to open \"{url}\": {err}"), + Ok(()) => log::info!("opened link: \"{url}\""), + } Command::none() } - Message::ChangedKaraId(kid) => { - Command::perform(KaraStore::into_get(self.kara_store.clone(), kid), |res| { - Message::from_err_or( - res.map(Message::ChangedKara), - Message::ChangedPlayback(PlayState::Stop), - ) - }) - } - Message::ChangedKara(kara) => { - self.current_kara = Some(kara.clone()); - self.topbar.update(topbar::Message::ChangedKara(Some(kara))); + + // Context page & header button pressed. + Message::ToggleContextPage(context_page) => { + if self.context_page == context_page { + self.core.window.show_context = !self.core.window.show_context; + } else { + self.context_page = context_page; + self.core.window.show_context = true; + } + self.set_context_title(context_page.title()); Command::none() } + Message::HeaderCommand(id) => match self.header_controls.action(id) { + Some(action) => cosmic::command::message(action.message()), + None => Command::none(), + }, - // Send a command to lektord, we delegate things to not clutter more this function. - Message::MainPanelRequest(req) => self.handle_main_panel_request(req), - Message::PlaybackRequest(req) => self.handle_playback_request(req), - Message::RefreshRequest(req) => self.handle_refresh_request(req), - Message::KaraRequest(req) => self.handle_kara_request(req, None), + // Send commands to lektord. + Message::SendCommand(cmd) => self.send_command(cmd), } } - /// Render the application and all its component. - fn view(&self) -> Element<'_, Self::Message, Renderer<Self::Theme>> { - if !self.is_init { - return components::loading(); - } + /// Called when a nav item is selected. + fn on_nav_select(&mut self, id: nav_bar::Id) -> Command<Self::Message> { + self.nav.activate(id); + self.update_title() + } +} - // Main panel - let inner_main_panel = container(match self.show_main_panel { - true => self.mainpanel.view().map(Message::from), - false => self.config.view().map(Message::from), - }) - .width(Length::Fill) - .height(Length::Fill) - .padding(20); - - let main_panel_title = match self.show_main_panel { - true => self.mainpanel.view_title().push(self.mainpanel.view_actions().map(Message::from)), - false => row![ - text("Settings").size(SIZE_FONT_TITLE), - horizontal_space(Length::Fill), - tip!(icon!(SIZE_FONT_MEDIUM | Fullscreen -> Message::ToggleFullScreen) => Bottom | "Toggle fullscreen"), - tip!(icon!(SIZE_FONT_MEDIUM | Github -> Message::OpenLinkInBrowser(LEKTORD_HOME_LINK)) => Bottom | "Open lektor homepage"), - tip!(icon!(SIZE_FONT_MEDIUM | Bug -> Message::OpenLinkInBrowser(LEKTORD_ISSUES_LINK)) => Bottom | "Open issues for lektor"), - tip!(icon!(SIZE_FONT_MEDIUM | XOctagon -> Message::ShutdownLektord) => Bottom | "Shutdown lektord and exit amadeus"), - ], - } - .padding(0) - .height(Length::Shrink) - .width(Length::Fill); - - let main_panel = column![ - main_panel_title, - horizontal_space(20), - horizontal_rule(4), - inner_main_panel - ] - .width(Length::Fill) - .height(Length::Fill) - .padding(14); - - // Screen - let screen = Split::new( - self.sidebar.view().map(Message::from), - column![self.topbar.view().map(Message::from), main_panel] - .padding(0.0) - .width(Length::Fill) - .height(Length::Fill), - self.sidebar_size, - split::Axis::Vertical, - Message::SideBarResize, - ) - .style(iced_aw::SplitStyles::custom(SideBarSplit)) - .padding(0.0) - .min_size_first(250) - .height(Length::Fill) - .width(Length::Fill); - - let screen = column![screen, self.bottombar.view().map(Message::from)].padding(0); - - // The modal - match self.modal { - Some(ref show) => { - let modal = match show { - WhichModal::KaraInfo(kara) => kara.view().map(|_| Message::None), - WhichModal::PlaylistSelect(plt, action) => { - plt.view().map(|a| action.clone().0(a)) - } - }; - let modal = container(modal) - .max_width(600) - .padding(10) - .style(iced::theme::Container::Custom(Box::new(ModalStyleSheet))); - Into::<Element<'_, _>>::into(Modal::new(screen, modal).on_blur(Message::CloseModal)) - .map(|msg| Message::from_iter([msg, Message::CloseModal])) - } - None => screen.into(), +impl AppModel { + /// Updates the header and window titles. + fn update_title(&mut self) -> Command<Message> { + let mut window_title = fl!("app-title"); + if let Some(page) = self.nav.text(self.nav.active()) { + window_title.push_str(" — "); + window_title.push_str(page); } + self.set_window_title(window_title) } - /// We need a tick every second to query lektord plus we listen for any event. - fn subscription(&self) -> iced::Subscription<Self::Message> { - use iced::time::{every, Duration}; - let (smoll_time, big_time) = either!(self.is_connected => - (Some(Duration::new(1, 0)), self.config.amadeus.retry_time_interval()); - (None, self.config.amadeus.retry_time_interval()) - ); - let keycodes = iced::subscription::events().map(|event| match event { - Event::Keyboard(KbdEvent::KeyReleased { - key_code, - modifiers, - }) => match key_code { - KeyCode::Space => PlaybackRequest::TogglePlaybackState.into(), - KeyCode::N if modifiers.control() => PlaybackRequest::PlayNext.into(), - KeyCode::P if modifiers.control() => PlaybackRequest::PlayPrevious.into(), - _ => Message::None, - }, - _ => Message::None, - }); - iced::Subscription::batch( - [keycodes, every(big_time).map(Message::BigTick)] - .into_iter() - .chain(smoll_time.map(|smoll_time| every(smoll_time).map(Message::SmollTick))), - ) + /// Update the connect config with a set config in the application. Because communications may + /// be in progress, we must wait to write the config pointer… + fn update_connect_config(&self) -> Command<Message> { + let config = self.config.get_connect_config(); + let connect_config = self.connect_config.clone(); + cosmic::command::future(async { + *connect_config.write_owned().await = config; + cosmic::app::message::none() + }) } - /// Scale factor from the config file. Between 0.5 and 2. - fn scale_factor(&self) -> f64 { - self.config.amadeus.scale_factor() - } + fn send_command(&self, cmd: LektordCommand) -> Command<Message> { + let config = self.connect_config.clone(); + use lektor_payloads::*; + macro_rules! cmd { + ($req:ident ($($arg:expr),*) $(, $res:pat => $handle:expr)?) => { + cosmic::command::future(async move { + cmd!(@handle $req: + lektor_lib::requests::$req(config.read().await.as_ref() $(, $arg)*).await, + $($res => $handle)? + ) + }) + }; + + (@handle $txt:ident: $req:expr, ) => { cmd!(@handle $txt: $req, _ => cosmic::app::message::none()) }; + (@handle $txt:ident: $req:expr, $res:pat => $handle:expr) => { match $req { + Ok($res) => $handle, + Err(err) => { + log::error!("failed '{}': {err}", stringify!($txt)); + cosmic::app::message::none() + } + }}; + } + + match cmd { + LektordCommand::PlaybackStop => cmd!(set_playback_state(PlayState::Stop)), + LektordCommand::PlaybackPlay => cmd!(set_playback_state(PlayState::Play)), + LektordCommand::PlaybackPause => cmd!(set_playback_state(PlayState::Pause)), + LektordCommand::PlaybackToggle => cmd!(toggle_playback_state()), + LektordCommand::PlaybackNext => cmd!(play_next()), + LektordCommand::PlaybackPrevious => cmd!(play_previous()), - /// We can change the theme of the application. The style will be automatically derived. As we - /// only have dark and light themes. - fn theme(&self) -> Self::Theme { - self.config.amadeus.theme.into() + LektordCommand::QueueShuffle => cmd!(shuffle_queue()), + + cmd => { + log::error!("need to implement {cmd:?}"); + Command::none() + } + } } } diff --git a/amadeus/src/app/about_page.rs b/amadeus/src/app/about_page.rs new file mode 100644 index 00000000..cefd37f6 --- /dev/null +++ b/amadeus/src/app/about_page.rs @@ -0,0 +1,76 @@ +use crate::{ + app::{AppModel, LektordState, Message, APP_ICON}, + fl, +}; +use cosmic::{ + iced::{Alignment, Length}, + theme, widget, Apply as _, Element, +}; + +pub fn view(app: &AppModel) -> Element<Message> { + macro_rules! url { + ($icon:ident => $url:literal) => {{ + widget::icon::from_svg_bytes(crate::icons::$icon) + .symbolic(true) + .apply(widget::button::icon) + .on_press(Message::OpenUrl($url)) + .tooltip(fl!("open-url", url = $url)) + }}; + } + + let app_icon = widget::image::Handle::from_memory(APP_ICON) + .apply(widget::image) + .width(128); + + let link_rows = widget::row() + .push(url!(WEB => "https://kurisu.iiens.net/")) + .push(url!(GIT => "https://git.iiens.net/martin2018/lektor")) + .push(url!(BUG => "https://git.iiens.net/martin2018/lektor/-/issues/new")) + .push(url!(BARCODES => "https://kurisu.iiens.net/api/download.php?token")) + .spacing(theme::active().cosmic().space_xs()); + + let amadeus_section = widget::settings::section() + .title("Amadeus informations") + .add(widget::settings::item( + "Version", + crate::version().apply(widget::text::body), + )); + + let lektord_section = widget::settings::section().title("Lektord informations"); + let lektord_section = match &app.lektord_state { + LektordState::Disconnected => lektord_section.add(widget::settings::item( + "Status", + widget::text::body("Disconnected"), + )), + LektordState::Connected { + version, + last_epoch, + .. + } => lektord_section + .add(widget::settings::item( + "Status", + widget::text::body("Connected"), + )) + .add(widget::settings::item( + "Version", + widget::text::body(version), + )) + .add(widget::settings::item( + "DB Epoch", + widget::text::body(last_epoch.unwrap_or_default().to_string()), + )), + }; + + widget::column() + .push(app_icon) + .push(widget::text::title3(fl!("app-title"))) + .push(link_rows) + .push(widget::settings::view_column(vec![ + amadeus_section.into(), + lektord_section.into(), + ])) + .align_items(Alignment::Center) + .spacing(theme::active().cosmic().space_xxs()) + .width(Length::Fill) + .into() +} diff --git a/amadeus/src/app/config_page.rs b/amadeus/src/app/config_page.rs new file mode 100644 index 00000000..f5f64fba --- /dev/null +++ b/amadeus/src/app/config_page.rs @@ -0,0 +1,83 @@ +use crate::{ + app::{AppModel, Message}, + fl, +}; +use cosmic::{theme, widget, Element}; +use lektor_utils::config::{SocketScheme, UserConfig}; + +pub fn view(app: &AppModel) -> Element<Message> { + macro_rules! dropdown { + ($array:expr, $val:expr => $msg:ident) => {{ + let idx = ($array.iter().enumerate()).find_map(|(i, a)| (*a == $val).then_some(i)); + widget::dropdown($array, idx, |idx| Message::$msg($array[idx])) + }}; + } + + // --- top section + let log_levels = dropdown!( + crate::config::LOG_LEVELS, lektor_utils::logger::get().into() => ChangeLogLevel + ); + let dark_theme = widget::toggler(None, theme::active_type().is_dark(), |is_dark| { + Message::ChangeTheme(match is_dark { + true => theme::system_dark(), + false => theme::system_light(), + }) + }); + + let top_section = widget::settings::section() + .title(fl!("app-config")) + .add(widget::settings::item(fl!("log-level"), log_levels)) + .add(widget::settings::item(fl!("dark-theme"), dark_theme)) + .into(); + + // --- lektord section + let url_schemes = dropdown!( + &[SocketScheme::Http, SocketScheme::Https], app.config.host().0 => ChangeURLScheme + ); + let mut instance_addr = widget::text_input("IPv4", &app.tmp_remote_addr) + .width(150) + .on_clear(Message::ChangeRemoteAddr("127.0.0.1".to_string())) + .on_input(Message::ChangeRemoteAddr); + let mut instance_port = widget::text_input(fl!("port"), &app.tmp_remote_port) + .width(150) + .on_clear(Message::ChangeRemotePort("6600".to_string())) + .on_input(Message::ChangeRemotePort); + if !app.tmp_remote_valid { + instance_addr = instance_addr.error("invalid"); + instance_port = instance_port.error("invalid"); + } + let instance_user = widget::text_input("Viieux", &app.tmp_remote_user) + .width(150) + .on_clear(Message::ChangeUserName(UserConfig::default().user)) + .on_input(Message::ChangeUserName); + let instance_token = widget::text_input(fl!("token"), &app.tmp_remote_token) + .password() + .width(150) + .on_clear(Message::ChangeUserToken(UserConfig::default().token)) + .on_input(Message::ChangeUserToken); + + let remote_section = widget::settings::section() + .title(fl!("remote-config")) + .add(widget::settings::item(fl!("instance-scheme"), url_schemes)) + .add(widget::settings::item(fl!("instance-addr"), instance_addr)) + .add(widget::settings::item(fl!("instance-port"), instance_port)) + .add(widget::settings::item("User", instance_user)) + .add(widget::settings::item(fl!("token"), instance_token)) + .into(); + + // --- kurisu section + let kurisu_token = + widget::text_input::text_input(fl!("token"), app.config.kurisu_token().unwrap_or_default()) + .password() + .width(150) + .on_clear(Message::ChangeKurisuToken("".to_string())) + .on_input(Message::ChangeKurisuToken); + + let kurisu_section = widget::settings::section() + .title("Kurisu configuration") + .add(widget::settings::item(fl!("kurisu-token"), kurisu_token)) + .into(); + + // --- total settings + widget::settings::view_column(vec![top_section, remote_section, kurisu_section]).into() +} diff --git a/amadeus/src/app/context_page.rs b/amadeus/src/app/context_page.rs new file mode 100644 index 00000000..11a54dea --- /dev/null +++ b/amadeus/src/app/context_page.rs @@ -0,0 +1,20 @@ +use crate::fl; + +/// The context page to display in the context drawer. This is the pane on the right that can be +/// hidden or shown. +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] +pub enum ContextPage { + #[default] + About, + + Settings, +} + +impl ContextPage { + pub fn title(&self) -> String { + match self { + Self::About => fl!("about"), + Self::Settings=> fl!("settings"), + } + } +} diff --git a/amadeus/src/app/history_page.rs b/amadeus/src/app/history_page.rs new file mode 100644 index 00000000..a191e2d6 --- /dev/null +++ b/amadeus/src/app/history_page.rs @@ -0,0 +1,19 @@ +use crate::{app::Message, fl}; +use cosmic::{ + iced::{ + alignment::{Horizontal, Vertical}, + Length, + }, + widget, Apply as _, Element, +}; + +pub fn view<'a>() -> Element<'a, Message> { + widget::text::title1(fl!("history")) + .apply(widget::container) + .width(Length::Fill) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .into() +} + diff --git a/amadeus/src/app/home_page.rs b/amadeus/src/app/home_page.rs new file mode 100644 index 00000000..ebfc6b18 --- /dev/null +++ b/amadeus/src/app/home_page.rs @@ -0,0 +1,18 @@ +use crate::{app::Message, fl}; +use cosmic::{ + iced::{ + alignment::{Horizontal, Vertical}, + Length, + }, + widget, Apply as _, Element, +}; + +pub fn view<'a>() -> Element<'a, Message> { + widget::text::title1(fl!("home")) + .apply(widget::container) + .width(Length::Fill) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .into() +} diff --git a/amadeus/src/app/main_page.rs b/amadeus/src/app/main_page.rs new file mode 100644 index 00000000..8788a36c --- /dev/null +++ b/amadeus/src/app/main_page.rs @@ -0,0 +1,58 @@ +use crate::fl; +use cosmic::widget::{icon, nav_bar, Icon}; +use derive_more::Display; +use std::sync::Arc; + +/// The page to display in the application. +#[derive(Default, Debug, Eq, PartialEq, Clone, Display)] +#[non_exhaustive] +pub enum Page { + #[default] + #[display("{}", fl!("home"))] + Home, + + #[display("{}", fl!("queue"))] + Queue, + + #[display("{}", fl!("history"))] + History, + + #[display("{}", fl!("search"))] + Search, + + #[display("{}", fl!("playlists"))] + Playlists, + + #[display("{}", fl!("playlist", name = _0.as_ref()))] + Playlist(Arc<str>), +} + +impl Page { + pub fn icon(&self) -> Icon { + let icon = match self { + Page::Home => crate::icons::HOME, + Page::Queue => crate::icons::QUEUE, + Page::History => crate::icons::HISTORY, + Page::Search => crate::icons::SEARCH, + Page::Playlists | Page::Playlist(_) => crate::icons::ARCHIVE, + }; + icon::icon(icon::from_svg_bytes(icon).symbolic(true)) + } +} + +pub fn nav_bar_model() -> nav_bar::Model { + macro_rules! insert { + ($b:expr, $page:ident) => { + $b.text(Page::$page.to_string()) + .icon(Page::$page.icon()) + .data(Page::$page) + }; + } + nav_bar::Model::builder() + .insert(|b| insert!(b, Home).activate()) + .insert(|b| insert!(b, Queue)) + .insert(|b| insert!(b, History)) + .insert(|b| insert!(b, Search)) + .insert(|b| insert!(b, Playlists)) + .build() +} diff --git a/amadeus/src/app/menu_bar.rs b/amadeus/src/app/menu_bar.rs new file mode 100644 index 00000000..9508f83b --- /dev/null +++ b/amadeus/src/app/menu_bar.rs @@ -0,0 +1,141 @@ +use crate::{ + app::{context_page::ContextPage, LektordCommand, Message}, + fl, +}; +use cosmic::{ + iced::{Alignment, Length}, + prelude::*, + widget::{icon, menu, segmented_button}, +}; +use derive_more::Display; +use std::collections::HashMap; + +/// The different actions that can be performed from the header bar of the window. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Display)] +#[rustfmt::skip] +pub enum MenuAction { + #[display("{}", fl!("about"))] About, + #[display("{}", fl!("settings"))] Settings, + #[display("{}", fl!("playback-clear"))] QueueClear, + #[display("{}", fl!("playback-crop"))] QueueCrop, + #[display("{}", fl!("playback-shuffle"))] QueueShuffle, + #[display("{}", fl!("toggle-playback"))] PlaybackToggle, + #[display("{}", fl!("stop-playback"))] PlaybackStop, + #[display("{}", fl!("pause-playback"))] PlaybackPlay, + #[display("{}", fl!("play-playback"))] PlaybackPause, + #[display("{}", fl!("next-kara"))] PlaybackNext, + #[display("{}", fl!("prev-kara"))] PlaybackPrevious, +} + +/// The group of buttons at the center of the header bar of the window. +pub struct MenuHeaderCentralCommands { + buttons: segmented_button::Model<segmented_button::SingleSelect>, +} + +impl menu::action::MenuAction for MenuAction { + type Message = Message; + + fn message(&self) -> Self::Message { + match self { + MenuAction::About => Message::ToggleContextPage(ContextPage::About), + MenuAction::Settings => Message::ToggleContextPage(ContextPage::Settings), + + MenuAction::PlaybackToggle => Message::SendCommand(LektordCommand::PlaybackToggle), + MenuAction::PlaybackNext => Message::SendCommand(LektordCommand::PlaybackNext), + MenuAction::PlaybackPrevious => Message::SendCommand(LektordCommand::PlaybackPrevious), + MenuAction::PlaybackStop => Message::SendCommand(LektordCommand::PlaybackStop), + MenuAction::PlaybackPlay => Message::SendCommand(LektordCommand::PlaybackPlay), + MenuAction::PlaybackPause => Message::SendCommand(LektordCommand::PlaybackPause), + + MenuAction::QueueShuffle => Message::SendCommand(LektordCommand::QueueShuffle), + MenuAction::QueueClear => Message::SendCommand(LektordCommand::QueueClear), + MenuAction::QueueCrop => Message::SendCommand(LektordCommand::QueueCrop), + } + } +} + +impl Default for MenuHeaderCentralCommands { + fn default() -> Self { + macro_rules! add { + ($b:ident, $icon:ident, $action:ident) => {{ + let icon = icon::from_svg_bytes(crate::icons::$icon) + .symbolic(true) + .apply(icon::icon); + $b.data(MenuAction::$action).icon(icon) + }}; + } + let buttons = segmented_button::Model::builder() + .insert(|b| add!(b, PREVIOUS, PlaybackPrevious)) + .insert(|b| add!(b, STOP, PlaybackStop)) + .insert(|b| add!(b, NEXT, PlaybackNext)) + .insert(|b| add!(b, SHUFFLE, QueueShuffle)) + .insert(|b| add!(b, METEOR, QueueClear)) + .build(); + Self { buttons } + } +} + +impl MenuHeaderCentralCommands { + pub fn view(&self) -> Element<Message> { + segmented_button::horizontal(&self.buttons) + .style(cosmic::theme::SegmentedButton::Control) + .button_alignment(Alignment::Center) + .button_height(32) + .button_padding([16, 10, 16, 10]) + .button_spacing(8) + .spacing(cosmic::theme::active().cosmic().space_xxs()) + .width(Length::Shrink) + .on_activate(Message::HeaderCommand) + .into() + } + + /// Get the action associated with an action. + pub fn action(&mut self, id: segmented_button::Entity) -> Option<MenuAction> { + self.buttons.deactivate(); + self.buttons.data(id).copied() + } +} + +/// Get the menu from the header bar, are at the start of the header. +pub fn header_menu(key_binds: &HashMap<menu::KeyBind, MenuAction>) -> Element<Message> { + macro_rules! button { + ($msg:ident) => {{ + menu::Item::Button(MenuAction::$msg.to_string(), MenuAction::$msg) + }}; + } + macro_rules! folder { + ($name:literal => [ $($content:expr),* $(,)? ]) => {{ + menu::Item::Folder(fl!($name), vec![ $($content),* ]) + }}; + } + macro_rules! menu { + ($name:literal => [ $($content:expr),* $(,)? ]) => {{ + menu::Tree::with_children( + menu::root(fl!($name)), + menu::items(key_binds, vec![ $($content),* ]), + ) + }}; + } + + Into::into(menu::bar(vec![ + menu!("edit" => [ + folder!("playback" => [ + button!(PlaybackPlay), + button!(PlaybackPause), + button!(PlaybackToggle), + button!(PlaybackStop), + button!(PlaybackNext), + button!(PlaybackPrevious), + ]), + folder!("menu-queue" => [ + button!(QueueShuffle), + button!(QueueCrop), + button!(QueueClear), + ]), + ]), + menu!("view" => [ + button!(About), + button!(Settings), + ]), + ])) +} diff --git a/amadeus/src/app/playlist_page.rs b/amadeus/src/app/playlist_page.rs new file mode 100644 index 00000000..aaf8cd23 --- /dev/null +++ b/amadeus/src/app/playlist_page.rs @@ -0,0 +1,18 @@ +use crate::{app::Message, fl}; +use cosmic::{ + iced::{ + alignment::{Horizontal, Vertical}, + Length, + }, + widget, Apply as _, Element, +}; + +pub fn view<'a>(playlist: &str) -> Element<'a, Message> { + widget::text::title1(fl!("playlist", name = playlist)) + .apply(widget::container) + .width(Length::Fill) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .into() +} diff --git a/amadeus/src/app/playlists_page.rs b/amadeus/src/app/playlists_page.rs new file mode 100644 index 00000000..dabcc76e --- /dev/null +++ b/amadeus/src/app/playlists_page.rs @@ -0,0 +1,18 @@ +use crate::{app::Message, fl}; +use cosmic::{ + iced::{ + alignment::{Horizontal, Vertical}, + Length, + }, + widget, Apply as _, Element, +}; + +pub fn view<'a>() -> Element<'a, Message> { + widget::text::title1(fl!("playlists")) + .apply(widget::container) + .width(Length::Fill) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .into() +} diff --git a/amadeus/src/app/queue_page.rs b/amadeus/src/app/queue_page.rs new file mode 100644 index 00000000..e1daae7a --- /dev/null +++ b/amadeus/src/app/queue_page.rs @@ -0,0 +1,18 @@ +use crate::{app::Message, fl}; +use cosmic::{ + iced::{ + alignment::{Horizontal, Vertical}, + Length, + }, + widget, Apply as _, Element, +}; + +pub fn view<'a>() -> Element<'a, Message> { + widget::text::title1(fl!("queue")) + .apply(widget::container) + .width(Length::Fill) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .into() +} diff --git a/amadeus/src/app/search_page.rs b/amadeus/src/app/search_page.rs new file mode 100644 index 00000000..03db263b --- /dev/null +++ b/amadeus/src/app/search_page.rs @@ -0,0 +1,18 @@ +use crate::{app::Message, fl}; +use cosmic::{ + iced::{ + alignment::{Horizontal, Vertical}, + Length, + }, + widget, Apply as _, Element, +}; + +pub fn view<'a>() -> Element<'a, Message> { + widget::text::title1(fl!("search")) + .apply(widget::container) + .width(Length::Fill) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(Vertical::Center) + .into() +} diff --git a/amadeus/src/components/bottombar.rs b/amadeus/src/components/bottombar.rs deleted file mode 100644 index d98e0bce..00000000 --- a/amadeus/src/components/bottombar.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! The bottom bar will permit to display the elapsed time and the remaining time of the currently -//! playing kara. - -use crate::style_sheet::BottomBarStyleSheet; -use iced::{widget::progress_bar, Element, Length}; - -#[derive(Default)] -pub struct State { - duration: f32, - elapsed: f32, -} - -#[derive(Default, Debug, Copy, Clone)] -pub struct Message(pub f32, pub f32); - -impl State { - pub fn update(&mut self, message: Message) { - let Message(elapsed, duration) = message; - self.duration = duration.max(0.0); - self.elapsed = elapsed.clamp(0.0, duration); - } - - pub fn view(&self) -> Element<'_, Message> { - progress_bar(0.0..=self.duration, self.elapsed) - .width(Length::Fill) - .height(Length::Fixed(10.0)) - .style(iced::theme::ProgressBar::Custom(Box::new( - BottomBarStyleSheet, - ))) - .into() - } -} diff --git a/amadeus/src/components/config/loglevel.rs b/amadeus/src/components/config/loglevel.rs deleted file mode 100644 index c89a679d..00000000 --- a/amadeus/src/components/config/loglevel.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::style_sheet::sizes::*; -use iced::{ - widget::{horizontal_space, radio, row, text}, - Element, Length, -}; -use lektor_utils::log::{Level as LogLevel, Level::*}; - -/// The state of the component -#[derive(Clone, Copy, Default)] -pub struct State; - -pub type Message = LogLevel; - -impl State { - /// Render the state of the component. - pub fn view(&self, selected: LogLevel) -> Element<'_, Message> { - [Warn, Info, Debug, Trace] - .into_iter() - .fold( - row![ - text("Log level".to_string()).size(SIZE_FONT_NORMAL), - horizontal_space(Length::Fill) - ], - |r, lvl| { - let choice = radio(lvl.as_str(), lvl, Some(selected), |lvl| lvl) - .size(SIZE_FONT_NORMAL) - .text_size(SIZE_FONT_NORMAL) - .spacing(5); - r.push(choice) - }, - ) - .spacing(30) - .into() - } -} diff --git a/amadeus/src/components/config/mod.rs b/amadeus/src/components/config/mod.rs deleted file mode 100644 index 2f43feff..00000000 --- a/amadeus/src/components/config/mod.rs +++ /dev/null @@ -1,585 +0,0 @@ -pub mod loglevel; -pub mod theme; - -use crate::{ - components::{icon, tip}, - links::*, - style_sheet::{sizes::*, Color, SquareButtonStyleSheet}, -}; -use iced::{ - alignment::{Horizontal, Vertical}, - widget::{ - button, column, container, horizontal_space, row, scrollable, - scrollable::{Direction, Viewport}, - text, text_input, toggler, vertical_space, Column, - }, - Alignment, Command, Element, Length, -}; -use lektor_payloads::Infos; -use lektor_utils::{ - config::{SocketScheme, UserConfig}, - either, - log::{self, Level as LogLevel}, - logger, -}; -use serde::{Deserialize, Serialize}; -use std::{borrow::Cow, net::SocketAddr, ops::Deref, sync::Arc}; - -pub struct State { - config: Arc<AmadeusConfig>, - scroll_id: scrollable::Id, - current_scroll_offset: scrollable::RelativeOffset, - - tmp_retry_time: u16, - tmp_scheme: String, - tmp_host: String, - tmp_port: u16, - remote_infos: Option<Option<Infos>>, - theme: theme::State, - loglevel: loglevel::State, - system_informations: Option<iced::system::Information>, -} - -fn clamp_scale_factor(scale: impl Into<f64>) -> f64 { - scale.into().clamp(0.5, 1.5) -} - -fn clamp_time_interval(time: impl Into<i64>) -> u16 { - time.into().clamp(10, u16::MAX as i64) as u16 -} - -/// Amadeus configuration. -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct AmadeusConfig { - #[serde(deserialize_with = "lektor_utils::config::deserialize_log_level")] - #[serde(serialize_with = "lektor_utils::config::serialize_log_level")] - pub log: LogLevel, - - #[serde(default = "serde_utils::get_false")] - pub mpris: bool, - - pub amadeus: UIConfig, - pub connect: RemoteConfig, -} - -/// Config for the amadeus application, like the theme, some limits, retry times, etc. -#[derive(Debug, Deserialize, Serialize, Default, Clone)] -pub struct UIConfig { - pub theme: theme::Message, - - #[serde(default = "serde_utils::get_1_f64")] - #[serde(serialize_with = "serde_utils::serialize_scale_factor")] - #[serde(deserialize_with = "serde_utils::deserialize_scale_factor")] - scale_factor: f64, - - /// Retry interval in seconds. - #[serde(default = "serde_utils::get_20_u16")] - #[serde(serialize_with = "serde_utils::serialize_interval")] - #[serde(deserialize_with = "serde_utils::deserialize_interval")] - retry_interval_sec: u16, - - #[serde(default = "serde_utils::get_true")] - pub open_config_if_init_ping_failed: bool, -} - -/// How to connect to the remote lektord instance. -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct RemoteConfig { - pub scheme: SocketScheme, - pub host: SocketAddr, - pub user: UserConfig, - pub kurisu_token: Option<String>, -} - -/// Messages used to update the config file -#[derive(Debug, Clone)] -pub enum Message { - /// Nothing to see. - None, - - /// Open a link in the browser. - OpenLinkInBrowser(&'static str), - - /// Try to connect. - TryConnect, - - /// Got informations back from the remote. - Infos(Option<Infos>), - - /// Apply a whole config change, usually at startup time this is how we load the configuration. - LoadConfig(AmadeusConfig), - - /// The theme was changed. - ThemeChanged(theme::Message), - - /// The log level has changed. - LogLevelChanged(loglevel::Message), - - /// The target lektord has changed. The address may not be valid at this point. If the string - /// is valid, we need to reconnect to the new lektord server and do the whole cache - /// invalidation thingy. - HostChanged(String), - - /// The port for the host changed. The total address may not be valid at this point. If the - /// address is valid, we need to reconnect to the new lektord server and do the whole cache - /// invalidation thingy. - PortChanged(u16), - - /// The scheme changed, but not the server, we will need to reconnect but not to flush all the - /// cache. - SchemeChanged(String), - - /// The user used to connect to lektord changed. Don't need to invalidate caches, but if we - /// holded a connection we now need to reconnect for sure. - UserChanged(String), - - /// The MPRIS flag changed. - MprisFlagChanged(bool), - - /// The token used to connect to lektord changed. Don't need to invalidate caches, but if we - /// holded a connection we now need to reconnect for sure. - TokenChanged(String), - - /// The token for kurisu changed. We do this so that we can override the token from lektord - /// config with one supplied by amadeus. - KurisuTokenChanged(String), - - /// Open the settings page if lektord was offline when we launched amadeus. - OpenConfigIfInitPingFailed(bool), - - /// The scale factor changed. - ScaleFactorChanged(f64), - - /// The retry interval time changed. - RetryIntervalChanged(u16), - - /// The config was scrolled. - Scrolled(Viewport), - - /// Got system informations. - SystemInformations(iced::system::Information), -} - -/// When updating the config, we will return a future that will try to write to the disk in an -/// async way. It can either succeed or failed with a message that needs to be displayed or printed -/// or whatever. In some case we may need to reconnect to lektord, in other we may want to discard -/// the cache (when connecting to a different server). -pub enum Request { - /// Nothing to say - None, - - /// The config was loaded, can start rendering the application. - Loaded, - - /// Need to reconnect to lektord - Reconnect, - - /// Need to trash all the caches and reconnect to the new lektord remote. - FlushCacheAndReconnect, - - /// Launch or close MPRIS? - ToggleMprisServer(bool), -} - -impl UIConfig { - /// Get the scale factor, should only be between 0.5 and 2.0 - pub fn scale_factor(&self) -> f64 { - clamp_scale_factor(self.scale_factor) - } - - /// Get the retry time for when we are offline. - pub fn retry_time_interval(&self) -> iced::time::Duration { - iced::time::Duration::new(clamp_time_interval(self.retry_interval_sec).into(), 0) - } -} - -#[rustfmt::skip] -mod serde_utils { - pub(super) fn get_1_f64() -> f64 { 1.0 } - pub(super) fn get_20_u16() -> u16 { 20 } - pub(super) fn get_true() -> bool { true } - pub(super) fn get_false() -> bool { true } - - pub(super) fn serialize_scale_factor<S: serde::Serializer>(v: &f64, ser: S) -> Result<S::Ok, S::Error> { ser.serialize_f64(*v) } - pub(super) fn deserialize_scale_factor<'de, D: serde::Deserializer<'de>>(de: D) -> Result<f64, D::Error> { - struct FloadVisitor; - impl<'de> serde::de::Visitor<'de> for FloadVisitor { - type Value = f64; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("f32 or f64") } - fn visit_f64<E: serde::de::Error>(self, v: f64) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) } - fn visit_f32<E: serde::de::Error>(self, v: f32) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) } - fn visit_i32<E: serde::de::Error>(self, v: i32) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) } - fn visit_u32<E: serde::de::Error>(self, v: u32) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) } - fn visit_i16<E: serde::de::Error>(self, v: i16) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) } - fn visit_u16<E: serde::de::Error>(self, v: u16) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) } - fn visit_i8 <E: serde::de::Error>(self, v: i8 ) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) } - fn visit_u8 <E: serde::de::Error>(self, v: u8 ) -> Result<Self::Value, E> { Ok(super::clamp_scale_factor(v)) } - } - de.deserialize_any(FloadVisitor) - } - - pub(super) fn serialize_interval<S: serde::Serializer>(v: &u16, ser: S) -> Result<S::Ok, S::Error> { ser.serialize_u16(*v) } - pub(super) fn deserialize_interval<'de, D: serde::Deserializer<'de>>(de: D) -> Result<u16, D::Error> { - struct FloadVisitor; - impl<'de> serde::de::Visitor<'de> for FloadVisitor { - type Value = u16; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("u16") } - fn visit_f64<E: serde::de::Error>(self, v: f64) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) } - fn visit_f32<E: serde::de::Error>(self, v: f32) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) } - fn visit_i32<E: serde::de::Error>(self, v: i32) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) } - fn visit_u32<E: serde::de::Error>(self, v: u32) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) } - fn visit_i16<E: serde::de::Error>(self, v: i16) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) } - fn visit_u16<E: serde::de::Error>(self, v: u16) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) } - fn visit_i8 <E: serde::de::Error>(self, v: i8 ) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) } - fn visit_u8 <E: serde::de::Error>(self, v: u8 ) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v as i64)) } - fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<Self::Value, E> { Ok(super::clamp_time_interval(v)) } - fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<Self::Value, E> { - Ok(super::clamp_time_interval(v.clamp(0, i64::MAX as u64) as i64)) - } - } - de.deserialize_any(FloadVisitor) - } -} - -impl Default for State { - fn default() -> Self { - Self { - scroll_id: scrollable::Id::unique(), - current_scroll_offset: scrollable::RelativeOffset::START, - config: Default::default(), - tmp_retry_time: serde_utils::get_20_u16(), - tmp_scheme: Default::default(), - tmp_host: Default::default(), - tmp_port: Default::default(), - remote_infos: Default::default(), - theme: Default::default(), - loglevel: Default::default(), - system_informations: None, - } - } -} - -impl Deref for State { - type Target = AmadeusConfig; - fn deref(&self) -> &Self::Target { - self.config.as_ref() - } -} - -impl Default for RemoteConfig { - fn default() -> Self { - Self { - scheme: SocketScheme::Http, - host: SocketAddr::new([127, 0, 0, 1].into(), 6600), - kurisu_token: None, - user: UserConfig { - admin: false, - ..Default::default() - }, - } - } -} - -impl Default for AmadeusConfig { - fn default() -> Self { - Self { - log: LogLevel::Info, - mpris: false, - amadeus: Default::default(), - connect: Default::default(), - } - } -} - -impl State { - fn write_config(&self, on_success: Request) -> Command<Request> { - Command::perform( - lektor_utils::config::write_config_async("amadeus", self.config.clone()), - |res| match res { - Ok(_) => on_success, - Err(err) => { - log::error!(target: "amadeus", "{err}"); - Request::None - } - }, - ) - } - - pub fn update(&mut self, message: Message) -> Command<Request> { - let Some(config) = Arc::get_mut(&mut self.config) else { - let (strong, weak) = ( - Arc::strong_count(&self.config), - Arc::weak_count(&self.config), - ); - return Command::perform(async {}, move |()| { - log::error!(target: "amadeus", "failed to mut the config, {strong} strong refs, {weak} weak refs"); - Request::None - }); - }; - macro_rules! connect_to { - ($expr: expr) => {{ - $expr; - match self.tmp_host.parse() { - Ok(host) => { - config.connect.host = SocketAddr::new(host, self.tmp_port); - self.write_config(Request::FlushCacheAndReconnect) - } - _ => return Command::none(), - } - }}; - } - macro_rules! write_config { - ($reload: expr, $expr: expr) => {{ - $expr; - self.write_config($reload) - }}; - } - match message { - Message::None | Message::OpenLinkInBrowser(_) => { - log::error!("an invalid message came back and was not handled by the application: {message:?}"); - Command::none() - } - - Message::SystemInformations(infos) => { - self.system_informations = Some(infos); - Command::none() - } - - Message::LoadConfig(new) => { - (self.tmp_host, self.tmp_port) = match new.connect.host { - SocketAddr::V4(v4) => (v4.ip().to_string(), v4.port()), - SocketAddr::V6(v6) => (v6.ip().to_string(), v6.port()), - }; - self.tmp_scheme = new.connect.scheme.to_string(); - self.tmp_retry_time = clamp_time_interval(new.amadeus.retry_interval_sec); - *config = new; - // Some times we add things to the config, we need to re-write the config when we - // load it completly to apply the new defaults. - Command::perform(async {}, |()| Request::Loaded) - } - - Message::TryConnect => Command::none(), - Message::Infos(infos) => { - self.remote_infos = Some(infos); - Command::none() - } - - Message::OpenConfigIfInitPingFailed(flag) => write_config!( - Request::None, - config.amadeus.open_config_if_init_ping_failed = flag - ), - Message::RetryIntervalChanged(interval) => write_config!(Request::None, { - config.amadeus.retry_interval_sec = interval; - self.tmp_retry_time = interval; - }), - Message::ScaleFactorChanged(scale) => write_config!( - Request::None, - config.amadeus.scale_factor = clamp_scale_factor(scale) - ), - Message::ThemeChanged(theme) => { - write_config!(Request::None, config.amadeus.theme = theme) - } - Message::UserChanged(user) => { - write_config!(Request::Reconnect, config.connect.user.user = user) - } - Message::TokenChanged(token) => { - write_config!(Request::Reconnect, config.connect.user.token = token) - } - Message::KurisuTokenChanged(token) => write_config!( - Request::Reconnect, - config.connect.kurisu_token = either!(token.is_empty() => None; Some(token)) - ), - Message::MprisFlagChanged(flag) => { - write_config!(Request::ToggleMprisServer(flag), config.mpris = flag) - } - Message::LogLevelChanged(level) => write_config!(Request::None, { - config.log = level; - logger::level(level); - }), - - Message::SchemeChanged(scheme) => { - self.tmp_scheme = scheme.to_string(); - if let Ok(scheme) = scheme.parse() { - write_config!(Request::None, config.connect.scheme = scheme) - } else { - Command::none() - } - } - - Message::PortChanged(port) => connect_to!(self.tmp_port = port), - Message::HostChanged(host) => connect_to!(self.tmp_host = host), - - Message::Scrolled(viewport) => { - self.current_scroll_offset = viewport.relative_offset(); - Command::none() - } - } - } - - pub fn view(&self) -> Element<'_, Message> { - macro_rules! section { - ($name: literal => [ $($content: expr),+ $(,)? ]) => { - Some(container(column![ - text(concat!("# ", $name)).size(SIZE_FONT_MEDIUM), - vertical_space(5), - $($content),+, - vertical_space(15) - ].spacing(5)).width(Length::Fixed(500.0))) - }; - } - - macro_rules! elem_row { - ($title: literal, $what: expr) => { - row![text($title), horizontal_space(Length::Fill), $what] - }; - } - - macro_rules! input { - ($what: ident! $(($portion: literal))? $name: literal $($name_aux: expr)?, $($args: expr),+ => $event: ident) => { - column![ - row![ - horizontal_space(3), text($name).size(SIZE_FONT_SMALL), - $(horizontal_space(3), $name_aux,)? - ] - .align_items(Alignment::Start), - input!(@$what $($portion)?; $($args),+ => $event), - vertical_space(5), - ] - }; - - (@number $($portion: literal)?; $tip: expr, $value: expr => $event: ident) => { - text_input($tip, &$value.to_string()) - $(.width(Length::Fixed($portion)))? - .size(SIZE_FONT_NORMAL) - .padding(5) - .on_input(|str| if str.trim().is_empty() { - Message::$event(Default::default()) - } else { - str.trim().parse() - .map(Message::$event) - .unwrap_or(Message::None) - }) - }; - - (@password $($portion: literal)?; $tip: expr, $value: expr => $event: ident) => { - text_input($tip, $value) - $(.width(Length::Fixed($portion)))? - .password() - .size(SIZE_FONT_NORMAL) - .padding(5) - .on_input(Message::$event) - }; - - (@text $($portion: literal)?; $tip: expr, $value: expr => $event: ident) => { - text_input($tip, $value) - $(.width(Length::Fixed($portion)))? - .size(SIZE_FONT_NORMAL) - .padding(5) - .on_input(Message::$event) - }; - } - - macro_rules! scale_factor { - ($factor: literal, $($factors: literal),+) => { - row![scale_factor!($factor), $(scale_factor!($factors)),+] - }; - - ($factor: literal) => { - button(text(stringify!($factor)).size(SIZE_FONT_SMALL)) - .on_press(Message::ScaleFactorChanged($factor)) - .style(iced::theme::Button::Custom( - match self.amadeus.scale_factor.partial_cmp(&$factor) { - Some(std::cmp::Ordering::Equal) => { - Box::new(SquareButtonStyleSheet::from(Color::Success)) - } - _ => Box::<SquareButtonStyleSheet>::default(), - }, - )) - }; - } - - let token_link = - icon!(SIZE_FONT_SMALL | Link -> Message::OpenLinkInBrowser(KURISU_TOKEN_LINK)) - .padding(0); - - let content = container([ - section![ "Misc" => [ - self.loglevel.view(self.config.log).map(Message::LogLevelChanged), - toggler(Some("MPRIS server".into()), self.config.mpris, Message::MprisFlagChanged) - .text_size(SIZE_FONT_NORMAL) - .size(SIZE_FONT_NORMAL), - ]], - section![ "Amadeus" => [ - self.theme.view(&self.config.amadeus.theme).map(Message::ThemeChanged), - toggler( - Some("Open settings when lektord is offline on launch".into()), - self.config.amadeus.open_config_if_init_ping_failed, - Message::OpenConfigIfInitPingFailed - ) - .text_size(SIZE_FONT_NORMAL) - .size(SIZE_FONT_NORMAL), - elem_row!["Scale factor", scale_factor! { 0.5, 0.75, 1.0, 1.25, 1.5 }], - input!(number! "Retry interval (sec)", "seconds", self.tmp_retry_time => RetryIntervalChanged), - ]], - section![ "Remote" => [ - row![ - input!(text! (100.0) "Scheme", "http", &self.tmp_scheme => SchemeChanged), - input!(text! (270.0) "Host", "host", &self.tmp_host => HostChanged), - input!(number! (100.0) "Port", "6600", self.tmp_port => PortChanged), - column![ - tip!(button(text(iced_aw::graphics::icons::icon_to_char(iced_aw::graphics::icons::Icon::Check)) - .horizontal_alignment(Horizontal::Center) - .vertical_alignment(Vertical::Center) - .size(SIZE_FONT_NORMAL) - .font(iced_aw::graphics::icons::ICON_FONT), - ).width(Length::Fixed(27.0)).style(iced::theme::Button::Custom( - match self.remote_infos.as_ref() { - Some(Some(_)) => Box::new(SquareButtonStyleSheet::from(Color::Success)), - Some(None) => Box::new(SquareButtonStyleSheet::from(Color::Danger)), - None => Box::<SquareButtonStyleSheet>::default(), - } - )).on_press(Message::TryConnect) => Right | " Try to connect"), - vertical_space(5) - ] - ] - .spacing(1) - .align_items(Alignment::End) - .width(Length::Fixed(500.0)), - input!(text! "User", "user", &self.config.connect.user.user => UserChanged), - input!(password! "Token", "token", &self.config.connect.user.token => TokenChanged), - input!(password! "Kurisu Token" token_link, KURISU_TOKEN_LINK, - self.config.connect.kurisu_token.as_deref().unwrap_or_default() - => KurisuTokenChanged - ), - ]], - match &self.remote_infos { - Some(Some(infos)) => section![ "Remote Infos" => [ - elem_row!["Server version", text(&infos.version)], - elem_row!["Database epoch", text(infos.last_epoch.map(|x| x.to_string().into()).unwrap_or(Cow::Borrowed("None")))], - ]], - _ => None, - }, - match &self.system_informations { - Some(sys) => section! [ "System Infos" => [ - elem_row!["System name", text(sys.system_name.as_deref().unwrap_or("..."))], - elem_row!["Kernel name", text(sys.system_kernel.as_deref().unwrap_or("..."))], - elem_row!["System version", text(sys.system_version.as_deref().unwrap_or("..."))], - elem_row!["CPU", text(format!("{}, {} cores", sys.cpu_brand.as_str(), sys.cpu_cores.unwrap_or(1)))], - elem_row!["Total memory", text(format!("{}GiB", sys.memory_total / (1024 * 1024 * 1024)))], - elem_row!["Graphics backend and adapter", text(format!("{}, {}", sys.graphics_backend, sys.graphics_adapter))], - ]], - _ => None, - } - ] - .into_iter().flatten() - .fold(Column::new(), |row, section| row.push(section))); - - scrollable(content) - .id(self.scroll_id.clone()) - .direction(Direction::Vertical( - scrollable::Properties::new().scroller_width(0.0).width(0.0), - )) - .on_scroll(Message::Scrolled) - .into() - } -} diff --git a/amadeus/src/components/config/theme.rs b/amadeus/src/components/config/theme.rs deleted file mode 100644 index 7bb7d035..00000000 --- a/amadeus/src/components/config/theme.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::style_sheet::sizes::*; -use iced::{theme::Theme, widget::toggler, Element}; -use lektor_utils::either; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, Deserialize, Serialize)] -#[serde(rename_all = "lowercase")] -pub enum Message { - #[default] - Dark, - Light, -} - -#[derive(Default, Clone, Copy)] -pub struct State; - -impl From<&Theme> for Message { - fn from(value: &Theme) -> Self { - match value { - Theme::Light => Message::Light, - Theme::Dark | Theme::Custom(_) => Message::Dark, - } - } -} - -impl From<Theme> for Message { - fn from(value: Theme) -> Self { - match value { - Theme::Light => Message::Light, - Theme::Dark | Theme::Custom(_) => Message::Dark, - } - } -} - -impl From<Message> for Theme { - fn from(value: Message) -> Self { - match value { - Message::Dark => Theme::Dark, - Message::Light => Theme::Light, - } - } -} - -impl State { - pub fn view(&self, theme: &Message) -> Element<'_, Message> { - toggler( - Some("Dark theme ".into()), - Message::Dark.eq(theme), - |is_dark| either!(is_dark => Message::Dark; Message::Light), - ) - .spacing(15) - .text_size(SIZE_FONT_NORMAL) - .size(SIZE_FONT_NORMAL) - .into() - } -} diff --git a/amadeus/src/components/kara.rs b/amadeus/src/components/kara.rs deleted file mode 100644 index ba7fe321..00000000 --- a/amadeus/src/components/kara.rs +++ /dev/null @@ -1,122 +0,0 @@ -use crate::style_sheet::{ - sizes::*, Color, ContextMenuStyleSheet, RoundBadgeStyleSheet, RoundButtonStyleSheet, -}; -use iced::{ - widget::{button, column, container, horizontal_space, row, text, text::LineHeight, Row}, - Alignment, Element, Length, -}; -use iced_aw::{badge, ContextMenu}; -use lektor_payloads::{KId, Kara, Priority}; -use std::sync::Arc; - -/// The state of the kara line viewer, just a pointer to the kara. -pub struct State(u16, Message); - -/// We take in input only the kara. -pub type Message = Arc<Kara>; - -/// We want to do something about the kara. Note that the last argument is always the id of the -/// kara that was cliked. -#[derive(Debug, Clone)] -pub enum Request { - OpenInformation(KId), - AddToQueue(Priority, KId), - RemoveFromQueue(KId), - AddToPlaylist(KId), - RemoveFromPlaylist(KId), - RemoveFromHistory(KId), -} - -impl State { - /// Create a new kara view for the title bar. - pub fn new_title_bar(value: Message) -> Self { - Self(SIZE_FONT_MOAR, value) - } - - /// Create a new kara view for a list. - pub fn new_list_item(value: Message) -> Self { - Self(SIZE_FONT_NORMAL, value) - } - - /// Get the [KId] of the kara represented by this view. - pub fn kid(&self) -> &KId { - &self.1.as_ref().id - } - - /// Render the kara, if clicked we return the [lektor_payloads::KId] of the kara to open a - /// modal to view more informations about the kara. - pub fn view(&self) -> Element<'_, Request> { - let mut langs: Vec<_> = self.1.language.iter().collect(); - langs.sort(); - - macro_rules! badge { - ($str: expr) => { - badge(text(format!(" {} ", $str)).size(self.0)) - .align_x(Alignment::Center) - .align_y(Alignment::Center) - .padding(5) - .style(iced_aw::BadgeStyles::Custom(Box::new( - RoundBadgeStyleSheet::from(Color::Primary), - ))) - }; - } - - let init_infos = [badge!(self.1.song_origin.as_str())] - .into_iter() - .chain(langs.into_iter().map(|lang| badge!(lang.as_ref()))) - .fold(Row::new(), |row, elem| row.push(elem)); - let with_song = [ - horizontal_space(5).into(), - text(format!("{} / {}", self.1.song_source, self.1.song_title)) - .size(self.0) - .line_height(LineHeight::Relative(2.0)) - .into(), - horizontal_space(5).into(), - ] - .into_iter() - .fold(init_infos, |row, elem: Element<'_, Request>| row.push(elem)); - let kara = with_song - .push(badge!(self.1.song_type.as_str())) - .width(Length::Fill) - .spacing(3) - .align_items(Alignment::Center); - - macro_rules! button { - ($fill: ident, $what: ident: $text: literal => $msg: ident $(($($msg_args: expr),+))?) => { - button(text($text).size(self.0)) - .width(Length::$fill) - .style(iced::theme::Button::Custom(Box::new( - RoundButtonStyleSheet::from(Color::$what), - ))) - .on_press(Request::$msg($($($msg_args)+,)? self.1.id.clone())) - }; - } - - ContextMenu::new(kara, || { - container( - column![ - button!(Fill, Primary: " Informations" => OpenInformation), - row![ - button!(Fill, Success: " Enqueue" => AddToQueue(1.into())), - button!(Shrink, Success: " 2 " => AddToQueue(2.into())), - button!(Shrink, Success: " 3 " => AddToQueue(3.into())), - button!(Shrink, Success: " 4 " => AddToQueue(4.into())), - ] - .spacing(2), - button!(Fill, Success: " Add to playlist" => AddToPlaylist), - button!(Fill, Danger: " Remove from queue" => RemoveFromQueue), - button!(Fill, Danger: " Remove from history" => RemoveFromHistory), - button!(Fill, Danger: " Remove from playlist" => RemoveFromPlaylist), - ] - .padding(3) - .spacing(3) - .max_width(200), - ) - .style(iced::theme::Container::Custom(Box::new( - ContextMenuStyleSheet, - ))) - .into() - }) - .into() - } -} diff --git a/amadeus/src/components/karalist.rs b/amadeus/src/components/karalist.rs deleted file mode 100644 index c9eaa98e..00000000 --- a/amadeus/src/components/karalist.rs +++ /dev/null @@ -1,65 +0,0 @@ -use crate::components::kara; -use iced::{ - widget::{column, horizontal_rule}, - Element, Length, -}; -use lektor_payloads::{KId, Kara}; -use std::sync::Arc; - -#[derive(Default)] -pub struct State(Vec<kara::State>); - -/// Message to update the content of the list. -#[derive(Debug, Clone)] -pub enum Message { - /// Change the content of the list by a new vector. - Reload(Vec<Arc<Kara>>), - - /// Clear the list. - Clear, - - /// Remove an element from the list by its Id. - RemoveId(KId), - - /// Add an element in the list at the end of it. - Add(Arc<Kara>), -} - -/// Requests comming for individual kara interactions or from the list itself (load after/load -/// before the main content). -#[derive(Debug, Clone)] -pub struct Request(pub kara::Request); - -impl State { - /// Returns whever the list is empty or not. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// Get the numbers of karas in this list. - pub fn len(&self) -> usize { - self.0.len() - } - - pub fn update(&mut self, message: Message) { - match message { - Message::Clear => self.0.clear(), - Message::RemoveId(kid) => self.0.retain(|kara| kid.ne(kara.kid())), - Message::Add(kara) => self.0.push(kara::State::new_list_item(kara)), - Message::Reload(karas) => { - self.0 = karas.into_iter().map(kara::State::new_list_item).collect() - } - } - } - - pub fn view(&self) -> Element<'_, Request> { - self.0 - .iter() - .fold(column![], |c, kara| { - c.push(kara.view().map(Request)).push(horizontal_rule(2)) - }) - .width(Length::Fill) - .spacing(2) - .into() - } -} diff --git a/amadeus/src/components/mainpanel/history.rs b/amadeus/src/components/mainpanel/history.rs deleted file mode 100644 index a43022d1..00000000 --- a/amadeus/src/components/mainpanel/history.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::components::{self, icon, karalist, tip}; -use iced::{widget::row, Command, Element}; -use lektor_payloads::{KId, Kara}; -use std::sync::Arc; - -#[derive(Default)] -pub struct State(karalist::State); - -#[derive(Debug, Clone)] -pub enum Message { - /// Clear the history. - Clear, - - /// Set the new history content to what is contained in the vector, we will do a diff to avoid - /// doing to much things. - Reload(Vec<Arc<Kara>>), - - // Remove a single kara from the history. - RemoveKara(KId), -} - -#[derive(Debug, Clone)] -pub enum Request { - /// Clear the history. - Clear, - - /// Refresh the history, need to make a call to lektord. - Refresh, - - /// Inner history event, wrapper around the [karalist::Request] - Inner(karalist::Request), -} - -impl State { - pub fn update(&mut self, message: Message) -> Command<Request> { - match message { - Message::Clear => { - self.0.update(karalist::Message::Clear); - Command::none() - } - Message::Reload(karas) => { - self.0.update(karalist::Message::Reload(karas)); - Command::none() - } - Message::RemoveKara(id) => { - self.0.update(karalist::Message::RemoveId(id)); - Command::none() - } - } - } - - pub fn view_actions(&self) -> Element<'_, Request> { - row![ - tip!(icon!(SIZE_FONT_MEDIUM | ArrowClockwise -> Request::Refresh) => Bottom | "Refresh the history"), - tip!(icon!(SIZE_FONT_MEDIUM | Trash -> Request::Clear) => Bottom | "Clear the history"), - ].into() - } - - pub fn view(&self) -> Element<'_, Request> { - if self.0.is_empty() { - components::loading() - } else { - self.0.view().map(Request::Inner) - } - } -} diff --git a/amadeus/src/components/mainpanel/mod.rs b/amadeus/src/components/mainpanel/mod.rs deleted file mode 100644 index e894b964..00000000 --- a/amadeus/src/components/mainpanel/mod.rs +++ /dev/null @@ -1,172 +0,0 @@ -//! The main panel will display the content of a playlist, the queue, the history, etc. - -pub mod history; -pub mod playlists; -pub mod queue; -pub mod search; - -use crate::style_sheet::sizes::*; -use iced::{ - widget::{horizontal_space, row, text, Row}, - Command, Element, Length, -}; -use search::filter; -use std::sync::Arc; - -/// The state of the component. We simply dispatch messages to the different panels. -#[derive(Default)] -pub struct State { - queue: queue::State, - search: search::State, - history: history::State, - playlists: playlists::State, - show: Show, -} - -/// What to show in the main panel. -#[derive(Debug, Clone, Default)] -pub enum Show { - #[default] - Queue, - History, - Database, - Playlist(Arc<str>), -} - -/// Messages going into the main panel, responses of requests. -#[derive(Debug, Clone)] -pub enum Message { - History(history::Message), - Queue(queue::Message), - Search(search::Message), - Playlists(playlists::Message), - Show(Show), -} - -/// Request more information to display. Those things requires to communicate whith the server. -#[derive(Debug, Clone)] -pub enum Request { - Queue(queue::Request), - History(history::Request), - Search(search::Request), - Playlists(playlists::Request), -} - -impl std::fmt::Display for Show { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Show::Queue => f.write_str("Queue"), - Show::History => f.write_str("History"), - Show::Database => f.write_str("Search Database"), - Show::Playlist(plt) => write!(f, "Playlist {plt}"), - } - } -} - -impl From<history::Message> for Message { - fn from(value: history::Message) -> Self { - Self::History(value) - } -} - -impl From<history::Request> for Request { - fn from(value: history::Request) -> Self { - Self::History(value) - } -} - -impl From<queue::Message> for Message { - fn from(value: queue::Message) -> Self { - Self::Queue(value) - } -} - -impl From<queue::Request> for Request { - fn from(value: queue::Request) -> Self { - Self::Queue(value) - } -} - -impl From<search::Message> for Message { - fn from(value: search::Message) -> Self { - Self::Search(value) - } -} - -impl From<search::Request> for Request { - fn from(value: search::Request) -> Self { - Self::Search(value) - } -} - -impl From<playlists::Message> for Message { - fn from(value: playlists::Message) -> Self { - Self::Playlists(value) - } -} - -impl From<playlists::Request> for Request { - fn from(value: playlists::Request) -> Self { - Self::Playlists(value) - } -} - -impl State { - /// Get the search filters - pub fn search_filters(&self) -> impl IntoIterator<Item = &filter::StateVariant> { - self.search.filters() - } - - /// Update the internal state and send commands. - pub fn update(&mut self, message: Message) -> Command<Request> { - match message { - Message::Queue(msg) => self.queue.update(msg).map(Request::Queue), - Message::Search(msg) => self.search.update(msg).map(Request::Search), - Message::History(msg) => self.history.update(msg).map(Request::History), - Message::Playlists(msg) => self.playlists.update(msg).map(Request::Playlists), - Message::Show(show) => match show { - Show::Playlist(ref name) => { - let name = name.clone(); - self.show = show; - self.playlists - .update(playlists::Message::ShowPlaylist(name)) - .map(Request::from) - } - show => { - self.show = show; - Command::none() - } - }, - } - } - - /// View the name of the main panel. As we don't return anny message, we add a generic type to - /// adapt this function to any message type. - pub fn view_title<'a, T: 'a>(&'a self) -> Row<'a, T> { - row![ - text(&self.show).size(SIZE_FONT_TITLE), - horizontal_space(Length::Fill), - ] - } - - /// View some global actions, to be displayed above the main panel, along side the main panel - /// name. Function called by the Amadeus application. - pub fn view_actions(&self) -> Element<'_, Request> { - match self.show { - Show::Queue => self.queue.view_actions().map(Request::from), - Show::History => self.history.view_actions().map(Request::from), - Show::Database => self.search.view_actions().map(Request::from), - Show::Playlist(ref plt) => self.playlists.view_actions(plt).map(Request::from), - } - } - - /// Render the state of the component. - pub fn view(&self) -> Element<'_, Request> { - match self.show { - Show::Queue => self.queue.view().map(Request::from), - Show::History => self.history.view().map(Request::from), - Show::Database => self.search.view().map(Request::from), - Show::Playlist(ref plt) => self.playlists.view(plt).map(Request::from), - } - } -} diff --git a/amadeus/src/components/mainpanel/playlists.rs b/amadeus/src/components/mainpanel/playlists.rs deleted file mode 100644 index 9c02680e..00000000 --- a/amadeus/src/components/mainpanel/playlists.rs +++ /dev/null @@ -1,224 +0,0 @@ -use crate::{ - components::{self, icon, karalist, tip}, - style_sheet::sizes::SIZE_FONT_MOAR, -}; -use chrono::TimeZone; -use hashbrown::HashMap; -use iced::{ - widget::{column, horizontal_rule, row, text, vertical_space}, - Command, Element, -}; -use lektor_payloads::{KId, Kara, PlaylistInfo}; -use lektor_utils::log; -use std::sync::Arc; - -#[derive(Default)] -pub struct State { - playlists: HashMap<Arc<str>, (Option<PlaylistInfo>, karalist::State)>, - to_show: Option<Arc<str>>, -} - -#[derive(Debug, Clone)] -pub enum Message { - /// Reload the content of a playlist. - Reload(Arc<str>, Vec<Arc<Kara>>), - - /// Clear all playlist data. - Clear, - - /// Update informations about a playlist. - UpdatePlaylistInfos(Arc<str>, PlaylistInfo), - - /// Delete a playlist by its name. - DeletePlaylist(Arc<str>), - - /// Keep playlists, delete all the others. - KeepPlaylists(Vec<Arc<str>>), - - /// Remove a kara from a playlist by its Id. - RemoveKaraFromPlaylist(Arc<str>, KId), - - /// Add a kara to a playlist. - AddKaraToPlaylist(Arc<str>, Arc<Kara>), - - /// Message to notify which playlist to show. - ShowPlaylist(Arc<str>), -} - -#[derive(Debug, Clone)] -pub enum Request { - /// Delete a playlist. - Delete(Arc<str>), - - /// Refresh a playlist. - Refresh(Arc<str>), - - /// Add a [KId] to a playlist. - AddTo(Arc<str>, KId), - - /// Remove a [KId] from a playlist. - RemoveFrom(Arc<str>, KId), - - /// Inner playlist event, wrapper around the [karalist::Request] - Inner(Arc<str>, karalist::Request), - - /// Message to tell Amadeus to change view. This can be the consequence of deleting a playlist. - ChangeView, -} - -impl State { - /// Get a mut view to a playlist info, content, etc. If the playlist was not found returns - /// [None], otherwise returns [Some]. - fn get_mut_or_insert( - &mut self, - name: Arc<str>, - ) -> &mut (Option<PlaylistInfo>, karalist::State) { - self.playlists.entry(name).or_default() - } - - /// Get a const view to a playlist info, content, etc. If the playlist was not found returns - /// [None], otherwise returns [Some]. - fn get( - &self, - name: impl AsRef<str>, - ) -> Option<(&Arc<str>, Option<&PlaylistInfo>, &karalist::State)> { - self.playlists - .get_key_value(name.as_ref()) - .map(|(k, (v1, v2))| (k, v1.as_ref(), v2)) - } - - /// Remove playlists from the list of playlists, returns whever the playlist was found and was - /// removed from the vector. - fn remove(&mut self, names: &[impl AsRef<str>]) -> bool { - !names - .iter() - .any(|name| self.playlists.remove(name.as_ref()).is_none()) - } - - /// Keep playlists from the list of playlists. - fn keep(&mut self, names: &[impl AsRef<str>]) { - self.playlists - .retain(|k, _| names.iter().any(|name| name.as_ref().eq(k.as_ref()))); - } - - /// Returns whever the container contains the asked playlist or not. - fn contains(&self, name: impl AsRef<str>) -> bool { - self.playlists.contains_key(name.as_ref()) - } - - pub fn update(&mut self, message: Message) -> Command<Request> { - match message { - Message::KeepPlaylists(plts) => { - self.keep(&plts); - match self.to_show { - Some(ref show) => (!self.contains(show)) - .then(|| Command::perform(async {}, |_| Request::ChangeView)) - .unwrap_or_else(Command::none), - _ => Command::none(), - } - } - - Message::Clear => { - // If the playlist view was cleared, then the view was already changed, so we don't - // send the change view request. - self.playlists.clear(); - self.to_show.take(); - Command::none() - } - - Message::Reload(plt, karas) => { - let (.., plt) = self.get_mut_or_insert(plt); - plt.update(karalist::Message::Reload(karas)); - Command::none() - } - - Message::UpdatePlaylistInfos(plt, infos) => { - let (old, _) = self.get_mut_or_insert(plt); - *old = Some(infos); - Command::none() - } - - Message::RemoveKaraFromPlaylist(plt, id) => { - let (.., plt) = self.get_mut_or_insert(plt); - plt.update(karalist::Message::RemoveId(id)); - Command::none() - } - - Message::DeletePlaylist(plt) => { - if !self.remove(&[plt.as_ref()]) { - log::error!("failed do delete playlist {plt}"); - Command::none() - } else if self - .to_show - .as_ref() - .map(|show| show.as_ref().eq(plt.as_ref())) - .unwrap_or_default() - { - Command::perform(async {}, |_| Request::ChangeView) - } else { - Command::none() - } - } - - Message::AddKaraToPlaylist(plt, kara) => { - let (.., plt) = self.get_mut_or_insert(plt); - plt.update(karalist::Message::Add(kara)); - Command::none() - } - - Message::ShowPlaylist(name) => { - if self.contains(&name) { - self.to_show = Some(name); - Command::none() - } else { - log::info!("asked to show playlist {name}, but it wasn't found"); - Command::perform(async {}, |_| Request::Refresh(name)) - } - } - } - } - - pub fn view_actions(&self, plt: &Arc<str>) -> Element<'_, Request> { - row![ - tip!(icon!(SIZE_FONT_MEDIUM | ArrowClockwise -> Request::Refresh(plt.clone())) => Bottom | "Refresh the playlist"), - tip!(icon!(SIZE_FONT_MEDIUM | FolderX -> Request::Delete(plt.clone())) => Bottom | "Delete the playlist"), - ].into() - } - - pub fn view(&self, plt: &Arc<str>) -> Element<'_, Request> { - self.get(plt) - .map(|(plt, infos, content)| { - infos - .map(|infos| { - let PlaylistInfo { user, .. } = infos; - let mut column = user - .as_ref() - .map(|user| { - column![text(format!("Created by: {user}")).size(SIZE_FONT_MOAR)] - }) - .unwrap_or_default(); - if let Some(time) = - chrono::Local.timestamp_opt(infos.created_at, 0).latest() - { - let time = time.format("%Y-%m-%d %H:%M:%S"); - column = column - .push(vertical_space(4)) - .push(text(format!("Created at: {time}"))); - }; - if let Some(time) = - chrono::Local.timestamp_opt(infos.updated_at, 0).latest() - { - let time = time.format("%Y-%m-%d %H:%M:%S"); - column = column - .push(vertical_space(4)) - .push(text(format!("Updated at: {time}"))); - }; - column.push(vertical_space(10)).push(horizontal_rule(4)) - }) - .unwrap_or_default() - .push(content.view().map(|req| Request::Inner(plt.clone(), req))) - .into() - }) - .unwrap_or(components::loading()) - } -} diff --git a/amadeus/src/components/mainpanel/queue.rs b/amadeus/src/components/mainpanel/queue.rs deleted file mode 100644 index 8b8ef734..00000000 --- a/amadeus/src/components/mainpanel/queue.rs +++ /dev/null @@ -1,162 +0,0 @@ -use crate::{ - components::{icon, karalist, tip}, - style_sheet::sizes::*, -}; -use iced::{ - widget::{ - column, horizontal_rule, horizontal_space, row, text, text::LineHeight, vertical_space, - }, - Command, Element, Length, -}; -use lektor_payloads::{KId, Kara, Priority, PRIORITY_LENGTH, PRIORITY_VALUES}; -use lektor_utils::either; -use std::sync::Arc; - -/// The state of the queue. -#[derive(Default)] -pub struct State([(bool, karalist::State); PRIORITY_LENGTH]); - -/// Messages for the queue. -#[derive(Debug, Clone)] -pub enum Message { - Clear, - ClearLevel(Priority), - Reload(Vec<(Priority, Arc<Kara>)>), - ReloadLevel(Priority, Vec<Arc<Kara>>), - RemoveKara(KId), - AddKara(Priority, Arc<Kara>), - ToggleLevel(Priority, Option<bool>), -} - -/// Request something. -#[derive(Debug, Clone)] -pub enum Request { - /// Inner queue event, wrapper around the [karalist::Request] - InnerQueueEvent(karalist::Request), - - /// Clear the queue. - ClearQueue, - - /// Refresh the queue. - RefreshQueue, - - /// Refresh a level of the queue. - RefreshQueueLevel(Priority), - - /// Clear the queue. - ClearQueueLevel(Priority), - - /// Shuffle the level of the queue. - ShuffleQueueLevel(Priority), - - /// Shuffle the queue. - ShuffleQueue, - - /// Toggle the queue level - ToggleQueueLevel(Priority, Option<bool>), -} - -impl State { - pub fn update(&mut self, message: Message) -> Command<Request> { - match message { - Message::Clear => { - self.0.iter_mut().for_each(|(show, lvl)| { - *show = false; - lvl.update(karalist::Message::Clear); - }); - Command::none() - } - Message::ClearLevel(prio) => { - let (show, level) = &mut self.0[prio.index()]; - *show = false; - level.update(karalist::Message::Clear); - Command::none() - } - Message::ReloadLevel(prio, karas) => { - let (show, level) = &mut self.0[prio.index()]; - level.update(karalist::Message::Reload(karas)); - *show = !level.is_empty(); - Command::none() - } - Message::Reload(karas) => { - let get_prio = |prio: Priority| { - move |(p, kara): &(_, Arc<Kara>)| prio.eq(p).then_some(kara.clone()) - }; - Command::batch(PRIORITY_VALUES.iter().copied().map(|prio| { - let karas = karas.iter().filter_map(get_prio(prio)); - self.update(Message::ReloadLevel(prio, karas.collect())) - })) - } - Message::AddKara(prio, kara) => { - self.0[prio.index()].1.update(karalist::Message::Add(kara)); - Command::none() - } - Message::RemoveKara(id) => { - self.0.iter_mut().for_each(|(show, lvl)| { - lvl.update(karalist::Message::RemoveId(id.clone())); - *show = !lvl.is_empty(); - }); - Command::none() - } - Message::ToggleLevel(prio, show) => { - let flag = &mut self.0[prio.index()].0; - match show { - Some(show) => *flag = show, - None => *flag = !*flag, - } - Command::none() - } - } - } - - pub fn view_actions(&self) -> Element<'_, Request> { - row![ - tip!(icon!(SIZE_FONT_MEDIUM | ArrowClockwise -> Request::RefreshQueue) => Bottom | "Refresh the queue"), - tip!(icon!(SIZE_FONT_MEDIUM | Shuffle -> Request::ShuffleQueue) => Bottom | "Shuffle the queue"), - tip!(icon!(SIZE_FONT_MEDIUM | Trash -> Request::ClearQueue) => Bottom | "Clear the queue"), - ].into() - } - - pub fn view(&self) -> Element<'_, Request> { - macro_rules! view_queue_level { - ($level: ident: $lvl: expr) => {{ - const SHUFFLE_TIP: &str = concat!("Shuffle the ", stringify!($level), " level of the queue"); - const CLEAR_TIP: &str = concat!("Clear the ", stringify!($level), " level of the queue"); - const COLLAPSE_TIP: &str = concat!("Collapse the ", stringify!($level), " level of the queue"); - const EXPAND_TIP: &str = concat!("Expand the ", stringify!($level), " level of the queue"); - const RELOAD_TIP: &str = concat!("Refresh the ", stringify!($level), " level of the queue"); - const LEVEL: Priority = Priority::$level; - column![ - row![ - text(format!("# {} kara(s) {}", $lvl.1.len(), stringify!($level))) - .size(SIZE_FONT_MOAR) - .line_height(LineHeight::Relative(2.0)), - horizontal_space(Length::Fill), - either!($lvl.0 - => tip!(icon!(SIZE_FONT_MOAR | ArrowsCollapse -> Request::ToggleQueueLevel(LEVEL, Some(false))) => Bottom | COLLAPSE_TIP) - ; tip!(icon!(SIZE_FONT_MOAR | ArrowsExpand -> Request::ToggleQueueLevel(LEVEL, Some(true))) => Bottom | EXPAND_TIP) - ), - tip!(icon!(SIZE_FONT_MOAR | ArrowClockwise -> Request::RefreshQueueLevel(LEVEL)) => Bottom | RELOAD_TIP), - tip!(icon!(SIZE_FONT_MOAR | Shuffle -> Request::ShuffleQueueLevel(LEVEL)) => Bottom | SHUFFLE_TIP), - tip!(icon!(SIZE_FONT_MOAR | Trash -> Request::ClearQueueLevel(LEVEL)) => Bottom | CLEAR_TIP), - ], - vertical_space(2), - horizontal_rule(2), - vertical_space(2), - either!($lvl.0 => $lvl.1.view().map(|req| Request::InnerQueueEvent(req)); vertical_space(10).into()) - ].spacing(0) - }}; - } - - [ - view_queue_level!(Enforce: self.0[Priority::Enforce.index()]), - view_queue_level!(Insert: self.0[Priority::Insert.index()]), - view_queue_level!(Suggest: self.0[Priority::Suggest.index()]), - view_queue_level!(Add: self.0[Priority::Add.index()]), - ] - .into_iter() - .fold(column![], |row, level| row.push(level)) - .spacing(20) - .into() - } -} diff --git a/amadeus/src/components/mainpanel/search/filter.rs b/amadeus/src/components/mainpanel/search/filter.rs deleted file mode 100644 index 794bb0c5..00000000 --- a/amadeus/src/components/mainpanel/search/filter.rs +++ /dev/null @@ -1,81 +0,0 @@ -use crate::{ - components::raw_icon, - style_sheet::{sizes::*, Color, HoverButtonStyleSheet}, -}; -use iced::{ - widget::{button, row, text}, - Element, -}; -use lektor_payloads::KaraBy; -use std::sync::atomic::{AtomicU64, Ordering}; - -static ID: AtomicU64 = AtomicU64::new(1); - -/// The state of a filter. All the fiters are displayed in the search bar alongside the input -/// field that is used to create a filter. -/// -/// When cliked, the filter will be deleted. -#[derive(Debug)] -pub struct State(pub(super) u64, pub(super) StateVariant); - -#[derive(Debug)] -pub struct StateVariant(KaraBy); - -impl From<String> for State { - fn from(value: String) -> Self { - Self(ID.fetch_add(1, Ordering::SeqCst), StateVariant::from(value)) - } -} - -impl From<String> for StateVariant { - fn from(value: String) -> Self { - Self(KaraBy::from(value)) - } -} - -impl State { - pub fn view(&self) -> Element<'_, u64> { - let content: Element<'_, u64> = match &self.1 .0 { - KaraBy::Query(query) => text(query).size(SIZE_FONT_NORMAL).into(), - - KaraBy::Id(id) => text(format!("#{id}")).size(SIZE_FONT_NORMAL).into(), - - KaraBy::SongType(ty) => text(ty.as_str()).size(SIZE_FONT_NORMAL).into(), - KaraBy::SongOrigin(ori) => text(ori.as_str()).size(SIZE_FONT_NORMAL).into(), - - KaraBy::Tag((tag, None)) => row![ - raw_icon!(SIZE_FONT_NORMAL | Tag), - text(tag).size(SIZE_FONT_NORMAL) - ] - .spacing(10) - .into(), - KaraBy::Tag((tag, Some(value))) => row![ - raw_icon!(SIZE_FONT_NORMAL | TagFill), - text(format!("{tag} : {value}")).size(SIZE_FONT_NORMAL) - ] - .spacing(10) - .into(), - - KaraBy::Author(author) => row![ - raw_icon!(SIZE_FONT_NORMAL | Person), - text(author).size(SIZE_FONT_NORMAL) - ] - .spacing(10) - .into(), - - KaraBy::Playlist(playlist) => row![ - raw_icon!(SIZE_FONT_NORMAL | Folder), - text(playlist).size(SIZE_FONT_NORMAL) - ] - .spacing(10) - .into(), - }; - - button(content) - .style(iced::theme::Button::Custom(Box::new( - HoverButtonStyleSheet::from((Color::Primary, Color::Danger)), - ))) - .on_press(self.0) - .into() - } -} diff --git a/amadeus/src/components/mainpanel/search/mod.rs b/amadeus/src/components/mainpanel/search/mod.rs deleted file mode 100644 index 16a2e187..00000000 --- a/amadeus/src/components/mainpanel/search/mod.rs +++ /dev/null @@ -1,133 +0,0 @@ -//! Module used to implement the search panel and utilities. - -pub mod filter; - -use crate::{ - components::{self, icon, kara, karalist, tip}, - style_sheet::sizes::SIZE_FONT_NORMAL, -}; -use iced::{ - widget::{column, row, text_input, text_input::Id}, - Command, Element, Length, -}; -use iced_aw::wrap_horizontal; -use lektor_utils::either; - -pub struct State { - input: String, - input_id: Id, - filters: Vec<filter::State>, - results: karalist::State, -} - -#[derive(Debug, Clone)] -pub enum Message { - /// Remove all filters. - ClearFilters, - - /// Remove a specific filter. - RemoveFilter(u64), - - /// Update the input bar with a new string. - UpdateInput(String), - - /// Create a filter from the input content and clears the input line. - CreateFilter, -} - -#[derive(Debug, Clone)] -pub enum Request { - /// Update lektord from repos. - UpdateFromRepo, - - /// Do the search. - Search, - - /// A message from the karalist. - Kara(kara::Request), - - /// Returns back a message. - Message(Message), -} - -impl Default for State { - fn default() -> Self { - Self { - input: Default::default(), - input_id: Id::unique(), - filters: Default::default(), - results: Default::default(), - } - } -} - -impl State { - pub fn filters(&self) -> impl IntoIterator<Item = &filter::StateVariant> { - self.filters.iter().map(|filter::State(_, filter)| filter) - } - - pub fn update(&mut self, message: Message) -> Command<Request> { - match message { - Message::CreateFilter => { - self.filters - .push(filter::State::from(std::mem::take(&mut self.input))); - Command::batch([ - Command::perform(async {}, |_| Request::Search), - iced::widget::text_input::focus(self.input_id.clone()), - ]) - } - Message::ClearFilters => { - self.filters.clear(); - self.results.update(karalist::Message::Clear); - iced::widget::text_input::focus(self.input_id.clone()) - } - Message::UpdateInput(input) => { - self.input = input; - Command::none() - } - Message::RemoveFilter(id) => { - self.filters.retain(|filter::State(fid, _)| id.ne(fid)); - self.results.update(karalist::Message::Clear); - Command::batch([ - Command::perform(async {}, |_| Request::Search), - iced::widget::text_input::focus(self.input_id.clone()), - ]) - } - } - } - - pub fn view_actions(&self) -> Element<'_, Request> { - row![ - tip!(icon!(SIZE_FONT_MEDIUM | Search -> Request::Search) => Bottom | "Perform a search with the current filters"), - tip!(icon!(SIZE_FONT_MEDIUM | CloudDownload -> Request::UpdateFromRepo) => Bottom | "Update lektord database from repo"), - tip!(icon!(SIZE_FONT_MEDIUM | Trash -> Request::Message(Message::ClearFilters)) => Bottom | "Clear all the search filters"), - ].into() - } - - pub fn view(&self) -> Element<'_, Request> { - let input_line = text_input("@author | tag:value | #playlist | OP | anime", &self.input) - .id(self.input_id.clone()) - .size(SIZE_FONT_NORMAL) - .width(Length::Fill) - .on_input(|txt| Request::Message(Message::UpdateInput(txt))) - .on_submit(Request::Message(Message::CreateFilter)); - - let filter_list = self - .filters - .iter() - .fold(wrap_horizontal![], |container, filter| { - let filter = filter - .view() - .map(|id| Request::Message(Message::RemoveFilter(id))); - container.push(filter) - }) - .spacing(10.0); - - let results = either!(self.results.is_empty() - => components::loading() - ; self.results.view().map(|karalist::Request(req)| Request::Kara(req)) - ); - - column![input_line, filter_list, results].spacing(10).into() - } -} diff --git a/amadeus/src/components/mod.rs b/amadeus/src/components/mod.rs deleted file mode 100644 index b216e6a8..00000000 --- a/amadeus/src/components/mod.rs +++ /dev/null @@ -1,67 +0,0 @@ -pub mod bottombar; -pub mod config; -pub mod kara; -pub mod karalist; -pub mod mainpanel; -pub mod modal; -pub mod sidebar; -pub mod topbar; - -pub fn loading<'a, T: 'a>() -> iced::Element<'a, T> { - iced::widget::container(iced_aw::Spinner::new()) - .width(iced::Length::Fill) - .height(iced::Length::Fill) - .center_x() - .center_y() - .into() -} - -pub fn file_size<'a, T: 'a>(bytes: usize) -> iced::Element<'a, T> { - let kilos = bytes.div_euclid(1024); - let megas = kilos.div_euclid(1024); - iced::widget::text(if megas > 0 { - format!("File Size: {megas}MiB") - } else if kilos > 0 { - format!("File Size: {kilos}KiB") - } else { - format!("File Size: {bytes}B") - }) - .into() -} - -macro_rules! tip { - ($inner: expr => $position: ident | $tip: expr) => { - iced::widget::tooltip($inner, $tip, iced::widget::tooltip::Position::$position) - .snap_within_viewport(true) - .gap($crate::style_sheet::sizes::SIZE_FONT_SMALL) - .size($crate::style_sheet::sizes::SIZE_FONT_NORMAL) - .style(iced::theme::Container::Custom(Box::new( - $crate::style_sheet::ToolTipStyleSheet, - ))) - }; -} -pub(crate) use tip; - -macro_rules! raw_icon { - ($size: ident | $icon: ident) => {{ - let icon = format!( - " {} ", - iced_aw::graphics::icons::icon_to_char(iced_aw::graphics::icons::Icon::$icon) - ); - iced::widget::text(icon) - .font(iced_aw::graphics::icons::ICON_FONT) - .size($crate::style_sheet::sizes::$size) - }}; -} -pub(crate) use raw_icon; - -macro_rules! icon { - ($size: ident | $icon: ident -> $msg: expr) => {{ - iced::widget::button($crate::components::raw_icon!($size | $icon)) - .style(iced::theme::Button::Custom(Box::new( - $crate::style_sheet::PlainButtonStyleSheet, - ))) - .on_press($msg) - }}; -} -pub(crate) use icon; diff --git a/amadeus/src/components/modal/helper.rs b/amadeus/src/components/modal/helper.rs deleted file mode 100644 index e4ebac79..00000000 --- a/amadeus/src/components/modal/helper.rs +++ /dev/null @@ -1,302 +0,0 @@ -use iced::{ - advanced::{ - layout::{self, Layout}, - overlay, renderer, - widget::{self, Widget}, - {self, Clipboard, Shell}, - }, - alignment::Alignment, - event, mouse, {BorderRadius, Color, Element, Event, Length, Point, Rectangle, Size}, -}; - -/// A widget that centers a modal element over some base element -pub struct Modal<'a, Message, Renderer> { - base: Element<'a, Message, Renderer>, - modal: Element<'a, Message, Renderer>, - on_blur: Option<Message>, -} - -impl<'a, Message, Renderer> Modal<'a, Message, Renderer> { - /// Returns a new [`Modal`] - pub fn new( - base: impl Into<Element<'a, Message, Renderer>>, - modal: impl Into<Element<'a, Message, Renderer>>, - ) -> Self { - Self { - base: base.into(), - modal: modal.into(), - on_blur: None, - } - } - - /// Sets the message that will be produces when the background - /// of the [`Modal`] is pressed - pub fn on_blur(self, on_blur: Message) -> Self { - Self { - on_blur: Some(on_blur), - ..self - } - } -} - -impl<'a, Message, Renderer> Widget<Message, Renderer> for Modal<'a, Message, Renderer> -where - Renderer: advanced::Renderer, - Message: Clone, -{ - fn children(&self) -> Vec<widget::Tree> { - vec![ - widget::Tree::new(&self.base), - widget::Tree::new(&self.modal), - ] - } - - fn diff(&self, tree: &mut widget::Tree) { - tree.diff_children(&[&self.base, &self.modal]); - } - - fn width(&self) -> Length { - self.base.as_widget().width() - } - - fn height(&self) -> Length { - self.base.as_widget().height() - } - - fn layout(&self, renderer: &Renderer, limits: &layout::Limits) -> layout::Node { - self.base.as_widget().layout(renderer, limits) - } - - fn on_event( - &mut self, - state: &mut widget::Tree, - event: Event, - layout: Layout<'_>, - cursor: mouse::Cursor, - renderer: &Renderer, - clipboard: &mut dyn Clipboard, - shell: &mut Shell<'_, Message>, - viewport: &Rectangle, - ) -> event::Status { - self.base.as_widget_mut().on_event( - &mut state.children[0], - event, - layout, - cursor, - renderer, - clipboard, - shell, - viewport, - ) - } - - fn draw( - &self, - state: &widget::Tree, - renderer: &mut Renderer, - theme: &<Renderer as advanced::Renderer>::Theme, - style: &renderer::Style, - layout: Layout<'_>, - cursor: mouse::Cursor, - viewport: &Rectangle, - ) { - self.base.as_widget().draw( - &state.children[0], - renderer, - theme, - style, - layout, - cursor, - viewport, - ); - } - - fn overlay<'b>( - &'b mut self, - state: &'b mut widget::Tree, - layout: Layout<'_>, - _renderer: &Renderer, - ) -> Option<overlay::Element<'b, Message, Renderer>> { - Some(overlay::Element::new( - layout.position(), - Box::new(Overlay { - content: &mut self.modal, - tree: &mut state.children[1], - size: layout.bounds().size(), - on_blur: self.on_blur.clone(), - }), - )) - } - - fn mouse_interaction( - &self, - state: &widget::Tree, - layout: Layout<'_>, - cursor: mouse::Cursor, - viewport: &Rectangle, - renderer: &Renderer, - ) -> mouse::Interaction { - self.base.as_widget().mouse_interaction( - &state.children[0], - layout, - cursor, - viewport, - renderer, - ) - } - - fn operate( - &self, - state: &mut widget::Tree, - layout: Layout<'_>, - renderer: &Renderer, - operation: &mut dyn widget::Operation<Message>, - ) { - self.base - .as_widget() - .operate(&mut state.children[0], layout, renderer, operation); - } -} - -struct Overlay<'a, 'b, Message, Renderer> { - content: &'b mut Element<'a, Message, Renderer>, - tree: &'b mut widget::Tree, - size: Size, - on_blur: Option<Message>, -} - -impl<'a, 'b, Message, Renderer> overlay::Overlay<Message, Renderer> - for Overlay<'a, 'b, Message, Renderer> -where - Renderer: advanced::Renderer, - Message: Clone, -{ - fn layout(&self, renderer: &Renderer, _bounds: Size, position: Point) -> layout::Node { - let limits = layout::Limits::new(Size::ZERO, self.size) - .width(Length::Fill) - .height(Length::Fill); - - let mut child = self.content.as_widget().layout(renderer, &limits); - - child.align(Alignment::Center, Alignment::Center, limits.max()); - - let mut node = layout::Node::with_children(self.size, vec![child]); - node.move_to(position); - - node - } - - fn on_event( - &mut self, - event: Event, - layout: Layout<'_>, - cursor: mouse::Cursor, - renderer: &Renderer, - clipboard: &mut dyn Clipboard, - shell: &mut Shell<'_, Message>, - ) -> event::Status { - let content_bounds = layout.children().next().unwrap().bounds(); - - if let Some(message) = self.on_blur.as_ref() { - if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) = &event { - if !cursor.is_over(content_bounds) { - shell.publish(message.clone()); - return event::Status::Captured; - } - } - } - - self.content.as_widget_mut().on_event( - self.tree, - event, - layout.children().next().unwrap(), - cursor, - renderer, - clipboard, - shell, - &layout.bounds(), - ) - } - - fn draw( - &self, - renderer: &mut Renderer, - theme: &Renderer::Theme, - style: &renderer::Style, - layout: Layout<'_>, - cursor: mouse::Cursor, - ) { - renderer.fill_quad( - renderer::Quad { - bounds: layout.bounds(), - border_radius: BorderRadius::default(), - border_width: 0.0, - border_color: Color::TRANSPARENT, - }, - Color { - a: 0.80, - ..Color::BLACK - }, - ); - - self.content.as_widget().draw( - self.tree, - renderer, - theme, - style, - layout.children().next().unwrap(), - cursor, - &layout.bounds(), - ); - } - - fn operate( - &mut self, - layout: Layout<'_>, - renderer: &Renderer, - operation: &mut dyn widget::Operation<Message>, - ) { - self.content.as_widget().operate( - self.tree, - layout.children().next().unwrap(), - renderer, - operation, - ); - } - - fn mouse_interaction( - &self, - layout: Layout<'_>, - cursor: mouse::Cursor, - viewport: &Rectangle, - renderer: &Renderer, - ) -> mouse::Interaction { - self.content.as_widget().mouse_interaction( - self.tree, - layout.children().next().unwrap(), - cursor, - viewport, - renderer, - ) - } - - fn overlay<'c>( - &'c mut self, - layout: Layout<'_>, - renderer: &Renderer, - ) -> Option<overlay::Element<'c, Message, Renderer>> { - self.content - .as_widget_mut() - .overlay(self.tree, layout.children().next().unwrap(), renderer) - } -} - -impl<'a, Message, Renderer> From<Modal<'a, Message, Renderer>> for Element<'a, Message, Renderer> -where - Renderer: 'a + advanced::Renderer, - Message: 'a + Clone, -{ - fn from(modal: Modal<'a, Message, Renderer>) -> Self { - Element::new(modal) - } -} diff --git a/amadeus/src/components/modal/karainfos.rs b/amadeus/src/components/modal/karainfos.rs deleted file mode 100644 index 889dae1e..00000000 --- a/amadeus/src/components/modal/karainfos.rs +++ /dev/null @@ -1,139 +0,0 @@ -use crate::{ - components::file_size, - style_sheet::{sizes::*, Color, RoundBadgeStyleSheet}, -}; -use chrono::TimeZone; -use iced::{ - widget::{column, container, horizontal_rule, text}, - Element, -}; -use iced_aw::native::{badge, wrap_horizontal}; -use lektor_payloads::Kara; -use std::sync::Arc; - -/// Display the specified kara in a modal. -pub struct State(Arc<Kara>); - -impl State { - /// A new modal for the specific kara. - pub fn new(kara: Arc<Kara>) -> Self { - Self(kara) - } - - /// View all the badges for this view, we just place all the informations in badges of - /// different colors. - fn view_badges(&self) -> impl IntoIterator<Item = Element<'_, ()>> { - let Kara { - kara_makers, - song_type, - song_origin, - language, - tags, - .. - } = self.0.as_ref(); - - let mut language: Vec<_> = language.iter().collect(); - language.sort(); - let language = language.into_iter().map(|lang| { - badge(text(lang.as_ref()).size(SIZE_FONT_MOAR)) - .style(iced_aw::style::badge::BadgeStyles::Custom(Box::new( - RoundBadgeStyleSheet::from(Color::Success), - ))) - .into() - }); - - let mut kara_makers: Vec<_> = kara_makers.iter().collect(); - kara_makers.sort(); - let kara_makers = kara_makers.into_iter().map(|author| { - badge(text(author.as_ref()).size(SIZE_FONT_MOAR)) - .style(iced_aw::style::badge::BadgeStyles::Custom(Box::new( - RoundBadgeStyleSheet::from(Color::Danger), - ))) - .into() - }); - - let mut tags: Vec<_> = tags.into_iter().collect(); - tags.sort(); - let tags = tags.into_iter().map(|(key, values)| { - if values.is_empty() { - badge(text(key.as_ref()).size(SIZE_FONT_MOAR)).style( - iced_aw::style::badge::BadgeStyles::Custom(Box::new( - RoundBadgeStyleSheet::from(Color::Primary), - )), - ) - } else { - badge(text(format!("{key}: {}", values.join(", "))).size(SIZE_FONT_MOAR)).style( - iced_aw::style::badge::BadgeStyles::Custom(Box::new( - RoundBadgeStyleSheet::from(Color::Primary), - )), - ) - } - .into() - }); - - [ - badge(text(song_origin.as_str()).size(SIZE_FONT_MOAR)) - .style(iced_aw::style::badge::BadgeStyles::Custom(Box::new( - RoundBadgeStyleSheet::from(Color::Success), - ))) - .into(), - badge(text(song_type.as_str()).size(SIZE_FONT_MOAR)) - .style(iced_aw::style::badge::BadgeStyles::Custom(Box::new( - RoundBadgeStyleSheet::from(Color::Success), - ))) - .into(), - ] - .into_iter() - .chain(language) - .chain(kara_makers) - .chain(tags) - } - - /// View the modal, no action available for now. - pub fn view(&self) -> Element<'_, ()> { - let Kara { - song_title, - song_source, - timestamps: ts, - .. - } = self.0.as_ref(); - - let mut column = column![text(format!( - "Remote Name: {}", - self.0.remote.remote_name() - ))]; - - if let Some(time) = chrono::Local.timestamp_opt(ts.created_at, 0).latest() { - let time = time.format("%Y-%m-%d %H:%M:%S"); - column = column.push(text(format!("Created at: {time}"))); - }; - - if let Some(time) = chrono::Local.timestamp_opt(ts.updated_at, 0).latest() { - let time = time.format("%Y-%m-%d %H:%M:%S"); - column = column.push(text(format!("Last Modified at: {time}"))); - }; - - let aux_infos = match self.0.kara_status { - lektor_payloads::KaraStatus::Virtual => column, - lektor_payloads::KaraStatus::Physical { filesize, hash } => column - .push(file_size(filesize as usize)) - .push(text(format!("File Hash: {hash}"))), - }; - - container( - column![ - column![text("Kara Information"), horizontal_rule(4)].spacing(5), - column![ - text(format!("Source: {song_source}")).size(SIZE_FONT_TITLE), - text(format!("Title: {song_title}")).size(SIZE_FONT_TITLE), - wrap_horizontal(self.view_badges().into_iter().collect()).spacing(5.0), - ] - .spacing(5), - horizontal_rule(4), - aux_infos.spacing(5) - ] - .spacing(10), - ) - .into() - } -} diff --git a/amadeus/src/components/modal/mod.rs b/amadeus/src/components/modal/mod.rs deleted file mode 100644 index c74e5163..00000000 --- a/amadeus/src/components/modal/mod.rs +++ /dev/null @@ -1,50 +0,0 @@ -mod helper; -pub mod karainfos; -pub mod playlistselect; - -pub use helper::Modal; - -use crate::message::Message; -use lektor_payloads::{KId, Kara}; -use std::sync::Arc; - -/// Callback used when the user has selected a playlist from the modal. -#[derive(Clone)] -pub struct OnPlaylistSelectCallback(pub Arc<dyn (Fn(Arc<str>) -> Message) + Send + Sync>); - -impl OnPlaylistSelectCallback { - pub fn new(callback: impl (Fn(Arc<str>) -> Message) + Send + Sync + 'static) -> Self { - Self(Arc::new(callback)) - } -} - -impl std::fmt::Debug for OnPlaylistSelectCallback { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let ptr = self.0.as_ref() as *const _; - f.debug_tuple("OnPlaylistSelectCallback") - .field(&ptr) - .finish() - } -} - -/// Chich modal to display. -pub enum WhichModal { - KaraInfo(karainfos::State), - PlaylistSelect(playlistselect::State, OnPlaylistSelectCallback), -} - -/// We want to show something in a modal. -#[derive(Debug, Clone)] -pub enum ShowModal { - /// Displays informations about a kara. - KaraInfoById(KId), - - /// Displays informations about a kara. - KaraInfo(Arc<Kara>), - - /// Choose a playlist from these choices. - ChoosePlaylist(Vec<Arc<str>>, OnPlaylistSelectCallback), - - /// Choose a playlist from these choices, expect from the current one. - ChoosePlaylistExpect(Arc<str>, Vec<Arc<str>>, OnPlaylistSelectCallback), -} diff --git a/amadeus/src/components/modal/playlistselect.rs b/amadeus/src/components/modal/playlistselect.rs deleted file mode 100644 index 9c206376..00000000 --- a/amadeus/src/components/modal/playlistselect.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::style_sheet::{sizes::*, RoundButtonStyleSheet}; -use iced::{ - alignment::{Horizontal, Vertical}, - widget::{button, column, container, horizontal_rule, text, text::LineHeight}, - Element, Length, -}; -use std::sync::Arc; - -/// Display a choice of playlists. -pub struct State(Vec<Arc<str>>); - -/// We specify which playlist the user choose. -pub type Message = Arc<str>; - -impl State { - /// The choices. - pub fn new(choices: Vec<Arc<str>>) -> Self { - Self(choices) - } - - /// The choices, without a specific playlist. - pub fn new_without(choices: Vec<Arc<str>>, without: Arc<str>) -> Self { - Self::new( - choices - .into_iter() - .filter(|name| name.as_ref().ne(without.as_ref())) - .collect(), - ) - } - - pub fn view(&self) -> Element<'_, Message> { - let content = if self.0.is_empty() { - Into::<Element<'_, _>>::into(text("No playlist to select from").size(SIZE_FONT_TITLE)) - } else { - self.0 - .iter() - .map(|name| { - button( - text(name.as_ref()) - .size(SIZE_FONT_MOAR) - .width(Length::Fill) - .line_height(LineHeight::Relative(2.0)) - .vertical_alignment(Vertical::Center) - .horizontal_alignment(Horizontal::Center), - ) - .style(iced::theme::Button::Custom( - Box::<RoundButtonStyleSheet>::default(), - )) - .width(Length::Fill) - .on_press(name.clone()) - }) - .fold(column![], |col, elem| col.push(elem)) - .spacing(5) - .into() - }; - - container( - column![ - column![text("Playlist Selection"), horizontal_rule(4)].spacing(5), - content - ] - .spacing(10), - ) - .into() - } -} diff --git a/amadeus/src/components/sidebar.rs b/amadeus/src/components/sidebar.rs deleted file mode 100644 index 42e18b75..00000000 --- a/amadeus/src/components/sidebar.rs +++ /dev/null @@ -1,150 +0,0 @@ -//! The side bar will permit to to select between the queue, the history and which playlist to view -//! in the main panel. - -use crate::{ - components::tip, - style_sheet::{sizes::*, BarStyleSheet, PlainButtonStyleSheet}, -}; -use iced::{ - widget::{ - button, column, container, horizontal_rule, scrollable, - scrollable::{Direction, Viewport}, - text, vertical_space, Column, Space, - }, - Command, Element, Length, -}; -use lektor_payloads::PlaylistName; -use lektor_utils::log; -use std::sync::Arc; - -pub struct State { - playlists: Vec<Arc<str>>, - - scroll_id: scrollable::Id, - current_scroll_offset: scrollable::RelativeOffset, -} - -#[derive(Debug, Clone)] -pub enum Request { - ShowQueue, - ShowHistory, - ShowDatabase, - ShowSettings, - ShowPlaylist(Arc<str>), - RefreshPlaylists, - Scrolled(Viewport), -} - -#[derive(Debug, Clone)] -pub enum Message { - /// The list of playlists was scrolled. - Scrolled(Viewport), - - /// Need to update the list of playlists. - Playlists(Vec<Arc<str>>), - - /// Clear all the playlists... - ClearPlaylists, - - /// Delete a specific playlist. - DeletePlaylist(Arc<str>), -} - -impl FromIterator<PlaylistName> for Message { - fn from_iter<T: IntoIterator<Item = PlaylistName>>(iter: T) -> Self { - Self::Playlists(iter.into_iter().map(|plt| plt.as_ref().into()).collect()) - } -} - -impl Default for State { - fn default() -> Self { - Self { - playlists: Default::default(), - scroll_id: scrollable::Id::unique(), - current_scroll_offset: scrollable::RelativeOffset::START, - } - } -} - -impl State { - pub fn update<T>(&mut self, message: Message) -> Command<T> { - match message { - Message::Scrolled(viewport) => { - self.current_scroll_offset = viewport.relative_offset(); - Command::none() - } - - Message::ClearPlaylists => { - self.playlists.clear(); - Command::none() - } - - Message::Playlists(playlists) => { - let _ = std::mem::replace(&mut self.playlists, playlists); - Command::none() - } - - Message::DeletePlaylist(plt) => { - let count = self.playlists.len(); - self.playlists.retain(|name| name.as_ref().ne(plt.as_ref())); - if count == self.playlists.len() { - log::error!("failed to delete playlist {plt} from the sidebar"); - } - Command::none() - } - } - } - - pub fn playlist_list(&self) -> &[Arc<str>] { - &self.playlists - } - - pub fn view(&self) -> Element<'_, Request> { - macro_rules! text_icon { - ($size: ident; $icon: ident: $name: expr => $msg: expr) => {{ - let icon = text(String::from(iced_aw::graphics::icons::icon_to_char( - iced_aw::graphics::icons::Icon::$icon, - ))) - .size($size) - .font(iced_aw::graphics::icons::ICON_FONT); - button(iced::widget::row![ - icon, - text(format!(" {}", $name)).size($size) - ]) - .style(iced::theme::Button::Custom(Box::new(PlainButtonStyleSheet))) - .padding(5.0) - .on_press($msg) - }}; - } - - container( - column![ - vertical_space(5), - text_icon!(SIZE_FONT_TITLE; MusicNoteList: "Queue" => Request::ShowQueue), - text_icon!(SIZE_FONT_TITLE; ClockHistory: "History" => Request::ShowHistory), - text_icon!(SIZE_FONT_TITLE; Search: "Search" => Request::ShowDatabase), - Space::with_height(Length::Fixed(20.0)), - tip!(text_icon!(SIZE_FONT_TITLE; Folder: "Playlists" => Request::RefreshPlaylists) => Right | "Click to refresh playlist list"), - scrollable(self.playlists.iter().fold(Column::new(), - |plts, plt| plts.push(text_icon!(SIZE_FONT_MEDIUM; Asterisk: plt.as_ref() => Request::ShowPlaylist(plt.clone()))) - ).height(Length::Fill).padding([0, 0, 0, 30])) - .id(self.scroll_id.clone()) - .direction(Direction::Vertical( - scrollable::Properties::new() - .scroller_width(0.0) - .width(0.0), - )) - .on_scroll(Request::Scrolled) - .height(Length::Fill), - vertical_space(5), - horizontal_rule(4), - vertical_space(5), - text_icon!(SIZE_FONT_MEDIUM; Gear: "Settings" => Request::ShowSettings), - vertical_space(5), - ] - .padding([0, 10]), - ) - .style(iced::theme::Container::Custom(Box::new(BarStyleSheet))) - .into() - } -} diff --git a/amadeus/src/components/topbar.rs b/amadeus/src/components/topbar.rs deleted file mode 100644 index 7e1c72d2..00000000 --- a/amadeus/src/components/topbar.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! The top bar will present some controls to control the playback, the settings, open the search -//! modal and display basic informations about the playing kara. - -use crate::{ - components::{kara, tip}, - style_sheet::{sizes::*, BarStyleSheet, SquareButtonStyleSheet}, -}; -use iced::{ - alignment::Vertical, - widget::{button, container, horizontal_space, text, Row}, - Element, Length, -}; -use lektor_payloads::{Kara, PlayState}; -use std::sync::Arc; - -#[derive(Default)] -pub struct State { - playback: PlayState, - current: Option<kara::State>, -} - -#[derive(Debug, Clone)] -pub enum Request { - ChangePlayback(PlayState), - PlayNext, - PlayPrevious, - Kara(kara::Request), -} - -#[derive(Debug, Clone)] -pub enum Message { - ChangedPlayback(PlayState), - ChangedKara(Option<Arc<Kara>>), -} - -impl State { - pub fn update(&mut self, message: Message) { - match message { - Message::ChangedPlayback(state) => self.playback = state, - Message::ChangedKara(kara) => self.current = kara.map(kara::State::new_title_bar), - } - } - - pub fn view(&self) -> Element<'_, Request> { - macro_rules! icon { - ($icon: ident, $tip: literal -> $msg: expr) => {{ - let icon = format!( - " {} ", - iced_aw::graphics::icons::icon_to_char(iced_aw::graphics::icons::Icon::$icon) - ); - tip!(button(text(icon).font(iced_aw::graphics::icons::ICON_FONT).size(SIZE_FONT_TITLE)) - .style(iced::theme::Button::Custom(Box::<SquareButtonStyleSheet>::default())) - .on_press($msg) => Bottom | $tip) - }}; - } - let (disp_play, disp_pauz, disp_stop) = ( - self.playback != PlayState::Play, - self.playback == PlayState::Play, - self.playback != PlayState::Stop, - ); - - // Controls. - let row = [ - Some(icon!(ChevronDoubleLeft, "Previous" -> Request::PlayPrevious)), - disp_play.then(|| icon!(Play, "Play" -> Request::ChangePlayback(PlayState::Play))), - disp_pauz.then(|| icon!(Pause, "Pause" -> Request::ChangePlayback(PlayState::Pause))), - disp_stop.then(|| icon!(Stop, "Stop" -> Request::ChangePlayback(PlayState::Stop))), - Some(icon!(ChevronDoubleRight, "Next" -> Request::PlayNext)), - ] - .into_iter() - .flatten() - .fold(Row::new(), |row, element| row.push(element)); - - // Current, we let it overflow on the right. - let row = [ - Some(horizontal_space(10).into()), - self.current.as_ref().map(|k| k.view().map(Request::Kara)), - ] - .into_iter() - .flatten() - .fold(row, |row, element| row.push(element)) - .align_items(Vertical::Center.into()); - - // Build the row. - container(row) - .align_y(Vertical::Center) - .style(iced::theme::Container::Custom(Box::new(BarStyleSheet))) - .width(Length::Fill) - .height(Length::Fixed(40.0)) - .into() - } -} diff --git a/amadeus/src/config.rs b/amadeus/src/config.rs new file mode 100644 index 00000000..96a85567 --- /dev/null +++ b/amadeus/src/config.rs @@ -0,0 +1,150 @@ +use cosmic::cosmic_config::{self, cosmic_config_derive::CosmicConfigEntry, CosmicConfigEntry}; +use derive_more::{AsRef, Display, From, Into}; +use lektor_lib::ConnectConfig; +use lektor_utils::config::{SocketScheme, UserConfig}; +use serde::{de::Visitor, Deserialize, Serialize}; +use std::{ + net::{IpAddr, Ipv4Addr, SocketAddr}, + time::Duration, +}; + +#[derive(Debug, Clone, CosmicConfigEntry, Eq, PartialEq)] +#[version = 1] +pub struct Config { + log_level: LogLevel, + + host: Host, + scheme: SocketScheme, + user: UserConfig, + retry_interval: Duration, + + kurisu_token: Option<String>, +} + +impl Config { + pub fn log_level(&self) -> log::Level { + self.log_level.into() + } + + pub fn host(&self) -> (SocketScheme, SocketAddr) { + (self.scheme, self.host.into()) + } + + pub fn user(&self) -> &UserConfig { + &self.user + } + + pub fn kurisu_token(&self) -> Option<&str> { + self.kurisu_token.as_deref() + } + + pub fn get_connect_config(&self) -> ConnectConfig { + ConnectConfig { + host: self.host.into(), + user: self.user.user.as_str().into(), + token: self.user.token.as_str().into(), + retry: self.retry_interval, + scheme: self.scheme, + } + } +} + +impl Default for Config { + fn default() -> Self { + Self { + retry_interval: Duration::from_secs(10), + kurisu_token: None, + + log_level: Default::default(), + host: Default::default(), + scheme: Default::default(), + user: Default::default(), + } + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Display, From, Into, Serialize, Deserialize)] +#[display("{socket_addr}")] +#[repr(transparent)] +pub struct Host { + socket_addr: SocketAddr, +} + +impl Default for Host { + fn default() -> Self { + Self::from(SocketAddr::new( + IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), + 6600, + )) + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Display, Into)] +#[display("{_0}")] +#[repr(transparent)] +pub struct LogLevel(log::Level); + +pub static LOG_LEVELS: &[LogLevel] = &[ + LogLevel(log::Level::Warn), + LogLevel(log::Level::Info), + LogLevel(log::Level::Debug), + LogLevel(log::Level::Trace), +]; + +impl AsRef<str> for LogLevel { + fn as_ref(&self) -> &str { + self.0.as_str() + } +} + +impl From<log::Level> for LogLevel { + fn from(value: log::Level) -> Self { + match value { + log::Level::Error | log::Level::Warn => Self(log::Level::Warn), + log::Level::Info | log::Level::Debug | log::Level::Trace => Self(value), + } + } +} + +impl From<&log::Level> for LogLevel { + fn from(value: &log::Level) -> Self { + (*value).into() + } +} + +impl<'de> Deserialize<'de> for LogLevel { + fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { + struct StrVisitor; + impl<'de> Visitor<'de> for StrVisitor { + type Value = log::Level; + + fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "expected a string: 'warn', 'info', 'debug', 'trace'") + } + + fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> { + match v { + "trace" | "TRACE" => Ok(log::Level::Trace), + "debug" | "DEBUG" => Ok(log::Level::Debug), + "info" | "INFO" => Ok(log::Level::Info), + "warning" | "WARNING" | "warn" | "WARN" => Ok(log::Level::Warn), + _ => Err(E::custom(format!("unknown log level: '{v}'"))), + } + } + } + + Ok(LogLevel(deserializer.deserialize_str(StrVisitor)?)) + } +} + +impl Serialize for LogLevel { + fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { + serializer.serialize_str(self.as_ref()) + } +} + +impl Default for LogLevel { + fn default() -> Self { + Self(log::Level::Warn) + } +} diff --git a/amadeus/src/i18n.rs b/amadeus/src/i18n.rs new file mode 100644 index 00000000..4769970a --- /dev/null +++ b/amadeus/src/i18n.rs @@ -0,0 +1,45 @@ +//! Provides localization support for this crate. + +use i18n_embed::{ + fluent::{fluent_language_loader, FluentLanguageLoader}, + unic_langid::LanguageIdentifier, + DefaultLocalizer, LanguageLoader, Localizer, +}; +use std::sync::LazyLock; + +/// Applies the requested language(s) to requested translations from the `fl!()` macro. +pub fn init(requested_languages: &[LanguageIdentifier]) { + if let Err(why) = localizer().select(requested_languages) { + log::error!("error while loading fluent localizations: {why}"); + } +} + +// Get the `Localizer` to be used for localizing this library. +#[must_use] +pub fn localizer() -> Box<dyn Localizer> { + Box::from(DefaultLocalizer::new(&*LANGUAGE_LOADER, &Localizations)) +} + +#[derive(rust_embed::RustEmbed)] +#[folder = "i18n/"] +struct Localizations; + +pub static LANGUAGE_LOADER: LazyLock<FluentLanguageLoader> = LazyLock::new(|| { + let loader: FluentLanguageLoader = fluent_language_loader!(); + loader + .load_fallback_language(&Localizations) + .expect("Error while loading fallback language"); + loader +}); + +/// Request a localized string by ID from the i18n/ directory. +#[macro_export] +macro_rules! fl { + ($message_id:literal) => {{ + i18n_embed_fl::fl!($crate::i18n::LANGUAGE_LOADER, $message_id) + }}; + + ($message_id:literal, $($args:expr),*) => {{ + i18n_embed_fl::fl!($crate::i18n::LANGUAGE_LOADER, $message_id, $($args), *) + }}; +} diff --git a/amadeus/src/icons.rs b/amadeus/src/icons.rs new file mode 100644 index 00000000..733cbcfc --- /dev/null +++ b/amadeus/src/icons.rs @@ -0,0 +1,58 @@ +//! Custom icons used, picked from: https://fontawesome.com. The license can be found here: +//! https://fontawesome.com/license/free. Copyright 2024 Fonticons, Inc. + +#![allow(unused)] + +pub const LINK: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M579.8 267.7c56.5-56.5 56.5-148 0-204.5c-50-50-128.8-56.5-186.3-15.4l-1.6 1.1c-14.4 10.3-17.7 30.3-7.4 44.6s30.3 17.7 44.6 7.4l1.6-1.1c32.1-22.9 76-19.3 103.8 8.6c31.5 31.5 31.5 82.5 0 114L422.3 334.8c-31.5 31.5-82.5 31.5-114 0c-27.9-27.9-31.5-71.8-8.6-103.8l1.1-1.6c10.3-14.4 6.9-34.4-7.4-44.6s-34.4-6.9-44.6 7.4l-1.1 1.6C206.5 251.2 213 330 263 380c56.5 56.5 148 56.5 204.5 0L579.8 267.7zM60.2 244.3c-56.5 56.5-56.5 148 0 204.5c50 50 128.8 56.5 186.3 15.4l1.6-1.1c14.4-10.3 17.7-30.3 7.4-44.6s-30.3-17.7-44.6-7.4l-1.6 1.1c-32.1 22.9-76 19.3-103.8-8.6C74 372 74 321 105.5 289.5L217.7 177.2c31.5-31.5 82.5-31.5 114 0c27.9 27.9 31.5 71.8 8.6 103.9l-1.1 1.6c-10.3 14.4-6.9 34.4 7.4 44.6s34.4 6.9 44.6-7.4l1.1-1.6C433.5 260.8 427 182 377 132c-56.5-56.5-148-56.5-204.5 0L60.2 244.3z"/></svg>"#.as_bytes(); + +pub const MINUS: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M432 256c0 17.7-14.3 32-32 32L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l352 0c17.7 0 32 14.3 32 32z"/></svg>"#.as_bytes(); + +pub const PLUS: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M256 80c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 144L48 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l144 0 0 144c0 17.7 14.3 32 32 32s32-14.3 32-32l0-144 144 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-144 0 0-144z"/></svg>"#.as_bytes(); + +pub const HISTORY: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9L0 168c0 13.3 10.7 24 24 24l110.1 0c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24l0 104c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65 0-94.1c0-13.3-10.7-24-24-24z"/></svg>"#.as_bytes(); + +pub const BARCODES: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M24 32C10.7 32 0 42.7 0 56L0 456c0 13.3 10.7 24 24 24l16 0c13.3 0 24-10.7 24-24L64 56c0-13.3-10.7-24-24-24L24 32zm88 0c-8.8 0-16 7.2-16 16l0 416c0 8.8 7.2 16 16 16s16-7.2 16-16l0-416c0-8.8-7.2-16-16-16zm72 0c-13.3 0-24 10.7-24 24l0 400c0 13.3 10.7 24 24 24l16 0c13.3 0 24-10.7 24-24l0-400c0-13.3-10.7-24-24-24l-16 0zm96 0c-13.3 0-24 10.7-24 24l0 400c0 13.3 10.7 24 24 24l16 0c13.3 0 24-10.7 24-24l0-400c0-13.3-10.7-24-24-24l-16 0zM448 56l0 400c0 13.3 10.7 24 24 24l16 0c13.3 0 24-10.7 24-24l0-400c0-13.3-10.7-24-24-24l-16 0c-13.3 0-24 10.7-24 24zm-64-8l0 416c0 8.8 7.2 16 16 16s16-7.2 16-16l0-416c0-8.8-7.2-16-16-16s-16 7.2-16 16z"/></svg>"#.as_bytes(); + +pub const WEB: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M352 256c0 22.2-1.2 43.6-3.3 64l-185.3 0c-2.2-20.4-3.3-41.8-3.3-64s1.2-43.6 3.3-64l185.3 0c2.2 20.4 3.3 41.8 3.3 64zm28.8-64l123.1 0c5.3 20.5 8.1 41.9 8.1 64s-2.8 43.5-8.1 64l-123.1 0c2.1-20.6 3.2-42 3.2-64s-1.1-43.4-3.2-64zm112.6-32l-116.7 0c-10-63.9-29.8-117.4-55.3-151.6c78.3 20.7 142 77.5 171.9 151.6zm-149.1 0l-176.6 0c6.1-36.4 15.5-68.6 27-94.7c10.5-23.6 22.2-40.7 33.5-51.5C239.4 3.2 248.7 0 256 0s16.6 3.2 27.8 13.8c11.3 10.8 23 27.9 33.5 51.5c11.6 26 20.9 58.2 27 94.7zm-209 0L18.6 160C48.6 85.9 112.2 29.1 190.6 8.4C165.1 42.6 145.3 96.1 135.3 160zM8.1 192l123.1 0c-2.1 20.6-3.2 42-3.2 64s1.1 43.4 3.2 64L8.1 320C2.8 299.5 0 278.1 0 256s2.8-43.5 8.1-64zM194.7 446.6c-11.6-26-20.9-58.2-27-94.6l176.6 0c-6.1 36.4-15.5 68.6-27 94.6c-10.5 23.6-22.2 40.7-33.5 51.5C272.6 508.8 263.3 512 256 512s-16.6-3.2-27.8-13.8c-11.3-10.8-23-27.9-33.5-51.5zM135.3 352c10 63.9 29.8 117.4 55.3 151.6C112.2 482.9 48.6 426.1 18.6 352l116.7 0zm358.1 0c-30 74.1-93.6 130.9-171.9 151.6c25.5-34.2 45.2-87.7 55.3-151.6l116.7 0z"/></svg>"#.as_bytes(); + +pub const USER: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M370.7 96.1C346.1 39.5 289.7 0 224 0S101.9 39.5 77.3 96.1C60.9 97.5 48 111.2 48 128l0 64c0 16.8 12.9 30.5 29.3 31.9C101.9 280.5 158.3 320 224 320s122.1-39.5 146.7-96.1c16.4-1.4 29.3-15.1 29.3-31.9l0-64c0-16.8-12.9-30.5-29.3-31.9zM336 144l0 16c0 53-43 96-96 96l-32 0c-53 0-96-43-96-96l0-16c0-26.5 21.5-48 48-48l128 0c26.5 0 48 21.5 48 48zM189.3 162.7l-6-21.2c-.9-3.3-3.9-5.5-7.3-5.5s-6.4 2.2-7.3 5.5l-6 21.2-21.2 6c-3.3 .9-5.5 3.9-5.5 7.3s2.2 6.4 5.5 7.3l21.2 6 6 21.2c.9 3.3 3.9 5.5 7.3 5.5s6.4-2.2 7.3-5.5l6-21.2 21.2-6c3.3-.9 5.5-3.9 5.5-7.3s-2.2-6.4-5.5-7.3l-21.2-6zM112.7 316.5C46.7 342.6 0 407 0 482.3C0 498.7 13.3 512 29.7 512l98.3 0 0-64c0-17.7 14.3-32 32-32l128 0c17.7 0 32 14.3 32 32l0 64 98.3 0c16.4 0 29.7-13.3 29.7-29.7c0-75.3-46.7-139.7-112.7-165.8C303.9 338.8 265.5 352 224 352s-79.9-13.2-111.3-35.5zM176 448c-8.8 0-16 7.2-16 16l0 48 32 0 0-48c0-8.8-7.2-16-16-16zm96 32a16 16 0 1 0 0-32 16 16 0 1 0 0 32z"/></svg>"#.as_bytes(); + +pub const GIT: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M439.6 236.1L244 40.5a28.9 28.9 0 0 0 -40.8 0l-40.7 40.6 51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.2 199v121.9c25.3 12.5 22.3 41.9 9.1 55a34.3 34.3 0 0 1 -48.6 0c-17.6-17.6-11.1-46.9 11.3-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1a28.9 28.9 0 0 0 0 40.8l195.6 195.6a28.9 28.9 0 0 0 40.8 0l194.7-194.7a28.9 28.9 0 0 0 0-40.8z"/></svg>"#.as_bytes(); + +pub const MENU: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M0 96C0 78.3 14.3 64 32 64l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 128C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 288c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32L32 448c-17.7 0-32-14.3-32-32s14.3-32 32-32l384 0c17.7 0 32 14.3 32 32z"/></svg>"#.as_bytes(); + +pub const FILTER: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M3.9 54.9C10.5 40.9 24.5 32 40 32l432 0c15.5 0 29.5 8.9 36.1 22.9s4.6 30.5-5.2 42.5L320 320.9 320 448c0 12.1-6.8 23.2-17.7 28.6s-23.8 4.3-33.5-3l-64-48c-8.1-6-12.8-15.5-12.8-25.6l0-79.1L9 97.3C-.7 85.4-2.8 68.8 3.9 54.9z"/></svg>"#.as_bytes(); + +pub const BUG: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M256 0c53 0 96 43 96 96l0 3.6c0 15.7-12.7 28.4-28.4 28.4l-135.1 0c-15.7 0-28.4-12.7-28.4-28.4l0-3.6c0-53 43-96 96-96zM41.4 105.4c12.5-12.5 32.8-12.5 45.3 0l64 64c.7 .7 1.3 1.4 1.9 2.1c14.2-7.3 30.4-11.4 47.5-11.4l112 0c17.1 0 33.2 4.1 47.5 11.4c.6-.7 1.2-1.4 1.9-2.1l64-64c12.5-12.5 32.8-12.5 45.3 0s12.5 32.8 0 45.3l-64 64c-.7 .7-1.4 1.3-2.1 1.9c6.2 12 10.1 25.3 11.1 39.5l64.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-64 0c0 24.6-5.5 47.8-15.4 68.6c2.2 1.3 4.2 2.9 6 4.8l64 64c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0l-63.1-63.1c-24.5 21.8-55.8 36.2-90.3 39.6L272 240c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 239.2c-34.5-3.4-65.8-17.8-90.3-39.6L86.6 502.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l64-64c1.9-1.9 3.9-3.4 6-4.8C101.5 367.8 96 344.6 96 320l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64.3 0c1.1-14.1 5-27.5 11.1-39.5c-.7-.6-1.4-1.2-2.1-1.9l-64-64c-12.5-12.5-12.5-32.8 0-45.3z"/></svg>"#.as_bytes(); + +pub const UNPIN: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L481.4 352c9.8-.4 18.9-5.3 24.6-13.3c6-8.3 7.7-19.1 4.4-28.8l-1-3c-13.8-41.5-42.8-74.8-79.5-94.7L418.5 64 448 64c17.7 0 32-14.3 32-32s-14.3-32-32-32L192 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l29.5 0-6.1 79.5L38.8 5.1zM324.9 352L177.1 235.6c-20.9 18.9-37.2 43.3-46.5 71.3l-1 3c-3.3 9.8-1.6 20.5 4.4 28.8s15.7 13.3 26 13.3l164.9 0zM288 384l0 96c0 17.7 14.3 32 32 32s32-14.3 32-32l0-96-64 0z"/></svg>"#.as_bytes(); + +pub const PIN: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M32 32C32 14.3 46.3 0 64 0L320 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-29.5 0 11.4 148.2c36.7 19.9 65.7 53.2 79.5 94.7l1 3c3.3 9.8 1.6 20.5-4.4 28.8s-15.7 13.3-26 13.3L32 352c-10.3 0-19.9-4.9-26-13.3s-7.7-19.1-4.4-28.8l1-3c13.8-41.5 42.8-74.8 79.5-94.7L93.5 64 64 64C46.3 64 32 49.7 32 32zM160 384l64 0 0 96c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-96z"/></svg>"#.as_bytes(); + +pub const SAVE: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-242.7c0-17-6.7-33.3-18.7-45.3L352 50.7C340 38.7 323.7 32 306.7 32L64 32zm0 96c0-17.7 14.3-32 32-32l192 0c17.7 0 32 14.3 32 32l0 64c0 17.7-14.3 32-32 32L96 224c-17.7 0-32-14.3-32-32l0-64zM224 288a64 64 0 1 1 0 128 64 64 0 1 1 0-128z"/></svg>"#.as_bytes(); + +pub const EDIT: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M368.4 18.3L312.7 74.1 437.9 199.3l55.7-55.7c21.9-21.9 21.9-57.3 0-79.2L447.6 18.3c-21.9-21.9-57.3-21.9-79.2 0zM288 94.6l-9.2 2.8L134.7 140.6c-19.9 6-35.7 21.2-42.3 41L3.8 445.8c-3.8 11.3-1 23.9 7.3 32.4L164.7 324.7c-3-6.3-4.7-13.3-4.7-20.7c0-26.5 21.5-48 48-48s48 21.5 48 48s-21.5 48-48 48c-7.4 0-14.4-1.7-20.7-4.7L33.7 500.9c8.6 8.3 21.1 11.2 32.4 7.3l264.3-88.6c19.7-6.6 35-22.4 41-42.3l43.2-144.1 2.7-9.2L288 94.6z"/></svg>"#.as_bytes(); + +pub const METEOR: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M493.7 .9L299.4 75.6l2.3-29.3c1-12.8-12.8-21.5-24-15.1L101.3 133.4C38.6 169.7 0 236.6 0 309C0 421.1 90.9 512 203 512c72.4 0 139.4-38.6 175.7-101.3L480.8 234.3c6.5-11.1-2.2-25-15.1-24l-29.3 2.3L511.1 18.3c.6-1.5 .9-3.2 .9-4.8C512 6 506 0 498.5 0c-1.7 0-3.3 .3-4.8 .9zM192 192a128 128 0 1 1 0 256 128 128 0 1 1 0-256zm0 96a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zm16 96a16 16 0 1 0 0-32 16 16 0 1 0 0 32z"/></svg>"#.as_bytes(); + +pub const SATELLITE: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M192 32c0-17.7 14.3-32 32-32C383.1 0 512 128.9 512 288c0 17.7-14.3 32-32 32s-32-14.3-32-32C448 164.3 347.7 64 224 64c-17.7 0-32-14.3-32-32zM60.6 220.6L164.7 324.7l28.4-28.4c-.7-2.6-1.1-5.4-1.1-8.3c0-17.7 14.3-32 32-32s32 14.3 32 32s-14.3 32-32 32c-2.9 0-5.6-.4-8.3-1.1l-28.4 28.4L291.4 451.4c14.5 14.5 11.8 38.8-7.3 46.3C260.5 506.9 234.9 512 208 512C93.1 512 0 418.9 0 304c0-26.9 5.1-52.5 14.4-76.1c7.5-19 31.8-21.8 46.3-7.3zM224 96c106 0 192 86 192 192c0 17.7-14.3 32-32 32s-32-14.3-32-32c0-70.7-57.3-128-128-128c-17.7 0-32-14.3-32-32s14.3-32 32-32z"/></svg>"#.as_bytes(); + +pub const HOME: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M575.8 255.5c0 18-15 32.1-32 32.1l-32 0 .7 160.2c0 2.7-.2 5.4-.5 8.1l0 16.2c0 22.1-17.9 40-40 40l-16 0c-1.1 0-2.2 0-3.3-.1c-1.4 .1-2.8 .1-4.2 .1L416 512l-24 0c-22.1 0-40-17.9-40-40l0-24 0-64c0-17.7-14.3-32-32-32l-64 0c-17.7 0-32 14.3-32 32l0 64 0 24c0 22.1-17.9 40-40 40l-24 0-31.9 0c-1.5 0-3-.1-4.5-.2c-1.2 .1-2.4 .2-3.6 .2l-16 0c-22.1 0-40-17.9-40-40l0-112c0-.9 0-1.9 .1-2.8l0-69.7-32 0c-18 0-32-14-32-32.1c0-9 3-17 10-24L266.4 8c7-7 15-8 22-8s15 2 21 7L564.8 231.5c8 7 12 15 11 24z"/></svg>"#.as_bytes(); + +pub const QUEUE: &[u8]= r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M24 56c0-13.3 10.7-24 24-24l32 0c13.3 0 24 10.7 24 24l0 120 16 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-80 0c-13.3 0-24-10.7-24-24s10.7-24 24-24l16 0 0-96-8 0C34.7 80 24 69.3 24 56zM86.7 341.2c-6.5-7.4-18.3-6.9-24 1.2L51.5 357.9c-7.7 10.8-22.7 13.3-33.5 5.6s-13.3-22.7-5.6-33.5l11.1-15.6c23.7-33.2 72.3-35.6 99.2-4.9c21.3 24.4 20.8 60.9-1.1 84.7L86.8 432l33.2 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-88 0c-9.5 0-18.2-5.6-22-14.4s-2.1-18.9 4.3-25.9l72-78c5.3-5.8 5.4-14.6 .3-20.5zM224 64l256 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-256 0c-17.7 0-32-14.3-32-32s14.3-32 32-32zm0 160l256 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-256 0c-17.7 0-32-14.3-32-32s14.3-32 32-32zm0 160l256 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-256 0c-17.7 0-32-14.3-32-32s14.3-32 32-32z"/></svg>"#.as_bytes(); + +pub const ARCHIVE: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M32 32l448 0c17.7 0 32 14.3 32 32l0 32c0 17.7-14.3 32-32 32L32 128C14.3 128 0 113.7 0 96L0 64C0 46.3 14.3 32 32 32zm0 128l448 0 0 256c0 35.3-28.7 64-64 64L96 480c-35.3 0-64-28.7-64-64l0-256zm128 80c0 8.8 7.2 16 16 16l160 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-160 0c-8.8 0-16 7.2-16 16z"/></svg>"#.as_bytes(); + +pub const SEARCH: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"/></svg>"#.as_bytes(); + +pub const PREVIOUS: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M459.5 440.6c9.5 7.9 22.8 9.7 34.1 4.4s18.4-16.6 18.4-29l0-320c0-12.4-7.2-23.7-18.4-29s-24.5-3.6-34.1 4.4L288 214.3l0 41.7 0 41.7L459.5 440.6zM256 352l0-96 0-128 0-32c0-12.4-7.2-23.7-18.4-29s-24.5-3.6-34.1 4.4l-192 160C4.2 237.5 0 246.5 0 256s4.2 18.5 11.5 24.6l192 160c9.5 7.9 22.8 9.7 34.1 4.4s18.4-16.6 18.4-29l0-64z"/></svg>"#.as_bytes(); + +pub const NEXT: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M52.5 440.6c-9.5 7.9-22.8 9.7-34.1 4.4S0 428.4 0 416L0 96C0 83.6 7.2 72.3 18.4 67s24.5-3.6 34.1 4.4L224 214.3l0 41.7 0 41.7L52.5 440.6zM256 352l0-96 0-128 0-32c0-12.4 7.2-23.7 18.4-29s24.5-3.6 34.1 4.4l192 160c7.3 6.1 11.5 15.1 11.5 24.6s-4.2 18.5-11.5 24.6l-192 160c-9.5 7.9-22.8 9.7-34.1 4.4s-18.4-16.6-18.4-29l0-64z"/></svg>"#.as_bytes(); + +pub const STOP: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M0 128C0 92.7 28.7 64 64 64H320c35.3 0 64 28.7 64 64V384c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V128z"/></svg>"#.as_bytes(); + +pub const SHUFFLE: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M403.8 34.4c12-5 25.7-2.2 34.9 6.9l64 64c6 6 9.4 14.1 9.4 22.6s-3.4 16.6-9.4 22.6l-64 64c-9.2 9.2-22.9 11.9-34.9 6.9s-19.8-16.6-19.8-29.6l0-32-32 0c-10.1 0-19.6 4.7-25.6 12.8L284 229.3 244 176l31.2-41.6C293.3 110.2 321.8 96 352 96l32 0 0-32c0-12.9 7.8-24.6 19.8-29.6zM164 282.7L204 336l-31.2 41.6C154.7 401.8 126.2 416 96 416l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64 0c10.1 0 19.6-4.7 25.6-12.8L164 282.7zm274.6 188c-9.2 9.2-22.9 11.9-34.9 6.9s-19.8-16.6-19.8-29.6l0-32-32 0c-30.2 0-58.7-14.2-76.8-38.4L121.6 172.8c-6-8.1-15.5-12.8-25.6-12.8l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64 0c30.2 0 58.7 14.2 76.8 38.4L326.4 339.2c6 8.1 15.5 12.8 25.6 12.8l32 0 0-32c0-12.9 7.8-24.6 19.8-29.6s25.7-2.2 34.9 6.9l64 64c6 6 9.4 14.1 9.4 22.6s-3.4 16.6-9.4 22.6l-64 64z"/></svg>"#.as_bytes(); + +pub const PLAY: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80L0 432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg>"#.as_bytes(); + +pub const PAUSE: &[u8] = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M48 64C21.5 64 0 85.5 0 112L0 400c0 26.5 21.5 48 48 48l32 0c26.5 0 48-21.5 48-48l0-288c0-26.5-21.5-48-48-48L48 64zm192 0c-26.5 0-48 21.5-48 48l0 288c0 26.5 21.5 48 48 48l32 0c26.5 0 48-21.5 48-48l0-288c0-26.5-21.5-48-48-48l-32 0z"/></svg>"#.as_bytes(); diff --git a/amadeus/src/links.rs b/amadeus/src/links.rs deleted file mode 100644 index 27e20f1a..00000000 --- a/amadeus/src/links.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! This file contains some usefull links, intended to be included in other crates to redirect the -//! user to some sites on some interactions. - -pub(crate) const LEKTORD_ISSUES_LINK: &str = "https://git.iiens.net/martin2018/lektor/-/issues"; -pub(crate) const LEKTORD_HOME_LINK: &str = "https://git.iiens.net/martin2018/lektor"; -pub(crate) const KURISU_TOKEN_LINK: &str = "https://kurisu.iiens.net/api/download.php?token"; diff --git a/amadeus/src/main.rs b/amadeus/src/main.rs index 948df8f3..efb28eaa 100644 --- a/amadeus/src/main.rs +++ b/amadeus/src/main.rs @@ -1,81 +1,36 @@ -//! The amadeus application. -//! -//! Use iced which is inspired by elm. All the component have a -//! state/update/view/message representation (which is inherited from elm). As such, appart from -//! the main application struct, all the componenent have the following base: -//! -//! ``` -//! use iced::{Command, Element}; -//! -//! /// The state of the component -//! #[derive(Default)] -//! pub struct State {} -//! -//! /// The messages going in and out of this component -//! #[derive(Debug, Copy, Clone)] -//! pub enum Message {} -//! -//! impl State { -//! /// Update the internal state and send commands. -//! pub fn update(&mut self, message: Message) -> Command<Message> { -//! todo!() -//! } -//! -//! /// Render the state of the component. -//! pub fn view(&self) -> Element<'_, Message> { -//! todo!() -//! } -//! } -//! ``` - mod app; -mod components; -mod links; -mod message; -mod store; -mod style_sheet; - -use crate::{app::Amadeus, components::config::AmadeusConfig}; -use anyhow::{Context, Result}; -use lektor_utils::*; +mod config; +mod i18n; +mod icons; +mod subscriptions; + +include!(concat!(env!("OUT_DIR"), "/amadeus_build_infos.rs")); + +use anyhow::Context as _; +use cosmic::cosmic_config::{self, CosmicConfigEntry as _}; +use lektor_utils::{appimage, logger}; + +fn main() -> anyhow::Result<()> { + let config = cosmic_config::Config::new(app::APP_ID, config::Config::VERSION).map(|ctx| { + match config::Config::get_entry(&ctx) + .inspect_err(|(errs, _)| errs.iter().for_each(|e| log::error!("config error: {e}"))) + { + Ok(config) | Err((_, config)) => (config, ctx), + } + })?; + + logger::Builder::default() + .level(config.0.log_level()) + .filter_targets([ + "iced", "wgpu", "cosmic", "naga", "sctk", "calloop", "reqwest", + ]) + .init() + .context("failed to init logger")?; -fn main() -> Result<()> { - logger::init(Some(log::Level::Debug)).expect("failed to install logger"); #[cfg(target_os = "linux")] appimage::detect_appimage()?; - let config = config::get_or_write_default_config::<AmadeusConfig>("amadeus") - .with_context(|| "failed to read or write the config file")?; - logger::level(config.log); - - let settings = iced::Settings { - id: Some("Amadeus".to_string()), - flags: config, - default_font: iced::font::Font::DEFAULT, - default_text_size: style_sheet::sizes::SIZE_FONT_NORMAL.into(), - antialiasing: false, - exit_on_close_request: false, - - window: iced::window::Settings { - icon: Some(iced::window::icon::from_file_data( - include_bytes!("../amadeus.png"), - Some(image::ImageFormat::Png), - )?), - - resizable: true, - transparent: false, - visible: true, - min_size: Some((900, 600)), - level: iced::window::Level::AlwaysOnTop, - position: iced::window::Position::Centered, - - // Wait for https://github.com/iced-rs/iced/pull/1542 to be merged - decorations: true, - - ..Default::default() - }, - }; - - <Amadeus as iced::Application>::run(settings)?; + i18n::init(&i18n_embed::DesktopLanguageRequester::requested_languages()); + cosmic::app::run::<app::AppModel>(cosmic::app::Settings::default(), config)?; Ok(()) } diff --git a/amadeus/src/message.rs b/amadeus/src/message.rs deleted file mode 100644 index 142cee24..00000000 --- a/amadeus/src/message.rs +++ /dev/null @@ -1,396 +0,0 @@ -use crate::components::{ - bottombar, config, kara, mainpanel, - mainpanel::{history, playlists, queue, search}, - modal::ShowModal, - sidebar, topbar, -}; -use iced::Command; -use lektor_payloads::{KId, Kara, PlayState, Priority}; -use lektor_utils::log; -use std::sync::Arc; - -/// What to display in the main panel. -#[derive(Debug, Clone)] -pub enum MainPanelDisplay { - /// Delegate to the main panel component to show something. - MainPanel(mainpanel::Show), - - /// Show the config. - Config, -} - -#[derive(Debug, Clone, Copy)] -pub enum PlaybackRequest { - ChangePlayback(PlayState), - TogglePlaybackState, - PlayNext, - PlayPrevious, -} - -#[derive(Debug, Clone)] -pub enum RefreshRequest { - Playlists, - Playlist(Arc<str>), - History, - Queue, - QueueLevel(Priority), -} - -/// The top level message enum in the application. Will wrap all the messages from its direct -/// componenet to re-dispatch them accordingly. -#[derive(Debug, Clone, Default)] -pub enum Message { - /// Nothing to see. - #[default] - None, - - /// We got a tick. - SmollTick(iced::time::Instant), - - /// We got another tick. - BigTick(iced::time::Instant), - - /// Open the issues link with firefox. - OpenLinkInBrowser(&'static str), - - /// The status of the connexion changed, either it went online ([true]) or offline ([false]). - ConnectionStatus(bool), - - /// Got the database epoch. Need to check if it changed and act accordingly. - DatabaseEpoch(u64), - - /// Shutdown lektord. - ShutdownLektord, - - /// Exit the application. - ExitApplication, - - /// Got a message from the config componenent, the config could be changed, or we try to get - /// informations on the server. - Config(config::Message), - - /// The config was loaded, can start rendering the application. - ConfigLoaded, - - /// Need to reconnect to the lektord instance. We need to flush the caches and reload things... - ReconnectToLektord, - - /// The current kara changed and we got the kara struct. - ChangedKara(Arc<Kara>), - - /// The current kara changed and we got the [KId] of the kara. - ChangedKaraId(KId), - - /// The playback changed. - ChangedPlayback(PlayState), - - /// Need to send a command to lektord. Depending on the command and the result we man get back - /// other events. - PlaybackRequest(PlaybackRequest), - - /// Event about the duration and position in the current kara. - TimeUpdate(f32, f32), - - /// Display something in the main panel. - MainPanelDisplay(MainPanelDisplay), - - /// Request for informations made by the main panel - MainPanelRequest(mainpanel::Request), - - /// Message for the main panel, response to a request that was made by the main panel. - MainPanel(mainpanel::Message), - - /// Request to refresh some informations from lektord. - RefreshRequest(RefreshRequest), - - /// Request concerning a kara. - KaraRequest(kara::Request), - - /// A message for the sidebar. - Sidebar(sidebar::Message), - - /// Toggle fullscreen. - ToggleFullScreen, - - /// Set the fullscreen state to a particular mode - SetWindowMode(iced::window::Mode), - - /// Should we launch or shutdown the Mpris server? - ToggleMprisServer(bool), - - /// Side bar was resized. - SideBarResize(u16), - - /// Multiple messages. Note that a [Message::Multiple] should not contain another - /// [Message::Multiple] message (logic error...) - Multiple(Vec<Message>), - - /// Needs to display something in a modal. - DisplayModal(ShowModal), - - /// Close any modal that is present. - CloseModal, -} - -impl Message { - /// Transform a result in a message or return the default thingy. - #[allow(dead_code)] - pub fn from_err_or(res: Result<Self, anyhow::Error>, err: Message) -> Self { - res.map_err(|err| log::error!("{err}")).unwrap_or(err) - } - - /// Transform a result in a message or return the default thingy. Build from an iterator. - #[allow(dead_code)] - pub fn from_err_ors( - res: Result<Self, anyhow::Error>, - err: impl IntoIterator<Item = Message>, - ) -> Self { - res.map_err(|err| log::error!("{err}")) - .unwrap_or_else(|()| err.into_iter().collect()) - } - - /// Transform a result in a message or return the default thingy. Call function version. - #[allow(dead_code)] - pub fn from_err_or_else( - res: Result<Self, anyhow::Error>, - err: impl FnOnce() -> Message, - ) -> Self { - res.map_err(|err| log::error!("{err}")) - .unwrap_or_else(|()| err()) - } - - /// Transform a result in a message or return the default thingy. Call function version. Build - /// from an iterator. - #[allow(dead_code)] - pub fn from_err_or_elses<Iter: IntoIterator<Item = Message>>( - res: Result<Self, anyhow::Error>, - err: impl FnOnce() -> Iter, - ) -> Self { - res.map_err(|err| log::error!("{err}")) - .unwrap_or_else(|()| Message::from_iter(err())) - } - - /// Wrapper to avoid calling [Command::perform] every time with an empty future... - pub fn perform(self) -> Command<Message> { - Command::perform(async {}, |_| self) - } - - pub fn into_perform(this: impl Into<Self>) -> Command<Message> { - let this = this.into(); - Command::perform(async {}, |_| this) - } -} - -impl std::fmt::Display for MainPanelDisplay { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - MainPanelDisplay::Config => f.write_str("Configuration"), - MainPanelDisplay::MainPanel(show) => match show { - mainpanel::Show::Queue => f.write_str("Queue"), - mainpanel::Show::History => f.write_str("History"), - mainpanel::Show::Database => f.write_str("Search"), - mainpanel::Show::Playlist(plt) => write!(f, "Playlist {plt}"), - }, - } - } -} - -impl Default for MainPanelDisplay { - fn default() -> Self { - MainPanelDisplay::MainPanel(Default::default()) - } -} - -impl From<Result<Message, anyhow::Error>> for Message { - fn from(value: Result<Message, anyhow::Error>) -> Self { - value - .map_err(|err| log::error!("{err}")) - .unwrap_or_default() - } -} - -impl From<Result<(), anyhow::Error>> for Message { - fn from(value: Result<(), anyhow::Error>) -> Self { - value.map(|()| Message::None).into() - } -} - -impl Iterator for Message { - type Item = Message; - - fn next(&mut self) -> Option<Self::Item> { - match self { - Message::None => None, - Message::Multiple(msgs) if msgs.is_empty() => None, - Message::Multiple(msgs) => Some(msgs.remove(0)), - simple => Some(std::mem::take(simple)), - } - } -} - -impl FromIterator<Message> for Message { - fn from_iter<T: IntoIterator<Item = Message>>(iter: T) -> Self { - Message::Multiple(iter.into_iter().flatten().collect()) - } -} - -impl From<RefreshRequest> for Message { - fn from(value: RefreshRequest) -> Self { - Message::RefreshRequest(value) - } -} - -impl From<ShowModal> for Message { - fn from(value: ShowModal) -> Self { - Message::DisplayModal(value) - } -} - -impl From<topbar::Message> for Message { - fn from(value: topbar::Message) -> Self { - match value { - topbar::Message::ChangedKara(Some(kara)) => Message::ChangedKara(kara), - topbar::Message::ChangedKara(None) => Message::ChangedPlayback(PlayState::Stop), - topbar::Message::ChangedPlayback(x) => Message::ChangedPlayback(x), - } - } -} - -impl From<mainpanel::Request> for Message { - fn from(value: mainpanel::Request) -> Self { - Message::MainPanelRequest(value) - } -} - -impl From<PlaybackRequest> for Message { - fn from(value: PlaybackRequest) -> Self { - Message::PlaybackRequest(value) - } -} - -impl From<topbar::Request> for Message { - fn from(value: topbar::Request) -> Self { - use topbar::Request::*; - match value { - // The things that are playback related - ChangePlayback(x) => Message::PlaybackRequest(PlaybackRequest::ChangePlayback(x)), - PlayNext => Message::PlaybackRequest(PlaybackRequest::PlayNext), - PlayPrevious => Message::PlaybackRequest(PlaybackRequest::PlayPrevious), - - // Kara. - Kara(x) => Message::KaraRequest(x), - } - } -} - -impl From<mainpanel::Message> for Message { - fn from(value: mainpanel::Message) -> Self { - Message::MainPanel(value) - } -} - -impl From<mainpanel::Show> for Message { - fn from(value: mainpanel::Show) -> Self { - Message::MainPanelDisplay(MainPanelDisplay::MainPanel(value)) - } -} - -impl From<sidebar::Request> for Message { - fn from(value: sidebar::Request) -> Self { - use sidebar::Request::*; - use MainPanelDisplay::*; - match value { - ShowQueue => Message::MainPanelDisplay(MainPanel(mainpanel::Show::Queue)), - ShowDatabase => Message::MainPanelDisplay(MainPanel(mainpanel::Show::Database)), - ShowHistory => Message::MainPanelDisplay(MainPanel(mainpanel::Show::History)), - ShowSettings => Message::MainPanelDisplay(Config), - RefreshPlaylists => Message::RefreshRequest(RefreshRequest::Playlists), - Scrolled(x) => Message::Sidebar(sidebar::Message::Scrolled(x)), - ShowPlaylist(x) => Message::from_iter([ - Message::RefreshRequest(RefreshRequest::Playlist(x.clone())), - Message::MainPanelDisplay(MainPanel(mainpanel::Show::Playlist(x))), - ]), - } - } -} - -impl From<sidebar::Message> for Message { - fn from(value: sidebar::Message) -> Self { - Message::Sidebar(value) - } -} - -impl From<bottombar::Message> for Message { - fn from(value: bottombar::Message) -> Self { - Message::TimeUpdate(value.0, value.1) - } -} - -impl From<config::Request> for Message { - fn from(value: config::Request) -> Self { - match value { - config::Request::Reconnect | config::Request::None => Message::None, - config::Request::FlushCacheAndReconnect => Message::ReconnectToLektord, - config::Request::Loaded => Message::ConfigLoaded, - config::Request::ToggleMprisServer(flag) => Message::ToggleMprisServer(flag), - } - } -} - -impl From<config::Message> for Message { - fn from(value: config::Message) -> Self { - match value { - config::Message::None => Message::None, - config::Message::OpenLinkInBrowser(x) => Message::OpenLinkInBrowser(x), - value => Message::Config(value), - } - } -} - -impl From<history::Message> for Message { - fn from(value: history::Message) -> Self { - Self::MainPanel(mainpanel::Message::History(value)) - } -} - -impl From<history::Request> for Message { - fn from(value: history::Request) -> Self { - Self::MainPanelRequest(mainpanel::Request::History(value)) - } -} - -impl From<queue::Message> for Message { - fn from(value: queue::Message) -> Self { - Self::MainPanel(mainpanel::Message::Queue(value)) - } -} - -impl From<queue::Request> for Message { - fn from(value: queue::Request) -> Self { - Self::MainPanelRequest(mainpanel::Request::Queue(value)) - } -} - -impl From<search::Message> for Message { - fn from(value: search::Message) -> Self { - Self::MainPanel(mainpanel::Message::Search(value)) - } -} - -impl From<search::Request> for Message { - fn from(value: search::Request) -> Self { - Self::MainPanelRequest(mainpanel::Request::Search(value)) - } -} - -impl From<playlists::Message> for Message { - fn from(value: playlists::Message) -> Self { - Self::MainPanel(mainpanel::Message::Playlists(value)) - } -} - -impl From<playlists::Request> for Message { - fn from(value: playlists::Request) -> Self { - Self::MainPanelRequest(mainpanel::Request::Playlists(value)) - } -} diff --git a/amadeus/src/store.rs b/amadeus/src/store.rs deleted file mode 100644 index 9cb0bc76..00000000 --- a/amadeus/src/store.rs +++ /dev/null @@ -1,76 +0,0 @@ -//! The kara store, to try to cache the [Kara] by their [KId]. - -use anyhow::Result; -use hashbrown::HashMap; -use lektor_lib::{requests::*, ConnectConfigPtr}; -use lektor_payloads::{KId, Kara}; -use std::sync::Arc; -use tokio::sync::RwLock; - -/// The pool of kara. -/// -/// We store a copy of the config to not clone it on each request as we assume that most of the -/// time the config won't change and thus passing it always around would force us to do many -/// unnessessary clones. -pub struct KaraStore { - sender: tokio::sync::watch::Sender<ConnectConfigPtr>, - receiver: tokio::sync::watch::Receiver<ConnectConfigPtr>, - config: RwLock<ConnectConfigPtr>, - store: RwLock<HashMap<KId, Arc<Kara>>>, -} - -impl KaraStore { - /// Create a new kara store, we use the default configuration here. Note that it should not be - /// a problem because before doing anything with the store the config should be loaded and - /// before the config is loaded we do not render anything that could cause a [KaraStore::get]. - pub fn new() -> Self { - let config = ConnectConfigPtr::default(); - let (sender, receiver) = tokio::sync::watch::channel(config.clone()); - Self { - sender, - receiver, - config: RwLock::new(config), - store: Default::default(), - } - } - - /// Update the configuration, it will really be updated the next time we do a get. - pub fn update(&self, config: ConnectConfigPtr) { - let _ = self.sender.send_replace(config); - } - - /// Clear the cache. - pub async fn clear(&self) -> Result<()> { - self.store.write().await.clear(); - Ok(()) - } - - /// Get a kara from lektord by its [KId]. If the config was updated, we apply the update. - /// We prefer to get the kara from the internal hashmap, if the kara is not present, we request - /// it from lektord. - pub async fn get(&self, id: KId) -> Result<Arc<Kara>> { - if let Ok(true) = self.receiver.has_changed() { - let new_config = self.receiver.borrow().clone(); - *self.config.write().await = new_config; - } - if let Some(kara) = self.store.read().await.get(&id) { - return Ok(kara.clone()); - } - let kara = Arc::new(get_kara_by_kid(self.config.read().await.clone(), id).await?); - let mut store = self.store.write().await; - store.insert(kara.id.clone(), kara.clone()); - Ok(kara) - } - - /// Same as the [KaraStore::get], but we consume a cloned pointer to have to write less - /// boiler-plate code. - pub async fn into_get(self: Arc<Self>, id: KId) -> Result<Arc<Kara>> { - self.as_ref().get(id).await - } - - /// Same as [KaraStore::clear], but we consume a cloned pointer to have to write less - /// boiler-plate code. - pub async fn into_clear(self: Arc<Self>) -> Result<()> { - self.clear().await - } -} diff --git a/amadeus/src/style_sheet/badge/mod.rs b/amadeus/src/style_sheet/badge/mod.rs deleted file mode 100644 index f8e24916..00000000 --- a/amadeus/src/style_sheet/badge/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod rounded; -mod squared; - -pub use rounded::*; -pub use squared::*; diff --git a/amadeus/src/style_sheet/badge/rounded.rs b/amadeus/src/style_sheet/badge/rounded.rs deleted file mode 100644 index f7810872..00000000 --- a/amadeus/src/style_sheet/badge/rounded.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::{ - style_sheet::{sizes::*, Color}, - Amadeus, -}; -use iced::Application; -use iced_aw::badge::{Appearance, StyleSheet}; - -/// Style for a simple rounded badge. -pub struct RoundBadgeStyleSheet(Color); - -impl From<Color> for RoundBadgeStyleSheet { - fn from(value: Color) -> Self { - Self(value) - } -} - -impl StyleSheet for RoundBadgeStyleSheet { - type Style = <Amadeus as Application>::Theme; - - fn active(&self, style: &Self::Style) -> Appearance { - let back = self.0.back(style); - Appearance { - background: back.into(), - border_radius: Some(BORDER_RADIUS), - border_width: 1.0, - border_color: Some(back), - text_color: style.palette().text, - } - } -} diff --git a/amadeus/src/style_sheet/badge/squared.rs b/amadeus/src/style_sheet/badge/squared.rs deleted file mode 100644 index 8866fa18..00000000 --- a/amadeus/src/style_sheet/badge/squared.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::{style_sheet::Color, Amadeus}; -use iced::Application; -use iced_aw::badge::{Appearance, StyleSheet}; - -/// Style for a simple squared badge. -pub struct SquareBadge(Color); - -impl From<Color> for SquareBadge { - fn from(value: Color) -> Self { - Self(value) - } -} - -impl StyleSheet for SquareBadge { - type Style = <Amadeus as Application>::Theme; - - fn active(&self, style: &Self::Style) -> Appearance { - let back = self.0.back(style); - Appearance { - background: back.into(), - border_radius: Some(0.0), - border_width: 1.0, - border_color: Some(back), - text_color: style.palette().text, - } - } -} diff --git a/amadeus/src/style_sheet/bar.rs b/amadeus/src/style_sheet/bar.rs deleted file mode 100644 index 5863cc25..00000000 --- a/amadeus/src/style_sheet/bar.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::{style_sheet::extended_palette, Amadeus}; -use iced::{ - widget::container::{Appearance, StyleSheet}, - Application, -}; - -/// The stylesheet for the side bar. -pub struct BarStyleSheet; - -impl StyleSheet for BarStyleSheet { - type Style = <Amadeus as Application>::Theme; - - fn appearance(&self, style: &Self::Style) -> Appearance { - Appearance { - text_color: Some(style.palette().text), - background: Some(extended_palette(style).background.weak.color.into()), - border_color: style.palette().text, - border_radius: 0.0.into(), - border_width: 0.0, - } - } -} diff --git a/amadeus/src/style_sheet/bottombar.rs b/amadeus/src/style_sheet/bottombar.rs deleted file mode 100644 index 9246e5b6..00000000 --- a/amadeus/src/style_sheet/bottombar.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::{style_sheet::extended_palette, Amadeus}; -use iced::{ - widget::progress_bar::{Appearance, StyleSheet}, - Application, -}; - -/// The stylesheet for the bottom bar. -pub struct BottomBarStyleSheet; - -impl StyleSheet for BottomBarStyleSheet { - type Style = <Amadeus as Application>::Theme; - - fn appearance(&self, style: &Self::Style) -> Appearance { - Appearance { - background: extended_palette(style).background.weak.color.into(), - bar: extended_palette(style).primary.base.color.into(), - border_radius: 0.0.into(), - } - } -} diff --git a/amadeus/src/style_sheet/button/mod.rs b/amadeus/src/style_sheet/button/mod.rs deleted file mode 100644 index 9b7c0fb5..00000000 --- a/amadeus/src/style_sheet/button/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod plain; -mod rounded; -mod squared; - -pub use plain::*; -pub use rounded::*; -pub use squared::*; diff --git a/amadeus/src/style_sheet/button/plain.rs b/amadeus/src/style_sheet/button/plain.rs deleted file mode 100644 index 9777a493..00000000 --- a/amadeus/src/style_sheet/button/plain.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::{style_sheet::extended_palette, Amadeus}; -use iced::{ - widget::button::{Appearance, StyleSheet}, - Application, Color, Vector, -}; - -/// The stylesheet for plain buttons. -pub struct PlainButtonStyleSheet; - -impl PlainButtonStyleSheet { - fn palette(text: Color) -> Appearance { - Appearance { - shadow_offset: Vector::new(0.0, 0.0), - background: None, - border_radius: 0.0.into(), - border_width: 0.0, - border_color: Color { - r: 0.0, - g: 0.0, - b: 0.0, - a: 1.0, - }, - text_color: text, - } - } -} - -impl StyleSheet for PlainButtonStyleSheet { - type Style = <Amadeus as Application>::Theme; - - fn active(&self, style: &Self::Style) -> Appearance { - Self::palette(style.palette().text) - } - - fn hovered(&self, style: &Self::Style) -> Appearance { - Self::palette(style.palette().primary) - } - - fn pressed(&self, style: &Self::Style) -> Appearance { - Self::palette(extended_palette(style).primary.strong.color) - } -} diff --git a/amadeus/src/style_sheet/button/rounded.rs b/amadeus/src/style_sheet/button/rounded.rs deleted file mode 100644 index 92932556..00000000 --- a/amadeus/src/style_sheet/button/rounded.rs +++ /dev/null @@ -1,97 +0,0 @@ -use crate::{ - style_sheet::{sizes::*, Color}, - Amadeus, -}; -use iced::{ - widget::button::{Appearance, StyleSheet}, - Application, Vector, -}; - -/// The stylesheet for plain buttons. -#[derive(Default)] -pub struct RoundButtonStyleSheet(Color); - -/// The stylesheet for hovered buttons, where the color if the hovered thing is really different -/// from the color of the base thing. -#[derive(Default)] -pub struct HoverButtonStyleSheet(Color, Color); - -impl From<Color> for RoundButtonStyleSheet { - fn from(value: Color) -> Self { - Self(value) - } -} - -impl From<(Color, Color)> for HoverButtonStyleSheet { - fn from((base, hover): (Color, Color)) -> Self { - Self(base, hover) - } -} - -impl StyleSheet for RoundButtonStyleSheet { - type Style = <Amadeus as Application>::Theme; - - fn active(&self, style: &Self::Style) -> Appearance { - let back = self.0.back(style); - Appearance { - shadow_offset: Vector::new(0.0, 0.0), - background: Some(back.into()), - border_radius: BORDER_RADIUS.into(), - border_width: 4.0, - border_color: back, - text_color: style.palette().text, - } - } - - fn hovered(&self, style: &Self::Style) -> Appearance { - let back = self.0.back(style); - Appearance { - shadow_offset: Vector::new(0.0, 0.0), - background: Some(back.into()), - border_radius: BORDER_RADIUS.into(), - border_width: 4.0, - border_color: back, - text_color: style.palette().background, - } - } -} - -impl StyleSheet for HoverButtonStyleSheet { - type Style = <Amadeus as Application>::Theme; - - fn active(&self, style: &Self::Style) -> Appearance { - let back = self.0.back(style); - Appearance { - shadow_offset: Vector::new(0.0, 0.0), - background: Some(back.into()), - border_radius: BORDER_RADIUS.into(), - border_width: 4.0, - border_color: back, - text_color: style.palette().text, - } - } - - fn pressed(&self, style: &Self::Style) -> Appearance { - let back = self.1.back_dim(style); - Appearance { - shadow_offset: Vector::new(0.0, 0.0), - background: Some(back.into()), - border_radius: BORDER_RADIUS.into(), - border_width: 4.0, - border_color: back, - text_color: style.palette().background, - } - } - - fn hovered(&self, style: &Self::Style) -> Appearance { - let back = self.1.back(style); - Appearance { - shadow_offset: Vector::new(0.0, 0.0), - background: Some(back.into()), - border_radius: BORDER_RADIUS.into(), - border_width: 4.0, - border_color: back, - text_color: style.palette().background, - } - } -} diff --git a/amadeus/src/style_sheet/button/squared.rs b/amadeus/src/style_sheet/button/squared.rs deleted file mode 100644 index f14118f4..00000000 --- a/amadeus/src/style_sheet/button/squared.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::{style_sheet::Color, Amadeus}; -use iced::{ - widget::button::{Appearance, StyleSheet}, - Application, Vector, -}; - -/// The stylesheet for plain buttons. -#[derive(Default)] -pub struct SquareButtonStyleSheet(Color); - -impl From<Color> for SquareButtonStyleSheet { - fn from(value: Color) -> Self { - Self(value) - } -} - -impl StyleSheet for SquareButtonStyleSheet { - type Style = <Amadeus as Application>::Theme; - - fn active(&self, style: &Self::Style) -> Appearance { - let back = self.0.back(style); - Appearance { - shadow_offset: Vector::new(0.0, 0.0), - background: Some(back.into()), - border_radius: 0.0.into(), - border_width: 4.0, - border_color: back, - text_color: style.palette().text, - } - } - - fn hovered(&self, style: &Self::Style) -> Appearance { - let back = self.0.back(style); - Appearance { - shadow_offset: Vector::new(0.0, 0.0), - background: Some(back.into()), - border_radius: 0.0.into(), - border_width: 4.0, - border_color: back, - text_color: style.palette().background, - } - } -} diff --git a/amadeus/src/style_sheet/context_menu.rs b/amadeus/src/style_sheet/context_menu.rs deleted file mode 100644 index 7de59dff..00000000 --- a/amadeus/src/style_sheet/context_menu.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::{ - style_sheet::{extended_palette, sizes::*}, - Amadeus, -}; -use iced::{ - widget::container::{Appearance, StyleSheet}, - Application, -}; - -/// The stylesheet for a context menu. -pub struct ContextMenuStyleSheet; - -impl StyleSheet for ContextMenuStyleSheet { - type Style = <Amadeus as Application>::Theme; - - fn appearance(&self, style: &Self::Style) -> Appearance { - let back = extended_palette(style).background.strong.color; - Appearance { - text_color: None, - background: Some(back.into()), - border_color: back, - border_radius: BORDER_RADIUS.into(), - border_width: 10.0, - } - } -} diff --git a/amadeus/src/style_sheet/mod.rs b/amadeus/src/style_sheet/mod.rs deleted file mode 100644 index 90c42a8b..00000000 --- a/amadeus/src/style_sheet/mod.rs +++ /dev/null @@ -1,59 +0,0 @@ -pub mod sizes; - -mod badge; -mod bar; -mod bottombar; -mod button; -mod context_menu; -mod modal; -mod split; -mod tooltip; - -pub use badge::*; -pub use bar::*; -pub use bottombar::*; -pub use button::*; -pub use context_menu::*; -pub use modal::*; -pub use split::*; -pub use tooltip::*; - -use iced::{theme::palette::Extended, Theme}; - -fn extended_palette(theme: &Theme) -> &Extended { - use crate::components::config::theme; - match Into::<theme::Message>::into(theme) { - theme::Message::Dark => iced::Theme::Dark.extended_palette(), - theme::Message::Light => iced::Theme::Light.extended_palette(), - } -} - -/// Color to decide which color to use for the button or the badge. -#[derive(Default, Clone, Copy, PartialEq, Eq)] -pub enum Color { - #[default] - Primary, - Success, - Danger, -} - -impl Color { - pub fn back(&self, style: &<crate::app::Amadeus as iced::Application>::Theme) -> iced::Color { - match self { - Color::Primary => extended_palette(style).primary.strong.color, - Color::Success => extended_palette(style).success.strong.color, - Color::Danger => extended_palette(style).danger.strong.color, - } - } - - pub fn back_dim( - &self, - style: &<crate::app::Amadeus as iced::Application>::Theme, - ) -> iced::Color { - match self { - Color::Primary => extended_palette(style).primary.weak.color, - Color::Success => extended_palette(style).success.weak.color, - Color::Danger => extended_palette(style).danger.weak.color, - } - } -} diff --git a/amadeus/src/style_sheet/modal.rs b/amadeus/src/style_sheet/modal.rs deleted file mode 100644 index f7b7bd6e..00000000 --- a/amadeus/src/style_sheet/modal.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::{ - style_sheet::{extended_palette, sizes::*}, - Amadeus, -}; -use iced::{ - widget::container::{Appearance, StyleSheet}, - Application, -}; - -/// The stylesheet for the tooltips. -pub struct ModalStyleSheet; - -impl StyleSheet for ModalStyleSheet { - type Style = <Amadeus as Application>::Theme; - - fn appearance(&self, style: &Self::Style) -> Appearance { - let back = extended_palette(style).background.weak.color; - Appearance { - text_color: Some(style.palette().text), - background: Some(back.into()), - border_color: back, - border_radius: BORDER_RADIUS.into(), - border_width: 10.0, - } - } -} diff --git a/amadeus/src/style_sheet/sizes.rs b/amadeus/src/style_sheet/sizes.rs deleted file mode 100644 index 65243831..00000000 --- a/amadeus/src/style_sheet/sizes.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Some sizes to be coherent in all the application - -/// Small font sizes -pub const SIZE_FONT_SMALL: u16 = 10; - -/// Normal font size, should prefer this size for all. -pub const SIZE_FONT_NORMAL: u16 = 13; - -/// When the [SIZE_FONT_NORMAL] is too small but we can't affort the place of the -/// [SIZE_FONT_MEDIUM], should only be used in the title bar for the current kara. -pub const SIZE_FONT_MOAR: u16 = 15; - -/// For sub-titles or big icons. -pub const SIZE_FONT_MEDIUM: u16 = 20; - -/// For titles. -pub const SIZE_FONT_TITLE: u16 = 25; - -/// The radius of everything that should be rounded. -pub const BORDER_RADIUS: f32 = 5.0; diff --git a/amadeus/src/style_sheet/split.rs b/amadeus/src/style_sheet/split.rs deleted file mode 100644 index 789ef8cc..00000000 --- a/amadeus/src/style_sheet/split.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::{style_sheet::extended_palette, Amadeus}; -use iced::Application; -use iced_aw::{split::Appearance, style::split::StyleSheet}; - -/// Style for the split of the main window, used to separate the side bar from the main panel, -/// including the top bar. -pub struct SideBarSplit; - -impl StyleSheet for SideBarSplit { - type Style = <Amadeus as Application>::Theme; - - fn active(&self, style: &Self::Style) -> Appearance { - Appearance { - background: None, - first_background: None, - second_background: None, - border_width: 2.0, - border_color: extended_palette(style).background.weak.color, - divider_background: extended_palette(style).background.weak.color.into(), - divider_border_width: 4.0, - divider_border_color: extended_palette(style).background.weak.color, - } - } - - fn hovered(&self, style: &Self::Style) -> Appearance { - Appearance { - background: None, - first_background: None, - second_background: None, - border_width: 2.0, - border_color: style.palette().text, - divider_background: style.palette().text.into(), - divider_border_width: 4.0, - divider_border_color: style.palette().text, - } - } - - fn dragged(&self, style: &Self::Style) -> Appearance { - self.hovered(style) - } -} diff --git a/amadeus/src/style_sheet/tooltip.rs b/amadeus/src/style_sheet/tooltip.rs deleted file mode 100644 index d64b2e7c..00000000 --- a/amadeus/src/style_sheet/tooltip.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::{ - style_sheet::{extended_palette, sizes::*}, - Amadeus, -}; -use iced::{ - widget::container::{Appearance, StyleSheet}, - Application, -}; - -/// The stylesheet for the tooltips. -pub struct ToolTipStyleSheet; - -impl StyleSheet for ToolTipStyleSheet { - type Style = <Amadeus as Application>::Theme; - - fn appearance(&self, style: &Self::Style) -> Appearance { - let back = extended_palette(style).background.strong.color; - Appearance { - text_color: Some(style.palette().background), - background: Some(back.into()), - border_color: back, - border_radius: BORDER_RADIUS.into(), - border_width: 10.0, - } - } -} diff --git a/amadeus/src/subscriptions.rs b/amadeus/src/subscriptions.rs new file mode 100644 index 00000000..f33e8faa --- /dev/null +++ b/amadeus/src/subscriptions.rs @@ -0,0 +1 @@ +pub mod lektord; diff --git a/amadeus/src/subscriptions/lektord.rs b/amadeus/src/subscriptions/lektord.rs new file mode 100644 index 00000000..38cd9f07 --- /dev/null +++ b/amadeus/src/subscriptions/lektord.rs @@ -0,0 +1,39 @@ +use crate::app::Message; +use cosmic::iced::{subscription, Subscription}; +use futures::SinkExt; +use lektor_lib::{requests, ConnectConfig}; +use std::{any::TypeId, sync::Arc, time::Duration}; +use tokio::sync::RwLock; + +pub struct Suscription { + pub config: Arc<RwLock<ConnectConfig>>, +} + +impl Suscription { + pub fn run(self) -> Subscription<Message> { + let Self { config } = self; + subscription::channel(TypeId::of::<Self>(), 10, move |mut channel| async move { + log::info!("lektord subscription launched"); + 'connect: loop { + macro_rules! disconnected { + () => {{ + log::warn!("failed to connect to lektord"); + _ = channel.send(Message::LektordDisconnected); + tokio::time::sleep(config.read().await.retry).await; + continue 'connect; + }}; + } + + match requests::get_infos(config.read().await.as_ref()).await { + Ok(infos) => _ = channel.send(Message::LektordConnected(infos)).await, + Err(_) => disconnected!(), + } + + while let Ok(state) = requests::get_status(config.read().await.as_ref()).await { + _ = channel.send(Message::LektordUpdate(state)); + tokio::time::sleep(Duration::from_secs(1)).await; + } + } + }) + } +} diff --git a/lektor_lib/Cargo.toml b/lektor_lib/Cargo.toml index 190cd320..c6f37da0 100644 --- a/lektor_lib/Cargo.toml +++ b/lektor_lib/Cargo.toml @@ -11,6 +11,7 @@ description = "Client library for lektord, used to factorize the code between lk serde.workspace = true serde_json.workspace = true +log.workspace = true url.workspace = true anyhow.workspace = true diff --git a/lektor_lib/src/config.rs b/lektor_lib/src/config.rs index 6b4867f9..41445774 100644 --- a/lektor_lib/src/config.rs +++ b/lektor_lib/src/config.rs @@ -1,7 +1,7 @@ use lektor_utils::config::SocketScheme; use std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, - sync::Arc, + sync::Arc, time::Duration, }; /// The config to use to connect to the remote. @@ -11,6 +11,7 @@ pub struct ConnectConfig { pub host: SocketAddr, pub user: Box<str>, pub token: Box<str>, + pub retry: Duration, } /// Ref-counted thingy. @@ -19,10 +20,18 @@ pub type ConnectConfigPtr = Arc<ConnectConfig>; impl Default for ConnectConfig { fn default() -> Self { Self { - scheme: Default::default(), host: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 6600), - user: Default::default(), + retry: Duration::from_secs(10), + + scheme: Default::default(), token: Default::default(), + user: Default::default(), } } } + +impl AsRef<ConnectConfig> for ConnectConfig { + fn as_ref(&self) -> &ConnectConfig { + self + } +} diff --git a/lektor_lib/src/requests.rs b/lektor_lib/src/requests.rs index f49ff348..719f9262 100644 --- a/lektor_lib/src/requests.rs +++ b/lektor_lib/src/requests.rs @@ -1,27 +1,37 @@ -use crate::ConnectConfigPtr; +use crate::ConnectConfig; use anyhow::{bail, Context, Result}; use lektor_payloads::*; -use lektor_utils::{encode_base64, encode_base64_value, log}; -use reqwest::{header, Body, Client, Method, Request, Url}; +use lektor_utils::{encode_base64, encode_base64_value}; +use reqwest::{ + header::{self, HeaderValue}, + Body, ClientBuilder, Method, Request, Url, +}; use std::sync::Arc; +const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); + macro_rules! request { ( - $config: expr; $method: ident $(($body: expr))? - @ $($query: expr),+ - $(=> $into: ty)? + $config:expr; + $method:ident $(($body:expr))? @ $($query:expr),+ + $(=> $into:ty)? ) => {{ - let config = $config.into(); - let url = Url::parse(&format!("{}{}", format!("{}://{}", config.scheme, config.host), format!($($query,)+))) - .with_context(|| "invalid url")?; + let ConnectConfig { scheme, host, user, token, retry, .. } = $config.as_ref(); + let url = Url::parse(&format!("{scheme}://{host}{}", format!($($query,)+))).context("invalid url")?; let mut req = Request::new(Method::$method, url); + let mut token = format!("{user}={token}").parse::<HeaderValue>().context("invalid token or user")?; + token.set_sensitive(true); + *req.timeout_mut() = Some(*retry); req.headers_mut().insert( header::AUTHORIZATION, - format!("{}={}", config.user, config.token).parse()?, + token, ); *req.body_mut() = request!(@body req, $($body)?); - let res = Client::new().execute(req).await?; + let res = ClientBuilder::new() + .user_agent(USER_AGENT) + .build()? + .execute(req).await?; match res.status() { ok if ok.is_success() => request!(@res res $(=> $into)?), err => bail!("got error code {err}"), @@ -29,19 +39,17 @@ macro_rules! request { }}; // Result body handling - (@res $body: expr) => { () }; - (@res $body: expr => $into: ty) => { $body.json::<$into>().await? }; + (@res $body: expr) => { Ok(()) }; + (@res $body: expr => $into: ty) => { $body.json::<$into>().await.context("invalid json body") }; // Post/Get/Delete/Put body handling (@body $req: expr,) => { None }; (@body $req: expr, $body: expr) => {{ $req.headers_mut().insert( header::CONTENT_TYPE, - "application/json".parse()?, + "application/json".parse().context("invalid content type")?, ); - let json = serde_json::to_string(&$body)?; - log::trace!("send json: {json}"); - Some(Body::from(json)) + Some(Body::from(serde_json::to_string(&$body).context("failed to serialize")?)) }}; } pub(crate) use request; @@ -50,113 +58,107 @@ pub(crate) use request; // Playback & status informations // // ================================================== // -pub async fn get_infos(config: impl Into<ConnectConfigPtr>) -> Result<Infos> { - Ok(request!(config; GET @ "/" => Infos)) +pub async fn get_infos(config: impl AsRef<ConnectConfig>) -> Result<Infos> { + request!(config; GET @ "/" => Infos) } -pub async fn get_status(config: impl Into<ConnectConfigPtr>) -> Result<PlayStateWithCurrent> { - Ok(request!(config; GET @ "/playback/state" => PlayStateWithCurrent)) +pub async fn get_status(config: impl AsRef<ConnectConfig>) -> Result<PlayStateWithCurrent> { + request!(config; GET @ "/playback/state" => PlayStateWithCurrent) } -pub async fn get_kara_by_kid(config: impl Into<ConnectConfigPtr>, kid: KId) -> Result<Kara> { +pub async fn get_kara_by_kid(config: impl AsRef<ConnectConfig>, kid: KId) -> Result<Kara> { let (len, kid) = encode_base64(kid.as_str())?; let kid = std::str::from_utf8(&kid[..len])?; - Ok(request!(config; GET @ "/get/kid/{}", kid => Kara)) + request!(config; GET @ "/get/kid/{kid}" => Kara) } -pub async fn get_kara_by_id(config: impl Into<ConnectConfigPtr>, id: u64) -> Result<Kara> { - Ok(request!(config; GET @ "/get/id/{id}" => Kara)) +pub async fn get_kara_by_id(config: impl AsRef<ConnectConfig>, id: u64) -> Result<Kara> { + request!(config; GET @ "/get/id/{id}" => Kara) } -pub async fn toggle_playback_state(config: impl Into<ConnectConfigPtr>) -> Result<()> { - Ok(request!(config; PUT @ "/playback/state")) +pub async fn toggle_playback_state(config: impl AsRef<ConnectConfig>) -> Result<()> { + request!(config; PUT @ "/playback/state") } -pub async fn set_playback_state( - config: impl Into<ConnectConfigPtr>, - state: PlayState, -) -> Result<()> { - Ok(request!(config; POST(state) @ "/playback/state")) +pub async fn set_playback_state(config: impl AsRef<ConnectConfig>, state: PlayState) -> Result<()> { + request!(config; POST(state) @ "/playback/state") } -pub async fn play_next(config: impl Into<ConnectConfigPtr>) -> Result<()> { - Ok(request!(config; PUT @ "/playback/next")) +pub async fn play_next(config: impl AsRef<ConnectConfig>) -> Result<()> { + request!(config; PUT @ "/playback/next") } -pub async fn play_previous(config: impl Into<ConnectConfigPtr>) -> Result<()> { - Ok(request!(config; PUT @ "/playback/previous")) +pub async fn play_previous(config: impl AsRef<ConnectConfig>) -> Result<()> { + request!(config; PUT @ "/playback/previous") } -pub async fn play_from_position(config: impl Into<ConnectConfigPtr>, pos: usize) -> Result<()> { - Ok(request!(config; POST @ "/playback/play/{pos}")) +pub async fn play_from_position(config: impl AsRef<ConnectConfig>, pos: usize) -> Result<()> { + request!(config; POST @ "/playback/play/{pos}") } -pub async fn update_from_repo(config: impl Into<ConnectConfigPtr>) -> Result<()> { - Ok(request!(config; POST @ "/adm/update")) +pub async fn update_from_repo(config: impl AsRef<ConnectConfig>) -> Result<()> { + request!(config; POST @ "/adm/update") } -pub async fn shutdown_lektord(config: impl Into<ConnectConfigPtr>) -> Result<()> { - Ok(request!(config; POST @ "/adm/shutdown")) +pub async fn shutdown_lektord(config: impl AsRef<ConnectConfig>) -> Result<()> { + request!(config; POST @ "/adm/shutdown") } // ================================================== // // Queue manipulation functions // // ================================================== // -pub async fn add_to_queue(config: impl Into<ConnectConfigPtr>, what: QueueAddAction) -> Result<()> { - Ok(request!(config; POST(what) @ "/queue")) +pub async fn add_to_queue(config: impl AsRef<ConnectConfig>, what: QueueAddAction) -> Result<()> { + request!(config; POST(what) @ "/queue") } pub async fn add_kid_to_queue( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, prio: Priority, id: KId, ) -> Result<()> { - Ok(request!(config; POST @ "/queue/{prio}/{id}")) + request!(config; POST @ "/queue/{prio}/{id}") } -pub async fn remove_kid_from_queue(config: impl Into<ConnectConfigPtr>, id: KId) -> Result<()> { - Ok(request!(config; DELETE @ "/queue/{id}")) +pub async fn remove_kid_from_queue(config: impl AsRef<ConnectConfig>, id: KId) -> Result<()> { + request!(config; DELETE @ "/queue/{id}") } -pub async fn remove_kid_from_history(config: impl Into<ConnectConfigPtr>, id: KId) -> Result<()> { - Ok(request!(config; DELETE @ "/history/{id}")) +pub async fn remove_kid_from_history(config: impl AsRef<ConnectConfig>, id: KId) -> Result<()> { + request!(config; DELETE @ "/history/{id}") } pub async fn remove_level_from_queue( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, level: Priority, ) -> Result<()> { - Ok(request!(config; DELETE @ "/queue/{level}")) + request!(config; DELETE @ "/queue/{level}") } pub async fn remove_range_from_queue( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, range: impl Into<Range>, ) -> Result<()> { let (len, range) = encode_base64(format!("{}", range.into()))?; let range = std::str::from_utf8(&range[..len])?; - Ok(request!(config; DELETE @ "/queue?range={range}")) + request!(config; DELETE @ "/queue?range={range}") } -pub async fn shuffle_level_queue( - config: impl Into<ConnectConfigPtr>, - prio: Priority, -) -> Result<()> { - Ok(request!(config; PUT @ "/queue/{prio}")) +pub async fn shuffle_level_queue(config: impl AsRef<ConnectConfig>, prio: Priority) -> Result<()> { + request!(config; PUT @ "/queue/{prio}") } -pub async fn shuffle_queue(config: impl Into<ConnectConfigPtr>) -> Result<()> { +pub async fn shuffle_queue(config: impl AsRef<ConnectConfig>) -> Result<()> { shuffle_queue_range(config, ..).await } pub async fn shuffle_queue_range( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, range: impl Into<Range>, ) -> Result<()> { let (len, range) = encode_base64(format!("{}", range.into()))?; let range = std::str::from_utf8(&range[..len])?; - Ok(request!(config; POST(QueueUpdateAction::Shuffle) @ "/queue?range={range}")) + request!(config; POST(QueueUpdateAction::Shuffle) @ "/queue?range={range}") } // ================================================== // @@ -164,12 +166,12 @@ pub async fn shuffle_queue_range( // ================================================== // pub async fn remove_range_from_history( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, range: impl Into<Range>, ) -> Result<()> { let (len, range) = encode_base64(format!("{}", range.into()))?; let range = std::str::from_utf8(&range[..len])?; - Ok(request!(config; DELETE @ "/history?range={range}")) + request!(config; DELETE @ "/history?range={range}") } // ================================================== // @@ -177,121 +179,121 @@ pub async fn remove_range_from_history( // ================================================== // pub async fn remove_kid_from_playlist( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, name: Arc<str>, id: KId, ) -> Result<()> { let action = PlaylistUpdateAction::Remove(KaraFilter::KId(id)); let (len, name) = encode_base64(name)?; let name = std::str::from_utf8(&name[..len])?; - Ok(request!(config; PATCH(action) @ "/playlist/{name}")) + request!(config; PATCH(action) @ "/playlist/{name}") } pub async fn add_to_playlist( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, name: Arc<str>, what: KaraFilter, ) -> Result<()> { let (len, name) = encode_base64(name)?; let name = std::str::from_utf8(&name[..len])?; - Ok(request!(config; PATCH(PlaylistUpdateAction::Add(what)) @ "/playlist/{name}")) + request!(config; PATCH(PlaylistUpdateAction::Add(what)) @ "/playlist/{name}") } pub async fn remove_from_playlist( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, name: Arc<str>, what: KaraFilter, ) -> Result<()> { let (len, name) = encode_base64(name)?; let name = std::str::from_utf8(&name[..len])?; - Ok(request!(config; PATCH(PlaylistUpdateAction::Remove(what)) @ "/playlist/{name}")) + request!(config; PATCH(PlaylistUpdateAction::Remove(what)) @ "/playlist/{name}") } -pub async fn create_playlist(config: impl Into<ConnectConfigPtr>, name: Arc<str>) -> Result<()> { +pub async fn create_playlist(config: impl AsRef<ConnectConfig>, name: Arc<str>) -> Result<()> { let (len, name) = encode_base64(name)?; let name = std::str::from_utf8(&name[..len])?; - Ok(request!(config; PUT @ "/playlist/{name}")) + request!(config; PUT @ "/playlist/{name}") } -pub async fn delete_playlist(config: impl Into<ConnectConfigPtr>, name: Arc<str>) -> Result<()> { +pub async fn delete_playlist(config: impl AsRef<ConnectConfig>, name: Arc<str>) -> Result<()> { let (len, name) = encode_base64(name)?; let name = std::str::from_utf8(&name[..len])?; - Ok(request!(config; DELETE @ "/playlist/{name}")) + request!(config; DELETE @ "/playlist/{name}") } // ================================================== // // Search functions // // ================================================== // -pub async fn get_queue(config: impl Into<ConnectConfigPtr>) -> Result<Vec<(Priority, KId)>> { +pub async fn get_queue(config: impl AsRef<ConnectConfig>) -> Result<Vec<(Priority, KId)>> { get_queue_range(config, ..).await } -pub async fn get_history(config: impl Into<ConnectConfigPtr>) -> Result<Vec<KId>> { +pub async fn get_history(config: impl AsRef<ConnectConfig>) -> Result<Vec<KId>> { get_history_range(config, ..).await } pub async fn get_queue_count( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, ) -> Result<[usize; PRIORITY_LENGTH]> { - Ok(request!(config; GET @ "/queue/count" => [usize; PRIORITY_LENGTH])) + request!(config; GET @ "/queue/count" => [usize; PRIORITY_LENGTH]) } -pub async fn get_history_count(config: impl Into<ConnectConfigPtr>) -> Result<usize> { - Ok(request!(config; GET @ "/history/count" => usize)) +pub async fn get_history_count(config: impl AsRef<ConnectConfig>) -> Result<usize> { + request!(config; GET @ "/history/count" => usize) } pub async fn get_queue_range( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, range: impl Into<Range>, ) -> Result<Vec<(Priority, KId)>> { let (len, range) = encode_base64(format!("{}", range.into()))?; let range = std::str::from_utf8(&range[..len])?; - Ok(request!(config; GET @ "/queue?range={range}" => Vec<(Priority, KId)>)) + request!(config; GET @ "/queue?range={range}" => Vec<(Priority, KId)>) } pub async fn get_history_range( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, range: impl Into<Range>, ) -> Result<Vec<KId>> { let (len, range) = encode_base64(format!("{}", range.into()))?; let range = std::str::from_utf8(&range[..len])?; - Ok(request!(config; GET @ "/history?range={range}" => Vec<KId>)) + request!(config; GET @ "/history?range={range}" => Vec<KId>) } pub async fn get_playlists( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, ) -> Result<Vec<(PlaylistName, PlaylistInfo)>> { - Ok(request!(config; GET @ "/playlist" => Vec<(PlaylistName, PlaylistInfo)>)) + request!(config; GET @ "/playlist" => Vec<(PlaylistName, PlaylistInfo)>) } pub async fn get_playlist_content( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, name: Arc<str>, ) -> Result<Vec<KId>> { let (len, name) = encode_base64(name)?; let name = std::str::from_utf8(&name[..len])?; - Ok(request!(config; GET @ "/playlist/{name}" => Vec<KId>)) + request!(config; GET @ "/playlist/{name}" => Vec<KId>) } pub async fn search_karas( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, from: SearchFrom, by: KaraBy, ) -> Result<Vec<KId>> { let regex = vec![by]; let (len, obj) = encode_base64_value(SearchData { from, regex })?; let get = std::str::from_utf8(&obj[..len])?; - Ok(request!(config; GET @ "/search/{get}" => Vec<KId>)) + request!(config; GET @ "/search/{get}" => Vec<KId>) } pub async fn count_karas( - config: impl Into<ConnectConfigPtr>, + config: impl AsRef<ConnectConfig>, from: SearchFrom, by: KaraBy, ) -> Result<usize> { let regex = vec![by]; let (len, obj) = encode_base64_value(SearchData { from, regex })?; let get = std::str::from_utf8(&obj[..len])?; - Ok(request!(config; GET @ "/count/{get}" => usize)) + request!(config; GET @ "/count/{get}" => usize) } diff --git a/lektor_mpris/Cargo.toml b/lektor_mpris/Cargo.toml index 2418277d..68701c86 100644 --- a/lektor_mpris/Cargo.toml +++ b/lektor_mpris/Cargo.toml @@ -1,17 +1,20 @@ [package] -name = "lektor_mpris" -version.workspace = true -edition.workspace = true -authors.workspace = true -license.workspace = true -rust-version.workspace = true +name = "lektor_mpris" description = "Implement the mpris spec, designed to be plugable into lektord or amadeus" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +rust-version.workspace = true + [dependencies] -hashbrown.workspace = true -tokio.workspace = true -serde.workspace = true -zbus.workspace = true +hashbrown.workspace = true +tokio.workspace = true +serde.workspace = true +zbus.workspace = true +derive_more.workspace = true +log.workspace = true -lektor_procmacros = { path = "../lektor_procmacros" } -lektor_utils = { path = "../lektor_utils" } +lektor_procmacros.workspace = true +lektor_utils.workspace = true diff --git a/lektor_mpris/src/server.rs b/lektor_mpris/src/server.rs index cc12e6b3..38ce3f20 100644 --- a/lektor_mpris/src/server.rs +++ b/lektor_mpris/src/server.rs @@ -2,7 +2,6 @@ //! `org.mpris.MediaPlayer2.TrackList` use crate::{types::*, AsMpris}; -use lektor_utils::log; use zbus::{Connection, ConnectionBuilder, SignalContext}; /// The adapter for MPRIS. diff --git a/lektor_mpris/src/trait.rs b/lektor_mpris/src/trait.rs index a4080eba..fadd07ce 100644 --- a/lektor_mpris/src/trait.rs +++ b/lektor_mpris/src/trait.rs @@ -1,7 +1,6 @@ //! TODO: See how we can do for the signals... We may need to fire them at some point. use crate::types::*; -use lektor_utils::log; /// An application must implement the [AsMpris] trait to be able to be wrapped by the /// [crate::server::MPRISAdapter]. diff --git a/lektor_nkdb/Cargo.toml b/lektor_nkdb/Cargo.toml index 55417008..4e18c45e 100644 --- a/lektor_nkdb/Cargo.toml +++ b/lektor_nkdb/Cargo.toml @@ -11,6 +11,7 @@ description = "New database implementation for lektord (New Kara DataBase)" serde.workspace = true serde_json.workspace = true +log.workspace = true url.workspace = true rand.workspace = true regex.workspace = true diff --git a/lektor_nkdb/src/database/pool.rs b/lektor_nkdb/src/database/pool.rs index e3a975da..332db3f2 100644 --- a/lektor_nkdb/src/database/pool.rs +++ b/lektor_nkdb/src/database/pool.rs @@ -4,14 +4,12 @@ //! representation for searching plus some mapping. A pool is common for all the epochs. For epoch //! specific things like the [u64] to [Kid] / [Kara] mappings, do that in the epoch struct. -use crate::Playlist; +use crate::{EpochData, Playlist}; use hashbrown::HashMap; use serde::{Deserialize, Serialize}; use std::{collections::hash_map::DefaultHasher, hash::Hasher, sync::Arc}; use tokio::sync::RwLock; -use super::EpochData; - /// A pool of all the available kara for every epochs #[derive(Debug, Default)] pub(crate) struct Pool { @@ -53,11 +51,10 @@ impl Pool { /// id is not present, returns none, else some(local_id). pub(crate) async fn get_from_remote(&self, rkid: impl AsRef<str>) -> (Option<KId>, RemoteKId) { let rkid = self.get_str::<RemoteKId>(rkid).await; - let list = self.id_mapping.read().await; - let id = list - .iter() - .find_map(|(id, remote)| remote.eq(&rkid).then_some(id)); - (id.cloned(), rkid) + let id = (self.id_mapping.read().await.iter()) + .find_map(|(id, remote)| remote.eq(&rkid).then_some(id)) + .cloned(); + (id, rkid) } /// Get a pointer to the string by its value. Used to reduce the amount of memory allocated for @@ -67,8 +64,7 @@ impl Pool { fn get_str_sync<I: sealed::Id>(&mut self, id: Arc<str>) -> I { let mut hash = DefaultHasher::new(); hash.write(id.as_ref().as_bytes()); - self.string_cache - .get_mut() + (self.string_cache.get_mut()) .entry(hash.finish()) .or_insert(id) .clone() diff --git a/lektor_nkdb/src/database/update.rs b/lektor_nkdb/src/database/update.rs index eb9f9ab3..d5bdcb64 100644 --- a/lektor_nkdb/src/database/update.rs +++ b/lektor_nkdb/src/database/update.rs @@ -5,10 +5,12 @@ use anyhow::Result; use futures::future::join_all; use hashbrown::HashMap; use kurisu_api::SHA256; -use lektor_utils::log; use lektor_utils::pushvec::*; use std::cell::RefCell; -use std::sync::{atomic::AtomicU64, Arc}; +use std::sync::{ + atomic::{AtomicU64, Ordering}, + Arc, +}; /// A pool handle. Used to add new karas to the pool. The update logic follows the following: /// - if a kara was not present, we add it and we download the file. @@ -116,11 +118,13 @@ impl<'a, Storage: DatabaseStorage> UpdateHandler<'a, Storage> { Some(old_kara) if !kara.same_file_as(old_kara) => { doit(kara, &self.new_epoch).await // The file has changed } - None => doit(kara, &self.new_epoch).await, // Not present last time - Some(_) => reuse(kara, &self.new_epoch), // Present last time, but we use the new - // built kara because some informations - // might have been updated even if the - // epoch was not incremented. + + // Not present last time + None => doit(kara, &self.new_epoch).await, + + // Present last time, but we use the new built kara because some informations might + // have been updated even if the epoch was not incremented. + Some(_) => reuse(kara, &self.new_epoch), }, } } @@ -136,26 +140,19 @@ impl<'a, Storage: DatabaseStorage> UpdateHandler<'a, Storage> { 'b: 'a, { // Convert data from V2 API. Create a local ID if needed. - let (id, rkid) = self - .pool + let (id, rkid) = (self.pool) .get_from_remote(unsafe { RemoteKId::new_raw(kara.id, repo) }) .await; let id = match id { Some(id) => id, - None => { - let max = self - .last_kid - .fetch_add(1, std::sync::atomic::Ordering::SeqCst); + None => unsafe { self.pool - .get_str::<KId>(unsafe { KId::new_raw(max, kara.file_hash) }) + .get_str::<KId>(KId::new_raw( + self.last_kid.fetch_add(1, Ordering::SeqCst), + kara.file_hash, + )) .await - } - }; - - let timestamps = KaraTimeStamps { - created_at: kara.created_at, - updated_at: kara.updated_at, - epoch: kara.epoch, + }, }; let get_str = |str| self.pool.get_str::<Arc<str>>(str); @@ -163,10 +160,6 @@ impl<'a, Storage: DatabaseStorage> UpdateHandler<'a, Storage> { join_all(kara.language.into_iter().map(get_str)), join_all(kara.kara_makers.into_iter().map(get_str)) ); - let (language, kara_makers) = ( - language.into_iter().collect(), - kara_makers.into_iter().collect(), - ); let mut tags = HashMap::<Arc<str>, Vec<Arc<str>>>::default(); for [key, value] in kara.tags { @@ -178,26 +171,31 @@ impl<'a, Storage: DatabaseStorage> UpdateHandler<'a, Storage> { } } - let kara_status = match kara.is_virtual { - true => KaraStatus::Virtual, - false => KaraStatus::Physical { - filesize: kara.filesize, - hash: kara.file_hash, - }, - }; + let kurisu_api::v2::Kara { + file_hash: hash, + filesize, + .. + } = kara; self.add_kara(Kara { - id: id.clone(), + id, + tags, remote: rkid, + song_type: kara.song_type, song_title: kara.song_title, song_source: kara.song_source, - kara_makers, - song_type: kara.song_type, song_origin: kara.song_origin, - language, - timestamps, - kara_status, - tags, + language: language.into_iter().collect(), + kara_makers: kara_makers.into_iter().collect(), + timestamps: KaraTimeStamps { + created_at: kara.created_at, + updated_at: kara.updated_at, + epoch: kara.epoch, + }, + kara_status: match kara.is_virtual { + true => KaraStatus::Virtual, + false => KaraStatus::Physical { filesize, hash }, + }, }) .await } diff --git a/lektor_nkdb/src/lib.rs b/lektor_nkdb/src/lib.rs index f501a002..e0d164a2 100644 --- a/lektor_nkdb/src/lib.rs +++ b/lektor_nkdb/src/lib.rs @@ -17,7 +17,7 @@ use futures::{ StreamExt, }; use hashbrown::HashMap; -use lektor_utils::{log, pushvec::*}; +use lektor_utils::pushvec::*; use playlist::Playlists; use serde::{Deserialize, Serialize}; use std::ops::{RangeBounds, RangeFull}; diff --git a/lektor_nkdb/src/playlist/infos.rs b/lektor_nkdb/src/playlist/infos.rs index 50ccf97a..e08b0fc7 100644 --- a/lektor_nkdb/src/playlist/infos.rs +++ b/lektor_nkdb/src/playlist/infos.rs @@ -1,4 +1,3 @@ -use lektor_utils::log; use serde::{Deserialize, Serialize}; /// Informations about a playlist. @@ -15,49 +14,28 @@ pub struct PlaylistInfo { pub updated_at: i64, } -/// Builder pattern to construct a new playlist. -#[derive(Default)] -pub struct Builder { - user: Option<String>, - created_at: Option<i64>, - updated_at: Option<i64>, -} - -impl From<Builder> for PlaylistInfo { - fn from(value: Builder) -> Self { - let now = chrono::Utc::now().timestamp(); - PlaylistInfo { - user: value.user, - created_at: value.created_at.unwrap_or(now), - updated_at: value.updated_at.unwrap_or(now), +impl PlaylistInfo { + pub fn new() -> Self { + Self { + user: None, + created_at: chrono::Utc::now().timestamp(), + updated_at: chrono::Utc::now().timestamp(), } } -} - -impl Builder { - pub fn user(mut self, user: impl ToString) -> Self { - self.user = Some(user.to_string()); - self - } - - pub fn created_at(mut self, created_at: i64) -> Self { - self.created_at = Some(created_at); - self - } - pub fn updated_at(mut self, updated_at: i64) -> Self { - self.updated_at = Some(updated_at); - self + pub fn user(self, user: impl ToString) -> Self { + Self { + user: Some(user.to_string()), + ..self + } } - pub fn build(self) -> PlaylistInfo { - self.into() + pub fn created_at(self, created_at: i64) -> Self { + Self { created_at, ..self } } -} -impl PlaylistInfo { - pub fn builder() -> Builder { - Default::default() + pub fn updated_at(self, updated_at: i64) -> Self { + Self { updated_at, ..self } } /// Should a user be authorized to modify a playlist? @@ -66,12 +44,10 @@ impl PlaylistInfo { if admin { log::warn!("bypass author on playlist request by admin {name}"); } - let user_ok = self - .user - .as_ref() - .map(|user| user.eq(name)) - .unwrap_or_default(); - let ret = admin || user_ok; + let ret = admin + || (self.user.as_ref()) + .map(|user| user.eq(name)) + .unwrap_or_default(); if ret { log::info!("authorize {name} to edit playlist"); } else { @@ -80,3 +56,9 @@ impl PlaylistInfo { ret } } + +impl Default for PlaylistInfo { + fn default() -> Self { + Self::new() + } +} diff --git a/lektor_nkdb/src/playlist/register.rs b/lektor_nkdb/src/playlist/register.rs index a85aaaf8..85664188 100644 --- a/lektor_nkdb/src/playlist/register.rs +++ b/lektor_nkdb/src/playlist/register.rs @@ -4,7 +4,6 @@ use crate::{DatabaseStorage, KId, Playlist, PlaylistInfo, PlaylistName}; use anyhow::{anyhow, bail, Result}; use hashbrown::{hash_map::OccupiedEntry, HashMap}; -use lektor_utils::log; use rand::{seq::SliceRandom, thread_rng}; use std::ops::Deref; use tokio::sync::RwLock; @@ -75,16 +74,14 @@ impl PlaylistsContent { admin: bool, cb: impl FnOnce(&mut Playlist) -> Result<T>, ) -> Result<T> { - if let Some(playlist) = self.0.get_mut(name.as_ref()) { - if playlist.authorize_write(user.as_ref(), admin) { - cb(playlist) - } else { - let (name, user) = (name.as_ref(), user.as_ref()); - bail!("user {user} is not authorized to write playlist {name}") - } - } else { - let (name, user) = (name.as_ref(), user.as_ref()); + let (name, user) = (name.as_ref(), user.as_ref()); + let Some(playlist) = self.0.get_mut(name) else { bail!("playlist {name} asked by user {user} doesn't exist") + }; + if playlist.authorize_write(user, admin) { + cb(playlist) + } else { + bail!("user {user} is not authorized to write playlist {name}") } } @@ -97,20 +94,17 @@ impl PlaylistsContent { admin: bool, cb: impl FnOnce(OccupiedEntry<'_, PlaylistName, Playlist>) -> Result<T>, ) -> Result<T> { + use hashbrown::hash_map::Entry; + let user = user.as_ref(); match self.0.entry(name.into()) { - hashbrown::hash_map::Entry::Occupied(entry) - if entry.get().authorize_write(user.as_ref(), admin) => - { - cb(entry) - } - hashbrown::hash_map::Entry::Occupied(entry) => { + Entry::Occupied(entry) if entry.get().authorize_write(user, admin) => cb(entry), + Entry::Occupied(entry) => { bail!( - "user {} is not authorized to write playlist {}", - user.as_ref(), + "user {user} is not authorized to write playlist {}", entry.key() ) } - hashbrown::hash_map::Entry::Vacant(entry) => { + Entry::Vacant(entry) => { bail!("failed to get playlist {}", entry.key()) } } @@ -283,24 +277,16 @@ impl_playlists! { /// Get the content of a playlist, we need to clone because of the lock... read fn get_content(&self, name: impl AsRef<str>) -> Option<Vec<KId>> { - match self.0.get(name.as_ref()) { - Some(plt) => Some(plt.content().to_vec()), - None => { - log::error!("playlist {} doesn't exist", name.as_ref()); - None - } - } + let res = self.0.get(name.as_ref()).map(|plt| plt.content().to_vec()); + if res.is_none() { log::error!("playlist {} doesn't exist", name.as_ref()); } + res } /// Count the number of elements in the playlist. If the playlist didn't exist returns [None], /// otherwise returns [Some] of the count. read fn count_playlist(&self, name: impl AsRef<str>) -> Option<usize> { - match self.0.get(name.as_ref()) { - Some(plt) => Some(plt.content().len()), - None => { - log::error!("playlist {} doesn't exist", name.as_ref()); - None - } - } + let res = self.0.get(name.as_ref()).map(|plt| plt.content().len()); + if res.is_none() { log::error!("playlist {} doesn't exist", name.as_ref()); } + res } } diff --git a/lektor_nkdb/src/playlist/values.rs b/lektor_nkdb/src/playlist/values.rs index 3b46ba65..67611570 100644 --- a/lektor_nkdb/src/playlist/values.rs +++ b/lektor_nkdb/src/playlist/values.rs @@ -4,7 +4,7 @@ use crate::{KId, PlaylistInfo}; use serde::{Deserialize, Serialize}; /// The playlist, with the informations and its content. -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Default)] pub struct Playlist { /// Metadata about the playlist. pub(crate) infos: PlaylistInfo, @@ -19,7 +19,7 @@ impl From<PlaylistInfo> for Playlist { fn from(infos: PlaylistInfo) -> Self { Self { infos, - content: Default::default(), + ..Default::default() } } } diff --git a/lektor_nkdb/src/queue/mod.rs b/lektor_nkdb/src/queue/mod.rs index dd81091a..4ae27535 100644 --- a/lektor_nkdb/src/queue/mod.rs +++ b/lektor_nkdb/src/queue/mod.rs @@ -6,7 +6,7 @@ mod priority; pub use priority::*; use crate::*; -use lektor_utils::{filter_range, log, BoundedBoundRange}; +use lektor_utils::{filter_range, BoundedBoundRange}; use rand::{seq::SliceRandom, thread_rng}; use std::ops::RangeInclusive; use tokio::sync::RwLock; @@ -210,9 +210,9 @@ impl_queue! { /// Returns the number of elements in each level of the queue read fn queue_count_per_level(&self) -> [usize; PRIORITY_LENGTH] { - [ self.queue[Priority::Add.index()].len() + [ self.queue[Priority::Add .index()].len() , self.queue[Priority::Suggest.index()].len() - , self.queue[Priority::Insert.index()].len() + , self.queue[Priority::Insert .index()].len() , self.queue[Priority::Enforce.index()].len() ] } @@ -225,6 +225,7 @@ impl_queue! { /// Insert something into one priority of the queue. write fn insert_slice(&self, prio: Priority, kara: &[KId]) { let level = &mut self.queue[prio.index()]; + level.reserve(kara.len()); kara.iter().rev().for_each(|id| level.insert(0, id.clone())); } diff --git a/lektor_nkdb/src/search/kara_by.rs b/lektor_nkdb/src/search/kara_by.rs index f0fbf825..21fe3b15 100644 --- a/lektor_nkdb/src/search/kara_by.rs +++ b/lektor_nkdb/src/search/kara_by.rs @@ -2,7 +2,7 @@ use crate::*; use lektor_utils::either; use regex::{Regex, RegexBuilder}; use serde::{Deserialize, Serialize}; -use std::{borrow::Cow, convert::Infallible, str::FromStr}; +use std::{borrow::Cow, convert::Infallible, fmt, str::FromStr}; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub enum KaraBy { @@ -42,10 +42,10 @@ fn build_regex_for_cow(value: Cow<'_, str>) -> Result<Regex> { .build()?) } -impl ToString for KaraBy { - fn to_string(&self) -> String { +impl fmt::Display for KaraBy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let str: Cow<str> = self.into(); - str.to_string() + f.write_str(&str) } } diff --git a/lektor_nkdb/src/storage/disk_storage.rs b/lektor_nkdb/src/storage/disk_storage.rs index 587e83e8..85543be1 100644 --- a/lektor_nkdb/src/storage/disk_storage.rs +++ b/lektor_nkdb/src/storage/disk_storage.rs @@ -11,7 +11,7 @@ use kurisu_api::SHA256; use regex::Regex; use std::{ path::{Path, PathBuf}, - sync::{atomic::AtomicU64, Arc, OnceLock}, + sync::{atomic::AtomicU64, Arc, LazyLock}, }; use tokio::{ fs::{create_dir_all, read, read_dir, write, OpenOptions}, @@ -46,32 +46,30 @@ enum PlaylistWriteEvent { Delete(Arc<str>), } +macro_rules! regex { + ($regex:literal) => { + LazyLock::new(|| Regex::new($regex).unwrap()) + }; +} + fn get_regex_epoch_ok() -> &'static Regex { - static REGEX: OnceLock<Regex> = OnceLock::new(); - REGEX.get_or_init(|| { - Regex::new(r"^([0123456789]+).ok$").expect("failed to build epoch_ok regex") - }) + static REGEX: LazyLock<Regex> = regex!(r"^([0123456789]+).ok$"); + ®EX } fn get_regex_epoch_json() -> &'static Regex { - static REGEX: OnceLock<Regex> = OnceLock::new(); - REGEX.get_or_init(|| { - Regex::new(r"^([0123456789]+).json$").expect("failed to build epoch_json regex") - }) + static REGEX: LazyLock<Regex> = regex!(r"^([0123456789]+).json$"); + ®EX } fn get_regex_playlist_ok() -> &'static Regex { - static REGEX: OnceLock<Regex> = OnceLock::new(); - REGEX.get_or_init(|| { - Regex::new(r"^([a-zA-Z0123456789]+).ok$").expect("failed to build playlist_ok regex") - }) + static REGEX: LazyLock<Regex> = regex!(r"^([a-zA-Z0123456789]+).ok$"); + ®EX } fn get_regex_playlist_json() -> &'static Regex { - static REGEX: OnceLock<Regex> = OnceLock::new(); - REGEX.get_or_init(|| { - Regex::new(r"^([a-zA-Z0123456789]+).json$").expect("failed to build playlist_json regex") - }) + static REGEX: LazyLock<Regex> = regex!(r"^([a-zA-Z0123456789]+).json$"); + ®EX } impl DatabaseDiskStorage { @@ -153,8 +151,8 @@ impl DatabaseDiskStorage { where 'a: 'b, { - let folder = folder.as_ref(); Ok(stream::iter(set.into_iter().map(|item| { + let folder = folder.as_ref(); let json = self.path_from_root(format!("{folder}/{item}.json")); let ok = self.path_from_root(format!("{folder}/{item}.ok")); (json, ok, item) @@ -389,13 +387,13 @@ impl DatabaseStorage for DatabaseDiskStorage { } async fn write_kara(&self, (_, file): &mut Self::File, data: &[u8]) -> Result<()> { - let _kib = file.write(data).await? / 2024; + let _ = file.write(data).await?; Ok(()) } async fn submit_kara(&self, (path, _): Self::File, id: KId, hash: SHA256) -> Result<()> { let digest = SHA256::try_from(sha256::try_async_digest(&path).await?).unwrap(); - let path = path.to_string_lossy(); + let path = path.display(); if digest != hash { bail!("invalid digest for {path}, expected {hash}, got {digest}",) } @@ -405,9 +403,6 @@ impl DatabaseStorage for DatabaseDiskStorage { fn get_kara_uri(&self, id: KId) -> Result<url::Url> { let path = self.path_from_root(format!("data/{}.mkv", id.path())); - Ok(url::Url::parse(&format!( - "file://{}", - path.to_string_lossy() - ))?) + Ok(url::Url::parse(&format!("file://{}", path.display()))?) } } diff --git a/lektor_payloads/src/lib.rs b/lektor_payloads/src/lib.rs index 33964b83..3ad79de1 100644 --- a/lektor_payloads/src/lib.rs +++ b/lektor_payloads/src/lib.rs @@ -12,7 +12,7 @@ pub use lektor_nkdb::{ RemoteKId, SearchFrom, SongOrigin, SongType, PRIORITY_LENGTH, PRIORITY_VALUES, }; -use anyhow::{anyhow, bail}; +use anyhow::{anyhow, ensure}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] @@ -85,23 +85,16 @@ pub enum PlaylistUpdateAction { impl std::str::FromStr for AddArguments { type Err = anyhow::Error; fn from_str(s: &str) -> Result<Self, Self::Err> { - fn parse_query(level: Priority, query: &str) -> AddArguments { - let query = query.parse().unwrap(); - AddArguments { level, query } + ensure!(!s.is_empty(), "the string is empty"); + match s.split_once(' ') { + Some((lvl, query)) => Ok(AddArguments { + level: lvl.parse().map_err(|err| anyhow!("{err}"))?, + query: query.parse()?, + }), + None => Ok(AddArguments { + level: Priority::Add, + query: s.parse()?, + }), } - - if s.is_empty() { - bail!("the string is empty"); - } - - Ok(match s.split_once(' ') { - Some((lvl, query)) => { - let lvl = lvl - .parse() - .map_err(|err| anyhow!("the value is not a correct queue level: {err}"))?; - parse_query(lvl, query) - } - None => parse_query(Priority::Add, s), - }) } } diff --git a/lektor_procmacros/src/getset/generate.rs b/lektor_procmacros/src/getset/generate.rs deleted file mode 100644 index 95a2f319..00000000 --- a/lektor_procmacros/src/getset/generate.rs +++ /dev/null @@ -1,141 +0,0 @@ -use self::GenMode::*; -use super::{parse_attr, quote}; -use proc_macro2::TokenStream as TokenStream2; -use proc_macro2::{Ident, Span}; -use proc_macro_error::abort; -use syn::MetaList; -use syn::{ext::IdentExt, spanned::Spanned, Field, Meta}; - -pub struct GenParams { - pub mode: GenMode, - pub global_attr: Option<Meta>, -} - -#[derive(PartialEq, Eq, Copy, Clone)] -pub enum GenMode { - Get, - GetCopy, - Set, - GetMut, -} - -impl GenMode { - pub fn name(self) -> &'static str { - match self { - Get => "get", - GetCopy => "get_copy", - Set => "set", - GetMut => "get_mut", - } - } - - pub fn prefix(self) -> &'static str { - match self { - Get | GetCopy | GetMut => "", - Set => "set_", - } - } - - pub fn suffix(self) -> &'static str { - match self { - Get | GetCopy | Set => "", - GetMut => "_mut", - } - } - - pub fn is_get(self) -> bool { - match self { - Get | GetCopy | GetMut => true, - Set => false, - } - } -} - -pub fn implement(field: &Field, params: &GenParams) -> TokenStream2 { - let field_name = field - .ident - .as_ref() - .unwrap_or_else(|| abort!(field.span(), "Expected the field to have a name")); - - let fn_name = if params.mode.is_get() - && params.mode.suffix().is_empty() - && field_name.to_string().starts_with("r#") - { - field_name.clone() - } else { - Ident::new( - &format!( - "{}{}{}", - params.mode.prefix(), - field_name.unraw(), - params.mode.suffix() - ), - Span::call_site(), - ) - }; - let ty = field.ty.clone(); - - let doc = field.attrs.iter().filter(|v| { - // The syn 1 code: - // v.parse_meta() - // .map(|meta| meta.path().is_ident("doc")) - // .unwrap_or(false) - match v.meta { - Meta::NameValue(_) => false, - Meta::List(MetaList { ref path, .. }) | Meta::Path(ref path) => path.is_ident("doc"), - } - }); - - let attr = field - .attrs - .iter() - .filter_map(|v| parse_attr(v, params.mode)) - .last() - .or_else(|| params.global_attr.clone()); - - match attr { - // Generate nothing for skipped field. - Some(meta) if meta.path().is_ident("skip") => quote! {}, - Some(_) => match params.mode { - GenMode::Get => { - quote! { - #(#doc)* - #[inline(always)] - pub fn #fn_name(&self) -> &#ty { - &self.#field_name - } - } - } - GenMode::GetCopy => { - quote! { - #(#doc)* - #[inline(always)] - pub fn #fn_name(&self) -> #ty { - self.#field_name - } - } - } - GenMode::Set => { - quote! { - #(#doc)* - #[inline(always)] - pub fn #fn_name(&mut self, val: #ty) -> &mut Self { - self.#field_name = val; - self - } - } - } - GenMode::GetMut => { - quote! { - #(#doc)* - #[inline(always)] - pub fn #fn_name(&mut self) -> &mut #ty { - &mut self.#field_name - } - } - } - }, - // Don't need to do anything. - None => quote! {}, - } -} diff --git a/lektor_procmacros/src/getset/mod.rs b/lektor_procmacros/src/getset/mod.rs deleted file mode 100644 index 04a0ed44..00000000 --- a/lektor_procmacros/src/getset/mod.rs +++ /dev/null @@ -1,234 +0,0 @@ -/*! -Getset, we're ready to go! - -A procedural macro for generating the most basic getters and setters on fields. Getters are -generated as `fn field(&self) -> &type`, while setters are generated as `fn field(&mut self, val: -type)`. These macros are not intended to be used on fields which require custom logic inside of -their setters and getters. Just write your own in that case! - -```rust -use lektor_procmacros::{CopyGetters, Getters, MutGetters, Setters}; - -#[derive(Getters, Setters, MutGetters, CopyGetters, Default)] -pub struct Foo<T> -where - T: Copy + Clone + Default, -{ - /// Doc comments are supported! - /// Multiline, even. - #[getset(get, set, get_mut)] - private: T, - - /// Doc comments are supported! - /// Multiline, even. - #[getset(get_copy, set, get_mut)] - public: T, -} - -let mut foo = Foo::default(); -foo.set_private(1); -(*foo.private_mut()) += 1; -assert_eq!(*foo.private(), 2); -``` - -You can use `cargo-expand` to generate the output. Here are the functions that the above generates (Replicate with `cargo expand --example simple`): - -```rust,ignore -use getset::{Getters, MutGetters, CopyGetters, Setters}; -pub struct Foo<T> -where - T: Copy + Clone + Default, -{ - /// Doc comments are supported! - /// Multiline, even. - #[getset(get, get, get_mut)] - private: T, - /// Doc comments are supported! - /// Multiline, even. - #[getset(get_copy, set, get_mut)] - public: T, -} -impl<T> Foo<T> -where - T: Copy + Clone + Default, -{ - /// Doc comments are supported! - /// Multiline, even. - #[inline(always)] - fn private(&self) -> &T { - &self.private - } -} -impl<T> Foo<T> -where - T: Copy + Clone + Default, -{ - /// Doc comments are supported! - /// Multiline, even. - #[inline(always)] - pub fn set_public(&mut self, val: T) -> &mut Self { - self.public = val; - self - } -} -impl<T> Foo<T> -where - T: Copy + Clone + Default, -{ - /// Doc comments are supported! - /// Multiline, even. - #[inline(always)] - fn private_mut(&mut self) -> &mut T { - &mut self.private - } - /// Doc comments are supported! - /// Multiline, even. - #[inline(always)] - pub fn public_mut(&mut self) -> &mut T { - &mut self.public - } -} -impl<T> Foo<T> -where - T: Copy + Clone + Default, -{ - /// Doc comments are supported! - /// Multiline, even. - #[inline(always)] - pub fn public(&self) -> T { - self.public - } -} -``` - -Skipping setters and getters generation for a field when struct level attribute is used -is possible with `#[getset(skip)]`. - -```rust -use lektor_procmacros::{CopyGetters, Setters}; - -#[derive(CopyGetters, Setters)] -#[getset(get_copy, set)] -pub struct Foo { - // If the field was not skipped, the compiler would complain about moving - // a non-copyable type in copy getter. - #[getset(skip)] - skipped: String, - - field1: usize, - field2: usize, -} - -impl Foo { - // It is possible to write getters and setters manually, - // possibly with a custom logic. - fn skipped(&self) -> &str { - &self.skipped - } - - fn set_skipped(&mut self, val: &str) -> &mut Self { - self.skipped = val.to_string(); - self - } -} -``` -*/ - -pub mod generate; - -use crate::getset::generate::{GenMode, GenParams}; -use proc_macro2::TokenStream as TokenStream2; -use proc_macro_error::{abort, abort_call_site}; -use quote::quote; -use syn::{spanned::Spanned, DataStruct, DeriveInput, Meta, MetaList}; - -pub fn parse_global_attr(attrs: &[syn::Attribute], mode: GenMode) -> Option<Meta> { - attrs - .iter() - .filter_map(|v| parse_attr(v, mode)) // non "meta" attributes are not our concern - .last() -} - -fn parse_attr(attr: &syn::Attribute, mode: GenMode) -> Option<Meta> { - use syn::{punctuated::Punctuated, Token}; - - if attr.path().is_ident("getset") { - let (last, skip, mut collected) = attr - .parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated) - .expect("failed to parse the getset attr") - .into_iter() - .inspect(|meta| { - if !(meta.path().is_ident("get") - || meta.path().is_ident("get_copy") - || meta.path().is_ident("get_mut") - || meta.path().is_ident("set") - || meta.path().is_ident("skip")) - { - abort!(meta.path().span(), "unknown setter or getter") - } - }) - .fold( - (None, None, Vec::new()), - |(last, skip, mut collected), meta| { - if meta.path().is_ident(mode.name()) { - (Some(meta), skip, collected) - } else if meta.path().is_ident("skip") { - (last, Some(meta), collected) - } else { - // Store inapplicable item for potential error message - // if used with skip. - collected.push(meta); - (last, skip, collected) - } - }, - ); - - if skip.is_some() { - // Check if there is any setter or getter used with skip, which is - // forbidden. - if last.is_none() && collected.is_empty() { - skip - } else { - abort!( - last.or_else(|| collected.pop()).unwrap().path().span(), - "use of setters and getters with skip is invalid" - ); - } - } else { - // If skip is not used, return the last occurrence of matching - // setter/getter, if there is any. - last - } - } else { - // The syn 1 code: - // attr.parse_meta() - // .ok() - // .filter(|meta| meta.path().is_ident(mode.name())); - match attr.meta { - Meta::NameValue(_) => None, - Meta::List(MetaList { ref path, .. }) | Meta::Path(ref path) => { - path.is_ident(mode.name()).then_some(attr.meta.clone()) - } - } - } -} - -pub fn produce(ast: &DeriveInput, params: &GenParams) -> TokenStream2 { - let name = &ast.ident; - let generics = &ast.generics; - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - - // Is it a struct? - if let syn::Data::Struct(DataStruct { ref fields, .. }) = ast.data { - let generated = fields.iter().map(|f| generate::implement(f, params)); - - quote! { - impl #impl_generics #name #ty_generics #where_clause { - #(#generated)* - } - } - } else { - // Nope. This is an Enum. We cannot handle these! - abort_call_site!("#[derive(Getters)] is only defined for structs, not for enums!"); - } -} diff --git a/lektor_procmacros/src/lib.rs b/lektor_procmacros/src/lib.rs index add6a66e..7a47c9e2 100644 --- a/lektor_procmacros/src/lib.rs +++ b/lektor_procmacros/src/lib.rs @@ -3,52 +3,6 @@ use proc_macro_error::proc_macro_error; use syn::{parse_macro_input, DeriveInput}; mod enums; -mod getset; -use crate::getset::generate::{GenMode as GetSetGenMode, GenParams as GetSetGenParams}; - -#[proc_macro_derive(Getters, attributes(get, with_prefix, getset))] -#[proc_macro_error] -pub fn getters(input: TokenStream) -> TokenStream { - let ast: DeriveInput = syn::parse(input).expect("couldn't parse for getters"); - let params = GetSetGenParams { - mode: GetSetGenMode::Get, - global_attr: getset::parse_global_attr(&ast.attrs, GetSetGenMode::Get), - }; - getset::produce(&ast, ¶ms).into() -} - -#[proc_macro_derive(CopyGetters, attributes(get_copy, with_prefix, getset))] -#[proc_macro_error] -pub fn copy_getters(input: TokenStream) -> TokenStream { - let ast: DeriveInput = syn::parse(input).expect("couldn't parse for getters"); - let params = GetSetGenParams { - mode: GetSetGenMode::GetCopy, - global_attr: getset::parse_global_attr(&ast.attrs, GetSetGenMode::GetCopy), - }; - getset::produce(&ast, ¶ms).into() -} - -#[proc_macro_derive(MutGetters, attributes(get_mut, getset))] -#[proc_macro_error] -pub fn mut_getters(input: TokenStream) -> TokenStream { - let ast: DeriveInput = syn::parse(input).expect("couldn't parse for getters"); - let params = GetSetGenParams { - mode: GetSetGenMode::GetMut, - global_attr: getset::parse_global_attr(&ast.attrs, GetSetGenMode::GetMut), - }; - getset::produce(&ast, ¶ms).into() -} - -#[proc_macro_derive(Setters, attributes(set, getset))] -#[proc_macro_error] -pub fn setters(input: TokenStream) -> TokenStream { - let ast: DeriveInput = syn::parse(input).expect("couldn't parse for setters"); - let params = GetSetGenParams { - mode: GetSetGenMode::Set, - global_attr: getset::parse_global_attr(&ast.attrs, GetSetGenMode::Set), - }; - getset::produce(&ast, ¶ms).into() -} #[proc_macro_derive(EnumVariantCount)] #[proc_macro_error] diff --git a/lektor_procmacros/tests/copy_getters.rs b/lektor_procmacros/tests/copy_getters.rs deleted file mode 100644 index 4cf8da0d..00000000 --- a/lektor_procmacros/tests/copy_getters.rs +++ /dev/null @@ -1,149 +0,0 @@ -#[macro_use] -extern crate lektor_procmacros; - -use crate::submodule::other::{Generic, Plain, Where}; - -// For testing `pub(super)` -mod submodule { - // For testing `pub(super::other)` - pub mod other { - #[derive(CopyGetters)] - #[get_copy] - pub struct Plain { - /// A doc comment. - /// Multiple lines, even. - private_accessible: usize, - - /// A doc comment. - #[get_copy = "pub"] - public_accessible: usize, - // /// A doc comment. - // #[get_copy = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[get_copy = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[get_copy = "pub(super::other)"] - // scope_accessible: usize, - - // Prefixed getter. - #[get_copy = "with_prefix"] - private_prefixed: usize, - - // Prefixed getter. - #[get_copy = "pub with_prefix"] - public_prefixed: usize, - } - - impl Default for Plain { - fn default() -> Plain { - Plain { - private_accessible: 17, - public_accessible: 18, - private_prefixed: 19, - public_prefixed: 20, - } - } - } - - #[derive(CopyGetters, Default)] - #[get_copy] - pub struct Generic<T: Copy + Clone + Default> { - /// A doc comment. - /// Multiple lines, even. - private_accessible: T, - - /// A doc comment. - #[get_copy = "pub"] - public_accessible: T, - // /// A doc comment. - // #[get_copy = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[get_copy = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[get_copy = "pub(super::other)"] - // scope_accessible: usize, - } - - #[derive(CopyGetters, Getters, Default)] - #[get_copy] - pub struct Where<T> - where - T: Copy + Clone + Default, - { - /// A doc comment. - /// Multiple lines, even. - private_accessible: T, - - /// A doc comment. - #[get_copy = "pub"] - public_accessible: T, - // /// A doc comment. - // #[get_copy = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[get_copy = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[get_copy = "pub(super::other)"] - // scope_accessible: usize, - } - - #[test] - fn test_plain() { - let val = Plain::default(); - val.private_accessible(); - } - - #[test] - fn test_generic() { - let val = Generic::<usize>::default(); - val.private_accessible(); - } - - #[test] - fn test_where() { - let val = Where::<usize>::default(); - val.private_accessible(); - } - - #[test] - fn test_prefixed_plain() { - let val = Plain::default(); - assert_eq!(19, val.private_prefixed()); - } - } -} - -#[test] -fn test_plain() { - let val = Plain::default(); - assert_eq!(18, val.public_accessible()); -} - -#[test] -fn test_generic() { - let val = Generic::<usize>::default(); - assert_eq!(usize::default(), val.public_accessible()); -} - -#[test] -fn test_where() { - let val = Where::<usize>::default(); - assert_eq!(usize::default(), val.public_accessible()); -} - -#[test] -fn test_prefixed_plain() { - let val = Plain::default(); - assert_eq!(20, val.public_prefixed()); -} diff --git a/lektor_procmacros/tests/getset.rs b/lektor_procmacros/tests/getset.rs deleted file mode 100644 index ba768e2c..00000000 --- a/lektor_procmacros/tests/getset.rs +++ /dev/null @@ -1,121 +0,0 @@ -#[macro_use] -extern crate lektor_procmacros; - -use crate::submodule::other::{Generic, Plain, Where}; - -// For testing `pub(super)` -mod submodule { - // For testing `pub(in super::other)` - pub mod other { - #[derive(MutGetters, Getters, Default)] - #[getset(get_mut)] - pub struct Plain { - /// A doc comment. - /// Multiple lines, even. - private_accessible: usize, - - /// A doc comment. - #[getset(get = "pub", get_mut = "pub")] - public_accessible: usize, - // /// A doc comment. - // #[get_mut = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[get_mut = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[get_mut = "pub(in super::other)"] - // scope_accessible: usize, - } - - #[derive(MutGetters, Getters, Default)] - #[getset(get_mut)] - pub struct Generic<T: Copy + Clone + Default> { - /// A doc comment. - /// Multiple lines, even. - private_accessible: T, - - /// A doc comment. - #[getset(get = "pub", get_mut = "pub")] - public_accessible: T, - // /// A doc comment. - // #[get_mut = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[get_mut = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[get_mut = "pub(in super::other)"] - // scope_accessible: usize, - } - - #[derive(MutGetters, Getters, Default)] - #[getset(get_mut)] - pub struct Where<T> - where - T: Copy + Clone + Default, - { - /// A doc comment. - /// Multiple lines, even. - private_accessible: T, - - /// A doc comment. - #[getset(get = "pub", get_mut = "pub")] - public_accessible: T, - // /// A doc comment. - // #[get_mut = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[get_mut = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[get_mut = "pub(in super::other)"] - // scope_accessible: usize, - } - - #[test] - fn test_plain() { - let mut val = Plain::default(); - (*val.private_accessible_mut()) += 1; - } - - #[test] - fn test_generic() { - let mut val = Generic::<usize>::default(); - (*val.private_accessible_mut()) += 1; - } - - #[test] - fn test_where() { - let mut val = Where::<usize>::default(); - (*val.private_accessible_mut()) += 1; - } - } -} - -#[test] -fn test_plain() { - let mut val = Plain::default(); - let _ = val.public_accessible(); - (*val.public_accessible_mut()) += 1; -} - -#[test] -fn test_generic() { - let mut val = Generic::<usize>::default(); - let _ = val.public_accessible(); - (*val.public_accessible_mut()) += 1; -} - -#[test] -fn test_where() { - let mut val = Where::<usize>::default(); - let _ = val.public_accessible(); - (*val.public_accessible_mut()) += 1; -} diff --git a/lektor_procmacros/tests/getters.rs b/lektor_procmacros/tests/getters.rs deleted file mode 100644 index 6fbde234..00000000 --- a/lektor_procmacros/tests/getters.rs +++ /dev/null @@ -1,147 +0,0 @@ -#[macro_use] -extern crate lektor_procmacros; - -use crate::submodule::other::{Generic, Plain, Where}; - -// For testing `pub(super)` -mod submodule { - // For testing `pub(super::other)` - pub mod other { - #[derive(Getters)] - #[get] - pub struct Plain { - /// A doc comment. - /// Multiple lines, even. - private_accessible: usize, - - /// A doc comment. - #[get = "pub"] - public_accessible: usize, - // /// A doc comment. - // #[get = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[get = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[get = "pub(super::other)"] - // scope_accessible: usize, - #[get] - private_prefixed: usize, - - // Prefixed getter. - #[get = "pub"] - public_prefixed: usize, - } - - impl Default for Plain { - fn default() -> Plain { - Plain { - private_accessible: 17, - public_accessible: 18, - private_prefixed: 19, - public_prefixed: 20, - } - } - } - - #[derive(Getters, Default)] - #[get] - pub struct Generic<T: Copy + Clone + Default> { - /// A doc comment. - /// Multiple lines, even. - private_accessible: T, - - /// A doc comment. - #[get = "pub(crate)"] - public_accessible: T, - // /// A doc comment. - // #[get = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[get = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[get = "pub(super::other)"] - // scope_accessible: usize, - } - - #[derive(Getters, Default)] - #[get] - pub struct Where<T> - where - T: Copy + Clone + Default, - { - /// A doc comment. - /// Multiple lines, even. - private_accessible: T, - - /// A doc comment. - #[get = "pub"] - public_accessible: T, - // /// A doc comment. - // #[get = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[get = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[get = "pub(super::other)"] - // scope_accessible: usize, - } - - #[test] - fn test_plain() { - let val = Plain::default(); - val.private_accessible(); - } - - #[test] - fn test_generic() { - let val = Generic::<usize>::default(); - val.private_accessible(); - } - - #[test] - fn test_where() { - let val = Where::<usize>::default(); - val.private_accessible(); - } - - #[test] - fn test_prefixed_plain() { - let val = Plain::default(); - assert_eq!(19, *val.private_prefixed()); - } - } -} - -#[test] -fn test_plain() { - let val = Plain::default(); - assert_eq!(18, *val.public_accessible()); -} - -#[test] -fn test_generic() { - let val = Generic::<usize>::default(); - assert_eq!(usize::default(), *val.public_accessible()); -} - -#[test] -fn test_where() { - let val = Where::<usize>::default(); - assert_eq!(usize::default(), *val.public_accessible()); -} - -#[test] -fn test_prefixed_plain() { - let val = Plain::default(); - assert_eq!(20, *val.public_prefixed()); -} diff --git a/lektor_procmacros/tests/mut_getters.rs b/lektor_procmacros/tests/mut_getters.rs deleted file mode 100644 index b4bae586..00000000 --- a/lektor_procmacros/tests/mut_getters.rs +++ /dev/null @@ -1,118 +0,0 @@ -#[macro_use] -extern crate lektor_procmacros; - -use crate::submodule::other::{Generic, Plain, Where}; - -// For testing `pub(super)` -mod submodule { - // For testing `pub(in super::other)` - pub mod other { - #[derive(MutGetters, Default)] - #[get_mut] - pub struct Plain { - /// A doc comment. - /// Multiple lines, even. - private_accessible: usize, - - /// A doc comment. - #[get_mut = "pub"] - public_accessible: usize, - // /// A doc comment. - // #[get_mut = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[get_mut = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[get_mut = "pub(in super::other)"] - // scope_accessible: usize, - } - - #[derive(MutGetters, Default)] - #[get_mut] - pub struct Generic<T: Copy + Clone + Default> { - /// A doc comment. - /// Multiple lines, even. - private_accessible: T, - - /// A doc comment. - #[get_mut = "pub"] - public_accessible: T, - // /// A doc comment. - // #[get_mut = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[get_mut = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[get_mut = "pub(in super::other)"] - // scope_accessible: usize, - } - - #[derive(MutGetters, Default)] - #[get_mut] - pub struct Where<T> - where - T: Copy + Clone + Default, - { - /// A doc comment. - /// Multiple lines, even. - private_accessible: T, - - /// A doc comment. - #[get_mut = "pub"] - public_accessible: T, - // /// A doc comment. - // #[get_mut = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[get_mut = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[get_mut = "pub(in super::other)"] - // scope_accessible: usize, - } - - #[test] - fn test_plain() { - let mut val = Plain::default(); - (*val.private_accessible_mut()) += 1; - } - - #[test] - fn test_generic() { - let mut val = Generic::<usize>::default(); - (*val.private_accessible_mut()) += 1; - } - - #[test] - fn test_where() { - let mut val = Where::<usize>::default(); - (*val.private_accessible_mut()) += 1; - } - } -} - -#[test] -fn test_plain() { - let mut val = Plain::default(); - (*val.public_accessible_mut()) += 1; -} - -#[test] -fn test_generic() { - let mut val = Generic::<usize>::default(); - (*val.public_accessible_mut()) += 1; -} - -#[test] -fn test_where() { - let mut val = Where::<usize>::default(); - (*val.public_accessible_mut()) += 1; -} diff --git a/lektor_procmacros/tests/raw_identifiers.rs b/lektor_procmacros/tests/raw_identifiers.rs deleted file mode 100644 index 052ecbca..00000000 --- a/lektor_procmacros/tests/raw_identifiers.rs +++ /dev/null @@ -1,57 +0,0 @@ -#[macro_use] -extern crate lektor_procmacros; - -#[derive(CopyGetters, Default, Getters, MutGetters, Setters)] -struct RawIdentifiers { - #[get] - r#type: usize, - #[get_copy] - r#move: usize, - #[get_mut] - r#union: usize, - #[set] - r#enum: usize, - #[get] - r#const: usize, - #[get_copy] - r#if: usize, - // Ensure having no gen mode doesn't break things. - #[allow(dead_code)] - r#loop: usize, -} - -#[test] -fn test_get() { - let val = RawIdentifiers::default(); - let _ = val.r#type(); -} - -#[test] -fn test_get_copy() { - let val = RawIdentifiers::default(); - let _ = val.r#move(); -} - -#[test] -fn test_get_mut() { - let mut val = RawIdentifiers::default(); - let _ = val.union_mut(); -} - -#[test] -fn test_set() { - let mut val = RawIdentifiers::default(); - val.set_enum(42); -} - -#[test] -fn test_get_with_prefix() { - let val = RawIdentifiers::default(); - let _ = val.r#const(); -} - -#[test] -fn test_get_copy_with_prefix() { - let val = RawIdentifiers::default(); - let _ = val.r#if(); -} diff --git a/lektor_procmacros/tests/setters.rs b/lektor_procmacros/tests/setters.rs deleted file mode 100644 index 7aa21288..00000000 --- a/lektor_procmacros/tests/setters.rs +++ /dev/null @@ -1,129 +0,0 @@ -#[macro_use] -extern crate lektor_procmacros; - -use crate::submodule::other::{Generic, Plain, Where}; - -// For testing `pub(super)` -mod submodule { - // For testing `pub(in super::other)` - pub mod other { - #[derive(Setters, Default)] - #[set] - pub struct Plain { - /// A doc comment. - /// Multiple lines, even. - private_accessible: usize, - - /// A doc comment. - #[set = "pub"] - public_accessible: usize, - - /// This field is used for testing chaining. - #[set = "pub"] - second_public_accessible: bool, - // /// A doc comment. - // #[set = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[set = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[set = "pub(in super::other)"] - // scope_accessible: usize, - } - - #[derive(Setters, Default)] - #[set] - pub struct Generic<T: Copy + Clone + Default> { - /// A doc comment. - /// Multiple lines, even. - private_accessible: T, - - /// A doc comment. - #[set = "pub"] - public_accessible: T, - // /// A doc comment. - // #[set = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[set = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[set = "pub(in super::other)"] - // scope_accessible: usize, - } - - #[derive(Setters, Default)] - #[set] - pub struct Where<T> - where - T: Copy + Clone + Default, - { - /// A doc comment. - /// Multiple lines, even. - private_accessible: T, - - /// A doc comment. - #[set = "pub"] - public_accessible: T, - // /// A doc comment. - // #[set = "pub(crate)"] - // crate_accessible: usize, - - // /// A doc comment. - // #[set = "pub(super)"] - // super_accessible: usize, - - // /// A doc comment. - // #[set = "pub(in super::other)"] - // scope_accessible: usize, - } - - #[test] - fn test_plain() { - let mut val = Plain::default(); - val.set_private_accessible(1); - } - - #[test] - fn test_generic() { - let mut val = Generic::default(); - val.set_private_accessible(1); - } - - #[test] - fn test_where() { - let mut val = Where::default(); - val.set_private_accessible(1); - } - } -} - -#[test] -fn test_plain() { - let mut val = Plain::default(); - val.set_public_accessible(1); -} - -#[test] -fn test_generic() { - let mut val = Generic::default(); - val.set_public_accessible(1); -} - -#[test] -fn test_where() { - let mut val = Where::default(); - val.set_public_accessible(1); -} - -#[test] -fn test_chaining() { - let mut val = Plain::default(); - val.set_public_accessible(1) - .set_second_public_accessible(true); -} diff --git a/lektor_procmacros/tests/skip.rs b/lektor_procmacros/tests/skip.rs deleted file mode 100644 index 9b43ecf2..00000000 --- a/lektor_procmacros/tests/skip.rs +++ /dev/null @@ -1,50 +0,0 @@ -#[macro_use] -extern crate lektor_procmacros; - -#[derive(CopyGetters, Setters)] -#[getset(get_copy, set)] -pub struct Plain { - // If the field was not skipped, the compiler would complain about moving a - // non-copyable type. - #[getset(skip)] - non_copyable: String, - - copyable: usize, - // Invalid use of skip -- compilation error. - // #[getset(skip, get_copy)] - // non_copyable2: String, - - // Invalid use of skip -- compilation error. - // #[getset(get_copy, skip)] - // non_copyable2: String, -} - -impl Plain { - fn custom_non_copyable(&self) -> &str { - &self.non_copyable - } - - // If the field was not skipped, the compiler would complain about duplicate - // definitions of `set_non_copyable`. - fn set_non_copyable(&mut self, val: String) -> &mut Self { - self.non_copyable = val; - self - } -} - -impl Default for Plain { - fn default() -> Self { - Plain { - non_copyable: "foo".to_string(), - copyable: 3, - } - } -} - -#[test] -fn test_plain() { - let mut val = Plain::default(); - val.copyable(); - val.custom_non_copyable(); - val.set_non_copyable("bar".to_string()); -} diff --git a/lektor_repo/Cargo.toml b/lektor_repo/Cargo.toml index 2a02274e..27521883 100644 --- a/lektor_repo/Cargo.toml +++ b/lektor_repo/Cargo.toml @@ -16,6 +16,7 @@ serde_json.workspace = true anyhow.workspace = true hashbrown.workspace = true +log.workspace = true tokio.workspace = true reqwest.workspace = true diff --git a/lektor_repo/src/downloader.rs b/lektor_repo/src/downloader.rs index f82d7877..87dc8d63 100644 --- a/lektor_repo/src/downloader.rs +++ b/lektor_repo/src/downloader.rs @@ -12,7 +12,7 @@ use kurisu_api::{ SHA256, }; use lektor_nkdb::{DatabaseStorage, KId, RemoteKId, UpdateHandler}; -use lektor_utils::{config::LektorRepoConfig, log}; +use lektor_utils::config::LektorRepoConfig; use reqwest::{ header::{self, HeaderName, HeaderValue}, Client, Method, Request, RequestBuilder, Url, @@ -111,7 +111,7 @@ pub async fn download_kara<Storage: DatabaseStorage>( // Make the request let mut res = request.send().await?; if !res.status().is_success() { - let (sta, json) = (res.status(), res.json().await?); + let (sta, json) = (res.status(), res.text().await?); bail!("failed to download kara from {url}, error {sta}: {json:?}") } diff --git a/lektor_repo/src/lib.rs b/lektor_repo/src/lib.rs index de39705c..2d8d6f5e 100644 --- a/lektor_repo/src/lib.rs +++ b/lektor_repo/src/lib.rs @@ -10,10 +10,7 @@ use futures::{ StreamExt, }; use lektor_nkdb::{DatabaseStorage, UpdateHandler}; -use lektor_utils::{ - config::{LektorRepoConfig, RepoApiVersion}, - log, -}; +use lektor_utils::config::{LektorRepoConfig, RepoApiVersion}; use std::sync::atomic::{AtomicU8, Ordering}; /// The repo downloader. Only works for V2 APIs... diff --git a/lektor_utils/src/config/base.rs b/lektor_utils/src/config/base.rs index 0207bef0..8a647fc2 100644 --- a/lektor_utils/src/config/base.rs +++ b/lektor_utils/src/config/base.rs @@ -135,3 +135,13 @@ impl Default for UserConfig { fn is_false(flag: &bool) -> bool { !*flag } + +impl UserConfig { + pub fn with_user(self, user: String) -> Self { + Self { user, ..self } + } + + pub fn with_token(self, token: String) -> Self { + Self { token, ..self } + } +} diff --git a/lektor_utils/src/iterator.rs b/lektor_utils/src/iterator.rs index 0d290ad9..1e9d7ea0 100644 --- a/lektor_utils/src/iterator.rs +++ b/lektor_utils/src/iterator.rs @@ -14,7 +14,7 @@ pub fn filter_range<T>( match range.end_bound() { std::ops::Bound::Included(idx) => iter.take(idx - from), std::ops::Bound::Excluded(idx) => iter.take(idx - from - 1), - std::ops::Bound::Unbounded => iter.take(usize::max_value()), + std::ops::Bound::Unbounded => iter.take(usize::MAX), } } diff --git a/lektor_utils/src/lib.rs b/lektor_utils/src/lib.rs index c17d9cf6..2b11df96 100644 --- a/lektor_utils/src/lib.rs +++ b/lektor_utils/src/lib.rs @@ -28,7 +28,6 @@ pub mod appimage; pub mod pathdiff; pub mod config; -pub mod log; pub mod logger; pub mod open; pub mod pushvec; diff --git a/lektor_utils/src/log.rs b/lektor_utils/src/log.rs deleted file mode 100644 index 59a74e3f..00000000 --- a/lektor_utils/src/log.rs +++ /dev/null @@ -1 +0,0 @@ -pub use log::{debug, error, info, log, set_logger, trace, warn, Level, Log, Metadata, Record}; diff --git a/lektor_utils/src/logger.rs b/lektor_utils/src/logger.rs index 4807d781..e239e6e0 100644 --- a/lektor_utils/src/logger.rs +++ b/lektor_utils/src/logger.rs @@ -5,7 +5,10 @@ use anyhow::anyhow; use log::{Level, LevelFilter, Metadata, Record}; use std::{ borrow::Cow, - sync::atomic::{AtomicU8, Ordering}, + sync::{ + atomic::{AtomicU8, Ordering}, + OnceLock, + }, }; /// Simple logger! @@ -17,6 +20,9 @@ struct SimpleLogger(AtomicU8); /// Ze logger! static LOGGER: SimpleLogger = SimpleLogger(AtomicU8::new(0)); +/// Filter out targets. +static FILTER_TARGETS: OnceLock<Vec<&'static str>> = OnceLock::new(); + impl SimpleLogger { /// Get the level filter for the logger. fn level(&self) -> LevelFilter { @@ -50,48 +56,82 @@ impl SimpleLogger { impl log::Log for SimpleLogger { fn enabled(&self, metadata: &Metadata) -> bool { - metadata.level() <= self.level() + (metadata.level() <= self.level()) + && FILTER_TARGETS.get().map_or(true, |filters| { + !filters + .iter() + .any(|filter| metadata.target().starts_with(filter)) + }) } fn log(&self, record: &Record) { - if self.enabled(record.metadata()) { - let level = match record.level() { - Level::Error => "ERROR", - Level::Warn => "WARN ", - Level::Info => "INFO ", - Level::Debug => "DEBUG", - Level::Trace => "TRACE", - }; - eprintln!( - "[{} {level} {}] {}", - chrono::Local::now().fixed_offset().format("%H:%M:%S"), - record.target(), - match record.args().as_str() { - Some(s) => Cow::Borrowed(s), - None => Cow::Owned(record.args().to_string()), - } - .trim() - ) + if !self.enabled(record.metadata()) { + return; } + let level = match record.level() { + Level::Error => "ERROR", + Level::Warn => "WARN ", + Level::Info => "INFO ", + Level::Debug => "DEBUG", + Level::Trace => "TRACE", + }; + eprintln!( + "[{time} {level} {target}] {msg}", + time = chrono::Local::now().fixed_offset().format("%H:%M:%S"), + target = record.target(), + msg = match record.args().as_str() { + Some(s) => Cow::Borrowed(s), + None => Cow::Owned(record.args().to_string()), + } + .trim() + ) } fn flush(&self) {} } +/// Get the log level. +pub fn get() -> Level { + LOGGER.level().to_level().unwrap_or(Level::Trace) +} + /// Set the log level with a flag. -pub fn level(lvl: Level) { +pub fn set_level(lvl: Level) { LOGGER.set_enum(lvl); } /// Same as [self::level], but as a verbose level. -pub fn verbose(lvl: u8) { +pub fn set_verbose(lvl: u8) { LOGGER.set_int(lvl); } -/// Init the logger. -pub fn init(lvl: Option<Level>) -> anyhow::Result<()> { - log::set_logger(&LOGGER).map_err(|err| anyhow!("failed to install logger: {err}"))?; - lvl.map(level) - .unwrap_or_else(|| log::set_max_level(LOGGER.level())); - Ok(()) +#[derive(Default)] +pub struct Builder { + level: Option<Level>, + filter_targets: Vec<&'static str>, +} + +impl Builder { + pub fn level(self, level: Level) -> Self { + Self { + level: Some(level), + ..self + } + } + + pub fn filter_targets(mut self, iter: impl IntoIterator<Item = &'static str>) -> Self { + self.filter_targets.extend(iter); + self + } + + pub fn init(self) -> anyhow::Result<()> { + log::set_logger(&LOGGER).map_err(|err| anyhow!("failed to install logger: {err}"))?; + self.level + .map(set_level) + .unwrap_or_else(|| log::set_max_level(LOGGER.level())); + if !self.filter_targets.is_empty() { + _ = FILTER_TARGETS.get_or_init(|| self.filter_targets); + } + Ok(()) + } } diff --git a/lektor_utils/src/pathdiff.rs b/lektor_utils/src/pathdiff.rs index d7457ff3..c41b9359 100644 --- a/lektor_utils/src/pathdiff.rs +++ b/lektor_utils/src/pathdiff.rs @@ -93,7 +93,7 @@ mod tests { assert_diff_paths("/foo", "/foo", Some("")); assert_diff_paths("foo", "foo", Some("")); - assert_diff_paths("../foo/bar/baz", "../foo/bar/baz", Some("".into())); + assert_diff_paths("../foo/bar/baz", "../foo/bar/baz", Some("")); assert_diff_paths("foo/bar/baz", "foo/bar/baz", Some("")); } diff --git a/lektor_utils/src/pushvec.rs b/lektor_utils/src/pushvec.rs index 98e605ca..eba1fcc1 100644 --- a/lektor_utils/src/pushvec.rs +++ b/lektor_utils/src/pushvec.rs @@ -2,7 +2,6 @@ //! latter versions we will see if we have better versions for the atomic read/write (SeqCst is //! terrible for performances...) -use crate::log; use std::{ptr::NonNull, sync::atomic::AtomicBool}; use tokio::sync::RwLock; diff --git a/lektord/Cargo.toml b/lektord/Cargo.toml index 682aeef6..7bbd03c3 100644 --- a/lektord/Cargo.toml +++ b/lektord/Cargo.toml @@ -11,6 +11,7 @@ description = "The lektord daemon" serde.workspace = true serde_json.workspace = true +log.workspace = true rand.workspace = true anyhow.workspace = true hashbrown.workspace = true diff --git a/lektord/build.rs b/lektord/build.rs index 819be18a..d1b5631b 100644 --- a/lektord/build.rs +++ b/lektord/build.rs @@ -70,6 +70,10 @@ fn main() -> anyhow::Result<()> { [OsStr::new("-S").to_owned(), source.as_os_str().to_owned()], [OsStr::new("-G").to_owned(), "Unix Makefiles".into()], [OsStr::new("-D").to_owned(), version], + [ + OsStr::new("-D").to_owned(), + "CMAKE_BUILD_TYPE=RELWITHDEBINFO".into(), + ], ] .into_iter() .flatten() diff --git a/lektord/src/app/mod.rs b/lektord/src/app/mod.rs index b0c20a48..15c32be3 100644 --- a/lektord/src/app/mod.rs +++ b/lektord/src/app/mod.rs @@ -18,7 +18,7 @@ use lektor_mpris::MPRISAdapter; use lektor_nkdb::{Database, DatabaseDiskStorage}; use lektor_payloads::LektorUser; use lektor_repo::Repo; -use lektor_utils::{config::LektorDatabaseConfig, log}; +use lektor_utils::config::LektorDatabaseConfig; use std::sync::{Arc, Weak}; use tokio::sync::{oneshot::Sender, RwLock}; @@ -65,7 +65,8 @@ pub async fn app( let state = LektorState::new(config, sender) .await .with_context(|| "failed to build lektord state")?; - let route = router! { "/" -> get: routes::root + let route = router! { + "/" -> get: routes::root // Control the playback ; "/playback/state" -> get: routes::get_state @@ -134,6 +135,7 @@ async fn log_requests(request: Request, next: Next) -> Response { Err(_) => log::warn!("{msg} failed with {status} and non-utf8 data blob"), }, } + StatusCode::BAD_REQUEST.into_response() } @@ -204,16 +206,11 @@ impl LektorState { /// Check whever the user is valid or not. pub fn verify_user(&self, user: LektorUser) -> LektorUser { - let (name, token) = user.as_parts(); - macro_rules! cond { - ($n: expr, $t: expr) => { - $n.as_ref().eq(name) && $t.as_ref().eq(token) - }; - } + let (name, tok) = user.as_parts(); for config in &self.users { match config { - LektorUser::User(n, t) if cond!(n, t) => return user.into_user(), - LektorUser::Admin(n, t) if cond!(n, t) => return user.into_admin(), + LektorUser::User(n, t) if &**n == name && &**t == tok => return user.into_user(), + LektorUser::Admin(n, t) if &**n == name && &**t == tok => return user.into_admin(), _ => {} } } @@ -227,10 +224,10 @@ impl LektorState { .next() .await .ok_or(anyhow!("no next kara to play"))?; - let local_id = id.local_id(); - let file = self.database.get_kara_uri(id)?.to_string(); - crate::c_wrapper::player_load_file(file, local_id)?; - Ok(()) + crate::c_wrapper::player_load_file( + self.database.get_kara_uri(id.clone())?.to_string(), + id.local_id(), + ) } /// Play the previous kara in the queue. @@ -239,11 +236,11 @@ impl LektorState { .database .previous() .await - .ok_or(anyhow!("no previous kara to play"))?; - let local_id = id.local_id(); - let file = self.database.get_kara_uri(id)?.to_string(); - crate::c_wrapper::player_load_file(file, local_id)?; - Ok(()) + .ok_or_else(|| anyhow!("no previous kara to play"))?; + crate::c_wrapper::player_load_file( + self.database.get_kara_uri(id.clone())?.to_string(), + id.local_id(), + ) } } diff --git a/lektord/src/app/mpris.rs b/lektord/src/app/mpris.rs index aca18877..9f57e52f 100644 --- a/lektord/src/app/mpris.rs +++ b/lektord/src/app/mpris.rs @@ -91,7 +91,7 @@ impl AsMpris for LektorStateWeakPtr { } fn set_volume(&self, volume: f64) { - lektor_utils::log::warn!("ignore volume {volume}"); + log::warn!("ignore volume {volume}"); } } diff --git a/lektord/src/app/routes.rs b/lektord/src/app/routes.rs index 5c4364e0..7f7becf7 100644 --- a/lektord/src/app/routes.rs +++ b/lektord/src/app/routes.rs @@ -15,7 +15,7 @@ use axum::{ }; use lektor_nkdb::*; use lektor_payloads::*; -use lektor_utils::{decode_base64_json, log}; +use lektor_utils::decode_base64_json; use rand::{seq::SliceRandom, thread_rng}; use std::{ops::RangeBounds, str::FromStr}; use tokio::task::LocalSet; @@ -63,14 +63,15 @@ pub(crate) async fn play_from_queue_pos( State(state): State<LektorStatePtr>, Path(position): Path<usize>, ) -> Result<(), LektordError> { - let db = &state.database; - let id = db + let id = state + .database .play_from_position(position) .await .ok_or(anyhow!("position {position} doesn't exists in queue"))?; - let local_id = id.local_id(); - let file = db.get_kara_uri(id)?.to_string(); - crate::c_wrapper::player_load_file(file, local_id)?; + crate::c_wrapper::player_load_file( + state.database.get_kara_uri(id.clone())?.to_string(), + id.local_id(), + )?; Ok(()) } @@ -162,8 +163,14 @@ pub(crate) async fn count( pub(crate) async fn get_playlists( State(state): State<LektorStatePtr>, ) -> Json<Vec<(lektor_payloads::PlaylistName, PlaylistInfo)>> { - let plts = state.database.playlists().await.into_iter(); - Json(plts.map(|(name, info)| (name.into(), info)).collect()) + Json(Vec::from_iter( + state + .database + .playlists() + .await + .into_iter() + .map(|(n, info)| (n.into(), info)), + )) } /// Get the content of a specific playlist. @@ -246,13 +253,11 @@ pub(crate) async fn create_playlist( user_infos: LektorUser, name: lektor_payloads::PlaylistName, ) -> Result<(), LektordError> { - let builder = match state.verify_user(user_infos) { - LektorUser::Unverified(_, _) => PlaylistInfo::builder(), - LektorUser::User(name, _) | LektorUser::Admin(name, _) => { - PlaylistInfo::builder().user(name) - } + let info = match state.verify_user(user_infos) { + LektorUser::Unverified(_, _) => PlaylistInfo::new(), + LektorUser::User(n, _) | LektorUser::Admin(n, _) => PlaylistInfo::new().user(n), }; - Ok(state.database.playlist_new(name, builder).await?) + Ok(state.database.playlist_new(name, info).await?) } /// Update the database from the remotes. The user must be the super user to do that. We can't use @@ -263,32 +268,35 @@ pub(crate) async fn adm_update( State(state): State<LektorStatePtr>, admin: LektorUser, ) -> Result<(), LektordError> { - let admin = state.verify_user(admin); - if !admin.is_admin() { - return Err(anyhow!("user {admin:?} is not an admin").into()); - } + let admin = match state.verify_user(admin) { + user @ LektorUser::Admin(_, _) => user, + user => return Err(anyhow!("user {user:?} is not an admin").into()), + }; + log::info!("launching update requested by {admin:?}"); std::thread::spawn(move || { - let rt = tokio::runtime::Builder::new_current_thread() - .max_blocking_threads(1024) - .enable_all() - .build() - .expect("failed to build tokio runtime to update database from repo"); let local = LocalSet::new(); local.spawn_local(async move { - let res = tokio::task::spawn_local(async move { + match tokio::task::spawn_local(async move { let handle = state.database.update().await; let count = state.repo.update_with(&handle).await?; handle.finished().await; state.database.refresh_playlist_contents().await; Ok::<_, anyhow::Error>(count) - }); - match res.await.map_err(|err| anyhow!("{err}")) { + }) + .await + .map_err(|err| anyhow!("{err}")) + { Ok(Ok(count)) => log::info!("finished updating database with karas: {count}"), Err(err) | Ok(Err(err)) => log::error!("{err}"), } }); - rt.block_on(local); + tokio::runtime::Builder::new_current_thread() + .max_blocking_threads(1024) + .enable_all() + .build() + .expect("failed to build tokio runtime to update database from repo") + .block_on(local); }); Ok(()) } @@ -299,14 +307,15 @@ pub(crate) async fn adm_shutdown( State(state): State<LektorStatePtr>, admin: LektorUser, ) -> StatusCode { - let admin = state.verify_user(admin); - if admin.is_admin() { - log::info!("shutdown requested by {admin:?}"); - let mut red_button = state.shutdown.write().await; - red_button.take().map(|shutdown| shutdown.send(())); - StatusCode::OK - } else { - StatusCode::FORBIDDEN + match state.verify_user(admin) { + admin @ LektorUser::Admin(..) => { + log::info!("shutdown requested by {admin:?}"); + if let Some(shutdown) = state.shutdown.write().await.take() { + let _ = shutdown.send(()); + } + StatusCode::OK + } + _ => StatusCode::FORBIDDEN, } } @@ -328,11 +337,12 @@ pub(crate) async fn get_queue_range( State(state): State<LektorStatePtr>, range: Range, ) -> Json<Vec<(Priority, KId)>> { - let content = state - .database - .queue((range.start_bound(), range.end_bound())) - .await; - Json(content) + Json( + state + .database + .queue((range.start_bound(), range.end_bound())) + .await, + ) } /// Add karas to the queue diff --git a/lektord/src/c_wrapper/commands.rs b/lektord/src/c_wrapper/commands.rs index ca218d47..6132438b 100644 --- a/lektord/src/c_wrapper/commands.rs +++ b/lektord/src/c_wrapper/commands.rs @@ -1,7 +1,6 @@ use super::{PlayerEvent, STATE}; -use anyhow::{bail, Error, Result}; +use anyhow::{bail, Context, Error, Result}; use lektor_nkdb::PlayState; -use lektor_utils::*; use std::{ffi::*, path::Path, ptr::NonNull}; /// Safe wrapper around `mod_stop_playback`. Stops the playback. Same as [player_toggle_pause], don't update @@ -10,10 +9,9 @@ pub(crate) fn player_stop() -> Result<()> { extern "C" { fn mod_stop_playback() -> c_int; } - if 0 != unsafe { mod_stop_playback() } { - bail!("failed to stop playback") - } - Ok(()) + (0 == unsafe { mod_stop_playback() }) + .then_some(()) + .context("failed to stop playback") } /// Safe wrapper around `mod_set_paused`. Set the pause state of the player. Same remark as @@ -28,10 +26,9 @@ pub(crate) fn player_set_paused(state: PlayState) -> Result<()> { PlayState::Play => 0 as c_int, PlayState::Pause => 1 as c_int, }; - if 0 != unsafe { mod_set_paused(paused) } { - bail!("failed to set paused state to {state:?}") - } - Ok(()) + (0 == unsafe { mod_set_paused(paused) }) + .then_some(()) + .with_context(|| format!("failed to set paused state to {state:?}")) } /// Safe wrapper around `mod_toggle_pause`. Send the toggle signal to the player. No need to update @@ -41,10 +38,9 @@ pub(crate) fn player_toggle_pause() -> Result<()> { extern "C" { fn mod_toggle_pause() -> c_int; } - if 0 != unsafe { mod_toggle_pause() } { - anyhow::bail!("failed to toggle pause state") - } - Ok(()) + (0 == unsafe { mod_toggle_pause() }) + .then_some(()) + .context("failed to toggle pause state") } /// Safe wrapper around `mod_set_position` Set the position in the player module. @@ -53,11 +49,9 @@ pub(crate) fn player_set_position(position: i64) -> Result<()> { extern "C" { fn mod_set_position(_: c_int) -> c_int; } - let position = c_int::try_from(position)?; - if 0 != unsafe { mod_set_position(position) } { - anyhow::bail!("failed to set player position to {position}s") - } - Ok(()) + (0 == unsafe { mod_set_position(c_int::try_from(position)?) }) + .then_some(()) + .with_context(|| format!("failed to set player position to {position}s")) } /// Safe wrapper around `mod_get_duration` Get the duration of the current playing file. @@ -66,10 +60,9 @@ pub(crate) fn player_get_duration() -> Result<i64> { fn mod_get_duration(_: NonNull<c_int>) -> c_int; } let mut duration: c_int = 0; - if 0 != unsafe { mod_get_duration(NonNull::new_unchecked((&mut duration) as *mut _)) } { - anyhow::bail!("failed to get current kara duration") - } - Ok(duration.into()) + (0 == unsafe { mod_get_duration(NonNull::new_unchecked((&mut duration) as *mut _)) }) + .then(|| duration.into()) + .context("failed to get current kara duration") } /// Safe wrapper around `mod_get_elapsed` Get the duration since the begin of the kara. @@ -78,10 +71,9 @@ pub(crate) fn player_get_elapsed() -> Result<i64> { fn mod_get_elapsed(_: NonNull<c_int>) -> c_int; } let mut elapsed: c_int = 0; - if 0 != unsafe { mod_get_elapsed(NonNull::new_unchecked((&mut elapsed) as *mut _)) } { - anyhow::bail!("failed to get current kara elapsed time since start of file") - } - Ok(elapsed.into()) + (0 == unsafe { mod_get_elapsed(NonNull::new_unchecked((&mut elapsed) as *mut _)) }) + .then(|| elapsed.into()) + .context("failed to get current kara elapsed time since start of file") } /// Safe wrapper around `mod_load_file` Tell the player to load a file by its path. @@ -94,10 +86,9 @@ pub(crate) fn player_load_file(path: impl AsRef<Path>, id: u64) -> Result<()> { .to_str() .ok_or_else(|| Error::msg("path contained non-utf8 characters"))?; let cstr = CString::new(path)?; - if 0 != unsafe { mod_load_file(NonNull::new_unchecked(cstr.as_ptr() as *mut _), id) } { - anyhow::bail!("failed load file {path}") - } - Ok(()) + (0 == unsafe { mod_load_file(NonNull::new_unchecked(cstr.as_ptr() as *mut _), id) }) + .then_some(()) + .with_context(|| format!("failed load file {path}")) } /// Safe wrapper around `mod_set_volume` Set the volume of the player. @@ -107,19 +98,19 @@ pub(crate) fn player_set_playback_volume(vol: i64) -> Result<()> { fn mod_set_volume(_: c_int) -> c_int; } let vol = c_int::try_from(vol)?.clamp(0, 100); - if 0 != unsafe { mod_set_volume(vol) } { - anyhow::bail!("failed to set player volume to {vol}%") - } - Ok(()) + (0 == unsafe { mod_set_volume(vol) }) + .then_some(()) + .with_context(|| format!("failed to set player volume to {vol}%")) } fn send_msg(msg: PlayerEvent) { - if let Some((sender, _)) = unsafe { STATE.get() } { - if let Err(err) = sender.blocking_send(msg) { - log::error!("failed to send msg {msg:?}: {err}"); + match unsafe { STATE.get() } { + Some((sender, _)) => { + let _ = sender + .blocking_send(msg) + .map_err(|err| log::error!("failed to send msg {msg:?}: {err}")); } - } else { - log::error!("no lektord state was set for the player module") + None => log::error!("no lektord state was set for the player module"), } } diff --git a/lektord/src/c_wrapper/loging.rs b/lektord/src/c_wrapper/loging.rs index b39e412b..1ef1f3f2 100644 --- a/lektord/src/c_wrapper/loging.rs +++ b/lektord/src/c_wrapper/loging.rs @@ -1,4 +1,3 @@ -use lektor_utils::log; use std::{ ffi::{c_char, c_int, CStr}, ptr::NonNull, @@ -17,21 +16,20 @@ pub unsafe extern "C" fn lkt_log_rs( line: u64, fmt: NonNull<c_char>, ) { - use lektor_utils::log::Level; - let (section, function, file, fmt, lvl) = unsafe { + let (section, function, file, fmt) = unsafe { ( CStr::from_ptr(section.as_ptr()).to_string_lossy(), CStr::from_ptr(function.as_ptr()).to_string_lossy(), CStr::from_ptr(file.as_ptr()).to_string_lossy(), CStr::from_ptr(fmt.as_ptr()).to_string_lossy(), - match log_level { - 1 => Level::Error, - 2 => Level::Warn, - 3 => Level::Info, - 4 => Level::Debug, - _ => Level::Trace, - }, ) }; + let lvl = match log_level { + 1 => log::Level::Error, + 2 => log::Level::Warn, + 3 => log::Level::Info, + 4 => log::Level::Debug, + _ => log::Level::Trace, + }; log::log!(target: format!("CC::{section}").as_str(), lvl, "{file}+{line}:{function}: {fmt}"); } diff --git a/lektord/src/c_wrapper/mod.rs b/lektord/src/c_wrapper/mod.rs index 98b09a34..f0ddb5fc 100644 --- a/lektord/src/c_wrapper/mod.rs +++ b/lektord/src/c_wrapper/mod.rs @@ -1,7 +1,7 @@ //! Interface with the C/C++ part of the code. The only place we allow unsafe code in this crate. use crate::LektorStatePtr; -use anyhow::{bail, Result}; +use anyhow::{bail, ensure, Context, Result}; use lektor_nkdb::PlayState; use lektor_utils::{config::LektorPlayerConfig, *}; use std::{ @@ -76,28 +76,23 @@ pub(crate) fn init_player_module(ptr: LektorStatePtr, config: LektorPlayerConfig let weak_ptr = Arc::downgrade(&ptr); let handle = tokio::task::spawn(async move { while let Some(event) = receiver.recv().await { - use LktPlayState as LPS; - use PlayState as PS; + use {LktPlayState as LPS, PlayState as PS}; match event { PlayerEvent::SetPlayState(state) => match LktPlayState::try_from(state) { Ok(LPS::Stop) => ptr.database.set_playstate(PS::Stop).await, - Ok(LPS::Pause) => ptr.database.set_playstate(PS::Pause).await, Ok(LPS::Play) => ptr.database.set_playstate(PS::Play).await, + Ok(LPS::Pause) => ptr.database.set_playstate(PS::Pause).await, Ok(LPS::Toggle) => ptr.database.toggle_playstate().await, - Err(err) => log::error!("invalid playstate: {err}"), + Err(e) => log::error!("invalid playstate: {e}"), }, PlayerEvent::PlayNext => { if let Some(ptr) = weak_ptr.upgrade() { - if let Err(err) = ptr.play_next().await { - log::error!("{err}"); - } + let _ = ptr.play_next().await.map_err(|e| log::error!("{e}")); } } PlayerEvent::PlayPrev => { if let Some(ptr) = weak_ptr.upgrade() { - if let Err(err) = ptr.play_previous().await { - log::error!("{err}"); - } + let _ = ptr.play_previous().await.map_err(|e| log::error!("{e}")); } } } @@ -105,22 +100,25 @@ pub(crate) fn init_player_module(ptr: LektorStatePtr, config: LektorPlayerConfig }); // Set the state for the C/C++ code - if STATE.set((sender, handle)).is_err() { - bail!("failed to register the lektord state pointer for the player module"); - } + ensure!( + STATE.set((sender, handle)).is_ok(), + "failed to register the lektord state pointer for the player module" + ); // Pass options to the C/C++ code - if 0 != mod_set_msg_options( - NonNull::new_unchecked(CString::new(font_name)?.as_ptr() as *mut _), - font_size, - msg_duration, - ) { - bail!("failed to set informations relative to fonts for the player module") - } - - if 0 != mod_set_force_x11(force_x11) { - bail!("failed to set informations relative x11 for the player module") - } + ensure!( + 0 == mod_set_msg_options( + NonNull::new_unchecked(CString::new(font_name)?.as_ptr() as *mut _), + font_size, + msg_duration, + ), + "failed to set informations relative to fonts for the player module" + ); + + ensure!( + 0 == mod_set_force_x11(force_x11), + "failed to set informations relative x11 for the player module" + ); // Create the player let table = FunctionTable { @@ -130,10 +128,9 @@ pub(crate) fn init_player_module(ptr: LektorStatePtr, config: LektorPlayerConfig toggle: lkt_toggle_play_state, abort: lkt_abort, }; - if 0 != mod_new(&table as *const _) { - bail!("failed to init the player module") - } - Ok(()) + (0 == mod_new(&table as *const _)) + .then_some(()) + .context("failed to init the player module") } } @@ -148,15 +145,11 @@ pub async fn close_player_module() -> Result<()> { None => bail!("the player state wasn't initialized"), Some((sender, handle)) => { drop(sender); - if let Err(err) = handle.await { - log::error!("{err}") - } + let _ = handle.await.map_err(|e| log::error!("{e}")); } } - if 0 != unsafe { mod_close() } { - bail!("qt application returned an error") - } - - Ok(()) + (0 == unsafe { mod_close() }) + .then_some(()) + .context("qt application returned an error") } diff --git a/lektord/src/c_wrapper/playstate.rs b/lektord/src/c_wrapper/playstate.rs index b49a9f79..d77d0fc5 100644 --- a/lektord/src/c_wrapper/playstate.rs +++ b/lektord/src/c_wrapper/playstate.rs @@ -17,8 +17,8 @@ impl TryFrom<LktPlayState> for PlayState { fn try_from(value: LktPlayState) -> Result<Self, Self::Error> { match value { LktPlayState::Stop => Ok(PlayState::Stop), - LktPlayState::Pause => Ok(PlayState::Pause), LktPlayState::Play => Ok(PlayState::Play), + LktPlayState::Pause => Ok(PlayState::Pause), LktPlayState::Toggle => Err(format!("can't convert {value:?} into a PlayState")), } } diff --git a/lektord/src/config.rs b/lektord/src/config.rs index 09406eb0..8cc48678 100644 --- a/lektord/src/config.rs +++ b/lektord/src/config.rs @@ -1,5 +1,6 @@ use anyhow::{bail, Context, Result}; -use lektor_utils::{config::*, log::Level as LogLevel}; +use lektor_utils::config::*; +use log::Level as LogLevel; use serde::{Deserialize, Serialize}; use std::{net::SocketAddr, path::PathBuf}; diff --git a/lektord/src/error.rs b/lektord/src/error.rs index f8bdb81d..235cc8b9 100644 --- a/lektord/src/error.rs +++ b/lektord/src/error.rs @@ -4,7 +4,6 @@ use axum::{response::IntoResponse, Json}; use hyper::StatusCode; -use lektor_utils::log; use serde_json::json; #[derive(Debug)] @@ -19,12 +18,11 @@ impl<E: Into<anyhow::Error>> From<E> for LektordError { impl IntoResponse for LektordError { fn into_response(self) -> axum::response::Response { log::error!("{self}"); - let code = StatusCode::INTERNAL_SERVER_ERROR; let json = json!({ - "code": code.as_u16(), + "code": StatusCode::INTERNAL_SERVER_ERROR.as_u16(), "msg": self.to_string(), }); - (code, Json(json)).into_response() + (StatusCode::INTERNAL_SERVER_ERROR, Json(json)).into_response() } } diff --git a/lektord/src/main.rs b/lektord/src/main.rs index f1d72a32..42035fdc 100644 --- a/lektord/src/main.rs +++ b/lektord/src/main.rs @@ -25,15 +25,19 @@ use tokio::{net::TcpListener, signal, sync::oneshot::Receiver}; use tower::Service; fn main() -> Result<()> { - logger::init(Some(log::Level::Debug))?; + logger::Builder::default() + .level(log::Level::Debug) + .init() + .context("failed to init logger")?; #[cfg(target_os = "linux")] appimage::detect_appimage()?; let config = lektor_utils::config::get_or_write_default_config::<LektorConfig>("lektord")?; let args = <cmd::Args as clap::Parser>::parse(); - logger::level(config.log); + + logger::set_level(config.log); if args.verbose != 0 { - logger::verbose(args.verbose); + logger::set_verbose(args.verbose); } match args.action.unwrap_or_default() { @@ -99,18 +103,14 @@ async fn launch_server(config: LektorConfig) -> Result<()> { async fn server_instance(addr: SocketAddr, socket: TcpListener, app: axum::Router) { loop { let Ok((stream, client)) = socket.accept().await else { - log::error!("failed to accept socket at {addr}"); - return; + return log::error!("failed to accept socket at {addr}"); }; let app = app.clone(); // One thread per client, they all share the same state! tokio::spawn(async move { ServerBuilder::new(TokioExecutor::new()) - .serve_connection( - TokioIo::new(stream), - service_fn(move |req| app.clone().call(req)), - ) + .serve_connection(TokioIo::new(stream), service_fn(|r| app.clone().call(r))) .await - .inspect_err(|err| log::error!("failed to serve {client} from {addr}: {err}")) + .inspect_err(|e| log::error!("failed to serve {client} from {addr}: {e}")) }); } } @@ -148,9 +148,9 @@ async fn shutdown_signal(shutdown: Receiver<()>) { } log::info!("received termination signal shutting down, try to unregister the state from the player module"); - if let Err(err) = c_wrapper::close_player_module().await { - log::error!("{err}") - } + let _ = c_wrapper::close_player_module() + .await + .map_err(|e| log::error!("{e}")); log::info!("will now call exit(EXIT_SUCCESS)"); std::process::exit(0); } diff --git a/lkt/Cargo.toml b/lkt/Cargo.toml index 3b675b92..c97c8633 100644 --- a/lkt/Cargo.toml +++ b/lkt/Cargo.toml @@ -16,6 +16,7 @@ async-trait.workspace = true serde.workspace = true serde_json.workspace = true +log.workspace = true chrono.workspace = true anyhow.workspace = true diff --git a/lkt/src/config.rs b/lkt/src/config.rs index 57cbab87..43f63164 100644 --- a/lkt/src/config.rs +++ b/lkt/src/config.rs @@ -1,9 +1,7 @@ -use lektor_utils::{ - config::{SocketScheme, UserConfig}, - log::Level as LogLevel, -}; +use lektor_utils::config::{SocketScheme, UserConfig}; +use log::Level as LogLevel; use serde::{Deserialize, Serialize}; -use std::net::SocketAddr; +use std::{net::SocketAddr, time::Duration}; /// Lkt configuration. #[derive(Debug, Deserialize, Serialize, Clone)] @@ -13,6 +11,7 @@ pub struct LktConfig { pub log: LogLevel, pub scheme: SocketScheme, + pub retry: Duration, pub host: SocketAddr, pub user: UserConfig, } @@ -21,6 +20,7 @@ impl From<LktConfig> for lektor_lib::ConnectConfig { fn from(value: LktConfig) -> Self { lektor_lib::ConnectConfig { scheme: value.scheme, + retry: value.retry, host: value.host, user: value.user.user.into(), token: value.user.token.into(), @@ -28,15 +28,34 @@ impl From<LktConfig> for lektor_lib::ConnectConfig { } } +impl From<&LktConfig> for lektor_lib::ConnectConfig { + fn from(value: &LktConfig) -> Self { + lektor_lib::ConnectConfig { + scheme: value.scheme, + retry: value.retry, + host: value.host, + user: value.user.user.clone().into(), + token: value.user.token.clone().into(), + } + } +} + impl From<LktConfig> for lektor_lib::ConnectConfigPtr { fn from(value: LktConfig) -> Self { lektor_lib::ConnectConfig::from(value).into() } } +impl From<&LktConfig> for lektor_lib::ConnectConfigPtr { + fn from(value: &LktConfig) -> Self { + lektor_lib::ConnectConfig::from(value).into() + } +} + impl Default for LktConfig { fn default() -> Self { Self { + retry: Duration::from_secs(10), log: LogLevel::Info, scheme: Default::default(), host: SocketAddr::new([127, 0, 0, 1].into(), 6600), diff --git a/lkt/src/main.rs b/lkt/src/main.rs index 07f68aa9..9afa21b2 100644 --- a/lkt/src/main.rs +++ b/lkt/src/main.rs @@ -7,7 +7,7 @@ mod config; mod manpage; use crate::{args::*, config::*}; -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, Context as _, Result}; use chrono::TimeZone; use futures::{stream, StreamExt}; use lektor_lib::*; @@ -16,7 +16,10 @@ use lektor_utils::*; use std::{borrow::Cow, ops::RangeBounds}; fn main() -> Result<()> { - logger::init(Some(log::Level::Trace)).expect("failed to install logger"); + logger::Builder::default() + .level(log::Level::Trace) + .init() + .context("failed to install logger")?; #[cfg(target_os = "linux")] appimage::detect_appimage()?; @@ -38,8 +41,8 @@ fn main() -> Result<()> { } let config = lektor_utils::config::get_or_write_default_config::<LktConfig>("lkt")?; - logger::level(config.log); - logger::verbose(args.verbose); + logger::set_level(config.log); + logger::set_verbose(args.verbose); tokio::runtime::Builder::new_current_thread() .enable_all() .build()? @@ -47,10 +50,10 @@ fn main() -> Result<()> { Ok(()) } -async fn collect_karas(config: LktConfig, ids: Vec<KId>) -> Result<Vec<Kara>> { +async fn collect_karas(config: &ConnectConfig, ids: Vec<KId>) -> Result<Vec<Kara>> { let count = ids.len(); let res: Vec<_> = stream::iter(ids.into_iter()) - .then(|id| requests::get_kara_by_kid(config.clone(), id)) + .then(|id| requests::get_kara_by_kid(config, id)) .filter_map(|res| async { res.map_err(|err| log::error!("{err}")).ok() }) .collect::<_>() .await; @@ -60,8 +63,8 @@ async fn collect_karas(config: LktConfig, ids: Vec<KId>) -> Result<Vec<Kara>> { .ok_or(anyhow!("got errors, didn't received all the karas' data")) } -async fn simple_karas_print(config: LktConfig, ids: Vec<KId>) -> Result<()> { - let res = collect_karas(config.clone(), ids).await?; +async fn simple_karas_print(config: &ConnectConfig, ids: Vec<KId>) -> Result<()> { + let res = collect_karas(config, ids).await?; let count = res.len().to_string().len(); res.into_iter() .enumerate() @@ -72,6 +75,8 @@ async fn simple_karas_print(config: LktConfig, ids: Vec<KId>) -> Result<()> { async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> { // Write to apply changes... lektor_utils::config::write_config_async("lkt", config.clone()).await?; + let config = ConnectConfig::from(config); + let config = &config; use crate::args::SubCommand::*; match cmd { @@ -81,8 +86,7 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> { // Display current kara in one line (for status lines...) Playback { current: true, .. } => { - let PlayStateWithCurrent { state, current } = - requests::get_status(config.clone()).await?; + let PlayStateWithCurrent { state, current } = requests::get_status(config).await?; match current { None => println!("[{state:?}]"), Some((kid, elapsed, duration)) => { @@ -98,18 +102,17 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> { let Infos { version, last_epoch, - } = requests::get_infos(config.clone()).await?; - let PlayStateWithCurrent { state, current } = - requests::get_status(config.clone()).await?; + } = requests::get_infos(config).await?; + let PlayStateWithCurrent { state, current } = requests::get_status(config).await?; let current = match current { None => None, Some((kid, elapsed, duration)) => Some(( - requests::get_kara_by_kid(config.clone(), kid).await?, + requests::get_kara_by_kid(config, kid).await?, elapsed, duration, )), }; - let queue_counts = requests::get_queue_count(config.clone()).await?; + let queue_counts = requests::get_queue_count(config).await?; let history_count = requests::get_history_count(config).await?; let last_epoch = match last_epoch { Some(num) => num.to_string().into(), @@ -163,7 +166,7 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> { // List kara in the queue Queue { pos: Some(pos), .. } => { let pos = pos.unwrap_or_default(); - let ids = requests::get_queue_range(config.clone(), pos).await?; + let ids = requests::get_queue_range(config, pos).await?; let prios: Vec<_> = ids.iter().map(|(prio, _)| *prio).collect(); let karas: Vec<_> = collect_karas(config, ids.into_iter().map(|(_, id)| id).collect()).await?; @@ -192,7 +195,7 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> { // Add karas to the queue Queue { add: Some(add), .. } => { let AddArguments { level: lvl, query } = add.join(" ").parse()?; - let ids = requests::search_karas(config.clone(), SearchFrom::Database, query).await?; + let ids = requests::search_karas(config, SearchFrom::Database, query).await?; let add = QueueAddAction { priority: lvl, action: KaraFilter::List(true, ids), @@ -216,7 +219,7 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> { // =============== // History { clear: true, .. } => requests::remove_range_from_history(config, ..).await, History { pos: Some(pos), .. } => { - let ids = requests::get_history_range(config.clone(), pos.unwrap_or_default()).await?; + let ids = requests::get_history_range(config, pos.unwrap_or_default()).await?; simple_karas_print(config, ids).await } @@ -228,7 +231,7 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> { .. } => { let regex = regex.join(" ").parse()?; - let ids = requests::search_karas(config.clone(), SearchFrom::Database, regex).await?; + let ids = requests::search_karas(config, SearchFrom::Database, regex).await?; simple_karas_print(config, ids).await } @@ -254,8 +257,7 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> { } => { let name = args.remove(0).parse()?; let regex = args.join(" ").parse()?; - let ids = - requests::search_karas(config.clone(), SearchFrom::Playlist(name), regex).await?; + let ids = requests::search_karas(config, SearchFrom::Playlist(name), regex).await?; simple_karas_print(config, ids).await } @@ -263,7 +265,7 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> { queue: Some(args), .. } => { let regex = args.join(" ").parse()?; - let ids = requests::search_karas(config.clone(), SearchFrom::Queue, regex).await?; + let ids = requests::search_karas(config, SearchFrom::Queue, regex).await?; simple_karas_print(config, ids).await } @@ -272,7 +274,7 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> { .. } => { let regex = args.join(" ").parse()?; - let ids = requests::search_karas(config.clone(), SearchFrom::History, regex).await?; + let ids = requests::search_karas(config, SearchFrom::History, regex).await?; simple_karas_print(config, ids).await } @@ -327,7 +329,7 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> { list: Some(Some(n)), .. } => { - let ids = requests::get_playlist_content(config.clone(), n.into()).await?; + let ids = requests::get_playlist_content(config, n.into()).await?; simple_karas_print(config, ids).await } @@ -338,7 +340,7 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> { } => { let name = args.remove(0).into(); let rgx = args.join(" ").parse()?; - let ids = requests::search_karas(config.clone(), SearchFrom::Database, rgx).await?; + let ids = requests::search_karas(config, SearchFrom::Database, rgx).await?; let add = KaraFilter::List(true, ids); requests::add_to_playlist(config, name, add).await } @@ -350,7 +352,7 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> { } => { let name = args.remove(0).into(); let rgx = args.join(" ").parse()?; - let ids = requests::search_karas(config.clone(), SearchFrom::Database, rgx).await?; + let ids = requests::search_karas(config, SearchFrom::Database, rgx).await?; let remove = KaraFilter::List(true, ids); requests::remove_from_playlist(config, name, remove).await } -- GitLab