diff --git a/CHANGELOG.md b/CHANGELOG.md index 25940d1b..58091747 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - Fix(tui): not having the current theme selected when entering Theme preview tab. - Fix(tui): actually report any errors when adding to the playlist. (Like "invalid file type") - Fix(tui): sort Music-Library content Alphanumerically. +- Fix(tui): consistent numbering of results in a search popup. - Fix(tui): let `ueberzug` command inherit `stdout` to display chafa. ### [V0.9.1] diff --git a/lib/src/library_db/mod.rs b/lib/src/library_db/mod.rs index b468dbe4..e061f265 100644 --- a/lib/src/library_db/mod.rs +++ b/lib/src/library_db/mod.rs @@ -325,13 +325,13 @@ impl DataBase { let conn = self.conn.lock(); let mut stmt = conn.prepare(search_str)?; - let vec_records: Vec = stmt + let maybe_record: Option = stmt .query_map([file_path], TrackDB::try_from_row_named)? .flatten() - .collect(); + .next(); - if let Some(record) = vec_records.first() { - return Ok(record.clone()); + if let Some(record) = maybe_record { + return Ok(record); } Err(Error::QueryReturnedNoRows) diff --git a/lib/src/playlist/mod.rs b/lib/src/playlist/mod.rs index ea13ddc4..228061ba 100644 --- a/lib/src/playlist/mod.rs +++ b/lib/src/playlist/mod.rs @@ -59,7 +59,7 @@ impl PlaylistValue { let as_path = url .to_file_path() .map_err(|()| anyhow!("Failed to convert URL to Path!")) - .context(url.to_string())?; + .with_context(|| url.to_string())?; *self = Self::Path(as_path); } diff --git a/lib/src/podcast/mod.rs b/lib/src/podcast/mod.rs index 4fac6634..b5a7631c 100644 --- a/lib/src/podcast/mod.rs +++ b/lib/src/podcast/mod.rs @@ -71,12 +71,8 @@ pub struct PodcastFeed { impl PodcastFeed { #[must_use] - pub fn new(id: Option, url: &str, title: Option) -> Self { - Self { - id, - url: url.to_string(), - title, - } + pub const fn new(id: Option, url: String, title: Option) -> Self { + Self { id, url, title } } } @@ -97,7 +93,7 @@ pub fn check_feed(feed: PodcastFeed, max_retries: usize, tp: &TaskPool, tx_to_ma }, Err(err) => { error!("get_feed_data had a Error: {:#?}", err); - let _ = tx_to_main.send(Msg::Podcast(PCMsg::Error(feed.url.to_string(), feed))); + let _ = tx_to_main.send(Msg::Podcast(PCMsg::Error(feed))); } } }); @@ -315,27 +311,23 @@ pub fn import_from_opml(db_path: &Path, config: &PodcastSettings, file: &Path) - match message { Msg::Podcast(PCMsg::NewData(pod)) => { msg_counter += 1; - let title = pod.title.clone(); + let title = &pod.title; let db_result = db_inst.insert_podcast(&pod); match db_result { Ok(_) => { println!("Added {title}"); } - Err(_err) => { + Err(err) => { failure = true; - error!("Error adding {title}"); + error!("Error adding {title}, err: {err}"); } } } - Msg::Podcast(PCMsg::Error(_, feed)) => { + Msg::Podcast(PCMsg::Error(feed)) => { msg_counter += 1; failure = true; - if let Some(t) = feed.title { - error!("Error retrieving RSS feed: {t}"); - } else { - error!("Error retrieving RSS feed"); - } + error!("Error retrieving RSS feed: {}", feed.url); } Msg::Podcast(PCMsg::SyncData((_id, _pod))) => { @@ -394,7 +386,7 @@ fn import_opml_feeds(xml: &str) -> Result> { Some(pod.text) } }); - feeds.push(PodcastFeed::new(None, &pod.xml_url.unwrap(), title)); + feeds.push(PodcastFeed::new(None, pod.xml_url.unwrap(), title)); } } Ok(feeds) diff --git a/lib/src/types.rs b/lib/src/types.rs index 45d2b30b..a29b15f7 100644 --- a/lib/src/types.rs +++ b/lib/src/types.rs @@ -398,7 +398,7 @@ pub enum PCMsg { PodcastAddPopupCloseCancel, SyncData((i64, PodcastNoId)), NewData(PodcastNoId), - Error(String, PodcastFeed), + Error(PodcastFeed), PodcastSelected(usize), DescriptionUpdate, EpisodeAdd(usize), diff --git a/tui/src/ui/components/config_editor/key_combo.rs b/tui/src/ui/components/config_editor/key_combo.rs index 80598246..dae2d427 100644 --- a/tui/src/ui/components/config_editor/key_combo.rs +++ b/tui/src/ui/components/config_editor/key_combo.rs @@ -301,9 +301,9 @@ impl InputStates { /// ### `render_value_chars` /// - /// Render value as a vec of chars - pub fn render_value_chars(&self) -> Vec { - self.input.clone() + /// Get the current input as a slice + pub fn render_value_chars(&self) -> &[char] { + &self.input } /// ### `get_value` @@ -469,7 +469,7 @@ impl KeyCombo { .states .choices .iter() - .map(|x| ListItem::new(Span::from(x.clone()))) + .map(|x| ListItem::new(Span::from(x))) .collect(); let mut foreground = self .props @@ -490,9 +490,9 @@ impl KeyCombo { .constraints([Constraint::Length(2), Constraint::Min(1)].as_ref()) .split(area); // Render like "closed" tab in chunk 0 - let selected_text: String = match self.states.choices.get(self.states.selected) { - None => String::default(), - Some(s) => s.clone(), + let selected_text = match self.states.choices.get(self.states.selected) { + None => "", + Some(s) => s.as_str(), }; let borders = self .props @@ -656,9 +656,9 @@ impl KeyCombo { style = style_invalid; } } - let selected_text: String = match self.states.choices.get(self.states.selected) { - None => String::default(), - Some(s) => s.clone(), + let selected_text = match self.states.choices.get(self.states.selected) { + None => "", + Some(s) => s.as_str(), }; let p: Paragraph<'_> = Paragraph::new(selected_text).style(style).block(block); @@ -845,9 +845,9 @@ impl MockComponent for KeyCombo { } Cmd::Cancel => { self.states.cancel_tab(); - let prev_input = self.states_input.input.clone(); + let prev_len = self.states_input.input.len(); self.states_input.delete(); - if prev_input == self.states_input.input { + if prev_len == self.states_input.input.len() { CmdResult::None } else { CmdResult::Changed(self.state()) @@ -866,9 +866,9 @@ impl MockComponent for KeyCombo { Cmd::Delete => { // Backspace and None - let prev_input = self.states_input.input.clone(); + let prev_len = self.states_input.input.len(); self.states_input.backspace(); - if prev_input == self.states_input.input { + if prev_len == self.states_input.input.len() { CmdResult::None } else { CmdResult::Changed(self.state()) @@ -892,10 +892,10 @@ impl MockComponent for KeyCombo { } Cmd::Type(ch) => { // Push char to input - let prev_input = self.states_input.input.clone(); + let prev_len = self.states_input.input.len(); self.states_input.append(ch, self.get_input_len()); // Message on change - if prev_input == self.states_input.input { + if prev_len == self.states_input.input.len() { CmdResult::None } else { CmdResult::Changed(self.state()) diff --git a/tui/src/ui/components/config_editor/update.rs b/tui/src/ui/components/config_editor/update.rs index c38f6ec1..ef193973 100644 --- a/tui/src/ui/components/config_editor/update.rs +++ b/tui/src/ui/components/config_editor/update.rs @@ -350,16 +350,13 @@ impl Model { match id { IdConfigEditor::LibraryHighlightSymbol => { - self.config_editor.theme.style.library.highlight_symbol = - symbol.to_string(); + self.config_editor.theme.style.library.highlight_symbol = symbol; } IdConfigEditor::PlaylistHighlightSymbol => { - self.config_editor.theme.style.playlist.highlight_symbol = - symbol.to_string(); + self.config_editor.theme.style.playlist.highlight_symbol = symbol; } IdConfigEditor::CurrentlyPlayingTrackSymbol => { - self.config_editor.theme.style.playlist.current_track_symbol = - symbol.to_string(); + self.config_editor.theme.style.playlist.current_track_symbol = symbol; } _ => {} }; diff --git a/tui/src/ui/components/lyric.rs b/tui/src/ui/components/lyric.rs index c526b813..350e2192 100644 --- a/tui/src/ui/components/lyric.rs +++ b/tui/src/ui/components/lyric.rs @@ -130,8 +130,7 @@ impl Model { ) .is_ok()); self.lyric_update_title(); - let lyric_line = self.lyric_line.clone(); - self.lyric_set_lyric(&lyric_line); + self.lyric_set_lyric(self.lyric_line.clone()); } pub fn lyric_update_for_podcast_by_current_track(&mut self) { diff --git a/tui/src/ui/components/music_library.rs b/tui/src/ui/components/music_library.rs index 7ca0ff6a..8f2c58f0 100644 --- a/tui/src/ui/components/music_library.rs +++ b/tui/src/ui/components/music_library.rs @@ -342,7 +342,7 @@ impl Model { .mount( Id::Library, Box::new(MusicLibrary::new( - &self.library.tree.clone(), + &self.library.tree, current_node, self.config_tui.clone(), ),), @@ -358,7 +358,7 @@ impl Model { .remount( Id::Library, Box::new(MusicLibrary::new( - &self.library.tree.clone(), + &self.library.tree, current_node, self.config_tui.clone(), ),), @@ -473,7 +473,7 @@ impl Model { let root = self.library.tree.root(); let p: &Path = Path::new(root.id()); let all_items = walkdir::WalkDir::new(p).follow_links(true); - let mut idx = 0; + let mut idx: usize = 0; let search = format!("*{}*", input.to_lowercase()); let search = wildmatch::WildMatch::new(&search); for record in all_items.into_iter().filter_map(std::result::Result::ok) { diff --git a/tui/src/ui/components/podcast.rs b/tui/src/ui/components/podcast.rs index 8d6fe7c2..f3d32793 100644 --- a/tui/src/ui/components/podcast.rs +++ b/tui/src/ui/components/podcast.rs @@ -427,7 +427,7 @@ impl Model { }); } - pub fn podcast_add(&mut self, url: &str) { + pub fn podcast_add(&mut self, url: String) { let feed = PodcastFeed::new(None, url, None); crate::podcast::check_feed( @@ -627,7 +627,7 @@ impl Model { .ok_or_else(|| anyhow!("get podcast selected failed."))?; let pcf = PodcastFeed::new( Some(pod_selected.id), - &pod_selected.url.clone(), + pod_selected.url.clone(), Some(pod_selected.title.clone()), ); pod_data.push(pcf); @@ -640,7 +640,7 @@ impl Model { .podcasts .iter() .map(|pod| { - PodcastFeed::new(Some(pod.id), &pod.url.clone(), Some(pod.title.clone())) + PodcastFeed::new(Some(pod.id), pod.url.clone(), Some(pod.title.clone())) }) .collect(); } @@ -843,7 +843,7 @@ impl Model { for ep in &mut podcast_selected.episodes { if ep.path.is_some() { - match std::fs::remove_file(ep.path.clone().unwrap()) { + match std::fs::remove_file(ep.path.as_ref().unwrap()) { Ok(()) => { eps_to_remove.push(ep.id); ep.path = None; @@ -977,12 +977,11 @@ impl Model { pub fn podcast_update_search_episode(&mut self, input: &str) { let mut table: TableBuilder = TableBuilder::default(); - let mut idx = 0; + let mut idx: usize = 0; let search = format!("*{}*", input.to_lowercase()); let mut db_tracks = vec![]; // Get all episodes - let podcasts = self.podcast.podcasts.clone(); - for podcast in podcasts { + for podcast in &self.podcast.podcasts { if let Ok(episodes) = self.podcast.db_podcast.get_episodes(podcast.id, true) { db_tracks.extend(episodes); } @@ -998,11 +997,11 @@ impl Model { if idx > 0 { table.add_row(); } + idx += 1; table .add_col(TextSpan::new(idx.to_string())) .add_col(TextSpan::new(record.title).bold()) .add_col(TextSpan::new(format!("{}", record.id))); - idx += 1; } } } @@ -1013,10 +1012,10 @@ impl Model { pub fn podcast_update_search_podcast(&mut self, input: &str) { let mut table: TableBuilder = TableBuilder::default(); - let mut idx = 0; + let mut idx: usize = 0; let search = format!("*{}*", input.to_lowercase()); // Get all episodes - let db_tracks = self.podcast.podcasts.clone(); + let db_tracks = &self.podcast.podcasts; if db_tracks.is_empty() { table.add_col(TextSpan::from("0")); @@ -1028,11 +1027,11 @@ impl Model { if idx > 0 { table.add_row(); } + idx += 1; table .add_col(TextSpan::new(idx.to_string())) - .add_col(TextSpan::new(record.title).bold()) + .add_col(TextSpan::new(&record.title).bold()) .add_col(TextSpan::new(format!("{}", record.id))); - idx += 1; } } } diff --git a/tui/src/ui/components/popups/message.rs b/tui/src/ui/components/popups/message.rs index 08b8e54a..bb941519 100644 --- a/tui/src/ui/components/popups/message.rs +++ b/tui/src/ui/components/popups/message.rs @@ -56,8 +56,8 @@ impl Model { if let Ok(Some(AttrValue::Payload(PropPayload::Vec(spans)))) = self.app.query(&Id::MessagePopup, Attribute::Text) { - if let Some(display_text) = spans.first() { - let d = display_text.clone().unwrap_text_span().content; + if let Some(display_text) = spans.into_iter().next() { + let d = display_text.unwrap_text_span().content; if text.eq(&d) { self.app.umount(&Id::MessagePopup).ok(); } diff --git a/tui/src/ui/components/popups/podcast.rs b/tui/src/ui/components/popups/podcast.rs index 957820ad..e0de9c3c 100644 --- a/tui/src/ui/components/popups/podcast.rs +++ b/tui/src/ui/components/popups/podcast.rs @@ -277,13 +277,15 @@ impl Model { pub fn update_podcast_search_table(&mut self) { let mut table: TableBuilder = TableBuilder::default(); - let mut idx = 0; + let mut idx: usize = 0; if let Some(vec) = &self.podcast.search_results { for record in vec { if idx > 0 { table.add_row(); } + idx += 1; + let title = record .title .clone() @@ -293,7 +295,6 @@ impl Model { .add_col(TextSpan::new(title).bold()) .add_col(TextSpan::new(record.url.clone())); // .add_col(TextSpan::new(record.album().unwrap_or("Unknown Album"))); - idx += 1; } // if self.player.playlist.is_empty() { // table.add_col(TextSpan::from("0")); diff --git a/tui/src/ui/model/download_tracker.rs b/tui/src/ui/model/download_tracker.rs index 8c3e2df3..fb20d005 100644 --- a/tui/src/ui/model/download_tracker.rs +++ b/tui/src/ui/model/download_tracker.rs @@ -18,8 +18,8 @@ impl Default for DownloadTracker { #[allow(dead_code)] impl DownloadTracker { - pub fn increase_one(&mut self, url: &str) { - self.items.insert(url.to_string()); + pub fn increase_one>(&mut self, url: U) { + self.items.insert(url.into()); } pub fn decrease_one(&mut self, url: &str) { diff --git a/tui/src/ui/model/update.rs b/tui/src/ui/model/update.rs index 1bba2d25..d654aedf 100644 --- a/tui/src/ui/model/update.rs +++ b/tui/src/ui/model/update.rs @@ -167,7 +167,7 @@ impl Update for Model { self.umount_save_playlist_confirm(); None } - Msg::Podcast(m) => self.update_podcast(&m), + Msg::Podcast(m) => self.update_podcast(m), Msg::LyricMessage(m) => self.update_lyric_textarea(m), Msg::Download(m) => self.update_download_msg(&m), Msg::Xywh(m) => self.update_xywh_msg(m), @@ -215,7 +215,7 @@ impl Model { } #[allow(clippy::too_many_lines)] - fn update_podcast(&mut self, msg: &PCMsg) -> Option { + fn update_podcast(&mut self, msg: PCMsg) -> Option { match msg { PCMsg::PodcastBlurDown => { self.app.active(&Id::Episode).ok(); @@ -236,7 +236,7 @@ impl Model { if url.starts_with("http") { self.podcast_add(url); } else { - self.podcast_search_itunes(url); + self.podcast_search_itunes(&url); self.mount_podcast_search_table(); } } @@ -249,7 +249,7 @@ impl Model { None, None, ); - if let Err(e) = self.add_or_sync_data(pod, Some(*id)) { + if let Err(e) = self.add_or_sync_data(&pod, Some(id)) { self.mount_error_popup(e.context("add or sync data")); }; } @@ -261,12 +261,12 @@ impl Model { None, None, ); - if let Err(e) = self.add_or_sync_data(pod, None) { + if let Err(e) = self.add_or_sync_data(&pod, None) { self.mount_error_popup(e.context("add or sync data")); } } - PCMsg::Error(url, feed) => { - self.download_tracker.decrease_one(url); + PCMsg::Error(feed) => { + self.download_tracker.decrease_one(&feed.url); self.mount_error_popup(anyhow!("Error happened with feed: {:?}", feed.title)); self.show_message_timeout_label_help( self.download_tracker.message_feed_sync_failed(), @@ -276,19 +276,19 @@ impl Model { ); } PCMsg::PodcastSelected(index) => { - self.podcast.podcasts_index = *index; + self.podcast.podcasts_index = index; if let Err(e) = self.podcast_sync_episodes() { self.mount_error_popup(e.context("podcast sync episodes")); } } PCMsg::DescriptionUpdate => self.lyric_update(), PCMsg::EpisodeAdd(index) => { - if let Err(e) = self.playlist_add_episode(*index) { + if let Err(e) = self.playlist_add_episode(index) { self.mount_error_popup(e.context("podcast playlist add episode")); } } PCMsg::EpisodeMarkPlayed(index) => { - if let Err(e) = self.episode_mark_played(*index) { + if let Err(e) = self.episode_mark_played(index) { self.mount_error_popup(e.context("podcast episode mark played")); } } @@ -298,7 +298,7 @@ impl Model { } } PCMsg::PodcastRefreshOne(index) => { - if let Err(e) = self.podcast_refresh_feeds(Some(*index)) { + if let Err(e) = self.podcast_refresh_feeds(Some(index)) { self.mount_error_popup(e.context("podcast refresh feeds one")); } } @@ -317,7 +317,7 @@ impl Model { ); } PCMsg::EpisodeDownload(index) => { - if let Err(e) = self.episode_download(Some(*index)) { + if let Err(e) = self.episode_download(Some(index)) { self.mount_error_popup(e.context("podcast episode download")); } } @@ -376,7 +376,7 @@ impl Model { ); } PCMsg::EpisodeDeleteFile(index) => { - if let Err(e) = self.episode_delete_file(*index) { + if let Err(e) = self.episode_delete_file(index) { self.mount_error_popup(e.context("podcast episode delete")); } } @@ -399,9 +399,8 @@ impl Model { PCMsg::SearchItunesCloseCancel => self.umount_podcast_search_table(), PCMsg::SearchItunesCloseOk(index) => { if let Some(vec) = &self.podcast.search_results { - if let Some(pod) = vec.get(*index) { - let url = pod.url.clone(); - self.podcast_add(&url); + if let Some(pod) = vec.get(index) { + self.podcast_add(pod.url.clone()); } } } @@ -409,7 +408,7 @@ impl Model { self.podcast.search_results = Some(vec.clone()); self.update_podcast_search_table(); } - PCMsg::SearchError(e) => self.mount_error_popup(anyhow!(e.to_owned())), + PCMsg::SearchError(e) => self.mount_error_popup(anyhow!(e)), } None } @@ -964,7 +963,7 @@ impl Model { self.redraw = true; match msg { DLMsg::DownloadRunning(url, title) => { - self.download_tracker.increase_one(url); + self.download_tracker.increase_one(&**url); self.show_message_timeout_label_help( self.download_tracker.message_download_start(title), None, diff --git a/tui/src/ui/model/youtube_options.rs b/tui/src/ui/model/youtube_options.rs index f7f4e8fe..ef799731 100644 --- a/tui/src/ui/model/youtube_options.rs +++ b/tui/src/ui/model/youtube_options.rs @@ -136,8 +136,7 @@ impl Model { table.add_row(); } let duration = - Track::duration_formatted_short(&Duration::from_secs(record.length_seconds)) - .to_string(); + Track::duration_formatted_short(&Duration::from_secs(record.length_seconds)); let duration_string = format!("[{duration:^10.10}]"); let title = record.title.as_str(); @@ -219,7 +218,7 @@ impl Model { extract_filepath(result.output(), &path.to_string_lossy()) { tx.send(Msg::Download(DLMsg::DownloadCompleted( - url.clone(), + url, Some(file_fullname.clone()), ))) .ok(); @@ -229,7 +228,7 @@ impl Model { embed_downloaded_lrc(&path, &file_fullname); } else { - tx.send(Msg::Download(DLMsg::DownloadCompleted(url.clone(), None))) + tx.send(Msg::Download(DLMsg::DownloadCompleted(url, None))) .ok(); } } @@ -241,7 +240,7 @@ impl Model { ))) .ok(); sleep(Duration::from_secs(5)); - tx.send(Msg::Download(DLMsg::DownloadCompleted(url.clone(), None))) + tx.send(Msg::Download(DLMsg::DownloadCompleted(url, None))) .ok(); } }