From 72e27dc20d8f8cbcd88e020368fb5f825288fa89 Mon Sep 17 00:00:00 2001 From: Florent Becker Date: Sat, 23 Jul 2022 18:31:25 +0200 Subject: [PATCH] =?UTF-8?q?Ajout=20/=20suppressions=20de=20queues,=20prior?= =?UTF-8?q?it=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.rs | 445 +++++++++++++++++++++++++++++----------------------- 1 file changed, 249 insertions(+), 196 deletions(-) diff --git a/src/main.rs b/src/main.rs index 160a812..815d91b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,270 +1,323 @@ -use sycamore::prelude::*; -use sycamore::builder::prelude::*; -use sycamore::rt::JsCast; -use rand::prelude::*; use rand::distributions::Alphanumeric; - -enum NomQueue { - A, B -} +use rand::prelude::*; +use sycamore::builder::prelude::*; +use sycamore::prelude::*; +use sycamore::rt::JsCast; #[derive(Clone, Copy, PartialEq, Eq)] enum ModeQueue { Chrono, - Aléatoire + Aléatoire, } impl ModeQueue { fn set_aléatoire(&mut self, b: bool) { - match b { - false => { *self = ModeQueue::Chrono}, - true => { *self = ModeQueue::Aléatoire}, - } + match b { + false => *self = ModeQueue::Chrono, + true => *self = ModeQueue::Aléatoire, + } } } impl std::fmt::Display for ModeQueue { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - let s = match self { - ModeQueue::Chrono => "Chrono", - ModeQueue::Aléatoire => "Aléatoire" - }; - write!(fmt, "{}", s) + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + let s = match self { + ModeQueue::Chrono => "Chrono", + ModeQueue::Aléatoire => "Aléatoire", + }; + write!(fmt, "{}", s) } } #[derive(Clone)] struct ÉtatQueue<'a> { nom: String, + id: usize, mode: &'a Signal, contenu: &'a Signal>, nouvelleau: &'a Signal, priorité: &'a Signal, + crédit_parole: &'a Signal, + à_détruire: &'a Signal, } +impl<'a> PartialEq for ÉtatQueue<'a> { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl<'a> Eq for ÉtatQueue<'a> {} + impl<'a> ÉtatQueue<'a> { fn new<'b>(cx: BoundedScope<'a, 'b>, nom: &str) -> Self { - ÉtatQueue { - nom: nom.into(), - mode: create_signal(cx, ModeQueue::Aléatoire), - contenu: create_signal(cx, vec![]), - nouvelleau: create_signal(cx, "".into()), - priorité: create_signal(cx, 1.into()), - } + ÉtatQueue { + nom: nom.into(), + mode: create_signal(cx, ModeQueue::Aléatoire), + contenu: create_signal(cx, vec![]), + nouvelleau: create_signal(cx, "".into()), + priorité: create_signal(cx, 1), + crédit_parole: create_signal(cx, 0.0), + id: thread_rng().gen(), + à_détruire: create_signal(cx, false), + } } fn len(&self) -> usize { - return self.contenu.get().len() + return self.contenu.get().len(); } fn enqueue(&mut self, rng: &mut ThreadRng) { - // - let s = &self.nouvelleau; - let n = self.len(); - let k = match *self.mode.get() { - ModeQueue::Chrono => n, - ModeQueue::Aléatoire => { - rng.gen_range(0, n + 1) - } - }; - self.contenu.modify().insert(k, s.to_string()) + // + let s = &self.nouvelleau; + let n = self.len(); + let k = match *self.mode.get() { + ModeQueue::Chrono => n, + ModeQueue::Aléatoire => rng.gen_range(0, n + 1), + }; + self.contenu.modify().insert(k, s.to_string()) } - - fn dequeue(&mut self) -> Option { - if self.len() > 0 { - Some(self.contenu.modify().remove(0)) - } else { - None - } + *self.crédit_parole.modify() -= 1.0; + if self.len() > 0 { + Some(self.contenu.modify().remove(0)) + } else { + None + } } - } #[derive(Prop)] -struct QueueProp<'a>{ - q: ÉtatQueue<'a> +struct QueueProp<'a> { + q: ÉtatQueue<'a>, } fn validate_queue<'a>(mut queue: ÉtatQueue<'a>) -> impl FnMut(web_sys::Event) + 'a { move |ev: web_sys::Event| { - let mut rng = thread_rng(); - let event : web_sys::KeyboardEvent = ev.unchecked_into(); - - if event.key_code() == 13 { - queue.enqueue(&mut rng); - queue.nouvelleau.set(String::new()) - } - } + let mut rng = thread_rng(); + let event: web_sys::KeyboardEvent = ev.unchecked_into(); + + if event.key_code() == 13 && !event.ctrl_key() { + queue.enqueue(&mut rng); + queue.nouvelleau.set(String::new()) + } + } } -// #[component] -// fn Queue<'a, G: Html>(cx: Scope<'a>, queue: QueueProp<'a>) -> View { -// let queue_courante = use_context::>(cx); - -// } - - #[component] -fn ConfigQueue<'a, G: Html>(cx: Scope<'a>, queue: QueueProp<'a>) -> View { +fn ConfigQueue<'a, G: Html>(cx: Scope<'a>, q: QueueProp<'a>) -> View { + let queue: ÉtatQueue = q.q; let prio_str = create_signal(cx, String::new()); let est_aléatoire = create_signal(cx, true); //*queue.q.mode.get() == ModeQueue::Aléatoire); - let nom = queue.q.nom; + let nom = queue.nom; let suffix = rand::thread_rng() .sample_iter(&Alphanumeric) .take(15) .map(char::from) .collect::(); - create_effect(cx, || - if let Ok(p) = prio_str.get().parse::() { - queue.q.priorité.set(p) - }); - create_effect(cx, || prio_str.set(format!("{}", queue.q.priorité.get()))); + create_effect(cx, || { + if let Ok(p) = prio_str.get().parse::() { + queue.priorité.set(p) + } + }); + create_effect(cx, || prio_str.set(format!("{}", queue.priorité.get()))); - create_effect(cx, || - queue.q.mode.modify().set_aléatoire(*est_aléatoire.get())); - create_effect(cx, || est_aléatoire.set(*queue.q.mode.get() == ModeQueue::Aléatoire)); + create_effect(cx, || { + queue.mode.modify().set_aléatoire(*est_aléatoire.get()) + }); + create_effect(cx, || { + est_aléatoire.set(*queue.mode.get() == ModeQueue::Aléatoire) + }); section() - .c(h3().dyn_t(move || nom.clone())) - .c(input() - .attr("type", "checkbox") - .dyn_attr("id", { let suffix = suffix.clone(); - move || Some(format!("mode_queue_{}", &suffix.clone())) - }) - .bind_checked(est_aléatoire) - ) - .c(label() - .dyn_attr("for", { - let suffix = suffix.clone(); - move || Some(format!("mode_queue_{}", &suffix.clone())) - }) - .t("Entrée aléatoire") - ) - .c(br()) - .c(input() - .dyn_attr("id", { let suffix = suffix.clone(); - move || Some(format!("prio_queue_{}", &suffix.clone())) - }) - .attr("type", "range") - .attr("min", "1") - .attr("max", "7") - .bind_value(prio_str) - ) - .c( - label() - .dyn_attr("for", { let suffix = suffix.clone(); - move || Some(format!("prio_queue_{}", &suffix.clone())) - }) - .dyn_t(|| format!("Priorité: {}", queue.q.priorité.get())) - ) - .view(cx) + .c(h3().dyn_t(move || nom.clone())) + .c(input() + .attr("type", "checkbox") + .dyn_attr("id", { + let suffix = suffix.clone(); + move || Some(format!("mode_queue_{}", &suffix.clone())) + }) + .bind_checked(est_aléatoire)) + .c(label() + .dyn_attr("for", { + let suffix = suffix.clone(); + move || Some(format!("mode_queue_{}", &suffix.clone())) + }) + .t("Entrée aléatoire")) + .c(br()) + .c(input() + .dyn_attr("id", { + let suffix = suffix.clone(); + move || Some(format!("prio_queue_{}", &suffix.clone())) + }) + .attr("type", "range") + .attr("min", "1") + .attr("max", "7") + .bind_value(prio_str)) + .c(label() + .dyn_attr("for", { + let suffix = suffix.clone(); + move || Some(format!("prio_queue_{}", &suffix.clone())) + }) + .dyn_t(|| format!("Priorité: {}", queue.priorité.get()))) + .c(button() + .t("Supprimer") + .on("click", move |ev| (queue.à_détruire.set(true)))) + .view(cx) } - #[component] fn Queue<'a, G: Html>(cx: Scope<'a>, queue: QueueProp<'a>) -> View { let ok_queue = validate_queue(queue.q.clone()); view! { cx, - div { - section(class="queue") { - h3 {(queue.q.nom)} - input(type="text", bind:value = queue.q.nouvelleau, on:keypress=ok_queue) {} - ul { - Keyed { - iterable: queue.q.contenu, - view: |cx, item: String| view! {cx, li { (item) }}, - key: |x| x.clone() - } - } - } - } + div { + section(class="queue") { + h3 {(format!("{} ({} - {})", queue.q.nom, queue.q.crédit_parole.get(), queue.q.priorité.get()))} + input(type="text", bind:value = queue.q.nouvelleau, on:keypress=ok_queue) {} + ul { + Keyed { + iterable: queue.q.contenu, + view: |cx, item: String| view! {cx, li { (item) }}, + key: |x| x.clone() + } + } + } + } } } fn main() { sycamore::render(|cx| { - let prochainə = create_signal(cx, String::from("personne encore")); - let conf_visible = create_signal(cx, false); - let queue_A = ÉtatQueue::new(cx, "Gauche"); - let queue_B = ÉtatQueue::new(cx, "Droite"); - let queue_courante = create_signal(cx, NomQueue::A); - provide_context_ref(cx, queue_courante); - let next = { - let mut my_queue_A = queue_A.clone(); - let mut my_queue_B = queue_B.clone(); - move |_ev| { - let (queue, next) = match *queue_courante.get() { - NomQueue::A => (&mut my_queue_A, NomQueue::B), - NomQueue::B => (&mut my_queue_B, NomQueue::A) - }; - match queue.dequeue() { - Some(p) => prochainə.set(p), - None => () - } - queue_courante.set(next); - } - - }; - - let queue_A_pour_aff = queue_A.clone(); - let queue_A_pour_conf = queue_A.clone(); - let queue_B_pour_aff = queue_B.clone(); - let queue_B_pour_conf = queue_B.clone(); + let prochainə = create_signal(cx, String::from("personne encore")); + let conf_visible = create_signal(cx, false); + let queues = create_signal( + cx, + vec![ÉtatQueue::new(cx, "Gauche"), ÉtatQueue::new(cx, "Droite")], + ); + let supprime_queue = + create_effect(cx, || queues.modify().retain(|q| !(*q.à_détruire.get()))); + let queues_suppression = queues.clone(); + let index_queues = create_memo(cx, { + || (0..queues.get().len()).into_iter().collect::>() + }); + let total_priorités: &ReadSignal = create_memo(cx, { + let queues = queues.clone(); + move || { + queues + .get() + .iter() + .map(|q| *q.priorité.get() as usize) + .sum() + } + }); + let queue_courante: &ReadSignal<(usize, usize)> = create_memo(cx, { + let queues = queues.clone(); + move || { + let (idx, (id, _q)) = queues + .get() + .iter() + .map(|q| (q.id, *q.crédit_parole.get())) + .enumerate() + .max_by(|(ia, (id_a, a)), (ib, (id_b, b))| { + a.partial_cmp(b).expect("Tried to compare a NaN") + }) + .expect("bla"); + (idx, id) + } + }); + provide_context_ref(cx, queue_courante); + let next = { + let mut queues = queues.clone(); + let queue_courante = queue_courante.clone(); + move |_ev| { + //js_sys::alert("coucou"); + let mut queue: ÉtatQueue = queues.get()[queue_courante.get().0].clone(); + match queue.dequeue() { + Some(p) => prochainə.set(p), + None => (), + } + for q in queues.get().iter() { + *q.crédit_parole.modify() += + (*q.priorité.get() as f32) / (*total_priorités.get() as f32) + } + } + }; + let nom_nouvelle_file = create_signal(cx, String::new()); + let nouvelle_file = { + let mut queues = queues.clone(); + move |_ev| { + let q = ÉtatQueue::new(cx, &nom_nouvelle_file.get()); + queues.modify().push(q); + *nom_nouvelle_file.modify() = String::new(); + } + }; - view! { cx, - main { - h1 { "Kikikoz" } - p(class="orateurice") { - "On écoute " (prochainə.get()) "." - br {} - button(on:click=next) { "Suivantə" } - } - section(id="les_queues") { - div(class=(match *queue_courante.get(){NomQueue::A=> "active", NomQueue::B=>"attente"})) { - Queue { - q: queue_A_pour_aff - } - } + view! { cx, + div(on:keypress= {let mut next = next.clone(); + move |ev: web_sys::Event| { + let event: web_sys::KeyboardEvent = ev.clone().unchecked_into(); + if event.key_code() == 13 && event.ctrl_key() { + next(ev) + } + } + }) { + main { + h1 { "Kikikoz" } + p(class="orateurice") { + "On écoute " (prochainə.get()) "." + br {} + button(on:click=next) { "Suivantə" } + } + section(id="les_queues") { + Keyed { + iterable: queues, //_pour_aff, + key: |q| q.id, + view: { + let queue_courante = queue_courante.clone(); + move |cx, q| + view!{ cx, + div(class=(if queue_courante.get().1 == q.id {"active"} else {"attente"})) { + Queue {q} + } - div(class=(match *queue_courante.get(){NomQueue::B=>"active", NomQueue::A=>"attente"})) { - Queue { - q: queue_B_pour_aff - } - } - } - } - aside { - button(on:click=|_| conf_visible.set(! *conf_visible.get())) { - ( - if *conf_visible.get() { - "cacher" - } else { - "configuration" - } - ) - } + } + } + } + } + } + aside { + button(on:click=|_| conf_visible.set(! *conf_visible.get())) { + ( + if *conf_visible.get() { + "cacher" + } else { + "configuration" + } + ) + } - div(class=if *conf_visible.get() { "visible" } else { "hidden" }) { - h2 { "Configuration" } - ConfigQueue { - q: queue_A_pour_conf - } - ConfigQueue { - q: queue_B_pour_conf - } - // section { - // h3 { "Queue B" } - // input(type="checkbox", id="mélanger_queue_B") {} - // label(for="enable_queue_B") {"Randomiser"} - // br {} - // input(type="range", id="prio_queue_B", min="1", max="7", bind:value=queue_B.priorité) {} - // label(for="prio_queue_B") {"Priorité "} // (queue_B.priorité.get())} - // } - } - } - } + div(class=if *conf_visible.get() { "visible" } else { "hidden" }) { + h2 { "Configuration" } + Keyed { + iterable: queues, + key: |q| q.id, + view: |cx, q| view!{cx, ConfigQueue{ q }} + } + section { + h3 {"Nouvelle file" } + input(type="text", bind:value=nom_nouvelle_file, on:keypress=move |ev: web_sys::Event| { + let event : web_sys::KeyboardEvent = ev.clone().unchecked_into(); + if event.key_code() == 13 && !event.ctrl_key() { + nouvelle_file(ev) + } + }) {} + button(on:click=nouvelle_file) { "Créer" } + } + } + } + } + } }); }