Modularised components, moved everythign there

This commit is contained in:
Gvidas Juknevičius 2024-09-22 01:07:34 +03:00
parent 2cde24e7a8
commit f26fd97809
Signed by: MCorange
GPG Key ID: 12B1346D720B7FBB
5 changed files with 226 additions and 186 deletions

View File

@ -0,0 +1,57 @@
use egui::{Color32, RichText};
use crate::{manifest::song::Song, ui::gui::windows::{song_edit::GuiSongEditor, WindowIndex}};
pub struct ContextMenu;
// NOTE: This should be a component but theres no easy way to do that, so we just make it folow the
// trait manually, ish, more like a convention
impl /* ComponentUi for */ ContextMenu {
pub fn ui(gui: &mut crate::ui::gui::Gui, ui: &mut egui::Ui, pname: &String, sname: &String, song: &Song) {
if ui.button("Edit").clicked() {
let w = gui.windows.get_window::<GuiSongEditor>(WindowIndex::SongEdit);
w.set_active_song(pname, sname, song.get_url_str());
gui.windows.open(WindowIndex::SongEdit, true);
ui.close_menu()
}
if ui.button("Download").clicked() {
if let Err(e) = gui.downloader.download_song_nb(&gui.cfg, pname, sname, song, gui.manifest.get_format()) {
log::error!("{e}");
gui.throw_error(format!("Failed to download song {sname}: {e}"));
}
ui.close_menu()
}
if ui.button("Open Source").clicked() {
if let Err(e) = open::that(song.get_url_str()) {
log::error!("{e}");
gui.throw_error(format!("Failed to open song source: {e}"));
}
ui.close_menu()
}
if ui.button("Play").clicked() {
let p = crate::util::get_song_path(pname, sname, gui.manifest.get_format());
if !p.exists() {
gui.throw_error(format!("Song does not exist on disk"));
} else if let Err(e) = open::that(p) {
log::error!("{e}");
gui.throw_error(format!("Failed to play song: {e}"));
}
ui.close_menu()
}
if ui.button("Delete from disk").clicked() {
let p = crate::util::get_song_path(pname, sname, gui.manifest.get_format());
if p.exists() {
if let Err(e) = std::fs::remove_file(p) {
gui.throw_error(format!("Failed to delete file: {e}"));
}
}
ui.close_menu();
}
if ui.button(RichText::new("Delete").color(Color32::RED)).clicked() {
gui.throw_error("TODO");
ui.close_menu()
}
}
}

View File

@ -0,0 +1,14 @@
use super::Gui;
pub mod nav;
pub mod song_list;
pub mod context_menu;
pub trait Component {
fn ui(gui: &mut Gui, ctx: &egui::Context);
}
pub trait ComponentUi {
fn ui(gui: &mut Gui, ui: &mut egui::Ui);
}

View File

