More data on exams page
This commit is contained in:
1 parent
7ad44110c3
commit
496f246125
1 file changed
+104
-26
+104
-26
@@ -1,6 +1,6 @@
|
||||
use crate::app::AppState;
|
||||
use crate::data::Id;
|
||||
use crate::data::entities::{DeckSettings, EntityHandle, Exam, ExamEntry};
|
||||
use crate::data::entities::{DeckSettings, EntityHandle, Exam, ExamEntry, WordData};
|
||||
use crate::data::repositories::{BatchedRepository, Repository};
|
||||
use crate::navigation::Page::PreviousPage;
|
||||
use crate::navigation::{NavigatedPage, Page, RootMessage};
|
||||
@@ -9,11 +9,18 @@ use crate::pages::exam::ExamState;
|
||||
use crate::pages::exams::ExamsMessage::*;
|
||||
use crate::pages::repetitions::Style;
|
||||
use crate::push_error;
|
||||
use crate::styling::{BUTTON_RADIUS, DEFAULT_SPACING, HALF_SPACING, back_overlay, cta_button};
|
||||
use crate::styling::{
|
||||
BUTTON_RADIUS, DEFAULT_SPACING, HALF_SPACING, QUARTER_SPACING, back_overlay, cta_button,
|
||||
};
|
||||
use crate::{jl_button, push_error_task};
|
||||
use chrono::{Local, Utc};
|
||||
use iced::widget::button::Status;
|
||||
use iced::widget::{Column, button, center_x, column, container, row, rule, scrollable, space, text, tooltip};
|
||||
use iced::widget::container::bordered_box;
|
||||
use iced::widget::space::horizontal;
|
||||
use iced::widget::{
|
||||
Column, button, center, center_x, column, container, row, rule, scrollable, space, text,
|
||||
tooltip,
|
||||
};
|
||||
use iced::{Element, Task};
|
||||
use iced_core::Alignment::*;
|
||||
use iced_core::Length::{Fill, FillPortion};
|
||||
@@ -46,7 +53,11 @@ impl NavigatedPage<ExamsMessage> for ExamsState {
|
||||
if let Some(selected_exam_id) = self.selected_exam_id
|
||||
&& GotoExam == *message
|
||||
{
|
||||
return Some(Page::Exam(ExamState::new(selected_exam_id.id, self.deck.clone(), &self.state)));
|
||||
return Some(Page::Exam(ExamState::new(
|
||||
selected_exam_id.id,
|
||||
self.deck.clone(),
|
||||
&self.state,
|
||||
)));
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -90,7 +101,7 @@ impl NavigatedPage<ExamsMessage> for ExamsState {
|
||||
back_overlay(
|
||||
column![
|
||||
text(format!("Экзамены для колоды {}", self.deck.name)),
|
||||
row![row![
|
||||
row![
|
||||
column![
|
||||
scrollable(self.exams_list()).height(Fill),
|
||||
jl_button!("Добавить").width(Fill).on_press(CreateExam),
|
||||
@@ -98,7 +109,7 @@ impl NavigatedPage<ExamsMessage> for ExamsState {
|
||||
.spacing(DEFAULT_SPACING)
|
||||
.width(FillPortion(1)),
|
||||
self.selected_exam_view(),
|
||||
]]
|
||||
].spacing(DEFAULT_SPACING)
|
||||
]
|
||||
.into(),
|
||||
Back,
|
||||
@@ -172,23 +183,33 @@ impl ExamsState {
|
||||
|
||||
for (handle, deck) in self.exams.iter() {
|
||||
column = column.push(
|
||||
jl_button!(text!("{}", &deck.timestamp.with_timezone(&Local).format("%d/%m/%Y %H:%M")))
|
||||
.on_press_with(move || SelectExam(*handle))
|
||||
.style(move |_x: &Theme, status: Status| Style {
|
||||
background: if status == Status::Hovered {
|
||||
Some(Background::Color(Color::WHITE.scale_alpha(0.2)))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
text_color: if deck.finished() { _x.palette().success } else { _x.palette().primary},
|
||||
border: Border {
|
||||
color: Default::default(),
|
||||
width: 0.0,
|
||||
radius: BUTTON_RADIUS.into(),
|
||||
},
|
||||
shadow: Shadow::default(),
|
||||
snap: false,
|
||||
}),
|
||||
jl_button!(text!(
|
||||
"{}",
|
||||
&deck
|
||||
.timestamp
|
||||
.with_timezone(&Local)
|
||||
.format("%d/%m/%Y %H:%M")
|
||||
))
|
||||
.on_press_with(move || SelectExam(*handle))
|
||||
.style(move |_x: &Theme, status: Status| Style {
|
||||
background: if status == Status::Hovered {
|
||||
Some(Background::Color(Color::WHITE.scale_alpha(0.2)))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
text_color: if deck.finished() {
|
||||
_x.palette().success
|
||||
} else {
|
||||
_x.palette().primary
|
||||
},
|
||||
border: Border {
|
||||
color: Default::default(),
|
||||
width: 0.0,
|
||||
radius: BUTTON_RADIUS.into(),
|
||||
},
|
||||
shadow: Shadow::default(),
|
||||
snap: false,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -199,7 +220,9 @@ impl ExamsState {
|
||||
return column![
|
||||
center_x(text!(
|
||||
"Экзамен от {}",
|
||||
exam.timestamp.with_timezone(&Local).format("%d/%m/%Y %H:%M")
|
||||
exam.timestamp
|
||||
.with_timezone(&Local)
|
||||
.format("%d/%m/%Y %H:%M")
|
||||
)),
|
||||
row![text!("{} карточек", exam.total), Self::exam_bar(exam)]
|
||||
.height(30)
|
||||
@@ -284,7 +307,35 @@ impl ExamsState {
|
||||
}
|
||||
|
||||
fn exam_finished_view(&self, exam: &ExamExtended) -> Element<'_, ExamsMessage> {
|
||||
column![].spacing(DEFAULT_SPACING).into()
|
||||
let result = (exam.answered as f64 / exam.total as f64 * 1000.0).round() / 10.0;
|
||||
let words_repo = self.state.dictionary.read();
|
||||
column![
|
||||
center_x(text!("Итоговый результат: {}%", result).size(28)),
|
||||
row![
|
||||
Self::words_list(
|
||||
"Правильно",
|
||||
exam.answered_list
|
||||
.iter()
|
||||
.map(|handle| words_repo.get_ref_static(*handle).unwrap())
|
||||
.collect::<Vec<_>>()
|
||||
.as_slice()
|
||||
)
|
||||
.width(Fill),
|
||||
Self::words_list(
|
||||
"Не получилось",
|
||||
exam.unknows_list
|
||||
.iter()
|
||||
.map(|handle| words_repo.get_ref_static(*handle).unwrap())
|
||||
.collect::<Vec<_>>()
|
||||
.as_slice()
|
||||
)
|
||||
.width(Fill)
|
||||
]
|
||||
.width(Fill)
|
||||
.spacing(QUARTER_SPACING)
|
||||
]
|
||||
.spacing(DEFAULT_SPACING)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn exam_ongoing_view(&self, exam: &ExamExtended) -> Element<'_, ExamsMessage> {
|
||||
@@ -295,6 +346,26 @@ impl ExamsState {
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn words_list<'a>(name: &str, words: &[&WordData]) -> Column<'a, ExamsMessage> {
|
||||
let mut column = column![];
|
||||
for word in words {
|
||||
let container = container(
|
||||
column![text!("{}", word.key), text!("{}", word.value)].padding(QUARTER_SPACING),
|
||||
)
|
||||
.width(Fill)
|
||||
.style(bordered_box);
|
||||
column = column.push(container);
|
||||
}
|
||||
column![
|
||||
text!("{}", name),
|
||||
scrollable(row![
|
||||
column.spacing(QUARTER_SPACING),
|
||||
horizontal().width(DEFAULT_SPACING)
|
||||
])
|
||||
]
|
||||
.align_x(Center)
|
||||
}
|
||||
}
|
||||
|
||||
struct ExamExtended {
|
||||
@@ -302,6 +373,8 @@ struct ExamExtended {
|
||||
total: u32,
|
||||
answered: u32,
|
||||
unknown: u32,
|
||||
answered_list: Vec<EntityHandle<WordData>>,
|
||||
unknows_list: Vec<EntityHandle<WordData>>,
|
||||
}
|
||||
|
||||
impl ExamExtended {
|
||||
@@ -310,6 +383,8 @@ impl ExamExtended {
|
||||
let mut total = 0;
|
||||
let mut answered = 0;
|
||||
let mut unknown = 0;
|
||||
let mut answered_list = Vec::with_capacity(128);
|
||||
let mut unknows_list = Vec::with_capacity(128);
|
||||
entries
|
||||
.iter()
|
||||
.filter(|e| e.exam_id == exam.id)
|
||||
@@ -320,8 +395,10 @@ impl ExamExtended {
|
||||
Some(s) => {
|
||||
if s {
|
||||
answered += 1;
|
||||
answered_list.push(EntityHandle::from_id(e.word_id));
|
||||
} else {
|
||||
unknown += 1;
|
||||
unknows_list.push(EntityHandle::from_id(e.word_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,10 +406,11 @@ impl ExamExtended {
|
||||
|
||||
Self {
|
||||
exam,
|
||||
|
||||
total,
|
||||
answered,
|
||||
unknown,
|
||||
answered_list,
|
||||
unknows_list,
|
||||
}
|
||||
}
|
||||
fn solved(&self) -> u32 {
|
||||
|
||||
Reference in new issue
Block a user