diff --git a/src/keys.rs b/src/keys.rs index f2b2dc4..1acca39 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -44,7 +44,7 @@ impl Handle for Taggart { press!(Left) => { self.column = self.column.saturating_sub(1); }, press!(Right) => { self.column = self.column + 1; }, press!(Enter) => { self.edit_begin() }, - press!(Char(' ')) => { open(&self.entries[self.cursor].path)?; } + press!(Char(' ')) => { open(self.entries[self.cursor].path.as_ref())?; } press!(Char(']')) => { self.columns.0[self.column].width += 1; } press!(Char('[')) => { self.columns.0[self.column].width = self.columns.0[self.column].width.saturating_sub(1).max(5); } diff --git a/src/model.rs b/src/model.rs index 2b8ca0a..643ec76 100644 --- a/src/model.rs +++ b/src/model.rs @@ -48,26 +48,3 @@ impl Taggart { }) } } - -pub(crate) fn entries_under ( - entries: &mut [Entry], index: usize -) -> Option>>> { - let path = if let Some(Entry { path, info, .. }) = entries.get(index) - && let Metadata::Directory { .. } = &*info.read().unwrap() - { - Some(path.clone()) - } else { - None - }; - if let Some(path) = path { - let mut others = vec![]; - for other in entries.iter_mut() { - if other.path.starts_with(&path) && !other.is_directory() { - others.push(other.info.clone()); - } - } - Some(others) - } else { - None - } -} diff --git a/src/model/column.rs b/src/model/column.rs index 1f801d6..6561e53 100644 --- a/src/model/column.rs +++ b/src/model/column.rs @@ -38,14 +38,14 @@ macro_rules! setter { value: &str ) { if let Some(entries) = entries_under(&mut state.entries, index) { - for entry in entries.iter() { - if let Some(task) = entry.write().unwrap().$name(&value) { - state.tasks.push(task); + for (path, entry) in entries.into_iter() { + if let Some(item) = entry.write().unwrap().$name(&value) { + state.tasks.push(Task { path, item, }); }; } } else if let Some(entry) = state.entries.get_mut(index) { - if let Some(task) = entry.$name(&value) { - state.tasks.push(task); + if let Some(item) = entry.$name(&value) { + state.tasks.push(Task { path: entry.path.clone(), item, }); }; } } @@ -53,8 +53,37 @@ macro_rules! setter { }} } +pub(crate) fn entries_under ( + entries: &mut [Entry], + index: usize +) -> Option, Arc>)>> { + let path = if let Some(Entry { path, info, .. }) = entries.get(index) + && let Metadata::Directory { .. } = &*info.read().unwrap() + { + Some(path.clone()) + } else { + None + }; + if let Some(path) = path { + let mut others = vec![]; + for other in entries.iter_mut() { + if other.path.starts_with(path.as_ref()) && !other.is_directory() { + others.push((other.path.clone(), other.info.clone())); + } + } + Some(others) + } else { + None + } +} + pub struct Columns(pub Vec>); +impl Columns { + const SCROLL_LEFT: &'static str = "❮"; + const SCROLL_RIGHT: &'static str = "❯"; +} + impl Default for ColumnsOption>, fn(&mut Taggart, usize, &str)> { fn default () -> Self { Self(vec![ diff --git a/src/model/entry.rs b/src/model/entry.rs index c616596..8f63e70 100644 --- a/src/model/entry.rs +++ b/src/model/entry.rs @@ -1,11 +1,15 @@ use crate::*; use std::cmp::{Eq, PartialEq, Ord, PartialOrd, Ordering}; +use lofty::tag::TagItem; #[derive(Debug)] pub struct Entry { - pub path: PathBuf, + /// How many levels deep is this from the working directory pub depth: usize, - pub info: Arc>, + /// Full path to this entry + pub path: Arc, + /// Type-specific metadata + pub info: Arc>, } impl Entry { @@ -22,7 +26,7 @@ impl Entry { fn new_dir (_: &impl AsRef, path: &Path, depth: usize) -> Perhaps { Ok(Some(Self { depth, - path: path.into(), + path: path.to_path_buf().into(), info: Arc::new(RwLock::new(Metadata::Directory { hash_file: None, catalog_file: None, @@ -34,8 +38,8 @@ impl Entry { fn new_file (_: &impl AsRef, path: &Path, depth: usize) -> Perhaps { Ok(Some(Self { depth, + path: path.to_path_buf().into(), info: Arc::new(RwLock::new(Metadata::new(path)?)), - path: path.into(), })) } pub fn is_directory (&self) -> bool { @@ -68,19 +72,19 @@ impl Entry { pub fn track (&self) -> Option> { self.info.read().unwrap().track() } - pub fn set_artist (&self, value: &impl AsRef) -> Option { + pub fn set_artist (&self, value: &impl AsRef) -> Option { self.info.write().unwrap().set_artist(value) } - pub fn set_year (&self, value: &impl AsRef) -> Option { + pub fn set_year (&self, value: &impl AsRef) -> Option { self.info.write().unwrap().set_year(value) } - pub fn set_album (&self, value: &impl AsRef) -> Option { + pub fn set_album (&self, value: &impl AsRef) -> Option { self.info.write().unwrap().set_album(value) } - pub fn set_title (&self, value: &impl AsRef) -> Option { + pub fn set_title (&self, value: &impl AsRef) -> Option { self.info.write().unwrap().set_title(value) } - pub fn set_track (&self, value: &impl AsRef) -> Option { + pub fn set_track (&self, value: &impl AsRef) -> Option { self.info.write().unwrap().set_track(value) } } diff --git a/src/model/metadata.rs b/src/model/metadata.rs index 764d3fa..51dd403 100644 --- a/src/model/metadata.rs +++ b/src/model/metadata.rs @@ -1,8 +1,8 @@ use crate::*; use std::fs::File; use std::io::{BufReader, Read}; -use lofty::{file::TaggedFileExt, probe::Probe, tag::Accessor}; use byte_unit::{Byte, Unit::MB}; +use lofty::{file::TaggedFileExt, probe::Probe, tag::{Accessor, TagItem, ItemKey, ItemValue}}; #[derive(Ord, Eq, PartialEq, PartialOrd, Debug)] pub enum Metadata { @@ -159,56 +159,70 @@ impl Metadata { _ => None } } - pub fn set_artist (&mut self, value: &impl AsRef) -> Option { + pub fn set_artist (&mut self, value: &impl AsRef) -> Option { match self { Metadata::Music { artist, .. } => { - *artist = Some(value.as_ref().into()); + if artist.as_deref() != Some(value.as_ref()) { + *artist = Some(value.as_ref().into()); + Some(TagItem::new( + ItemKey::TrackArtist, + ItemValue::Text(value.as_ref().into()) + )); + } //todo!("emit task"); None }, _ => None } } - pub fn set_year (&mut self, value: &impl AsRef ) -> Option { + pub fn set_year (&mut self, value: &impl AsRef ) -> Option { match self { Metadata::Music { year, .. } => { if let Ok(value) = value.as_ref().trim().parse::() { *year = Some(value); } - //todo!("emit task"); - None + Some(TagItem::new( + ItemKey::Year, + ItemValue::Text(value.as_ref().into()) + )) }, _ => None } } - pub fn set_album (&mut self, value: &impl AsRef) -> Option { + pub fn set_album (&mut self, value: &impl AsRef) -> Option { match self { Metadata::Music { album, .. } => { *album = Some(value.as_ref().into()); - //todo!("emit task"); - None + Some(TagItem::new( + ItemKey::AlbumTitle, + ItemValue::Text(value.as_ref().into()) + )) }, _ => None } } - pub fn set_title (&mut self, value: &impl AsRef) -> Option { + pub fn set_title (&mut self, value: &impl AsRef) -> Option { match self { Metadata::Music { title, .. } => { *title = Some(value.as_ref().into()); - //todo!("emit task"); - None + Some(TagItem::new( + ItemKey::TrackTitle, + ItemValue::Text(value.as_ref().into()) + )) }, _ => None } } - pub fn set_track (&mut self, value: &impl AsRef) -> Option { + pub fn set_track (&mut self, value: &impl AsRef) -> Option { match self { Metadata::Music { track, .. } => { if let Ok(value) = value.as_ref().trim().parse::() { *track = Some(value); } - //todo!("emit task"); - None + Some(TagItem::new( + ItemKey::TrackNumber, + ItemValue::Text(value.as_ref().into()) + )) }, _ => None } diff --git a/src/model/task.rs b/src/model/task.rs index 1343c6d..5aa27df 100644 --- a/src/model/task.rs +++ b/src/model/task.rs @@ -3,14 +3,14 @@ use lofty::tag::TagItem; /// An update to a file's metadata to be performed. pub struct Task { - pub path: PathBuf, + pub path: Arc, pub item: TagItem } impl Task { fn new (path: &impl AsRef, item: TagItem) -> Self { Self { - path: path.as_ref().into(), + path: path.as_ref().to_path_buf().into(), item } }