From febc0bf5199b4275c931cf6e76ecbc05235f27bd Mon Sep 17 00:00:00 2001 From: Tobias Reiher <15232394+treiher@users.noreply.github.com> Date: Sat, 19 Oct 2024 23:29:32 +0200 Subject: [PATCH] Add option to prefer exercise in training session --- CHANGELOG.md | 1 + frontend/src/page/training_session.rs | 281 ++++++++++++++++++++++++++ 2 files changed, 282 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e8234a..ac7eb7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Archiving of routines - Button for saving changes during guided training session - Settings for hiding UI elements related to RPE and TUT +- Option to prefer exercise in training session ### Changed diff --git a/frontend/src/page/training_session.rs b/frontend/src/page/training_session.rs index 7b5ff4a..e2e29d6 100644 --- a/frontend/src/page/training_session.rs +++ b/frontend/src/page/training_session.rs @@ -684,6 +684,7 @@ pub enum Msg { FilterChanged(usize), CreateExercise, ReplaceExercise(usize, usize, u32), + PreferExercise(usize), DeferExercise(usize), AddSet(usize), AddExercise(usize, usize, u32), @@ -1192,6 +1193,13 @@ pub fn update( .send_msg(Msg::SaveTrainingSession) .send_msg(Msg::CloseDialog); } + Msg::PreferExercise(element_idx) => { + prefer_exercise(&mut model.form.elements, element_idx); + update_metronome(model, orders, data_model.settings.automatic_metronome); + orders + .send_msg(Msg::SaveTrainingSession) + .send_msg(Msg::CloseDialog); + } Msg::DeferExercise(element_idx) => { defer_exercise(&mut model.form.elements, element_idx); update_metronome(model, orders, data_model.settings.automatic_metronome); @@ -1511,6 +1519,25 @@ fn replace_exercise( } } +fn prefer_exercise(elements: &mut [FormElement], element_idx: usize) { + let sections = determine_sections(elements); + let Some(preferred_section) = sections.iter().find(|s| (s.0..=s.1).contains(&element_idx)) + else { + return; + }; + if preferred_section.0 == 0 { + return; + } + let Some(deferred_section) = sections + .iter() + .find(|s| (s.0..=s.1).contains(&(preferred_section.0 - 1))) + else { + return; + }; + elements[deferred_section.0..=preferred_section.1] + .rotate_right(preferred_section.1 - preferred_section.0 + 1); +} + fn defer_exercise(elements: &mut Vec, element_idx: usize) { let mut deferred_ids = vec![]; let mut deferred_elements = 0; @@ -2634,6 +2661,22 @@ fn view_options_dialog(element_idx: usize, exercise_idx: usize) -> Vec span!["Replace exercise"], ] ]], + IF![exercise_idx == 0 => + p![ + C!["mt-3"], + a![ + C!["has-text-weight-bold"], + ev(Ev::Click, move |_| Msg::PreferExercise( + element_idx + )), + span![ + C!["icon-text"], + span![C!["icon"], i![C!["fas fa-arrow-turn-up"]]], + span!["Prefer exercise"], + ] + ] + ] + ], IF![exercise_idx == 0 => p![ C!["mt-3"], @@ -3046,6 +3089,208 @@ mod tests { ); } + #[test] + fn test_prefer_exercise_first_set() { + let mut elements = vec![ + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(1, 1)]), + rest(1), + set(vec![exercise(2, 2)]), + rest(2), + ]; + prefer_exercise(&mut elements, 0); + assert_eq!( + elements, + vec![ + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(1, 1)]), + rest(1), + set(vec![exercise(2, 2)]), + rest(2), + ] + ); + } + + #[test] + fn test_prefer_exercise_penultimate_set() { + let mut elements = vec![ + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(1, 1)]), + rest(1), + set(vec![exercise(2, 2)]), + rest(2), + ]; + prefer_exercise(&mut elements, 2); + assert_eq!( + elements, + vec![ + set(vec![exercise(1, 1)]), + rest(1), + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(2, 2)]), + rest(2), + ] + ); + } + + #[test] + fn test_prefer_exercise_penultimate_set_without_trailing_rest() { + let mut elements = vec![ + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(1, 1)]), + rest(1), + set(vec![exercise(2, 2)]), + ]; + prefer_exercise(&mut elements, 2); + assert_eq!( + elements, + vec![ + set(vec![exercise(1, 1)]), + rest(1), + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(2, 2)]), + ] + ); + } + + #[test] + fn test_prefer_exercise_last_set() { + let mut elements = vec![ + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(1, 1)]), + rest(1), + set(vec![exercise(2, 2)]), + rest(2), + ]; + prefer_exercise(&mut elements, 4); + assert_eq!( + elements, + vec![ + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(2, 2)]), + rest(2), + set(vec![exercise(1, 1)]), + rest(1), + ] + ); + } + + #[test] + fn test_prefer_exercise_multiple_sets() { + let mut elements = vec![ + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(1, 0)]), + rest(1), + set(vec![exercise(2, 1)]), + rest(2), + set(vec![exercise(3, 1)]), + rest(3), + set(vec![exercise(4, 2)]), + rest(4), + set(vec![exercise(5, 2)]), + rest(5), + ]; + prefer_exercise(&mut elements, 4); + assert_eq!( + elements, + vec![ + set(vec![exercise(2, 1)]), + rest(2), + set(vec![exercise(3, 1)]), + rest(3), + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(1, 0)]), + rest(1), + set(vec![exercise(4, 2)]), + rest(4), + set(vec![exercise(5, 2)]), + rest(5), + ] + ); + } + + #[test] + fn test_prefer_exercise_multiple_sets_last_set() { + let mut elements = vec![ + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(1, 0)]), + rest(1), + set(vec![exercise(2, 1)]), + rest(2), + set(vec![exercise(3, 1)]), + rest(3), + set(vec![exercise(4, 2)]), + rest(4), + set(vec![exercise(5, 2)]), + rest(5), + ]; + prefer_exercise(&mut elements, 6); + assert_eq!( + elements, + vec![ + set(vec![exercise(2, 1)]), + rest(2), + set(vec![exercise(3, 1)]), + rest(3), + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(1, 0)]), + rest(1), + set(vec![exercise(4, 2)]), + rest(4), + set(vec![exercise(5, 2)]), + rest(5), + ] + ); + } + + #[test] + fn test_prefer_exercise_supersets() { + let mut elements = vec![ + set(vec![exercise(0, 0), exercise(1, 1)]), + rest(0), + set(vec![exercise(2, 0), exercise(3, 1)]), + rest(1), + set(vec![exercise(4, 0), exercise(5, 2)]), + rest(2), + set(vec![exercise(6, 0), exercise(7, 2)]), + rest(3), + set(vec![exercise(8, 1), exercise(9, 2)]), + rest(4), + set(vec![exercise(10, 1), exercise(11, 2)]), + rest(5), + ]; + prefer_exercise(&mut elements, 4); + assert_eq!( + elements, + vec![ + set(vec![exercise(4, 0), exercise(5, 2)]), + rest(2), + set(vec![exercise(6, 0), exercise(7, 2)]), + rest(3), + set(vec![exercise(0, 0), exercise(1, 1)]), + rest(0), + set(vec![exercise(2, 0), exercise(3, 1)]), + rest(1), + set(vec![exercise(8, 1), exercise(9, 2)]), + rest(4), + set(vec![exercise(10, 1), exercise(11, 2)]), + rest(5), + ] + ); + } + #[test] fn test_defer_exercise_first_set() { let mut elements = vec![ @@ -3177,6 +3422,42 @@ mod tests { ); } + #[test] + fn test_defer_exercise_multiple_sets_last_set() { + let mut elements = vec![ + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(1, 0)]), + rest(1), + set(vec![exercise(2, 1)]), + rest(2), + set(vec![exercise(3, 1)]), + rest(3), + set(vec![exercise(4, 2)]), + rest(4), + set(vec![exercise(5, 2)]), + rest(5), + ]; + defer_exercise(&mut elements, 2); + assert_eq!( + elements, + vec![ + set(vec![exercise(0, 0)]), + rest(0), + set(vec![exercise(2, 1)]), + rest(2), + set(vec![exercise(3, 1)]), + rest(3), + set(vec![exercise(1, 0)]), + rest(1), + set(vec![exercise(4, 2)]), + rest(4), + set(vec![exercise(5, 2)]), + rest(5), + ] + ); + } + #[test] fn test_defer_exercise_supersets() { let mut elements = vec![