use jellycommon::{NodeKind, NodePublic}; use rocket::{ http::uri::fmt::{Query, UriDisplay}, FromForm, FromFormField, UriDisplayQuery, }; #[derive(FromForm, UriDisplayQuery)] pub struct NodeFilterSort { sort_by: Option, filter_kind: Option>, sort_order: Option, } #[rustfmt::skip] #[derive(FromFormField, UriDisplayQuery, Clone, Copy, PartialEq, Eq)] enum SortProperty { #[field(value = "release_date")] ReleaseDate, #[field(value = "title")] Title, } #[rustfmt::skip] #[derive(FromFormField, UriDisplayQuery, Clone, Copy, PartialEq, Eq)] enum SortOrder { #[field(value = "ascending")] Ascending, #[field(value = "descending")] Descending, } pub fn filter_and_sort_nodes(f: &NodeFilterSort, nodes: &mut Vec<(String, NodePublic)>) { nodes.retain(|(_id, node)| { let mut o = true; if let Some(kind) = &f.filter_kind { o &= kind.contains(&node.kind) } o }); if let Some(sort_prop) = f.sort_by { match sort_prop { SortProperty::ReleaseDate => nodes.sort_by_key(|(_, _n)| 0), // TODO SortProperty::Title => nodes.sort_by(|(_, a), (_, b)| a.title.cmp(&b.title)), } } match f.sort_order.unwrap_or(SortOrder::Ascending) { SortOrder::Ascending => (), SortOrder::Descending => nodes.reverse(), } } markup::define! { NodeFilterSortForm<'a>(f: &'a NodeFilterSort) { details { summary { "Filter and Sort" } form[method="GET", action=""] { fieldset { legend { "Filter" } @use NodeKind::*; @for (value, label) in [(Movie, "Movie"), (Episode, "Episode"), (Video, "Video"), (Channel, "Channel")] { label { input[type="checkbox", name="filter_kind", value=A(value), checked=f.filter_kind.as_ref().map(|k|k.contains(&value)).unwrap_or(true)]; @label } br; } } fieldset { legend { "Sort By" } @use SortProperty::*; @for (value, label) in [(Title, "Title"), (ReleaseDate, "Release Date")] { label { input[type="radio", name="sort_by", value=value, checked=Some(value)==f.sort_by]; @label } br; } } fieldset { legend { "Sort Order" } @use SortOrder::*; @for (value, label) in [(Ascending, "Ascending"), (Descending, "Descending")] { label { input[type="radio", name="sort_order", value=value, checked=Some(value)==f.sort_order]; @label } br; } } input[type="submit", value="Apply"]; } } } } impl markup::Render for SortProperty { fn render(&self, writer: &mut impl std::fmt::Write) -> std::fmt::Result { writer.write_fmt(format_args!("{}", self as &dyn UriDisplay)) } } impl markup::Render for SortOrder { fn render(&self, writer: &mut impl std::fmt::Write) -> std::fmt::Result { writer.write_fmt(format_args!("{}", self as &dyn UriDisplay)) } } struct A(NodeKind); impl markup::Render for A { fn render(&self, writer: &mut impl std::fmt::Write) -> std::fmt::Result { writer.write_fmt(format_args!("{}", &self.0 as &dyn UriDisplay)) } }