P3UIUIKP5EB53CPLHJMN6XGJWKUAPZYMOXF5DB6SBRYFPFUFVVAAC
use eframe::egui;
use eframe::egui::mutex::RwLock;
use eframe::egui::vec2;
use eframe::egui::Button;
use eframe::egui::Color32;
use eframe::egui::Label;
use eframe::egui::Link;
use eframe::egui::RichText;
use eframe::egui::ScrollArea;
use eframe::egui::Stroke;
use eframe::egui::TextEdit;
// use eframe::Frame;
use egui_flex::item;
use egui_flex::Flex;
use serde::Deserialize;
use serde::Serialize;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::iter::zip;
use std::sync::Arc;
use std::sync::OnceLock;
use super::activities::activities;
use super::activities::activity_form::act_teachers;
use super::activities::activity_form::filtered_teachers;
// use super::activities::activity_form::filtered_teachers;
use super::activities::activity_form::teachers_ui::set_teachers_filter;
use super::activities::save_activities;
use super::activities::Activity;
use super::limitations::limitations_ui::create_teachers_sched;
use super::limitations::limitations_ui::save_teachers_limitations;
use super::limitations::limitations_ui::teachers_limitations;
use super::limitations::limitations_ui::teachers_scheds;
use super::limitations::limitations_ui::TeacherLimitation;
#[derive(Clone, Serialize, Deserialize)]
pub struct Teacher {
pub id: i32,
pub name: String,
pub short_name: String,
}
pub fn selected_teacher() -> &'static Arc<RwLock<Option<i32>>> {
static SELECTED: OnceLock<Arc<RwLock<Option<i32>>>> = OnceLock::new();
SELECTED.get_or_init(|| Arc::new(RwLock::new(None)))
}
pub fn get_teachers() -> &'static Arc<RwLock<BTreeMap<i32, Teacher>>> {
static TEACHERS: OnceLock<Arc<RwLock<BTreeMap<i32, Teacher>>>> = OnceLock::new();
TEACHERS.get_or_init(|| Arc::new(RwLock::new(read_teachers())))
}
pub fn del_teachers_state() -> &'static Arc<RwLock<Vec<bool>>> {
static TEACHERS: OnceLock<Arc<RwLock<Vec<bool>>>> = OnceLock::new();
TEACHERS.get_or_init(|| Arc::new(RwLock::new(vec![false; filtered_teachers().read().len()])))
}
pub fn teachers_acts() -> &'static Arc<RwLock<BTreeMap<i32, Vec<Activity>>>> {
static CLASSES: OnceLock<Arc<RwLock<BTreeMap<i32, Vec<Activity>>>>> = OnceLock::new();
CLASSES.get_or_init(|| Arc::new(RwLock::new(create_teacher_acts())))
}
pub fn create_teacher_acts() -> BTreeMap<i32, Vec<Activity>> {
let acts = &*activities().read();
let mut map = BTreeMap::new();
for t in &*get_teachers().read() {
let mut c_acts = acts
// .clone()
.values()
.filter(|a| {
a.teachers.iter().any(|ac| ac == &t.1.id)
|| a.teachers.is_empty()
|| a.classes.is_empty()
})
.map(|a| a.clone())
.collect::<Vec<Activity>>();
c_acts.sort_by(|a, b| a.lecture.cmp(&b.lecture));
map.insert(t.1.id, c_acts);
}
map
}
pub fn teacher_name() -> &'static Arc<RwLock<String>> {
static NAME: OnceLock<Arc<RwLock<String>>> = OnceLock::new();
NAME.get_or_init(|| Arc::new(RwLock::new("".to_string())))
}
fn teacher_short_name() -> &'static Arc<RwLock<String>> {
static SHORT_NAME: OnceLock<Arc<RwLock<String>>> = OnceLock::new();
SHORT_NAME.get_or_init(|| Arc::new(RwLock::new("".to_string())))
}
fn update_teacher_form() -> &'static Arc<RwLock<bool>> {
static SHORT_NAME: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
SHORT_NAME.get_or_init(|| Arc::new(RwLock::new(false)))
}
fn update_teacher(ui: &mut eframe::egui::Ui) {
egui::Window::new("Select Teacher")
.open(&mut *update_teacher_form().write())
.resizable([true, true])
.show(ui.ctx(), |ui| {
ui.add(TextEdit::singleline(&mut *teacher_name().write()));
ui.add(TextEdit::singleline(&mut *teacher_short_name().write()));
if ui.add(Button::new("Güncelle")).clicked() {
if let Some(t) = get_teachers()
.write()
.get_mut(&selected_teacher().read().unwrap())
{
t.name = teacher_name().read().clone();
t.short_name = teacher_short_name().read().clone();
save_teachers();
}
}
});
}
pub fn teachers_page(ui: &mut eframe::egui::Ui) {
// let mut name = get_name().lock().unwrap();
ui.vertical_centered(|ui| {
if ui
.add_sized(
vec2(250., 30.),
TextEdit::singleline(&mut *teacher_name().write())
.hint_text("Öğretmenin Adı ve Soyadı"),
)
.changed()
{
set_teachers_filter();
};
if ui
.add_sized(
vec2(250., 30.),
TextEdit::singleline(&mut *teacher_short_name().write()).hint_text("Kısa Ad"),
)
.changed()
{};
if ui
.add_sized(vec2(250., 30.), Button::new("Öğretmeni Ekle"))
.clicked()
{
add_teacher();
save_teachers();
}
});
ui.separator();
teachers_ui(ui);
}
pub fn teachers_list_ui(ui: &mut egui::Ui) {
ScrollArea::vertical().show(ui, |ui| {
ui.add_space(30.);
ui.separator();
ui.vertical_centered(|ui| {
if ui
.add_sized(
vec2(250., 30.),
TextEdit::singleline(&mut *teacher_name().write()).hint_text("Filtrele"),
)
.changed()
{
set_teachers_filter();
};
let mut teachers = filtered_teachers().write();
for c in &mut *teachers {
let fill_color = if selected_teacher().read().is_some_and(|i| i == c.id) {
Color32::BLUE
} else {
Color32::default()
};
let stroke_color = if selected_teacher().read().is_some_and(|i| i == c.id) {
Color32::LIGHT_BLUE
} else {
Color32::LIGHT_GRAY
};
let button = egui::Frame::none()
.fill(fill_color)
.inner_margin(10.)
.outer_margin(2.)
.rounding(5.0)
.stroke(Stroke::new(1., stroke_color))
.show(ui, |ui| {
ui.label(&c.name);
})
.response;
let button = button
.interact(egui::Sense::click())
.on_hover_cursor(egui::CursorIcon::PointingHand);
if button.clicked() {
set_selected_teacher(c.clone());
}
}
});
});
}
pub fn teachers_ui(ui: &mut eframe::egui::Ui) {
update_teacher(ui);
Flex::horizontal()
.gap(vec2(20., 20.))
.wrap(true)
.show(ui, |flex| {
let del_states = del_teachers_state().read().clone();
let del_states = del_states.iter().enumerate();
for (del_state, teacher) in zip(del_states, filtered_teachers().read().iter()) {
let frame = egui::Frame::default()
.stroke(Stroke::new(0.3, Color32::GRAY))
.rounding(5.)
.inner_margin(5.);
flex.add_flex(item().grow(1.).frame(frame), Flex::vertical(), |flex| {
flex.add(item(), Label::new(&teacher.name));
if *del_state.1 {
flex.add_flex(
item().grow(1.),
Flex::horizontal()
.align_items(egui_flex::FlexAlign::Center)
.wrap(false),
|flex| {
if flex
.add(
item(),
Link::new(RichText::new("Sil").color(Color32::RED)),
)
// .inner
.clicked()
{
del_teacher(teacher.id, del_state.0);
// del_teacher(teacher.id);
};
if flex
.add(item().grow(1.), Link::new("Vazgeç"))
// .inner
.clicked()
{
std::thread::spawn(move || {
if let Some(state) =
del_teachers_state().write().get_mut(del_state.0)
{
*state = false;
}
});
};
},
);
} else {
flex.ui().layout().horizontal_justify();
flex.add_flex(
item().grow(0.0),
Flex::horizontal()
.align_items(egui_flex::FlexAlign::Center)
.wrap(false),
|flex| {
if flex
.add(
item(),
Link::new(RichText::new("Sil").color(Color32::RED)),
)
// .inner
.clicked()
{
std::thread::spawn(move || {
if let Some(state) =
del_teachers_state().write().get_mut(del_state.0)
{
*state = true;
}
});
};
if flex
.add(item().grow(1.), Link::new("Düzenle"))
// .inner
.clicked()
{
let t = teacher.clone();
set_selected_teacher(t.clone());
std::thread::spawn(move || {
*teacher_name().write() = t.name.clone();
*teacher_short_name().write() = t.short_name.clone();
*update_teacher_form().write() = true;
});
};
},
);
}
});
}
});
}
fn save_teachers() {
std::thread::spawn(move || {
let teachers = get_teachers().read();
let js = serde_json::to_string(&*teachers);
match js {
Ok(j) => {
let mut f = File::create("./db/teachers.json").unwrap();
f.write_all(j.as_bytes()).unwrap();
}
Err(_) => {}
}
});
}
fn add_teacher() {
let id = find_new_id();
let teacher = Teacher {
id,
name: teacher_name().read().clone(),
short_name: teacher_short_name().read().clone(),
};
get_teachers().write().insert(id, teacher);
*teacher_name().write() = "".to_string();
*teacher_short_name().write() = "".to_string();
set_teachers_filter();
let t_lims = TeacherLimitation::new(id);
teachers_limitations().write().insert(id, t_lims);
save_teachers();
save_teachers_limitations();
del_teachers_state().write().push(false);
}
fn read_teachers() -> BTreeMap<i32, Teacher> {
let f = File::open("./db/teachers.json");
if let Ok(mut f) = f {
let mut content: String = String::new();
f.read_to_string(&mut content).unwrap();
let cls: BTreeMap<i32, Teacher> = serde_json::from_str(content.as_str()).unwrap();
return cls;
}
BTreeMap::new()
}
fn del_teacher(id: i32, state: usize) {
// let cls = Arc::clone(&teachers);
std::thread::spawn(move || {
get_teachers().write().remove(&id);
save_teachers();
del_teacher_acts(id);
teachers_limitations().write().remove(&id);
save_teachers_limitations();
*teachers_scheds().write() = create_teachers_sched();
teachers_acts().write().remove(&id);
set_teachers_filter();
del_teachers_state().write().remove(state);
})
.join()
.unwrap();
}
fn del_teacher_acts(id: i32) {
// let acts = &mut *activities().write();
if let Some(c_acts) = teachers_acts().read().get(&id) {
for a in c_acts {
if a.teachers.iter().any(|t| t == &id) {
activities().write().remove(&a.id);
}
}
}
teachers_acts().write().remove(&id);
save_activities();
}
fn find_new_id() -> i32 {
let len = get_teachers().read().len() as i32;
for i in 1..len + 1 {
if !get_teachers().read().contains_key(&i) {
return i;
}
}
len + 1
}
pub fn set_selected_teacher(t: Teacher) {
let teacher = Arc::clone(selected_teacher());
std::thread::spawn(move || {
*teacher.write() = Some(t.id);
});
// let lims = teachers_limitations().read();
// let lims = lims.get(&t.id);
// match lims {
// Some(lims) => {
// *teacher_limitation().write() = lims.clone();
// }
// None => {
// *teacher_limitation().write() = TeacherLimitation::new(t.id);
// }
// }
*act_teachers().write() = vec![t.clone()];
}
// pub mod all_classes;
// pub mod all_teachers;
pub mod classes;
pub mod teachers;
use std::iter::zip;
use genpdf::*;
use crate::{
tabs::{
get_school, limitations::limitations_ui::teachers_scheds, school_name,
teachers::get_teachers,
},
DAYS,
};
pub fn teachers_prints() {
let fon_family = crate::fonts::font_family();
// let font_family = genpdf::fonts::from_files("./fonts", "LiberationSans", None)
// .expect("Failed to load font family");
let mut doc = genpdf::Document::new(fon_family);
// Change the default settings
doc.set_title(format!("{}", &*school_name().read()));
// Customize the pages
let mut decorator = genpdf::SimplePageDecorator::new();
decorator.set_margins(10);
doc.set_page_decorator(decorator);
// let mut buf: Vec<u8> = Vec::new();
print_teachers(&mut doc);
// doc.render(&mut buf).expect("Render edilemedi");
doc.render_to_file("ogretmenler.pdf")
.expect("Failed to write PDF file");
opener::open(std::path::Path::new("ogretmenler.pdf"));
// let png_jsarray: zoon::JsValue = js_sys::Uint8Array::from(&buf[..]).into();
// // the buffer has to be an array of arrays
// let png_buffer: js_sys::Array = std::iter::IntoIterator::into_iter([png_jsarray]).collect();
// let mut properties = web_sys::BlobPropertyBag::new();
// properties.type_("application/pdf");
// let png_blob =
// web_sys::Blob::new_with_buffer_source_sequence_and_options(&png_buffer, &properties)
// .unwrap();
// let url = web_sys::Url::create_object_url_with_blob(&png_blob).unwrap();
// let window = web_sys::window().unwrap();
// window.open_with_url(&url).expect("Pdf açılamadı");
}
fn print_teachers(doc: &mut genpdf::Document) {
let school_name = &*school_name().read();
doc.set_minimal_conformance();
doc.set_line_spacing(1.25);
let mut decorator = genpdf::SimplePageDecorator::new();
decorator.set_margins(10 as i32);
doc.set_page_decorator(decorator);
doc.set_line_spacing(1.25);
let teachers = &*get_teachers().read();
for teacher in teachers {
let mut title = elements::LinearLayout::vertical();
let mut title_style = style::Style::new();
title_style.set_bold();
title_style.set_font_size(20);
let title_paragraph = elements::Paragraph::default();
title.push(
title_paragraph
.styled_string(school_name, title_style)
.aligned(Alignment::Center),
);
let t_name = format!("{}", teacher.1.name);
let mut teacher_style = style::Style::new();
teacher_style.set_italic();
teacher_style.set_font_size(18);
title.push(elements::Paragraph::new(&t_name).aligned(Alignment::Center));
doc.push(title);
//doc.push(elements::Break::new(1));
add_row(doc, teacher.1.id);
doc.push(elements::PageBreak::new());
}
}
fn add_row(doc: &mut genpdf::Document, c: i32) {
let len = get_school().read().hour as usize;
let mut table = elements::TableLayout::new(vec![8; len + 1]);
table.set_cell_decorator(elements::FrameCellDecorator::new(true, true, false));
let mut row = table.row();
row.push_element(
create_row_title(format!("{} ve {}", "Günler", "Saatler")).aligned(Alignment::Center),
);
for hour in vec![1; len].iter().enumerate() {
row.push_element(
create_row_title(format!("{}. saat", hour.0 + 1)).aligned(Alignment::Center),
);
}
row.push().expect("Invalid table row");
let sched = teachers_scheds().read();
let scheds = sched.get(&c).unwrap();
for (day, sched) in zip(DAYS, scheds) {
let mut row = table.row();
let mut day_row = elements::LinearLayout::vertical();
day_row.push(create_row_title(day.to_string()).aligned(Alignment::Center));
let mut line_style = style::Style::new();
line_style.bold();
line_style.set_font_size(8);
// let par = elements::Paragraph::default()
// .styled_string("00:00-00:00", line_style)
// .aligned(Alignment::Center);
// day_row.push(par);
row.push_element(day_row);
// println!("{:?}", sched);
for s in sched {
if let Some(s) = s {
row.push_element(create_row_title(format!("{:?}", s)))
} else {
row.push_element(create_row_title("".to_string()))
}
}
row.push().unwrap();
}
doc.push(table);
}
fn create_row_title(title: String) -> elements::Paragraph {
let paragraph = elements::Paragraph::default();
let mut title_style = style::Style::new();
title_style.bold();
title_style.set_font_size(10);
paragraph.styled_string(title, title_style)
}
use std::iter::zip;
use genpdf::*;
use crate::{
tabs::{
classes::get_classes, get_school, limitations::limitations_ui::classes_sched, school_name,
},
DAYS,
};
pub fn classes_prints() {
let fon_family = crate::fonts::font_family();
let mut doc = genpdf::Document::new(fon_family);
// Change the default settings
doc.set_title(format!("{}", &*school_name().read()));
// Customize the pages
let mut decorator = genpdf::SimplePageDecorator::new();
decorator.set_margins(10);
doc.set_page_decorator(decorator);
// let mut buf: Vec<u8> = Vec::new();
print_classes(&mut doc);
// doc.render(&mut buf).expect("Render edilemedi");
doc.render_to_file("output.pdf")
.expect("Failed to write PDF file");
// let png_jsarray: zoon::JsValue = js_sys::Uint8Array::from(&buf[..]).into();
// // the buffer has to be an array of arrays
// let png_buffer: js_sys::Array = std::iter::IntoIterator::into_iter([png_jsarray]).collect();
// let mut properties = web_sys::BlobPropertyBag::new();
// properties.type_("application/pdf");
// let png_blob =
// web_sys::Blob::new_with_buffer_source_sequence_and_options(&png_buffer, &properties)
// .unwrap();
// let url = web_sys::Url::create_object_url_with_blob(&png_blob).unwrap();
// let window = web_sys::window().unwrap();
// window.open_with_url(&url).expect("Pdf açılamadı");
}
fn print_classes(doc: &mut genpdf::Document) {
let school_name = &*school_name().read();
doc.set_minimal_conformance();
doc.set_line_spacing(1.25);
let mut decorator = genpdf::SimplePageDecorator::new();
decorator.set_margins(10 as i32);
doc.set_page_decorator(decorator);
doc.set_line_spacing(1.25);
let clss = &*get_classes().read();
for class in clss {
let mut title = elements::LinearLayout::vertical();
let mut title_style = style::Style::new();
title_style.set_bold();
title_style.set_font_size(20);
let title_paragraph = elements::Paragraph::default();
title.push(
title_paragraph
.styled_string(school_name, title_style)
.aligned(Alignment::Center),
);
let cls_name = format!("{}", class.1.name);
let mut teacher_style = style::Style::new();
teacher_style.set_italic();
teacher_style.set_font_size(18);
title.push(elements::Paragraph::new(&cls_name).aligned(Alignment::Center));
doc.push(title);
//doc.push(elements::Break::new(1));
add_row(doc, class.1.id);
doc.push(elements::PageBreak::new());
}
}
fn add_row(doc: &mut genpdf::Document, c: i32) {
let len = get_school().read().hour as usize;
let mut table = elements::TableLayout::new(vec![8; len + 1]);
table.set_cell_decorator(elements::FrameCellDecorator::new(true, true, false));
let mut row = table.row();
row.push_element(
create_row_title(format!("{} ve {}", "Günler", "Saatler")).aligned(Alignment::Center),
);
for hour in vec![0; len].iter().enumerate() {
row.push_element(create_row_title(format!("{}. saat", hour.0)).aligned(Alignment::Center));
}
row.push().expect("Invalid table row");
let sched = classes_sched().read();
let scheds = sched.get(&c).unwrap();
for (day, sched) in zip(DAYS, scheds) {
let mut row = table.row();
let mut day_row = elements::LinearLayout::vertical();
day_row.push(create_row_title(day.to_string()).aligned(Alignment::Center));
let mut line_style = style::Style::new();
line_style.bold();
line_style.set_font_size(8);
// let par = elements::Paragraph::default()
// .styled_string("00:00-00:00", line_style)
// .aligned(Alignment::Center);
// day_row.push(par);
row.push_element(day_row);
for s in sched {
if let Some(s) = s {
row.push_element(create_row_title(format!("{:?}", s)))
} else {
row.push_element(create_row_title("".to_string()))
}
}
row.push().unwrap();
}
doc.push(table);
}
fn create_row_title(title: String) -> elements::Paragraph {
let paragraph = elements::Paragraph::default();
let mut title_style = style::Style::new();
title_style.bold();
title_style.set_font_size(10);
paragraph.styled_string(title, title_style)
}
use genpdf::elements::TableLayout;
use genpdf::{elements, style, Alignment, Document, Size};
use shared::msgs::activities::FullActivity;
use shared::msgs::teachers::Teacher;
use shared::msgs::timetables::Schedule;
use crate::app::timetables::{selected_timetable_hour, schedules, activities, teachers, classes};
use crate::app::timetables::school;
pub fn print_teacher_all(){
let fon_family = crate::fonts::font_family();
let mut doc = genpdf::Document::new(fon_family);
let mut buf: Vec<u8> = Vec::new();
//print_classes(&mut doc);
print_teachers(&mut doc);
doc.render(&mut buf).expect("Render edilemedi");
let png_jsarray: zoon::JsValue = js_sys::Uint8Array::from(&buf[..]).into();
// the buffer has to be an array of arrays
let png_buffer: js_sys::Array = std::iter::IntoIterator::into_iter([png_jsarray]).collect();
let mut properties = web_sys::BlobPropertyBag::new();
properties.type_("application/pdf");
let png_blob =
web_sys::Blob::new_with_buffer_source_sequence_and_options(&png_buffer, &properties)
.unwrap();
let url = web_sys::Url::create_object_url_with_blob(&png_blob).unwrap();
let window = web_sys::window().unwrap();
window.open_with_url(&url).expect("Pdf açılamadı");
}
fn print_teachers(doc: &mut genpdf::Document){
doc.set_paper_size(Size::new(297,210));
doc.set_title(format!("{}", school().get_cloned().unwrap().name));
// Customize the pages
let mut decorator = genpdf::SimplePageDecorator::new();
decorator.set_margins(10);
doc.set_page_decorator(decorator);
let school_name = school().get_cloned().unwrap().name;
doc.set_minimal_conformance();
doc.set_line_spacing(1.25);
let mut title = elements::LinearLayout::vertical();
let mut title_style = style::Style::new();
title_style.set_bold();
title_style.set_font_size(20);
let title_paragraph = elements::Paragraph::default();
title.push(title_paragraph.styled_string(&school_name, title_style).aligned(Alignment::Center));
doc.push(title);
day_row(doc);
}
use crate::i18n::t_s;
fn day_row(doc: &mut Document){
let mut table = elements::TableLayout::new(vec![8, 8, 8, 8, 8, 8]);
table.set_cell_decorator(elements::FrameCellDecorator::new(true, true, false));
let mut row = table.row();
row.push_element(create_row_title(format!("{}", t_s!("days"))).aligned(Alignment::Center));
for day in &["Pzt","Salı","Çarş","Per","Cuma"]{
row.push_element(create_row_title(format!("{}",day)).aligned(Alignment::Center));
}
row.push().expect("Invalid table row");
let mut row = table.row();
row.push_element(create_row_title(format!("{}", t_s!("hours"))).aligned(Alignment::Center));
for _day in &["Pzt","Salı","Çarş","Per","Cuma"]{
let mut table2 = elements::TableLayout::new(vec![1, 1, 1, 1, 1, 1, 1]);
table2.set_cell_decorator(elements::FrameCellDecorator::new(true, false, false));
let mut row2 = table2.row();
for i in [1,2,3,4,5,6,7]{
row2.push_element(create_row_title(i.to_string()));
}
row2.push().expect("");
row.push_element(table2);
}
row.push().expect("");
create_teacher_row(&mut table);
doc.push(table);
}
fn create_teacher_row(table: &mut TableLayout){
let tchrs = teachers().lock_mut().to_vec();
for t in tchrs{
let mut row = table.row();
row.push_element(create_row_title(format!("{} {}",t.first_name, t.last_name)));
for d in 0..5{
let t = create_table_for_row(&t, d+1);
row.push_element(t);
}
row.push().expect("msg");
}
}
fn create_table_for_row(t: &Teacher, d: i32)-> TableLayout{
let acts = activities().lock_mut().to_vec();
let t_acts: Vec<&FullActivity> = acts.iter().filter(|a| a.teachers.iter().any(|c2| c2 == &t.id)).collect();
let sch = schedules().lock_mut().to_vec();
let sch: Vec<&Schedule> = sch.iter().filter(|s| t_acts.iter().any(|a| a.id == s.activity)).collect();
let l = selected_timetable_hour().lock_mut().to_vec();
let mut table = genpdf::elements::TableLayout::new(vec![1; l.len()]);
table.set_cell_decorator(elements::FrameCellDecorator::new(true, false, false));
let mut row = table.row();
for i in 0..l.len(){
let s = sch.iter().find(|s| s.day_id == d && s.hour as usize == i);
match s{
Some(s) => {
let a = t_acts.iter().find(|a| a.id == s.activity).unwrap();
let cls = classes().lock_mut().to_vec();
let cls = cls.iter().find(|c| a.classes.iter().any(|c2| c2 == &c.id )).unwrap();
let cls = format!("{}{}", cls.kademe, cls.sube);
let cls = cls.chars().take(2).collect::<String>();
row.push_element(create_row_title(cls));
}
None => row.push_element(create_row_title2("".to_string()))
}
}
row.push().expect("msg");
table
}
fn create_row_title(title: String) -> elements::Paragraph{
let mut paragraph = elements::Paragraph::default();
let mut title_style = style::Style::new();
title_style.bold();
title_style.set_font_size(10);
paragraph = paragraph.styled_string(title, title_style);
paragraph = paragraph.aligned(Alignment::Center);
paragraph
}
fn create_row_title2(title: String) -> elements::Paragraph{
let paragraph = elements::Paragraph::default();
let mut title_style = style::Style::new();
//title_style.bold();
title_style.set_font_size(10);
paragraph.styled_string(title, title_style)
}
use genpdf::elements::TableLayout;
use genpdf::{elements, style, Alignment, Document, Size};
pub fn print_class_all() {
let fon_family = crate::fonts::font_family();
let mut doc = genpdf::Document::new(fon_family);
let mut buf: Vec<u8> = Vec::new();
//print_classes(&mut doc);
print_classes(&mut doc);
// doc.render(&mut buf).expect("Render edilemedi");
// let png_jsarray: zoon::JsValue = js_sys::Uint8Array::from(&buf[..]).into();
// // the buffer has to be an array of arrays
// let png_buffer: js_sys::Array = std::iter::IntoIterator::into_iter([png_jsarray]).collect();
// let mut properties = web_sys::BlobPropertyBag::new();
// properties.type_("application/pdf");
// let png_blob =
// web_sys::Blob::new_with_buffer_source_sequence_and_options(&png_buffer, &properties)
// .unwrap();
// let url = web_sys::Url::create_object_url_with_blob(&png_blob).unwrap();
// let window = web_sys::window().unwrap();
// window.open_with_url(&url).expect("Pdf açılamadı");
}
fn print_classes(doc: &mut genpdf::Document) {
doc.set_paper_size(Size::new(297, 210));
doc.set_title(format!("{}", school_name().read()));
// Customize the pages
let mut decorator = genpdf::SimplePageDecorator::new();
decorator.set_margins(10);
doc.set_page_decorator(decorator);
let school_name = &*school_name().read();
doc.set_minimal_conformance();
doc.set_line_spacing(1.25);
let mut title = elements::LinearLayout::vertical();
let mut title_style = style::Style::new();
title_style.set_bold();
title_style.set_font_size(20);
let title_paragraph = elements::Paragraph::default();
title.push(
title_paragraph
.styled_string(school_name, title_style)
.aligned(Alignment::Center),
);
doc.push(title);
day_row(doc);
}
use crate::tabs::activities::{activities, Activity};
use crate::tabs::classes::{get_classes, Class};
use crate::tabs::generating::Schedule;
use crate::tabs::limitations::limitations_ui::{classes_sched, schedules};
use crate::tabs::{school_hour, school_name};
fn day_row(doc: &mut Document) {
let mut table = elements::TableLayout::new(vec![8, 8, 8, 8, 8, 8]);
table.set_cell_decorator(elements::FrameCellDecorator::new(true, true, false));
let mut row = table.row();
row.push_element(create_row_title(format!("{}", "Günler")).aligned(Alignment::Center));
for day in &["Pzt", "Salı", "Çarş", "Per", "Cuma"] {
row.push_element(create_row_title(format!("{}", day)).aligned(Alignment::Center));
}
row.push().expect("Invalid table row");
let mut row = table.row();
row.push_element(create_row_title(format!("{}", "Saatler")).aligned(Alignment::Center));
for _day in &["Pzt", "Salı", "Çarş", "Per", "Cuma"] {
let mut table2 = elements::TableLayout::new(vec![1, 1, 1, 1, 1, 1, 1]);
table2.set_cell_decorator(elements::FrameCellDecorator::new(true, false, false));
let mut row2 = table2.row();
for i in [1, 2, 3, 4, 5, 6, 7] {
row2.push_element(create_row_title(i.to_string()));
}
row2.push().expect("");
row.push_element(table2);
}
row.push().expect("");
create_class_row(&mut table);
doc.push(table);
}
fn create_class_row(table: &mut TableLayout) {
let clss = &*get_classes().read();
for c in clss {
let mut row = table.row();
row.push_element(create_row_title(format!("{}", &c.1.name)));
for d in 0..5 {
let t = create_table_for_row(&c.1, d + 1);
row.push_element(t);
}
row.push().expect("msg");
}
}
fn create_table_for_row(c: &Class, d: i32) -> TableLayout {
let acts = activities().read();
let c_acts: Vec<&Activity> = acts
.values()
.filter(|a| a.classes.iter().any(|c2| c2 == &c.id))
.collect();
let sch = &*classes_sched().read();
let sch = sch.get(&c.id).unwrap();
let l = &*school_hour().read();
let l = l.parse::<usize>().unwrap();
let mut table = genpdf::elements::TableLayout::new(vec![1; l]);
table.set_cell_decorator(elements::FrameCellDecorator::new(true, false, false));
let mut row = table.row();
for s in sch {
// match s {
// Some(s) => {
// row.push_element(create_row_title(format!("{s:?}")));
// }
// None => row.push_element(create_row_title2("".to_string())),
// }
}
row.push().expect("msg");
table
}
fn create_row_title(title: String) -> elements::Paragraph {
let mut paragraph = elements::Paragraph::default();
let mut title_style = style::Style::new();
title_style.bold();
title_style.set_font_size(10);
paragraph = paragraph.styled_string(title, title_style);
paragraph = paragraph.aligned(Alignment::Center);
paragraph
}
fn create_row_title2(title: String) -> elements::Paragraph {
let paragraph = elements::Paragraph::default();
let mut title_style = style::Style::new();
//title_style.bold();
title_style.set_font_size(10);
paragraph.styled_string(title, title_style)
}
use eframe::egui::{self, ScrollArea};
use limitations_ui::limitations_ui;
use super::{
classes::classes_lists_ui, get_page, panel_buttons, teachers::teachers_list_ui, SubPage,
};
pub mod limitations_ui;
pub fn limitations(ui: &mut egui::Ui) {
egui::TopBottomPanel::top("top_panel")
.resizable(true)
.default_height(60.)
.height_range(50.0..=350.0)
.show_inside(ui, |ui| {
panel_buttons(ui);
});
egui::SidePanel::left("right_panel")
.resizable(true)
.default_width(250.0)
.width_range(150.0..=300.0)
.show_inside(ui, |ui| {
if let SubPage::Teachers = *get_page().read() {
teachers_list_ui(ui);
} else {
classes_lists_ui(ui);
}
// limitations_ui(ui);
});
egui::CentralPanel::default()
// .resizable(true)
// .default_width(1024.0)
// .width_range(800.0..=1280.0)
.show_inside(ui, |ui| {
ScrollArea::vertical()
// .scroll_bar_visibility(true)
.max_width(f32::INFINITY)
.show_viewport(ui, |ui, _viewport| {
// ui.add_sized(Vec2::new(1500., 5000.), Label::new("A"));
// Flex::vertical().wrap(false).show(ui, |flex| {
limitations_ui(ui);
// list_activities_ui(ui);
// });
});
});
}
use std::{
collections::HashMap,
fs::File,
io::{Read, Write},
sync::{Arc, OnceLock},
thread::spawn,
};
use eframe::egui::{
self, mutex::RwLock, vec2, Button, Color32, Frame, Label, RichText, Stroke, Vec2,
};
use egui_flex::{item, Flex, FlexInstance};
use serde::{Deserialize, Serialize};
use crate::{
tabs::{
activities::{
activities, acts_frames, get_classes_name, get_teachers_name, partnered_act,
teachers_acts_hours, Activity,
},
classes::{classes_acts, get_classes, selected_class},
generating::{available_days, create_available_days, data, Schedule, TimetableData},
get_school, school_hour,
teachers::{get_teachers, selected_teacher, teachers_acts},
SubPage,
},
DAYS,
};
use super::get_page;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ClassLimitation {
pub class_id: i32,
pub limitations: Vec<Vec<bool>>,
}
impl ClassLimitation {
pub fn new(id: i32) -> Self {
let hour = school_hour().read().parse::<usize>().unwrap_or(8);
Self {
class_id: id,
limitations: vec![vec![true; hour]; 7],
}
}
fn validation(&mut self) {
let hour = &*school_hour().read();
let hour = hour.parse::<usize>().unwrap_or(8);
while self.limitations.len() > 7 {
self.limitations.pop();
}
while self.limitations.len() < 7 {
self.limitations.push(vec![true; hour]);
}
self.limitations.iter_mut().for_each(|l| {
while l.len() > hour {
l.pop();
}
while l.len() < hour {
l.push(true);
}
})
}
}
pub fn classes_volumes() -> &'static Arc<RwLock<HashMap<i32, Vec<Vec<i32>>>>> {
static PAGE: OnceLock<Arc<RwLock<HashMap<i32, Vec<Vec<i32>>>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(create_classes_volumes())))
}
fn create_classes_volumes() -> HashMap<i32, Vec<Vec<i32>>> {
let clss = get_classes().read();
let s_hour = get_school().read().hour;
let acts = classes_acts().read().clone();
let mut map = HashMap::new();
for c in &*clss {
let c_acts = acts.get(c.0).unwrap();
let mut days = vec![];
for day in DAYS.iter().enumerate() {
let mut hours = vec![0; s_hour as usize];
for act in c_acts {
let h_lim = s_hour - act.hour + 1;
for h in 0..h_lim as usize {
if act.hour + h <= s_hour
&& act.classes_available(h, day.0)
&& act.teachers_available(h, day.0)
{
(0..act.hour).for_each(|hh| hours[h + hh as usize] += 1);
}
}
}
days.push(hours);
}
map.insert(*c.0 as i32, days);
}
map
}
pub fn teachers_volumes() -> &'static Arc<RwLock<HashMap<i32, Vec<Vec<i32>>>>> {
static PAGE: OnceLock<Arc<RwLock<HashMap<i32, Vec<Vec<i32>>>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(create_teachers_volumes())))
}
fn create_teachers_volumes() -> HashMap<i32, Vec<Vec<i32>>> {
let teachers = get_teachers().read();
let s_hour = get_school().read().hour;
let acts = teachers_acts().read().clone();
let mut map = HashMap::new();
for t in &*teachers {
let t_acts = acts.get(t.0).unwrap();
let mut days = vec![];
for day in DAYS.iter().enumerate() {
let mut hours = vec![0; s_hour as usize];
for h in 0..s_hour as usize {
for act in t_acts {
if act.hour + h <= s_hour
&& act.classes_available(h, day.0)
&& act.teachers_available(h, day.0)
{
hours[h] += 1;
}
}
}
days.push(hours);
}
map.insert(*t.0 as i32, days);
}
map
}
pub fn schedules() -> &'static Arc<RwLock<Vec<Schedule>>> {
static PAGE: OnceLock<Arc<RwLock<Vec<Schedule>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(vec![])))
}
pub fn classes_limitations() -> &'static Arc<RwLock<HashMap<i32, ClassLimitation>>> {
static PAGE: OnceLock<Arc<RwLock<HashMap<i32, ClassLimitation>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(get_class_limitations())))
}
pub fn get_class_limitations() -> HashMap<i32, ClassLimitation> {
let lims = File::open("./db/classes_limitations.json");
if let Ok(mut lims) = lims {
let mut content: String = String::new();
lims.read_to_string(&mut content).unwrap();
let mut cls: Vec<ClassLimitation> = serde_json::from_str(content.as_str()).unwrap();
cls.iter_mut().for_each(|l| l.validation());
let mut lims: HashMap<i32, ClassLimitation> = HashMap::new();
for c in cls {
lims.insert(c.class_id, c);
}
return lims;
} else {
let mut lims: HashMap<i32, ClassLimitation> = HashMap::new();
for c in &*get_classes().read() {
lims.insert(c.1.id, ClassLimitation::new(c.1.id));
}
return lims;
}
}
type ClassSched = Arc<RwLock<HashMap<i32, Vec<Vec<Option<Activity>>>>>>;
pub fn classes_sched() -> &'static ClassSched {
static ACT: OnceLock<ClassSched> = OnceLock::new();
ACT.get_or_init(|| Arc::new(RwLock::new(create_classes_sched())))
}
fn get_class_scheds(id: i32) -> Vec<Vec<Option<Activity>>> {
let scheds = &*classes_sched().read();
let scheds = scheds.get(&id);
if let Some(scheds) = scheds {
return scheds.clone();
} else {
create_classes_sched();
return get_class_scheds(id);
}
}
fn get_class_lims(id: i32) -> Vec<Vec<bool>> {
let lims = classes_limitations().read();
let lims = lims.get(&id);
if let Some(lims) = lims {
return lims.limitations.clone();
} else {
std::thread::spawn(move || {
classes_limitations()
.write()
.insert(id, ClassLimitation::new(id));
});
return get_class_lims(id);
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct TeacherLimitation {
pub teacher_id: i32,
pub limitations: Vec<Vec<bool>>,
}
impl TeacherLimitation {
pub fn new(id: i32) -> Self {
let hour = school_hour().read().parse::<usize>().unwrap_or(8);
Self {
teacher_id: id,
limitations: vec![vec![true; hour]; 7],
}
}
fn validation(&mut self) {
let hour = &*school_hour().read();
let hour = hour.parse::<usize>().unwrap_or(8);
while self.limitations.len() > 7 {
self.limitations.pop();
}
while self.limitations.len() < 7 {
self.limitations.push(vec![true; hour]);
}
self.limitations.iter_mut().for_each(|l| {
while l.len() > hour {
l.pop();
}
while l.len() < hour {
l.push(true);
}
})
}
}
fn get_teacher_lims(id: i32) -> Vec<Vec<bool>> {
let lims = teachers_limitations().read();
let lims = lims.get(&id);
if let Some(lims) = lims {
return lims.limitations.clone();
} else {
let lims = TeacherLimitation::new(id);
let lims2 = lims.clone();
std::thread::spawn(move || {
teachers_limitations().write().insert(id, lims2);
});
return lims.limitations;
}
}
pub fn teachers_limitations() -> &'static Arc<RwLock<HashMap<i32, TeacherLimitation>>> {
static PAGE: OnceLock<Arc<RwLock<HashMap<i32, TeacherLimitation>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(get_teacher_limitations())))
}
pub fn get_teacher_limitations() -> HashMap<i32, TeacherLimitation> {
let lims = File::open("./db/teachers_limitations.json");
if let Ok(mut lims) = lims {
let mut content: String = String::new();
lims.read_to_string(&mut content).unwrap();
let mut cls: Vec<TeacherLimitation> = serde_json::from_str(content.as_str()).unwrap();
cls.iter_mut().for_each(|l| l.validation());
let mut lims: HashMap<i32, TeacherLimitation> = HashMap::new();
for c in cls {
lims.insert(c.teacher_id, c);
}
return lims;
} else {
let tchrs = get_teachers().read();
let mut lims: HashMap<i32, TeacherLimitation> = HashMap::new();
for t in &*tchrs {
lims.insert(t.1.id, TeacherLimitation::new(t.1.id));
}
return lims;
}
}
type TeacherSched = Arc<RwLock<HashMap<i32, Vec<Vec<Option<Activity>>>>>>;
pub fn teachers_scheds() -> &'static TeacherSched {
// create_sched();
static ACT: OnceLock<TeacherSched> = OnceLock::new();
ACT.get_or_init(|| Arc::new(RwLock::new(create_teachers_sched())))
}
fn get_teacher_scheds(id: i32) -> Vec<Vec<Option<Activity>>> {
let scheds = teachers_scheds().read();
let scheds = scheds.get(&id);
if let Some(scheds) = scheds {
return scheds.clone();
} else {
create_teachers_sched();
return get_teacher_scheds(id);
}
}
fn _update_teacher_limitation() {
// let teacher_lims = &*teacher_limitation().read();
// let mut lims = teachers_limitations().write();
// let id = selected_teacher().read().unwrap();
// lims.insert(id, teacher_lims.clone());
}
pub fn limitations_ui(ui: &mut egui::Ui) {
let page = &*get_page().read();
let acts = if let SubPage::Teachers = page {
let id = selected_teacher().read().unwrap_or(1);
let activities = teachers_acts().read().clone();
let act = activities.get(&id).unwrap();
act.clone()
} else {
let id = selected_class().read().unwrap_or(1);
let activities = classes_acts().read().clone();
let act = activities.get(&id).unwrap();
act.clone()
};
match page {
super::SubPage::Teachers => {
if let Some(teacher_id) = *selected_teacher().read() {
ui.set_width(1024.);
Flex::vertical()
// .grow_items(0.5)
.gap(Vec2::new(0., 0.))
.show(ui, |flex| {
flex.add(
item(),
Label::new(
RichText::new(format!(
"{}: {} saat",
get_teachers_name(&[teacher_id]),
teachers_acts_hours()
.read()
.clone()
.get(&teacher_id)
.unwrap()
))
.size(24.),
),
);
flex.add_ui(item(), |ui| ui.add_space(10.));
hours_frame(flex);
days_frame(
flex,
get_teacher_lims(teacher_id),
get_teacher_scheds(teacher_id),
teachers_volumes().read().get(&teacher_id).unwrap(),
);
flex.add_ui(item(), |ui| ui.add_space(10.));
flex.add_ui(item(), |ui| {
ui.horizontal(|ui| {
if ui
.add_sized(Vec2::new(150., 50.), Button::new("Kaydet"))
.clicked()
{
save_teachers_limitations();
}
if ui
.add_sized(Vec2::new(150., 50.), Button::new("Tümüne Uygula"))
.clicked()
{
change_all();
}
});
});
});
} else {
ui.label("Sol listeden seçim yapın");
}
}
super::SubPage::Classes => {
if let Some(class_id) = *selected_class().read() {
ui.set_width(1024.);
Flex::vertical()
// .grow_items(0.5)
.gap(Vec2::new(0., 0.))
.show(ui, |flex| {
flex.add(
item().grow(1.),
Label::new(RichText::new(get_classes_name(&[class_id])).size(24.)),
);
flex.add_ui(item(), |ui| ui.add_space(10.));
hours_frame(flex);
days_frame(
flex,
get_class_lims(class_id),
get_class_scheds(class_id),
classes_volumes().read().get(&class_id).unwrap(),
);
flex.add_ui(item(), |ui| ui.add_space(10.));
flex.add_ui(item(), |ui| {
ui.horizontal(|ui| {
if ui
.add_sized(Vec2::new(150., 50.), Button::new("Kaydet"))
.clicked()
{
save_classes_limitations();
}
if ui
.add_sized(Vec2::new(150., 50.), Button::new("Tümüne Uygula"))
.clicked()
{
change_all();
}
});
});
});
} else {
ui.label("Sol listeden seçim yapın");
}
}
}
acts_frames(ui, &acts);
}
fn hours_frame(flex: &mut FlexInstance) {
let hour = school_hour().read().parse::<usize>().unwrap_or(8);
let frame = Frame::none().stroke(Stroke::new(1., Color32::LIGHT_GRAY));
flex.add_flex(
item().grow(1.),
Flex::horizontal().gap(vec2(0., 0.)),
|flex| {
flex.add_flex(item().frame(frame), Flex::new(), |flex| {
flex.add_ui(item(), |ui| {
ui.add_sized(Vec2::new(100., 50.), Label::new("Günler ve Saatler"));
});
});
for i in 0..hour {
flex.add_flex(item().frame(frame), Flex::new(), |flex| {
flex.add_ui(item(), |ui| {
if ui
.add_sized(Vec2::new(100., 50.), Label::new((i + 1).to_string()))
.clicked()
{
change_all_hours(i);
};
})
});
}
},
);
}
// static LIMS: &[&[bool]] = &'static [&'static [true; 10]; 7];
fn days_frame(
flex: &mut FlexInstance,
_lims: Vec<Vec<bool>>,
_scheds: Vec<Vec<Option<Activity>>>,
vol: &Vec<Vec<i32>>,
) {
let hour = school_hour().read().parse::<usize>().unwrap_or(8);
let frame = Frame::none().stroke(Stroke::new(1., Color32::LIGHT_GRAY));
for (index, day) in DAYS.iter().enumerate() {
flex.add_flex(item(), Flex::horizontal().gap(Vec2::splat(0.)), |flex| {
flex.add_flex(item().frame(frame), Flex::new(), |flex| {
flex.add_ui(item(), |ui| {
if ui
.add_sized(Vec2::new(100., 50.), Label::new(*day))
.clicked()
{
change_all_day(index);
};
});
});
for i in 0..hour {
let v: u8 = if vol[index][i] > 100 {
100
} else {
vol[index][i] as u8
};
let f_color = if _lims[index][i] {
Color32::from_rgb(50 + v * 2, 0, 0)
} else {
Color32::default()
};
let frame = Frame::none()
.stroke(Stroke::new(1., Color32::LIGHT_GRAY))
.fill(f_color);
flex.add_flex(item().grow(1.).frame(frame), Flex::vertical(), |ui| {
ui.add_ui(item(), |ui| {
ui.visuals_mut().widgets.inactive.bg_fill = egui::Color32::TRANSPARENT;
let (_, payl) = ui.dnd_drop_zone::<Activity, ()>(Frame::none(), |ui| {
sched_act(ui, &_scheds[index][i], index, i)
});
if let Some(p) = payl {
if p.teachers_available(i, index) && p.classes_available(i, index) {
std::thread::spawn(move || {
if let Some(p_id) = partnered_act().read().get(&p.id) {
let a = activities().read();
let a = a.get(p_id).unwrap();
data().write().put_act(index, i, &a.clone(), false);
} else {
data().write().put_act(index, i, &p.clone(), false);
}
data().write().replace_act(index, i, p.id, p.hour);
// update_tt();
});
}
// println!("{p:?}");
}
});
});
}
});
}
}
pub fn create_teachers_sched() -> HashMap<i32, Vec<Vec<Option<Activity>>>> {
let mut t_scheds = HashMap::new();
let acts = activities().read().clone();
let p_acts = partnered_act().read().clone();
for teacher in &*get_teachers().read() {
let mut teacher_acts = activities()
.read()
.iter()
.filter(|a| a.1.teachers.iter().any(|c| c == &teacher.1.id))
.map(|a| a.1.clone())
.collect::<Vec<Activity>>();
let p_ids = p_acts
.iter()
.filter(|pa| teacher_acts.iter().any(|ta| pa.0 == &ta.id))
.map(|pa| pa.1.clone())
.collect::<Vec<i32>>();
for p_id in p_ids {
if let Some(act) = acts.get(&p_id) {
teacher_acts.push(act.clone());
}
}
// let mut scheds = vec![];
let scs = (*schedules().read()).clone();
let sched = scs
.iter()
.filter(|s| teacher_acts.iter().any(|a| a.id == s.activity))
.map(|s| s.clone())
.collect::<Vec<Schedule>>();
let mut scheduls: Vec<Vec<Option<Activity>>> =
vec![vec![None; get_school().read().hour as usize]; 7];
sched.iter().for_each(|s| {
scheduls[s.day_id][s.hour as usize] = teacher_acts
.clone()
.into_iter()
.find(|ca| ca.id == s.activity);
});
let t = teacher.1.clone();
// let t_sched = Arc::clone(teacher_scheds());
// std::thread::spawn(move || {
t_scheds.insert(t.id, scheduls);
// });
}
t_scheds
}
pub fn create_classes_sched() -> HashMap<i32, Vec<Vec<Option<Activity>>>> {
let mut t_scheds = HashMap::new();
for class in &*get_classes().read() {
let class_acts = activities()
.read()
.iter()
.filter(|a| a.1.classes.iter().any(|c| c == &class.1.id))
.map(|a| a.1.clone())
.collect::<Vec<Activity>>();
// let mut scheds = vec![];
let scs = (*schedules().read()).clone();
let sched = scs
.iter()
.filter(|s| class_acts.iter().any(|a| a.id == s.activity))
.map(|s| s.clone())
.collect::<Vec<Schedule>>();
let mut scheduls: Vec<Vec<Option<Activity>>> =
vec![vec![None; get_school().read().hour as usize]; 7];
sched.iter().for_each(|s| {
scheduls[s.day_id][s.hour as usize] = class_acts
.clone()
.into_iter()
.find(|ca| ca.id == s.activity);
});
let t = class.1.clone();
// let t_sched = Arc::clone(class_scheds());
// std::thread::spawn(move || {
t_scheds.insert(t.id, scheduls);
// });
}
t_scheds
}
fn sched_act(ui: &mut egui::Ui, a: &Option<Activity>, index: usize, i: usize) {
let Some(a) = a else {
if ui
.add_sized(Vec2::new(100., 50.), Label::new(""))
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
change_row(index, i);
};
return ();
};
let rtext = RichText::new(&a.lectures_name()).size(12.).strong();
if ui
.add_sized(Vec2::new(100., 15.), Label::new(rtext))
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
change_row(index, i);
};
match *get_page().read() {
SubPage::Teachers => {
let rtext = RichText::new(&a.classes_name()).size(16.).strong();
if ui
.add_sized(vec2(100., 20.), Label::new(rtext))
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
change_row(index, i);
};
}
SubPage::Classes => {
let rtext = RichText::new(&a.teachers_short_name()).size(10.).strong();
if ui
.add_sized(vec2(100., 15.), Label::new(rtext))
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
change_row(index, i);
};
}
}
ui.horizontal(|ui| {
let rtext = RichText::new("🗑").size(16.).strong();
if ui
.add_sized(Vec2::new(45., 15.), Label::new(rtext))
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
del_tt(a.id);
};
let color = if is_lock_tt(a.id) {
Color32::BLUE
} else {
Color32::GRAY
};
let ltext = RichText::new("🔒").size(16.).color(color).strong();
if ui
.add_sized(Vec2::new(45., 15.), Label::new(ltext))
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
lock_tt(a.id);
};
});
// ui.add(Label::new());
// format!("{}\n{}", a.lectures_name(), a.teachers_short_name())
}
fn lock_tt(act_id: i32) {
std::thread::spawn(move || {
let dt: &mut TimetableData = &mut *data().write();
let scheds = &mut dt.timetables;
let sched = scheds.get_mut(&act_id);
if let Some(tt) = sched {
tt.iter_mut().for_each(|t| t.locked = !t.locked);
}
update_tt();
});
}
fn del_tt(act_id: i32) {
std::thread::spawn(move || {
let dt: &mut TimetableData = &mut *data().write();
let scheds = &mut dt.timetables;
let sched = scheds.remove(&act_id);
update_tt();
});
}
pub fn update_tt() {
std::thread::spawn(move || {
let dt: &mut TimetableData = &mut *data().write();
let scheds = &mut dt.timetables;
let mut sch = vec![];
scheds.values().for_each(|tt| sch.append(&mut tt.clone()));
*schedules().write() = sch.clone();
*classes_sched().write() = create_classes_sched();
*teachers_scheds().write() = create_teachers_sched();
*classes_volumes().write() = create_classes_volumes();
*teachers_volumes().write() = create_teachers_volumes();
});
}
fn is_lock_tt(act_id: i32) -> bool {
let scheds: &Vec<Schedule> = &*schedules().write();
let sched = scheds.iter().find(|a| a.activity == act_id);
if let Some(tt) = sched {
return tt.locked;
}
return false;
}
fn change_all_day(day: usize) {
std::thread::spawn(move || {
let page = &*get_page().read();
match page {
super::SubPage::Teachers => {
let lims = &*teachers_limitations();
let lim = Arc::clone(lims);
std::thread::spawn(move || {
let lims = &mut lim.write();
let day = &mut lims
.get_mut(&selected_teacher().read().unwrap())
.unwrap()
.limitations[day];
if day.iter().any(|h| !*h) {
*day = vec![true; 10];
} else {
*day = vec![false; 10];
}
});
}
super::SubPage::Classes => {
let lims = &*classes_limitations();
let lim = Arc::clone(lims);
std::thread::spawn(move || {
let lims = &mut lim.write();
let day = &mut lims
.get_mut(&selected_class().read().unwrap())
.unwrap()
.limitations[day];
if day.iter().any(|h| !*h) {
*day = vec![true; 10];
} else {
*day = vec![false; 10];
}
});
}
}
});
}
fn change_all_hours(hour: usize) {
std::thread::spawn(move || {
let page = &*get_page().read();
match page {
super::SubPage::Teachers => {
let lims = &*teachers_limitations();
let lim = Arc::clone(lims);
std::thread::spawn(move || {
let lims = &mut lim.write();
let lims = &mut lims
.get_mut(&selected_teacher().read().unwrap())
.unwrap()
.limitations;
if lims.iter().any(|h| !h[hour]) {
lims.iter_mut().for_each(|d| d[hour] = true);
} else {
lims.iter_mut().for_each(|d| d[hour] = false);
// *day = vec![false; 10];
}
// lim.write().limitations[day][hour] = !row;
});
}
super::SubPage::Classes => {
let lims = &*classes_limitations();
let lim = Arc::clone(lims);
std::thread::spawn(move || {
let lims = &mut lim.write();
let lims = &mut lims
.get_mut(&selected_class().read().unwrap())
.unwrap()
.limitations;
if lims.iter().any(|h| !h[hour]) {
lims.iter_mut().for_each(|d| d[hour] = true);
} else {
lims.iter_mut().for_each(|d| d[hour] = false);
}
});
}
}
});
}
pub fn save_teachers_limitations() {
spawn(move || {
let lims = &*teachers_limitations().read();
let lims = lims.values().collect::<Vec<&TeacherLimitation>>();
let mut f = File::create("./db/teachers_limitations.json").unwrap();
f.write_all(serde_json::to_string(&lims).unwrap().as_bytes())
.unwrap();
*available_days().write() = create_available_days();
});
}
pub fn save_classes_limitations() {
let lims = &*classes_limitations().read();
let lims = lims.values().collect::<Vec<&ClassLimitation>>();
let mut f = File::create("./db/classes_limitations.json").unwrap();
f.write_all(serde_json::to_string(&lims).unwrap().as_bytes())
.expect("Sınıf Kısıtları Yazılamadı");
}
fn change_row(day: usize, hour: usize) {
std::thread::spawn(move || {
let page = &*get_page().read();
match page {
SubPage::Teachers => {
let c_id = selected_teacher().read().unwrap();
let mut lims = teachers_limitations().write();
let row = lims.get_mut(&c_id);
if let Some(r) = row {
r.limitations[day][hour] = !r.limitations[day][hour];
}
}
SubPage::Classes => {
let c_id = selected_class().read().unwrap();
let mut lims = classes_limitations().write();
let row = lims.get_mut(&c_id);
if let Some(r) = row {
r.limitations[day][hour] = !r.limitations[day][hour];
}
}
}
});
}
fn change_all() {
let page = get_page();
match &*page.read() {
SubPage::Teachers => {
change_all_teachers();
}
SubPage::Classes => {
change_all_classes();
}
}
}
fn change_all_teachers() {
let t_id = selected_teacher().read().unwrap();
let teachers_lims = teachers_limitations().read().clone();
let t_lims = teachers_lims.get(&t_id).unwrap().clone();
std::thread::spawn(move || {
let t_lims = t_lims.clone();
let teachers = &*get_teachers().read();
for t in teachers {
let lims = &mut *teachers_limitations().write();
if let Some(lims) = lims.get_mut(&t.1.id) {
lims.limitations = t_lims.limitations.clone();
}
}
});
}
fn change_all_classes() {
let c_id = selected_class().read().unwrap();
let classes_lims = classes_limitations().read().clone();
let c_lims = classes_lims.get(&c_id).unwrap().clone();
std::thread::spawn(move || {
let c_lims = c_lims.clone();
let classes = &*get_classes().read();
for c in classes {
let lims = &mut *classes_limitations().write();
if let Some(lims) = lims.get_mut(&c.1.id) {
lims.limitations = c_lims.limitations.clone();
}
}
});
}
use std::{
collections::HashMap,
fs::File,
io::{Read, Write},
sync::{Arc, OnceLock},
};
use eframe::egui::{self, mutex::RwLock, Color32, Label, RichText, Sense, Stroke, Vec2};
use serde::{Deserialize, Serialize};
use crate::{
tabs::{
activities::{activities, get_lec_short_name, get_teachers_short_name, Activity},
classes::{get_classes, selected_class, set_selected_class},
generating::Schedule,
},
DAYS,
};
use super::save_classes_limitations;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ClassLimitation {
pub class_id: i32,
pub limitations: Vec<Vec<bool>>,
}
impl ClassLimitation {
pub fn new(id: i32) -> Self {
Self {
class_id: id,
limitations: vec![vec![true; 10]; 7],
}
}
}
pub fn classes_limitations() -> &'static Arc<RwLock<HashMap<i32, ClassLimitation>>> {
static PAGE: OnceLock<Arc<RwLock<HashMap<i32, ClassLimitation>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(get_class_limitations())))
}
pub fn schedules() -> &'static Arc<RwLock<Vec<Schedule>>> {
static PAGE: OnceLock<Arc<RwLock<Vec<Schedule>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(vec![])))
}
pub fn get_class_limitations() -> HashMap<i32, ClassLimitation> {
let lims = File::open("./db/classes_limitations.json");
if let Ok(mut lims) = lims {
let mut content: String = String::new();
lims.read_to_string(&mut content).unwrap();
let cls: Vec<ClassLimitation> = serde_json::from_str(content.as_str()).unwrap();
let mut lims: HashMap<i32, ClassLimitation> = HashMap::new();
for c in cls {
lims.insert(c.class_id, c);
}
return lims;
}
HashMap::new()
}
type ClassSched = Arc<RwLock<HashMap<i32, Vec<Vec<Option<Activity>>>>>>;
pub fn class_sched() -> &'static ClassSched {
static ACT: OnceLock<ClassSched> = OnceLock::new();
ACT.get_or_init(|| Arc::new(RwLock::new(HashMap::new())))
}
pub fn class_limitation() -> &'static Arc<RwLock<ClassLimitation>> {
static LIM: OnceLock<Arc<RwLock<ClassLimitation>>> = OnceLock::new();
LIM.get_or_init(|| Arc::new(RwLock::new(ClassLimitation::default())))
}
pub fn create_sched(id: i32) {
// let id = selected_class().read().unwrap();
let class_acts = activities()
.read()
.iter()
.filter(|a| a.1.classes.iter().any(|c| c == &id))
.map(|a| a.1.clone())
.collect::<Vec<Activity>>();
// let mut scheds = vec![];
let scs = (*schedules().read()).clone();
let sched = scs
.iter()
.filter(|s| class_acts.iter().any(|a| a.id == s.activity))
.map(|s| s.clone())
.collect::<Vec<Schedule>>();
let mut scheduls: Vec<Vec<Option<Activity>>> = vec![vec![None; 10]; 7];
sched.iter().for_each(|s| {
scheduls[s.day_id as usize - 1][s.hour as usize] = class_acts
.clone()
.into_iter()
.find(|ca| ca.id == s.activity);
});
std::thread::spawn(move || {
let c_sched = Arc::clone(class_sched());
c_sched.write().insert(id, scheduls);
});
}
pub fn save_class_limitations() {
let lims = &*classes_limitations().read();
let lims = lims.values().collect::<Vec<&ClassLimitation>>();
let mut f = File::create("./db/classes_limitations.json").unwrap();
f.write_all(serde_json::to_string(&lims).unwrap().as_bytes())
.expect("Kısıtlamalar Yazılamadı");
}
pub fn update_class_limitation() {
let class_lims = &*class_limitation().read();
let mut lims = classes_limitations().write();
let id = selected_class().read().unwrap();
lims.insert(id, class_lims.clone());
}
pub fn class_lim_ui(ui: &mut egui::Ui) {
for c in &*get_classes().read() {
create_sched(c.1.id);
}
egui::SidePanel::left("right_panel")
.resizable(true)
.default_width(250.0)
.width_range(150.0..=300.0)
.show_inside(ui, |ui| {
ui.vertical_centered(|ui| {
let class_id = selected_class().read();
let mut classes = get_classes().write();
for c in &mut *classes {
let fill_color = if class_id.is_some_and(|c2| c2 == c.1.id) {
Color32::LIGHT_BLUE
} else {
Color32::default()
};
let stroke_color = if class_id.is_some_and(|c2| c2 == c.1.id) {
Color32::DARK_BLUE
} else {
Color32::default()
};
let button = egui::Frame::none()
.fill(fill_color)
.stroke(Stroke::new(1., stroke_color))
.show(ui, |ui| {
ui.label(&c.1.name);
})
.response;
let button = button
.interact(egui::Sense::click())
.on_hover_cursor(egui::CursorIcon::PointingHand);
if button.clicked() {
set_selected_class(c.1.id);
}
}
});
});
egui::CentralPanel::default()
// .resizable(true)
// .default_width(1024.0)
// .width_range(800.0..=1280.0)
.show_inside(ui, |ui| {
class_limitation_ui(ui);
});
}
fn class_limitation_ui(ui: &mut egui::Ui) {
if let None = *selected_class().read() {
return ();
}
// ui.set_width(1024.)
let class_id = selected_class().read().unwrap();
let c_sched = class_sched().read();
let c_sched = c_sched.get(&class_id);
if let Some(c_sched) = c_sched {
ui.add_space(50.);
ui.horizontal(|ui| {
ui.add_space(100.);
egui::Grid::new("some_unique_id")
.min_col_width(100.)
.max_col_width(100.)
.min_row_height(100.)
// .with_row_color(100.)
.spacing((1.0, 1.0))
.show(ui, |ui| {
hours_row(ui);
ui.end_row();
days_row(ui, c_sched);
});
ui.end_row();
});
ui.vertical_centered(|ui| {
ui.add_space(20.);
if ui.button("Kaydet").clicked() {
update_class_limitation();
};
if ui.button("Tümünü dosyaya Kaydet").clicked() {
save_classes_limitations();
};
});
}
}
fn days_row(ui: &mut egui::Ui, c_sched: &Vec<Vec<Option<Activity>>>) {
for day in DAYS.iter().enumerate() {
ui.painter().rect(
ui.available_rect_before_wrap(),
0.0,
Color32::default(),
Stroke::new(1.0, Color32::LIGHT_GRAY),
);
if ui
.add_sized(Vec2::new(100., 50.), Label::new(*day.1))
.interact(Sense::click())
.clicked()
{
change_all_day(day.0);
};
for i in 1..=10 {
row_paint(ui, day.0, i - 1);
let r = ui.add_sized(
Vec2::new(100., 50.),
Label::new(sched_act(&c_sched[day.0][i - 1])),
);
let r = r
.interact(Sense::click())
.on_hover_cursor(egui::CursorIcon::PointingHand);
if r.clicked() {
change_row(day.0, i - 1);
}
}
ui.end_row();
}
}
fn hours_row(ui: &mut egui::Ui) {
ui.painter().rect(
ui.available_rect_before_wrap(),
0.0,
Color32::default(),
Stroke::new(1.0, Color32::LIGHT_GRAY),
);
ui.label("Günler ve Saatler");
for i in 1..=10 {
ui.painter().rect(
ui.available_rect_before_wrap(),
0.0,
Color32::default(),
Stroke::new(1.0, Color32::LIGHT_GRAY),
);
if ui
.add_sized(
Vec2::new(100., 50.),
Label::new(RichText::new(format!("{i}. Saat")).color(Color32::WHITE)),
)
.interact(Sense::click())
.clicked()
{
change_all_hours(i - 1);
};
}
}
fn row_paint(ui: &mut egui::Ui, day: usize, hour: usize) {
let lims = &*class_limitation().read().limitations;
if lims[day][hour] {
ui.painter()
.rect_filled(ui.available_rect_before_wrap(), 0.0, Color32::BROWN);
}
ui.painter().rect(
ui.available_rect_before_wrap(),
0.0,
Color32::default(),
Stroke::new(1., Color32::WHITE),
);
}
fn change_row(day: usize, hour: usize) {
let lims = &*class_limitation();
std::thread::spawn(move || {
let lim = Arc::clone(lims);
let row = lim.read().limitations[day][hour];
lim.write().limitations[day][hour] = !row;
});
}
fn sched_act(a: &Option<Activity>) -> String {
let Some(a) = a else {
return "".to_string();
};
let mut activity = a.id.to_string();
activity.push_str("-");
activity.push_str(&get_lec_short_name(a.lecture));
activity.push_str("\n");
// activity.push_str(&get_classes_name(&a.classes));
activity.push_str(&get_teachers_short_name(&a.teachers));
activity
}
fn change_all_day(day: usize) {
let lims = &*class_limitation();
std::thread::spawn(move || {
let lim = Arc::clone(lims);
let day = &mut lim.write().limitations[day];
if day.iter().any(|h| !*h) {
*day = vec![true; 10];
} else {
*day = vec![false; 10];
}
// lim.write().limitations[day][hour] = !row;
});
}
fn change_all_hours(hour: usize) {
let lims = &*class_limitation();
std::thread::spawn(move || {
let lim = Arc::clone(lims);
let day = &mut lim.write().limitations;
if day.iter().any(|h| !h[hour]) {
day.iter_mut().for_each(|d| d[hour] = true);
} else {
day.iter_mut().for_each(|d| d[hour] = false);
// *day = vec![false; 10];
}
// lim.write().limitations[day][hour] = !row;
});
}
use eframe::egui;
use eframe::egui::mutex::RwLock;
use eframe::egui::vec2;
use eframe::egui::Align2;
use eframe::egui::Button;
use eframe::egui::Color32;
use eframe::egui::Label;
use eframe::egui::Link;
use eframe::egui::RichText;
use eframe::egui::Stroke;
use eframe::egui::TextEdit;
use egui::TextBuffer;
// use eframe::Frame;
use egui_flex::item;
use egui_flex::Flex;
use serde::Deserialize;
use serde::Serialize;
use std::collections::BTreeMap;
use std::fmt::Display;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::iter::zip;
use std::sync::Arc;
use std::sync::OnceLock;
use super::activities::activities;
use super::activities::activity_form::filtered_lectures;
use super::activities::activity_form::filtering_lectures;
use super::activities::activity_form::lectures_ui::set_lecture_filter;
use super::activities::save_activities;
use super::activities::Activity;
use super::classes::get_classes;
#[derive(Clone, Serialize, Deserialize, Debug, Default)]
pub struct Lecture {
pub id: i32,
pub name: String,
pub short_name: String,
}
impl Display for Lecture {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}
pub fn lec_del_states() -> &'static Arc<RwLock<Vec<bool>>> {
static LECTURES: OnceLock<Arc<RwLock<Vec<bool>>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(vec![false; filtered_lectures().read().len()])))
}
pub fn create_states() -> Vec<bool> {
vec![false; filtered_lectures().read().len()]
}
pub fn class_lectures() -> &'static Arc<RwLock<BTreeMap<i32, Vec<Lecture>>>> {
static LECTURES: OnceLock<Arc<RwLock<BTreeMap<i32, Vec<Lecture>>>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(create_class_lectures())))
}
pub fn not_class_lectures() -> &'static Arc<RwLock<BTreeMap<i32, Vec<Lecture>>>> {
static LECTURES: OnceLock<Arc<RwLock<BTreeMap<i32, Vec<Lecture>>>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(not_create_class_lectures())))
}
pub fn get_lectures() -> &'static Arc<RwLock<BTreeMap<i32, Lecture>>> {
static LECTURES: OnceLock<Arc<RwLock<BTreeMap<i32, Lecture>>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(read_lectures())))
}
pub fn lec_name() -> &'static Arc<RwLock<String>> {
static NAME: OnceLock<Arc<RwLock<String>>> = OnceLock::new();
NAME.get_or_init(|| Arc::new(RwLock::new("".to_string())))
}
pub fn selected_lec() -> &'static Arc<RwLock<i32>> {
static NAME: OnceLock<Arc<RwLock<i32>>> = OnceLock::new();
NAME.get_or_init(|| Arc::new(RwLock::new(-1)))
}
pub fn lec_short_name() -> &'static Arc<RwLock<String>> {
static SHORT_NAME: OnceLock<Arc<RwLock<String>>> = OnceLock::new();
SHORT_NAME.get_or_init(|| Arc::new(RwLock::new("".to_string())))
}
fn update_lec_form() -> &'static Arc<RwLock<bool>> {
static SHORT_NAME: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
SHORT_NAME.get_or_init(|| Arc::new(RwLock::new(false)))
}
fn update_lec(ui: &mut eframe::egui::Ui) {
egui::Window::new("Update Lecture")
.open(&mut *update_lec_form().write())
.resizable([true, true])
.show(ui.ctx(), |ui| {
ui.add(TextEdit::singleline(&mut *lec_name().write()));
ui.add(TextEdit::singleline(&mut *lec_short_name().write()));
if ui.add(Button::new("Güncelle")).clicked() {
if let Some(t) = get_lectures().write().get_mut(&selected_lec().read()) {
t.name = lec_name().read().clone();
t.short_name = lec_short_name().read().clone();
save_lectures();
lec_name().write().clear();
lec_short_name().write().clear();
set_lecture_filter();
*update_lec_form().write() = false;
}
}
});
}
pub fn lectures_page(ui: &mut eframe::egui::Ui) {
// let mut name = get_name().lock().unwrap();
ui.vertical_centered(|ui| {
if ui
.add_sized(
vec2(250., 30.),
TextEdit::singleline(&mut *lec_name().write()).hint_text("Ders Adını Gir"),
)
.changed()
{
set_lecture_filter();
};
ui.add_sized(
vec2(250., 30.),
TextEdit::singleline(&mut *lec_short_name().write()).hint_text("Kısa Adı"),
);
if ui.add_sized(vec2(250., 30.), Button::new("Ekle")).clicked() {
add_lec();
}
});
ui.separator();
lectures_ui(ui);
}
fn add_lec() {
let new_id = find_new_id();
let new_lec = Lecture {
id: new_id,
name: lec_name().write().clone(),
short_name: lec_short_name().write().clone(),
};
std::thread::spawn(move || {
let lecs = get_lectures();
lecs.write().insert(new_id, new_lec);
*lec_name().write() = "".to_string();
*lec_short_name().write() = "".to_string();
set_lecture_filter();
*filtered_lectures().write() = filtering_lectures();
save_lectures();
lec_del_states().write().push(false);
});
}
fn lectures_ui(ui: &mut eframe::egui::Ui) {
update_lec(ui);
Flex::horizontal()
// .grow_items(1.)
.wrap(true)
.gap(vec2(20., 20.))
.show(ui, |flex| {
let del_states = lec_del_states().read().clone();
let del_states = del_states.iter().enumerate();
for (del_state, lecture) in zip(del_states, filtered_lectures().read().iter()) {
let frame = egui::Frame::default()
.stroke(Stroke::new(0.3, Color32::GRAY))
.rounding(5.)
.inner_margin(10.);
flex.add_flex(
item().grow(1.).frame(frame),
Flex::vertical().align_items_content(Align2::CENTER_TOP),
|flex| {
flex.add(item(), Label::new(&lecture.name));
if *del_state.1 {
flex.add_flex(
item().grow(1.),
Flex::horizontal().align_items(egui_flex::FlexAlign::Center),
|flex| {
if flex
.add(
item().grow(1.),
Link::new(
RichText::new("Sil").color(Color32::LIGHT_RED),
),
)
// .inner
.clicked()
{
del_lecture(lecture.id);
};
if flex
.add(item().grow(1.), Link::new("Vazgeç"))
// .inner
.clicked()
{
change_state(del_state.0);
};
},
);
} else {
if flex
.add(
item(),
Link::new(RichText::new("Sil").color(Color32::DARK_RED)),
)
// .inner
.clicked()
{
change_state(del_state.0);
}
if flex.add(item(), Link::new("Düzenle")).clicked() {
let c = lecture.clone();
*selected_lec().write() = c.id;
std::thread::spawn(move || {
*lec_name().write() = c.name.clone();
*lec_short_name().write() = c.short_name.clone();
*update_lec_form().write() = true;
});
}
}
},
);
}
});
}
fn change_state(state: usize) {
std::thread::spawn(move || {
if let Some(st) = lec_del_states().write().get_mut(state) {
*st = !*st;
}
});
}
fn save_lectures() {
std::thread::spawn(move || {
let lectures = get_lectures().read();
let js = serde_json::to_string(&*lectures);
match js {
Ok(j) => {
let mut f = File::create("./db/lectures.json").unwrap();
f.write_all(j.as_bytes()).unwrap();
}
Err(_) => {}
}
});
}
fn read_lectures() -> BTreeMap<i32, Lecture> {
let f = File::open("./db/lectures.json");
if let Ok(mut f) = f {
let mut content: String = String::new();
f.read_to_string(&mut content).unwrap();
let cls: BTreeMap<i32, Lecture> = serde_json::from_str(content.as_str()).unwrap();
return cls;
}
BTreeMap::new()
}
fn create_class_lectures() -> BTreeMap<i32, Vec<Lecture>> {
let mut map = BTreeMap::new();
let cls = get_classes().read();
let acts = &*activities().read();
let lecs = get_lectures()
.read()
.values()
.map(|l| l.clone())
.collect::<Vec<Lecture>>();
for c in &*cls {
let c_acts = acts
.values()
.filter(|a| a.classes.iter().any(|ac| ac == &c.1.id))
.map(|a| a.clone())
.collect::<Vec<Activity>>();
let lec = &lecs
.iter()
.filter(|l| c_acts.iter().any(|a| a.lecture == l.id))
.map(|l| l.clone())
.collect::<Vec<Lecture>>();
map.insert(c.1.id, lec.clone());
}
map
}
fn not_create_class_lectures() -> BTreeMap<i32, Vec<Lecture>> {
let mut map = BTreeMap::new();
let cls = get_classes().read();
// let acts = &*activities().read();
let lecs = get_lectures()
.read()
.values()
.map(|l| l.clone())
.collect::<Vec<Lecture>>();
let c_lecs = class_lectures().read().clone();
for c in &*cls {
let c_lecs = c_lecs.get(&c.1.id);
if let Some(cl) = c_lecs {
let mut l = lecs.clone();
l.retain(|l| !cl.iter().any(|cl| cl.id == l.id));
map.insert(c.1.id, l.clone());
} else {
map.insert(c.1.id, lecs.clone());
}
// let lec = &lecs.retain(|l| class_lectures().read().values().any(|cl| cl. =))
// map.insert(c.1.id, lec.clone());
}
map
}
fn del_lecture(id: i32) {
let lectures = get_lectures().clone();
let cls = Arc::clone(&lectures);
std::thread::spawn(move || {
cls.write().remove(&id);
save_lectures();
*filtered_lectures().write() = filtering_lectures();
*lec_del_states().write() = create_states();
let acts = &mut *activities().write();
acts.retain(|_a, b| b.lecture != id);
save_activities();
});
}
fn find_new_id() -> i32 {
let len = get_lectures().read().len() as i32;
for i in 1..len + 1 {
if !get_lectures().read().contains_key(&i) {
return i;
}
}
len + 1
}
use floem::{
reactive::{create_rw_signal, create_signal},
text,
views::{container, text_input, v_stack},
IntoView,
};
pub fn homepage() -> impl IntoView {
let name = create_rw_signal("".to_string());
container(v_stack((text_input(name),)))
}
use std::{
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
sync::{Arc, OnceLock},
thread::sleep,
time::Duration,
};
use activities::activities;
use eframe::{egui::mutex::RwLock, glow::MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS};
use rand::{seq::SliceRandom, thread_rng};
use serde::{Deserialize, Serialize};
use super::{
activities::{self, partnered_act, selected_act, Activity},
classes::{get_classes, validates_c_lims, validates_t_lims, Class},
generate::{
continued, create_total_hours, generating, multi_thread, recalc_sched, total_hours,
},
get_school,
limitations::limitations_ui::{
classes_sched, create_classes_sched, create_teachers_sched, get_class_limitations,
get_teacher_limitations, schedules, teachers_limitations, teachers_scheds, update_tt,
ClassLimitation, TeacherLimitation,
},
school_hour,
teachers::{get_teachers, Teacher},
};
pub fn act_total_teachers() -> &'static Arc<RwLock<HashMap<i32, Vec<i32>>>> {
static STOP: OnceLock<Arc<RwLock<HashMap<i32, Vec<i32>>>>> = OnceLock::new();
STOP.get_or_init(|| Arc::new(RwLock::new(create_act_total_teachers())))
}
fn create_act_total_teachers() -> HashMap<i32, Vec<i32>> {
let acts = activities().read().clone();
let mut map = HashMap::new();
for act in &acts {
let mut v = act.1.teachers.clone();
for a in &act.1.partners {
if let Some(a) = acts.get(&a) {
v.append(&mut a.teachers.clone())
};
}
map.insert(act.1.id, v);
}
map
}
pub fn act_total_classes() -> &'static Arc<RwLock<HashMap<i32, Vec<i32>>>> {
static STOP: OnceLock<Arc<RwLock<HashMap<i32, Vec<i32>>>>> = OnceLock::new();
STOP.get_or_init(|| Arc::new(RwLock::new(create_act_total_classes())))
}
pub fn available_days() -> &'static Arc<RwLock<HashMap<i32, Vec<(usize, Vec<usize>)>>>> {
static STOP: OnceLock<Arc<RwLock<HashMap<i32, Vec<(usize, Vec<usize>)>>>>> = OnceLock::new();
STOP.get_or_init(|| Arc::new(RwLock::new(create_available_days())))
}
pub fn conflict_acts() -> &'static Arc<RwLock<HashSet<i32>>> {
static STOP: OnceLock<Arc<RwLock<HashSet<i32>>>> = OnceLock::new();
STOP.get_or_init(|| Arc::new(RwLock::new(HashSet::new())))
}
pub fn create_available_days() -> HashMap<i32, Vec<(usize, Vec<usize>)>> {
let acts = activities().read();
let mut map = HashMap::new();
let hour = get_school().read().hour;
for a in &*acts {
let mut days = vec![];
for i in 0..7 {
let mut hours = vec![];
for h in (0..hour).rev() {
if a.1.teachers_available(h, i) && a.1.classes_available(h, i) {
hours.push(h);
}
}
if !hours.is_empty() {
days.push((i, hours));
}
}
map.insert(*a.0, days);
}
map
}
// fn started() -> &'static Arc<RwLock<bool>> {
// static STOP: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
// STOP.get_or_init(|| Arc::new(RwLock::new(false)))
// }
fn create_act_total_classes() -> HashMap<i32, Vec<i32>> {
let acts = activities().read().clone();
let mut map = HashMap::new();
for act in &acts {
let mut v = act.1.classes.clone();
for a in &act.1.partners {
if let Some(a) = acts.get(&a) {
v.append(&mut a.classes.clone())
};
}
map.insert(act.1.id, v);
}
map
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(crate = "serde")]
pub struct Schedule {
pub day_id: usize,
pub hour: usize,
pub activity: i32,
pub locked: bool,
}
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
#[serde(crate = "serde")]
pub struct Params {
pub hour: usize,
pub depth: usize,
pub depth2: usize,
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(crate = "serde")]
pub struct TimetableData {
pub tat: HashMap<i32, TeacherLimitation>,
pub cat: HashMap<i32, ClassLimitation>,
pub clean_tat: HashMap<i32, TeacherLimitation>,
pub clean_cat: HashMap<i32, ClassLimitation>,
pub acts: Vec<Activity>,
pub teachers_acts: HashMap<i32, Vec<Activity>>,
pub neighbour_acts: HashMap<i32, HashSet<i32>>,
pub classes: BTreeMap<i32, Class>,
pub teachers: BTreeMap<i32, Teacher>,
pub timetables: HashMap<i32, Vec<Schedule>>,
pub school_hour: usize,
pub not_placed_acts: HashSet<i32>,
}
// fn cpu_nums() -> &'static Arc<RwLock<u8>> {
// static STOP: OnceLock<Arc<RwLock<u8>>> = OnceLock::new();
// STOP.get_or_init(|| Arc::new(RwLock::new(0)))
// }
impl TimetableData {
// fn generate_multi(&mut self, params: &Params, act: &Activity) -> bool {
// let cpus = 3;
// *started().write() = false;
// drop(started().write());
// let ac_dt = Arc::new(RwLock::new(self.clone()));
// // drop(start);
// for _ in 0..cpus {
// let a = act.clone();
// let p = params.clone();
// let ac_clone = Arc::clone(&ac_dt);
// // if *cond_rec.read() {
// // break;
// // }
// std::thread::spawn(move || {
// let s = ac_clone
// .write()
// .recursive_put(&a.clone(), 0, &a.clone(), &p.clone());
// if s {
// // *started().write() = true;
// // drop(started().write());
// // let l = data().read().timetables.len();
// // if ac_clone.read().timetables.len() > l {
// *data().write() = ac_clone.read().clone();
// // }
// }
// });
// }
// if self.timetables.len() < data().read().timetables.len() {
// *self = data().read().clone();
// return true;
// }
// return false;
// }
pub fn generate(&mut self, params: &mut Params) -> bool {
// println!("{}", self.not_placed_acts.len());
let mut act = self.not_placed_acts.iter();
let Some(act) = act.next() else {
return true;
};
let acts = activities().read();
let Some(act) = acts.get(&act) else {
return false;
};
*selected_act().write() = act.id;
let available = self.find_timeslot(act, params);
match available {
Some(slots) => {
self.put_act(slots.0, slots.1, act, false);
return true;
}
None => {
let mut s_c = self.clone();
// if *multi_thread().read() {
// if s_c.generate_multi(params, act) {
// *self = s_c;
// return true;
// };
conflict_acts().write().clear();
if s_c.recursive_put(act, 0, &act, params) {
*self = s_c;
return true;
}
// let mut days = create_available_days();
// days.iter_mut().for_each(|d| d.1.shuffle(&mut thread_rng()));
// *available_days().write() = days;
self.not_placed_acts = HashSet::from_iter(
self.acts
.clone()
.into_iter()
.filter(|a| !a.teachers.is_empty() && self.timetables.get(&a.id).is_none())
.map(|a| a.id),
);
let conflict_acts = self.find_conflict_activity(act, &act, params);
if conflict_acts.is_empty() {
return false;
}
for a in &conflict_acts[0] {
self.delete_activity(a);
}
if let Some(slots) = self.find_timeslot(act, params) {
self.put_act(slots.0, slots.1, act, false);
}
// for a in &conflict_acts[0] {
// if let Some(slots) = self.find_timeslot(a, params) {
// self.put_act(slots.0, slots.1, a);
// }
// }
return true;
}
}
}
pub fn replace_act(&mut self, day: usize, hour: usize, act_id: i32, act_hour: usize) {
let tt = &mut self.timetables;
let scheds = &*schedules().write().clone();
let ng = self.neighbour_acts.get(&act_id);
if let Some(ng) = ng {
let acts = scheds
.iter()
.filter(|s| s.day_id == day && ng.iter().any(|a| a == &s.activity))
.collect::<Vec<&Schedule>>();
println!("{acts:?}");
for h in hour..hour + act_hour {
if let Some(s) = acts.iter().find(|a| a.hour == h) {
tt.remove(&s.activity);
};
}
update_tt();
}
}
pub fn find_timeslot(&self, act: &Activity, params: &Params) -> Option<(usize, usize)> {
let days = available_days().read().clone();
let days = days.get(&act.id).unwrap();
if self.tat.len() == 0 {
validates_c_lims();
validates_t_lims();
return None;
}
// days.shuffle(&mut thread_rng());
// let hour_lim = self.school_hour - act.hour as usize + 1;
for day in days {
for hour in &day.1 {
if self.teachers_available(act, *hour, day.0)
&& self.classes_available(act, *hour, day.0)
&& (
//act.teachers.is_empty()
act.no_limit || self.same_day_available(act, *hour, day.0, params)
)
{
// println!("{:?} {}", day, hour);
return Some((day.0, *hour));
}
}
}
None
}
fn same_day_available(&self, act: &Activity, hour: usize, day: usize, params: &Params) -> bool {
if let Some(teacher_acts) = self.teachers_acts.get(&act.id) {
let mut same_day_acts = vec![];
for a in teacher_acts {
if !a.no_limit {
if let Some(s) = self.timetables.get(&a.id) {
same_day_acts.append(&mut s.clone());
// return false;
}
}
}
let same_day_acts: Vec<&Schedule> =
same_day_acts.iter().filter(|t| t.day_id == day).collect();
if same_day_acts.len() == 0 {
return true;
} else if (act.hour + same_day_acts.len()) > params.hour {
return false;
} else {
let hours = same_day_acts
.iter()
.cloned()
.find(|t| hour > 0 && t.hour == (hour - 1) || t.hour == (hour + act.hour));
if hours.is_some() {
return true;
}
return false;
}
}
true
}
fn classes_available(&self, act: &Activity, hour: usize, day: usize) -> bool {
let mut classes_availables = vec![];
let act_classes = act_total_classes().read();
let Some(classes) = act_classes.get(&act.id) else {
return false;
};
for class in classes {
let class = self.cat.get(class);
if let Some(c) = class {
classes_availables.push(c.limitations[day].clone());
}
}
(hour..hour + act.hour as usize).all(|h| classes_availables.iter().all(|ca| ca[h]))
}
fn teachers_available(&self, act: &Activity, hour: usize, day: usize) -> bool {
let mut teachers_availables = vec![];
let act_teachers = act_total_teachers().read();
let Some(teachers) = act_teachers.get(&act.id) else {
return false;
};
for teacher in teachers {
let teacher = self.tat.get(teacher);
if let Some(t) = teacher {
teachers_availables.push(t.limitations[day].clone());
}
}
(hour..hour + act.hour as usize).all(|h| teachers_availables.iter().all(|ta| ta[h]))
}
pub fn put_act(&mut self, day: usize, hour: usize, act: &Activity, lock: bool) {
for timetable in hour..hour + act.hour as usize {
let tt = Schedule {
day_id: day,
hour: timetable,
activity: act.id,
locked: lock,
};
let act_teachers = act_total_teachers().read();
if let Some(teachers) = act_teachers.get(&act.id) {
for teacher in teachers {
if let Some(tat) = self.tat.get_mut(teacher) {
if let Some(tat_index) = tat.limitations.get_mut(tt.day_id) {
tat_index[tt.hour as usize] = false;
}
}
}
}
let act_classes = act_total_classes().read();
if let Some(classes) = act_classes.get(&act.id) {
for class in classes {
if let Some(cat) = self.cat.get_mut(class) {
if let Some(cat_index) = cat.limitations.get_mut(tt.day_id) {
cat_index[tt.hour] = false;
}
}
}
}
if let Some(timetables) = self.timetables.get_mut(&act.id) {
timetables.push(tt);
} else {
self.timetables.insert(act.id, vec![tt.clone()]);
}
}
self.not_placed_acts.remove(&act.id);
}
pub fn delete_activity(&mut self, act: &Activity) {
let tt = self.timetables.get(&act.id).unwrap();
for t in tt {
let act_teachers = act_total_teachers().read();
if let Some(teachers) = act_teachers.get(&act.id) {
for teacher in teachers {
if let Some(tat) = self.tat.get_mut(teacher) {
if let Some(tat_index) = tat.limitations.get_mut(t.day_id) {
tat_index[t.hour as usize] = true;
}
}
}
}
let act_classes = act_total_classes().read();
if let Some(classes) = act_classes.get(&act.id) {
for class in classes {
if let Some(cat) = self.cat.get_mut(class) {
if let Some(cat_index) = cat.limitations.get_mut(t.day_id) {
cat_index[t.hour as usize] = true;
}
}
}
}
}
self.not_placed_acts.insert(act.id);
self.timetables.remove(&act.id);
//self.timetables.retain(|t| t.activity != act.id);
}
fn find_conflict_activity(
&self,
act: &Activity,
ignores: &Activity,
params: &Params,
) -> Vec<Vec<Activity>> {
//let now = instant::Instant::now();
let mut total_act: Vec<Vec<Activity>> = Vec::new();
let acts = self.neighbour_acts.get(&act.id).unwrap();
let days = &*available_days().read();
let days = days.get(&act.id).unwrap();
for day in days {
for h in &day.1 {
let mut less_conflict: HashSet<Activity> = HashSet::new();
for i in *h..*h + act.hour as usize {
for a in acts {
if let Some(s) = self.timetables.get(&a) {
let sa = s.iter().find(|t| {
t.day_id == day.0 && t.hour as usize == i && !t.locked
// && ignores.id != t.activity
});
if let Some(s) = sa {
if let Some(a) = activities().read().get(&s.activity) {
less_conflict.insert(a.clone());
};
};
}
}
}
if !less_conflict.is_empty() {
total_act.push(Vec::from_iter(less_conflict));
}
}
}
total_act.shuffle(&mut thread_rng());
if total_act.len() >= params.depth {
return total_act[..params.depth].to_vec();
}
total_act
}
pub(crate) fn recursive_put(
&mut self,
act: &Activity,
depth: usize,
ignores: &Activity,
params: &Params,
) -> bool {
let mut conflict_acts = self.find_conflict_activity(act, ignores, params);
let mut okey2 = false;
let tat2 = self.tat.clone();
let not_placed_acts = self.not_placed_acts.clone();
let cat2 = self.cat.clone();
let timetables2 = self.timetables.clone();
for c_act in &mut conflict_acts {
for a in &*c_act {
self.delete_activity(a);
}
c_act.sort_by(|a, b| a.hour.cmp(&b.hour));
c_act.push(act.clone());
//ignore_list.append(&mut c_act.clone());
let mut okey = true;
for a in c_act.iter().rev() {
let available = self.find_timeslot(a, params);
match available {
Some(slots) => {
self.put_act(slots.0, slots.1, a, false);
}
None => {
if depth < params.depth2 {
let rec_result = self.recursive_put(a, depth + 1, ignores, params);
if !rec_result {
okey = false;
break;
}
} else {
okey = false;
break;
}
}
}
}
if okey {
okey2 = true;
//ignore_list.retain(|a3| a3.id != act.id);
break;
} else {
self.tat = tat2.to_owned();
self.cat = cat2.to_owned();
self.timetables = timetables2.to_owned();
self.not_placed_acts = not_placed_acts.to_owned();
}
}
okey2
}
fn validate_tt(&mut self) {
self.clean_cat = get_class_limitations();
self.clean_tat = get_teacher_limitations();
self.tat = self.clean_tat.clone();
self.cat = self.clean_cat.clone();
let tt_c = self.timetables.clone();
self.timetables.clear();
schedules().write().clear();
teachers_scheds().write().clear();
classes_sched().write().clear();
self.not_placed_acts = self.acts.iter().map(|a| a.id.clone()).collect();
for tt in &tt_c {
let act = self
.acts
.clone()
.into_iter()
.find(|a| a.id == *tt.0)
.unwrap();
if self.teachers_available(&act, tt.1[0].hour as usize, tt.1[0].day_id)
&& self.classes_available(&act, tt.1[0].hour as usize, tt.1[0].day_id)
&& (act.no_limit
|| self.same_day_available(
&act,
tt.1[0].hour as usize,
tt.1[0].day_id,
&Params {
hour: 2,
depth: 0,
depth2: 0,
},
))
{
self.put_act(tt.1[0].day_id, tt.1[0].hour as usize, &act, tt.1[0].locked);
} else {
// self.delete_activity(&act);
}
}
let mut sch = vec![];
self.timetables
.values()
.for_each(|tt| sch.append(&mut tt.clone()));
*schedules().write() = sch.clone();
*teachers_scheds().write() = create_teachers_sched();
*classes_sched().write() = create_classes_sched();
*data().write() = self.clone();
}
}
pub fn create_data() -> TimetableData {
// create_acts_data();
let clean_tat = get_teacher_limitations();
let tat = get_teacher_limitations();
let clean_cat = get_class_limitations();
let cat = get_class_limitations();
let mut acts = (*activities().read())
.clone()
.values()
.filter(|a| partnered_act().read().get(&a.id).is_none())
.map(|a| a.clone())
.collect::<Vec<Activity>>();
acts.shuffle(&mut thread_rng());
acts.sort_by(|a, b| a.hour.cmp(&b.hour));
let not_placed_acts = acts.iter().map(|a| a.id).collect();
let hour = &*school_hour().read();
let h = hour.parse::<usize>().unwrap_or(8);
let timetables = HashMap::new();
let dt = TimetableData {
tat,
cat,
clean_cat,
clean_tat,
acts,
teachers_acts: create_teachers_acts(),
neighbour_acts: create_ng(),
classes: get_classes().read().clone(),
teachers: (*get_teachers().read()).clone(),
timetables, //(*schedules().read()).clone(),
school_hour: h,
not_placed_acts,
};
dt
}
fn create_teachers_acts() -> HashMap<i32, Vec<Activity>> {
let activities = (*activities().read()).clone();
let acts: Vec<Activity> = activities.clone().values().map(|a| a.clone()).collect();
let mut ts_acts = HashMap::new();
for act in &activities {
let acts: Vec<Activity> = acts
.iter()
.cloned()
.filter(
|a| {
act.1
.teachers
.iter()
.all(|t| a.teachers.iter().any(|t2| t2 == t))
&& act
.1
.classes
.iter()
.all(|c| a.classes.iter().any(|c2| c2 == c))
}, //&& act.lecture == a.lecture
)
// .map(|a| a.1)
.collect();
ts_acts.insert(act.1.id, acts);
// teachers_acts().set(ts_acts);
}
ts_acts
}
pub fn data() -> &'static Arc<RwLock<TimetableData>> {
static DATA: OnceLock<Arc<RwLock<TimetableData>>> = OnceLock::new();
DATA.get_or_init(|| Arc::new(RwLock::new(create_data())))
}
pub fn generate() {
// create_data();
let mut params = Params {
hour: 2,
depth: 6,
depth2: 6,
};
std::thread::spawn(move || {
let mut t_data = data().read().clone();
t_data.validate_tt();
t_data.timetables = recalc_sched();
*total_hours().write() = create_total_hours();
let mut sch = vec![];
t_data
.timetables
.values()
.for_each(|tt| sch.append(&mut tt.clone()));
*schedules().write() = sch.clone();
*teachers_scheds().write() = create_teachers_sched();
*classes_sched().write() = create_classes_sched();
// println!("not:{:?}", t_data.not_placed_acts);
loop {
if !*generating().read() {
break;
}
// let len = t_data.timetables.len();
if t_data.not_placed_acts.is_empty() {
// // t_data.timetables = recalc_sched();
// // is_generate().set(true);
let mut sch = vec![];
t_data
.timetables
.values()
.for_each(|tt| sch.append(&mut tt.clone()));
*schedules().write() = sch.clone();
*teachers_scheds().write() = create_teachers_sched();
*classes_sched().write() = create_classes_sched();
*generating().write() = false;
*continued().write() = false;
break;
}
if t_data.generate(&mut params) {
if t_data.timetables.len() >= data().read().timetables.len() {
*data().write() = t_data.clone();
} else {
t_data = data().read().clone();
}
let mut sch = vec![];
t_data
.timetables
.values()
.for_each(|tt| sch.append(&mut tt.clone()));
*schedules().write() = sch.clone();
*teachers_scheds().write() = create_teachers_sched();
*classes_sched().write() = create_classes_sched();
} else {
*generating().write() = false;
*continued().write() = false;
break;
}
}
});
// println!("{:?}", t_data.timetables);
}
fn create_ng() -> HashMap<i32, HashSet<i32>> {
let acts = &*activities()
.read()
.values()
.map(|a| a.clone())
.collect::<Vec<Activity>>();
let mut neighbours: HashMap<i32, HashSet<i32>> = HashMap::new();
for a in &*acts {
let ns = &*acts
// .clone()
.into_iter()
.filter(|a2| {
a2.id != a.id
&& (a2
.classes
.iter()
.any(|c| a.classes.iter().any(|c2| c2 == c))
|| a2
.teachers
.iter()
.any(|t| a.teachers.iter().any(|t2| t2 == t)))
})
.collect::<Vec<&Activity>>();
let neigh_map: HashSet<i32> = HashSet::from_iter(ns.iter().map(|n| n.id));
neighbours.insert(a.id, neigh_map);
}
neighbours
}
use std::{
collections::HashMap,
fs::File,
io::{Read, Write},
path::{Path, PathBuf},
sync::{Arc, OnceLock},
time::Instant,
};
use chrono::Local;
use eframe::egui::{mutex::RwLock, vec2, Button, ProgressBar, TextEdit};
use egui::Context;
use egui_flex::{item, Flex};
use rfd::FileDialog;
use super::{
activities::{activities, partnered_act, selected_act},
generating::{data, generate, Schedule},
limitations::limitations_ui::{
classes_sched, create_classes_sched, create_teachers_sched, schedules, teachers_scheds,
},
print_pdf::{classes::classes_prints, teachers::teachers_prints},
};
pub fn params_hour() -> &'static RwLock<String> {
static PARAM: OnceLock<RwLock<String>> = OnceLock::new();
PARAM.get_or_init(|| RwLock::new("".to_string()))
}
pub fn total_hours() -> &'static RwLock<f32> {
static PARAM: OnceLock<RwLock<f32>> = OnceLock::new();
PARAM.get_or_init(|| RwLock::new(create_total_hours()))
}
pub fn create_total_hours() -> f32 {
activities()
.read()
.clone()
.values()
.filter(|a| partnered_act().read().get(&a.id).is_none())
.fold(0., |acc, x| acc + x.hour as f32)
}
pub fn continued() -> &'static RwLock<bool> {
static PARAM: OnceLock<RwLock<bool>> = OnceLock::new();
PARAM.get_or_init(|| RwLock::new(false))
}
pub fn generating() -> &'static Arc<RwLock<bool>> {
static GENERATING: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
GENERATING.get_or_init(|| Arc::new(RwLock::new(false)))
}
pub fn multi_thread() -> &'static Arc<RwLock<bool>> {
static GENERATING: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
GENERATING.get_or_init(|| Arc::new(RwLock::new(false)))
}
pub fn recalc_sched() -> HashMap<i32, Vec<Schedule>> {
let schdls = &*schedules().read();
let mut map: HashMap<i32, Vec<Schedule>> = HashMap::new();
for s in schdls {
let acts = activities().read();
if let Some(a) = acts.get(&s.activity) {
if let Some(tt) = map.get_mut(&a.id) {
tt.push(s.clone());
} else {
map.insert(a.id, vec![s.clone()]);
};
};
}
map
}
pub fn generate_ui(ui: &mut eframe::egui::Ui) {
ui.vertical_centered(|ui| {
ui.add_sized(
vec2(400., 30.),
TextEdit::singleline(&mut *params_hour().write())
.hint_text("Bir öğretmenin aynı sınıfa verebileceği ders saati sayısı"),
);
ui.add_space(10.);
ui.add(
ProgressBar::new(schedules().read().len() as f32 / *total_hours().read())
.desired_width(400.)
.desired_height(50.)
.text(format!(
" {}/{}",
schedules().read().len(),
total_hours().read()
))
.animate(*continued().read())
.corner_radius(5),
);
ui.add_space(10.);
if *generating().read() {
if ui
.add_sized(vec2(400., 30.), Button::new("Durdur"))
.clicked()
{
*generating().write() = false;
}
} else {
if *continued().read() {
if ui
.add_sized(vec2(400., 30.), Button::new("Devam Et"))
.clicked()
{
*generating().write() = true;
// *continued().write() = true;
generate();
}
} else {
if ui
.add_sized(vec2(400., 30.), Button::new("Çalıştır"))
.clicked()
{
*generating().write() = true;
*continued().write() = true;
generate();
};
}
}
if ui
.add_sized(vec2(400., 30.), Button::new("Sıfırla"))
.clicked()
{
let mut sch = vec![];
data()
.write()
.timetables
.retain(|_id, tt| tt.iter().any(|t| t.locked));
data()
.read()
.timetables
.values()
.for_each(|tt| sch.append(&mut tt.clone()));
*schedules().write() = sch.clone();
*teachers_scheds().write() = create_teachers_sched();
*classes_sched().write() = create_classes_sched();
*total_hours().write() = create_total_hours();
}
// ui.allocate_space(ui.available_size());
// ui.checkbox(&mut *multi_thread().write(), "Çoklu Thread Kullan");
ui.layout().horizontal_justify();
Flex::horizontal()
.wrap(true)
.width_percent(1.)
.grow_items(1.)
.show(ui, |flex| {
flex.add_ui(item(), |ui| {
if ui
.add_sized(vec2(197., 30.), Button::new("Sınıf Programını Yazdır"))
.clicked()
{
classes_prints();
}
if ui
.add_sized(vec2(197., 30.), Button::new("Öğretmen Programını Yazdır"))
.clicked()
{
teachers_prints();
}
});
});
ui.label(format!("{:?}", *selected_act().read()));
if ui
.add_sized(vec2(197., 30.), Button::new("Programı Kaydet"))
.clicked()
{
save_scheds();
}
if ui
.add_sized(vec2(197., 30.), Button::new("Programı Aç"))
.clicked()
{
open_scheds();
}
});
}
pub fn save_scheds() {
std::thread::spawn(move || {
let scheds = &*schedules().read();
let js = serde_json::to_string(&*scheds.clone());
match js {
Ok(j) => {
let date = Local::now();
let file_name = format!("./db/scheds/{}.json", date.format("%Y-%m-%d %H:%M"));
let mut f = File::create(file_name).unwrap();
f.write_all(j.as_bytes()).unwrap();
}
Err(_) => {}
}
});
}
pub fn read_scheds(path: PathBuf) {
std::thread::spawn(move || {
let f = File::open(path);
if let Ok(mut f) = f {
let mut content: String = String::new();
f.read_to_string(&mut content).unwrap();
let cls: Vec<Schedule> = serde_json::from_str(content.as_str()).unwrap();
let data = &mut *data().write();
let tt = &mut data.timetables;
for sch in &cls {
tt.entry(sch.activity)
.and_modify(|a| a.push(sch.clone()))
.or_insert(vec![sch.clone()]);
}
*schedules().write() = cls;
}
});
}
pub fn open_scheds() {
let file = FileDialog::new()
.set_title("Dosya Seç")
.set_directory("./db/scheds")
.pick_file();
read_scheds(file.unwrap());
}
use eframe::egui;
use eframe::egui::mutex::RwLock;
use eframe::egui::vec2;
use eframe::egui::Align2;
use eframe::egui::Button;
use eframe::egui::Color32;
use eframe::egui::Label;
use eframe::egui::Link;
use eframe::egui::RichText;
use eframe::egui::ScrollArea;
use eframe::egui::Stroke;
use eframe::egui::TextEdit;
// use eframe::Frame;
use egui_flex::item;
use egui_flex::Flex;
use serde::Deserialize;
use serde::Serialize;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::iter::zip;
use std::sync::Arc;
use std::sync::OnceLock;
use crate::tabs::activities::activity_form::filtered_classrooms;
use crate::tabs::activities::Activity;
use super::activities::activities;
use super::activities::activity_form::classrooms_ui::set_classrooms_filter;
// use super::activities::activity_form::filtered_classes;
// use super::activities::activity_form::filtering_classes;
use super::activities::activity_form::filtering_classrooms;
use super::activities::save_activities;
// use super::limitations::limitations_ui::create_classes_sched;
// use super::classrooms::get_classrooms;
// use super::limitations::limitations_ui::ClassLimitation;
// use super::limitations::limitations_ui::{classes_limitations, save_classes_limitations};
#[derive(Clone, Serialize, Deserialize)]
pub struct ClassRoom {
pub id: i32,
pub name: String,
short_name: String,
}
pub fn selected_classroom() -> &'static Arc<RwLock<Option<i32>>> {
static SELECTED: OnceLock<Arc<RwLock<Option<i32>>>> = OnceLock::new();
SELECTED.get_or_init(|| Arc::new(RwLock::new(None)))
}
pub fn get_classrooms() -> &'static Arc<RwLock<BTreeMap<i32, ClassRoom>>> {
static CLASSES: OnceLock<Arc<RwLock<BTreeMap<i32, ClassRoom>>>> = OnceLock::new();
CLASSES.get_or_init(|| Arc::new(RwLock::new(read_classrooms())))
}
pub fn del_classrooms_state() -> &'static Arc<RwLock<Vec<bool>>> {
static TEACHERS: OnceLock<Arc<RwLock<Vec<bool>>>> = OnceLock::new();
TEACHERS.get_or_init(|| Arc::new(RwLock::new(vec![false; filtered_classrooms().read().len()])))
}
pub fn classrooms_acts() -> &'static Arc<RwLock<BTreeMap<i32, Vec<Activity>>>> {
static CLASSES: OnceLock<Arc<RwLock<BTreeMap<i32, Vec<Activity>>>>> = OnceLock::new();
CLASSES.get_or_init(|| Arc::new(RwLock::new(create_classrooms_acts())))
}
pub fn create_classrooms_acts() -> BTreeMap<i32, Vec<Activity>> {
let acts = &*activities().read();
let mut map = BTreeMap::new();
for c in &*get_classrooms().read() {
let mut c_acts = acts
// .clone()
.values()
.filter(|a| a.classes.iter().any(|ac| ac == &c.1.id))
.map(|a| a.clone())
.collect::<Vec<Activity>>();
c_acts.sort_by(|a, b| a.lecture.cmp(&b.lecture));
map.insert(c.1.id, c_acts);
}
map
}
pub fn classroom_name() -> &'static Arc<RwLock<String>> {
static NAME: OnceLock<Arc<RwLock<String>>> = OnceLock::new();
NAME.get_or_init(|| Arc::new(RwLock::new("".to_string())))
}
fn classroom_short_name() -> &'static Arc<RwLock<String>> {
static SHORT_NAME: OnceLock<Arc<RwLock<String>>> = OnceLock::new();
SHORT_NAME.get_or_init(|| Arc::new(RwLock::new("".to_string())))
}
pub fn set_selected_classroom(id: i32) {
let class = Arc::clone(selected_classroom());
std::thread::spawn(move || {
*class.write() = Some(id);
});
}
pub fn classrooms_page(ui: &mut eframe::egui::Ui) {
// let mut name = get_name().lock().unwrap();
ui.vertical_centered(|ui| {
ui.add_sized(
vec2(250., 30.),
TextEdit::singleline(&mut *classroom_name().write()).hint_text("Derslik Adını Gir"),
);
ui.add_sized(
vec2(250., 30.),
TextEdit::singleline(&mut *classroom_short_name().write()).hint_text("Kısa Adı"),
);
if ui.add_sized(vec2(250., 30.), Button::new("Ekle")).clicked() {
add_classroom();
}
});
ui.separator();
flex_classes_ui(ui);
}
fn flex_classes_ui(ui: &mut eframe::egui::Ui) {
Flex::horizontal()
.gap(vec2(20., 20.))
.wrap(true)
.show(ui, |flex| {
let del_states = del_classrooms_state().read().clone();
let del_states = del_states.iter().enumerate();
for (del_state, cl) in zip(del_states, filtered_classrooms().read().iter()) {
let frame = egui::Frame::default()
.stroke(Stroke::new(0.3, Color32::GRAY))
.rounding(5.)
.inner_margin(5.);
flex.add_flex(
item().grow(1.).frame(frame),
Flex::vertical().align_items_content(Align2::CENTER_TOP),
|flex| {
flex.add(item(), Label::new(&cl.name));
if *del_state.1 {
flex.add_flex(
item().grow(1.),
Flex::horizontal()
.align_items(egui_flex::FlexAlign::Center)
.wrap(false),
|flex| {
if flex
.add(
item(),
Link::new(RichText::new("Sil").color(Color32::RED)),
)
// .inner
.clicked()
{
del_classroom(cl.id, del_state.0);
// del_teacher(teacher.id);
};
if flex
.add(item().grow(1.), Link::new("Vazgeç"))
// .inner
.clicked()
{
std::thread::spawn(move || {
if let Some(state) =
del_classrooms_state().write().get_mut(del_state.0)
{
*state = false;
}
});
};
},
);
} else if flex
.add(
item().grow(1.),
Link::new(RichText::new("Sil").color(Color32::DARK_RED)),
)
// .inner
.clicked()
{
std::thread::spawn(move || {
if let Some(state) =
del_classrooms_state().write().get_mut(del_state.0)
{
*state = true;
}
});
// del_teacher(teacher.id);
}
},
);
}
});
}
pub fn classrooms_lists_ui(ui: &mut eframe::egui::Ui) {
ScrollArea::vertical().show(ui, |ui| {
ui.add_space(30.);
ui.separator();
ui.vertical_centered(|ui| {
if ui
.add_sized(
vec2(250., 30.),
TextEdit::singleline(&mut *classroom_name().write()).hint_text("Filtrele"),
)
.changed()
{
set_classrooms_filter();
};
let mut classes = filtered_classrooms().write();
for c in &mut *classes {
let fill_color = if selected_classroom().read().is_some_and(|i| i == c.id) {
Color32::BLUE
} else {
Color32::default()
};
let stroke_color = if selected_classroom().read().is_some_and(|i| i == c.id) {
Color32::LIGHT_BLUE
} else {
Color32::LIGHT_GRAY
};
let button = egui::Frame::none()
.fill(fill_color)
.inner_margin(10.)
.outer_margin(2.)
.rounding(5.0)
.stroke(Stroke::new(1., stroke_color))
.show(ui, |ui| {
ui.label(&c.name);
})
.response;
let button = button
.interact(egui::Sense::click())
.on_hover_cursor(egui::CursorIcon::PointingHand);
if button.clicked() {
set_selected_classroom(c.id);
}
}
});
});
}
fn save_classrooms() {
let classes = get_classrooms().read();
let js = serde_json::to_string(&*classes);
match js {
Ok(j) => {
let mut f = File::create("./db/classrooms.json").unwrap();
f.write_all(j.as_bytes()).unwrap();
}
Err(_) => {}
}
}
fn read_classrooms() -> BTreeMap<i32, ClassRoom> {
let f = File::open("./db/classrooms.json");
if let Ok(mut f) = f {
let mut content: String = String::new();
f.read_to_string(&mut content).unwrap();
let cls: BTreeMap<i32, ClassRoom> = serde_json::from_str(content.as_str()).unwrap();
return cls;
// return BTreeMap::from_iter(cls.iter().map(|c| (c.id, c.clone())));
}
// validates_c_lims();
BTreeMap::new()
}
fn add_classroom() {
std::thread::spawn(move || {
let len = find_new_id();
let class = ClassRoom {
id: len,
name: classroom_name().write().clone(),
short_name: classroom_short_name().write().clone(),
};
let mut cls = get_classrooms().write();
cls.insert(len, class);
drop(cls);
*filtered_classrooms().write() = filtering_classrooms();
// let c_lims = ClassLimitation::new(len);
// classes_limitations().write().insert(len, c_lims);
// save_classes_limitations();
save_classrooms();
});
}
fn del_classroom(index: i32, state: usize) {
let classes = get_classrooms().clone();
std::thread::spawn(move || {
let cls = Arc::clone(&classes);
cls.write().remove(&index);
*filtered_classrooms().write() = filtering_classrooms();
// classes_limitations().write().remove(&index);
// save_classes_limitations();
let acts = &mut *activities().write();
acts.iter_mut()
.for_each(|a| a.1.classes.retain(|c| c != &index));
acts.retain(|_, a| !a.classes.is_empty());
save_activities();
std::thread::spawn(move || {
// *classes_sched().write() = create_classes_sched();
// *classes_acts().write() = create_classes_acts();
// *().write() = create_teacher_acts();
});
del_classrooms_state().write().remove(state);
});
del_classrooms_acts(index);
save_classrooms();
}
fn del_classrooms_acts(index: i32) {
let acts = &mut *activities().write();
if let Some(c_acts) = classrooms_acts().read().get(&index) {
for a in c_acts {
acts.remove(&a.id);
}
}
classrooms_acts().write().remove(&index);
save_activities();
}
fn find_new_id() -> i32 {
let len = get_classrooms().read().len() as i32;
for i in 1..len + 1 {
if !get_classrooms().read().contains_key(&i) {
return i;
}
}
len + 1
}
// pub fn validates_c_lims() {
// std::thread::spawn(move || {
// let classes = &*get_classrooms().read();
// // let lims = &mut *classes_limitations().write();
// // lims.retain(|id, _lim| classes.contains_key(id));
// // save_classes_limitations();
// // validates_t_lims();
// });
// }
// pub fn validates_t_lims() {
// std::thread::spawn(move || {
// let teachers = &*get_teachers().read();
// let lims = &mut *teachers_limitations().write();
// lims.retain(|id, _lim| teachers.contains_key(id));
// save_teachers_limitations();
// validates_c_acts();
// });
// }
// fn validates_trlims() {
// let teachers = &*get_classrooms().read();
// let lims = &mut *classr_limitations().write();
// lims.retain(|id, _lim| teachers.contains_key(id));
// save_teachers_limitations();
// }
// pub fn validates_c_acts() {
// std::thread::spawn(move || {
// let classes = &*get_classes().read();
// let acts = &mut *activities().write();
// acts.retain(|_id, act| act.classes.iter().all(|ac| classes.contains_key(ac)));
// save_activities();
// validates_t_acts();
// });
// }
// pub fn validates_t_acts() {
// std::thread::spawn(move || {
// let teachers = &*get_teachers().read();
// let acts = &mut *activities().write();
// acts.retain(|_id, act| act.teachers.iter().all(|ac| teachers.contains_key(ac)));
// save_activities();
// validates_l_acts();
// });
// }
// pub fn validates_l_acts() {
// std::thread::spawn(move || {
// let lectures = &*get_lectures().read();
// let acts = &mut *activities().write();
// acts.retain(|_id, act| lectures.contains_key(&act.lecture));
// save_activities();
// });
// }
use eframe::egui;
use eframe::egui::mutex::RwLock;
use eframe::egui::vec2;
use eframe::egui::Align2;
use eframe::egui::Button;
use eframe::egui::Color32;
use eframe::egui::Label;
use eframe::egui::Link;
use eframe::egui::RichText;
use eframe::egui::ScrollArea;
use eframe::egui::Stroke;
use eframe::egui::TextEdit;
// use eframe::Frame;
use egui_flex::item;
use egui_flex::Flex;
use serde::Deserialize;
use serde::Serialize;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::iter::zip;
use std::sync::Arc;
use std::sync::OnceLock;
use crate::tabs::activities::Activity;
use super::activities::activities;
use super::activities::activity_form::classes_ui::set_classes_filter;
use super::activities::activity_form::filtered_classes;
use super::activities::activity_form::filtering_classes;
use super::activities::save_activities;
// use super::classrooms::get_classrooms;
use super::lectures::get_lectures;
use super::limitations::limitations_ui::classes_sched;
// use super::limitations::limitations_ui::create_classes_sched;
use super::limitations::limitations_ui::ClassLimitation;
use super::limitations::limitations_ui::{
classes_limitations, save_classes_limitations, save_teachers_limitations, teachers_limitations,
};
use super::teachers::get_teachers;
#[derive(Clone, Serialize, Deserialize)]
pub struct Class {
pub id: i32,
pub name: String,
short_name: String,
}
pub fn selected_class() -> &'static Arc<RwLock<Option<i32>>> {
static SELECTED: OnceLock<Arc<RwLock<Option<i32>>>> = OnceLock::new();
SELECTED.get_or_init(|| Arc::new(RwLock::new(None)))
}
pub fn get_classes() -> &'static Arc<RwLock<BTreeMap<i32, Class>>> {
static CLASSES: OnceLock<Arc<RwLock<BTreeMap<i32, Class>>>> = OnceLock::new();
CLASSES.get_or_init(|| Arc::new(RwLock::new(read_classes())))
}
pub fn del_classes_state() -> &'static Arc<RwLock<Vec<bool>>> {
static TEACHERS: OnceLock<Arc<RwLock<Vec<bool>>>> = OnceLock::new();
TEACHERS.get_or_init(|| Arc::new(RwLock::new(vec![false; filtered_classes().read().len()])))
}
pub fn classes_acts() -> &'static Arc<RwLock<BTreeMap<i32, Vec<Activity>>>> {
static CLASSES: OnceLock<Arc<RwLock<BTreeMap<i32, Vec<Activity>>>>> = OnceLock::new();
CLASSES.get_or_init(|| Arc::new(RwLock::new(create_classes_acts())))
}
pub fn create_classes_acts() -> BTreeMap<i32, Vec<Activity>> {
let acts = &*activities().read();
let mut map = BTreeMap::new();
for c in &*get_classes().read() {
let mut c_acts = acts
// .clone()
.values()
.filter(|a| a.classes.iter().any(|ac| ac == &c.1.id) || a.classes.is_empty())
.map(|a| a.clone())
.collect::<Vec<Activity>>();
c_acts.sort_by(|a, b| a.lecture.cmp(&b.lecture));
map.insert(c.1.id, c_acts);
}
map
}
pub fn class_name() -> &'static Arc<RwLock<String>> {
static NAME: OnceLock<Arc<RwLock<String>>> = OnceLock::new();
NAME.get_or_init(|| Arc::new(RwLock::new("".to_string())))
}
fn class_short_name() -> &'static Arc<RwLock<String>> {
static SHORT_NAME: OnceLock<Arc<RwLock<String>>> = OnceLock::new();
SHORT_NAME.get_or_init(|| Arc::new(RwLock::new("".to_string())))
}
pub fn set_selected_class(id: i32) {
let class = Arc::clone(selected_class());
std::thread::spawn(move || {
*class.write() = Some(id);
});
}
fn update_class_form() -> &'static Arc<RwLock<bool>> {
static SHORT_NAME: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
SHORT_NAME.get_or_init(|| Arc::new(RwLock::new(false)))
}
fn update_class(ui: &mut eframe::egui::Ui) {
egui::Window::new("Select Class")
.open(&mut *update_class_form().write())
.resizable([true, true])
.show(ui.ctx(), |ui| {
ui.add(TextEdit::singleline(&mut *class_name().write()));
ui.add(TextEdit::singleline(&mut *class_short_name().write()));
if ui.add(Button::new("Güncelle")).clicked() {
if let Some(t) = get_classes()
.write()
.get_mut(&selected_class().read().unwrap())
{
t.name = class_name().read().clone();
t.short_name = class_short_name().read().clone();
save_classes();
}
}
});
}
pub fn classes_page(ui: &mut eframe::egui::Ui) {
// let mut name = get_name().lock().unwrap();
ui.vertical_centered(|ui| {
if ui
.add_sized(
vec2(250., 30.),
TextEdit::singleline(&mut *class_name().write()).hint_text("Sınıf Adını Gir"),
)
.changed()
{
set_classes_filter();
};
ui.add_sized(
vec2(250., 30.),
TextEdit::singleline(&mut *class_short_name().write()).hint_text("Kısa Adı"),
);
if ui.add_sized(vec2(250., 30.), Button::new("Ekle")).clicked() {
add_class();
}
});
ui.separator();
flex_classes_ui(ui);
}
fn flex_classes_ui(ui: &mut eframe::egui::Ui) {
update_class(ui);
Flex::horizontal()
.gap(vec2(20., 20.))
.wrap(true)
.show(ui, |flex| {
let del_states = del_classes_state().read().clone();
let del_states = del_states.iter().enumerate();
for (del_state, class) in zip(del_states, filtered_classes().read().iter()) {
let frame = egui::Frame::default()
.stroke(Stroke::new(0.3, Color32::GRAY))
.rounding(5.)
.inner_margin(5.);
flex.add_flex(
item().grow(1.).frame(frame),
Flex::vertical().align_items_content(Align2::CENTER_TOP),
|flex| {
flex.add(item(), Label::new(&class.name));
if *del_state.1 {
flex.add_flex(
item().grow(1.),
Flex::horizontal()
.align_items(egui_flex::FlexAlign::Center)
.wrap(false),
|flex| {
if flex
.add(
item(),
Link::new(RichText::new("Sil").color(Color32::RED)),
)
// .inner
.clicked()
{
del_class(class.id, del_state.0);
// del_teacher(teacher.id);
};
if flex
.add(item().grow(1.), Link::new("Vazgeç"))
// .inner
.clicked()
{
std::thread::spawn(move || {
if let Some(state) =
del_classes_state().write().get_mut(del_state.0)
{
*state = false;
}
});
};
},
);
} else {
if flex
.add(
item().grow(1.),
Link::new(RichText::new("Sil").color(Color32::DARK_RED)),
)
// .inner
.clicked()
{
std::thread::spawn(move || {
if let Some(state) =
del_classes_state().write().get_mut(del_state.0)
{
*state = true;
}
});
// del_teacher(teacher.id);
}
if flex.add(item(), Link::new("Düzenle")).clicked() {
let c = class.clone();
set_selected_class(c.id);
std::thread::spawn(move || {
*class_name().write() = c.name.clone();
*class_short_name().write() = c.short_name.clone();
*update_class_form().write() = true;
});
}
}
},
);
}
});
}
pub fn classes_lists_ui(ui: &mut eframe::egui::Ui) {
ScrollArea::vertical().show(ui, |ui| {
ui.add_space(30.);
ui.separator();
ui.vertical_centered(|ui| {
if ui
.add_sized(
vec2(250., 30.),
TextEdit::singleline(&mut *class_name().write()).hint_text("Filtrele"),
)
.changed()
{
set_classes_filter();
};
let classes = &*filtered_classes().read();
for c in classes {
let fill_color = if selected_class().read().is_some_and(|i| i == c.id) {
Color32::BLUE
} else {
Color32::default()
};
let stroke_color = if selected_class().read().is_some_and(|i| i == c.id) {
Color32::LIGHT_BLUE
} else {
Color32::LIGHT_GRAY
};
let button = egui::Frame::none()
.fill(fill_color)
.inner_margin(10.)
.outer_margin(2.)
.rounding(5.0)
.stroke(Stroke::new(1., stroke_color))
.show(ui, |ui| {
ui.label(&c.name);
})
.response;
let button = button
.interact(egui::Sense::click())
.on_hover_cursor(egui::CursorIcon::PointingHand);
if button.clicked() {
set_selected_class(c.id);
}
}
});
});
}
fn save_classes() {
std::thread::spawn(move || {
let classes = get_classes().read();
let js = serde_json::to_string(&*classes);
match js {
Ok(j) => {
let mut f = File::create("./db/classes.json").unwrap();
f.write_all(j.as_bytes()).unwrap();
}
Err(_) => {}
}
});
}
fn read_classes() -> BTreeMap<i32, Class> {
let f = File::open("./db/classes.json");
if let Ok(mut f) = f {
let mut content: String = String::new();
f.read_to_string(&mut content).unwrap();
let cls: BTreeMap<i32, Class> = serde_json::from_str(content.as_str()).unwrap();
return cls;
// return BTreeMap::from_iter(cls.iter().map(|c| (c.id, c.clone())));
}
// validates_c_lims();
BTreeMap::new()
}
fn add_class() {
let len = find_new_id();
let class = Class {
id: len,
name: class_name().write().clone(),
short_name: class_short_name().write().clone(),
};
std::thread::spawn(move || {
get_classes().write().insert(len, class);
*class_name().write() = "".to_string();
*class_short_name().write() = "".to_string();
set_classes_filter();
let c_lims = ClassLimitation::new(len);
classes_limitations().write().insert(len, c_lims);
save_classes_limitations();
save_classes();
del_classes_state().write().push(false);
});
}
fn del_class(index: i32, state: usize) {
std::thread::spawn(move || {
let classes = get_classes();
classes.write().remove(&index);
save_classes();
// drop(cls);
classes_limitations().write().remove(&index);
save_classes_limitations();
del_class_acts(index);
*filtered_classes().write() = filtering_classes();
classes_sched().write().remove(&index);
classes_acts().write().remove(&index);
// *().write() = create_teacher_acts();
del_classes_state().write().remove(state);
});
}
fn del_class_acts(index: i32) {
// let acts = &mut *activities().write();
if let Some(c_acts) = classes_acts().read().get(&index) {
for a in c_acts {
activities().write().remove(&a.id);
}
}
classes_acts().write().remove(&index);
save_activities();
}
fn find_new_id() -> i32 {
let len = get_classes().read().len() as i32;
for i in 1..len + 1 {
if !get_classes().read().contains_key(&i) {
return i;
}
}
len + 1
}
pub fn validates_c_lims() {
std::thread::spawn(move || {
let classes = &*get_classes().read();
let lims = &mut *classes_limitations().write();
lims.retain(|id, _lim| classes.contains_key(id));
save_classes_limitations();
// validates_t_lims();
});
}
pub fn validates_t_lims() {
std::thread::spawn(move || {
let teachers = &*get_teachers().read();
let lims = &mut *teachers_limitations().write();
lims.retain(|id, _lim| teachers.contains_key(id));
save_teachers_limitations();
validates_c_acts();
});
}
// fn validates_trlims() {
// let teachers = &*get_classrooms().read();
// let lims = &mut *classr_limitations().write();
// lims.retain(|id, _lim| teachers.contains_key(id));
// save_teachers_limitations();
// }
pub fn validates_c_acts() {
std::thread::spawn(move || {
let classes = &*get_classes().read();
let acts = &mut *activities().write();
acts.retain(|_id, act| act.classes.iter().all(|ac| classes.contains_key(ac)));
save_activities();
validates_t_acts();
});
}
pub fn validates_t_acts() {
std::thread::spawn(move || {
let teachers = &*get_teachers().read();
let acts = &mut *activities().write();
acts.retain(|_id, act| act.teachers.iter().all(|ac| teachers.contains_key(ac)));
save_activities();
validates_l_acts();
});
}
pub fn validates_l_acts() {
std::thread::spawn(move || {
let lectures = &*get_lectures().read();
let acts = &mut *activities().write();
acts.retain(|_id, act| lectures.contains_key(&act.lecture));
save_activities();
});
}
use activity_form::{
act_form, add_activity, filtered_teachers, find_new_act_id, lectures_ui,
teachers_ui::filter_teacher_text, update_activity_data,
};
use eframe::egui::{
self, mutex::RwLock, vec2, Align2, Button, Color32, ComboBox, Frame, Label, RichText, Rounding,
Stroke, TextEdit,
};
use egui::{CornerRadius, Id};
use egui_extras::{Column, TableBody, TableBuilder};
use egui_flex::{item, Flex};
use serde::{Deserialize, Serialize};
use std::{
collections::{BTreeMap, HashMap},
fmt::Debug,
fs::File,
io::{Read, Write},
iter::zip,
sync::{Arc, OnceLock},
};
use super::{
classes::{classes_acts, classes_lists_ui, create_classes_acts, get_classes, selected_class},
classrooms::get_classrooms,
generating::{act_total_classes, act_total_teachers, data},
get_page, get_school,
lectures::get_lectures,
limitations::limitations_ui::{classes_limitations, teachers_limitations},
panel_buttons,
teachers::{
create_teacher_acts, get_teachers, selected_teacher, teachers_acts, teachers_list_ui,
},
SubPage,
};
pub mod activity_form;
#[derive(Hash, Clone, Default, Serialize, PartialEq, Eq, PartialOrd, Ord, Deserialize)]
pub struct Activity {
pub id: i32,
pub lecture: i32,
pub classes: Vec<i32>,
pub teachers: Vec<i32>,
pub hour: usize,
pub classroom: Vec<i32>,
pub no_limit: bool,
pub partners: Vec<i32>,
}
impl Activity {
pub fn lectures_name(&self) -> String {
let mut activity = "".to_string();
activity.push_str(&get_lec_short_name(self.lecture));
activity.push_str(" ");
for p_id in &self.partners {
let p_act = activities().read().clone();
let p_act = p_act.get(&p_id).unwrap();
activity.push_str(&get_lec_short_name(p_act.lecture));
}
activity.trim().to_string()
}
pub fn classes_name(&self) -> String {
let mut activity = "".to_string();
for c in &self.classes {
activity.push_str(&get_class_name(*c));
}
activity.push_str(" ");
for p_id in &self.partners {
let p_act = activities().read().clone();
let p_act = p_act.get(&p_id).unwrap();
for c in &p_act.classes {
activity.push_str(&get_class_name(*c));
}
}
activity.trim().to_string()
}
pub fn teachers_short_name(&self) -> String {
let mut activity = "".to_string();
for t in &self.teachers {
activity.push_str(&get_teacher_name(*t));
}
activity.push_str(" ");
for p_id in &self.partners {
let p_act = activities().read().clone();
let p_act = p_act.get(&p_id).unwrap();
for t in &p_act.teachers {
activity.push_str(&get_teacher_name(*t));
}
}
activity.trim().to_string()
}
pub fn teachers_name(&self) -> String {
let mut activity = "".to_string();
for t in &self.teachers {
activity.push_str(&get_teacher_name(*t));
}
activity.push_str(" ");
for p_id in &self.partners {
let p_act = activities().read().clone();
let p_act = p_act.get(&p_id).unwrap();
for t in &p_act.teachers {
activity.push_str(&get_teacher_name(*t));
}
}
activity.trim().to_string()
}
fn classes_lims(&self) -> Option<Vec<Vec<Vec<bool>>>> {
let mut c_availables = vec![];
let act_classes = act_total_classes().read();
let Some(classes) = act_classes.get(&self.id) else {
return None;
};
for class in classes {
let c = &*classes_limitations().read();
if let Some(c) = c.get(class) {
c_availables.push(c.limitations.clone());
}
}
Some(c_availables)
}
pub fn classes_available(&self, hour: usize, day: usize) -> bool {
let Some(lims) = self.classes_lims() else {
return false;
};
hour + self.hour <= get_school().read().hour
&& (hour..hour + self.hour as usize).all(|h| lims.iter().all(|ta| ta[day][h]))
}
fn teachers_lims(&self) -> Option<Vec<Vec<Vec<bool>>>> {
let mut t_availables = vec![];
let act_teachers = act_total_teachers().read();
let Some(teachers) = act_teachers.get(&self.id) else {
return None;
};
for teacher in teachers {
let t = &*teachers_limitations().read();
if let Some(t) = t.get(teacher) {
t_availables.push(t.limitations.clone());
}
}
Some(t_availables)
}
pub fn teachers_available(&self, hour: usize, day: usize) -> bool {
let Some(lims) = self.teachers_lims() else {
return false;
};
hour + self.hour <= get_school().read().hour
&& (hour..hour + self.hour as usize).all(|h| lims.iter().all(|ta| ta[day][h]))
}
}
impl Debug for Activity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = format!(
"{}, {} {} {} - {}",
self.id,
self.lectures_name(),
self.teachers_short_name(),
self.classes_name(),
self.hour
);
write!(f, "{}", name)
}
}
pub fn save_activities() {
std::thread::spawn(move || {
let acts = &*activities().read();
// let acts = acts.iter().map(|a| a.1.clone()).collect::<Vec<Activity>>();
// let mut map = BTreeMap::new();
// for a in acts {
// map.insert(a.id, a.clone());
// }
let mut f = File::create("./db/activities.json").unwrap();
f.write_all(serde_json::to_string(&acts).unwrap().as_bytes())
.expect("Aktiviteler yazılamadı");
});
}
fn read_activities() -> BTreeMap<i32, Activity> {
let f = File::open("./db/activities.json");
if let Ok(mut f) = f {
let mut content: String = String::new();
f.read_to_string(&mut content).unwrap();
let cls: BTreeMap<i32, Activity> = serde_json::from_str(content.as_str()).unwrap();
// cls.sort_by(|a, b| b.id.cmp(&a.id));
return cls;
}
BTreeMap::new()
}
pub fn activities() -> &'static Arc<RwLock<BTreeMap<i32, Activity>>> {
static PAGE: OnceLock<Arc<RwLock<BTreeMap<i32, Activity>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(read_activities())))
}
pub fn classes_acts_hours() -> &'static Arc<RwLock<BTreeMap<i32, usize>>> {
static PAGE: OnceLock<Arc<RwLock<BTreeMap<i32, usize>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(create_classes_hours())))
}
pub fn teachers_acts_hours() -> &'static Arc<RwLock<BTreeMap<i32, usize>>> {
static PAGE: OnceLock<Arc<RwLock<BTreeMap<i32, usize>>>> = OnceLock::new();
PAGE.get_or_init(|| Arc::new(RwLock::new(create_teachers_hours())))
}
pub fn selected_act() -> &'static Arc<RwLock<i32>> {
static LECTURES: OnceLock<Arc<RwLock<i32>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(-1)))
}
pub fn partnered_act() -> &'static Arc<RwLock<HashMap<i32, i32>>> {
static LECTURES: OnceLock<Arc<RwLock<HashMap<i32, i32>>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(create_partnered_act())))
}
pub fn create_partnered_act() -> HashMap<i32, i32> {
let acts = &*activities().read();
let mut map = HashMap::new();
for a in acts {
for id in &a.1.partners {
map.insert(id.clone(), a.1.id);
}
}
map
}
pub fn show_add_class_form() -> &'static Arc<RwLock<bool>> {
static LECTURES: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(false)))
}
pub fn set_show_class_form() {
let stat = *show_add_class_form().read();
std::thread::spawn(move || {
*show_add_class_form().write() = !stat;
});
}
pub fn show_add_classroom_form() -> &'static Arc<RwLock<bool>> {
static LECTURES: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(false)))
}
pub fn set_show_classroom_form() {
let stat = *show_add_classroom_form().read();
std::thread::spawn(move || {
*show_add_classroom_form().write() = !stat;
});
}
pub fn show_add_teacher_form() -> &'static Arc<RwLock<bool>> {
static LECTURES: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(false)))
}
pub fn select_class_for_move() -> &'static Arc<RwLock<Option<i32>>> {
static LECTURES: OnceLock<Arc<RwLock<Option<i32>>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(None)))
}
pub fn class_name_for_move() -> &'static Arc<RwLock<String>> {
static LECTURES: OnceLock<Arc<RwLock<String>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new("".to_string())))
}
pub fn set_show_teacher_form() {
let stat = show_add_teacher_form().read().clone();
std::thread::spawn(move || {
*show_add_teacher_form().write() = !stat;
});
}
pub fn show_add_partner_form() -> &'static Arc<RwLock<bool>> {
static LECTURES: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(false)))
}
pub fn set_partner_form() {
let stat = show_add_partner_form().read().clone();
std::thread::spawn(move || {
*show_add_partner_form().write() = !stat;
});
}
fn create_classes_hours() -> BTreeMap<i32, usize> {
let acts = &*activities().read();
let mut cah = BTreeMap::new();
for c in &*get_classes().read() {
let c_acts = acts
.iter()
.filter(|a| a.1.classes.iter().any(|ca| ca == &c.1.id))
.fold(0, |acc, a| acc + a.1.hour);
cah.insert(c.1.id, c_acts);
}
cah
}
fn create_teachers_hours() -> BTreeMap<i32, usize> {
let acts = &*activities().read();
let mut cah = BTreeMap::new();
for c in &*get_teachers().read() {
let c_acts = acts
.iter()
.filter(|a| a.1.teachers.iter().any(|ca| ca == &c.1.id))
.fold(0, |acc, a| acc + a.1.hour);
cah.insert(c.1.id, c_acts);
}
cah
}
pub fn del_states() -> &'static Arc<RwLock<Vec<bool>>> {
static SELECTED: OnceLock<Arc<RwLock<Vec<bool>>>> = OnceLock::new();
let len = activities().read().len();
SELECTED.get_or_init(|| Arc::new(RwLock::new(vec![false; len])))
}
pub fn get_lec_name(id: i32) -> String {
let lec = get_lectures()
.read()
.clone()
.into_iter()
.find(|l| l.1.id == id);
if let Some(lec) = lec {
return lec.1.name;
}
"".to_string()
}
pub fn get_lec_short_name(id: i32) -> String {
let lec = get_lectures()
.read()
.clone()
.into_iter()
.find(|l| l.1.id == id);
if let Some(lec) = lec {
return lec.1.short_name;
}
"".to_string()
}
pub fn get_classes_name(ids: &[i32]) -> String {
let mut name = "".to_string();
for i in ids {
if let Some(c) = get_classes().read().get(i) {
name.push_str(&c.name);
name.push_str(" ");
}
}
name.trim().to_string()
}
pub fn get_class_name(id: i32) -> String {
let mut name = "".to_string();
if let Some(c) = get_classes().read().get(&id) {
name.push_str(&c.name);
}
name.trim().to_string()
}
pub fn get_act_classrooms_name(id: i32) -> String {
let mut name = "".to_string();
if let Some(c) = get_classrooms().read().get(&id) {
name.push_str(&c.name);
}
name.trim().to_string()
}
pub fn get_teachers_name(ids: &[i32]) -> String {
let mut name = "".to_string();
for i in ids {
if let Some(c) = get_teachers().read().get(i) {
name.push_str(&c.short_name);
name.push_str("\n");
}
}
name.trim().to_string()
}
pub fn get_teacher_name(id: i32) -> String {
let mut name = "".to_string();
if let Some(c) = get_teachers().read().get(&id) {
name.push_str(&c.short_name);
}
name.trim().to_string()
}
pub fn get_teachers_short_name(ids: &[i32]) -> String {
let mut name = "".to_string();
for i in ids {
if let Some(c) = get_teachers().read().get(i) {
name.push_str(&c.short_name);
name.push_str(" ");
}
}
name.trim().to_string()
}
fn del_act(id: i32) {
std::thread::spawn(move || {
activities().write().remove(&id);
let len = activities().read().len();
*del_states().write() = vec![false; len];
*classes_acts().write() = create_classes_acts();
*classes_acts_hours().write() = create_classes_hours();
*teachers_acts().write() = create_teacher_acts();
*teachers_acts_hours().write() = create_teachers_hours();
save_activities();
});
}
pub fn activities_ui(ui: &mut egui::Ui) {
egui::TopBottomPanel::top("top_panel")
.resizable(true)
.default_height(60.)
.height_range(50.0..=350.0)
.show_inside(ui, |ui| {
panel_buttons(ui);
});
home_ui(ui);
}
pub fn home_ui(ui: &mut egui::Ui) {
egui::SidePanel::left("left_panel")
.resizable(true)
.default_width(250.0)
.width_range(200.0..=500.0)
.show_inside(ui, |ui| {
if let SubPage::Teachers = *get_page().read() {
teachers_list_ui(ui);
} else {
classes_lists_ui(ui);
}
});
egui::CentralPanel::default().show_inside(ui, |ui| {
act_form(ui);
ui.horizontal(|ui| {
// ui.vertical(|ui| {
// ui.add_sized(vec2(250., 50.), Label::new("Atanmamış dersler"));
// not_put_acts(ui);
// });
ui.separator();
ui.vertical(|ui| {
list_activities_ui(ui);
});
});
});
}
pub fn list_activities_ui(ui: &mut egui::Ui) {
add_more_teachers_list(ui);
add_more_classes_list(ui);
add_more_classroom_list(ui);
add_partner_form(ui);
lectures_ui::select_lecture_ui(ui);
let w = ui.available_width();
if ui
.add_sized(vec2(w, 50.), Button::new("Ders Ata"))
.clicked()
{
*lectures_ui::show_lectures().write() = true;
};
match *get_page().read() {
SubPage::Teachers => {
if let Some(t) = *selected_teacher().read() {
let text = get_teachers_name(&[t]);
let hour = *teachers_acts_hours().read().get(&t).unwrap_or(&0);
if let Some(acts) = teachers_acts().write().get_mut(&t) {
list_acts_table(ui, acts);
}
ui.separator();
ui.add(Label::new(
RichText::new(format!(
"{} adlı öğretmene atanan toplam ders yükü: {} saat",
text, hour
))
.size(18.),
));
}
}
SubPage::Classes => {
if let Some(c) = *selected_class().read() {
let text = get_classes_name(&[c]);
let hour = *classes_acts_hours().read().get(&c).unwrap_or(&0);
if let Some(acts) = classes_acts().write().get(&c) {
list_acts_table(ui, acts);
}
ui.separator();
ui.horizontal_centered(|ui| {
ui.add(Label::new(
RichText::new(format!(
"{} sınıfına atanan toplam ders yükü: {} saat",
text, hour
))
.size(18.),
));
ui.add_space(50.);
ComboBox::new("move_classes", "")
.width(50.)
.selected_text(&*class_name_for_move().read())
.show_ui(ui, |ui| {
for c in &*get_classes().read() {
let cl = c.1.clone();
if ui.button(&c.1.name).clicked() {
std::thread::spawn(move || {
*class_name_for_move().write() = cl.name.clone();
*select_class_for_move().write() = Some(cl.id);
});
};
}
});
if ui
.add_sized(vec2(100., 30.), Button::new("Seçili Sınıfa Aktar"))
.clicked()
{
std::thread::spawn(move || {
if let Some(id) = *select_class_for_move().read() {
if let Some(acts) = classes_acts().read().get(&c) {
for a in acts {
let mut a = a.clone();
a.classes.iter_mut().for_each(|c2| {
if c == *c2 {
*c2 = id;
}
});
a.id = find_new_act_id();
add_activity(a);
}
}
}
});
}
});
}
}
};
ui.separator();
}
pub fn list_acts_table(ui: &mut egui::Ui, acts: &Vec<Activity>) {
TableBuilder::new(ui)
.column(Column::initial(50.).resizable(true))
.column(Column::initial(250.).resizable(true))
.column(Column::initial(230.).resizable(true))
.column(Column::initial(100.).resizable(true))
.column(Column::initial(50.).resizable(true))
.column(Column::initial(50.).resizable(true))
.column(Column::initial(120.).resizable(true))
.column(Column::initial(120.).resizable(true))
.column(Column::initial(50.).resizable(true))
.striped(true)
.min_scrolled_height(800.)
.auto_shrink(false)
// .column(Column::remainder())
.header(50., |mut header| {
header.col(|ui| {
ui.heading("İd");
});
header.col(|ui| {
ui.heading("Ders");
});
header.col(|ui| {
ui.heading("Öğretmenler");
});
header.col(|ui| {
ui.heading("Sınıflar");
});
header.col(|ui| {
ui.heading("Saat");
});
header.col(|ui| {
ui.heading("Limit");
});
header.col(|ui| {
ui.heading("Derslik");
});
header.col(|ui| {
ui.heading("Ortak Dersler");
});
})
.body(|body| table_body(body, acts));
}
fn table_body(mut body: TableBody, acts: &Vec<Activity>) {
let stats = &*del_states().read();
for (index, (act, stat)) in zip(acts, stats).enumerate() {
body.row(40., |mut row| {
row.col(|ui| {
ui.horizontal_centered(|ui| {
if !*stat {
if ui.button("Sil").clicked() {
std::thread::spawn(move || {
del_states().write()[index] = true;
});
};
if ui.button("Çoğalt").clicked() {
let mut a = act.clone();
a.id = find_new_act_id();
add_activity(a);
};
if ui.button("Böl").clicked() {
let id = act.id;
let hour = act.hour;
std::thread::spawn(move || {
let a = &mut *activities().write();
let a = a.get_mut(&id);
if let Some(a) = a {
a.hour = hour - a.hour / 2;
}
})
.join()
.unwrap();
let mut a = act.clone();
a.id = find_new_act_id();
a.hour = a.hour / 2;
add_activity(a);
save_activities();
// println!("a");
};
if index > 0 && acts[index - 1].lecture == act.lecture {
if ui.button("↑").clicked() {
let id = act.id;
let id2 = acts[index - 1].clone();
let hour = id2.hour;
let id2 = id2.id;
std::thread::spawn(move || {
let a = &mut *activities().write();
a.remove(&id2);
let a = a.get_mut(&id);
if let Some(a) = a {
a.hour = a.hour + hour;
}
save_activities();
update_activity_data();
});
// let mut a = act.clone();
// a.id = find_new_act_id();
// add_activity(a);
};
}
} else {
ui.horizontal_centered(|ui| {
if ui
.button(RichText::new("Sil").color(Color32::DARK_RED))
.clicked()
{
del_act(act.id);
};
if ui
.button(RichText::new("Vazgeç").color(Color32::DARK_RED))
.clicked()
{
std::thread::spawn(move || {
del_states().write()[index] = false;
});
};
});
}
});
});
row.col(|ui| {
ui.horizontal_centered(|ui| {
ui.label(RichText::new(get_lec_name(act.lecture)).size(
if act.id == *selected_act().read() {
24.
} else {
16.
},
));
});
});
row.col(|ui| {
act_teachers_row(ui, &act);
});
row.col(|ui| {
act_classes_row(ui, &act);
});
row.col(|ui| {
ui.horizontal_centered(|ui| {
ui.label(act.hour.to_string());
});
});
row.col(|ui| {
if ui.checkbox(&mut act.no_limit.clone(), "").changed() {
change_no_limit(act.id);
};
});
row.col(|ui| {
act_classrooms_row(ui, &act);
});
row.col(|ui| {
ui.horizontal_wrapped(|ui| {
act_partners_row(ui, &act);
});
});
});
}
}
fn act_partners_row(ui: &mut egui::Ui, act: &Activity) {
let ids = &act.partners;
ui.horizontal_centered(|ui| {
for id in ids {
let a = activities().read().clone();
let a = a.get(&id).unwrap();
let fmt = format!(
"{}-{}",
get_lec_name(a.lecture),
get_teachers_name(&a.teachers)
);
Frame::new()
.corner_radius(CornerRadius::same(5))
.stroke(Stroke::new(0.5, Color32::GRAY))
.inner_margin(2.)
.show(ui, |ui| {
ui.label(fmt);
let b = Button::new(" ✖")
.stroke(Stroke::NONE)
.fill(Color32::default());
if ui
.add(b)
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
del_partner(act.id, a.id);
};
});
}
});
if partnered_act().read().get(&act.id).is_none()
&& ui
.button(RichText::new(" ➕").color(Color32::LIGHT_BLUE))
.clicked()
{
*selected_act().write() = act.id;
set_partner_form();
}
}
fn act_teachers_row(ui: &mut egui::Ui, act: &Activity) {
ui.horizontal_centered(|ui| {
ui.horizontal(|ui| {
for t in &act.teachers {
Frame::new()
.corner_radius(CornerRadius::same(5))
.stroke(Stroke::new(0.5, Color32::GRAY))
.show(ui, |ui| {
ui.label(get_teacher_name(*t));
let b = Button::new("✖")
.stroke(Stroke::NONE)
.fill(Color32::default());
if ui
.add(b)
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
remove_teacher(*t, act.id);
};
});
}
});
if ui
.button(RichText::new(" ➕").color(Color32::LIGHT_BLUE))
.clicked()
{
*selected_act().write() = act.id;
set_show_teacher_form();
}
});
}
fn act_classes_row(ui: &mut egui::Ui, act: &Activity) {
ui.horizontal_centered(|ui| {
ui.horizontal(|ui| {
for c in &act.classes {
Frame::new()
.corner_radius(CornerRadius::same(5))
.stroke(Stroke::new(0.5, Color32::GRAY))
.show(ui, |ui| {
ui.label(get_class_name(*c));
let b = Button::new("✖")
.stroke(Stroke::NONE)
.fill(Color32::default());
if ui
.add(b)
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
remove_class(*c, act.id);
};
});
}
});
if ui
.button(RichText::new(" ➕").color(Color32::LIGHT_BLUE))
.clicked()
{
*selected_act().write() = act.id;
*show_add_class_form().write() = true;
}
});
}
fn act_classrooms_row(ui: &mut egui::Ui, act: &Activity) {
ui.horizontal_centered(|ui| {
ui.horizontal(|ui| {
for c in &act.classroom {
Frame::new()
.corner_radius(CornerRadius::same(5))
.stroke(Stroke::new(0.5, Color32::GRAY))
.show(ui, |ui| {
ui.label(get_act_classrooms_name(*c));
let b = Button::new("✖")
.stroke(Stroke::NONE)
.fill(Color32::default());
if ui
.add(b)
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
remove_classroom(*c, act.id);
};
});
}
});
if ui
.button(RichText::new(" ➕").color(Color32::LIGHT_BLUE))
.clicked()
{
*selected_act().write() = act.id;
set_show_classroom_form();
}
});
}
fn add_more_classes_list(ui: &mut egui::Ui) {
let id = *selected_act().read();
egui::Window::new("Select Class")
.open(&mut *show_add_class_form().write())
.show(ui.ctx(), |ui| {
// classes_ui(ui);
Flex::horizontal()
.align_items(egui_flex::FlexAlign::Stretch)
.align_items_content(Align2::CENTER_CENTER)
.gap(vec2(1., 1.0))
.show(ui, |flex| {
for c in &*get_classes().read() {
flex.add_ui(item().grow(5.), |ui| {
// let b = Button::new(&c.1.name);
if ui
.add_sized(vec2(50., 30.), Button::new(&c.1.name))
.clicked()
{
add_more_class(c.1.id, id);
}
});
}
});
});
}
fn add_more_classroom_list(ui: &mut egui::Ui) {
let id = *selected_act().read();
egui::Window::new("Select Classroom")
.open(&mut *show_add_classroom_form().write())
.show(ui.ctx(), |ui| {
// classes_ui(ui);
Flex::horizontal()
.align_items(egui_flex::FlexAlign::Stretch)
.align_items_content(Align2::CENTER_CENTER)
.gap(vec2(1., 1.0))
.show(ui, |flex| {
for c in &*get_classrooms().read() {
flex.add_ui(item().grow(5.), |ui| {
// let b = Button::new(&c.1.name);
if ui
.add_sized(vec2(50., 30.), Button::new(&c.1.name))
.clicked()
{
add_more_classroom(c.1.id, id);
}
});
}
});
});
}
fn add_more_teachers_list(ui: &mut egui::Ui) {
let id = *selected_act().read();
egui::Window::new("Select Teacher")
.open(&mut *show_add_teacher_form().write())
.show(ui.ctx(), |ui| {
filter_teacher_text(ui);
Flex::vertical()
// .justify(egui_flex::FlexJustify::SpaceAround)
.wrap(true)
.gap(vec2(1., 1.0))
.show(ui, |flex| {
for t in &*filtered_teachers().read() {
flex.add_ui(item().grow(1.), |ui| {
// let b = Button::new(&c.1.name);
if ui
.add_sized(vec2(250., 30.), Button::new(&t.name))
.clicked()
{
add_more_teacher(t.id, id);
}
});
}
});
});
}
fn add_partner_form(ui: &mut egui::Ui) {
let act_id = *selected_act().read();
egui::Window::new("Ortak Ders Ekle")
.open(&mut *show_add_partner_form().write())
.show(ui.ctx(), |ui| {
Flex::vertical()
// .justify(egui_flex::FlexJustify::SpaceAround)
// .wrap(false)
.gap(vec2(1., 1.0))
.show(ui, |flex| {
flex.add_ui(item(), |ui| {
if ui
.add(
TextEdit::singleline(&mut *filter_acts_string().write())
.hint_text("Ders adı Öğretmen Sınıf sıralamasıyla filtrele"),
)
.changed()
{
filtering_acts();
};
});
for a in &*filtered_acts().read() {
if a.id != act_id
&& a.partners.is_empty()
&& partnered_act().read().get(&a.id).is_none()
{
flex.add_ui(item().grow(1.), |ui| {
// let b = Button::new(&c.1.name);
if ui
.add_sized(vec2(250., 30.), Button::new(format!("{:?}", a)))
.clicked()
{
change_partner(act_id, a.id);
}
});
}
}
});
});
}
pub fn acts_frames(ui: &mut egui::Ui, acts: &Vec<Activity>) {
let tt = data().read().timetables.clone();
let frame = Frame::none()
.stroke(Stroke::new(0.5, Color32::LIGHT_GRAY))
.inner_margin(vec2(10., 10.))
.rounding(5.);
Flex::horizontal()
.gap(vec2(10., 10.))
.wrap(true)
.show(ui, |flex| {
for a in acts {
if !tt.contains_key(&a.id) {
flex.add_ui(item().grow(1.).frame(frame), |ui| {
ui.dnd_drag_source(Id::new(a.id), a.clone(), |ui| {
ui.add(Label::new(format!("{:?}", a)));
});
});
}
}
});
}
pub fn filtered_acts() -> &'static Arc<RwLock<Vec<Activity>>> {
static TEACHERS: OnceLock<Arc<RwLock<Vec<Activity>>>> = OnceLock::new();
TEACHERS.get_or_init(|| Arc::new(RwLock::new(vec![])))
}
pub fn filter_acts_string() -> &'static Arc<RwLock<String>> {
static TEACHERS: OnceLock<Arc<RwLock<String>>> = OnceLock::new();
TEACHERS.get_or_init(|| Arc::new(RwLock::new("".to_string())))
}
pub fn filtering_acts() {
let flt = &*filter_acts_string().read().clone().to_uppercase();
*filtered_acts().write() = activities()
.read()
.iter()
.filter(|a| format!("{:?}", a.1).to_uppercase().contains(flt))
.map(|a| a.1.clone())
.collect();
}
fn change_no_limit(id: i32) {
let acts = &mut *activities().write();
let act = acts.get_mut(&id);
if let Some(a) = act {
a.no_limit = !a.no_limit;
std::thread::spawn(move || {
*classes_acts().write() = create_classes_acts();
*teachers_acts().write() = create_teacher_acts();
save_activities();
// set_show_teacher_form();
});
}
}
fn change_partner(act_id: i32, p_id: i32) {
let acts = &mut *activities().write();
let act = acts.get_mut(&act_id);
if let Some(a) = act {
a.partners.push(p_id);
std::thread::spawn(move || {
*partnered_act().write() = create_partnered_act();
*classes_acts().write() = create_classes_acts();
*teachers_acts().write() = create_teacher_acts();
save_activities();
});
}
}
fn add_more_teacher(teacher: i32, id: i32) {
let acts = &mut *activities().write();
let act = acts.get_mut(&id);
if let Some(a) = act {
if !a.teachers.iter().any(|i| i == &teacher) {
a.teachers.push(teacher);
}
std::thread::spawn(move || {
*classes_acts().write() = create_classes_acts();
*teachers_acts().write() = create_teacher_acts();
save_activities();
set_show_teacher_form();
});
}
}
fn del_partner(id: i32, p_id: i32) {
let acts = &mut *activities().write();
let act = acts.get_mut(&id);
if let Some(a) = act {
a.partners.retain(|a| a != &p_id);
std::thread::spawn(move || {
*classes_acts().write() = create_classes_acts();
*teachers_acts().write() = create_teacher_acts();
*partnered_act().write() = create_partnered_act();
save_activities();
});
}
}
fn remove_teacher(teacher: i32, id: i32) {
let acts = &mut *activities().write();
let act = acts.get_mut(&id);
if let Some(a) = act {
a.teachers.retain(|t| t != &teacher);
std::thread::spawn(move || {
*classes_acts().write() = create_classes_acts();
*teachers_acts().write() = create_teacher_acts();
save_activities();
});
}
}
fn add_more_class(class: i32, id: i32) {
let acts = &mut *activities().write();
let act = acts.get_mut(&id);
if let Some(a) = act {
if !a.classes.iter().any(|i| i == &class) {
a.classes.push(class);
}
std::thread::spawn(move || {
*classes_acts().write() = create_classes_acts();
*teachers_acts().write() = create_teacher_acts();
save_activities();
// set_show_teacher_form();
});
}
}
fn remove_class(class: i32, id: i32) {
let acts = &mut *activities().write();
let act = acts.get_mut(&id);
if let Some(a) = act {
a.classes.retain(|c| c != &class);
std::thread::spawn(move || {
*classes_acts().write() = create_classes_acts();
*teachers_acts().write() = create_teacher_acts();
save_activities();
});
}
}
fn add_more_classroom(class: i32, id: i32) {
let acts = &mut *activities().write();
let act = acts.get_mut(&id);
if let Some(a) = act {
if !a.classroom.iter().any(|i| i == &class) {
a.classroom.push(class);
}
std::thread::spawn(move || {
// *classes_acts().write() = create_classes_acts();
// *teachers_acts().write() = create_teacher_acts();
save_activities();
// set_show_teacher_form();
});
}
}
fn remove_classroom(cr: i32, id: i32) {
let acts = &mut *activities().write();
let act = acts.get_mut(&id);
if let Some(a) = act {
a.classroom.retain(|c| c != &cr);
std::thread::spawn(move || {
// *classes_acts().write() = create_classes_acts();
// *teachers_acts().write() = create_teacher_acts();
save_activities();
});
}
}
// fn addd(a: Activity, teacher: i32) {
// // std::thread::spawn(move || {
// if let Some(c_acts) = teachers_acts().write().get_mut(&teacher) {
// c_acts.push(a.clone());
// }
// // });
// }
// use std::sync::{Arc, OnceLock, RwLock};
use std::sync::{Arc, OnceLock};
use eframe::egui::{self, mutex::RwLock, Align2, Button, Vec2};
use egui_flex::item;
use crate::tabs::{
classes::{classes_acts, create_classes_acts, get_classes, selected_class, Class},
classrooms::{get_classrooms, ClassRoom},
get_page,
lectures::{get_lectures, Lecture},
teachers::{create_teacher_acts, get_teachers, selected_teacher, teachers_acts, Teacher},
SubPage,
};
use super::{
activities, classes_acts_hours, create_classes_hours, create_teachers_hours, del_states,
save_activities, teachers_acts_hours, Activity,
};
pub mod classes_ui;
pub mod classrooms_ui;
pub mod lectures_ui;
pub mod teachers_ui;
pub fn filtered_classes() -> &'static Arc<RwLock<Vec<Class>>> {
static LECTURES: OnceLock<Arc<RwLock<Vec<Class>>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(filtering_classes())))
}
pub fn show_form() -> &'static Arc<RwLock<bool>> {
static LECTURES: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(false)))
}
pub fn filtering_classes() -> Vec<Class> {
let lecs = get_classes().read().clone();
let mut lecs = lecs.values().map(|v| v.clone()).collect::<Vec<Class>>();
lecs.sort_by(|a, b| a.name.cmp(&b.name));
lecs
}
pub fn filtered_lectures() -> &'static Arc<RwLock<Vec<Lecture>>> {
static LECTURES: OnceLock<Arc<RwLock<Vec<Lecture>>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(filtering_lectures())))
}
pub fn filtering_lectures() -> Vec<Lecture> {
let lecs = get_lectures().read().clone();
let mut lecs = lecs.values().map(|v| v.clone()).collect::<Vec<Lecture>>();
lecs.sort_by(|a, b| a.name.to_uppercase().cmp(&b.name.to_uppercase()));
lecs
}
pub fn filtered_teachers() -> &'static Arc<RwLock<Vec<Teacher>>> {
static LECTURES: OnceLock<Arc<RwLock<Vec<Teacher>>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(filtering_teachers().clone())))
}
pub fn filtering_teachers() -> Vec<Teacher> {
let teachers = get_teachers().read().clone();
let mut teachers = teachers
.values()
.map(|v| v.clone())
.collect::<Vec<Teacher>>();
teachers.sort_by(|a, b| a.name.to_uppercase().cmp(&b.name.to_uppercase()));
teachers
}
pub fn filtered_classrooms() -> &'static Arc<RwLock<Vec<ClassRoom>>> {
static LECTURES: OnceLock<Arc<RwLock<Vec<ClassRoom>>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new(filtering_classrooms().clone())))
}
pub fn filtering_classrooms() -> Vec<ClassRoom> {
let classrooms = get_classrooms().read().clone();
let mut classrooms = classrooms
.values()
.map(|v| v.clone())
.collect::<Vec<ClassRoom>>();
classrooms.sort_by(|a, b| a.name.to_uppercase().cmp(&b.name.to_uppercase()));
classrooms
}
pub fn act_lec() -> &'static Arc<RwLock<Option<Lecture>>> {
static ACT_LEC: OnceLock<Arc<RwLock<Option<Lecture>>>> = OnceLock::new();
ACT_LEC.get_or_init(|| Arc::new(RwLock::new(None)))
}
pub fn act_classes() -> &'static Arc<RwLock<Vec<Class>>> {
static ACT_CLASSES: OnceLock<Arc<RwLock<Vec<Class>>>> = OnceLock::new();
ACT_CLASSES.get_or_init(|| Arc::new(RwLock::new(vec![])))
}
pub fn act_hours() -> &'static Arc<RwLock<String>> {
static ACT_HOURS: OnceLock<Arc<RwLock<String>>> = OnceLock::new();
ACT_HOURS.get_or_init(|| Arc::new(RwLock::new("".to_string())))
}
pub fn act_teachers() -> &'static Arc<RwLock<Vec<Teacher>>> {
static ACT_TEACHER: OnceLock<Arc<RwLock<Vec<Teacher>>>> = OnceLock::new();
ACT_TEACHER.get_or_init(|| Arc::new(RwLock::new(vec![])))
}
pub fn act_classrooms() -> &'static Arc<RwLock<Vec<ClassRoom>>> {
static ACT_TEACHER: OnceLock<Arc<RwLock<Vec<ClassRoom>>>> = OnceLock::new();
ACT_TEACHER.get_or_init(|| Arc::new(RwLock::new(vec![])))
}
pub fn add_act() {
let lec = &*act_lec().read();
if let Some(lec) = lec {
let hours = act_hours().read().clone();
let tchr = if let SubPage::Teachers = *get_page().read() {
if let Some(t) = *selected_teacher().read() {
vec![t]
} else {
vec![]
}
} else {
vec![]
};
let cls = if let SubPage::Classes = *get_page().read() {
if let Some(c) = *selected_class().read() {
vec![c]
} else {
vec![]
}
} else {
vec![]
};
hours.split(" ").for_each(|h| {
let Ok(h) = h.parse::<usize>() else {
return ();
};
let lec = lec.clone();
let act = Activity {
id: find_new_act_id(),
lecture: lec.id,
classes: cls.clone(),
teachers: tchr.clone(),
hour: h,
classroom: vec![],
no_limit: false,
partners: vec![],
};
add_activity(act);
// update_activity_data();
});
}
}
pub fn add_activity(act: Activity) {
std::thread::spawn(move || {
let acts = activities();
acts.write().insert(act.id, act.clone());
update_activity_data();
save_activities();
})
.join()
.unwrap();
}
pub fn update_activity_data() {
std::thread::spawn(move || {
*teachers_acts().write() = create_teacher_acts();
*classes_acts().write() = create_classes_acts();
*teachers_acts_hours().write() = create_teachers_hours();
*classes_acts_hours().write() = create_classes_hours();
let len = activities().read().len();
*del_states().write() = vec![false; len];
});
}
pub fn find_new_act_id() -> i32 {
let len = activities().read().len() as i32;
for i in 1..len + 1 {
if !activities().read().contains_key(&i) {
return i;
}
}
len + 1
}
pub fn act_form(ui: &mut egui::Ui) {
egui::Window::new("My Window")
.open(&mut *show_form().write())
// .default_size(vec2(500., 500.))
.show(ui.ctx(), |ui| {
ui.vertical_centered(|ui| {
egui_flex::Flex::horizontal()
// .gap(Vec2::new(5., 5.))
.grow_items(1.0)
.align_content(egui_flex::FlexAlignContent::SpaceBetween)
.align_items_content(Align2::CENTER_TOP)
// .wrap(true)
.gap(Vec2::new(1., 1.))
.show(ui, |flex| {
flex.add_ui(item().basis(500.), |ui| {
lectures_ui::select_lecture_ui(ui);
});
flex.add_ui(item().basis(500.), |ui| {
classes_ui::select_classes_ui(ui);
});
flex.add_ui(item().basis(500.), |_ui| {
// teachers_ui::select_teachers_ui(ui);
});
});
if ui
.add_sized(Vec2::new(500., 30.), Button::new("Dosyaya Kaydet"))
.clicked()
{
save_activities();
};
});
});
}
use eframe::egui::{self, TextEdit};
use crate::tabs::teachers::{get_teachers, teacher_name};
use super::filtered_teachers;
pub fn set_teachers_filter() {
std::thread::spawn(move || {
let f = teacher_name().read();
let f = &*f.to_uppercase();
let tchrs = get_teachers()
.read()
.clone()
.into_iter()
.filter(|l| l.1.name.to_uppercase().contains(&f));
*filtered_teachers().write() = tchrs.map(|t| t.1.clone()).collect();
filtered_teachers()
.write()
.sort_by(|a, b| a.name.cmp(&b.name));
});
}
pub fn filter_teacher_text(ui: &mut egui::Ui) {
ui.label("Öğretmen(ler)i Seçin ");
let text = ui
.add(TextEdit::singleline(&mut *teacher_name().write()).hint_text("Öğretmenleri Filtrele"));
text.request_focus();
if text.changed() {
set_teachers_filter()
};
}
// pub fn select_teachers_ui(ui: &mut egui::Ui) {
// ui.vertical(|ui| {
// Frame::none()
// .stroke(Stroke::new(1., Color32::BLACK))
// .rounding(1.)
// .inner_margin(10.0)
// .outer_margin(10.0)
// .show(ui, |ui| {
// ui.label("Öğretmen(ler)i Seçin ");
// if ui
// .add(
// TextEdit::singleline(&mut *teacher_name().write())
// .hint_text("Öğretmenleri Filtrele"),
// )
// .changed()
// {
// set_teachers_filter()
// };
// ui.add_space(5.);
// Flex::horizontal()
// .wrap(true)
// // .justify(egui_flex::FlexJustify::Center)
// .align_items(egui_flex::FlexAlign::Center)
// .show(ui, |flex| {
// let teachers = filtered_teachers().read();
// for teacher in &*teachers {
// let is_selected =
// act_teachers().read().iter().any(|i| teacher.id == i.id);
// let _stroke = Stroke::new(
// if is_selected { 1.0 } else { 0.5 },
// if is_selected {
// Color32::BLUE
// } else {
// Color32::GRAY
// },
// );
// // let frame = egui::Frame::default()
// // .stroke(stroke)
// // .rounding(5.)
// // .inner_margin(5.);
// flex.add_flex(
// item(),
// Flex::horizontal().align_items_content(Align2::CENTER_TOP),
// |flex| {
// // let sel_lec = act_lec();
// if flex
// .add_ui(item(), |ui| {
// ui.add_sized(
// Vec2::new(30., 15.),
// Label::new(&teacher.name),
// )
// })
// .inner
// .on_hover_cursor(egui::CursorIcon::PointingHand)
// .clicked()
// {
// select_teacher(teacher.clone(), is_selected);
// };
// },
// );
// }
// });
// });
// });
// }
// fn select_teacher(teacher: Teacher, del: bool) {
// let teachers = act_teachers();
// // let selected_class = selected_class().read().unwrap();
// std::thread::spawn(move || {
// // let class = class.clone();
// let teachers: Arc<RwLock<Vec<Teacher>>> = Arc::clone(teachers);
// if del {
// teachers.write().retain(|t| &t.id != &teacher.id);
// } else {
// teachers.write().push(teacher.clone());
// }
// });
// }
use std::sync::{Arc, OnceLock};
use eframe::egui::{self, mutex::RwLock, vec2, Button, Color32, Label, Sense, Stroke, TextEdit};
use egui_flex::{item, Flex};
use crate::tabs::lectures::{get_lectures, lec_name};
use super::{act_hours, act_lec, add_act, filtered_lectures};
pub fn show_lectures() -> &'static Arc<RwLock<bool>> {
static ACT_LEC: OnceLock<Arc<RwLock<bool>>> = OnceLock::new();
ACT_LEC.get_or_init(|| Arc::new(RwLock::new(false)))
}
// fn filter_lectures() -> &'static Arc<RwLock<String>> {
// static LECTURES: OnceLock<Arc<RwLock<String>>> = OnceLock::new();
// LECTURES.get_or_init(|| Arc::new(RwLock::new("".to_string())))
// }
pub fn set_lecture_filter() {
std::thread::spawn(move || {
let f = &*lec_name().read();
let f = &*f
.replace('i', "İ")
// .replace('ı', "I")
// .replace('I', "ı")
// .replace('İ', "i")
.to_uppercase();
let lecs = get_lectures()
.read()
.clone()
.into_iter()
.filter(|l| l.1.name.replace('i', "İ").to_uppercase().contains(&f));
*filtered_lectures().write() = lecs.map(|l| l.1).collect();
});
}
pub fn select_lecture_ui(ui: &mut egui::Ui) {
egui::Window::new("Lectures Ui")
.open(&mut *show_lectures().write())
.show(ui.ctx(), |ui| {
ui.label("Ders Seçin");
if ui
.add(TextEdit::singleline(&mut *lec_name().write()).hint_text("Dersleri Filtrele"))
.changed()
{
set_lecture_filter();
};
ui.add_space(5.);
ui.layout().with_main_wrap(true);
Flex::horizontal()
.wrap(true)
.align_items(egui_flex::FlexAlign::Start)
// .justify(egui_flex::FlexJustify::Center)
// .align_items(egui_flex::FlexAlign::Center)
.width_percent(0.3)
.show(ui, |flex| {
for lec in &filtered_lectures().read()[..] {
let sel_lec = act_lec();
let mut color = Color32::GRAY;
let mut stroke = 0.3;
if let Some(l) = &*sel_lec.read() {
if &l.id == &lec.id {
color = Color32::BLUE;
stroke = 1.0;
}
}
let frame = egui::Frame::default()
.stroke(Stroke::new(stroke, color))
.rounding(5.)
.inner_margin(5.);
if flex
.add_widget(
item().frame(frame),
Label::new(&lec.name).sense(Sense::click()),
)
.inner
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
let lec = lec.clone();
std::thread::spawn(move || {
let lec_clone = Arc::clone(sel_lec);
*lec_clone.write() = Some(lec.clone());
});
}
}
});
ui.add_sized(
vec2(500., 30.),
TextEdit::singleline(&mut *act_hours().write()).hint_text("Ders bloklarını gir"),
);
if ui.add_sized(vec2(500., 30.), Button::new("Ekle")).clicked() {
add_act();
};
});
}
use std::sync::Arc;
use eframe::egui::{self, mutex::RwLock, Align2, Color32, Frame, Label, Stroke, TextEdit, Vec2};
use egui_flex::{item, Flex};
use crate::tabs::classrooms::{classroom_name, get_classrooms, ClassRoom};
use super::{act_classrooms, filtered_classrooms};
pub fn set_classrooms_filter() {
let f = classroom_name().read();
let f = &*f.to_uppercase();
let tchrs = get_classrooms()
.read()
.clone()
.into_iter()
.filter(|l| l.1.name.to_uppercase().contains(&f));
*filtered_classrooms().write() = tchrs.map(|t| t.1.clone()).collect();
filtered_classrooms()
.write()
.sort_by(|a, b| a.name.cmp(&b.name));
}
pub fn select_classroom_ui(ui: &mut egui::Ui) {
ui.vertical(|ui| {
Frame::none()
.stroke(Stroke::new(1., Color32::BLACK))
.rounding(1.)
.inner_margin(10.0)
.outer_margin(10.0)
.show(ui, |ui| {
ui.label("Derslik(ler)i Seçin ");
if ui
.add(
TextEdit::singleline(&mut *classroom_name().write())
.hint_text("Derslikleri Filtrele"),
)
.changed()
{
set_classrooms_filter()
};
ui.add_space(5.);
Flex::horizontal()
.wrap(true)
// .justify(egui_flex::FlexJustify::Center)
.align_items(egui_flex::FlexAlign::Center)
.show(ui, |flex| {
let teachers = filtered_classrooms().read();
for teacher in &*teachers {
let is_selected =
act_classrooms().read().iter().any(|i| teacher.id == i.id);
let stroke = Stroke::new(
if is_selected { 1.0 } else { 0.5 },
if is_selected {
Color32::BLUE
} else {
Color32::GRAY
},
);
let _frame = egui::Frame::default()
.stroke(stroke)
.rounding(5.)
.inner_margin(5.);
flex.add_flex(
item(),
Flex::horizontal().align_items_content(Align2::CENTER_TOP),
// frame,
|flex| {
// let sel_lec = act_lec();
if flex
.add_ui(item(), |ui| {
ui.add_sized(
Vec2::new(30., 15.),
Label::new(&teacher.name),
)
})
.inner
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
select_classroom(teacher.clone(), is_selected);
};
},
);
}
});
});
});
}
fn select_classroom(cl: ClassRoom, del: bool) {
let teachers = act_classrooms();
// let selected_class = selected_class().read().unwrap();
std::thread::spawn(move || {
// let class = class.clone();
let classrooms: Arc<RwLock<Vec<ClassRoom>>> = Arc::clone(teachers);
if del {
classrooms.write().retain(|t| &t.id != &cl.id);
} else {
classrooms.write().push(cl.clone());
}
});
}
use std::sync::{Arc, OnceLock};
use eframe::egui::{self, mutex::RwLock, Align2, Color32, Frame, Label, Stroke, TextEdit, Vec2};
use egui_flex::{item, Flex};
use crate::tabs::classes::{class_name, get_classes, Class};
use super::{act_classes, filtered_classes};
fn filter_classes() -> &'static Arc<RwLock<String>> {
static LECTURES: OnceLock<Arc<RwLock<String>>> = OnceLock::new();
LECTURES.get_or_init(|| Arc::new(RwLock::new("".to_string())))
}
// fn filter_range() -> &'static Arc<RwLock<usize>> {
// let lec_len = filtered_classes().read().len();
// let range = if lec_len >= 10 { lec_len } else { 5 };
// static RANGE: OnceLock<Arc<RwLock<usize>>> = OnceLock::new();
// RANGE.get_or_init(|| Arc::new(RwLock::new(range)))
// }
pub fn set_classes_filter() {
let f = class_name().read();
let f = &*f.to_uppercase();
let lecs = get_classes()
.read()
.clone()
.into_iter()
.filter(|l| l.1.name.to_uppercase().contains(&f));
*filtered_classes().write() = lecs.map(|c| c.1.clone()).collect();
}
pub fn select_classes_ui(ui: &mut egui::Ui) {
ui.vertical(|ui| {
Frame::none()
.stroke(Stroke::new(1., Color32::BLACK))
.rounding(1.)
.inner_margin(10.0)
.outer_margin(10.0)
.show(ui, |ui| {
ui.label("Sınıfları Seçin");
if ui
.add(
TextEdit::singleline(&mut *filter_classes().write())
.hint_text("Sınıfları Filtrele"),
)
.changed()
{
set_classes_filter()
};
ui.add_space(5.);
Flex::horizontal()
.wrap(true)
// .justify(egui_flex::FlexJustify::Center)
.align_items(egui_flex::FlexAlign::Center)
.show(ui, |flex| {
let classes = filtered_classes().read();
// for class in &classes[..*filter_range().read()] {
for class in &classes[..] {
let is_selected = act_classes().read().iter().any(|i| class.id == i.id);
let stroke = Stroke::new(
if is_selected { 1.0 } else { 0.5 },
if is_selected {
Color32::BLUE
} else {
Color32::GRAY
},
);
let _frame = egui::Frame::default()
.stroke(stroke)
.rounding(5.)
.inner_margin(5.);
flex.add_flex(
item(),
Flex::horizontal().align_items_content(Align2::CENTER_TOP),
// frame,
|flex| {
// let sel_lec = act_lec();
if flex
.add_ui(item(), |ui| {
ui.add_sized([30., 15.], Label::new(&class.name))
})
.inner
.on_hover_cursor(egui::CursorIcon::PointingHand)
.clicked()
{
select_class(class.clone(), is_selected);
};
},
);
}
// if *filter_range().read() != filtered_classes().read().len() {
// show_more(flex);
// }
});
});
});
}
// fn show_more(flex: &mut FlexInstance) {
// let frame = egui::Frame::default()
// .stroke(Stroke::new(0.5, Color32::GRAY))
// .rounding(5.)
// .inner_margin(5.);
// flex.add_flex_frame(
// item(),
// Flex::horizontal().align_items_content(Align2::CENTER_TOP),
// frame,
// |flex| {
// // let sel_lec = act_lec();
// if flex
// .add_simple(item(), |ui| {
// ui.add_sized(Vec2::new(30., 15.), Label::new("...Tümünü Göster"))
// })
// .inner
// .on_hover_cursor(egui::CursorIcon::PointingHand)
// .clicked()
// {
// let l = filtered_classes().read().len();
// // *filter_range().write() = l;
// };
// },
// );
// }
fn select_class(class: Class, del: bool) {
let clss = act_classes();
// let selected_class = selected_teacher().read().unwrap();
std::thread::spawn(move || {
// let class = class.clone();
let clss = Arc::clone(clss);
if del {
clss.write().retain(|c| &c.id != &class.id);
} else {
clss.write().push(class.clone());
}
});
}