Files
jecnaclient/src/main/java/cz/jzitnik/controllers/TimetableController.java
T
2026-05-29 19:17:40 +02:00

267 lines
9.4 KiB
Java

package cz.jzitnik.controllers;
import cz.jzitnik.router.Route;
import cz.jzitnik.router.Router;
import cz.jzitnik.query.QueryOptions;
import cz.jzitnik.query.QueryResult;
import io.github.tomhula.jecnaapi.data.timetable.Lesson;
import io.github.tomhula.jecnaapi.data.timetable.LessonPeriod;
import io.github.tomhula.jecnaapi.data.timetable.LessonSpot;
import io.github.tomhula.jecnaapi.data.timetable.Timetable;
import io.github.tomhula.jecnaapi.data.timetable.TimetablePage;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import kotlinx.datetime.DayOfWeek;
import java.util.List;
import java.util.Map;
@Route(path = "/timetable", fxml = "/timetable.fxml")
public class TimetableController extends DashboardBaseController {
@FXML
private GridPane timetableGrid;
@FXML
private ProgressIndicator loadingIndicator;
@FXML
private ScrollPane scrollPane;
private TimetablePage currentPage;
@Override
public void onNavigate(Map<String, Object> props) {
super.onNavigate(props);
loadTimetable();
}
private void loadTimetable() {
loadingIndicator.setVisible(true);
scrollPane.setVisible(false);
timetableGrid.getChildren().clear();
appState.getQueryClient().fetch("timetable:page", () -> {
try {
return appState.getClient().getTimetablePage().join();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}, QueryOptions.defaultOptions()).thenAccept(this::handleTimetableResult);
}
private void handleTimetableResult(QueryResult<TimetablePage> result) {
Platform.runLater(() -> {
loadingIndicator.setVisible(false);
if (result.isSuccess() && result.getData().isPresent()) {
scrollPane.setVisible(true);
currentPage = result.getData().get();
renderTimetable();
} else {
Label errorLabel = new Label("Failed to load timetable.");
errorLabel.getStyleClass().addAll("text-danger", "title-3");
timetableGrid.add(errorLabel, 0, 0);
timetableGrid.setAlignment(Pos.CENTER);
scrollPane.setVisible(true);
}
});
}
private void renderTimetable() {
timetableGrid.getChildren().clear();
timetableGrid.getColumnConstraints().clear();
timetableGrid.getRowConstraints().clear();
timetableGrid.setAlignment(Pos.CENTER);
Timetable timetable = currentPage.getTimetable();
List<LessonPeriod> periods = timetable.getLessonPeriods();
List<DayOfWeek> days = timetable.getDaysSorted();
ColumnConstraints dayCol = new ColumnConstraints();
dayCol.setMinWidth(120);
timetableGrid.getColumnConstraints().add(dayCol);
for (int i = 0; i < periods.size(); i++) {
LessonPeriod p = periods.get(i);
VBox header = new VBox(2);
header.setAlignment(Pos.CENTER);
header.getStyleClass().add("timetable-header");
Label indexLbl = new Label(String.valueOf(i));
indexLbl.getStyleClass().add("timetable-header-index");
Label timeLbl = new Label(p.toString());
timeLbl.getStyleClass().add("timetable-header-time");
header.getChildren().addAll(indexLbl, timeLbl);
ColumnConstraints col = new ColumnConstraints();
col.setMinWidth(110);
timetableGrid.getColumnConstraints().add(col);
timetableGrid.add(header, i + 1, 0);
}
int rowIndex = 1;
for (DayOfWeek day : days) {
VBox dayCell = new VBox();
dayCell.setAlignment(Pos.CENTER_RIGHT);
dayCell.getStyleClass().add("timetable-day-cell");
Label dayLabel = new Label(translateDay(day));
dayLabel.getStyleClass().addAll("timetable-day-label", "title-3");
dayCell.getChildren().add(dayLabel);
timetableGrid.add(dayCell, 0, rowIndex);
List<LessonSpot> spots = timetable.get(day);
if (spots != null) {
int colIndex = 1;
for (LessonSpot spot : spots) {
int span = spot.getPeriodSpan();
if (spot.isNotEmpty()) {
VBox cell = createLessonCell(spot);
timetableGrid.add(cell, colIndex, rowIndex, span, 1);
} else {
VBox emptyCell = new VBox();
emptyCell.getStyleClass().add("timetable-cell-empty");
timetableGrid.add(emptyCell, colIndex, rowIndex, span, 1);
}
colIndex += span;
}
}
rowIndex++;
}
}
private VBox createLessonCell(LessonSpot spot) {
VBox cell = new VBox(5);
cell.setAlignment(Pos.CENTER);
cell.getStyleClass().addAll("card", "timetable-cell");
if (spot.getSize() == 1) {
Lesson lesson = spot.getLesson(0);
addLessonInfoToCell(cell, lesson);
} else {
VBox groupContainer = new VBox(5);
groupContainer.setAlignment(Pos.CENTER);
for (int i = 0; i < spot.getSize(); i++) {
Lesson lesson = spot.getLesson(i);
VBox groupCell = new VBox(2);
groupCell.setAlignment(Pos.CENTER);
addLessonInfoToCell(groupCell, lesson);
if (lesson.getGroup() != null) {
Label groupLbl = new Label(lesson.getGroup());
groupLbl.getStyleClass().add("timetable-group-label");
groupCell.getChildren().add(0, groupLbl);
}
groupContainer.getChildren().add(groupCell);
if (i < spot.getSize() - 1) {
Separator sep = new Separator(javafx.geometry.Orientation.HORIZONTAL);
groupContainer.getChildren().add(sep);
}
}
cell.getChildren().add(groupContainer);
}
cell.setOnMouseClicked(e -> showLessonDetails(spot));
return cell;
}
private void addLessonInfoToCell(VBox cell, Lesson lesson) {
Label subjectLbl = new Label(lesson.getSubjectName().getShort() != null ? lesson.getSubjectName().getShort() : lesson.getSubjectName().getFull());
subjectLbl.getStyleClass().add("timetable-subject");
HBox bottomInfo = new HBox(5);
bottomInfo.setAlignment(Pos.CENTER);
if (lesson.getTeacherName() != null) {
Label teacherLbl = new Label(lesson.getTeacherName().getShort() != null ? lesson.getTeacherName().getShort() : lesson.getTeacherName().getFull());
teacherLbl.getStyleClass().add("timetable-teacher");
bottomInfo.getChildren().add(teacherLbl);
}
if (lesson.getClassroom() != null) {
Label roomLbl = new Label(lesson.getClassroom());
roomLbl.getStyleClass().add("timetable-room");
bottomInfo.getChildren().add(roomLbl);
}
cell.getChildren().addAll(subjectLbl, bottomInfo);
}
private void showLessonDetails(LessonSpot spot) {
Dialog<Void> dialog = new Dialog<>();
dialog.setTitle("Detail hodiny");
dialog.setHeaderText(null);
dialog.getDialogPane().getButtonTypes().add(ButtonType.CLOSE);
VBox content = new VBox(15);
content.setPadding(new Insets(20));
for (Lesson lesson : spot) {
VBox lessonInfo = new VBox(5);
lessonInfo.getStyleClass().add("timetable-detail-box");
Label title = new Label(lesson.getSubjectName().getFull());
title.getStyleClass().add("title-3");
lessonInfo.getChildren().add(title);
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(5);
int row = 0;
if (lesson.getTeacherName() != null) {
grid.add(new Label("Učitel:"), 0, row);
grid.add(new Label(lesson.getTeacherName().getFull()), 1, row++);
}
if (lesson.getClassroom() != null) {
grid.add(new Label("Učebna:"), 0, row);
grid.add(new Label(lesson.getClassroom()), 1, row++);
}
if (lesson.getGroup() != null) {
grid.add(new Label("Skupina:"), 0, row);
grid.add(new Label(lesson.getGroup()), 1, row++);
}
lessonInfo.getChildren().add(grid);
content.getChildren().add(lessonInfo);
}
dialog.getDialogPane().setContent(content);
dialog.show();
}
private String translateDay(DayOfWeek day) {
return switch (day) {
case MONDAY -> "Pondělí";
case TUESDAY -> "Úterý";
case WEDNESDAY -> "Středa";
case THURSDAY -> "Čtvrtek";
case FRIDAY -> "Pátek";
case SATURDAY -> "Sobota";
case SUNDAY -> "Neděle";
};
}
@FXML
protected void onBackToDashboard() {
Router.getInstance().navigate("/dashboard");
}
}