From 65991f742e221f9eacfe09538506865bfb6ae4fa Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 3 Oct 2026 15:12:09 +0300 Subject: [PATCH] Basic exams page ready --- src/pages.rs | 1 + src/pages/exam.rs | 0 src/pages/exams.rs | 134 +++++++++++++++++++++++---------------------- 3 files changed, 69 insertions(+), 66 deletions(-) create mode 100644 src/pages/exam.rs diff --git a/src/pages.rs b/src/pages.rs index a4b7bb1..0150f3c 100644 --- a/src/pages.rs +++ b/src/pages.rs @@ -12,3 +12,4 @@ pub mod sync; pub mod word; pub mod writing; pub mod exams; +pub mod exam; diff --git a/src/pages/exam.rs b/src/pages/exam.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/exams.rs b/src/pages/exams.rs index 1729265..6ac07c6 100644 --- a/src/pages/exams.rs +++ b/src/pages/exams.rs @@ -8,13 +8,12 @@ use crate::notification::MaybeError; use crate::pages::exams::ExamsMessage::*; use crate::pages::repetitions::Style; use crate::push_error; -use crate::styling::{back_overlay, BUTTON_RADIUS, DEFAULT_SPACING, HALF_SPACING}; +use crate::styling::{back_overlay, cta_button, BUTTON_RADIUS, DEFAULT_SPACING, HALF_SPACING}; use crate::{jl_button, push_error_task}; use chrono::Utc; use iced::widget::button::Status; -use iced::widget::{ - button, center_x, column, container, row, scrollable, space, text, tooltip, Column, -}; +use iced::widget::rule::horizontal; +use iced::widget::{button, center_x, column, container, row, rule, scrollable, space, text, tooltip, Column}; use iced::{Element, Task}; use iced_core::Alignment::*; use iced_core::Length::{Fill, FillPortion}; @@ -35,7 +34,6 @@ pub struct ExamsState { pub enum ExamsMessage { Back, SelectExam(EntityHandle), - DeleteExam(EntityHandle), CreateExam, GotoExam, } @@ -62,9 +60,6 @@ impl NavigatedPage for ExamsState { SelectExam(id) => { self.selected_exam_id = Some(id); } - DeleteExam(id) => { - self.selected_exam_id = None; - } CreateExam => { let exam = Exam { id: Default::default(), @@ -125,9 +120,6 @@ impl ExamsState { fn selected_exam(&self) -> Option<&ExamExtended> { self.exams.get(&self.selected_exam_id?) } - fn selected_exam_mut(&mut self) -> Option<&mut ExamExtended> { - self.exams.get_mut(&self.selected_exam_id?) - } fn append_exam_entries(&mut self, handle: EntityHandle) -> MaybeError { let deck_id = self.deck_id.id; @@ -178,7 +170,7 @@ impl ExamsState { for (handle, deck) in self.exams.iter() { column = column.push( - button(text!("{}", &deck.timestamp.format("%d/%m/%Y %H:%M"))) + jl_button!(text!("{}", &deck.timestamp.format("%d/%m/%Y %H:%M"))) .on_press_with(move || SelectExam(*handle)) .style(move |_x: &Theme, status: Status| Style { background: if status == Status::Hovered { @@ -210,7 +202,9 @@ impl ExamsState { row![text!("{} карточек", exam.total), Self::exam_bar(exam)] .height(30) .align_y(Center) - .width(Fill).spacing(HALF_SPACING), + .width(Fill) + .spacing(HALF_SPACING), + rule::horizontal(2), self.exam_variable_view(exam), ] .spacing(DEFAULT_SPACING) @@ -226,59 +220,58 @@ impl ExamsState { let answered = exam.answered as f64 / exam.total as f64 * total; let unknown = exam.unknown as f64 / exam.total as f64 * total; let remaining = exam.remaining() as f64 / exam.total as f64 * total; - row![ - tooltip( + println!("{} {} {}", remaining, answered, unknown); + let mut row = row![]; + if answered > 0.0 { + row = row.push(tooltip( container(space()) .height(Fill) .width(FillPortion(answered as u16)) - .style(|theme: &Theme| { - container::Style { - background: Some(Background::Color(theme.palette().success)), - text_color: Default::default(), - border: Default::default(), - shadow: Default::default(), - snap: false, - } + .style(|theme: &Theme| container::Style { + background: Some(Background::Color(theme.palette().success)), + text_color: Default::default(), + border: Default::default(), + shadow: Default::default(), + snap: false, }), - text!("Правильно: {}%", answered / 10.0), - tooltip::Position::Bottom - ), - tooltip( + text!("Правильно: {}% ({})", answered / 10.0, exam.answered), + tooltip::Position::Bottom, + )); + } + if unknown > 0.0 { + row = row.push(tooltip( container(space()) .height(Fill) .width(FillPortion(unknown as u16)) - .style(|theme: &Theme| { - container::Style { - background: Some(Background::Color(theme.palette().danger)), - text_color: Default::default(), - border: Default::default(), - shadow: Default::default(), - snap: false, - } + .style(|theme: &Theme| container::Style { + background: Some(Background::Color(theme.palette().danger)), + text_color: Default::default(), + border: Default::default(), + shadow: Default::default(), + snap: false, }), - text!("Не получилось: {}%", unknown / 10.0), - tooltip::Position::Bottom - ), - tooltip( + text!("Не получилось: {}% ({})", unknown / 10.0, exam.unknown), + tooltip::Position::Bottom, + )); + } + if remaining > 0.0 { + row = row.push(tooltip( container(space()) .height(Fill) .width(FillPortion(remaining as u16)) - .style(|theme: &Theme| { - container::Style { - background: Some(Background::Color(theme.palette().primary)), - text_color: Default::default(), - border: Default::default(), - shadow: Default::default(), - snap: false, - } + .style(|theme: &Theme| container::Style { + background: Some(Background::Color(theme.palette().primary)), + text_color: Default::default(), + border: Default::default(), + shadow: Default::default(), + snap: false, }), - text!("Осталось {}%", remaining / 10.0), - tooltip::Position::Bottom - ) - ] - .width(Fill) - .height(Fill) - .into() + text!("Осталось {}% ({})", remaining / 10.0, exam.remaining()), + tooltip::Position::Bottom, + )); + } + + row.width(Fill).height(Fill).into() } fn exam_variable_view(&self, exam: &ExamExtended) -> Element<'_, ExamsMessage> { @@ -294,7 +287,12 @@ impl ExamsState { } fn exam_ongoing_view(&self, exam: &ExamExtended) -> Element<'_, ExamsMessage> { - center_x(button("Продолжить экзамен").on_press(GotoExam)).into() + center_x( + button("Продолжить экзамен") + .style(cta_button) + .on_press(GotoExam), + ) + .into() } } @@ -311,19 +309,23 @@ impl ExamExtended { let mut total = 0; let mut answered = 0; let mut unknown = 0; - entries.iter().filter(|e| e.exam_id == e.id).for_each(|e| { - total += 1; - match e.status { - None => {} - Some(s) => { - if s { - answered += 1; - } else { - unknown += 1; + entries + .iter() + .filter(|e| e.exam_id == exam.id) + .for_each(|e| { + total += 1; + match e.status { + None => {} + Some(s) => { + if s { + answered += 1; + } else { + unknown += 1; + } } } - } - }); + }); + Self { exam,