use std::sync::Arc;
use derive_where::derive_where;
use topcoat::{context::Cx, view::BoxView};
use super::{
Column, ColumnToggle, ColumnWidth, Includes,
cell::{TextCell, text_cell},
};
use crate::display::{Alignment, Color};
#[derive_where(Clone, Debug)]
pub struct ComputedColumn<M> {
name: String,
label: crate::Text,
#[derive_where(skip(Debug))]
project: Arc<dyn Fn(&M) -> String + Send + Sync>,
width: ColumnWidth,
alignment: Alignment,
toggle: ColumnToggle,
includes: Includes<M>,
reads: Option<crate::lens::Reads<M>>,
badge: bool,
#[derive_where(skip(Debug))]
color: Option<super::ReadFn<M, Option<Color>>>,
}
impl<M> ComputedColumn<M>
where
M: toasty::schema::Model,
{
pub fn new(
label: impl Into<crate::Text>,
project: impl Fn(&M) -> String + Send + Sync + 'static,
) -> Self {
let label = label.into();
Self {
name: label.key(),
label,
project: Arc::new(project),
width: ColumnWidth::Auto,
alignment: Alignment::Start,
toggle: ColumnToggle::Fixed,
includes: Includes::new(),
reads: None,
badge: false,
color: None,
}
}
pub fn badge(mut self) -> Self {
self.badge = true;
self
}
pub fn color(mut self, color: impl Fn(&M) -> Option<Color> + Send + Sync + 'static) -> Self {
self.color = Some(Arc::new(color));
self
}
pub fn include_unscoped<T>(mut self, relation: impl Into<toasty::stmt::Include<M, T>>) -> Self {
self.includes = self.includes.with(relation);
self
}
pub fn reading(mut self, reads: crate::lens::Reads<M>) -> Self {
self.reads = Some(reads);
self
}
pub fn width(mut self, width: ColumnWidth) -> Self {
self.width = width;
self
}
pub fn align(mut self, alignment: Alignment) -> Self {
self.alignment = alignment;
self
}
toggle_builders!(toggle);
}
impl<M> Column<M> for ComputedColumn<M>
where
M: toasty::schema::Model + Send + Sync + 'static,
{
fn name(&self) -> &str {
&self.name
}
fn label(&self) -> crate::Text {
self.label.clone()
}
fn text(&self, _cx: &Cx, row: &M) -> String {
(self.project)(row)
}
fn cell<'a>(&self, cx: &'a Cx, row: &M) -> BoxView<'a> {
let text = (self.project)(row);
let color = self
.color
.as_ref()
.filter(|_| !text.trim().is_empty())
.and_then(|color| color(row));
text_cell(
cx,
TextCell {
text,
color,
badge: self.badge,
..TextCell::default()
},
)
}
fn column_width(&self) -> ColumnWidth {
self.width
}
fn toggle(&self) -> ColumnToggle {
self.toggle
}
fn alignment(&self) -> Alignment {
self.alignment
}
fn includes(&self) -> Includes<M> {
self.includes.clone()
}
fn reads(&self) -> Option<crate::lens::Reads<M>> {
self.reads.clone()
}
}