aboutsummaryrefslogtreecommitdiff
path: root/server/src/routes/ui/sort.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2023-08-07 11:10:10 +0200
committermetamuffin <metamuffin@disroot.org>2023-08-07 11:59:59 +0200
commitdc7ed1ccaa5e727b3ab0569fd7fe56a2d0084bd5 (patch)
treeeb724ec5c0de92abef03549365eba01e07c06d90 /server/src/routes/ui/sort.rs
parent55eba6fdc6742d2850d003059220284bace059fc (diff)
downloadjellything-dc7ed1ccaa5e727b3ab0569fd7fe56a2d0084bd5.tar
jellything-dc7ed1ccaa5e727b3ab0569fd7fe56a2d0084bd5.tar.bz2
jellything-dc7ed1ccaa5e727b3ab0569fd7fe56a2d0084bd5.tar.zst
node sort ui
Diffstat (limited to 'server/src/routes/ui/sort.rs')
-rw-r--r--server/src/routes/ui/sort.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/server/src/routes/ui/sort.rs b/server/src/routes/ui/sort.rs
new file mode 100644
index 0000000..3ab6cef
--- /dev/null
+++ b/server/src/routes/ui/sort.rs
@@ -0,0 +1,95 @@
+use jellycommon::{NodeKind, NodePublic};
+use rocket::{
+ http::uri::fmt::{Query, UriDisplay},
+ FromForm, FromFormField, UriDisplayQuery,
+};
+
+#[derive(FromForm, UriDisplayQuery)]
+pub struct NodeFilterSort {
+ sort_by: Option<SortProperty>,
+ filter_kind: Option<Vec<NodeKind>>,
+ sort_order: Option<SortOrder>,
+}
+
+#[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<Query>))
+ }
+}
+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<Query>))
+ }
+}
+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<Query>))
+ }
+}