docs: Added some javadoc
This commit is contained in:
@@ -19,8 +19,22 @@ import java.util.Optional;
|
||||
import cz.jzitnik.query.QueryClient;
|
||||
import cz.jzitnik.query.QueryOptions;
|
||||
|
||||
/**
|
||||
* The main entry point for the JecnaClient desktop application.
|
||||
* This class initializes the application's UI theme, sets up the navigation router,
|
||||
* and handles the initial application state, including attempting to restore
|
||||
* a user's session from previously saved credentials.
|
||||
*/
|
||||
public class Main extends Application {
|
||||
|
||||
/**
|
||||
* Initializes the JavaFX application, configures the UI, and sets up the routing system.
|
||||
* It attempts to automatically log the user in if stored credentials are available,
|
||||
* navigating to the dashboard on success or to the login screen if authentication fails.
|
||||
*
|
||||
* @param stage the primary window for the application.
|
||||
* @throws Exception if an error occurs during initialization.
|
||||
*/
|
||||
@Override
|
||||
public void start(Stage stage) throws Exception {
|
||||
Application.setUserAgentStylesheet(new PrimerDark().getUserAgentStylesheet());
|
||||
@@ -77,6 +91,11 @@ public class Main extends Application {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard entry point for launching the JavaFX application.
|
||||
*
|
||||
* @param args command-line arguments passed to the application.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
/*
|
||||
AI GENERATED SLOP
|
||||
*/
|
||||
|
||||
package cz.jzitnik.auth;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
@@ -19,6 +15,9 @@ import java.util.EnumSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Securely stores and retrieves user credentials using AES-GCM encryption.
|
||||
*/
|
||||
public class CredentialStore {
|
||||
private static final Path DIR = Paths.get(System.getProperty("user.home"), ".jecnaclient");
|
||||
private static final Path KEY_FILE = DIR.resolve("secret.key");
|
||||
@@ -26,16 +25,32 @@ public class CredentialStore {
|
||||
private static final int KEY_SIZE = 256;
|
||||
private static final SecureRandom RAND = new SecureRandom();
|
||||
|
||||
/**
|
||||
* Represents user credentials (username and password).
|
||||
*/
|
||||
public static final class Credentials {
|
||||
public final String username;
|
||||
public final String password;
|
||||
|
||||
/**
|
||||
* Creates a new Credentials object.
|
||||
*
|
||||
* @param u The username.
|
||||
* @param p The password.
|
||||
*/
|
||||
public Credentials(String u, String p) {
|
||||
this.username = u;
|
||||
this.password = p;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves user credentials to a secure file.
|
||||
*
|
||||
* @param username The username to save.
|
||||
* @param password The password to save.
|
||||
* @throws Exception If an error occurs during saving.
|
||||
*/
|
||||
public static void saveCredentials(String username, String password) throws Exception {
|
||||
if (username == null || password == null) return;
|
||||
ensureDir();
|
||||
@@ -60,6 +75,12 @@ public class CredentialStore {
|
||||
trySetOwnerOnly(CRED_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads user credentials from the secure file.
|
||||
*
|
||||
* @return An Optional containing the credentials if found and decrypted successfully, or empty otherwise.
|
||||
* @throws Exception If an error occurs during loading or decryption.
|
||||
*/
|
||||
public static Optional<Credentials> loadCredentials() throws Exception {
|
||||
if (!Files.exists(CRED_FILE)) return Optional.empty();
|
||||
if (!Files.exists(KEY_FILE)) return Optional.empty();
|
||||
@@ -87,12 +108,18 @@ public class CredentialStore {
|
||||
return Optional.of(new Credentials(u, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears stored credentials by deleting the encrypted file.
|
||||
*/
|
||||
public static void clearCredentials() {
|
||||
try {
|
||||
Files.deleteIfExists(CRED_FILE);
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the credentials directory exists with appropriate permissions.
|
||||
*/
|
||||
private static void ensureDir() throws IOException {
|
||||
if (!Files.exists(DIR)) {
|
||||
Files.createDirectories(DIR);
|
||||
@@ -100,6 +127,9 @@ public class CredentialStore {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the encryption key or creates a new one if it doesn't exist.
|
||||
*/
|
||||
private static SecretKey loadOrCreateKey() throws Exception {
|
||||
if (Files.exists(KEY_FILE)) {
|
||||
byte[] k = Files.readAllBytes(KEY_FILE);
|
||||
@@ -113,6 +143,9 @@ public class CredentialStore {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort attempt to set POSIX file permissions to owner-only.
|
||||
*/
|
||||
private static void trySetOwnerOnly(Path p) {
|
||||
try {
|
||||
// POSIX systems
|
||||
|
||||
@@ -18,6 +18,10 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Controller for handling the absences view.
|
||||
* Displays student absences, including a summary and detailed breakdown by date.
|
||||
*/
|
||||
@Route(path = "/absences", fxml = "/absences.fxml")
|
||||
public class AbsencesController extends DashboardBaseController {
|
||||
|
||||
@@ -35,12 +39,22 @@ public class AbsencesController extends DashboardBaseController {
|
||||
|
||||
private AbsencesPage currentPage;
|
||||
|
||||
/**
|
||||
* Initializes the controller when navigating to this view.
|
||||
* Initiates loading of absence data.
|
||||
*
|
||||
* @param props Navigation properties, not explicitly used here.
|
||||
*/
|
||||
@Override
|
||||
public void onNavigate(Map<String, Object> props) {
|
||||
super.onNavigate(props);
|
||||
loadAbsences();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the absences page from the API and updates the UI.
|
||||
* Shows a loading indicator while fetching.
|
||||
*/
|
||||
private void loadAbsences() {
|
||||
loadingIndicator.setVisible(true);
|
||||
scrollPane.setVisible(false);
|
||||
@@ -57,6 +71,11 @@ public class AbsencesController extends DashboardBaseController {
|
||||
}, QueryOptions.defaultOptions()).thenAccept(this::handleAbsencesResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the result of the absences fetch operation.
|
||||
*
|
||||
* @param result The result of the fetch.
|
||||
*/
|
||||
private void handleAbsencesResult(QueryResult<AbsencesPage> result) {
|
||||
Platform.runLater(() -> {
|
||||
loadingIndicator.setVisible(false);
|
||||
@@ -75,6 +94,9 @@ public class AbsencesController extends DashboardBaseController {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the absence summary and detail cards.
|
||||
*/
|
||||
private void renderAbsences() {
|
||||
summaryBox.getChildren().clear();
|
||||
detailFlow.getChildren().clear();
|
||||
@@ -111,6 +133,14 @@ public class AbsencesController extends DashboardBaseController {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a summary card UI component.
|
||||
*
|
||||
* @param title The title of the summary.
|
||||
* @param count The numerical value to display.
|
||||
* @param styleClass The CSS style class to apply for coloring.
|
||||
* @return The created VBox component.
|
||||
*/
|
||||
private VBox createSummaryCard(String title, int count, String styleClass) {
|
||||
VBox card = new VBox(5);
|
||||
card.setAlignment(Pos.CENTER);
|
||||
@@ -126,6 +156,13 @@ public class AbsencesController extends DashboardBaseController {
|
||||
return card;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an absence detail card UI component for a specific day.
|
||||
*
|
||||
* @param day The date of the absence.
|
||||
* @param info The absence information for the day.
|
||||
* @return The created VBox component.
|
||||
*/
|
||||
private VBox createAbsenceCard(LocalDate day, AbsenceInfo info) {
|
||||
VBox card = new VBox(8);
|
||||
card.getStyleClass().addAll("card", "absence-card");
|
||||
@@ -162,11 +199,20 @@ public class AbsencesController extends DashboardBaseController {
|
||||
return card;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a date for display.
|
||||
*
|
||||
* @param date The date to format.
|
||||
* @return The formatted date string.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private String formatDate(LocalDate date) {
|
||||
return date.getDayOfMonth() + ". " + date.getMonthNumber() + ". " + date.getYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles navigation back to the dashboard.
|
||||
*/
|
||||
@FXML
|
||||
protected void onBackToDashboard() {
|
||||
Router.getInstance().navigate("/dashboard");
|
||||
|
||||
@@ -12,6 +12,11 @@ import javafx.scene.layout.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Controller responsible for displaying detailed information about a specific classroom.
|
||||
* This includes fetching room data from the Jecna API and rendering the room's details,
|
||||
* such as its name, code, floor, and timetable.
|
||||
*/
|
||||
@Route(path = "/classroom_detail", fxml = "/classroom_detail.fxml")
|
||||
public class ClassroomDetailController extends DashboardBaseController {
|
||||
|
||||
@@ -32,6 +37,11 @@ public class ClassroomDetailController extends DashboardBaseController {
|
||||
|
||||
private String roomCode;
|
||||
|
||||
/**
|
||||
* Initializes the view with the specified room code.
|
||||
*
|
||||
* @param props a map containing the "code" of the room to display.
|
||||
*/
|
||||
@Override
|
||||
public void onNavigate(Map<String, Object> props) {
|
||||
super.onNavigate(props);
|
||||
@@ -45,6 +55,12 @@ public class ClassroomDetailController extends DashboardBaseController {
|
||||
loadRoom();
|
||||
}
|
||||
|
||||
@FXML
|
||||
@Override
|
||||
protected void onBack() {
|
||||
Router.getInstance().navigate("/classrooms");
|
||||
}
|
||||
|
||||
private void loadRoom() {
|
||||
loadingIndicator.setVisible(true);
|
||||
scrollPane.setVisible(false);
|
||||
@@ -121,10 +137,4 @@ public class ClassroomDetailController extends DashboardBaseController {
|
||||
|
||||
return row + 1;
|
||||
}
|
||||
|
||||
@FXML
|
||||
@Override
|
||||
protected void onBack() {
|
||||
Router.getInstance().navigate("/classrooms");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,11 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Controller for the classrooms view, which displays a list of available classrooms.
|
||||
* Users can search and filter classrooms, and clicking a classroom navigates
|
||||
* to its detailed view.
|
||||
*/
|
||||
@Route(path = "/classrooms", fxml = "/classrooms.fxml")
|
||||
public class ClassroomsController extends DashboardBaseController {
|
||||
|
||||
@@ -33,6 +38,11 @@ public class ClassroomsController extends DashboardBaseController {
|
||||
|
||||
private List<RoomReference> allRooms = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Initializes the view, sets up the search filter, and triggers loading of the classrooms.
|
||||
*
|
||||
* @param props navigation properties.
|
||||
*/
|
||||
@Override
|
||||
public void onNavigate(Map<String, Object> props) {
|
||||
super.onNavigate(props);
|
||||
@@ -115,6 +125,9 @@ public class ClassroomsController extends DashboardBaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates back to the dashboard.
|
||||
*/
|
||||
@FXML
|
||||
protected void onBackToDashboard() {
|
||||
Router.getInstance().navigate("/dashboard");
|
||||
|
||||
@@ -12,6 +12,10 @@ import cz.jzitnik.router.Router;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
|
||||
/**
|
||||
* Base controller for dashboard views.
|
||||
* Handles common functionality such as navigation and loading user profile information.
|
||||
*/
|
||||
public class DashboardBaseController implements Routable {
|
||||
|
||||
@InjectState
|
||||
@@ -48,9 +52,18 @@ public class DashboardBaseController implements Routable {
|
||||
protected void onDoNothing() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles navigation back to the home view.
|
||||
*/
|
||||
@FXML
|
||||
protected void onBack() { Router.getInstance().navigate("/home"); }
|
||||
|
||||
/**
|
||||
* Called when navigating to a dashboard view.
|
||||
* Initializes the welcome and class labels and fetches user profile data.
|
||||
*
|
||||
* @param props Navigation properties.
|
||||
*/
|
||||
@Override
|
||||
public void onNavigate(Map<String, Object> props) {
|
||||
if (welcomeLabel != null && classLabel != null) {
|
||||
|
||||
@@ -7,14 +7,26 @@ import javafx.fxml.FXML;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Controller for handling the main dashboard view.
|
||||
*/
|
||||
@Route(path = "/dashboard", fxml = "/dashboard_modern.fxml")
|
||||
public class DashboardController extends DashboardBaseController {
|
||||
|
||||
/**
|
||||
* Called when navigating to the dashboard view.
|
||||
*
|
||||
* @param props Navigation properties.
|
||||
*/
|
||||
@Override
|
||||
public void onNavigate(Map<String, Object> props) {
|
||||
super.onNavigate(props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the logout action.
|
||||
* Clears application state, credentials, and navigates back to the login screen.
|
||||
*/
|
||||
@FXML
|
||||
public void onLogoutClick() {
|
||||
appState.clear();
|
||||
|
||||
@@ -20,6 +20,10 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Controller for handling the grades view.
|
||||
* Displays student grades grouped by subject and allows grade prediction.
|
||||
*/
|
||||
@Route(path = "/grades", fxml = "/grades.fxml")
|
||||
public class GradesController extends DashboardBaseController {
|
||||
|
||||
@@ -35,8 +39,20 @@ public class GradesController extends DashboardBaseController {
|
||||
private GradesPage currentPage;
|
||||
private final Map<String, List<PredictedGrade>> predictions = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Represents a predicted grade.
|
||||
*
|
||||
* @param value The grade value (1-5).
|
||||
* @param isSmall Whether the grade has a smaller weight.
|
||||
*/
|
||||
public record PredictedGrade(int value, boolean isSmall) {}
|
||||
|
||||
/**
|
||||
* Initializes the controller when navigating to this view.
|
||||
* Clears previous predictions and initiates loading of grades data.
|
||||
*
|
||||
* @param props Navigation properties, not explicitly used here.
|
||||
*/
|
||||
@Override
|
||||
public void onNavigate(Map<String, Object> props) {
|
||||
super.onNavigate(props);
|
||||
@@ -44,6 +60,10 @@ public class GradesController extends DashboardBaseController {
|
||||
loadGrades();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the grades page from the API and updates the UI.
|
||||
* Shows a loading indicator while fetching.
|
||||
*/
|
||||
private void loadGrades() {
|
||||
loadingIndicator.setVisible(true);
|
||||
scrollPane.setVisible(false);
|
||||
@@ -59,6 +79,11 @@ public class GradesController extends DashboardBaseController {
|
||||
}, QueryOptions.defaultOptions()).thenAccept(this::handleGradesResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the result of the grades fetch operation.
|
||||
*
|
||||
* @param result The result of the fetch.
|
||||
*/
|
||||
private void handleGradesResult(QueryResult<GradesPage> result) {
|
||||
Platform.runLater(() -> {
|
||||
loadingIndicator.setVisible(false);
|
||||
@@ -78,6 +103,9 @@ public class GradesController extends DashboardBaseController {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders all subjects and their grades.
|
||||
*/
|
||||
private void renderAllSubjects() {
|
||||
contentBox.getChildren().clear();
|
||||
contentBox.setAlignment(Pos.TOP_CENTER);
|
||||
@@ -95,6 +123,13 @@ public class GradesController extends DashboardBaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the average grade for a subject, including predictions.
|
||||
*
|
||||
* @param subject The subject.
|
||||
* @param preds List of predicted grades.
|
||||
* @return The calculated average, or null if no grades.
|
||||
*/
|
||||
private Float calculateAverage(Subject subject, List<PredictedGrade> preds) {
|
||||
float sum = 0;
|
||||
float count = 0;
|
||||
@@ -122,6 +157,12 @@ public class GradesController extends DashboardBaseController {
|
||||
return count > 0 ? sum / count : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a subject card UI component.
|
||||
*
|
||||
* @param subject The subject.
|
||||
* @return The created VBox component.
|
||||
*/
|
||||
private VBox createSubjectCard(Subject subject) {
|
||||
String subjectNameFull = subject.getName().getFull();
|
||||
List<PredictedGrade> preds = predictions.getOrDefault(subjectNameFull, new ArrayList<>());
|
||||
@@ -208,6 +249,12 @@ public class GradesController extends DashboardBaseController {
|
||||
return card;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a dialog to add a predicted grade.
|
||||
*
|
||||
* @param subjectNameFull Full subject name.
|
||||
* @param preds List of existing predictions for the subject.
|
||||
*/
|
||||
private void showPredictionDialog(String subjectNameFull, List<PredictedGrade> preds) {
|
||||
Dialog<PredictedGrade> dialog = new Dialog<>();
|
||||
dialog.setTitle("Nová predikce");
|
||||
@@ -247,6 +294,18 @@ public class GradesController extends DashboardBaseController {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a grade badge UI component.
|
||||
*
|
||||
* @param value The grade value.
|
||||
* @param isSmall Whether it's a small grade.
|
||||
* @param valueChar The character representation of the grade (if not numeric).
|
||||
* @param isPredicted Whether this is a predicted grade.
|
||||
* @param desc Description of the grade.
|
||||
* @param teacher Teacher who gave the grade.
|
||||
* @param date Date the grade was received.
|
||||
* @return The created StackPane component.
|
||||
*/
|
||||
private StackPane createGradeBadge(int value, boolean isSmall, char valueChar, boolean isPredicted, String desc, String teacher, String date) {
|
||||
StackPane badge = new StackPane();
|
||||
String valStr = String.valueOf(valueChar);
|
||||
@@ -302,6 +361,13 @@ public class GradesController extends DashboardBaseController {
|
||||
return badge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a dialog with grade details.
|
||||
*
|
||||
* @param desc Description of the grade.
|
||||
* @param teacher Teacher who gave the grade.
|
||||
* @param date Date the grade was received.
|
||||
*/
|
||||
private void showGradeDetailsDialog(String desc, String teacher, String date) {
|
||||
Dialog<Void> dialog = new Dialog<>();
|
||||
dialog.setTitle("Detail známky");
|
||||
@@ -325,6 +391,9 @@ public class GradesController extends DashboardBaseController {
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles navigation back to the dashboard.
|
||||
*/
|
||||
@FXML
|
||||
protected void onBackToDashboard() {
|
||||
Router.getInstance().navigate("/dashboard");
|
||||
|
||||
@@ -10,6 +10,9 @@ import javafx.scene.control.Label;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Controller for handling the home view.
|
||||
*/
|
||||
@Route(path = "/home", fxml = "/home.fxml")
|
||||
public class HomeController implements Routable {
|
||||
|
||||
@@ -19,6 +22,12 @@ public class HomeController implements Routable {
|
||||
@FXML
|
||||
private Label welcomeLabel;
|
||||
|
||||
/**
|
||||
* Called when navigating to the home view.
|
||||
* Updates the welcome label with the username.
|
||||
*
|
||||
* @param props Navigation properties.
|
||||
*/
|
||||
@Override
|
||||
public void onNavigate(Map<String, Object> props) {
|
||||
String username = appState.getUsername();
|
||||
@@ -27,6 +36,9 @@ public class HomeController implements Routable {
|
||||
welcomeLabel.setText("Welcome, " + username + "!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the logout action.
|
||||
*/
|
||||
@FXML
|
||||
public void onLogoutClick() {
|
||||
appState.clear();
|
||||
|
||||
@@ -11,6 +11,9 @@ import javafx.scene.control.*;
|
||||
import java.util.Map;
|
||||
import javafx.application.Platform;
|
||||
|
||||
/**
|
||||
* Controller for handling the login view.
|
||||
*/
|
||||
@Route(path = "/login", fxml = "/login.fxml")
|
||||
public class LoginController implements Routable {
|
||||
|
||||
@@ -29,10 +32,18 @@ public class LoginController implements Routable {
|
||||
@FXML
|
||||
private ProgressIndicator loadingIndicator;
|
||||
|
||||
/**
|
||||
* Called when navigating to the login view.
|
||||
*
|
||||
* @param props Navigation properties.
|
||||
*/
|
||||
@Override
|
||||
public void onNavigate(Map<String, Object> props) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the login action. Initiates the login process in a background thread.
|
||||
*/
|
||||
@FXML
|
||||
public void onLoginClick() {
|
||||
final String username = usernameField.getText();
|
||||
@@ -63,6 +74,9 @@ public class LoginController implements Routable {
|
||||
}, "login-thread").start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles username action (e.g., pressing enter) by requesting focus on the password field.
|
||||
*/
|
||||
@FXML
|
||||
public void onUsernameAction() {
|
||||
passwordField.requestFocus();
|
||||
|
||||
@@ -13,6 +13,10 @@ import javafx.scene.web.WebView;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Controller for handling the Moodle integration view.
|
||||
* Displays a WebView with the Moodle website and handles automatic login.
|
||||
*/
|
||||
@Route(path = "/moodle", fxml = "/moodle.fxml")
|
||||
public class MoodleController extends DashboardBaseController {
|
||||
|
||||
@@ -33,6 +37,12 @@ public class MoodleController extends DashboardBaseController {
|
||||
|
||||
private WebEngine webEngine;
|
||||
|
||||
/**
|
||||
* Initializes the controller when navigating to this view.
|
||||
* Sets up the WebView, auto-login logic, and navigation buttons.
|
||||
*
|
||||
* @param props Navigation properties, not explicitly used here.
|
||||
*/
|
||||
@Override
|
||||
public void onNavigate(Map<String, Object> props) {
|
||||
super.onNavigate(props);
|
||||
@@ -104,6 +114,9 @@ public class MoodleController extends DashboardBaseController {
|
||||
webEngine.load("https://moodle.spsejecna.cz/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the back and forward navigation buttons state.
|
||||
*/
|
||||
private void updateNavigationButtons() {
|
||||
WebHistory history = webEngine.getHistory();
|
||||
int currentIndex = history.getCurrentIndex();
|
||||
@@ -129,6 +142,9 @@ public class MoodleController extends DashboardBaseController {
|
||||
btnForward.setDisable(validForwardIndex == -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates back in the WebView history.
|
||||
*/
|
||||
@FXML
|
||||
protected void onBrowserBack() {
|
||||
WebHistory history = webEngine.getHistory();
|
||||
@@ -142,6 +158,9 @@ public class MoodleController extends DashboardBaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates forward in the WebView history.
|
||||
*/
|
||||
@FXML
|
||||
protected void onBrowserForward() {
|
||||
WebHistory history = webEngine.getHistory();
|
||||
@@ -155,11 +174,17 @@ public class MoodleController extends DashboardBaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the current page in the WebView.
|
||||
*/
|
||||
@FXML
|
||||
protected void onBrowserReload() {
|
||||
webEngine.reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles navigation back to the dashboard.
|
||||
*/
|
||||
@FXML
|
||||
protected void onBackToDashboard() {
|
||||
Router.getInstance().navigate("/dashboard");
|
||||
|
||||
@@ -15,6 +15,10 @@ import javafx.scene.layout.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Controller for handling the teacher profile view.
|
||||
* Displays details about a specific teacher, including contact information and their timetable.
|
||||
*/
|
||||
@Route(path = "/teacher_profile", fxml = "/teacher_profile.fxml")
|
||||
public class TeacherProfileController extends DashboardBaseController {
|
||||
|
||||
@@ -44,6 +48,12 @@ public class TeacherProfileController extends DashboardBaseController {
|
||||
|
||||
private String teacherTag;
|
||||
|
||||
/**
|
||||
* Initializes the controller when navigating to this view.
|
||||
* Sets the teacher tag from navigation properties and initiates data loading.
|
||||
*
|
||||
* @param props Navigation properties, must contain a "tag" key with the teacher's tag.
|
||||
*/
|
||||
@Override
|
||||
public void onNavigate(Map<String, Object> props) {
|
||||
super.onNavigate(props);
|
||||
@@ -57,6 +67,10 @@ public class TeacherProfileController extends DashboardBaseController {
|
||||
loadTeacher();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the teacher profile from the API and updates the UI.
|
||||
* Shows a loading indicator while fetching.
|
||||
*/
|
||||
private void loadTeacher() {
|
||||
loadingIndicator.setVisible(true);
|
||||
scrollPane.setVisible(false);
|
||||
@@ -85,6 +99,11 @@ public class TeacherProfileController extends DashboardBaseController {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the teacher profile information into the UI.
|
||||
*
|
||||
* @param teacher The teacher object to display.
|
||||
*/
|
||||
private void renderTeacher(Teacher teacher) {
|
||||
headerNameLabel.setText(teacher.getFullName());
|
||||
fullNameLabel.setText(teacher.getFullName());
|
||||
@@ -127,6 +146,14 @@ public class TeacherProfileController extends DashboardBaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a row of detail information to the details grid.
|
||||
*
|
||||
* @param labelText The label text for the detail.
|
||||
* @param value The value of the detail.
|
||||
* @param row The row index in the grid.
|
||||
* @return The next row index.
|
||||
*/
|
||||
private int addDetailRow(String labelText, String value, int row) {
|
||||
if (value == null || value.isBlank()) {
|
||||
return row;
|
||||
@@ -145,6 +172,9 @@ public class TeacherProfileController extends DashboardBaseController {
|
||||
return row + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles navigation back to the teachers list view.
|
||||
*/
|
||||
@FXML
|
||||
@Override
|
||||
protected void onBack() {
|
||||
|
||||
@@ -15,6 +15,10 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Controller for handling the teachers list view.
|
||||
* Provides functionality to display, search, and navigate to teacher profiles.
|
||||
*/
|
||||
@Route(path = "/teachers", fxml = "/teachers.fxml")
|
||||
public class TeachersController extends DashboardBaseController {
|
||||
|
||||
@@ -32,6 +36,12 @@ public class TeachersController extends DashboardBaseController {
|
||||
|
||||
private List<TeacherReference> allTeachers = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Initializes the controller when navigating to this view.
|
||||
* Sets up the search filter and initiates data loading.
|
||||
*
|
||||
* @param props Navigation properties, not explicitly used here.
|
||||
*/
|
||||
@Override
|
||||
public void onNavigate(Map<String, Object> props) {
|
||||
super.onNavigate(props);
|
||||
@@ -43,6 +53,10 @@ public class TeachersController extends DashboardBaseController {
|
||||
loadTeachers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the list of teachers from the API and updates the UI.
|
||||
* Shows a loading indicator while fetching.
|
||||
*/
|
||||
private void loadTeachers() {
|
||||
loadingIndicator.setVisible(true);
|
||||
scrollPane.setVisible(false);
|
||||
@@ -76,6 +90,11 @@ public class TeachersController extends DashboardBaseController {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the list of teachers based on the provided search query.
|
||||
*
|
||||
* @param query The search string to filter by.
|
||||
*/
|
||||
private void filterTeachers(String query) {
|
||||
teachersFlow.getChildren().clear();
|
||||
|
||||
@@ -113,6 +132,9 @@ public class TeachersController extends DashboardBaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles navigation back to the dashboard.
|
||||
*/
|
||||
@FXML
|
||||
protected void onBackToDashboard() {
|
||||
Router.getInstance().navigate("/dashboard");
|
||||
|
||||
@@ -21,6 +21,10 @@ import kotlinx.datetime.DayOfWeek;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Controller for handling the timetable view.
|
||||
* Displays the weekly timetable for the student.
|
||||
*/
|
||||
@Route(path = "/timetable", fxml = "/timetable.fxml")
|
||||
public class TimetableController extends DashboardBaseController {
|
||||
|
||||
@@ -35,12 +39,22 @@ public class TimetableController extends DashboardBaseController {
|
||||
|
||||
private TimetablePage currentPage;
|
||||
|
||||
/**
|
||||
* Initializes the controller when navigating to this view.
|
||||
* Initiates loading of timetable data.
|
||||
*
|
||||
* @param props Navigation properties, not explicitly used here.
|
||||
*/
|
||||
@Override
|
||||
public void onNavigate(Map<String, Object> props) {
|
||||
super.onNavigate(props);
|
||||
loadTimetable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the timetable page from the API and updates the UI.
|
||||
* Shows a loading indicator while fetching.
|
||||
*/
|
||||
private void loadTimetable() {
|
||||
loadingIndicator.setVisible(true);
|
||||
scrollPane.setVisible(false);
|
||||
@@ -56,6 +70,11 @@ public class TimetableController extends DashboardBaseController {
|
||||
}, QueryOptions.defaultOptions()).thenAccept(this::handleTimetableResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the result of the timetable fetch operation.
|
||||
*
|
||||
* @param result The result of the fetch.
|
||||
*/
|
||||
private void handleTimetableResult(QueryResult<TimetablePage> result) {
|
||||
Platform.runLater(() -> {
|
||||
loadingIndicator.setVisible(false);
|
||||
@@ -75,6 +94,9 @@ public class TimetableController extends DashboardBaseController {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the timetable grid using the TimetableRenderer.
|
||||
*/
|
||||
private void renderTimetable() {
|
||||
timetableGrid.getChildren().clear();
|
||||
timetableGrid.getColumnConstraints().clear();
|
||||
@@ -85,6 +107,9 @@ public class TimetableController extends DashboardBaseController {
|
||||
TimetableRenderer.renderTimetable(timetableGrid, timetable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles navigation back to the dashboard.
|
||||
*/
|
||||
@FXML
|
||||
protected void onBackToDashboard() {
|
||||
Router.getInstance().navigate("/dashboard");
|
||||
|
||||
@@ -4,11 +4,23 @@ import java.util.Map;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A client for handling data fetching with caching and background updates.
|
||||
*/
|
||||
public class QueryClient {
|
||||
|
||||
private final Map<String, CachedItem<?>> cache = new ConcurrentHashMap<>();
|
||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||
|
||||
/**
|
||||
* Fetches data with caching support.
|
||||
*
|
||||
* @param key The cache key.
|
||||
* @param fetcher Supplier for fetching data if not cached or stale.
|
||||
* @param opts Query options for caching behavior.
|
||||
* @param <T> The type of data.
|
||||
* @return A CompletableFuture with the result.
|
||||
*/
|
||||
public <T> CompletableFuture<QueryResult<T>> fetch(String key, Supplier<T> fetcher, QueryOptions opts) {
|
||||
@SuppressWarnings("unchecked") CachedItem<T> item = (CachedItem<T>) cache.get(key);
|
||||
long now = System.currentTimeMillis();
|
||||
@@ -53,14 +65,29 @@ public class QueryClient {
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually sets an item in the cache.
|
||||
*
|
||||
* @param key The cache key.
|
||||
* @param value The value to cache.
|
||||
* @param <T> The type of data.
|
||||
*/
|
||||
public <T> void set(String key, T value) {
|
||||
cache.put(key, new CachedItem<>(value, System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates a cache item.
|
||||
*
|
||||
* @param key The cache key to remove.
|
||||
*/
|
||||
public void invalidate(String key) {
|
||||
cache.remove(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down the scheduler.
|
||||
*/
|
||||
public void shutdown() {
|
||||
scheduler.shutdownNow();
|
||||
}
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
package cz.jzitnik.query;
|
||||
|
||||
/**
|
||||
* Configuration options for query operations, such as caching and retries.
|
||||
*/
|
||||
public class QueryOptions {
|
||||
// time until data is considered stale (ms)
|
||||
public long staleTime = 5 * 60 * 1000; // 5 minutes
|
||||
// time until unused cache entry is evicted (ms)
|
||||
public long cacheTime = 30 * 60 * 1000; // 30 minutes
|
||||
// if >0, interval to refetch in background (ms)
|
||||
/** Time until data is considered stale (ms). Default: 5 minutes. */
|
||||
public long staleTime = 5 * 60 * 1000;
|
||||
/** Time until unused cache entry is evicted (ms). Default: 30 minutes. */
|
||||
public long cacheTime = 30 * 60 * 1000;
|
||||
/** If > 0, interval to refetch in background (ms). Default: 0 (disabled). */
|
||||
public long refetchInterval = 0;
|
||||
// number of retry attempts on failure
|
||||
/** Number of retry attempts on failure. Default: 0. */
|
||||
public int retryAttempts = 0;
|
||||
|
||||
/**
|
||||
* Creates new default query options.
|
||||
*/
|
||||
public QueryOptions() {}
|
||||
|
||||
/**
|
||||
* Returns default query options.
|
||||
*
|
||||
* @return Default QueryOptions instance.
|
||||
*/
|
||||
public static QueryOptions defaultOptions() {
|
||||
return new QueryOptions();
|
||||
}
|
||||
|
||||
@@ -3,19 +3,53 @@ package cz.jzitnik.query;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents the result of a query operation.
|
||||
*
|
||||
* @param <T> The type of the data.
|
||||
*/
|
||||
public class QueryResult<T> {
|
||||
private final T data;
|
||||
private final Throwable error;
|
||||
private final Instant fetchedAt;
|
||||
|
||||
/**
|
||||
* Creates a new QueryResult.
|
||||
*
|
||||
* @param data The query data, or null if an error occurred.
|
||||
* @param error The error, or null if successful.
|
||||
*/
|
||||
public QueryResult(T data, Throwable error) {
|
||||
this.data = data;
|
||||
this.error = error;
|
||||
this.fetchedAt = Instant.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data.
|
||||
*
|
||||
* @return Optional containing the data.
|
||||
*/
|
||||
public Optional<T> getData() { return Optional.ofNullable(data); }
|
||||
|
||||
/**
|
||||
* Gets the error.
|
||||
*
|
||||
* @return Optional containing the error.
|
||||
*/
|
||||
public Optional<Throwable> getError() { return Optional.ofNullable(error); }
|
||||
|
||||
/**
|
||||
* Gets the fetch time.
|
||||
*
|
||||
* @return The fetch time.
|
||||
*/
|
||||
public Instant getFetchedAt() { return fetchedAt; }
|
||||
|
||||
/**
|
||||
* Checks if the query was successful.
|
||||
*
|
||||
* @return True if successful, false otherwise.
|
||||
*/
|
||||
public boolean isSuccess() { return error == null; }
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A simple router for navigating between views in a JavaFX application.
|
||||
*/
|
||||
public class Router {
|
||||
private static Router instance;
|
||||
private Pane rootContainer;
|
||||
@@ -18,6 +21,11 @@ public class Router {
|
||||
|
||||
private Router() {}
|
||||
|
||||
/**
|
||||
* Gets the singleton instance of the router.
|
||||
*
|
||||
* @return The Router instance.
|
||||
*/
|
||||
public static Router getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Router();
|
||||
@@ -25,10 +33,20 @@ public class Router {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the root container pane for the router.
|
||||
*
|
||||
* @param rootContainer The root container.
|
||||
*/
|
||||
public void setRootContainer(Pane rootContainer) {
|
||||
this.rootContainer = rootContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers routes annotated with @Route in the specified base package.
|
||||
*
|
||||
* @param basePackage The base package to scan for routes.
|
||||
*/
|
||||
public void registerAnnotatedRoutes(String basePackage) {
|
||||
Reflections r = new Reflections(basePackage);
|
||||
Set<Class<?>> controllers = r.getTypesAnnotatedWith(Route.class);
|
||||
@@ -40,10 +58,21 @@ public class Router {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates to a specific path.
|
||||
*
|
||||
* @param path The path to navigate to.
|
||||
*/
|
||||
public void navigate(String path) {
|
||||
navigate(path, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates to a specific path with navigation properties.
|
||||
*
|
||||
* @param path The path to navigate to.
|
||||
* @param props Navigation properties.
|
||||
*/
|
||||
public void navigate(String path, Map<String, Object> props) {
|
||||
if (rootContainer == null) {
|
||||
throw new IllegalStateException("Root container not set in Router.");
|
||||
|
||||
@@ -4,6 +4,11 @@ import cz.jzitnik.auth.CredentialStore;
|
||||
import io.github.tomhula.jecnaapi.java.JecnaClientJavaWrapper;
|
||||
import cz.jzitnik.query.QueryClient;
|
||||
|
||||
/**
|
||||
* Manages the current application state, including user authentication and API interactions.
|
||||
* This class serves as the central hub for tracking the logged-in user, managing
|
||||
* the active Jecna API client session, and providing access to query tools.
|
||||
*/
|
||||
@State
|
||||
public class AppState {
|
||||
|
||||
@@ -12,26 +17,59 @@ public class AppState {
|
||||
private JecnaClientJavaWrapper client;
|
||||
private QueryClient queryClient;
|
||||
|
||||
/**
|
||||
* Gets the username of the currently logged-in user.
|
||||
*
|
||||
* @return the username, or null if no user is logged in.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the password of the currently logged-in user.
|
||||
*
|
||||
* @return the password, or null if no user is logged in.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the active Jecna API client wrapper.
|
||||
*
|
||||
* @return the Jecna API client instance, or null if not initialized/logged in.
|
||||
*/
|
||||
public JecnaClientJavaWrapper getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the query client used for fetching specific data.
|
||||
*
|
||||
* @return the QueryClient instance.
|
||||
*/
|
||||
public QueryClient getQueryClient() {
|
||||
return queryClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query client for this state.
|
||||
*
|
||||
* @param qc the QueryClient instance to use.
|
||||
*/
|
||||
public void setQueryClient(QueryClient qc) {
|
||||
this.queryClient = qc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to log the user into the Jecna API with the provided credentials.
|
||||
* If successful, it stores the credentials securely for future sessions.
|
||||
*
|
||||
* @param username the user's username.
|
||||
* @param password the user's password.
|
||||
* @return true if login was successful, false otherwise.
|
||||
*/
|
||||
public boolean login(String username, String password) {
|
||||
if (username == null || username.isEmpty() || password == null) return false;
|
||||
|
||||
@@ -61,6 +99,10 @@ public class AppState {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the current application state, including logging out the user
|
||||
* and resetting the API client.
|
||||
*/
|
||||
public void clear() {
|
||||
this.username = null;
|
||||
this.password = null;
|
||||
|
||||
@@ -11,8 +11,14 @@ import javafx.scene.paint.Color;
|
||||
import javafx.scene.shape.Circle;
|
||||
import javafx.util.Duration;
|
||||
|
||||
/**
|
||||
* A UI component that displays an animated aurora-like background.
|
||||
*/
|
||||
public class AuroraBackground extends StackPane {
|
||||
|
||||
/**
|
||||
* Initializes the aurora background with animated blobs of color.
|
||||
*/
|
||||
public AuroraBackground() {
|
||||
Color color1 = Color.web("#00FFFF", 0.10); // Cyan
|
||||
Color color2 = Color.web("#FF00FF", 0.10); // Magenta
|
||||
@@ -38,6 +44,16 @@ public class AuroraBackground extends StackPane {
|
||||
setupAnimation(blob3, 0, -200, 0, 200, 15);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the animation for a color blob.
|
||||
*
|
||||
* @param node The circle node to animate.
|
||||
* @param startX Starting X translation.
|
||||
* @param startY Starting Y translation.
|
||||
* @param endX Ending X translation.
|
||||
* @param endY Ending Y translation.
|
||||
* @param durationSeconds Duration of the animation in seconds.
|
||||
*/
|
||||
private void setupAnimation(Circle node, double startX, double startY, double endX, double endY, int durationSeconds) {
|
||||
Timeline timeline = new Timeline(
|
||||
new KeyFrame(Duration.ZERO,
|
||||
|
||||
@@ -8,8 +8,20 @@ import java.net.URL;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
/**
|
||||
* A little utility to grab images from the school website.
|
||||
* Since the server can be picky about requests, we have to pretend
|
||||
* to be a real browser to get the files successfully.
|
||||
*/
|
||||
public class ImageFetcher {
|
||||
|
||||
/**
|
||||
* Fetches an image from the school server, handling decompression
|
||||
* and proper headers to avoid being blocked.
|
||||
*
|
||||
* @param imagePath The relative path to the image on the school server.
|
||||
* @return The loaded JavaFX Image, or null if something went wrong.
|
||||
*/
|
||||
public static Image fetchImage(String imagePath) {
|
||||
if (imagePath == null || imagePath.isEmpty()) {
|
||||
return null;
|
||||
|
||||
@@ -7,8 +7,18 @@ import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.input.ScrollEvent;
|
||||
import javafx.util.Duration;
|
||||
|
||||
/**
|
||||
* Helps make scrolling through the app feel a bit more premium.
|
||||
* Instead of jumping straight to the new position, this gently animates
|
||||
* the scroll, making it much easier on the eyes.
|
||||
*/
|
||||
public class ScrollUtils {
|
||||
|
||||
/**
|
||||
* Enables smooth, animated scrolling for a given ScrollPane.
|
||||
*
|
||||
* @param scrollPane The ScrollPane we want to make feel smoother.
|
||||
*/
|
||||
public static void enableSmoothScrolling(ScrollPane scrollPane) {
|
||||
scrollPane.addEventFilter(ScrollEvent.SCROLL, event -> {
|
||||
double deltaY = event.getDeltaY();
|
||||
|
||||
@@ -21,8 +21,17 @@ import kotlinx.datetime.DayOfWeek;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utility class for rendering the timetable in a JavaFX GridPane.
|
||||
*/
|
||||
public class TimetableRenderer {
|
||||
|
||||
/**
|
||||
* Renders the timetable into the provided GridPane.
|
||||
*
|
||||
* @param timetableGrid The GridPane to render into.
|
||||
* @param timetable The timetable data to render.
|
||||
*/
|
||||
public static void renderTimetable(GridPane timetableGrid, Timetable timetable) {
|
||||
timetableGrid.getChildren().clear();
|
||||
timetableGrid.getColumnConstraints().clear();
|
||||
@@ -92,6 +101,12 @@ public class TimetableRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cell UI component for a lesson spot.
|
||||
*
|
||||
* @param spot The lesson spot data.
|
||||
* @return The created VBox component.
|
||||
*/
|
||||
private static VBox createLessonCell(LessonSpot spot) {
|
||||
VBox cell = new VBox(5);
|
||||
cell.setAlignment(Pos.CENTER);
|
||||
@@ -131,6 +146,12 @@ public class TimetableRenderer {
|
||||
return cell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds lesson information to a cell UI component.
|
||||
*
|
||||
* @param cell The cell UI component.
|
||||
* @param lesson The lesson data.
|
||||
*/
|
||||
private static 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");
|
||||
@@ -153,6 +174,11 @@ public class TimetableRenderer {
|
||||
cell.getChildren().addAll(subjectLbl, bottomInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a dialog with detailed lesson information.
|
||||
*
|
||||
* @param spot The lesson spot data.
|
||||
*/
|
||||
private static void showLessonDetails(LessonSpot spot) {
|
||||
Dialog<Void> dialog = new Dialog<>();
|
||||
dialog.setTitle("Detail hodiny");
|
||||
@@ -209,6 +235,12 @@ public class TimetableRenderer {
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates DayOfWeek to a Czech string.
|
||||
*
|
||||
* @param day The DayOfWeek.
|
||||
* @return The translated day name.
|
||||
*/
|
||||
private static String translateDay(DayOfWeek day) {
|
||||
return switch (day) {
|
||||
case MONDAY -> "Pondělí";
|
||||
|
||||
Reference in New Issue
Block a user