use super::search::{read_local_only, read_range_filter, read_tag_filter};
use crate::MainWindow;
use indicatrix_editor::guide::viewing_events as events;
use indicatrix_vault::model::filter::RangeFilter;
use std::cell::Cell;
#[derive(Clone, Copy, Debug)]
pub(super) struct Narrowing<'a> {
pub(super) search: &'a str,
pub(super) shape: &'a str,
pub(super) gear: &'a str,
pub(super) range: &'a RangeFilter,
pub(super) local_only: bool,
pub(super) tag_chosen: bool,
}
impl Narrowing<'_> {
pub(super) fn is_on(&self) -> bool {
let narrowing_ranges = RangeFilter {
include_ignored: false,
..self.range.clone()
};
!self.search.trim().is_empty()
|| !matches!(self.shape, "All Shapes" | "All" | "")
|| !matches!(self.gear, "All Gears" | "All" | "")
|| self.local_only
|| self.tag_chosen
|| narrowing_ranges != RangeFilter::default()
}
}
pub(super) fn library_is_narrowed(ui: &MainWindow, search: &str, shape: &str, gear: &str) -> bool {
let range = read_range_filter(ui);
Narrowing {
search,
shape,
gear,
range: &range,
local_only: read_local_only(ui),
tag_chosen: read_tag_filter(ui).is_some(),
}
.is_on()
}
pub(super) fn search_event(search: &str) -> &'static str {
if search.trim().is_empty() {
events::LIBRARY_SEARCH_CLEARED
} else {
events::LIBRARY_SEARCHED
}
}
#[derive(Debug, Default)]
pub(super) struct NarrowingMemory {
narrowed: Cell<bool>,
}
impl NarrowingMemory {
pub(super) const fn went_off(&self, narrowed_now: bool) -> bool {
self.narrowed.replace(narrowed_now) && !narrowed_now
}
}
#[cfg(test)]
mod tests {
use super::*;
fn untouched(range: &RangeFilter) -> Narrowing<'_> {
Narrowing {
search: "",
shape: "All Shapes",
gear: "All Gears",
range,
local_only: false,
tag_chosen: false,
}
}
#[test]
fn an_untouched_library_is_not_narrowed() {
let range = RangeFilter::default();
assert!(!untouched(&range).is_on());
}
#[test]
fn a_search_a_shape_a_gear_my_designs_a_tag_or_a_range_narrows_it() {
let range = RangeFilter::default();
let base = untouched(&range);
assert!(
Narrowing {
search: "rbc",
..base
}
.is_on()
);
assert!(
Narrowing {
shape: "Round",
..base
}
.is_on()
);
assert!(Narrowing { gear: "96", ..base }.is_on());
assert!(
Narrowing {
local_only: true,
..base
}
.is_on()
);
assert!(
Narrowing {
tag_chosen: true,
..base
}
.is_on()
);
let narrowed = RangeFilter {
ri_min: Some(1.6),
..RangeFilter::default()
};
assert!(untouched(&narrowed).is_on());
}
#[test]
fn spaces_in_the_box_and_the_all_entries_are_no_filter() {
let range = RangeFilter::default();
let base = untouched(&range);
assert!(
!Narrowing {
search: " ",
shape: "All",
gear: "All",
..base
}
.is_on()
);
}
#[test]
fn show_ignored_only_widens_the_list() {
let range = RangeFilter {
include_ignored: true,
..RangeFilter::default()
};
assert!(!untouched(&range).is_on());
}
#[test]
fn an_emptied_box_reports_a_cleared_search_and_a_box_with_text_a_search() {
assert_eq!(search_event("rbc"), events::LIBRARY_SEARCHED);
assert_eq!(search_event(" r "), events::LIBRARY_SEARCHED);
assert_eq!(search_event(""), events::LIBRARY_SEARCH_CLEARED);
assert_eq!(search_event(" "), events::LIBRARY_SEARCH_CLEARED);
}
#[test]
fn the_memory_reports_only_the_change_from_narrowed_to_not() {
let memory = NarrowingMemory::default();
assert!(!memory.went_off(false));
assert!(!memory.went_off(true));
assert!(!memory.went_off(true));
assert!(memory.went_off(false));
assert!(!memory.went_off(false));
assert!(!memory.went_off(true));
assert!(memory.went_off(false));
}
}