diff --git a/src/argparse.rs b/src/argparse.rs index 296ea6a..9adb05f 100644 --- a/src/argparse.rs +++ b/src/argparse.rs @@ -8,8 +8,10 @@ use url::Url; #[derive(Debug, Default)] pub struct Arguments { - /// URLs to play with associated metadata - pub urls: Vec, + /// Files or directory URLs to play + pub urls: Option>, + /// Single URL only + pub url_opt: Option, } impl Arguments { @@ -31,7 +33,17 @@ impl Arguments { warn!("Unused argument: {arg:?}"); } - Ok(Arguments { urls }) + if urls.len() > 1 { + Ok(Arguments { + urls: Some(urls), + ..Default::default() + }) + } else { + Ok(Arguments { + url_opt: urls.into_iter().next(), + ..Default::default() + }) + } } } diff --git a/src/main.rs b/src/main.rs index 44ba40c..5e52ea5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -111,8 +111,7 @@ pub fn main() -> Result<(), Box> { settings = settings.theme(config.app_theme.theme()); settings = settings.size_limits(Limits::NONE.min_width(360.0).min_height(180.0)); - let args = argparse::Arguments::from_args().unwrap_or_default(); - let url_opt = args.urls.into_iter().next(); + let argparse::Arguments { urls, url_opt } = argparse::Arguments::from_args().unwrap_or_default(); let flags = Flags { config_handler, @@ -120,6 +119,7 @@ pub fn main() -> Result<(), Box> { config_state_handler, config_state, url_opt, + urls }; cosmic::app::run::(settings, flags)?; @@ -168,6 +168,7 @@ pub struct Flags { config_state_handler: Option, config_state: ConfigState, url_opt: Option, + urls: Option>, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -219,6 +220,7 @@ pub enum Message { FolderLoad(PathBuf), FolderOpen, FolderOpenRecent(usize), + MultipleLoad(Vec), Fullscreen, Key(Modifiers, Key), AudioCode(usize), @@ -543,6 +545,30 @@ impl App { self.open_folder(path, position + 1, 1); } + fn add_file_to_project(&mut self, path: impl AsRef) { + let path = path.as_ref(); + let node = match ProjectNode::new(path) { + Ok(node) if matches!(node, ProjectNode::File { .. }) => node, + Err(e) => { + log::error!("failed to open project {} {}", path.display(), e); + return; + } + _ => { + log::error!( + "failed to open project: expected {} to be a file path", + path.display() + ); + return; + } + }; + + let mut entity = self.nav_model.insert().text(node.name().to_owned()); + if let Some(icon) = node.icon(16) { + entity = entity.icon(icon); + } + entity.data(node); + } + fn save_config_state(&mut self) { if let Some(ref config_state_handler) = self.flags.config_state_handler { if let Err(err) = self.flags.config_state.write_entry(config_state_handler) { @@ -793,13 +819,15 @@ impl Application for App { .icon(widget::icon::from_name("folder-open-symbolic").size(16)) .text(fl!("open-folder")); + // TODO: This is kind of ugly and may be handled better in Arguments let maybe_path = app .flags .url_opt .as_ref() .and_then(|url| url.to_file_path().ok()); - let command = match maybe_path { - Some(path) if path.is_dir() => command::message::app(Message::FolderLoad(path)), + let command = match (app.flags.urls.take(), maybe_path) { + (Some(urls), _) => command::message::app(Message::MultipleLoad(urls)), + (None, Some(path)) if path.is_dir() => command::message::app(Message::FolderLoad(path)), _ => app.load(), }; (app, command) @@ -1010,6 +1038,30 @@ impl Application for App { return self.update(Message::FolderLoad(path.clone())); } } + Message::MultipleLoad(urls) => { + log::trace!("Loading multiple URLs: {urls:?}"); + let paths: Vec<_> = urls + .into_iter() + .flat_map(|url| url.to_file_path()) + .collect(); + + for path in paths { + if path.is_file() { + log::trace!("Appending file to playlist: {}", path.display()); + self.add_file_to_project(path); + } else if path.is_dir() { + log::trace!("Appending directory to playlist: {}", path.display()); + self.open_project(path); + } else { + log::warn!( + "Tried to add unsupported path to playlist: {}", + path.display() + ); + } + } + + self.core.nav_bar_set_toggled(true); + } Message::Fullscreen => { //TODO: cleanest way to close dropdowns self.dropdown_opt = None;