Extra gui stuff, looking really nice at this point
This commit is contained in:
parent
a384f45796
commit
14ee1e69bc
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4353,6 +4353,7 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"uuid",
|
||||||
"xmpd-derive",
|
"xmpd-derive",
|
||||||
"xmpd-manifest",
|
"xmpd-manifest",
|
||||||
]
|
]
|
||||||
|
|
1385
manifest.json
1385
manifest.json
File diff suppressed because one or more lines are too long
|
@ -28,3 +28,4 @@ lazy_static.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
egui_extras.workspace = true
|
egui_extras.workspace = true
|
||||||
egui-aesthetix = "0.2.4"
|
egui-aesthetix = "0.2.4"
|
||||||
|
uuid.workspace = true
|
||||||
|
|
|
@ -1,40 +1,90 @@
|
||||||
|
use egui::RichText;
|
||||||
use xmpd_manifest::store::BaseStore;
|
use xmpd_manifest::store::BaseStore;
|
||||||
|
|
||||||
use super::CompUi;
|
use super::{CompGetter, CompUi};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct LeftNav;
|
pub struct LeftNav {
|
||||||
|
pub selected_playlist_id: Option<uuid::Uuid>,
|
||||||
|
}
|
||||||
|
|
||||||
component_register!(LeftNav);
|
component_register!(LeftNav);
|
||||||
|
|
||||||
impl CompUi for LeftNav {
|
impl CompUi for LeftNav {
|
||||||
fn draw(ui: &mut egui::Ui, state: &mut crate::GuiState) -> crate::Result<()> {
|
fn draw(ui: &mut egui::Ui, state: &mut crate::GuiState) -> crate::Result<()> {
|
||||||
let height = ui.available_height();
|
let w = ui.available_width();
|
||||||
egui::ScrollArea::vertical().id_source("left_nav").show(ui, |ui| {
|
egui::ScrollArea::vertical()
|
||||||
//ui.horizontal(|ui| {
|
.id_source("left_nav")
|
||||||
|
.drag_to_scroll(false)
|
||||||
|
.show(ui, |ui| {
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
let playlists = state.manifest.store().get_playlists();
|
let len = state.manifest.store().get_songs().len();
|
||||||
for (_pid, playlist) in playlists.iter() {
|
add_playlist_tab(ui, &None, "All Songs", None, len, w);
|
||||||
ui.horizontal(|ui| {
|
let mut playlists: Vec<_> = state.manifest.store().get_playlists().into_iter().collect();
|
||||||
ui.add_space(5.0);
|
playlists.sort_by(|a, b| {
|
||||||
ui.add(
|
let a = a.1.name().to_lowercase();
|
||||||
egui::Image::new(crate::data::NOTE_ICON)
|
let b = b.1.name().to_lowercase();
|
||||||
.tint(crate::data::C_ACCENT)
|
a.cmp(&b)
|
||||||
.fit_to_exact_size(egui::Vec2::new(32.0, 32.0))
|
});
|
||||||
);
|
for (pid, playlist) in playlists.iter() {
|
||||||
ui.label(playlist.name());
|
add_playlist_tab(ui,
|
||||||
ui.with_layout(egui::Layout::bottom_up(egui::Align::RIGHT), |ui| {
|
&Some(**pid),
|
||||||
ui.label(format!("{}", playlist.songs().len()));
|
playlist.name(),
|
||||||
});
|
Some(playlist.author()),
|
||||||
});
|
playlist.songs().len(),
|
||||||
ui.separator();
|
w
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_playlist_tab(ui: &mut egui::Ui, pid: &Option<uuid::Uuid>, title: &str, author: Option<&str>, song_count: usize, width: f32) {
|
||||||
|
let wdg_rect = ui.horizontal(|ui| {
|
||||||
|
ui.set_width(width);
|
||||||
|
ui.add_space(5.0);
|
||||||
|
ui.add(
|
||||||
|
egui::Image::new(crate::data::NOTE_ICON)
|
||||||
|
.tint(crate::data::C_ACCENT)
|
||||||
|
.fit_to_exact_size(egui::Vec2::new(32.0, 32.0))
|
||||||
|
);
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
{
|
||||||
|
if handle_error_ui!(LeftNav::get()).selected_playlist_id == *pid {
|
||||||
|
ui.label(
|
||||||
|
RichText::new(title)
|
||||||
|
.size(10.0)
|
||||||
|
.color(crate::data::C_ACCENT)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
ui.label(
|
||||||
|
RichText::new(title)
|
||||||
|
.size(10.0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(author) = author {
|
||||||
|
ui.monospace(
|
||||||
|
RichText::new(format!("By {author}"))
|
||||||
|
.color(crate::data::C_TEXT_DIM)
|
||||||
|
.size(8.0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ui.monospace(
|
||||||
|
RichText::new(format!("{song_count} songs"))
|
||||||
|
.color(crate::data::C_TEXT_DIM)
|
||||||
|
.size(8.0)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}).response.rect;
|
||||||
|
|
||||||
|
if ui.interact(wdg_rect, format!("left_nav_playlist_{pid:?}").into(), egui::Sense::click()).clicked() {
|
||||||
|
handle_error_ui!(LeftNav::get()).selected_playlist_id = pid.clone();
|
||||||
|
}
|
||||||
|
ui.separator();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
use egui::{Color32, RichText, Vec2};
|
|
||||||
use xmpd_manifest::store::BaseStore;
|
|
||||||
|
|
||||||
use super::CompUi;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct SongList;
|
|
||||||
|
|
||||||
component_register!(SongList);
|
|
||||||
|
|
||||||
impl CompUi for SongList {
|
|
||||||
fn draw(ui: &mut egui::Ui, state: &mut crate::GuiState) -> crate::Result<()> {
|
|
||||||
egui::ScrollArea::vertical().id_source("song_list").show(ui, |ui| {
|
|
||||||
ui.vertical(|ui| {
|
|
||||||
ui.add_space(3.0);
|
|
||||||
let songs = state.manifest.store().get_songs();
|
|
||||||
for (sid, song) in songs.iter() {
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.add(
|
|
||||||
egui::Image::new(crate::data::NOTE_ICON)
|
|
||||||
.tint(crate::data::C_ACCENT)
|
|
||||||
.fit_to_exact_size(Vec2::new(32.0, 32.0))
|
|
||||||
);
|
|
||||||
ui.vertical(|ui| {
|
|
||||||
ui.label(song.name());
|
|
||||||
ui.monospace(
|
|
||||||
RichText::new(song.author())
|
|
||||||
.color(crate::data::C_TEXT_DIM)
|
|
||||||
.size(10.0)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ui.separator();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
107
xmpd-gui/src/components/song_list/mod.rs
Normal file
107
xmpd-gui/src/components/song_list/mod.rs
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
use egui::{Color32, RichText, Vec2};
|
||||||
|
use song_list_nav::SearchType;
|
||||||
|
use xmpd_manifest::{query::QueryType, song::Song, store::BaseStore};
|
||||||
|
use super::{CompGetter, CompUi};
|
||||||
|
|
||||||
|
pub mod song_list_nav;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct SongList {
|
||||||
|
selected_song_id: uuid::Uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
component_register!(SongList);
|
||||||
|
|
||||||
|
impl CompUi for SongList {
|
||||||
|
fn draw(ui: &mut egui::Ui, state: &mut crate::GuiState) -> crate::Result<()> {
|
||||||
|
egui::ScrollArea::vertical()
|
||||||
|
.id_source("song_list")
|
||||||
|
.drag_to_scroll(false)
|
||||||
|
.show(ui, |ui| {
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.add_space(3.0);
|
||||||
|
let pid = {handle_error_ui!(super::left_nav::LeftNav::get()).selected_playlist_id.clone()};
|
||||||
|
match pid {
|
||||||
|
None => {
|
||||||
|
let mut songs: Vec<_> = state.manifest.store().get_songs().iter().collect();
|
||||||
|
songs.sort_by(|a, b| {
|
||||||
|
let a = a.1.name().to_lowercase();
|
||||||
|
let b = b.1.name().to_lowercase();
|
||||||
|
a.cmp(&b)
|
||||||
|
});
|
||||||
|
|
||||||
|
for (sid, song) in songs {
|
||||||
|
let query = {handle_error_ui!(song_list_nav::SongListNav::get()).parse_search()}.clone();
|
||||||
|
let should_display = match query {
|
||||||
|
SearchType::Source(s) if !s.is_empty() => format!("{:?}", &song.source_type()).to_lowercase().contains(&s),
|
||||||
|
SearchType::Author(s) if !s.is_empty() => song.author().to_lowercase().contains(&s),
|
||||||
|
SearchType::Name(s) if !s.is_empty() => song.name().to_owned().contains(&s),
|
||||||
|
_ => true
|
||||||
|
};
|
||||||
|
if should_display {
|
||||||
|
display_song_tab(ui, sid, song);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(pid) => {
|
||||||
|
if let Some(playlist) = state.manifest.store().get_playlist(&pid) {
|
||||||
|
let mut songs = Vec::new();
|
||||||
|
for sid in playlist.songs() {
|
||||||
|
if let Some(song) = state.manifest.store().get_song(&sid) {
|
||||||
|
songs.push((sid, song));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
songs.sort_by(|a, b| {
|
||||||
|
let a = a.1.name().to_lowercase();
|
||||||
|
let b = b.1.name().to_lowercase();
|
||||||
|
a.cmp(&b)
|
||||||
|
});
|
||||||
|
let query = {handle_error_ui!(song_list_nav::SongListNav::get()).parse_search()}.clone();
|
||||||
|
for (sid, song) in songs {
|
||||||
|
let should_display = match query {
|
||||||
|
SearchType::Source(ref s) if !s.is_empty() && format!("{:?}", &song.source_type()).to_lowercase().contains(s) => true,
|
||||||
|
SearchType::Author(ref s) if !s.is_empty() && song.author().to_lowercase().contains(s) => true,
|
||||||
|
SearchType::Name(ref s) if !s.is_empty() && song.name().to_owned().contains(s) => true,
|
||||||
|
_ => false
|
||||||
|
};
|
||||||
|
if should_display {
|
||||||
|
display_song_tab(ui, sid, song);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_song_tab(ui: &mut egui::Ui, sid: &uuid::Uuid, song: &Song) {
|
||||||
|
|
||||||
|
let rct = ui.horizontal(|ui| {
|
||||||
|
ui.add(
|
||||||
|
egui::Image::new(crate::data::NOTE_ICON)
|
||||||
|
.tint(crate::data::C_ACCENT)
|
||||||
|
.fit_to_exact_size(Vec2::new(32.0, 32.0))
|
||||||
|
);
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
let selected_song_id = {handle_error_ui!(SongList::get()).selected_song_id};
|
||||||
|
if selected_song_id == *sid {
|
||||||
|
ui.label(RichText::new(song.name()).color(crate::data::C_ACCENT));
|
||||||
|
} else {
|
||||||
|
ui.label(song.name());
|
||||||
|
};
|
||||||
|
ui.monospace(
|
||||||
|
RichText::new(format!("By {}", song.author()))
|
||||||
|
.color(crate::data::C_TEXT_DIM)
|
||||||
|
.size(10.0)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}).response.rect;
|
||||||
|
if ui.interact(rct, format!("song_list_{sid:?}").into(), egui::Sense::click()).clicked() {
|
||||||
|
handle_error_ui!(SongList::get()).selected_song_id = sid.clone();
|
||||||
|
}
|
||||||
|
ui.separator();
|
||||||
|
}
|
46
xmpd-gui/src/components/song_list/song_list_nav.rs
Normal file
46
xmpd-gui/src/components/song_list/song_list_nav.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
use crate::components::{CompGetter, CompUi};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum SearchType {
|
||||||
|
Name(String),
|
||||||
|
Author(String),
|
||||||
|
Source(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct SongListNav {
|
||||||
|
text: String
|
||||||
|
}
|
||||||
|
|
||||||
|
component_register!(SongListNav);
|
||||||
|
|
||||||
|
impl CompUi for SongListNav {
|
||||||
|
fn draw(ui: &mut egui::Ui, _: &mut crate::GuiState) -> crate::Result<()> {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
let search_icon = egui::Image::new(crate::data::SEARCH_ICON)
|
||||||
|
.fit_to_exact_size(egui::Vec2::new(16.0, 16.0))
|
||||||
|
.tint(crate::data::C_ACCENT);
|
||||||
|
ui.add(search_icon);
|
||||||
|
{
|
||||||
|
ui.text_edit_singleline(&mut handle_error_ui!(SongListNav::get()).text);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SongListNav {
|
||||||
|
pub fn parse_search(&self) -> SearchType {
|
||||||
|
match &self.text {
|
||||||
|
i @ _ if i.starts_with("source:") =>
|
||||||
|
SearchType::Source(i.strip_prefix("source:").unwrap_or("").to_string().to_lowercase()),
|
||||||
|
i @ _ if i.starts_with("author:") =>
|
||||||
|
SearchType::Author(i.strip_prefix("author:").unwrap_or("").to_string().to_lowercase()),
|
||||||
|
i @ _ => SearchType::Name(i.to_string().to_lowercase())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,13 @@ impl CompUi for TopNav {
|
||||||
ui.ctx().open_url(egui::OpenUrl::new_tab("https://git.mcorangehq.xyz/XOR64/music"));
|
ui.ctx().open_url(egui::OpenUrl::new_tab("https://git.mcorangehq.xyz/XOR64/music"));
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
});
|
||||||
|
ui.menu_button("Manifest", |ui| {
|
||||||
|
if ui.button("Save").clicked() {
|
||||||
|
handle_error_ui!(state.manifest.save());
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,17 @@ pub fn draw(ui: &mut egui::Ui, state: &mut GuiState) -> crate::Result<()> {
|
||||||
ui.set_height(main_height);
|
ui.set_height(main_height);
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
ui.set_height(main_height);
|
ui.set_height(main_height);
|
||||||
ui.set_width(avail.x * 0.25);
|
ui.set_max_width((avail.x * 0.25).clamp(0.0, 200.0));
|
||||||
handle_error_ui!(crate::components::left_nav::LeftNav::draw(ui, state));
|
handle_error_ui!(crate::components::left_nav::LeftNav::draw(ui, state));
|
||||||
});
|
});
|
||||||
ui.group(|ui| {
|
ui.vertical(|ui| {
|
||||||
handle_error_ui!(crate::components::song_list::SongList::draw(ui, state));
|
ui.group(|ui| {
|
||||||
|
ui.set_width(avail.x * 0.75);
|
||||||
|
handle_error_ui!(crate::components::song_list::song_list_nav::SongListNav::draw(ui, state));
|
||||||
|
});
|
||||||
|
ui.group(|ui| {
|
||||||
|
handle_error_ui!(crate::components::song_list::SongList::draw(ui, state));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
egui::TopBottomPanel::new(egui::panel::TopBottomSide::Bottom, "player")
|
egui::TopBottomPanel::new(egui::panel::TopBottomSide::Bottom, "player")
|
||||||
|
@ -41,33 +47,6 @@ pub fn draw(ui: &mut egui::Ui, state: &mut GuiState) -> crate::Result<()> {
|
||||||
handle_error_ui!(crate::components::player::Player::draw(ui, state));
|
handle_error_ui!(crate::components::player::Player::draw(ui, state));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
//ui.vertical_centered_justified(|ui| {
|
|
||||||
// ui.with_layout(egui::Layout::top_down_justified(egui::Align::TOP), |ui| {
|
|
||||||
// let avail = ui.available_size();
|
|
||||||
// ui.vertical(|ui| {
|
|
||||||
// let avail_width = ui.available_width();
|
|
||||||
// ui.set_height(avail.y);
|
|
||||||
// ui.vertical(|ui| {
|
|
||||||
// ui.set_height(avail.y * 0.9);
|
|
||||||
// ui.horizontal(|ui| {
|
|
||||||
//
|
|
||||||
// ui.group(|ui| {
|
|
||||||
// ui.set_width(avail_width * 0.25);
|
|
||||||
// handle_error_ui!(crate::components::left_nav::LeftNav::draw(ui, state));
|
|
||||||
// });
|
|
||||||
// // crate::utils::super_separator(ui, crate::data::C_ACCENT, 3.0, avail_width);
|
|
||||||
// // handle_error_ui!(crate::components::song_list::SongList::draw(ui, state));
|
|
||||||
// });
|
|
||||||
// // handle_error_ui!(crate::components::player::Player::draw(ui, state));
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| {
|
|
||||||
// egui::warn_if_debug_build(ui);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
//});
|
|
||||||
//
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user