@ -1,8 +1,13 @@
use super::{windows::WindowIndex, Gui};
use crate::ui::gui::{windows::WindowIndex, Gui};
impl Gui {
use super::Component;
pub fn draw_nav(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
pub struct NavBar;
impl Component for NavBar {
fn ui(gui: &mut Gui, ctx: &egui::Context) {
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
// The top panel is often a good place for a menu bar:
egui::menu::bar(ui, |ui| {
@ -11,7 +16,7 @@ impl Gui {
ctx.open_url(egui::OpenUrl::new_tab("https://git.mcorangehq.xyz/XOR64/music"));
}
if ui.button("Save").clicked() {
if let Err(e) = self.manifest.save(None) {
if let Err(e) = gui.manifest.save(None) {
log::error!("Failed to save manifest: {e}");
}
}
@ -22,19 +27,19 @@ impl Gui {
ui.menu_button("Song", |ui| {
if ui.button("Add New").clicked() {
self.windows.open(WindowIndex::SongNew, true);
gui.windows.open(WindowIndex::SongNew, true);
}
});
ui.menu_button("Playlist", |ui| {
if ui.button("Import").clicked() {
self.windows.open(WindowIndex::ImportPlaylist, true);
gui.windows.open(WindowIndex::ImportPlaylist, true);
}
});
ui.menu_button("Downloader", |ui| {
if ui.button("Download All").clicked() {
if let Err(e) = self.downloader.download_all_nb(&self.manifest, &self.cfg) {
if let Err(e) = gui.downloader.download_all_nb(&gui.manifest, &gui.cfg) {
log::error!("Err: {e}");
}
}
@ -42,21 +47,22 @@ impl Gui {
ui.add_space(16.0);
ui.with_layout(egui::Layout::bottom_up(egui::Align::RIGHT), |ui| {
ui.horizontal(|ui| {
if self.downloader.get_songs_left_nb() > 0 {
self.downloading = true;
ui.label(format!("Downloading: {}/{}", self.downloader.get_songs_left_nb(), self.downloader.get_initial_song_count_nb()));
} else if self.downloading {
if gui.downloader.get_songs_left_nb() > 0 {
gui.downloading = true;
ui.label(format!("Downloading: {}/{}", gui.downloader.get_songs_left_nb(), gui.downloader.get_initial_song_count_nb()));
} else if gui.downloading {
let _ = notify_rust::Notification::new()
.summary("Done downloading")
.body("Your music has been downloaded")
.show();
self.downloading = false;
gui.downloading = false;
}
let _ = self.downloader.download_all_nb_poll(&self.cfg);
let _ = gui.downloader.download_all_nb_poll(&gui.cfg);
egui::widgets::global_dark_light_mode_buttons(ui);
});
});
});
});
}
}

View File

@ -0,0 +1,130 @@
use egui::{Color32, RichText};
use egui_extras::{Column, TableBuilder};
use crate::manifest::song::SongType;
use super::{context_menu::ContextMenu, ComponentUi};
pub struct SongList;
impl ComponentUi for SongList {
fn ui(gui: &mut crate::ui::gui::Gui, ui: &mut egui::Ui) {
let fltr_by;
let filter_clean;
if gui.filter.starts_with("playlist:") {
fltr_by = "playlist";
filter_clean = gui.filter.strip_prefix("playlist:").unwrap_or("").to_string().to_lowercase();
} else if gui.filter.starts_with("source:") {
fltr_by = "source";
filter_clean = gui.filter.strip_prefix("source:").unwrap_or("").to_string().to_lowercase();
} else if gui.filter.starts_with("url:") {
fltr_by = "url";
filter_clean = gui.filter.strip_prefix("url:").unwrap_or("").to_string();
} else {
fltr_by = "";
filter_clean = gui.filter.clone();
}
ui.vertical(|ui| {
ui.horizontal(|ui| {
ui.colored_label(Color32::from_hex("#4444aa").unwrap(), "Filter: ");
ui.text_edit_singleline(&mut gui.filter);
});
});
ui.vertical(|ui| {
let available_height = ui.available_height();
let table = TableBuilder::new(ui)
.striped(true)
.cell_layout(egui::Layout::left_to_right(egui::Align::Center))
.resizable(true)
//.column(Column::auto())
.column(Column::auto())
//.column(
// Column::remainder()
// .at_least(40.0)
// .clip(true)
// .resizable(true),
//)
.column(Column::auto())
.column(Column::remainder())
//.column(Column::remainder())
.min_scrolled_height(0.0)
.max_scroll_height(available_height)
.sense(egui::Sense::click());
let playlists = gui.manifest.get_playlists().clone();
let songs = {
let mut songs = Vec::new();
for (pname, p) in playlists {
for (sname, s) in p {
songs.push((pname.clone(), sname, s))
}
}
songs
};
table.header(20.0, |mut header| {
// header.col(|_|{});
header.col(|ui| {
ui.strong("Playlist");
});
header.col(|ui| {
ui.strong("Source");
});
header.col(|ui| {
ui.strong("Name");
});
}).body(|mut body| {
for (pname, sname, s) in songs {
if fltr_by == "playlist" && !filter_clean.is_empty() {
if !pname.to_lowercase().contains(&filter_clean) {
continue;
}
} else if fltr_by == "type" && !filter_clean.is_empty(){
if !s.get_type().to_string().to_lowercase().contains(&filter_clean) {
continue;
}
} else if fltr_by == "url" && !filter_clean.is_empty(){
if !s.get_url_str().contains(&filter_clean) {
continue;
}
} else if !filter_clean.is_empty() {
if !sname.to_lowercase().contains(&filter_clean) {
continue;
}
}
body.row(18.0, |mut row| {
row.col(|ui| {
ui.label(pname.clone())
.context_menu(|ui| ContextMenu::ui(gui, ui, &pname, &sname, &s));
});
row.col(|ui| {
let color =
match s.get_type() {
SongType::Youtube => Color32::from_hex("#FF0000").unwrap(),
SongType::Spotify => Color32::from_hex("#1db954").unwrap(),
SongType::Soundcloud => Color32::from_hex("#F26F23").unwrap()
};
ui.colored_label(color, s.get_type().to_string())
.context_menu(|ui| ContextMenu::ui(gui, ui, &pname, &sname, &s));
});
row.col(|ui| {
ui.hyperlink_to(sname.clone(), s.get_url_str())
.context_menu(|ui| ContextMenu::ui(gui, ui, &pname, &sname, &s));
});
row.response()
.context_menu(|ui| ContextMenu::ui(gui, ui, &pname, &sname, &s));
})
}
});
});
}
}

View File

@ -1,12 +1,9 @@
mod nav_bar;
mod windows;
mod components;
use egui::{Color32, RichText};
use egui_extras::{Column, TableBuilder};
use components::{Component, ComponentUi};
use windows::{State, WindowIndex, WindowManager};
use crate::{config::ConfigWrapper, downloader::Downloader, manifest::{song::{Song, SongType}, Manifest}};
use crate::{config::ConfigWrapper, downloader::Downloader, manifest::Manifest};
#[derive(Debug, Default)]
@ -61,8 +58,8 @@ impl Gui {
}
impl eframe::App for Gui {
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
self.draw_nav(ctx, frame);
fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
components::nav::NavBar::ui(self, ctx);
{
let mut state = State {
cfg: self.cfg.clone(),
@ -78,173 +75,9 @@ impl eframe::App for Gui {
egui::CentralPanel::default().show(ctx, |ui| {
// The central panel the region left after adding TopPanel's and SidePanel's
//ui.heading(format!("Songs ({})", self.manifest.get_song_count()));
let fltr_by;
let filter_clean;
if self.filter.starts_with("playlist:") {
fltr_by = "playlist";
filter_clean = self.filter.strip_prefix("playlist:").unwrap_or("").to_string().to_lowercase();
} else if self.filter.starts_with("source:") {
fltr_by = "source";
filter_clean = self.filter.strip_prefix("source:").unwrap_or("").to_string().to_lowercase();
} else if self.filter.starts_with("url:") {
fltr_by = "url";
filter_clean = self.filter.strip_prefix("url:").unwrap_or("").to_string();
} else {
fltr_by = "";
filter_clean = self.filter.clone();
}
ui.vertical(|ui| {
ui.horizontal(|ui| {
ui.colored_label(Color32::from_hex("#4444aa").unwrap(), "Filter: ");
ui.text_edit_singleline(&mut self.filter);
});
});
ui.vertical(|ui| {
let available_height = ui.available_height();
let table = TableBuilder::new(ui)
.striped(true)
.cell_layout(egui::Layout::left_to_right(egui::Align::Center))
.resizable(true)
//.column(Column::auto())
.column(Column::auto())
//.column(
// Column::remainder()
// .at_least(40.0)
// .clip(true)
// .resizable(true),
//)
.column(Column::auto())
.column(Column::remainder())
//.column(Column::remainder())
.min_scrolled_height(0.0)
.max_scroll_height(available_height)
.sense(egui::Sense::click());
let playlists = self.manifest.get_playlists().clone();
let songs = {
let mut songs = Vec::new();
for (pname, p) in playlists {
for (sname, s) in p {
songs.push((pname.clone(), sname, s))
}
}
songs
};
table.header(20.0, |mut header| {
// header.col(|_|{});
header.col(|ui| {
ui.strong("Playlist");
});
header.col(|ui| {
ui.strong("Source");
});
header.col(|ui| {
ui.strong("Name");
});
}).body(|mut body| {
for (pname, sname, s) in songs {
if fltr_by == "playlist" && !filter_clean.is_empty() {
if !pname.to_lowercase().contains(&filter_clean) {
continue;
}
} else if fltr_by == "type" && !filter_clean.is_empty(){
if !s.get_type().to_string().to_lowercase().contains(&filter_clean) {
continue;
}
} else if fltr_by == "url" && !filter_clean.is_empty(){
if !s.get_url_str().contains(&filter_clean) {
continue;
}
} else if !filter_clean.is_empty() {
if !sname.to_lowercase().contains(&filter_clean) {
continue;
}
}
body.row(18.0, |mut row| {
row.col(|ui| {
ui.label(pname.clone())
.context_menu(|ui| context_menu(self, ui, &pname, &sname, &s));
});
row.col(|ui| {
let color =
match s.get_type() {
SongType::Youtube => Color32::from_hex("#FF0000").unwrap(),
SongType::Spotify => Color32::from_hex("#1db954").unwrap(),
SongType::Soundcloud => Color32::from_hex("#F26F23").unwrap()
};
ui.colored_label(color, s.get_type().to_string())
.context_menu(|ui| context_menu(self, ui, &pname, &sname, &s));
});
row.col(|ui| {
ui.hyperlink_to(sname.clone(), s.get_url_str())
.context_menu(|ui| context_menu(self, ui, &pname, &sname, &s));
});
row.response()
.context_menu(|ui| context_menu(self, ui, &pname, &sname, &s));
fn context_menu(this: &mut Gui, ui: &mut egui::Ui, pname: &String, sname: &String, song: &Song) {
if ui.button("Edit").clicked() {
let w = this.windows.get_window::<windows::song_edit::GuiSongEditor>(WindowIndex::SongEdit);
w.set_active_song(pname, sname, song.get_url_str());
this.windows.open(WindowIndex::SongEdit, true);
ui.close_menu()
}
if ui.button("Download").clicked() {
if let Err(e) = this.downloader.download_song_nb(&this.cfg, pname, sname, song, this.manifest.get_format()) {
log::error!("{e}");
this.throw_error(format!("Failed to download song {sname}: {e}"));
}
ui.close_menu()
}
if ui.button("Open Source").clicked() {
if let Err(e) = open::that(song.get_url_str()) {
log::error!("{e}");
this.throw_error(format!("Failed to open song source: {e}"));
}
ui.close_menu()
}
if ui.button("Play").clicked() {
let p = crate::util::get_song_path(pname, sname, this.manifest.get_format());
if !p.exists() {
this.throw_error(format!("Song does not exist on disk"));
} else if let Err(e) = open::that(p) {
log::error!("{e}");
this.throw_error(format!("Failed to play song: {e}"));
}
ui.close_menu()
}
if ui.button("Delete from disk").clicked() {
let p = crate::util::get_song_path(pname, sname, this.manifest.get_format());
if p.exists() {
if let Err(e) = std::fs::remove_file(p) {
this.throw_error(format!("Failed to delete file: {e}"));
}
}
ui.close_menu();
}
if ui.button(RichText::new("Delete").color(Color32::RED)).clicked() {
this.throw_error("TODO");
ui.close_menu()
}
}
})
}
});
});
components::song_list::SongList::ui(self, ui);
ui.separator();
ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| {
egui::warn_if_debug_build(ui);
});