diff --git a/kikikoz.css b/kikikoz.css index 0026108..66d5779 100644 --- a/kikikoz.css +++ b/kikikoz.css @@ -30,11 +30,11 @@ li.dernier_arrive { color: darkgrey; } -.courante { +.active section.queue { background-color: lightgreen; } -.attente { +.attente section.queue { background-color: pink; } @@ -45,3 +45,7 @@ section.queue { display: flex; flex-direction: column; } + +.hidden { + display: none; +} diff --git a/src/main.rs b/src/main.rs index d378527..160a812 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,69 +1,270 @@ use sycamore::prelude::*; +use sycamore::builder::prelude::*; use sycamore::rt::JsCast; use rand::prelude::*; +use rand::distributions::Alphanumeric; -enum Queue { +enum NomQueue { A, B } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq)] enum ModeQueue { Chrono, Aléatoire } -fn enqueue(queue: &mut Vec, s: A, mode: ModeQueue, rng: &mut ThreadRng) { - // - let n = queue.len(); - let k = match mode { - ModeQueue::Chrono => 0, - ModeQueue::Aléatoire => { - // let mut rng = thread_rng(); - rng.gen_range(0, n + 1) +impl ModeQueue { + fn set_aléatoire(&mut self, b: bool) { + match b { + false => { *self = ModeQueue::Chrono}, + true => { *self = ModeQueue::Aléatoire}, } - }; - queue.insert(k, s) + } +} + +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) + } +} + +#[derive(Clone)] +struct ÉtatQueue<'a> { + nom: String, + mode: &'a Signal, + contenu: &'a Signal>, + nouvelleau: &'a Signal, + priorité: &'a Signal, +} + +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()), + } + } + + fn len(&self) -> usize { + 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()) + } + + + + fn dequeue(&mut self) -> Option { + if self.len() > 0 { + Some(self.contenu.modify().remove(0)) + } else { + None + } + } + +} + +#[derive(Prop)] +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()) + } + } +} + +// #[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 { + 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 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, || + 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)); + + 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) +} + + +#[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() + } + } + } + } + } } fn main() { sycamore::render(|cx| { - let prochainə = create_signal(cx, String::from("Camille")); - let queue_A = create_signal(cx, vec![]); - let nouvelleau_queue_A = create_signal(cx, "".into()); - let mode_queue_A = create_signal(cx, ModeQueue::Aléatoire); - let mut do_enqueue = |_queue| { - let mut rng = thread_rng(); - let val: std::rc::Rc = nouvelleau_queue_A.get(); - enqueue(&mut queue_A.modify(), String::from(val.as_str()), *mode_queue_A.get(), &mut rng) + 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(); + + view! { cx, main { h1 { "Kikikoz" } - p(class="orateurice") { (prochainə.get()) } + p(class="orateurice") { + "On écoute " (prochainə.get()) "." + br {} + button(on:click=next) { "Suivantə" } + } section(id="les_queues") { - section(id="queue_A", class="queue") { - "Queue A" - input(type="text", bind:value=nouvelleau_queue_A, on:keypress=move |ev: web_sys::Event| { - let event : web_sys::KeyboardEvent = ev.unchecked_into(); - - if event.key_code() == 13 { - do_enqueue(Queue::A); - nouvelleau_queue_A.set(String::new()) - } - }) - ul { - Indexed { - iterable: &queue_A, - view: |cx, item: String| view! {cx, - li { (item) } - }, - } - } + div(class=(match *queue_courante.get(){NomQueue::A=> "active", NomQueue::B=>"attente"})) { + Queue { + q: queue_A_pour_aff + } + } + + div(class=(match *queue_courante.get(){NomQueue::B=>"active", NomQueue::A=>"attente"})) { + Queue { + q: queue_B_pour_aff + } } - section(id="queue_B", class="queue") { "Queue B" } } } - + 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())} + // } + } + } } }); }