From 12f78d5acc6ee6fea271cc2ad8f86afabaedeeea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asger=20Juul=20Brunsh=C3=B8j?= Date: Fri, 28 Feb 2025 15:29:03 +0100 Subject: [PATCH] nested suspend --- .helix/languages.toml | 2 +- crates/ascend/src/components/attempt.rs | 30 ++++++++ crates/ascend/src/components/icons.rs | 72 +++++++++++++++++-- crates/ascend/src/lib.rs | 1 + crates/ascend/src/models.rs | 32 ++++++--- crates/ascend/src/pages/wall.rs | 96 +++++++++++++++++++++---- 6 files changed, 205 insertions(+), 28 deletions(-) create mode 100644 crates/ascend/src/components/attempt.rs diff --git a/.helix/languages.toml b/.helix/languages.toml index a9719ff..3ec7ed5 100644 --- a/.helix/languages.toml +++ b/.helix/languages.toml @@ -5,7 +5,7 @@ language-servers = ["rust-analyzer", "tailwindcss-ls"] [language-server.rust-analyzer.config] # procMacro = { ignored = { leptos_macro = ["server"] } } cargo = { features = ["ssr", "hydrate"] } -check = { command = "clippy" } +check = { command = "check" } rustfmt = { overrideCommand = [ "sh", "-c", diff --git a/crates/ascend/src/components/attempt.rs b/crates/ascend/src/components/attempt.rs new file mode 100644 index 0000000..43d6e9f --- /dev/null +++ b/crates/ascend/src/components/attempt.rs @@ -0,0 +1,30 @@ +use crate::components::icons; +use crate::models; +use leptos::prelude::*; + +#[component] +#[tracing::instrument(skip_all)] +pub fn Attempt(#[prop(into)] attempt: Signal>) -> impl IntoView { + tracing::trace!("Enter"); + + let text = move || match attempt.get() { + Some(models::Attempt::Attempt) => "Learning experience", + Some(models::Attempt::Send) => "Send", + Some(models::Attempt::Flash) => "Flash", + None => "No attempt", + }; + + let icon = move || match attempt.get() { + Some(models::Attempt::Attempt) => view! { }.into_any(), + Some(models::Attempt::Send) => view! { }.into_any(), + Some(models::Attempt::Flash) => view! { }.into_any(), + None => view! { }.into_any(), + }; + + view! { +
+ {icon} + {text} +
+ } +} diff --git a/crates/ascend/src/components/icons.rs b/crates/ascend/src/components/icons.rs index 0069c38..e802f34 100644 --- a/crates/ascend/src/components/icons.rs +++ b/crates/ascend/src/components/icons.rs @@ -1,7 +1,7 @@ use leptos::prelude::*; #[component] -pub fn Bolt() -> impl IntoView { +pub fn BoltSolid() -> impl IntoView { view! { impl IntoView { } #[component] -pub fn Wrench() -> impl IntoView { +pub fn BoltSlashSolid() -> impl IntoView { + view! { + + + + } +} + +#[component] +pub fn WrenchSolid() -> impl IntoView { view! { impl IntoView { } #[component] -pub fn Forward() -> impl IntoView { +pub fn ForwardSolid() -> impl IntoView { view! { impl IntoView { } #[component] -pub fn Heart() -> impl IntoView { +pub fn HeartOutline() -> impl IntoView { view! { impl IntoView { } } + +#[component] +pub fn ArrowPath() -> impl IntoView { + view! { + + + + } +} + +#[component] +pub fn PaperAirplaneSolid() -> impl IntoView { + view! { + + + + } +} + +#[component] +pub fn NoSymbol() -> impl IntoView { + view! { + + + + } +} diff --git a/crates/ascend/src/lib.rs b/crates/ascend/src/lib.rs index 8baa318..aee0c62 100644 --- a/crates/ascend/src/lib.rs +++ b/crates/ascend/src/lib.rs @@ -11,6 +11,7 @@ pub mod components { pub use problem::Problem; pub use problem_info::ProblemInfo; + pub mod attempt; pub mod button; pub mod header; pub mod icons; diff --git a/crates/ascend/src/models.rs b/crates/ascend/src/models.rs index 50d1c1c..16f2673 100644 --- a/crates/ascend/src/models.rs +++ b/crates/ascend/src/models.rs @@ -14,6 +14,7 @@ pub use v2::Root; pub use v2::Wall; pub use v2::WallDimensions; pub use v2::WallUid; +pub use v3::Attempt; pub use v3::UserInteraction; pub mod v3 { @@ -21,7 +22,7 @@ pub mod v3 { use chrono::NaiveDate; use serde::Deserialize; use serde::Serialize; - use std::collections::BTreeSet; + use std::collections::BTreeMap; /// Registers user interaction with a problem #[derive(Serialize, Deserialize, Debug, Clone)] @@ -29,11 +30,8 @@ pub mod v3 { pub wall_uid: v2::WallUid, pub problem_uid: v2::ProblemUid, - /// Climbed problem - pub completed_on: BTreeSet, - - /// Flashed problem - pub flashed_on: BTreeSet, + /// Dates on which this problem was attempted, and how it went + pub attempted_on: BTreeMap, /// Is among favorite problems pub is_favorite: bool, @@ -47,11 +45,29 @@ pub mod v3 { wall_uid, problem_uid, is_favorite: false, - completed_on: BTreeSet::new(), - flashed_on: BTreeSet::new(), + attempted_on: BTreeMap::new(), is_saved: false, } } + + pub fn best_attempt(&self) -> Option<(NaiveDate, Attempt)> { + self.attempted_on + .iter() + .max_by_key(|(_date, attempt)| *attempt) + .map(|(date, attempt)| (*date, *attempt)) + } + } + + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)] + pub enum Attempt { + /// Tried to climb problem, but was not able to. + Attempt, + + /// Climbed problem, but not flashed. + Send, + + /// Flashed problem. + Flash, } } diff --git a/crates/ascend/src/pages/wall.rs b/crates/ascend/src/pages/wall.rs index 3b408c5..f2677b9 100644 --- a/crates/ascend/src/pages/wall.rs +++ b/crates/ascend/src/pages/wall.rs @@ -1,5 +1,18 @@ +// +------------------------+ +// | Name: ... | +// | Method: ... | +// | Set by: ... | +// | | +// | | Flash | Top | Attempt | | +// | | +// +-----------------------------+ +// | Today: | +// | | +// +--------------------------------------+ + use crate::codec::ron::RonEncoded; use crate::components::ProblemInfo; +use crate::components::attempt::Attempt; use crate::components::button::Button; use crate::components::header::HeaderItem; use crate::components::header::HeaderItems; @@ -78,8 +91,36 @@ pub fn Wall() -> impl IntoView { } }); + let ui_is_flash = RwSignal::new(false); + let ui_is_climbed = RwSignal::new(false); + let ui_is_favorite = RwSignal::new(false); + let user_interaction = crate::resources::user_interaction(wall_uid, problem_uid.into()); + // On reception of user interaction state, set UI signals + Effect::new(move |_prev_value| { + if let Some(user_interaction) = user_interaction.get() { + let user_interaction = user_interaction.ok().flatten(); + + if let Some(user_interaction) = user_interaction { + ui_is_favorite.set(user_interaction.is_favorite); + } else { + ui_is_favorite.set(false); + } + } + }); + + let attempt_suspend = Suspend::new(async move { + let user_interaction = user_interaction.await; + let user_interaction = user_interaction.ok().flatten(); + let best_attempt = user_interaction.and_then(|x| x.best_attempt()); + + let best_attempt_date = move || best_attempt.map(|pair| pair.0); + let best_attempt_attempt = move || best_attempt.map(|pair| pair.1); + + view! { } + }); + let header_items = move || HeaderItems { left: vec![], middle: vec![HeaderItem { @@ -98,10 +139,6 @@ pub fn Wall() -> impl IntoView { ], }; - let foo = RwSignal::new(false); - let bar = RwSignal::new(false); - let baz = RwSignal::new(false); - leptos::view! {
@@ -143,15 +180,15 @@ pub fn Wall() -> impl IntoView { value="" class="hidden peer" required="" - bind:checked=foo + bind:checked=ui_is_flash />