melors 0.2.2

Keyboard-first terminal MP3 player with queue, search, and tag editing
use super::*;

impl UiState {
    fn is_filtering_library(&self) -> bool {
        self.mode == InputMode::Search
    }

    pub fn visible_track_ids(&mut self, app: &App) -> &[i64] {
        self.refresh_library_cache(app);
        &self.library_cached_track_ids
    }

    pub fn selected_track_id(&mut self, app: &App) -> Option<i64> {
        self.refresh_library_cache(app);
        if self.library_cached_track_ids.is_empty() {
            return None;
        }
        self.library_cached_track_ids
            .get(min(
                self.library_selected,
                self.library_cached_track_ids.len() - 1,
            ))
            .copied()
    }

    pub fn library_rows_for_width(&mut self, app: &App, width: usize) -> &[String] {
        self.refresh_library_cache(app);
        if self.library_render_width != width
            || self.library_cached_render_rows.len() != self.library_cached_rows.len()
        {
            self.library_cached_render_rows = self
                .library_cached_rows
                .iter()
                .map(|row| Self::fixed_width_cell(row, width))
                .collect();
            self.library_render_width = width;
        }
        &self.library_cached_render_rows
    }

    pub(super) fn refresh_library_cache(&mut self, app: &App) {
        let tracks_version = app.tracks_version();
        let current_track_id = app.playback_state().current_track_id;
        if self.library_cache_tracks_version == tracks_version
            && self.library_cache_query == self.search_input
            && self.library_cache_mode == self.mode
            && self.library_cache_current_track_id == current_track_id
        {
            return;
        }

        self.library_cached_track_ids.clear();
        self.library_cached_rows.clear();

        if self.is_filtering_library() {
            self.search_warning = Self::search_warning_for_query(&self.search_input);
            let ids = app
                .search_track_ids_action(&self.search_input)
                .unwrap_or_default();
            self.library_cached_track_ids.reserve(ids.len());
            self.library_cached_rows.reserve(ids.len());
            for track_id in ids {
                if let Some(track) = app.track_by_id(track_id) {
                    self.library_cached_track_ids.push(track.id);
                    let marker = if Some(track.id) == current_track_id {
                        ">"
                    } else {
                        " "
                    };
                    let favorite = if track.favorite { "*" } else { " " };
                    self.library_cached_rows.push(format!(
                        "{}{} #{:04} {} - {}",
                        marker,
                        favorite,
                        track.id,
                        track.artist.as_deref().unwrap_or("Unknown Artist"),
                        track.title
                    ));
                }
            }
        } else {
            self.search_warning = None;
            let tracks = app.tracks();
            self.library_cached_track_ids.reserve(tracks.len());
            self.library_cached_rows.reserve(tracks.len());
            for track in tracks {
                self.library_cached_track_ids.push(track.id);
                let marker = if Some(track.id) == current_track_id {
                    ">"
                } else {
                    " "
                };
                let favorite = if track.favorite { "*" } else { " " };
                self.library_cached_rows.push(format!(
                    "{}{} #{:04} {} - {}",
                    marker,
                    favorite,
                    track.id,
                    track.artist.as_deref().unwrap_or("Unknown Artist"),
                    track.title
                ));
            }
        }

        self.library_cache_tracks_version = tracks_version;
        self.library_cache_query = self.search_input.clone();
        self.library_cache_mode = self.mode;
        self.library_cache_current_track_id = current_track_id;
        self.library_render_width = 0;
        self.library_cached_render_rows.clear();
    }

    pub(super) fn invalidate_library_cache(&mut self) {
        self.library_cache_tracks_version = 0;
        self.library_cache_query.clear();
        self.library_cache_current_track_id = None;
        self.library_cached_track_ids.clear();
        self.library_cached_rows.clear();
        self.library_render_width = 0;
        self.library_cached_render_rows.clear();
    }
    pub fn cached_track_seed(&mut self, app: &App) -> u64 {
        let current_track_id = app.playback_state().current_track_id;
        let tracks_version = app.tracks_version();
        if self.seed_cache_valid
            && self.seed_cached_track_id == current_track_id
            && self.seed_cached_tracks_version == tracks_version
        {
            return self.seed_cached_value;
        }
        let mut hasher = DefaultHasher::new();
        if let Some(track) = app.current_track() {
            track.id.hash(&mut hasher);
            track.path.hash(&mut hasher);
            track.title.hash(&mut hasher);
            track.artist.hash(&mut hasher);
            track.album.hash(&mut hasher);
            track.duration_secs.hash(&mut hasher);
        } else {
            0u64.hash(&mut hasher);
        }
        let value = hasher.finish();
        self.seed_cache_valid = true;
        self.seed_cached_track_id = current_track_id;
        self.seed_cached_tracks_version = tracks_version;
        self.seed_cached_value = value;
        value
    }

    fn fixed_width_cell(text: &str, width: usize) -> String {
        if width == 0 {
            return String::new();
        }

        let mut out: String = text.chars().take(width).collect();
        let used = out.chars().count();
        if used < width {
            out.push_str(&" ".repeat(width - used));
        }
        out
    }
}