New icons, new side panel, table no longer shows playlists, as they are selectable seperately
This commit is contained in:
5
src/data.rs
Normal file
5
src/data.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
// pub const APP_ICON: egui::ImageSource = egui::include_image!("../assets/app_icon.png");
|
||||
pub const APP_ICON_BYTES: &[u8] = include_bytes!("../assets/app_icon.png");
|
||||
pub const NOTE_ICON: egui::ImageSource = egui::include_image!("../assets/note.svg");
|
||||
pub const SEARCH_ICON: egui::ImageSource = egui::include_image!("../assets/search.svg");
|
||||
@@ -143,8 +143,8 @@ impl Downloader {
|
||||
log::debug!("File {dl_file} doesnt exist, downloading");
|
||||
let mut cmd = match song.get_type() {
|
||||
|
||||
&SongType::Youtube => {
|
||||
log::debug!("Song {} is from yotube", song.get_url_str());
|
||||
SongType::Youtube | SongType::Soundcloud=> {
|
||||
log::debug!("Song {} is from youtube or sondclound", song.get_url_str());
|
||||
let mut cmd = tokio::process::Command::new(&cfg.cfg.ytdlp.path);
|
||||
cmd.args([
|
||||
"-x",
|
||||
@@ -168,7 +168,7 @@ impl Downloader {
|
||||
]);
|
||||
cmd
|
||||
}
|
||||
url @ SongType::Soundcloud => {
|
||||
url => {
|
||||
log::error!("Unknown or unsupported hostname '{:?}'", url);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#![feature(downcast_unchecked)]
|
||||
#![feature(async_closure)]
|
||||
|
||||
use config::ConfigWrapper;
|
||||
|
||||
@@ -13,12 +14,14 @@ mod constants;
|
||||
mod process_manager;
|
||||
mod ui;
|
||||
mod prompt;
|
||||
mod data;
|
||||
|
||||
fn main() {
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let Ok(cfg) = ConfigWrapper::parse() else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
let mut manifest = match manifest::Manifest::load_new(&cfg.cli.manifest.clone().into_std_path_buf()) {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
|
||||
@@ -18,7 +18,6 @@ lazy_static::lazy_static!(
|
||||
static PROC_INC: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
|
||||
|
||||
pub fn add_proc(mut cmd: Command, msg: String) -> anyhow::Result<()> {
|
||||
let mut proc = cmd.spawn()?;
|
||||
let id = PROC_INC.fetch_add(1, Ordering::AcqRel);
|
||||
@@ -65,7 +64,7 @@ pub fn purge_done_procs() -> usize {
|
||||
finish_count
|
||||
}
|
||||
|
||||
/// Waits for processes to finish untill the proc count is lower or equal to `max`
|
||||
/// Waits for processes to finish until the proc count is lower or equal to `max`
|
||||
pub fn wait_for_procs_untill(max: usize) -> anyhow::Result<usize> {
|
||||
// NOTE: This looks really fucked because i dont want to deadlock the processes so i lock PROCESSES for as little as possible
|
||||
// NOTE: So its also kinda really slow
|
||||
|
||||
@@ -9,7 +9,7 @@ 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());
|
||||
w.set_active_song(pname, sname, song.get_url_str(), song.get_type());
|
||||
gui.windows.open(WindowIndex::SongEdit, true);
|
||||
ui.close_menu();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ use super::Gui;
|
||||
pub mod nav;
|
||||
pub mod song_list;
|
||||
pub mod context_menu;
|
||||
pub mod side_nav;
|
||||
pub mod search_bar;
|
||||
|
||||
pub trait Component {
|
||||
fn ui(gui: &mut Gui, ctx: &egui::Context);
|
||||
@@ -12,3 +14,7 @@ pub trait Component {
|
||||
pub trait ComponentUi {
|
||||
fn ui(gui: &mut Gui, ui: &mut egui::Ui);
|
||||
}
|
||||
|
||||
pub trait ComponentUiMut {
|
||||
fn ui(&mut self, gui: &mut Gui, ui: &mut egui::Ui);
|
||||
}
|
||||
|
||||
53
src/ui/gui/components/search_bar.rs
Normal file
53
src/ui/gui/components/search_bar.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use egui::Color32;
|
||||
|
||||
use super::ComponentUiMut;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct SearchBar {
|
||||
text: String
|
||||
}
|
||||
|
||||
pub enum SearchType {
|
||||
Generic,
|
||||
Song,
|
||||
Url,
|
||||
Source,
|
||||
}
|
||||
|
||||
impl SearchBar {
|
||||
pub fn get_search(&self) -> (SearchType, String) {
|
||||
if self.text.starts_with("source:") {
|
||||
(
|
||||
SearchType::Source,
|
||||
self.text.strip_prefix("source:").unwrap_or("").to_string().to_lowercase()
|
||||
)
|
||||
} else if self.text.starts_with("song:") {
|
||||
(
|
||||
SearchType::Song,
|
||||
self.text.strip_prefix("song:").unwrap_or("").to_string().to_lowercase()
|
||||
)
|
||||
} else if self.text.starts_with("url:") {
|
||||
(
|
||||
SearchType::Url,
|
||||
self.text.strip_prefix("url:").unwrap_or("").to_string().to_lowercase()
|
||||
)
|
||||
} else {
|
||||
(
|
||||
SearchType::Generic,
|
||||
self.text.clone()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ComponentUiMut for SearchBar {
|
||||
fn ui(&mut self, _: &mut crate::ui::gui::Gui, ui: &mut egui::Ui) {
|
||||
ui.vertical(|ui| {
|
||||
ui.horizontal(|ui| {
|
||||
let tint = Color32::from_hex("#333377").unwrap();
|
||||
ui.add(egui::Image::new(crate::data::SEARCH_ICON).tint(tint));
|
||||
ui.text_edit_singleline(&mut self.text);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
45
src/ui/gui/components/side_nav.rs
Normal file
45
src/ui/gui/components/side_nav.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use std::borrow::BorrowMut;
|
||||
|
||||
use egui::{Button, Color32, Label, RichText, Sense};
|
||||
|
||||
use super::ComponentUi;
|
||||
|
||||
|
||||
|
||||
pub struct SideNav;
|
||||
|
||||
impl ComponentUi for SideNav {
|
||||
fn ui(gui: &mut crate::ui::gui::Gui, ui: &mut egui::Ui) {
|
||||
let mut playlist_names = gui.manifest
|
||||
.get_playlists()
|
||||
.keys().cloned().collect::<Vec<String>>();
|
||||
|
||||
playlist_names.sort_by_key(|name| name.to_lowercase());
|
||||
ui.with_layout(egui::Layout::top_down(egui::Align::TOP), |ui| {
|
||||
|
||||
for pname in playlist_names {
|
||||
if gui.current_playlist.is_empty() {
|
||||
gui.current_playlist = pname.to_string();
|
||||
}
|
||||
ui.horizontal(|ui| {
|
||||
|
||||
let tint = Color32::from_hex("#333377").unwrap();
|
||||
ui.add(egui::Image::new(crate::data::NOTE_ICON).tint(tint));
|
||||
ui.horizontal(|ui| {
|
||||
let text;
|
||||
if gui.current_playlist == *pname {
|
||||
text = RichText::new(&pname).color(tint);
|
||||
} else {
|
||||
text = RichText::new(&pname);
|
||||
}
|
||||
let button = Label::new(text).sense(Sense::click());
|
||||
if ui.add(button).clicked() {
|
||||
gui.current_playlist = pname.to_string();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
// #333377
|
||||
}
|
||||
@@ -3,126 +3,128 @@ use egui_extras::{Column, TableBuilder};
|
||||
|
||||
use crate::manifest::song::SongType;
|
||||
|
||||
use super::{context_menu::ContextMenu, ComponentUi};
|
||||
use super::{context_menu::ContextMenu, search_bar::SearchType, ComponentUi};
|
||||
|
||||
|
||||
pub struct SongList;
|
||||
#[derive(Debug, Default)]
|
||||
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());
|
||||
{
|
||||
use crate::ui::gui::components::ComponentUiMut;
|
||||
let mut search = gui.search.clone();
|
||||
search.ui(gui, ui);
|
||||
gui.search = search;
|
||||
}
|
||||
|
||||
let playlists = gui.manifest.get_playlists().clone();
|
||||
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));
|
||||
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() && !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));
|
||||
|
||||
songs.sort_by_key(|song| song.1.to_lowercase());
|
||||
songs
|
||||
};
|
||||
|
||||
table.header(20.0, |mut header| {
|
||||
// header.col(|_|{});
|
||||
//header.col(|ui| {
|
||||
// ui.strong("Playlist");vec.sort_by_key(|name| name.to_lowercase());
|
||||
//});
|
||||
header.col(|ui| {
|
||||
ui.strong("Source");
|
||||
});
|
||||
}
|
||||
header.col(|ui| {
|
||||
ui.strong("Name");
|
||||
});
|
||||
}).body(|mut body| {
|
||||
for (pname, sname, s) in songs {
|
||||
if pname != gui.current_playlist {
|
||||
continue;
|
||||
}
|
||||
match gui.search.get_search() {
|
||||
(SearchType::Generic, filter) if !filter.is_empty() => {
|
||||
if !pname.to_lowercase().contains(&filter) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
(SearchType::Song, filter) if !filter.is_empty() => {
|
||||
if !sname.to_lowercase().contains(&filter) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
(SearchType::Source, filter) if !filter.is_empty() => {
|
||||
if !s.get_type().to_string().to_lowercase().contains(&filter) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
(SearchType::Url, filter) if !filter.is_empty() => {
|
||||
if !s.get_url_str().contains(&filter) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
(SearchType::Source, _) => (),
|
||||
(SearchType::Song, _) => (),
|
||||
(SearchType::Generic, _) => (),
|
||||
(SearchType::Url, _) => (),
|
||||
}
|
||||
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));
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ mod windows;
|
||||
mod components;
|
||||
|
||||
use components::{Component, ComponentUi};
|
||||
use egui_extras::install_image_loaders;
|
||||
use windows::{State, WindowIndex, WindowManager};
|
||||
use crate::{config::ConfigWrapper, downloader::Downloader, manifest::Manifest};
|
||||
|
||||
@@ -10,10 +11,11 @@ use crate::{config::ConfigWrapper, downloader::Downloader, manifest::Manifest};
|
||||
pub struct Gui {
|
||||
windows: WindowManager,
|
||||
manifest: Manifest,
|
||||
filter: String,
|
||||
downloader: Downloader,
|
||||
cfg: ConfigWrapper,
|
||||
downloading: bool,
|
||||
search: components::search_bar::SearchBar,
|
||||
current_playlist: String,
|
||||
}
|
||||
|
||||
impl Gui {
|
||||
@@ -33,13 +35,13 @@ impl Gui {
|
||||
.with_inner_size([400.0, 300.0])
|
||||
.with_min_inner_size([300.0, 220.0])
|
||||
.with_icon(
|
||||
eframe::icon_data::from_png_bytes(&include_bytes!("../../../assets/icon.png")[..])?,
|
||||
eframe::icon_data::from_png_bytes(crate::data::APP_ICON_BYTES)?,
|
||||
),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if let Err(e) = eframe::run_native(
|
||||
"eframe template",
|
||||
"McMG",
|
||||
native_options,
|
||||
Box::new(|cc| Box::new(Gui::new(cc, manifest, downloader, cfg))),
|
||||
) {
|
||||
@@ -59,7 +61,7 @@ impl Gui {
|
||||
|
||||
impl eframe::App for Gui {
|
||||
fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
|
||||
components::nav::NavBar::ui(self, ctx);
|
||||
install_image_loaders(ctx);
|
||||
{
|
||||
let mut state = State {
|
||||
cfg: self.cfg.clone(),
|
||||
@@ -72,14 +74,24 @@ impl eframe::App for Gui {
|
||||
self.manifest = state.manifest;
|
||||
}
|
||||
|
||||
components::nav::NavBar::ui(self, ctx);
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
let avail_height = ui.available_height();
|
||||
// The central panel the region left after adding TopPanel's and SidePanel's
|
||||
//ui.heading(format!("Songs ({})", self.manifest.get_song_count()));
|
||||
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);
|
||||
ui.vertical_centered_justified(|ui| {
|
||||
ui.with_layout(egui::Layout::top_down_justified(egui::Align::TOP), |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.set_height(avail_height);
|
||||
components::side_nav::SideNav::ui(self, ui);
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
use crate::manifest::song::{Song, SongType};
|
||||
|
||||
use super::{State, Window};
|
||||
|
||||
|
||||
#[allow(clippy::pedantic)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct GuiImportPlaylist {
|
||||
ed_type: SongType,
|
||||
ed_name: String,
|
||||
ed_url: String,
|
||||
urls_to_add: Vec<String>,
|
||||
playlist_name: String,
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +21,15 @@ impl Window for GuiImportPlaylist {
|
||||
.open(open)
|
||||
.show(ctx, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Type: Youtube");
|
||||
ui.label("Type: ");
|
||||
egui::ComboBox::from_id_source("new_playlist_window_type")
|
||||
.selected_text(format!("{:?}", self.ed_type))
|
||||
.show_ui(ui, |ui| {
|
||||
ui.selectable_value(&mut self.ed_type, SongType::Youtube, "Youtube");
|
||||
ui.selectable_value(&mut self.ed_type, SongType::Spotify, "Spotify");
|
||||
// ui.selectable_value(&mut self.ed_type, SongType::Soundcloud, "Soundcloud");
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
@@ -33,6 +46,20 @@ impl Window for GuiImportPlaylist {
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(url) = self.urls_to_add.pop() {
|
||||
todo!();
|
||||
//let client = reqwest::blocking::Client::new();
|
||||
// let song_name = crate::crawler::spotify::get_song_name(&client, url.clone())?;
|
||||
|
||||
//if let Some(playlist) = state.manifest.get_playlist_mut(&self.playlist_name) {
|
||||
// let mut song = Song::from_url_str(url)?;
|
||||
// song.set_type(SongType::Spotify);
|
||||
// playlist.add_song(song_name, song);
|
||||
//}
|
||||
//let _ = state.manifest.save(None);
|
||||
}
|
||||
|
||||
|
||||
if save {
|
||||
let name = self.ed_name.clone();
|
||||
let url = self.ed_url.clone();
|
||||
@@ -40,15 +67,22 @@ impl Window for GuiImportPlaylist {
|
||||
if state.manifest.get_playlist(&name).is_some() {
|
||||
log::error!("Playlist {name} already exists");
|
||||
}
|
||||
if self.ed_type == SongType::Spotify {
|
||||
todo!()
|
||||
//let client = reqwest::blocking::Client::new();
|
||||
//self.urls_to_add = crate::crawler::spotify::get_playlist_song_urls(&client, self.ed_url.clone())?;
|
||||
//self.playlist_name = self.ed_name.clone();
|
||||
//state.manifest.add_playlist(name.clone());
|
||||
} else if self.ed_type == SongType::Youtube {
|
||||
let songs = state.downloader.download_playlist_nb(&state.cfg, &url, &name, state.manifest.get_format()).unwrap();
|
||||
state.manifest.add_playlist(name.clone());
|
||||
|
||||
let songs = state.downloader.download_playlist_nb(&state.cfg, &url, &name, state.manifest.get_format()).unwrap();
|
||||
state.manifest.add_playlist(name.clone());
|
||||
|
||||
let playlist = state.manifest.get_playlist_mut(&name).expect("Unreachable");
|
||||
|
||||
for (sname, song) in songs {
|
||||
log::info!("Added: {sname}");
|
||||
playlist.add_song(sname, song);
|
||||
let playlist = state.manifest.get_playlist_mut(&name).expect("Unreachable");
|
||||
|
||||
for (sname, song) in songs {
|
||||
log::info!("Added: {sname}");
|
||||
playlist.add_song(sname, song);
|
||||
}
|
||||
}
|
||||
let _ = state.manifest.save(None);
|
||||
*open = false;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use anyhow::bail;
|
||||
use egui::Color32;
|
||||
|
||||
use crate::manifest::song::SongType;
|
||||
|
||||
use super::{State, Window};
|
||||
|
||||
|
||||
@@ -9,19 +11,20 @@ pub struct GuiSongEditor {
|
||||
song: (String, String),
|
||||
ed_url: String,
|
||||
ed_name: String,
|
||||
ed_type: SongType
|
||||
}
|
||||
|
||||
|
||||
impl Window for GuiSongEditor {
|
||||
fn ui(&mut self, state: &mut State, ctx: &egui::Context, open: &mut bool) -> anyhow::Result<()> {
|
||||
let mut save = false;
|
||||
let (playlist, song_name) = self.song.clone();
|
||||
let (playlist_name, song_name) = self.song.clone();
|
||||
|
||||
if playlist.is_empty() {
|
||||
if playlist_name.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let Some(song) = state.manifest.get_song(&playlist, &song_name) else {
|
||||
let Some(song) = state.manifest.get_song(&playlist_name, &song_name) else {
|
||||
bail!("Failed to get song (1)");
|
||||
};
|
||||
let song = song.clone();
|
||||
@@ -36,7 +39,7 @@ impl Window for GuiSongEditor {
|
||||
ui.label("[");
|
||||
ui.hyperlink_to("link", song.get_url().unwrap());
|
||||
ui.label("] ");
|
||||
ui.colored_label(Color32::LIGHT_BLUE, &playlist);
|
||||
ui.colored_label(Color32::LIGHT_BLUE, &playlist_name);
|
||||
ui.label(": ");
|
||||
ui.label(&song_name)
|
||||
});
|
||||
@@ -44,6 +47,14 @@ impl Window for GuiSongEditor {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Type: ");
|
||||
ui.label(song.get_type().to_string());
|
||||
egui::ComboBox::from_id_source("song_edit_window_type")
|
||||
.selected_text(format!("{:?}", self.ed_type))
|
||||
.show_ui(ui, |ui| {
|
||||
ui.selectable_value(&mut self.ed_type, SongType::Youtube, "Youtube");
|
||||
ui.selectable_value(&mut self.ed_type, SongType::Spotify, "Spotify");
|
||||
ui.selectable_value(&mut self.ed_type, SongType::Soundcloud, "Soundcloud");
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
@@ -61,21 +72,23 @@ impl Window for GuiSongEditor {
|
||||
});
|
||||
|
||||
if save {
|
||||
{
|
||||
let Some(song) = state.manifest.get_song_mut(&playlist, &song_name) else {
|
||||
let song = {
|
||||
let Some(song) = state.manifest.get_song_mut(&playlist_name, &song_name) else {
|
||||
bail!("Failed to get song (2)");
|
||||
};
|
||||
|
||||
song.get_url_str_mut().clone_from(&self.ed_url);
|
||||
}
|
||||
song.get_type_mut().clone_from(&self.ed_type);
|
||||
song.clone()
|
||||
};
|
||||
|
||||
|
||||
let Some(playlist) = state.manifest.get_playlist_mut(&playlist) else {
|
||||
let Some(playlist) = state.manifest.get_playlist_mut(&playlist_name) else {
|
||||
bail!("Failed to get playlist");
|
||||
};
|
||||
|
||||
|
||||
playlist.remove_song(&song_name);
|
||||
playlist.add_song(self.ed_name.clone(), song);
|
||||
playlist.add_song(self.ed_name.clone(), song.clone());
|
||||
*open = false;
|
||||
let _ = state.manifest.save(None);
|
||||
}
|
||||
@@ -85,10 +98,11 @@ impl Window for GuiSongEditor {
|
||||
}
|
||||
|
||||
impl GuiSongEditor {
|
||||
pub fn set_active_song(&mut self, pname: &str, sname: &str, url: &str) {
|
||||
pub fn set_active_song(&mut self, pname: &str, sname: &str, url: &str, typ: &SongType) {
|
||||
self.song.0 = pname.to_string();
|
||||
self.song.1 = sname.to_string();
|
||||
self.ed_name = sname.to_string();
|
||||
self.ed_url = url.to_string();
|
||||
self.ed_type = typ.clone();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user