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 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::filtering_classrooms;
use super::activities::save_activities;
#[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
.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) {
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)),
)
.clicked()
{
del_classroom(cl.id, del_state.0);
};
if flex
.add(item().grow(1.), Link::new("Vazgeç"))
.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)),
)
.clicked()
{
std::thread::spawn(move || {
if let Some(state) =
del_classrooms_state().write().get_mut(del_state.0)
{
*state = true;
}
});
}
},
);
}
});
}
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;
}
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();
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();
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 || {
});
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
}