diff --git a/Cargo.lock b/Cargo.lock
index 1db9dec..c017459 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -137,6 +137,28 @@ version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
+[[package]]
+name = "alsa"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43"
+dependencies = [
+ "alsa-sys",
+ "bitflags 2.6.0",
+ "cfg-if",
+ "libc",
+]
+
+[[package]]
+name = "alsa-sys"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527"
+dependencies = [
+ "libc",
+ "pkg-config",
+]
+
[[package]]
name = "android-activity"
version = "0.5.2"
@@ -532,6 +554,24 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+[[package]]
+name = "bindgen"
+version = "0.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
+dependencies = [
+ "bitflags 2.6.0",
+ "cexpr",
+ "clang-sys",
+ "itertools",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn 2.0.87",
+]
+
[[package]]
name = "bit-set"
version = "0.5.3"
@@ -750,6 +790,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -771,6 +820,17 @@ dependencies = [
"libc",
]
+[[package]]
+name = "clang-sys"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading 0.8.5",
+]
+
[[package]]
name = "clap"
version = "4.5.20"
@@ -811,6 +871,12 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
+[[package]]
+name = "claxon"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688"
+
[[package]]
name = "clipboard-win"
version = "5.4.0"
@@ -968,6 +1034,49 @@ dependencies = [
"libc",
]
+[[package]]
+name = "coreaudio-rs"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation-sys",
+ "coreaudio-sys",
+]
+
+[[package]]
+name = "coreaudio-sys"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ce857aa0b77d77287acc1ac3e37a05a8c95a2af3647d23b15f263bdaeb7562b"
+dependencies = [
+ "bindgen",
+]
+
+[[package]]
+name = "cpal"
+version = "0.15.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779"
+dependencies = [
+ "alsa",
+ "core-foundation-sys",
+ "coreaudio-rs",
+ "dasp_sample",
+ "jni",
+ "js-sys",
+ "libc",
+ "mach2",
+ "ndk",
+ "ndk-context",
+ "oboe",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "windows 0.54.0",
+]
+
[[package]]
name = "cpufeatures"
version = "0.2.14"
@@ -1008,6 +1117,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
+[[package]]
+name = "dasp_sample"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
+
[[package]]
name = "data-url"
version = "0.3.1"
@@ -1256,6 +1371,12 @@ dependencies = [
"web-sys",
]
+[[package]]
+name = "either"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+
[[package]]
name = "emath"
version = "0.27.2"
@@ -1272,6 +1393,15 @@ version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6a21708405ea88f63d8309650b4d77431f4bc28fb9d8e6f77d3963b51249e6"
+[[package]]
+name = "encoding_rs"
+version = "0.8.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
+dependencies = [
+ "cfg-if",
+]
+
[[package]]
name = "enum-map"
version = "2.7.3"
@@ -1439,6 +1569,12 @@ dependencies = [
"pin-project-lite",
]
+[[package]]
+name = "extended"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365"
+
[[package]]
name = "fastrand"
version = "1.9.0"
@@ -1631,6 +1767,12 @@ dependencies = [
"xml-rs",
]
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
[[package]]
name = "glow"
version = "0.13.1"
@@ -1830,6 +1972,12 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[package]]
+name = "hound"
+version = "3.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f"
+
[[package]]
name = "humantime"
version = "2.1.0"
@@ -1912,6 +2060,15 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
[[package]]
name = "itoa"
version = "1.0.11"
@@ -1990,6 +2147,17 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+[[package]]
+name = "lewton"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030"
+dependencies = [
+ "byteorder",
+ "ogg",
+ "tinyvec",
+]
+
[[package]]
name = "libc"
version = "0.2.161"
@@ -2061,6 +2229,15 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+[[package]]
+name = "mach2"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "malloc_buf"
version = "0.0.6"
@@ -2134,6 +2311,12 @@ dependencies = [
"unicase",
]
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
[[package]]
name = "miniz_oxide"
version = "0.8.0"
@@ -2225,6 +2408,27 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -2424,6 +2628,38 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "oboe"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb"
+dependencies = [
+ "jni",
+ "ndk",
+ "ndk-context",
+ "num-derive",
+ "num-traits",
+ "oboe-sys",
+]
+
+[[package]]
+name = "oboe-sys"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "ogg"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e"
+dependencies = [
+ "byteorder",
+]
+
[[package]]
name = "once_cell"
version = "1.20.2"
@@ -2801,6 +3037,19 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[package]]
+name = "rodio"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7ceb6607dd738c99bc8cb28eff249b7cd5c8ec88b9db96c0608c1480d140fb1"
+dependencies = [
+ "claxon",
+ "cpal",
+ "hound",
+ "lewton",
+ "symphonia",
+]
+
[[package]]
name = "roxmltree"
version = "0.19.0"
@@ -3173,6 +3422,151 @@ dependencies = [
"siphasher",
]
+[[package]]
+name = "symphonia"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "815c942ae7ee74737bb00f965fa5b5a2ac2ce7b6c01c0cc169bbeaf7abd5f5a9"
+dependencies = [
+ "lazy_static",
+ "symphonia-bundle-flac",
+ "symphonia-bundle-mp3",
+ "symphonia-codec-aac",
+ "symphonia-codec-adpcm",
+ "symphonia-codec-pcm",
+ "symphonia-codec-vorbis",
+ "symphonia-core",
+ "symphonia-format-isomp4",
+ "symphonia-format-riff",
+ "symphonia-metadata",
+]
+
+[[package]]
+name = "symphonia-bundle-flac"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72e34f34298a7308d4397a6c7fbf5b84c5d491231ce3dd379707ba673ab3bd97"
+dependencies = [
+ "log",
+ "symphonia-core",
+ "symphonia-metadata",
+ "symphonia-utils-xiph",
+]
+
+[[package]]
+name = "symphonia-bundle-mp3"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c01c2aae70f0f1fb096b6f0ff112a930b1fb3626178fba3ae68b09dce71706d4"
+dependencies = [
+ "lazy_static",
+ "log",
+ "symphonia-core",
+ "symphonia-metadata",
+]
+
+[[package]]
+name = "symphonia-codec-aac"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdbf25b545ad0d3ee3e891ea643ad115aff4ca92f6aec472086b957a58522f70"
+dependencies = [
+ "lazy_static",
+ "log",
+ "symphonia-core",
+]
+
+[[package]]
+name = "symphonia-codec-adpcm"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c94e1feac3327cd616e973d5be69ad36b3945f16b06f19c6773fc3ac0b426a0f"
+dependencies = [
+ "log",
+ "symphonia-core",
+]
+
+[[package]]
+name = "symphonia-codec-pcm"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f395a67057c2ebc5e84d7bb1be71cce1a7ba99f64e0f0f0e303a03f79116f89b"
+dependencies = [
+ "log",
+ "symphonia-core",
+]
+
+[[package]]
+name = "symphonia-codec-vorbis"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a98765fb46a0a6732b007f7e2870c2129b6f78d87db7987e6533c8f164a9f30"
+dependencies = [
+ "log",
+ "symphonia-core",
+ "symphonia-utils-xiph",
+]
+
+[[package]]
+name = "symphonia-core"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "798306779e3dc7d5231bd5691f5a813496dc79d3f56bf82e25789f2094e022c3"
+dependencies = [
+ "arrayvec",
+ "bitflags 1.3.2",
+ "bytemuck",
+ "lazy_static",
+ "log",
+]
+
+[[package]]
+name = "symphonia-format-isomp4"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abfdf178d697e50ce1e5d9b982ba1b94c47218e03ec35022d9f0e071a16dc844"
+dependencies = [
+ "encoding_rs",
+ "log",
+ "symphonia-core",
+ "symphonia-metadata",
+ "symphonia-utils-xiph",
+]
+
+[[package]]
+name = "symphonia-format-riff"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f7be232f962f937f4b7115cbe62c330929345434c834359425e043bfd15f50"
+dependencies = [
+ "extended",
+ "log",
+ "symphonia-core",
+ "symphonia-metadata",
+]
+
+[[package]]
+name = "symphonia-metadata"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc622b9841a10089c5b18e99eb904f4341615d5aa55bbf4eedde1be721a4023c"
+dependencies = [
+ "encoding_rs",
+ "lazy_static",
+ "log",
+ "symphonia-core",
+]
+
+[[package]]
+name = "symphonia-utils-xiph"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "484472580fa49991afda5f6550ece662237b00c6f562c7d9638d1b086ed010fe"
+dependencies = [
+ "symphonia-core",
+ "symphonia-metadata",
+]
+
[[package]]
name = "syn"
version = "1.0.109"
@@ -3983,7 +4377,17 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
dependencies = [
- "windows-core",
+ "windows-core 0.52.0",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows"
+version = "0.54.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49"
+dependencies = [
+ "windows-core 0.54.0",
"windows-targets 0.52.6",
]
@@ -3996,6 +4400,16 @@ dependencies = [
"windows-targets 0.52.6",
]
+[[package]]
+name = "windows-core"
+version = "0.54.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
+dependencies = [
+ "windows-result",
+ "windows-targets 0.52.6",
+]
+
[[package]]
name = "windows-implement"
version = "0.48.0"
@@ -4018,6 +4432,15 @@ dependencies = [
"syn 1.0.109",
]
+[[package]]
+name = "windows-result"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
[[package]]
name = "windows-sys"
version = "0.45.0"
@@ -4448,6 +4871,13 @@ dependencies = [
"uuid",
]
+[[package]]
+name = "xmpd-player"
+version = "2.0.0"
+dependencies = [
+ "rodio",
+]
+
[[package]]
name = "xmpd-settings"
version = "2.0.0"
diff --git a/Cargo.toml b/Cargo.toml
index cb51893..bc9c4a5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,6 +8,7 @@ members=[
"xmpd-cache",
"xmpd-settings",
"xmpd-tooling",
+ "xmpd-player",
# "xmpd-tui"
]
diff --git a/assets/error.svg b/assets/error.svg
new file mode 100644
index 0000000..c0b9858
--- /dev/null
+++ b/assets/error.svg
@@ -0,0 +1 @@
+
diff --git a/assets/info.svg b/assets/info.svg
new file mode 100644
index 0000000..3a59676
--- /dev/null
+++ b/assets/info.svg
@@ -0,0 +1 @@
+
diff --git a/xmpd-gui/src/components/mod.rs b/xmpd-gui/src/components/mod.rs
index 3d75592..71adbf3 100644
--- a/xmpd-gui/src/components/mod.rs
+++ b/xmpd-gui/src/components/mod.rs
@@ -6,6 +6,7 @@ pub mod left_nav;
pub mod song_list;
pub mod top_nav;
pub mod player;
+pub mod toast;
pub trait CompUi {
fn draw(ui: &mut egui::Ui, state: &mut GuiState) -> crate::Result<()>;
diff --git a/xmpd-gui/src/components/toast.rs b/xmpd-gui/src/components/toast.rs
new file mode 100644
index 0000000..247280b
--- /dev/null
+++ b/xmpd-gui/src/components/toast.rs
@@ -0,0 +1,107 @@
+
+use std::{collections::VecDeque, time::SystemTime};
+
+use egui::{epaint::Shadow, load::TexturePoll, Align2, Color32, Frame, Image, Margin, Pos2, Rect, RichText, Rounding, Stroke, Style, Vec2};
+
+use super::{CompGetter, CompUi};
+
+#[derive(Debug, Default, PartialEq, Clone, Copy)]
+pub enum ToastType {
+ #[default]
+ Info,
+ Warn,
+ Error,
+}
+
+
+#[derive(Debug, Default)]
+pub struct Toast {
+ queue: VecDeque<(String, String, ToastType, SystemTime)>
+}
+
+component_register!(Toast);
+
+impl CompUi for Toast {
+ fn draw(ui: &mut egui::Ui, _: &mut crate::GuiState) -> crate::Result<()> {
+ let screen_size = ui.ctx().screen_rect().size();
+ let (w, h) = (300.0, 100.0);
+ let theme = &xmpd_settings::Settings::get()?.theme;
+ let mut toastw = Toast::get()?;
+ let mut height_iter = 6.0;
+ let mut to_remove = Vec::new();
+
+ for (i, (title, description, toast_type, shown_since)) in toastw.queue.iter().enumerate() {
+ let area = egui::Area::new(egui::Id::new(format!("toast_{i}")))
+ .fixed_pos(Pos2::new(screen_size.x - w, height_iter))
+ .pivot(Align2::LEFT_TOP)
+ .show(ui.ctx(), |ui| {
+ ui.set_width(w);
+
+ let img;
+ let color;
+ match toast_type {
+ ToastType::Info => {
+ color = theme.accent_color;
+ img = Image::new(crate::data::INFO_ICON)
+ .max_size(Vec2::new(16.0, 16.0))
+ .tint(color);
+ }
+ ToastType::Warn => {
+ color = crate::data::C_WARN;
+ img = Image::new(crate::data::WARN_ICON)
+ .max_size(Vec2::new(16.0, 16.0))
+ .tint(color);
+ }
+ ToastType::Error => {
+ color = Color32::LIGHT_RED;
+ img = Image::new(crate::data::ERROR_ICON)
+ .max_size(Vec2::new(16.0, 16.0))
+ .tint(color);
+ }
+ }
+ Frame::none()
+ .stroke(Stroke::new(1.0, color))
+ .fill(theme.primary_bg_color)
+ .rounding(Rounding::same(3.0))
+ .inner_margin(Margin::same(3.0))
+ .show(ui, |ui| {
+ ui.set_width(w-9.0);
+ ui.style_mut().visuals.override_text_color = Some(theme.text_color);
+ ui.horizontal(|ui| {
+
+ ui.add(img);
+ ui.label(RichText::new(title));
+ });
+ ui.label(
+ RichText::new(description)
+ .size(10.0)
+ );
+ ui.shrink_height_to_current();
+ // height_iter += ui.available_height();
+ }
+ )
+ }
+ );
+ height_iter += area.response.rect.height() + 6.0;
+
+ // if shown for longer than 5 seconds remove it
+ if SystemTime::now().duration_since(*shown_since)?.as_secs() > 5 {
+ to_remove.push(i);
+ }
+ }
+
+ for idx in to_remove {
+ toastw.queue.remove(idx);
+ }
+
+ Ok(())
+ }
+}
+
+
+impl Toast {
+ pub fn show_toast(&mut self, title: &str, description: &str, toast_type: ToastType) {
+ self.queue.push_front((title.to_string(), description.to_string(), toast_type, SystemTime::now()));
+ }
+}
+
diff --git a/xmpd-gui/src/components/top_nav.rs b/xmpd-gui/src/components/top_nav.rs
index ace61a2..5684558 100644
--- a/xmpd-gui/src/components/top_nav.rs
+++ b/xmpd-gui/src/components/top_nav.rs
@@ -28,6 +28,12 @@ impl CompUi for TopNav {
ui.ctx().open_url(egui::OpenUrl::new_tab("https://git.mcorangehq.xyz/XOR64/music"));
ui.close_menu();
}
+
+ #[cfg(debug_assertions)]
+ if ui.button("Debug").clicked() {
+ state.windows.toggle(&WindowId::Debug, true);
+ ui.close_menu();
+ }
});
diff --git a/xmpd-gui/src/data.rs b/xmpd-gui/src/data.rs
index b1dd09e..491d85b 100644
--- a/xmpd-gui/src/data.rs
+++ b/xmpd-gui/src/data.rs
@@ -8,4 +8,10 @@ pub const PLAY_ICON: egui::ImageSource = egui::include_image!("../../assets/pla
pub const PAUSE_ICON: egui::ImageSource = egui::include_image!("../../assets/pause.svg");
pub const CHECK_ICON: egui::ImageSource = egui::include_image!("../../assets/check.svg");
pub const DL_ICON: egui::ImageSource = egui::include_image!("../../assets/download.svg");
+pub const INFO_ICON: egui::ImageSource = egui::include_image!("../../assets/info.svg");
pub const WARN_ICON: egui::ImageSource = egui::include_image!("../../assets/warning.svg");
+pub const ERROR_ICON: egui::ImageSource = egui::include_image!("../../assets/error.svg");
+
+
+pub const C_WARN: egui::Color32 = egui::Color32::from_rgb(255, 183, 0); // #ffb700
+
diff --git a/xmpd-gui/src/lib.rs b/xmpd-gui/src/lib.rs
index 004e10f..286c8c6 100644
--- a/xmpd-gui/src/lib.rs
+++ b/xmpd-gui/src/lib.rs
@@ -16,7 +16,7 @@ const W_NAME: &str = "xmpd v2.0.0a";
type Result = anyhow::Result;
pub fn start() -> Result<()> {
- xmpd_cache::Cache::get()?.init();
+ xmpd_cache::Cache::get()?.init()?;
let options = eframe::NativeOptions::default();
let mut state = GuiState::new()?;
let res = eframe::run_simple_native(W_NAME, options, move |ctx, _frame| {
diff --git a/xmpd-gui/src/macros.rs b/xmpd-gui/src/macros.rs
index f32d7e7..3497e4c 100644
--- a/xmpd-gui/src/macros.rs
+++ b/xmpd-gui/src/macros.rs
@@ -21,7 +21,15 @@ macro_rules! handle_error_ui {
match $val {
Ok(v) => v,
Err(e) => {
- log::error!("Error in ui: {e:?}");
+ use crate::components::CompGetter;
+ log::error!("Error in {}:{}: {e}", std::file!(), std::line!());
+ if let Ok(mut toast) = crate::components::toast::Toast::get() {
+ toast.show_toast(
+ &format!("Error in {}:{}", std::file!(), std::line!()),
+ &format!("{e}"),
+ crate::components::toast::ToastType::Error,
+ );
+ }
return;
}
}
diff --git a/xmpd-gui/src/main_window.rs b/xmpd-gui/src/main_window.rs
index fb7a575..9776d58 100644
--- a/xmpd-gui/src/main_window.rs
+++ b/xmpd-gui/src/main_window.rs
@@ -1,10 +1,8 @@
use xmpd_settings::theme::Theme;
-use crate::{components::{song_list, CompUi}, GuiState};
+use crate::{components::{self, song_list, CompUi}, GuiState};
pub fn draw(ctx: &egui::Context, state: &mut GuiState) -> crate::Result<()> {
- // The central panel the region left after adding TopPanel's and SidePanel's
- // ui.heading(format!("Songs ({})", self.manifest.get_song_count()));
let theme = xmpd_settings::Settings::get()?.theme.clone();
egui::TopBottomPanel::new(egui::panel::TopBottomSide::Top, "top_nav")
.frame(get_themed_frame(&theme))
@@ -16,6 +14,7 @@ pub fn draw(ctx: &egui::Context, state: &mut GuiState) -> crate::Result<()> {
egui::CentralPanel::default()
.frame(get_themed_frame(&theme))
.show(ctx, |ui| {
+ handle_error_ui!(components::toast::Toast::draw(ui, state));
let avail = ui.available_size();
ui.vertical(|ui| {
crate::utils::super_separator(ui, theme.accent_color, avail.x, 2.0);
@@ -23,7 +22,7 @@ pub fn draw(ctx: &egui::Context, state: &mut GuiState) -> crate::Result<()> {
let main_height = avail.y * 0.91;
let left_nav_width = (avail.x * 0.25).clamp(0.0, 200.0);
- let song_list_width = (avail.x - left_nav_width - 35.0);
+ let song_list_width = avail.x - left_nav_width - 35.0;
ui.horizontal(|ui| {
ui.set_height(main_height);
ui.group(|ui| {
@@ -54,6 +53,7 @@ pub fn draw(ctx: &egui::Context, state: &mut GuiState) -> crate::Result<()> {
handle_error_ui!(crate::components::player::Player::draw(ui, state));
}
);
+
Ok(())
}
diff --git a/xmpd-gui/src/windows/debug.rs b/xmpd-gui/src/windows/debug.rs
new file mode 100644
index 0000000..84a3e21
--- /dev/null
+++ b/xmpd-gui/src/windows/debug.rs
@@ -0,0 +1,74 @@
+use egui::RichText;
+
+use crate::components::{toast::{self, ToastType}, CompGetter};
+
+use super::Window;
+
+
+#[derive(Debug, Default)]
+pub struct DebugW {
+ toast_title: String,
+ toast_descr: String,
+ toast_type: ToastType,
+}
+
+impl Window for DebugW {
+ fn draw(&mut self, ui: &mut egui::Ui, _: &mut crate::GuiState) -> crate::Result<()> {
+ ui.group(|ui| {
+ ui.vertical(|ui| {
+ ui.label(
+ RichText::new("DEBUG")
+ .heading()
+ );
+ ui.horizontal(|ui| {
+ {
+ ui.group(|ui| {
+ ui.vertical(|ui| {
+ ui.label(
+ RichText::new("Toast")
+ .heading()
+ );
+ Self::add_input_field(&mut self.toast_title, ui, "Title");
+ Self::add_input_field(&mut self.toast_descr, ui, "Description");
+ ui.horizontal(|ui| {
+ ui.label("Type:");
+ egui::ComboBox::from_id_source("debug_combo")
+ .selected_text(format!("{:?}", self.toast_type))
+ .show_ui(ui, |ui| {
+ ui.selectable_value(&mut self.toast_type, ToastType::Info, "Info");
+ ui.selectable_value(&mut self.toast_type, ToastType::Warn, "Warn");
+ ui.selectable_value(&mut self.toast_type, ToastType::Error, "Error");
+ }
+ );
+ });
+ if ui.button("Add").clicked() {
+ toast::Toast::get().unwrap().show_toast(&self.toast_title, &self.toast_descr, self.toast_type);
+ }
+ if ui.button("Throw Error").clicked() {
+ handle_error_ui!(Err(anyhow::anyhow!("{}: {}", self.toast_title, self.toast_descr)));
+ }
+ });
+ });
+
+ }
+ });
+ });
+ });
+ Ok(())
+ }
+}
+
+impl DebugW {
+ fn add_input_field(inp: &mut String, ui: &mut egui::Ui, name: &str) {
+ ui.horizontal(|ui|{
+ ui.label(format!("{name}: "));
+ ui.text_edit_singleline(inp);
+ });
+ }
+ fn add_input_field_ml(inp: &mut String, ui: &mut egui::Ui, name: &str) {
+ ui.horizontal(|ui|{
+ ui.label(format!("{name}: "));
+ ui.text_edit_multiline(inp);
+ });
+ }
+}
diff --git a/xmpd-gui/src/windows/mod.rs b/xmpd-gui/src/windows/mod.rs
index 126e007..bb747af 100644
--- a/xmpd-gui/src/windows/mod.rs
+++ b/xmpd-gui/src/windows/mod.rs
@@ -2,6 +2,8 @@ use std::{collections::{HashMap, HashSet}, sync::{Arc, Mutex}};
use egui::{ViewportBuilder, ViewportId};
use crate::GuiState;
+#[cfg(debug_assertions)]
+mod debug;
mod error;
mod settings;
@@ -18,7 +20,9 @@ pub trait Window: std::fmt::Debug + Send {
#[derive(Debug, Clone, Hash, PartialEq, PartialOrd, Ord, Eq)]
pub enum WindowId {
Settings,
- Error
+ Error,
+ #[cfg(debug_assertions)]
+ Debug
}
#[derive(Debug, Clone)]
@@ -38,6 +42,8 @@ impl Windows {
pub fn add_all_windows(&mut self) {
self.add_new_window(WindowId::Error, "Error!", Box::::default());
self.add_new_window(WindowId::Settings, "Settings", Box::::default());
+ #[cfg(debug_assertions)]
+ self.add_new_window(WindowId::Debug, "Debug", Box::::default());
}
pub fn add_new_window(&mut self, id: WindowId, title: &str, cb: Box) {
diff --git a/xmpd-player/Cargo.toml b/xmpd-player/Cargo.toml
new file mode 100644
index 0000000..f3dc537
--- /dev/null
+++ b/xmpd-player/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "xmpd-player"
+edition = "2021"
+version.workspace = true
+repository.workspace = true
+license.workspace = true
+authors.workspace = true
+
+[dependencies]
+rodio = { version = "0.20.1", features = ["symphonia-all"] }
diff --git a/xmpd-player/src/lib.rs b/xmpd-player/src/lib.rs
new file mode 100644
index 0000000..e69de29