Basic exams page ready

This commit is contained in:
micialware committed 2026-10-03 15:12:09 +03:00
1 parent 79c42d0feb
commit 65991f742e
3 files changed
+69 -66

No files matched your search

+1
View File
@@ -12,3 +12,4 @@ pub mod sync;
pub mod word; pub mod word;
pub mod writing; pub mod writing;
pub mod exams; pub mod exams;
pub mod exam;
View File
Whitespace-only changes.
+68 -66
View File
@@ -8,13 +8,12 @@ use crate::notification::MaybeError;
use crate::pages::exams::ExamsMessage::*; use crate::pages::exams::ExamsMessage::*;
use crate::pages::repetitions::Style; use crate::pages::repetitions::Style;
use crate::push_error; 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 crate::{jl_button, push_error_task};
use chrono::Utc; use chrono::Utc;
use iced::widget::button::Status; use iced::widget::button::Status;
use iced::widget::{ use iced::widget::rule::horizontal;
button, center_x, column, container, row, scrollable, space, text, tooltip, Column, use iced::widget::{button, center_x, column, container, row, rule, scrollable, space, text, tooltip, Column};
};
use iced::{Element, Task}; use iced::{Element, Task};
use iced_core::Alignment::*; use iced_core::Alignment::*;
use iced_core::Length::{Fill, FillPortion}; use iced_core::Length::{Fill, FillPortion};
@@ -35,7 +34,6 @@ pub struct ExamsState {
pub enum ExamsMessage { pub enum ExamsMessage {
Back, Back,
SelectExam(EntityHandle<Exam>), SelectExam(EntityHandle<Exam>),
DeleteExam(EntityHandle<Exam>),
CreateExam, CreateExam,
GotoExam, GotoExam,
} }
@@ -62,9 +60,6 @@ impl NavigatedPage<ExamsMessage> for ExamsState {
SelectExam(id) => { SelectExam(id) => {
self.selected_exam_id = Some(id); self.selected_exam_id = Some(id);
} }
DeleteExam(id) => {
self.selected_exam_id = None;
}
CreateExam => { CreateExam => {
let exam = Exam { let exam = Exam {
id: Default::default(), id: Default::default(),
@@ -125,9 +120,6 @@ impl ExamsState {
fn selected_exam(&self) -> Option<&ExamExtended> { fn selected_exam(&self) -> Option<&ExamExtended> {
self.exams.get(&self.selected_exam_id?) 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<Exam>) -> MaybeError { fn append_exam_entries(&mut self, handle: EntityHandle<Exam>) -> MaybeError {
let deck_id = self.deck_id.id; let deck_id = self.deck_id.id;
@@ -178,7 +170,7 @@ impl ExamsState {
for (handle, deck) in self.exams.iter() { for (handle, deck) in self.exams.iter() {
column = column.push( 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)) .on_press_with(move || SelectExam(*handle))
.style(move |_x: &Theme, status: Status| Style { .style(move |_x: &Theme, status: Status| Style {
background: if status == Status::Hovered { background: if status == Status::Hovered {
@@ -210,7 +202,9 @@ impl ExamsState {
row![text!("{} карточек", exam.total), Self::exam_bar(exam)] row![text!("{} карточек", exam.total), Self::exam_bar(exam)]
.height(30) .height(30)
.align_y(Center) .align_y(Center)
.width(Fill).spacing(HALF_SPACING), .width(Fill)
.spacing(HALF_SPACING),
rule::horizontal(2),
self.exam_variable_view(exam), self.exam_variable_view(exam),
] ]
.spacing(DEFAULT_SPACING) .spacing(DEFAULT_SPACING)
@@ -226,59 +220,58 @@ impl ExamsState {
let answered = exam.answered as f64 / exam.total as f64 * total; let answered = exam.answered as f64 / exam.total as f64 * total;
let unknown = exam.unknown 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; let remaining = exam.remaining() as f64 / exam.total as f64 * total;
row![ println!("{} {} {}", remaining, answered, unknown);
tooltip( let mut row = row![];
if answered > 0.0 {
row = row.push(tooltip(
container(space()) container(space())
.height(Fill) .height(Fill)
.width(FillPortion(answered as u16)) .width(FillPortion(answered as u16))
.style(|theme: &Theme| { .style(|theme: &Theme| container::Style {
container::Style { background: Some(Background::Color(theme.palette().success)),
background: Some(Background::Color(theme.palette().success)), text_color: Default::default(),
text_color: Default::default(), border: Default::default(),
border: Default::default(), shadow: Default::default(),
shadow: Default::default(), snap: false,
snap: false,
}
}), }),
text!("Правильно: {}%", answered / 10.0), text!("Правильно: {}% ({})", answered / 10.0, exam.answered),
tooltip::Position::Bottom tooltip::Position::Bottom,
), ));
tooltip( }
if unknown > 0.0 {
row = row.push(tooltip(
container(space()) container(space())
.height(Fill) .height(Fill)
.width(FillPortion(unknown as u16)) .width(FillPortion(unknown as u16))
.style(|theme: &Theme| { .style(|theme: &Theme| container::Style {
container::Style { background: Some(Background::Color(theme.palette().danger)),
background: Some(Background::Color(theme.palette().danger)), text_color: Default::default(),
text_color: Default::default(), border: Default::default(),
border: Default::default(), shadow: Default::default(),
shadow: Default::default(), snap: false,
snap: false,
}
}), }),
text!("Не получилось: {}%", unknown / 10.0), text!("Не получилось: {}% ({})", unknown / 10.0, exam.unknown),
tooltip::Position::Bottom tooltip::Position::Bottom,
), ));
tooltip( }
if remaining > 0.0 {
row = row.push(tooltip(
container(space()) container(space())
.height(Fill) .height(Fill)
.width(FillPortion(remaining as u16)) .width(FillPortion(remaining as u16))
.style(|theme: &Theme| { .style(|theme: &Theme| container::Style {
container::Style { background: Some(Background::Color(theme.palette().primary)),
background: Some(Background::Color(theme.palette().primary)), text_color: Default::default(),
text_color: Default::default(), border: Default::default(),
border: Default::default(), shadow: Default::default(),
shadow: Default::default(), snap: false,
snap: false,
}
}), }),
text!("Осталось {}%", remaining / 10.0), text!("Осталось {}% ({})", remaining / 10.0, exam.remaining()),
tooltip::Position::Bottom tooltip::Position::Bottom,
) ));
] }
.width(Fill)
.height(Fill) row.width(Fill).height(Fill).into()
.into()
} }
fn exam_variable_view(&self, exam: &ExamExtended) -> Element<'_, ExamsMessage> { fn exam_variable_view(&self, exam: &ExamExtended) -> Element<'_, ExamsMessage> {
@@ -294,7 +287,12 @@ impl ExamsState {
} }
fn exam_ongoing_view(&self, exam: &ExamExtended) -> Element<'_, ExamsMessage> { 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 total = 0;
let mut answered = 0; let mut answered = 0;
let mut unknown = 0; let mut unknown = 0;
entries.iter().filter(|e| e.exam_id == e.id).for_each(|e| { entries
total += 1; .iter()
match e.status { .filter(|e| e.exam_id == exam.id)
None => {} .for_each(|e| {
Some(s) => { total += 1;
if s { match e.status {
answered += 1; None => {}
} else { Some(s) => {
unknown += 1; if s {
answered += 1;
} else {
unknown += 1;
}
} }
} }
} });
});
Self { Self {
exam, exam,