diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/Popup.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/Popup.java
index e0d27dd..e4be32b 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/Popup.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/Popup.java
@@ -156,7 +156,6 @@ private void loadStylesheets() {
}
}
-
private Button buildCloseButton() {
Button button = new Button();
button.setShape(new Circle(6));
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/AppStoreApp.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/AppStoreApp.java
index fed24d1..45148dc 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/AppStoreApp.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/AppStoreApp.java
@@ -4,18 +4,29 @@
import edu.ntnu.idi.idatt2003.gruppe42.view.Popup;
/**
- * A popup for the app store app.
+ * A popup window for the App Store application.
+ *
+ *
This popup is responsible for displaying available applications and related
+ * store functionality.
*/
public class AppStoreApp extends Popup {
/**
- * Constructs a new app store popup.
+ * Constructs a new App Store popup.
+ *
+ *
Initializes the popup with default size and position, and builds its UI content.
*/
public AppStoreApp() {
super(500, 450, 100, 100, App.APPSTORE);
buildContent();
}
+ /**
+ * Builds the UI content for the App Store popup.
+ *
+ *
This method is responsible for constructing and populating all visual
+ * components inside the popup.
+ */
private void buildContent() {
}
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/BankApp.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/BankApp.java
index 9d34d70..733ae01 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/BankApp.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/BankApp.java
@@ -19,7 +19,12 @@
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
-/** Bank app popup showing portfolio summary. */
+/**
+ * Bank application popup showing the player's portfolio and financial summary.
+ *
+ *
Displays total net worth, cash, invested value, return percentage, and a detailed
+ * list of owned shares with live market values and gains.
+ */
public class BankApp extends Popup {
private static final String POSITIVE_STYLE = "stock-price-positive";
@@ -33,7 +38,11 @@ public class BankApp extends Popup {
private Consumer onShareSelected;
- /** Constructs the Bank app. */
+ /**
+ * Constructs the Bank app popup.
+ *
+ * Initializes the portfolio list view and builds the UI layout.
+ */
public BankApp() {
super(600, 550, 220, 100, App.BANK);
@@ -123,7 +132,14 @@ private VBox summaryItem(String title, Label valueLabel) {
return box;
}
- /** Refreshes summary with latest figures. */
+ /**
+ * Updates the financial summary values displayed in the UI.
+ *
+ * @param netWorth the player's total net worth
+ * @param cash the available cash balance
+ * @param invested the total invested amount
+ * @param startingMoney the initial starting capital used to calculate return percentage
+ */
public void updateStatus(double netWorth, double cash, double invested, double startingMoney) {
Platform.runLater(() -> {
netWorthLabel.setText(formatUsd(netWorth));
@@ -137,12 +153,15 @@ public void updateStatus(double netWorth, double cash, double invested, double s
});
}
- /** @return the portfolio list view. */
public ListView getPortfolioList() {
return portfolioList;
}
- /** Sets the share selection callback. */
+ /**
+ * Sets a callback triggered when a share is selected in the portfolio list.
+ *
+ * @param onShareSelected consumer handling the selected share
+ */
public void setOnShareSelected(Consumer onShareSelected) {
this.onShareSelected = onShareSelected;
}
@@ -161,7 +180,11 @@ private static String formatUsd(double amount) {
return "$" + String.format("%,.2f", amount);
}
- /** Renders a single share holding row. */
+ /**
+ * List cell representing a single share holding in the portfolio.
+ *
+ * Displays symbol, company name, quantity, prices, market value, and gain/loss.
+ */
private class ShareCell extends ListCell {
private static final double COL_SYMBOL_MIN = 120;
@@ -251,6 +274,12 @@ private void addCellContent() {
grid.add(gainBox, 3, 0);
}
+ /**
+ * Updates the cell content for a given share.
+ *
+ * @param share the share to display
+ * @param empty whether the cell is empty
+ */
@Override
protected void updateItem(Share share, boolean empty) {
super.updateItem(share, empty);
@@ -271,7 +300,7 @@ private void populateLabels(Share share) {
BigDecimal marketValue = currentPrice.multiply(quantity);
BigDecimal totalCost = purchasePrice.multiply(quantity);
BigDecimal gain = marketValue.subtract(totalCost);
- BigDecimal gainPercent = computeGainPercent(gain, totalCost);
+ final BigDecimal gainPercent = computeGainPercent(gain, totalCost);
symbolLabel.setText(share.getStock().getSymbol());
companyLabel.setText(share.getStock().getCompany());
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/FilePickerApp.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/FilePickerApp.java
index 7ba8668..26d9b3c 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/FilePickerApp.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/FilePickerApp.java
@@ -18,11 +18,14 @@
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
-/** File picker app. */
+/**
+ * File picker popup used to browse the local file system and select CSV files.
+ *
+ * The picker provides navigation (back, forward, up), a quick access sidebar,
+ * and a selectable file list filtered to CSV files.
+ */
public class FilePickerApp extends Popup {
-
private static final String FILTER = ".csv";
-
private final Button backButton = new Button("←");
private final Button forwardButton = new Button("→");
private final Button upButton = new Button("↑");
@@ -47,6 +50,10 @@ public class FilePickerApp extends Popup {
private File selectedFile;
private Consumer onFileConfirmed;
+ /**
+ * Constructs a new file picker popup.
+ * Initializes UI and loads the initial directory view.
+ */
public FilePickerApp() {
super(580, 420, 80, 60, App.FILEPICKER);
buildLayout();
@@ -54,7 +61,10 @@ public FilePickerApp() {
populateDir(currentDir);
}
-
+ /**
+ * Builds the full layout of the file picker including sidebar,
+ * toolbar, file list, and bottom action bar.
+ */
private void buildLayout() {
backButton.getStyleClass().add("fp-toolbar-button");
forwardButton.getStyleClass().add("fp-toolbar-button");
@@ -84,7 +94,11 @@ private void buildLayout() {
String[] names = { "Home", "Desktop", "Documents", "Downloads" };
for (int i = 0; i < QUICK_ACCESS.length; i++) {
File dir = QUICK_ACCESS[i];
- if (!dir.exists()) continue;
+
+ if (!dir.exists()) {
+ continue;
+ }
+
Button btn = new Button(icons[i] + " " + names[i]);
btn.getStyleClass().add("fp-sidebar-item");
btn.setMaxWidth(Double.MAX_VALUE);
@@ -130,7 +144,7 @@ private void buildLayout() {
HBox nameRow = new HBox(8, new Label("File name:"), selectedField, filterLabel);
nameRow.setAlignment(Pos.CENTER_LEFT);
- ((Label) nameRow.getChildren().get(0)).getStyleClass().add("fp-bottom-label");
+ (nameRow.getChildren().get(0)).getStyleClass().add("fp-bottom-label");
HBox buttonRow = new HBox(6, openButton, cancelButton);
buttonRow.setAlignment(Pos.CENTER_RIGHT);
@@ -145,6 +159,11 @@ private void buildLayout() {
content.setPrefSize(580, 420);
}
+ /**
+ * Builds the column header row for the file list.
+ *
+ * @return header HBox containing column labels
+ */
private HBox buildColumnHeader() {
Label nameCol = new Label("Name");
Label typeCol = new Label("Type");
@@ -162,7 +181,9 @@ private HBox buildColumnHeader() {
return header;
}
-
+ /**
+ * Wires toolbar navigation actions (back, up, address bar input).
+ */
private void wireToolbar() {
backButton.setOnAction(e -> {
if (prevDir != null) {
@@ -180,11 +201,17 @@ private void wireToolbar() {
});
addressBar.setOnAction(e -> {
File typed = new File(addressBar.getText());
- if (typed.isDirectory()) populateDir(typed);
+ if (typed.isDirectory()) {
+ populateDir(typed);
+ }
});
}
-
+ /**
+ * Populates the file list with entries from the given directory.
+ *
+ * @param dir directory to display
+ */
private void populateDir(final File dir) {
currentDir = dir;
addressBar.setText(dir.getAbsolutePath());
@@ -195,7 +222,9 @@ private void populateDir(final File dir) {
openButton.setDisable(true);
File[] entries = dir.listFiles();
- if (entries == null) return;
+ if (entries == null) {
+ return;
+ }
Arrays.stream(entries)
.filter(f -> f.isDirectory() || f.getName().endsWith(FILTER))
@@ -205,10 +234,16 @@ private void populateDir(final File dir) {
.forEach(f -> fileList.getChildren().add(buildRow(f)));
}
+ /**
+ * Builds a UI row representing a file or directory.
+ *
+ * @param file file or directory to render
+ * @return HBox representing the row
+ */
private HBox buildRow(final File file) {
String icon = file.isDirectory() ? "📁" : "📄";
- String type = file.isDirectory() ? "Folder" : "CSV File";
- String size = file.isDirectory() ? ""
+ final String type = file.isDirectory() ? "Folder" : "CSV File";
+ final String size = file.isDirectory() ? ""
: formatSize(file.length());
Label iconLabel = new Label(icon);
@@ -256,6 +291,9 @@ private HBox buildRow(final File file) {
return row;
}
+ /**
+ * Confirms the currently selected file and triggers callback.
+ */
private void confirm() {
if (selectedFile != null && onFileConfirmed != null) {
onFileConfirmed.accept(selectedFile.toPath());
@@ -263,24 +301,42 @@ private void confirm() {
}
}
+ /**
+ * Clears the current selection highlight from the file list.
+ */
private void clearSelection() {
fileList.getChildren()
.forEach(n -> n.getStyleClass().remove("fp-row-selected"));
}
+ /**
+ * Formats file size into human-readable units.
+ *
+ * @param bytes file size in bytes
+ * @return formatted string (B, KB, MB)
+ */
private static String formatSize(final long bytes) {
- if (bytes < 1024) return bytes + " B";
- if (bytes < 1024 * 1024) return (bytes / 1024) + " KB";
+ if (bytes < 1024) {
+ return bytes + " B";
+ }
+ if (bytes < 1024 * 1024) {
+ return (bytes / 1024) + " KB";
+ }
return (bytes / (1024 * 1024)) + " MB";
}
-
- /** Sets onFileConfirmed callback. */
+ /**
+ * Sets callback executed when a file is confirmed.
+ *
+ * @param callback consumer receiving selected file path
+ */
public void setOnFileConfirmed(final Consumer callback) {
this.onFileConfirmed = callback;
}
- /** Shows the picker. */
+ /**
+ * Shows the file picker and refreshes the directory view.
+ */
@Override
public void show() {
selectedFile = null;
@@ -290,7 +346,7 @@ public void show() {
super.show();
}
- /** Hides the picker. */
+ /** Hides the file picker. */
@Override
public void hide() {
super.hide();
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/GameOverApp.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/GameOverApp.java
index aea7d44..b924a4b 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/GameOverApp.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/GameOverApp.java
@@ -8,11 +8,21 @@
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
-/** Modal shown on game over. */
+/**
+ * Game over modal popup shown when the player has lost all lives.
+ *
+ * Displays a final message and provides a restart option.
+ */
public class GameOverApp extends Popup {
private final Button startOverButton = new Button("Start Over");
+ /**
+ * Constructs the Game Over popup.
+ *
+ * Initializes UI components and disables the close button to prevent
+ * accidental dismissal.
+ */
public GameOverApp() {
super(500, 360, 0, 0, App.GAMEOVER);
@@ -27,6 +37,10 @@ public GameOverApp() {
buildLayout();
}
+ /**
+ * Builds the internal layout of the game over screen,
+ * including title, message, and restart button.
+ */
private void buildLayout() {
Label title = new Label("Game Over");
title.getStyleClass().add("game-over-title");
@@ -45,14 +59,15 @@ private void buildLayout() {
content.getChildren().setAll(inner);
}
- /** @return start over button. */
public Button getStartOverButton() {
return startOverButton;
}
- /** Shows the app. */
+ /**
+ * Shows the Game Over popup.
+ */
@Override
- public void show(){
+ public void show() {
super.show();
}
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/HustlersApp.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/HustlersApp.java
index a7bdc69..a436384 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/HustlersApp.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/HustlersApp.java
@@ -16,9 +16,14 @@
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
-/** Tutorial app popup. */
+/**
+ * Tutorial-style popup application that provides in-game guidance
+ * for core mechanics such as trading, banking, messaging, and rent.
+ *
+ * The content is structured into chapters displayed in a sidebar,
+ * with dynamic rendering of formatted instructional text in the main panel.
+ */
public class HustlersApp extends Popup {
-
private static final String BG_ROOT = "#ffffff";
private static final String BG_SIDEBAR = "#f4f4f4";
private static final String BG_CONTENT = "#ffffff";
@@ -29,19 +34,28 @@ public class HustlersApp extends Popup {
private static final String DIVIDER = "#e0e0e0";
private static final String HOVER_BG = "#e8e8e8";
private static final String SELECTED_BG = "#fef9ec";
-
private Label activeNavItem = null;
private VBox contentBody;
private Label chapterTitleLabel;
private final Map chapters = new LinkedHashMap<>();
- /** Constructs the Hustlers app. */
+ /**
+ * Constructs the Hustler's University tutorial popup.
+ *
+ * Initializes all tutorial chapters and builds the UI layout,
+ * including sidebar navigation and content rendering system.
+ */
public HustlersApp() {
super(720, 480, 80, 60, App.HUSTLERS);
buildChapters();
- buildUI();
+ buildUi();
}
+ /**
+ * Builds all tutorial chapters used in the sidebar navigation.
+ *
+ * Each chapter consists of a title and formatted instructional content.
+ */
private void buildChapters() {
chapters.put("Welcome", new String[]{
"HUSTLER'S UNIVERSITY",
@@ -61,7 +75,8 @@ private void buildChapters() {
+ "Green means the price is climbing; red means it's falling.\n\n"
+ "HOW TO BUY\n"
+ "Select s stock, enter how many units you want, and tap TRADE. "
- + "The cost is deducted from your wallet immediately, unless you don't have enough...\n\n"
+ + "The cost is deducted from your wallet immediately, "
+ + "unless you don't have enough...\n\n"
+ "HOW TO SELL\n"
+ "Select a held stock, enter how many units you want to sell, and tap TRADE. "
+ "Profit = (sell price minus buy price) times units.\n\n"
@@ -78,7 +93,8 @@ private void buildChapters() {
"HOW THE BANK WORKS",
"The Bank app is your financial safety net — and leverage tool.\n\n"
+ "SAVINGS ACCOUNT\n"
- + "Your account displays your total balance, cash available, cash invested and total return. "
+ + "Your account displays your total balance, cash available, "
+ + "cash invested and total return. "
+ "Remember, green numbers mean you're flying, red means you gotta lock in chief.\n\n"
+ "PORTFOLIO\n"
+ "If you like to brag about your investments, this is where it's at. "
@@ -153,9 +169,10 @@ private void buildChapters() {
chapters.put("Rent", new String[]{
"HOW RENT WORKS",
- "Rent is collected automatically at the end of every in-game week.\n\n"
+ "Rent is collected automatically at the end of every in-game week.\n"
+ "WHEN IT'S DUE\n"
- + "Rent is charged on Saturday 00:00, right before the new week begins, so you have until Friday to make sure you're set.\n\n"
+ + "Rent is charged on Saturday 00:00, right before the new week begins, "
+ + "so you have until Friday to make sure you're set.\n\n"
+ "HOW IT'S PAID\n"
+ "The rent amount is deducted directly from your wallet — automatically, "
+ "no action needed on your part. Make sure the money is in your wallet, "
@@ -165,7 +182,8 @@ private void buildChapters() {
+ " - You lose ONE heart.\n"
+ " - Losing all hearts ends the game.\n\n"
+ "HOW MUCH IS RENT?\n"
- + "Your rent amount is shown on the Rent Day popup at Saturday 00:00. You can count on it being $50 the first couple weeks.\n"
+ + "Your rent amount is shown on the Rent Day popup at Saturday 00:00. "
+ + "You can count on it being $50 the first couple weeks.\n"
+ "It may increase as you progress — so keep earning.\n\n"
+ "PRO TIPS\n"
+ "Check your wallet balance on Friday.\n"
@@ -190,7 +208,10 @@ private void buildChapters() {
});
}
- private void buildUI() {
+ /**
+ * Builds the full UI layout including sidebar navigation and content area.
+ */
+ private void buildUi() {
chapterTitleLabel = new Label();
chapterTitleLabel.setStyle(
"-fx-text-fill: " + ACCENT + ";"
@@ -223,6 +244,11 @@ private void buildUI() {
applyChapter(firstKey);
}
+ /**
+ * Constructs the sidebar containing chapter navigation items.
+ *
+ * @return configured sidebar VBox
+ */
private VBox buildSidebar() {
VBox sidebar = new VBox();
sidebar.setStyle(
@@ -249,29 +275,7 @@ private VBox buildSidebar() {
nav.setPadding(new Insets(8, 6, 8, 6));
for (String chapter : chapters.keySet()) {
- Label item = new Label(chapter);
- item.setPadding(new Insets(8, 10, 8, 10));
- item.setMaxWidth(Double.MAX_VALUE);
- item.setStyle(navStyle(false));
-
- item.setOnMouseEntered(e -> {
- if (item != activeNavItem) {
- item.setStyle(navHoverStyle());
- }
- });
- item.setOnMouseExited(e -> {
- if (item != activeNavItem) {
- item.setStyle(navStyle(false));
- }
- });
- item.setOnMouseClicked(e -> {
- if (activeNavItem != null) {
- activeNavItem.setStyle(navStyle(false));
- }
- activeNavItem = item;
- item.setStyle(navStyle(true));
- applyChapter(chapter);
- });
+ Label item = getLabel(chapter);
nav.getChildren().add(item);
}
@@ -286,6 +290,38 @@ private VBox buildSidebar() {
return sidebar;
}
+ private Label getLabel(String chapter) {
+ Label item = new Label(chapter);
+ item.setPadding(new Insets(8, 10, 8, 10));
+ item.setMaxWidth(Double.MAX_VALUE);
+ item.setStyle(navStyle(false));
+
+ item.setOnMouseEntered(e -> {
+ if (item != activeNavItem) {
+ item.setStyle(navHoverStyle());
+ }
+ });
+ item.setOnMouseExited(e -> {
+ if (item != activeNavItem) {
+ item.setStyle(navStyle(false));
+ }
+ });
+ item.setOnMouseClicked(e -> {
+ if (activeNavItem != null) {
+ activeNavItem.setStyle(navStyle(false));
+ }
+ activeNavItem = item;
+ item.setStyle(navStyle(true));
+ applyChapter(chapter);
+ });
+ return item;
+ }
+
+ /**
+ * Builds the main content wrapper containing the chapter title and scrollable content area.
+ *
+ * @return configured content wrapper VBox
+ */
private VBox buildContentWrapper() {
HBox titleBar = new HBox();
titleBar.setPadding(new Insets(13, 20, 13, 20));
@@ -311,6 +347,11 @@ private VBox buildContentWrapper() {
return wrapper;
}
+ /**
+ * Applies the selected chapter and renders its content.
+ *
+ * @param key the chapter key to display
+ */
private void applyChapter(String key) {
String[] content = chapters.get(key);
if (content == null) {
@@ -321,6 +362,11 @@ private void applyChapter(String key) {
renderContent(content[1]);
}
+ /**
+ * Renders formatted instructional text into the content body.
+ *
+ * @param rawText raw chapter text to render
+ */
private void renderContent(String rawText) {
for (String para : rawText.split("\n\n")) {
para = para.trim();
@@ -357,6 +403,12 @@ private void renderContent(String rawText) {
}
}
+ /**
+ * Determines whether a paragraph should be rendered as a section header.
+ *
+ * @param text input text
+ * @return true if text is considered a header, false otherwise
+ */
private boolean isSectionHeader(String text) {
String stripped = text.replaceAll("[^a-zA-Z]", "");
if (stripped.isEmpty()) {
@@ -365,6 +417,12 @@ private boolean isSectionHeader(String text) {
return stripped.equals(stripped.toUpperCase()) && text.length() < 60;
}
+ /**
+ * Generates CSS style string for navigation items.
+ *
+ * @param selected whether the item is currently selected
+ * @return CSS style string
+ */
private String navStyle(boolean selected) {
return "-fx-text-fill: " + (selected ? ACCENT : TEXT_SEC) + ";"
+ "-fx-font-size: 11px;"
@@ -377,6 +435,11 @@ private String navStyle(boolean selected) {
: "");
}
+ /**
+ * Generates CSS style string for hovered navigation items.
+ *
+ * @return CSS style string for hover state
+ */
private String navHoverStyle() {
return "-fx-text-fill: " + TEXT_PRIMARY + ";"
+ "-fx-font-size: 11px;"
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/NewsApp.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/NewsApp.java
index d4f3019..ec58d77 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/NewsApp.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/NewsApp.java
@@ -3,10 +3,20 @@
import edu.ntnu.idi.idatt2003.gruppe42.model.App;
import edu.ntnu.idi.idatt2003.gruppe42.view.Popup;
-/** News app popup. */
+/**
+ * News application popup.
+ *
+ * This popup represents a simple news app window. Content is intended
+ * to be added in future implementations.
+ */
public class NewsApp extends Popup {
- /** Constructs the News app. */
+ /**
+ * Constructs the NewsApp popup.
+ *
+ * Initializes the popup window with default size and position,
+ * and assigns it to the NEWS application type.
+ */
public NewsApp() {
super(400, 300, 180, 180, App.NEWS);
// Add news-specific content here
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/StockApp.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/StockApp.java
index c9d30d8..313b822 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/StockApp.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/StockApp.java
@@ -11,6 +11,7 @@
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
+import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.Spinner;
import javafx.scene.control.TextField;
@@ -18,9 +19,21 @@
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
-import javafx.scene.control.Label;
-/** Popup for the Stock app. */
+/**
+ * Popup window for the Stock trading application.
+ *
+ * Provides a searchable and sortable list of available stocks, and a detailed
+ * trading view where the user can buy or sell shares. The view includes a
+ * price display, interactive trade controls, a live price graph, and a receipt
+ * preview of the current transaction.
+ *
+ *
The popup supports two main states:
+ *
+ * - Search view – browse and filter available stocks
+ * - Stock detail view – view charts and execute trades
+ *
+ */
public class StockApp extends Popup {
private final ListView stockList;
@@ -34,7 +47,11 @@ public class StockApp extends Popup {
private final Button backButton;
private final Receipt receipt;
- /** Constructs the Stock app. */
+ /**
+ * Constructs the Stock trading popup.
+ *
+ * @param player the current player, used for portfolio context and receipt calculations
+ */
public StockApp(final Player player) {
super(500, 450, 140, 140, App.STOCK);
@@ -76,7 +93,9 @@ public StockApp(final Player player) {
showSearchPage();
}
- /** Shows stock search page. */
+ /**
+ * Shows the stock search page where the user can browse and filter stocks.
+ */
public void showSearchPage() {
content.setPadding(new Insets(20));
content.setSpacing(20);
@@ -85,7 +104,11 @@ public void showSearchPage() {
content.getChildren().setAll(searchBox, stockList);
}
- /** Shows stock detail page. */
+ /**
+ * Shows the detailed stock view including graph, price, and trading controls.
+ *
+ * @param stock the selected stock to display
+ */
public void showStockPage(final Stock stock) {
content.getChildren().clear();
@@ -98,7 +121,7 @@ public void showStockPage(final Stock stock) {
companyTitle.getStyleClass().add("stock-title");
Label symbolLabel = new Label(stock.getSymbol());
symbolLabel.getStyleClass().add("stock-symbol-large");
- VBox titleBox = new VBox(5, companyTitle, symbolLabel);
+ final VBox titleBox = new VBox(5, companyTitle, symbolLabel);
HBox tradeControls = new HBox(10);
tradeControls.setAlignment(Pos.CENTER_RIGHT);
@@ -135,47 +158,38 @@ public void updatePriceLabel(final Stock stock) {
}
}
- /** @return the search field. */
public TextField getSearchField() {
return searchField;
}
- /** @return the stock list view. */
public ListView getStockList() {
return stockList;
}
- /** @return quantity spinner. */
public Spinner getQuantitySpinner() {
return quantitySpinner;
}
- /** @return confirm button. */
public Button getConfirmButton() {
return confirmButton;
}
- /** @return receipt component. */
public Receipt getReceipt() {
return receipt;
}
- /** @return back button. */
public Button getBackButton() {
return backButton;
}
- /** @return alpha button. */
public Button getAlphaButton() {
return alphaButton;
}
- /** @return gainer button. */
public Button getGainerButton() {
return gainerButton;
}
- /** @return price button. */
public Button getPriceButton() {
return priceButton;
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/WarningApp.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/WarningApp.java
index 34b1fb3..37e958d 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/WarningApp.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/WarningApp.java
@@ -11,6 +11,14 @@
import javafx.scene.layout.VBox;
import javafx.scene.text.TextAlignment;
+/**
+ * A reusable warning popup used to display alerts, confirmations,
+ * and important game messages.
+ *
+ * The popup supports configurable icon, title, message text, and
+ * one or two action buttons depending on the context.
+ * It is used for game warnings, confirmations, and critical events.
+ */
public final class WarningApp extends Popup {
private final Label iconLabel = new Label();
@@ -18,8 +26,14 @@ public final class WarningApp extends Popup {
private final Label messageLabel = new Label();
private final Button primaryButton = new Button();
private final Button secondaryButton = new Button();
- private final HBox buttons;
+ /**
+ * Constructs a Warning popup window.
+ *
+ *
Initializes the UI layout including icon, title, message area,
+ * and action buttons. The popup is styled for modal warnings
+ * and can be configured dynamically using {@link #configure}.
+ */
public WarningApp() {
super(370, 270, 0, 0, App.WARNING);
@@ -52,7 +66,7 @@ public WarningApp() {
secondaryButton.getStyleClass().add("back-button");
secondaryButton.setPrefWidth(130);
- buttons = new HBox(12, secondaryButton, primaryButton);
+ HBox buttons = new HBox(12, secondaryButton, primaryButton);
buttons.setAlignment(Pos.CENTER);
VBox inner = new VBox(10, iconLabel, titleLabel, messageScroll, buttons);
@@ -63,6 +77,14 @@ public WarningApp() {
content.getChildren().setAll(inner);
}
+ /**
+ * Configures the warning popup with a single primary action button.
+ *
+ * @param icon the icon/emoji displayed at the top of the popup
+ * @param title the title of the warning
+ * @param message the detailed warning message
+ * @param primaryLabel the label for the primary action button
+ */
public void configure(
final String icon,
final String title,
@@ -82,6 +104,15 @@ public void configure(
getCloseButton().setOnAction(event -> primaryButton.fire());
}
+ /**
+ * Configures the warning popup with both primary and secondary actions.
+ *
+ * @param icon the icon/emoji displayed at the top of the popup
+ * @param title the title of the warning
+ * @param message the detailed warning message
+ * @param secondaryLabel the label for the secondary/cancel button
+ * @param primaryLabel the label for the primary action button
+ */
public void configure(
final String icon,
final String title,
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/WeekendReportApp.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/WeekendReportApp.java
index 8baca67..1e2e9a9 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/WeekendReportApp.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/apps/WeekendReportApp.java
@@ -16,7 +16,15 @@
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
-/** End-of-week financial report. */
+/**
+ * End-of-week financial report popup shown after the weekly simulation cycle.
+ *
+ *
Displays the player's trading performance, including net income, rent deduction,
+ * balance after rent, and a list of all transactions performed during the week.
+ *
+ *
The report also provides a qualitative verdict based on financial performance
+ * and allows the player to continue to the next in-game day.
+ */
public class WeekendReportApp extends Popup {
private static final BigDecimal STRONG_WEEK_THRESHOLD = new BigDecimal("50.00");
@@ -33,6 +41,11 @@ public class WeekendReportApp extends Popup {
private final Button continueButton = new Button("Continue to Sunday →");
+ /**
+ * Constructs the weekend report popup.
+ *
+ *
Initializes the layout and binds the continue button to close/advance the report.
+ */
public WeekendReportApp() {
super(740, 620, 0, 0, App.WEEKENDRAPPORT);
@@ -62,7 +75,7 @@ private void buildLayout() {
playerBlock.getStyleClass().add("rapport-player-block");
playerBlock.setPadding(new Insets(20, 16, 20, 16));
- Label transactionHeader = sectionHeader("Transactions");
+ final Label transactionHeader = sectionHeader();
ScrollPane scrollPane = new ScrollPane(receiptList);
scrollPane.setFitToWidth(true);
@@ -72,7 +85,7 @@ private void buildLayout() {
cashLabel.getStyleClass().add("rapport-line-value");
rentLabel.getStyleClass().addAll("rapport-line-value", "rapport-rent-value");
- HBox cashRow = footerRow("Cash Available", cashLabel);
+ final HBox cashRow = footerRow("Cash Available", cashLabel);
HBox rentRow = footerRow("Rent Due", rentLabel);
rentRow.getStyleClass().add("rapport-rent-row");
@@ -104,8 +117,8 @@ private void buildLayout() {
);
}
- private static Label sectionHeader(String text) {
- Label label = new Label(text);
+ private static Label sectionHeader() {
+ Label label = new Label("Transactions");
label.getStyleClass().add("rapport-section-header");
return label;
}
@@ -123,14 +136,15 @@ private static HBox footerRow(String labelText, Label valueLabel) {
}
/**
- * Populates the rapport with the completed week's data.
- * Rent has already been deducted from the player's balance before this is called.
+ * Populates the weekend report with financial data from the completed week.
*
- * @param transactions all transactions that occurred this week
- * @param netIncome net cash change from trading (sales minus purchases)
- * @param cashBeforeRent cash available before rent was deducted
- * @param rent the rent amount that was deducted
- * @param cashAfterRent cash balance after rent deduction (may be negative)
+ *
All transactions and balances reflect the state after rent has been deducted.
+ *
+ * @param transactions all transactions performed during the week
+ * @param netIncome net profit/loss from trading activities
+ * @param cashBeforeRent cash balance before rent was deducted
+ * @param rent rent amount deducted from the player
+ * @param cashAfterRent final balance after rent deduction
*/
public void populate(
List transactions,
@@ -237,9 +251,11 @@ static String formatBalance(BigDecimal amount) {
return "$" + String.format("%,.2f", amount);
}
- /** Shows the rapport. */
+ /**
+ * Displays the weekend report popup.
+ */
@Override
- public void show(){
+ public void show() {
super.show();
}
}
\ No newline at end of file
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/DesktopView.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/DesktopView.java
index 19f352d..a72d501 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/DesktopView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/DesktopView.java
@@ -3,19 +3,15 @@
import edu.ntnu.idi.idatt2003.gruppe42.controller.viewcontrollers.DesktopViewController;
import edu.ntnu.idi.idatt2003.gruppe42.model.App;
import edu.ntnu.idi.idatt2003.gruppe42.view.views.components.DesktopBottomBar;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
+import java.util.Objects;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.effect.GaussianBlur;
-import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
@@ -26,16 +22,28 @@
import javafx.scene.layout.StackPane;
/**
- * Desktop view: 10x6 app-icon grid, bottom status bar, and a layered modal overlay system.
+ * Main desktop UI view of the application.
+ *
+ * The desktop view consists of:
+ *
+ * - A 10x6 grid of application icons
+ * - A bottom status bar showing player and game state
+ * - A layered modal system (rapport, warning, game over)
+ * - A popup overlay system for draggable apps
+ *
+ *
+ * The view supports drag-and-drop app placement, modal locking,
+ * and dynamic updates from the {@link DesktopViewController}.
*/
public final class DesktopView {
-
+ /**
+ * Represents the available modal overlay layers in the desktop UI.
+ */
public enum ModalLayer { RAPPORT, WARNING, GAME_OVER }
private static final int COLS = 10;
private static final int ROWS = 6;
- private static final int HEART_COUNT = 3;
private static final double BACKDROP_BLUR = 8.0;
private final DesktopViewController controller;
@@ -47,8 +55,8 @@ public enum ModalLayer { RAPPORT, WARNING, GAME_OVER }
private final Pane warningOverlay = createOverlayPane();
private final Pane gameOverOverlay = createOverlayPane();
- private Node gridArea;
- private DesktopBottomBar bottomBar;
+ private final Node gridArea;
+ private final DesktopBottomBar bottomBar;
private final List popupRoots = new ArrayList<>();
@@ -58,7 +66,12 @@ public enum ModalLayer { RAPPORT, WARNING, GAME_OVER }
private final EnumSet activeLayers = EnumSet.noneOf(ModalLayer.class);
- /** Constructs the desktop view. */
+ /**
+ * Constructs the desktop view and initializes the grid, bottom bar,
+ * and overlay layers.
+ *
+ * @param controller the controller responsible for handling UI actions
+ */
public DesktopView(final DesktopViewController controller) {
this.controller = controller;
this.desktopPane = new BorderPane();
@@ -72,10 +85,9 @@ public DesktopView(final DesktopViewController controller) {
// Ensure the popup overlay is in a pane that allows x,y positioning,
// and then place that pane in the center of the BorderPane.
Pane centerArea = new Pane(gridArea, popupOverlay);
- if (gridArea instanceof Region region) {
- region.prefWidthProperty().bind(centerArea.widthProperty());
- region.prefHeightProperty().bind(centerArea.heightProperty());
- }
+ Region region = (Region) gridArea;
+ region.prefWidthProperty().bind(centerArea.widthProperty());
+ region.prefHeightProperty().bind(centerArea.heightProperty());
popupOverlay.prefWidthProperty().bind(centerArea.widthProperty());
popupOverlay.prefHeightProperty().bind(centerArea.heightProperty());
@@ -84,7 +96,12 @@ public DesktopView(final DesktopViewController controller) {
desktopPane.getStyleClass().add("desktop-root");
}
- /** @return the scene root containing the desktop and popup overlay. */
+ /**
+ * Returns the root node of the desktop scene graph.
+ * Initializes stylesheets and layout if not already created.
+ *
+ * @return the root {@link Pane} containing the desktop view
+ */
public Pane getRoot() {
if (sceneRoot == null) {
sceneRoot = new Pane(desktopPane);
@@ -97,12 +114,20 @@ public Pane getRoot() {
return sceneRoot;
}
- /** @return the inner BorderPane for gradient/style targeting. */
+ /**
+ * Returns the main desktop container (used for styling and bindings).
+ *
+ * @return the root {@link BorderPane} of the desktop UI
+ */
public BorderPane getDesktopPane() {
return desktopPane;
}
- /** @return the overlay pane that holds popups and modals. */
+ /**
+ * Returns the overlay pane used for displaying popup windows.
+ *
+ * @return the popup overlay {@link Pane}
+ */
public Pane getPopupOverlay() {
return popupOverlay;
}
@@ -128,22 +153,36 @@ private void loadStylesheets() {
}
}
-
- /** Registers a popup root. */
+ /**
+ * Registers a popup node so it can be disabled/enabled when modals are active.
+ *
+ * @param popupRoot the root node of the popup
+ */
public void registerPopup(final Node popupRoot) {
popupRoots.add(popupRoot);
}
- /** Registers a modal root. */
+ /**
+ * Registers a modal root node for a given modal layer.
+ *
+ * @param layer the modal layer type
+ * @param modalRoot the root node of the modal
+ */
public void registerModal(final ModalLayer layer, final Node modalRoot) {
switch (layer) {
case RAPPORT -> rapportRoot = modalRoot;
case WARNING -> warningRoot = modalRoot;
case GAME_OVER -> gameOverRoot = modalRoot;
+ default -> throw new IllegalStateException("Unexpected modal layer: " + layer);
}
}
- /** @return the overlay pane for the given layer. */
+ /**
+ * Returns the overlay pane associated with a modal layer.
+ *
+ * @param layer the modal layer
+ * @return the overlay pane for that layer
+ */
public Pane getOverlay(final ModalLayer layer) {
return switch (layer) {
case RAPPORT -> rapportOverlay;
@@ -152,13 +191,21 @@ public Pane getOverlay(final ModalLayer layer) {
};
}
- /** Activates modal layer. */
+ /**
+ * Activates the given modal layer and updates UI locking.
+ *
+ * @param layer the layer to activate
+ */
public void enterLayer(final ModalLayer layer) {
activeLayers.add(layer);
recompute();
}
- /** Deactivates modal layer. */
+ /**
+ * Deactivates the given modal layer and updates UI locking.
+ *
+ * @param layer the layer to deactivate
+ */
public void exitLayer(final ModalLayer layer) {
activeLayers.remove(layer);
recompute();
@@ -272,25 +319,42 @@ private static boolean isDesktopApp(final App app) {
}
private String resource(final String path) {
- return getClass().getResource(path).toExternalForm();
+ return Objects.requireNonNull(getClass().getResource(path)).toExternalForm();
}
- /** Updates player name. */
+ /**
+ * Updates the displayed player name in the bottom bar.
+ *
+ * @param name the player name
+ */
public void updatePlayerName(final String name) {
Platform.runLater(() -> bottomBar.getPlayerLabel().setText("User: " + name));
}
- /** Updates player status. */
+ /**
+ * Updates the displayed player status.
+ *
+ * @param status the status text
+ */
public void updatePlayerStatus(final String status) {
Platform.runLater(() -> bottomBar.getPlayerStatusLabel().setText("Status: " + status));
}
- /** Updates clock. */
+ /**
+ * Updates the clock display.
+ *
+ * @param time formatted time string
+ */
public void updateClock(final String time) {
Platform.runLater(() -> bottomBar.getClockLabel().setText(time));
}
- /** Updates day. */
+ /**
+ * Updates the day display and weekend button visibility.
+ *
+ * @param day the current day name
+ * @param isSunday whether the current day is Sunday
+ */
public void updateDay(final String day, final boolean isSunday) {
Platform.runLater(() -> {
bottomBar.getDayLabel().setText(day);
@@ -298,27 +362,47 @@ public void updateDay(final String day, final boolean isSunday) {
});
}
- /** Updates week. */
+ /**
+ * Updates the week display.
+ *
+ * @param week formatted week string
+ */
public void updateWeek(final String week) {
Platform.runLater(() -> bottomBar.getWeekLabel().setText(week));
}
- /** Updates weather. */
+ /**
+ * Updates the weather display.
+ *
+ * @param weather weather description
+ */
public void updateWeather(final String weather) {
Platform.runLater(() -> bottomBar.getWeatherLabel().setText(weather));
}
- /** Updates temperature. */
+ /**
+ * Updates the temperature display.
+ *
+ * @param temperature temperature value
+ */
public void updateTemperature(final String temperature) {
Platform.runLater(() -> bottomBar.getTempLabel().setText(temperature + "°C"));
}
- /** @return the next week button. */
+ /**
+ * Returns the "Next Week" button from the bottom bar.
+ *
+ * @return the next week {@link Button}
+ */
public Button getNextWeekButton() {
return bottomBar.getNextWeekButton();
}
- /** @return the settings button. */
+ /**
+ * Returns the settings button from the bottom bar.
+ *
+ * @return the settings {@link Button}
+ */
public Button getSettingsButton() {
return bottomBar.getSettingsButton();
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/StartView.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/StartView.java
index 3f04b6f..d23c8b8 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/StartView.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/StartView.java
@@ -15,10 +15,13 @@
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
-/** Start screen view. */
+/**
+ * Represents the start screen view of the application.
+ *
+ * This view allows the user to enter a username, select a starting difficulty
+ * (starting money), and proceed into the game. It also provides access to settings.
+ */
public class StartView {
-
-
private final TextField usernameField = new TextField();
private final Button loginButton = new Button("→");
private Button settingsButton;
@@ -26,8 +29,12 @@ public class StartView {
private final StackPane content = new StackPane();
private final BorderPane root = new BorderPane();
-
- /** @return the root node. */
+ /**
+ * Returns the root node of the start screen. If the UI has not yet been built,
+ * it constructs and initializes all components.
+ *
+ * @return the root {@link BorderPane} containing the start view
+ */
public BorderPane getRoot() {
if (!root.getChildren().isEmpty()) {
return root; // already built
@@ -42,7 +49,8 @@ public BorderPane getRoot() {
// Avatar
VBox avatarContainer = new VBox();
avatarContainer.getStyleClass().add("avatar-container");
- Image logoImage = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/images/logo.jpg")));
+ Image logoImage = new Image(Objects.requireNonNull(getClass()
+ .getResourceAsStream("/images/logo.jpg")));
ImageView logoView = new ImageView(logoImage);
logoView.setPreserveRatio(true);
logoView.setFitWidth(120);
@@ -104,25 +112,35 @@ public BorderPane getRoot() {
return root;
}
+ /**
+ * Loads the CSS stylesheets required for the start view.
+ */
private void loadStylesheets() {
root.getStylesheets().clear();
try {
root.getStylesheets().addAll(
- getClass().getResource("/css/global.css").toExternalForm(),
- getClass().getResource("/css/login.css").toExternalForm()
+ Objects.requireNonNull(getClass().getResource("/css/global.css")).toExternalForm(),
+ Objects.requireNonNull(getClass().getResource("/css/login.css")).toExternalForm()
);
} catch (Exception e) {
System.err.println("[CSS] Failed to load stylesheets: " + e.getMessage());
}
}
-
- /** @return the username field. */
+ /**
+ * Returns the username input field.
+ *
+ * @return the {@link TextField} used for username input
+ */
public TextField getUsernameField() {
return usernameField;
}
- /** @return selected difficulty mode. */
+ /**
+ * Returns the selected starting difficulty option as text.
+ *
+ * @return the selected mode, or {@code null} if none is selected
+ */
public String getSelectedMode() {
RadioButton selectedMode = (RadioButton) startingMoneyGroup.getSelectedToggle();
if (selectedMode == null) {
@@ -131,12 +149,20 @@ public String getSelectedMode() {
return selectedMode.getText();
}
- /** @return login button. */
+ /**
+ * Returns the login/continue button.
+ *
+ * @return the login {@link Button}
+ */
public Button getLoginButton() {
return loginButton;
}
- /** @return settings button. */
+ /**
+ * Returns the settings button.
+ *
+ * @return the settings {@link Button}
+ */
public Button getSettingsButton() {
return settingsButton;
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/components/DesktopBottomBar.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/components/DesktopBottomBar.java
index dbb7310..4029551 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/components/DesktopBottomBar.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/components/DesktopBottomBar.java
@@ -11,13 +11,19 @@
import javafx.scene.layout.Region;
/**
- * The bottom bar of the desktop view.
- * Displays player information, lives, game time, and status.
+ * Bottom status bar for the desktop view.
+ *
+ * Displays key player and game information such as:
+ *
+ * - Player name and status
+ * - Lives (hearts)
+ * - Current weather and temperature
+ * - Day, week, and clock
+ * - Controls for settings and advancing the week
+ *
*/
public final class DesktopBottomBar extends HBox {
-
private static final int HEART_COUNT = 3;
-
private final Label playerLabel;
private final Label playerStatusLabel;
private final Label weatherLabel;
@@ -29,9 +35,9 @@ public final class DesktopBottomBar extends HBox {
private final Button settingsButton;
/**
- * Constructs the bottom bar.
+ * Constructs the bottom bar UI and binds it to the player model.
*
- * @param player the player model to display info from
+ * @param player the player model used to populate UI data
*/
public DesktopBottomBar(Player player) {
super(15);
@@ -50,7 +56,7 @@ public DesktopBottomBar(Player player) {
playerStatusLabel.getStyleClass().add("desktop-label-bold");
playerStatusLabel.setMinWidth(Region.USE_PREF_SIZE);
- HBox heartsBox = buildHeartsBox(player);
+ final HBox heartsBox = buildHeartsBox(player);
nextWeekButton = new Button("Advance to next week");
nextWeekButton.getStyleClass().add("primary-button");
@@ -77,6 +83,14 @@ public DesktopBottomBar(Player player) {
);
}
+ /**
+ * Builds the lives display using heart icons and binds it to the player.
+ *
+ * The hearts update automatically when the player's lives change.
+ *
+ * @param player the player whose lives are displayed
+ * @return an {@link HBox} containing heart icons
+ */
private HBox buildHeartsBox(final Player player) {
HBox box = new HBox(4);
box.setAlignment(Pos.CENTER_LEFT);
@@ -103,6 +117,12 @@ private HBox buildHeartsBox(final Player player) {
return box;
}
+ /**
+ * Creates a label with the given CSS style class.
+ *
+ * @param styleClass the CSS style class to apply
+ * @return a styled {@link Label}
+ */
private Label styledLabel(final String styleClass) {
Label label = new Label();
label.getStyleClass().add(styleClass);
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/components/Receipt.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/components/Receipt.java
index a35fbf0..ec8c559 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/components/Receipt.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/components/Receipt.java
@@ -15,7 +15,15 @@
import javafx.scene.layout.VBox;
/**
- * The single shared receipt component used everywhere in the game.
+ * Shared receipt component used to display transaction details in the game.
+ *
+ *
The receipt supports two modes:
+ *
+ * - Live preview for upcoming trades
+ * - Historical view for completed transactions
+ *
+ *
+ * It calculates gross value, commission, and optional tax depending on trade type.
*/
public final class Receipt extends VBox {
@@ -23,7 +31,12 @@ public final class Receipt extends VBox {
private static final BigDecimal TAX_RATE = new BigDecimal("0.22");
private final Player player;
- /** Creates an empty live-preview receipt. Call {@link #update} to populate. */
+ /**
+ * Creates an empty live-preview receipt.
+ * Call {@link #update(Stock, BigDecimal)} to populate it.
+ *
+ * @param player the player used for tax estimation (might be {@code null} in read-only mode)
+ */
public Receipt(final Player player) {
this.player = player;
getStyleClass().add("receipt-container");
@@ -34,10 +47,11 @@ public Receipt(final Player player) {
/**
* Creates a populated receipt for a completed transaction.
- * Used by the Weekend Rapport (read-only).
+ *
+ *
Used in read-only contexts such as the weekend report.
*
* @param tx the completed transaction to render
- * @return a new populated receipt card
+ * @return a fully populated receipt instance
*/
public static Receipt forTransaction(final Transaction tx) {
Receipt receipt = new Receipt(null);
@@ -59,8 +73,12 @@ public static Receipt forTransaction(final Transaction tx) {
}
/**
- * Re-renders as a live preview for the given stock and signed quantity.
- * A positive quantity is a BUY; negative is a SELL.
+ * Updates the receipt as a live preview for a potential trade.
+ *
+ *
A positive quantity represents a BUY, and a negative quantity represents a SELL.
+ *
+ * @param stock the selected stock
+ * @param quantity the signed quantity of shares
*/
public void update(final Stock stock, final BigDecimal quantity) {
if (stock == null || quantity == null) {
@@ -83,7 +101,13 @@ public void update(final Stock stock, final BigDecimal quantity) {
);
}
- /** Computes the estimated capital-gains tax for a hypothetical sale. */
+ /**
+ * Estimates capital gains tax for a hypothetical sale.
+ *
+ * @param stock the stock being sold
+ * @param qty the quantity being sold
+ * @return estimated tax, or {@link BigDecimal#ZERO} if not applicable
+ */
private BigDecimal estimateSaleTax(final Stock stock, final BigDecimal qty) {
if (player == null) {
return BigDecimal.ZERO;
@@ -103,11 +127,11 @@ private BigDecimal estimateSaleTax(final Stock stock, final BigDecimal qty) {
return profit.multiply(TAX_RATE).setScale(2, RoundingMode.HALF_UP);
}
-
/**
- * Renders the canonical receipt layout with the given values.
- * Used by both live-preview and historical-transaction modes so the
- * visual output is identical.
+ * Renders the receipt UI using the provided computed values.
+ *
+ *
This method is shared between live preview and historical transaction rendering
+ * to ensure consistent visual output.
*/
private void renderPopulated(
final boolean isBuy,
@@ -145,7 +169,7 @@ private void renderPopulated(
totals.getChildren().add(keyValueLine("TOTAL:", formatUsd(total)));
getChildren().addAll(
- headerLabel("RECEIPT"),
+ headerLabel(),
ruleStrong(),
details,
ruleSoft(),
@@ -154,36 +178,48 @@ private void renderPopulated(
);
}
- private static Label headerLabel(final String text) {
- Label l = new Label(text);
+ /**
+ * Creates a styled header label.
+ */
+ private static Label headerLabel() {
+ Label l = new Label("RECEIPT");
l.getStyleClass().add("receipt-header");
return l;
}
+ /**
+ * Creates a strong divider line.
+ */
private static Region ruleStrong() {
Region r = new Region();
r.getStyleClass().add("receipt-divider-strong");
return r;
}
+ /**
+ * Creates a soft divider line.
+ */
private static Region ruleSoft() {
Region r = new Region();
r.getStyleClass().add("receipt-divider");
return r;
}
- private static Label receiptLine(final String text) {
- Label l = new Label(text);
- l.getStyleClass().add("receipt-text");
- return l;
- }
-
+ /**
+ * Creates a formatted key-value line.
+ */
private static Label keyValueLine(final String key, final String value) {
Label l = new Label(String.format("%-12s %s", key, value));
l.getStyleClass().add("receipt-text");
return l;
}
+ /**
+ * Formats a value as USD currency.
+ *
+ * @param amount the amount to format
+ * @return formatted currency string
+ */
private static String formatUsd(final BigDecimal amount) {
return "$" + String.format("%,.2f", amount);
}
diff --git a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/components/StockGraph.java b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/components/StockGraph.java
index 23d85f7..9a47b6c 100644
--- a/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/components/StockGraph.java
+++ b/src/main/java/edu/ntnu/idi/idatt2003/gruppe42/view/views/components/StockGraph.java
@@ -1,24 +1,28 @@
package edu.ntnu.idi.idatt2003.gruppe42.view.views.components;
import edu.ntnu.idi.idatt2003.gruppe42.model.Stock;
+import java.math.BigDecimal;
+import java.util.List;
import javafx.application.Platform;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.VBox;
-import java.math.BigDecimal;
-import java.util.List;
-
/**
* Component for displaying a stock price history graph.
+ *
+ *
Shows an area chart based on the historical price data of a {@link Stock}.
+ * The graph is updated dynamically and supports toggling visibility state.
*/
public final class StockGraph extends VBox {
private final AreaChart areaChart;
private boolean isVisible = false;
/**
- * Constructs a new StockGraph.
+ * Constructs a new StockGraph component.
+ *
+ * Initializes the chart axes, styling, and default layout configuration.
*/
public StockGraph() {
this.getStyleClass().add("stock-graph-container");
@@ -43,9 +47,9 @@ public StockGraph() {
}
/**
- * Updates the graph with data from the specified stock.
+ * Updates the graph with historical price data from the given stock.
*
- * @param stock the stock to display
+ * @param stock the stock whose price history should be displayed
*/
public void update(final Stock stock) {
if (stock == null) {
@@ -78,18 +82,18 @@ public void update(final Stock stock) {
}
/**
- * Returns the visibility.
+ * Returns whether the graph is currently marked as visible.
*
- * @return the value
+ * @return true if visible, false otherwise
*/
public boolean getVisibility() {
return isVisible;
}
/**
- * Sets the visibility.
+ * Sets whether the graph is considered visible.
*
- * @param visible the new value
+ * @param visible true to mark as visible, false otherwise
*/
public void setVisibility(final boolean visible) {
isVisible = visible;
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/CriticalFeaturesTest.java b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/CriticalFeaturesTest.java
index 2b98fba..53f96b2 100644
--- a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/CriticalFeaturesTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/CriticalFeaturesTest.java
@@ -12,7 +12,10 @@
import org.junit.jupiter.api.Test;
/**
- * Tests for critical features of the Millions game.
+ * Integration-style tests for critical gameplay features in the Millions game.
+ *
+ *
Verifies core mechanics such as debt handling, life loss, portfolio management,
+ * and net worth calculation across multiple model components.
*/
public class CriticalFeaturesTest {
private Player player;
@@ -46,7 +49,8 @@ void testPortfolioManagement() {
assertEquals(quantity, portfolio.getShares().get(0).getQuantity(), "Quantity should match");
portfolio.removeShare(new Share(apple, new BigDecimal("5"), buyPrice));
- assertEquals(new BigDecimal("5"), portfolio.getShares().get(0).getQuantity(), "Quantity should be reduced");
+ assertEquals(new BigDecimal("5"), portfolio.getShares()
+ .get(0).getQuantity(), "Quantity should be reduced");
}
@Test
@@ -63,6 +67,7 @@ void testNetWorthCalculation() {
// Total Sale Value = 1000 - 10 - 55 = 935
// Net Worth = 1000 + 935 = 1935
- assertEquals(new BigDecimal("1935.00"), player.getNetWorth(), "Net worth calculation incorrect");
+ assertEquals(new BigDecimal("1935.00"),
+ player.getNetWorth(), "Net worth calculation incorrect");
}
}
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/ExchangeTest.java b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/ExchangeTest.java
index 2bd565c..11024ec 100644
--- a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/ExchangeTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/ExchangeTest.java
@@ -2,7 +2,6 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.math.BigDecimal;
@@ -10,6 +9,12 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+/**
+ * Unit tests for the {@link Exchange} class.
+ *
+ *
Verifies stock management, search functionality, and time progression
+ * within the exchange simulation.
+ */
public class ExchangeTest {
private Exchange exchange;
@@ -37,7 +42,7 @@ void findStocksTest() {
assertEquals(1, result.size());
assertEquals("Apple Inc.", result.get(0).getCompany());
- // Case insensitive match
+ // Case-insensitive match
result = exchange.findStocks("apple");
assertEquals(1, result.size());
assertEquals("Apple Inc.", result.get(0).getCompany());
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/PlayerTest.java b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/PlayerTest.java
index 48cec18..fb02274 100644
--- a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/PlayerTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/PlayerTest.java
@@ -10,6 +10,12 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+/**
+ * Unit tests for the {@link Player} class.
+ *
+ *
Verifies money management, portfolio access, exception handling,
+ * and net worth calculations.
+ */
public class PlayerTest {
private Player player;
@@ -76,7 +82,11 @@ void getNetworthTest() {
// Starting with 10000 money and adding 5000 moneys worth of AAPL then calculating the networth
// with commissions taken account of will result in this:
// 10000 + 5000 - (5000 * 0.01) = 14950
- player.getPortfolio().addShare(new Share(new Stock("AAPL", "Apple Inc.", new BigDecimal("5000")), new BigDecimal("1"), new BigDecimal("5000")));
+ player.getPortfolio().addShare(new Share(
+ new Stock("AAPL", "Apple Inc.",
+ new BigDecimal("5000")),
+ new BigDecimal("1"),
+ new BigDecimal("5000")));
assertEquals(new BigDecimal("14950.00"), player.getNetWorth());
}
}
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/PortfolioTest.java b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/PortfolioTest.java
index 6680e62..a71b58d 100644
--- a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/PortfolioTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/PortfolioTest.java
@@ -8,6 +8,11 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+/**
+ * Unit tests for the {@link Exchange} class.
+ *
+ *
Verifies stock management, search functionality, and week progression behavior.
+ */
public class PortfolioTest {
private Portfolio portfolio;
private Stock stock;
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/ShareTest.java b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/ShareTest.java
index 44715dc..7655ba4 100644
--- a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/ShareTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/ShareTest.java
@@ -5,6 +5,12 @@
import java.math.BigDecimal;
import org.junit.jupiter.api.Test;
+/**
+ * Unit tests for the {@link Share} class.
+ *
+ *
Verifies that share properties (stock, quantity, and purchase price)
+ * are correctly stored and retrieved.
+ */
public class ShareTest {
@Test
void sharePropertiesTest() {
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/StockFileHandlerTest.java b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/StockFileHandlerTest.java
index 6e3af16..d61bcb4 100644
--- a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/StockFileHandlerTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/StockFileHandlerTest.java
@@ -1,7 +1,6 @@
package edu.ntnu.idi.idatt2003.gruppe42.model;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
import java.nio.file.Files;
@@ -9,6 +8,12 @@
import java.util.List;
import org.junit.jupiter.api.Test;
+/**
+ * Unit tests for the {@link StockFileHandler} class.
+ *
+ *
Verifies correct parsing of stock data from CSV files,
+ * including handling of valid entries, comments, and empty lines.
+ */
public class StockFileHandlerTest {
@Test
diff --git a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/StockTest.java b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/StockTest.java
index 7309f59..b90aebf 100644
--- a/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/StockTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt2003/gruppe42/model/StockTest.java
@@ -5,6 +5,11 @@
import java.math.BigDecimal;
import org.junit.jupiter.api.Test;
+/**
+ * Unit tests for the {@link Stock} class.
+ *
+ *
Verifies correct storage of stock properties and updates to sales price.
+ */
public class StockTest {
@Test
void stockPropertiesTest() {