//! The library organizer (name + kind of each top-level pool folder) and the //! choice of libraries feeding miniDLNA generation. use std::collections::HashSet; use std::fs; use super::{DialogState, Env, Event, modal, ok_cancel_row}; use crate::core::file_manager::{FileManager, Library, LibraryKind}; use crate::ui::common::{GREY, RED}; pub struct LibraryOrganizerDialog { rows: Vec<(String, LibraryKind)>, selected: Option, } impl LibraryOrganizerDialog { pub fn new(fm: &FileManager) -> Self { Self { rows: fm .libraries() .into_iter() .map(|l| (l.name, l.kind)) .collect(), selected: None, } } pub fn show(&mut self, ctx: &egui::Context, env: &mut Env) -> DialogState { let mut ok = None; let (_, close) = modal(ctx, "libraries", "Knihovny poolu", 560.0, |ui| { ui.label("Knihovny = složky v kořeni poolu, každá je jedna knihovna v Jellyfinu.\nTyp určuje, jak Curator složku zpracuje."); ui.add_space(6.0); egui::Grid::new("lib_rows") .striped(true) .num_columns(3) .show(ui, |ui| { ui.strong(""); ui.strong("Název složky"); ui.strong("Typ"); ui.end_row(); for (i, (name, kind)) in self.rows.iter_mut().enumerate() { ui.radio_value(&mut self.selected, Some(i), ""); crate::ui::common::sized(ui, 240.0, egui::TextEdit::singleline(name)); egui::ComboBox::from_id_salt(("kind", i)) .selected_text(kind.label()) .show_ui(ui, |ui| { for k in LibraryKind::ALL { ui.selectable_value(kind, k, k.label()); } }); ui.end_row(); } }); ui.horizontal(|ui| { if ui.button("➕ Přidat knihovnu").clicked() { self.rows.push((String::new(), LibraryKind::Movie)); } if ui.button("➖ Odebrat").clicked() && let Some(i) = self.selected.take().filter(|i| *i < self.rows.len()) { self.rows.remove(i); } }); ui.add(egui::Label::new(egui::RichText::new( "Pozn.: „Mix“ zpracuje filmy (v kořeni) i seriály (v podsložkách); „Domácí videa“ se do miniDLNA zrcadlí celé. Po uložení nabídnu smazání prázdných složek, které už nejsou knihovnou (s obsahem nechám být).", ).color(GREY)).wrap()); ok = ok_cancel_row(ui); }); match ok { Some(true) => { let specs: Vec = self .rows .iter() .filter(|(n, _)| !n.trim().is_empty()) .map(|(n, k)| Library::new(n.trim(), *k)) .collect(); if let Err(e) = env.fm.set_libraries(specs) { env.warn("Knihovny", e.to_string()); return DialogState::Open; } if let Some(pool) = env.fm.pool_dir() { for lib in env.fm.libraries() { let _ = fs::create_dir_all(pool.join(&lib.name)); } } let names: Vec = env .fm .libraries() .iter() .map(|l| format!("{} ({})", l.name, l.kind.as_str())) .collect(); env.events .push(Event::Status(format!("Knihovny: {}", names.join(", ")))); env.events.push(Event::LibrariesChanged); DialogState::Closed } Some(false) => DialogState::Closed, None if close => DialogState::Closed, None => DialogState::Open, } } } pub struct MinidlnaLibrariesDialog { rows: Vec<(String, LibraryKind, bool)>, } impl MinidlnaLibrariesDialog { pub fn new(fm: &FileManager) -> Self { let chosen: Option> = fm.minidlna_libraries().map(|v| v.into_iter().collect()); Self { rows: fm .libraries() .into_iter() .map(|l| { let on = chosen.as_ref().is_none_or(|c| c.contains(&l.name)); (l.name, l.kind, on) }) .collect(), } } pub fn show(&mut self, ctx: &egui::Context, env: &mut Env) -> DialogState { let mut ok = None; let (_, close) = modal( ctx, "minidlna_libs", "Knihovny pro generování miniDLNA", 440.0, |ui| { ui.add(egui::Label::new("Které knihovny se mají promítnout do miniDLNA stromu (žánry, Tipy dne, Nově přidané, zrcadlené seriály)?").wrap()); ui.add(egui::Label::new(egui::RichText::new("⚠ Odškrtnutá knihovna: její odkazy ve stromu se při dalším generování odeberou jako zastaralé, dokud ji znovu nezaškrtneš.").color(RED)).wrap()); ui.add_space(6.0); for (name, kind, on) in &mut self.rows { ui.checkbox(on, format!("{name} ({})", kind.as_str())); } ui.horizontal(|ui| { if ui.button("Vše").clicked() { self.rows.iter_mut().for_each(|r| r.2 = true); } if ui.button("Nic").clicked() { self.rows.iter_mut().for_each(|r| r.2 = false); } }); ok = ok_cancel_row(ui); }, ); match ok { Some(true) => { let chosen: Vec = self .rows .iter() .filter(|r| r.2) .map(|r| r.0.clone()) .collect(); let all = chosen.len() == self.rows.len(); if let Err(e) = env.fm .set_minidlna_libraries(if all { None } else { Some(chosen.clone()) }) { env.warn("miniDLNA", e.to_string()); } env.events.push(Event::Status(format!( "miniDLNA: {}/{} knihoven vybráno pro generování.", chosen.len(), self.rows.len() ))); DialogState::Closed } Some(false) => DialogState::Closed, None if close => DialogState::Closed, None => DialogState::Open, } } }