use std::rc::Rc;
use teksilo_data::ListModel;
pub trait SectionProvider: 'static {
fn section_count(&self) -> usize;
fn items_in_section(&self, section: usize) -> usize;
fn section_title(&self, section: usize) -> String;
fn section_counts(&self) -> Vec<usize> {
(0..self.section_count())
.map(|s| self.items_in_section(s))
.collect()
}
}
pub struct GroupingSections {
runs: Vec<(String, usize)>,
}
impl GroupingSections {
fn new(runs: Vec<(String, usize)>) -> Self {
Self { runs }
}
}
impl SectionProvider for GroupingSections {
fn section_count(&self) -> usize {
self.runs.len()
}
fn items_in_section(&self, section: usize) -> usize {
self.runs.get(section).map(|(_, c)| *c).unwrap_or(0)
}
fn section_title(&self, section: usize) -> String {
self.runs
.get(section)
.map(|(t, _)| t.clone())
.unwrap_or_default()
}
}
pub fn grouping_sections<T, K, F>(model: &ListModel<T>, key_fn: F) -> GroupingSections
where
T: 'static,
K: ToString + PartialEq + 'static,
F: Fn(&T) -> K + 'static,
{
let mut runs: Vec<(String, usize)> = Vec::new();
let mut last_key: Option<K> = None;
for i in 0..model.len() {
let key = model.with_item(i, &key_fn);
if let Some(key) = key {
let same = last_key.as_ref().map(|k| *k == key).unwrap_or(false);
if same {
if let Some(last) = runs.last_mut() {
last.1 += 1;
}
} else {
runs.push((key.to_string(), 1));
last_key = Some(key);
}
}
}
GroupingSections::new(runs)
}
#[derive(Clone)]
pub(crate) struct SectionData {
pub(crate) counts_fn: Rc<dyn Fn() -> Vec<usize>>,
pub(crate) title_fn: Rc<dyn Fn(usize) -> String>,
}