#![allow(unknown_lints)] #![warn(clippy)] extern crate clap; extern crate cursive; extern crate failure; #[macro_use] extern crate lazy_static; extern crate walkdir; use clap::{App, Arg}; use cursive::traits::*; use cursive::views::{Checkbox, Dialog, ListView, ProgressBar, TextView}; use cursive::Cursive; use failure::Error; use std::ffi::OsStr; use std::path::PathBuf; use std::sync::{Arc, Mutex}; use registry::Registry; lazy_static! { static ref REGISTRY: Arc> = Arc::new(Mutex::new(Registry::default())); } mod registry; fn main() -> Result<(), Error> { let matches = App::new("Music Sync") .version("0.1.0") .author("Paul van Tilburg ") .about("Syncs selected music (albums) to a remote location using rsync") .arg(Arg::with_name("device").index(1).required(true)) .arg(Arg::with_name("directory").index(2).required(true)) .get_matches(); let device = matches.value_of("device").unwrap(); let base_path = matches.value_of("directory").unwrap(); { let mut registry = REGISTRY.lock().unwrap(); registry.device = String::from(device); registry.base_path = PathBuf::from(base_path); } let mut ui = Cursive::default(); load_albums(&mut ui); ui.set_fps(10); ui.run(); Ok(()) } fn load_albums(ui: &mut Cursive) { let mut registry = REGISTRY.lock().unwrap(); if let Err(error) = registry.load_albums_file() { eprintln!("Something went wrong: {}", error); quit(ui); } let cb = ui.cb_sink().clone(); ui.add_layer( Dialog::around( ProgressBar::new() .range(0, registry.albums_list.len()) .with_task(move |counter| { let mut registry = REGISTRY.lock().unwrap(); if let Err(error) = registry.load_albums_fs(&counter) { eprintln!("Something went wrong: {}", error); cb.send(Box::new(quit)); } else { cb.send(Box::new(select_albums)); } }), ).title("Loading list of albums…"), ); } fn album_name(album_path: &PathBuf) -> &str { album_path .file_name() .unwrap_or_else(|| OsStr::new("")) .to_str() .unwrap_or("") } fn select_albums(ui: &mut Cursive) { let registry = REGISTRY.lock().unwrap(); let added_albums = registry.added_albums(); let existing_albums = registry.existing_albums(); let removed_albums = registry.removed_albums(); let list_view = ListView::new() .with(|list_view| { list_view.add_child("--- New", Checkbox::new().disabled()); for album_path in added_albums { let album_name = album_name(&album_path); let album_path = album_path.clone(); let mut checkbox = Checkbox::new().on_change(move |_, checked| { let mut registry = REGISTRY.lock().unwrap(); registry.select_album(&album_path, checked); }); list_view.add_child(album_name, checkbox); } list_view.add_child("--- Existing ", Checkbox::new().disabled()); for album_path in existing_albums { let album_name = album_name(&album_path); let album_path = album_path.clone(); let selected = registry.selected_albums.contains(&album_path); let mut checkbox = Checkbox::new().on_change(move |_, checked| { let mut registry = REGISTRY.lock().unwrap(); registry.select_album(&album_path, checked); }); if selected { checkbox.check(); } list_view.add_child(album_name, checkbox) } list_view.add_child("--- Gone ", Checkbox::new().disabled()); for album_path in removed_albums { let mut checkbox = Checkbox::new().disabled(); if registry.selected_albums.contains(album_path) { checkbox.check(); } list_view.add_child(album_name(album_path), checkbox); } }) .scrollable(); ui.pop_layer(); ui.add_layer( Dialog::new() .title("Select or unselect albums") .button("Quit", |ui| quit(ui)) .button("Apply", |ui| save_albums(ui)) .content(list_view), ); } fn save_albums(ui: &mut Cursive) { let registry = REGISTRY.lock().unwrap(); if let Err(error) = registry.save_albums_file() { eprintln!("Something went wrong: {}", error); quit(ui); } ui.pop_layer(); ui.add_layer( Dialog::around(TextView::new("All albums have been saved!")).button("Ok", |ui| ui.quit()), ); } fn quit(ui: &mut Cursive) { ui.quit(); }