BreweryControlSystem/code/src/app.rs

1311 lines
53 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

use std::{collections::HashMap, ops::Deref, sync::Arc};
use crate::{
database::DBOperator,
models::{
Equipment, Material, MaterialCategory, MaterialRow, ModalStatus, ModalWinState, Position,
Worker,
},
};
use egui::{TextBuffer, mutex::RwLock};
use egui_dock::{DockArea, Style, TabViewer};
use egui_extras::{Column, TableBuilder};
use sqlx::types::BigDecimal;
static TABS_CAN_BE_WINDOWS: bool = false;
enum TabTypes {
Equipment,
Worker,
Position,
Salary,
Material,
Recipe,
Product,
Order,
Settings,
WorkerList,
WorkerPosition,
MaterialList,
MaterialTypeList,
RecipeList,
RecipeDetail,
ProductList,
}
struct Tab {
tab_type: TabTypes,
title: String,
}
pub struct App {
pub tree: egui_dock::DockState<Tab>,
pub main_viewer: MainTabViewer,
}
impl Default for App {
fn default() -> Self {
let tree = egui_dock::DockState::new(vec![
Tab {
tab_type: TabTypes::Equipment,
title: "Оборудование".to_owned(),
},
Tab {
tab_type: TabTypes::Material,
title: "Сырьё".to_owned(),
},
Tab {
tab_type: TabTypes::Worker,
title: "Сотрудники".to_owned(),
},
Tab {
tab_type: TabTypes::Salary,
title: "Выплаты".to_owned(),
},
Tab {
tab_type: TabTypes::Recipe,
title: "Рецепты".to_owned(),
},
Tab {
tab_type: TabTypes::Product,
title: "Продукция".to_owned(),
},
Tab {
tab_type: TabTypes::Settings,
title: "Настройки".to_owned(),
},
]);
let main_viewer = MainTabViewer::default();
Self { tree, main_viewer }
}
}
impl App {
pub fn new(_cc: &eframe::CreationContext<'_>) -> Self {
Default::default()
}
}
impl eframe::App for App {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
DockArea::new(&mut self.tree)
.style(Style::from_egui(ui.style().as_ref()))
.show_inside(ui, &mut self.main_viewer);
}
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
if self.main_viewer.is_dark_theme {
ctx.set_visuals(egui::Visuals::dark());
} else {
ctx.set_visuals(egui::Visuals::light());
}
ctx.set_zoom_factor(self.main_viewer.interface_scale_ratio);
}
}
struct MainTabViewer {
positions: Arc<RwLock<Option<Vec<Position>>>>,
workers: Arc<RwLock<Option<Vec<Worker>>>>,
equipment: Arc<RwLock<Option<Vec<Equipment>>>>,
db_oper: DBOperator,
worker_tabs: WorkerTabViewer,
worker_tree: egui_dock::DockState<Tab>,
material_tabs: MaterialTabViewer,
material_tree: egui_dock::DockState<Tab>,
rt: tokio::runtime::Runtime,
is_dark_theme: bool,
interface_scale_ratio: f32,
}
impl Default for MainTabViewer {
fn default() -> Self {
let rt = tokio::runtime::Runtime::new().unwrap();
let db_oper = rt.block_on(async { DBOperator::new().await });
Self {
positions: Arc::new(RwLock::new(Option::Some(
rt.block_on(async { db_oper.get_position().await.unwrap() }),
))),
workers: Arc::new(RwLock::new(Option::Some(
rt.block_on(async { db_oper.get_workers().await.unwrap() }),
))),
equipment: Arc::new(RwLock::new(Option::Some(
rt.block_on(async { db_oper.get_equipment().await.unwrap() }),
))),
db_oper,
worker_tabs: WorkerTabViewer::default(),
worker_tree: egui_dock::DockState::new(vec![
Tab {
title: "Работники".to_owned(),
tab_type: TabTypes::WorkerList,
},
Tab {
title: "Должности".to_owned(),
tab_type: TabTypes::WorkerPosition,
},
]),
material_tabs: MaterialTabViewer::default(),
material_tree: egui_dock::DockState::new(vec![
Tab {
title: "Сырьё".to_owned(),
tab_type: TabTypes::MaterialList,
},
Tab {
title: "Тип".to_owned(),
tab_type: TabTypes::MaterialTypeList,
},
]),
rt,
is_dark_theme: true,
interface_scale_ratio: 1.2,
}
}
}
impl MainTabViewer {
fn show_equipment(&mut self, ui: &mut egui::Ui) {
let mut table = TableBuilder::new(ui)
.striped(true)
.resizable(false)
.cell_layout(egui::Layout::left_to_right(egui::Align::Center))
.column(Column::auto())
.column(Column::auto())
.column(Column::auto())
.column(Column::auto())
.column(Column::auto())
.header(30.0, |mut header| {
header.col(|ui| {
ui.heading("ID");
});
header.col(|ui| {
ui.heading("Название");
});
header.col(|ui| {
ui.heading("Инв. номер");
});
header.col(|ui| {
ui.heading("Ответственный");
});
header.col(|ui| {
ui.heading("Дата последнего\nя техобслуживания");
});
})
.body(|mut body| {
for eq in self.equipment.read().clone().unwrap().iter() {
body.row(20.0, |mut row| {
row.col(|ui| {
ui.label(eq.id.to_string());
});
row.col(|ui| {
ui.label(&eq.name);
});
row.col(|ui| {
ui.label(&eq.inv_number);
});
row.col(|ui| {
ui.label(&eq.worker.full_name);
});
row.col(|ui| {
ui.label(eq.maintenance_date.date_naive().to_string());
});
});
}
});
}
fn show_worker(&mut self, ui: &mut egui::Ui) {
let id = ui.make_persistent_id("WorkerMenu");
DockArea::new(&mut self.worker_tree)
.style(Style::from_egui(ui.style().as_ref()))
.id(id)
.show_inside(ui, &mut self.worker_tabs);
}
fn show_material(&mut self, ui: &mut egui::Ui) {
let id = ui.make_persistent_id("MaterialMenu");
DockArea::new(&mut self.material_tree)
.id(id)
.show_inside(ui, &mut self.material_tabs);
}
fn show_salary(&mut self, ui: &mut egui::Ui) {
ui.label("Помогите");
}
fn show_settings(&mut self, ui: &mut egui::Ui) {
ui.checkbox(&mut self.is_dark_theme, "Тёмная тема");
ui.add(
egui::Slider::new(&mut self.interface_scale_ratio, 1.0..=2.0)
.text("Масштаб интерфейса"),
);
if ui.button("Сбросить Масштаб интерфейса").clicked() {
self.interface_scale_ratio = 1.2;
}
}
}
impl egui_dock::TabViewer for MainTabViewer {
type Tab = Tab;
fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText {
(&*tab.title).into()
}
fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) {
match &tab.tab_type {
TabTypes::Equipment => {
&self.show_equipment(ui);
}
TabTypes::Worker => {
&self.show_worker(ui);
}
TabTypes::Salary => {
&self.show_salary(ui);
}
TabTypes::Material => {
&self.show_material(ui);
}
TabTypes::Settings => {
&self.show_settings(ui);
}
_ => {
ui.label("This is not");
}
}
}
fn allowed_in_windows(&self, _tab: &mut Self::Tab) -> bool {
TABS_CAN_BE_WINDOWS
}
fn is_closeable(&self, _tab: &Self::Tab) -> bool {
false
}
fn id(&mut self, tab: &mut Self::Tab) -> egui::Id {
egui::Id::new(&tab.title)
}
}
struct WorkerTabViewer {
db_oper: DBOperator,
workers: Arc<RwLock<Option<Vec<Worker>>>>,
positions: Arc<RwLock<Option<Vec<Position>>>>,
show_worker_add_modal: bool,
show_worker_edit_modal: bool,
show_position_add_modal: bool,
fire_worker_id: String,
add_worker_name: String,
add_worker_hire_date: String,
add_worker_position: Position,
can_add_worker: bool,
can_edit_worker: bool,
add_position_name: String,
add_position_wage: String,
edit_worker_id: i32,
edit_worker_name: String,
edit_worker_hire_date: String,
edit_worker_is_fired: bool,
edit_worker_position: Position,
rt: tokio::runtime::Runtime,
show_position_delete_modal: bool,
delete_position: Position,
}
impl WorkerTabViewer {
fn update_workers(&mut self) {
self.workers = Arc::new(RwLock::new(Option::Some(
self.rt
.block_on(async { self.db_oper.get_workers().await.unwrap() }),
)));
}
fn update_positions(&mut self) {
self.positions = Arc::new(RwLock::new(Option::Some(
self.rt
.block_on(async { self.db_oper.get_position().await.unwrap() }),
)));
}
fn show_worker(&mut self, ui: &mut egui::Ui) {
ui.horizontal(|ui| {
if ui.button("Добавить").clicked() {
self.show_worker_add_modal = true;
self.add_worker_name = String::new();
self.add_worker_position = Position::default();
};
if ui.button("Редактировать").clicked() {
self.show_worker_edit_modal = true;
self.rt.block_on(async {
let wrkr = match self.db_oper.get_worker_by_id(self.edit_worker_id).await {
Ok(worker) => worker,
Err(_) => Worker::default(),
};
self.edit_worker_name = wrkr.full_name;
self.edit_worker_hire_date = wrkr.hire_date.format("%Y-%m-%d").to_string();
self.edit_worker_position = wrkr.position;
self.edit_worker_is_fired = wrkr.is_fired;
});
}
if ui.button("Обновить").clicked() {
self.update_workers();
}
});
if self.show_worker_add_modal {
egui::Modal::new("add_worker".into()).show(ui.ctx(), |ui| {
if ui.button("Закрыть").clicked() {
self.show_worker_add_modal = false;
}
ui.horizontal(|ui| {
ui.vertical(|ui| {
ui.label("Имя сотрудника:");
ui.label("Дата найма:");
ui.label("Должность:");
});
ui.vertical(|ui| {
ui.add(
egui::TextEdit::singleline(&mut self.add_worker_name)
.hint_text("Напр: Иванов Иван"),
);
ui.add(
egui::TextEdit::singleline(&mut self.add_worker_hire_date)
.hint_text("Напр: 12-02-2010"),
);
egui::ComboBox::from_label("Выбрать!")
.selected_text(format!("{}", self.add_worker_position.name))
.show_ui(ui, |ui| {
self.rt.block_on(async {
for pos in self.db_oper.get_position().await.unwrap().iter() {
ui.selectable_value(
&mut self.add_worker_position,
pos.clone(),
&pos.name,
);
}
});
});
});
});
if chrono::NaiveDate::parse_from_str(&self.add_worker_hire_date, "%d-%m-%Y")
.is_err()
{
ui.label(egui::RichText::new("ДАТА УКАЗАНА НЕВЕРНО").color(egui::Color32::RED));
self.can_add_worker = false;
} else {
self.can_add_worker = true;
}
ui.vertical_centered(|ui| {
let resp = ui.add_enabled(self.can_add_worker, egui::Button::new("Добавить"));
if resp.clicked() {
self.rt.block_on(async {
let ndate = chrono::NaiveDate::parse_from_str(
&self.add_worker_hire_date,
"%d-%m-%Y",
)
.unwrap();
self.db_oper
.add_worker(Worker {
id: 0,
full_name: self.add_worker_name.clone(),
hire_date: ndate
.and_hms_opt(0, 0, 0)
.unwrap()
.and_local_timezone(chrono::Local)
.unwrap(),
position: self.add_worker_position.clone(),
is_fired: false,
})
.await
.ok();
self.show_worker_add_modal = false;
});
self.update_workers();
}
});
});
}
if self.show_worker_edit_modal {
egui::Modal::new("edit_worker".into()).show(ui.ctx(), |ui| {
if ui.button("Закрыть").clicked() {
self.show_worker_edit_modal = false;
}
let mut size = ui.spacing().interact_size;
size.x = 200.0;
egui::Grid::new("edit_worker_grid").show(ui, |ui| {
ui.label("ID");
let old = self.edit_worker_id.clone();
egui::ComboBox::from_id_salt("edit_worker_id")
.selected_text(format!("#{:08}", &self.edit_worker_id))
.show_ui(ui, |ui| {
self.rt.block_on(async {
for worker in self.db_oper.get_workers().await.unwrap().iter() {
ui.selectable_value(
&mut self.edit_worker_id,
worker.id,
format!("#{:08} | {}", worker.id, worker.full_name),
);
}
});
});
if self.edit_worker_id != old {
self.rt.block_on(async {
let wrkr =
match self.db_oper.get_worker_by_id(self.edit_worker_id).await {
Ok(worker) => worker,
Err(_) => Worker::default(),
};
self.edit_worker_name = wrkr.full_name;
self.edit_worker_hire_date =
wrkr.hire_date.format("%Y-%m-%d").to_string();
self.edit_worker_position = wrkr.position;
self.edit_worker_is_fired = wrkr.is_fired;
});
}
ui.end_row();
ui.label("Имя");
ui.add_sized(size, |ui: &mut egui::Ui| {
ui.text_edit_singleline(&mut self.edit_worker_name)
});
ui.end_row();
ui.label("Должность");
egui::ComboBox::from_id_salt("edit_worker_pos")
.selected_text(&self.edit_worker_position.name)
.show_ui(ui, |ui| {
self.rt.block_on(async {
for pos in self.db_oper.get_position().await.unwrap().iter() {
ui.selectable_value(
&mut self.edit_worker_position,
pos.clone(),
&pos.name,
);
}
});
});
ui.end_row();
ui.label("Дата найма");
ui.text_edit_singleline(&mut self.edit_worker_hire_date);
ui.end_row();
ui.checkbox(&mut self.edit_worker_is_fired, "Уволен");
ui.end_row();
});
if chrono::NaiveDate::parse_from_str(&self.edit_worker_hire_date, "%Y-%m-%d")
.is_ok()
&& self.edit_worker_name.len() > 0
{
self.can_edit_worker = true;
} else {
self.can_edit_worker = false;
}
let resp = ui.add_enabled(self.can_edit_worker, egui::Button::new("Добавить"));
if resp.clicked() {
self.rt.block_on(async {
let ndate = chrono::NaiveDate::parse_from_str(
&self.edit_worker_hire_date,
"%Y-%m-%d",
)
.unwrap();
self.db_oper
.update_worker(Worker {
id: self.edit_worker_id,
full_name: self.edit_worker_name.clone(),
hire_date: ndate
.and_hms_opt(0, 0, 0)
.unwrap()
.and_local_timezone(chrono::Local)
.unwrap(),
position: self.edit_worker_position.clone(),
is_fired: self.edit_worker_is_fired,
})
.await
.unwrap();
});
self.update_workers();
self.show_worker_edit_modal = false;
}
});
}
for wk in self.workers.read().clone().unwrap().iter() {
ui.push_id(format!("{}:{}", &wk.full_name, &wk.id), |ui| {
egui::CollapsingHeader::new(format!("#{:08} | {}", &wk.id, &wk.full_name))
.default_open(false)
.show(ui, |ui| {
ui.horizontal(|ui| {
ui.label("Нанят: ");
ui.label(format!(
"{}",
wk.hire_date.date_naive().format("%d-%m-%Y").to_string()
));
});
ui.horizontal(|ui| {
ui.label("Должность: ");
ui.label(&wk.position.name);
});
ui.horizontal(|ui| {
ui.label("Уволен: ");
ui.label(if wk.is_fired { "Да" } else { "Нет" })
})
})
});
}
}
fn show_position(&mut self, ui: &mut egui::Ui) {
ui.horizontal(|ui| {
if ui.button("Добавить").clicked() {
self.show_position_add_modal = true;
}
if ui.button("Удалить").clicked() {
self.show_position_delete_modal = true;
self.delete_position = self.positions.read().clone().unwrap()[0].clone();
self.update_positions();
self.update_workers();
}
if ui.button("Обновить").clicked() {
self.update_positions();
}
});
for eq in self.positions.read().clone().unwrap().iter() {
ui.push_id(&eq.name, |ui| {
egui::CollapsingHeader::new(&eq.name)
.default_open(false)
.show(ui, |ui| {
ui.horizontal(|ui| {
ui.monospace("Оклад:");
ui.label(format!("${}", eq.wage));
});
})
});
}
if self.show_position_add_modal {
egui::Modal::new("add_position".into()).show(ui.ctx(), |ui| {
if ui.button("Закрыть").clicked() {
self.show_position_add_modal = false;
}
let mut size = ui.spacing().interact_size;
size.x = 200.0;
egui::Grid::new("add_pos_grid").show(ui, |ui| {
ui.label("Название");
ui.add_sized(size, |ui: &mut egui::Ui| {
ui.text_edit_singleline(&mut self.add_position_name)
});
ui.end_row();
ui.label("Оклад");
ui.text_edit_singleline(&mut self.add_position_wage);
ui.end_row();
});
let resp = ui.add_enabled(
self.add_position_name.len() > 0 && self.add_position_wage.len() > 0,
egui::Button::new("Добавить"),
);
if resp.clicked() {
self.rt.block_on(async {
self.db_oper
.add_position(Position {
id: 0,
name: self.add_position_name.clone(),
wage: BigDecimal::from(
self.add_position_wage.trim().parse::<i32>().unwrap(),
),
})
.await
.ok();
});
self.update_positions();
self.show_position_add_modal = false;
}
});
}
if self.show_position_delete_modal {
egui::Modal::new("delete_position".into()).show(ui.ctx(), |ui| {
if ui.button("Закрыть").clicked() {
self.show_position_delete_modal = false;
}
egui::ComboBox::from_label("Должность")
.selected_text(&self.delete_position.name)
.show_ui(ui, |ui| {
self.rt.block_on(async {
for pos in self.positions.read().clone().unwrap().iter() {
ui.selectable_value(
&mut self.delete_position,
pos.clone(),
&pos.name,
);
}
});
});
let can_delete = self
.workers
.read()
.clone()
.unwrap()
.iter()
.find(|wrkr| wrkr.position.id == self.delete_position.id)
.iter()
.len()
== 0;
if !can_delete {
ui.label(
egui::RichText::new("Есть сотрудники с этой должностью")
.color(egui::Color32::YELLOW),
);
}
let resp = ui.add_enabled(can_delete, egui::Button::new("Удалить"));
if resp.clicked() {
self.rt.block_on(async {
self.db_oper
.delete_position(self.delete_position.clone())
.await
.unwrap();
});
}
});
}
}
}
impl egui_dock::TabViewer for WorkerTabViewer {
type Tab = Tab;
fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText {
(&*tab.title).into()
}
fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) {
match &tab.tab_type {
TabTypes::WorkerList => self.show_worker(ui),
TabTypes::WorkerPosition => self.show_position(ui),
_ => {
ui.label("Nope");
}
}
}
fn id(&mut self, tab: &mut Self::Tab) -> egui::Id {
egui::Id::new(&tab.title)
}
fn allowed_in_windows(&self, _tab: &mut Self::Tab) -> bool {
TABS_CAN_BE_WINDOWS
}
fn is_closeable(&self, _tab: &Self::Tab) -> bool {
false
}
}
impl Default for WorkerTabViewer {
fn default() -> Self {
let rt = tokio::runtime::Runtime::new().unwrap();
let db_oper = rt.block_on(async { DBOperator::new().await });
Self {
workers: Arc::new(RwLock::new(Option::Some(
rt.block_on(async { db_oper.get_workers().await.unwrap() }),
))),
positions: Arc::new(RwLock::new(Option::Some(
rt.block_on(async { db_oper.get_position().await.unwrap() }),
))),
show_worker_add_modal: false,
show_worker_edit_modal: false,
show_position_add_modal: false,
show_position_delete_modal: false,
fire_worker_id: String::new(),
add_worker_name: String::new(),
add_worker_position: Position::default(),
add_worker_hire_date: String::new(),
can_add_worker: false,
can_edit_worker: false,
add_position_name: String::new(),
add_position_wage: String::new(),
delete_position: Position::default(),
edit_worker_id: 1,
edit_worker_name: String::new(),
edit_worker_hire_date: String::new(),
edit_worker_position: Position::default(),
edit_worker_is_fired: false,
db_oper,
rt,
}
}
}
struct MaterialTabViewer {
db_oper: DBOperator,
rt: tokio::runtime::Runtime,
process_mcat_state: ModalWinState,
process_material_state: ModalWinState,
mat_cats: Arc<RwLock<Vec<MaterialCategory>>>,
mats: Arc<RwLock<Vec<Material>>>,
}
impl MaterialTabViewer {
fn update_material_category(&mut self) {
self.mat_cats = Arc::new(RwLock::new(
self.rt
.block_on(async { self.db_oper.get_mcat().await.unwrap() }),
));
}
fn update_materials(&mut self) {
self.mats = Arc::new(RwLock::new(
self.rt
.block_on(async { self.db_oper.get_materials().await.unwrap() }),
));
}
fn show_material(&mut self, ui: &mut egui::Ui) {
ui.horizontal(|ui| {
if ui.button("Добавить").clicked() {
self.process_material_state.is_open = true;
self.process_material_state.status = ModalStatus::Add;
}
if ui.button("Редактировать").clicked() {
self.process_material_state.is_open = true;
self.process_material_state.status = ModalStatus::Edit;
}
if ui.button("Удалить").clicked() {
self.process_material_state.is_open = true;
self.process_material_state.status = ModalStatus::Remove;
}
if ui.button("Обновить").clicked() {
self.update_materials();
}
});
TableBuilder::new(ui)
.striped(true)
.cell_layout(egui::Layout::centered_and_justified(
egui::Direction::LeftToRight,
))
.vscroll(true)
.column(Column::auto())
.column(Column::auto())
.column(Column::auto())
.column(Column::auto())
.header(20.0, |mut header| {
header.col(|ui| {
ui.heading("ID");
});
header.col(|ui| {
ui.heading("Название");
});
header.col(|ui| {
ui.heading("Тип");
});
header.col(|ui| {
ui.heading("Количество");
});
})
.body(|mut body| {
self.rt.block_on(async {
for mat in self.mats.read().clone().iter() {
body.row(30.0, |mut row| {
row.col(|ui| {
ui.label(mat.id.to_string());
});
row.col(|ui| {
ui.label(&mat.name);
});
row.col(|ui| {
ui.label(&mat.category.name);
});
row.col(|ui| {
ui.label(mat.quantity.to_string());
});
});
}
})
});
if self.process_material_state.is_open {
egui::Modal::new("process_material".into()).show(ui.ctx(), |ui| {
if ui.button("Закрыть").clicked() {
self.process_material_state.is_open = false;
}
egui::Grid::new("process_material_grid").show(ui, |ui| {
let old = self.process_material_state.data.get("id").unwrap().clone();
if self.process_material_state.status != ModalStatus::Add {
ui.label("Материал");
let mats = self.mats.read().clone();
let sel_id = self
.process_material_state
.data
.get("id")
.map(|d| d.as_str())
.unwrap_or("");
let cur_name = mats
.iter()
.find(|m| m.id.to_string() == sel_id)
.map(|m| m.name.clone())
.unwrap_or_default();
egui::ComboBox::from_id_salt("process_material_combobox_mat")
.selected_text(cur_name)
.show_ui(ui, |ui| {
for mat in self.mats.read().iter().clone() {
ui.selectable_value(
self.process_material_state.data.get_mut("id").unwrap(),
mat.id.to_string(),
&mat.name,
);
}
let id = self
.process_material_state
.data
.get_mut("id")
.unwrap()
.clone();
if id != old {
self.process_material_state.data.insert(
"name".to_owned(),
mats.iter()
.find(|m| m.id.to_string() == id)
.unwrap()
.name
.clone(),
);
self.process_material_state.data.insert(
"quantity".to_owned(),
mats.iter()
.find(|m| m.id.to_string() == id)
.unwrap()
.quantity
.to_string(),
);
self.process_material_state.data.insert(
"category_id".to_owned(),
mats.iter()
.find(|m| m.id.to_string() == id)
.unwrap()
.category
.id
.to_string(),
);
}
});
ui.end_row();
}
let old = self
.process_material_state
.data
.get("category_id")
.unwrap()
.clone();
if self.process_material_state.status != ModalStatus::Remove {
ui.label("Название");
ui.text_edit_singleline(
self.process_material_state.data.get_mut("name").unwrap(),
);
ui.end_row();
ui.label("Количество");
ui.text_edit_singleline(
self.process_material_state
.data
.get_mut("quantity")
.unwrap(),
);
ui.end_row();
ui.label("Тип");
let mats = self.mat_cats.read().clone();
let sel_id = self
.process_material_state
.data
.get("category_id")
.map(|d| d.as_str())
.unwrap_or_default();
let cur_name = mats
.iter()
.find(|m| m.id.to_string() == sel_id)
.map(|m| m.name.clone())
.unwrap_or_default();
egui::ComboBox::from_id_salt("process_material_combobox_cat")
.selected_text(cur_name)
.show_ui(ui, |ui| {
for mat in self.mat_cats.read().iter() {
ui.selectable_value(
self.process_material_state
.data
.get_mut("category_id")
.unwrap(),
mat.id.to_string(),
&mat.name.clone(),
);
}
});
ui.end_row();
}
});
match self.process_material_state.status {
ModalStatus::Add => {
let resp = ui.add_enabled(
self.process_material_state.data.get("name").unwrap().len() > 0
&& self
.process_material_state
.data
.get("quantity")
.unwrap()
.len()
> 0,
egui::Button::new("Добавить"),
);
if resp.clicked() {
self.rt.block_on(async {
self.db_oper
.add_material(MaterialRow {
id: self
.process_material_state
.data
.get("id")
.unwrap()
.parse::<i32>()
.unwrap(),
name: self
.process_material_state
.data
.get("name")
.unwrap()
.to_string(),
quantity: self
.process_material_state
.data
.get("quantity")
.unwrap()
.parse::<i32>()
.unwrap(),
category_id: self
.process_material_state
.data
.get("category_id")
.unwrap()
.parse::<i32>()
.unwrap(),
})
.await
.unwrap();
});
self.update_materials();
self.process_material_state.is_open = false;
}
}
ModalStatus::Edit => {
if ui.button("Сохранить").clicked() {
self.rt.block_on(async {
self.db_oper
.update_material(MaterialRow {
id: self
.process_material_state
.data
.get("id")
.unwrap()
.parse::<i32>()
.unwrap(),
name: self
.process_material_state
.data
.get("name")
.unwrap()
.to_string(),
quantity: self
.process_material_state
.data
.get("quantity")
.unwrap()
.parse::<i32>()
.unwrap(),
category_id: self
.process_material_state
.data
.get("category_id")
.unwrap()
.parse::<i32>()
.unwrap(),
})
.await
.unwrap();
});
self.update_materials();
self.process_material_state.is_open = false;
}
}
ModalStatus::Remove => {
if ui.button("Удалить").clicked() {
self.rt.block_on(async {
self.db_oper
.delete_material(MaterialRow {
id: self
.process_material_state
.data
.get("id")
.unwrap()
.parse::<i32>()
.unwrap(),
name: "".to_owned(),
quantity: 0,
category_id: 0,
})
.await
.unwrap();
});
self.update_materials();
self.process_material_state.is_open = false;
}
}
}
});
}
}
fn show_material_type(&mut self, ui: &mut egui::Ui) {
ui.horizontal(|ui| {
if ui.button("Добавить").clicked() {
self.process_mcat_state.is_open = true;
self.process_mcat_state.status = ModalStatus::Add;
}
if ui.button("Редактировать").clicked() {
self.process_mcat_state.is_open = true;
self.process_mcat_state.status = ModalStatus::Edit;
}
if ui.button("Удалить").clicked() {
self.process_mcat_state.is_open = true;
self.process_mcat_state.status = ModalStatus::Remove;
}
if ui.button("Обновить").clicked() {
self.update_material_category();
}
});
if self.process_mcat_state.is_open {
egui::Modal::new("process_mcat".into()).show(ui.ctx(), |ui| {
if ui.button("Закрыть").clicked() {
self.process_mcat_state.is_open = false;
}
egui::Grid::new("process_mcat_grid").show(ui, |ui| {
let old = self.process_mcat_state.data.get("id").unwrap().clone();
let iterr = self.mat_cats.read().clone();
let selected_id = self
.process_mcat_state
.data
.get("id")
.map(|s| s.as_str())
.unwrap_or("");
let current_name = iterr
.iter()
.find(|mc| mc.id.to_string() == *selected_id)
.map(|mc| mc.name.as_str())
.unwrap_or("Выбрать");
if self.process_mcat_state.status != ModalStatus::Add {
ui.label("Тип");
egui::ComboBox::new("process_mcat_grid_selector", "Выбрать")
.selected_text(current_name)
.show_ui(ui, |ui| {
self.rt.block_on(async {
for mcat in iterr {
ui.selectable_value(
self.process_mcat_state.data.get_mut("id").unwrap(),
mcat.id.to_string(),
format!("{}|{}", mcat.id, &mcat.name),
);
}
});
});
ui.end_row();
}
let current_id = self.process_mcat_state.data.get("id").unwrap().clone();
if self.process_mcat_state.data.get("id").unwrap() != &old {
self.process_mcat_state.data.insert(
"name".to_owned(),
self.mat_cats
.read()
.iter()
.find(|mc| mc.id.to_string() == current_id)
.unwrap()
.name
.clone(),
);
}
if self.process_mcat_state.status != ModalStatus::Remove {
ui.label("Название");
let mut name = self.process_mcat_state.data.get_mut("name").unwrap();
ui.text_edit_singleline(name);
ui.end_row();
}
match self.process_mcat_state.status {
ModalStatus::Add => {
if ui.button("Добавить").clicked() {
let name =
self.process_mcat_state.data.get("name").unwrap().clone();
self.rt.block_on(async {
self.db_oper
.add_material_category(MaterialCategory { id: 0, name })
.await
.unwrap();
});
self.update_material_category();
self.process_mcat_state.is_open = false;
}
}
ModalStatus::Edit => {
if ui.button("Сохранить").clicked() {
let id = self.process_mcat_state.data.get("id").unwrap().clone();
let name =
self.process_mcat_state.data.get("name").unwrap().clone();
self.rt.block_on(async {
self.db_oper
.update_material_category(MaterialCategory {
id: id.parse::<i32>().unwrap(),
name: name.clone(),
})
.await
.unwrap()
});
println!("{}", &name);
self.update_material_category();
self.process_mcat_state.is_open = false;
}
}
ModalStatus::Remove => {
if ui.button("Удалить").clicked() {
let idd = self.process_mcat_state.data.get("id").unwrap().clone();
self.rt.block_on(async {
self.db_oper
.delete_material_category(MaterialCategory {
id: idd.parse::<i32>().unwrap(),
name: "".to_owned(),
})
.await
.unwrap()
});
self.update_material_category();
self.process_mcat_state.is_open = false;
}
}
}
});
});
}
TableBuilder::new(ui)
.striped(true)
.column(Column::auto())
.column(Column::auto())
.header(20.0, |mut header| {
header.col(|ui| {
ui.heading("ID");
});
header.col(|ui| {
ui.heading("Название");
});
})
.body(|mut body| {
self.rt.block_on(async {
for mcat in self.mat_cats.read().clone().iter() {
body.row(20.0, |mut row| {
row.col(|ui| {
ui.label(mcat.id.to_string());
});
row.col(|ui| {
ui.label(&mcat.name);
});
});
}
});
});
}
}
impl egui_dock::TabViewer for MaterialTabViewer {
type Tab = Tab;
fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText {
(&*tab.title).into()
}
fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) {
match &tab.tab_type {
TabTypes::MaterialList => self.show_material(ui),
TabTypes::MaterialTypeList => self.show_material_type(ui),
_ => {
ui.label("Каким образом?");
}
}
}
fn allowed_in_windows(&self, _tab: &mut Self::Tab) -> bool {
TABS_CAN_BE_WINDOWS
}
fn is_closeable(&self, _tab: &Self::Tab) -> bool {
false
}
}
impl Default for MaterialTabViewer {
fn default() -> Self {
let rt = tokio::runtime::Runtime::new().unwrap();
let db_oper = rt.block_on(async { DBOperator::new().await });
let mat_cats = Arc::new(RwLock::new(
rt.block_on(async { db_oper.get_mcat().await.unwrap() }),
));
let mats = Arc::new(RwLock::new(
rt.block_on(async { db_oper.get_materials().await.unwrap() }),
));
Self {
db_oper,
rt,
process_mcat_state: ModalWinState {
data: HashMap::from([
(
String::from("id"),
mat_cats.clone().read().clone()[0].id.to_string(),
),
(
String::from("name"),
mat_cats.clone().read().clone()[0].name.clone(),
),
]),
status: ModalStatus::Add,
..Default::default()
},
process_material_state: ModalWinState {
data: HashMap::from([
(
"id".to_owned(),
mats.clone().read().clone()[0].id.to_string(),
),
(
"name".to_owned(),
mats.clone().read().clone()[0].name.clone(),
),
(
"quantity".to_owned(),
mats.clone().read().clone()[0].quantity.to_string(),
),
("category_id".to_owned(), "1".to_owned()),
]),
..Default::default()
},
mat_cats,
mats,
}
}
}
struct RecipeTabViewer {}
impl RecipeTabViewer {
fn show_recipe_list(&mut self, ui: &mut egui::Ui) {}
fn show_recipe_detail(&mut self, ui: &mut egui::Ui) {}
}
impl egui_dock::TabViewer for RecipeTabViewer {
type Tab = Tab;
fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText {
tab.title.clone().into()
}
fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) {
match &tab.tab_type {
TabTypes::RecipeList => {
self.show_recipe_list(ui);
}
TabTypes::RecipeDetail => {
self.show_recipe_detail(ui);
}
_ => {
ui.label("Hello!");
}
}
}
}