Skip to content

Per/merge #146

Merged
merged 2 commits into from
May 25, 2026
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt2003/gruppe42/Launcher.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
package edu.ntnu.idi.idatt2003.gruppe42;

/**
* Main class for launching the application.
*/
public class Launcher {
/**
* Launches the application.
*
* @param args command-line arguments
*/
public static void main(String[] args) {
Millions.launch(Millions.class, args);
}
Expand Down
6 changes: 2 additions & 4 deletions src/main/java/edu/ntnu/idi/idatt2003/gruppe42/Millions.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import edu.ntnu.idi.idatt2003.gruppe42.model.Player;
import edu.ntnu.idi.idatt2003.gruppe42.view.views.DesktopView;
import edu.ntnu.idi.idatt2003.gruppe42.view.views.StartView;

import java.io.InputStream;
import javafx.application.Application;
import javafx.scene.Scene;
Expand Down Expand Up @@ -68,7 +67,8 @@ public void start(final Stage stage) {
* @param popupsController controller managing popups
*/
public void initGame(final String username, final Difficulty difficulty,
InputStream stocksStream, PopupsController popupsController) {
InputStream stocksStream, PopupsController popupsController)
throws Exception {
player = GameFactory.createPlayer(username, difficulty);
gameController = new GameController();

Expand All @@ -77,8 +77,6 @@ public void initGame(final String username, final Difficulty difficulty,
desktopViewController.setOnGameOver(this::resetGame);
desktopView = desktopViewController.getDesktopView();
scene.setRoot(desktopView.getRoot());

gameController.startGame();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void setGameState(final GameState gameState) {
public void startGame() {
timer = new Timer(true);
final int delay = 0;
final int period = 100;
final int period = 1000;

timer.scheduleAtFixedRate(new TimerTask() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import edu.ntnu.idi.idatt2003.gruppe42.model.exceptions.StockFileParseException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -78,11 +79,16 @@ public void nextTick() {
public void startMarket() {
for (Stock stock : exchange.getAllStocks()) {
StockController controller = stockControllers.get(stock.getSymbol());
if (controller != null) {
for (int i = 0; i < STOCK_RESOLUTION; i++) {
stock.addNewSalesPrice(controller.updatePrice());
}
if (controller == null) {
continue;
}

for (int i = 0; i < STOCK_RESOLUTION; i++) {
stock.addNewSalesPrice(controller.updatePrice());
}

stock.reverseHistory();
controller.syncPrice();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,11 @@ public BigDecimal getPrice() {
return price;
}

/**
* Resets the internal price to match the stock's current sales price after history manipulation.
*/
public void syncPrice() {
this.price = stock.getSalesPrice();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
* Controller responsible for managing in-game time, days, weeks, and weather.
*/
public class TimeAndWeatherController implements AppController {
private final IntegerProperty hour = new SimpleIntegerProperty(HOURS_PER_DAY - 1);
private final IntegerProperty dayIndex = new SimpleIntegerProperty(SATURDAY_INDEX);
private final IntegerProperty hour = new SimpleIntegerProperty(0);
private final IntegerProperty dayIndex = new SimpleIntegerProperty(0);
private final IntegerProperty weekNumber = new SimpleIntegerProperty(0);
private final IntegerProperty temperature = new SimpleIntegerProperty(15);
private final StringProperty weather = new SimpleStringProperty("Sunny");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package edu.ntnu.idi.idatt2003.gruppe42.controller.appcontrollers;

import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;

/**
* Renders formatted tutorial chapter text into a VBox content area.
*/
public record HustlersContentRenderer(VBox contentBody) {

private static final String ACCENT = "#a0720a";
private static final String ACCENT_DIM = "#c9a84c";
private static final String TEXT_PRIMARY = "#1a1a1a";

/**
* Creates a renderer targeting the given content body.
*
* @param contentBody the VBox to render content into
*/
public HustlersContentRenderer {
}

/**
* Clears the content body and renders the given raw text.
*
* @param rawText the chapter body text to render
*/
public void render(final String rawText) {
contentBody.getChildren().clear();
for (String para : rawText.split("\n\n")) {
para = para.trim();
if (para.isEmpty()) {
continue;
}

if (isSectionHeader(para)) {
renderSectionHeader(para);
} else {
renderParagraph(para);
}
}
}

private void renderSectionHeader(final String text) {
Region divider = new Region();
divider.setPrefHeight(1);
divider.setMaxWidth(32);
divider.setStyle("-fx-background-color: " + ACCENT_DIM + ";");
VBox.setMargin(divider, new Insets(4, 0, 5, 0));

Label header = new Label(text);
header.setStyle(
"-fx-text-fill: " + ACCENT + ";"
+ "-fx-font-size: 10px;"
+ "-fx-font-weight: bold;"
+ "-fx-font-family: 'Georgia';"
);
contentBody.getChildren().addAll(divider, header);
}

private void renderParagraph(final String para) {
TextFlow flow = new TextFlow();
flow.setLineSpacing(3);
String[] lines = para.split("\n");
for (int i = 0; i < lines.length; i++) {
Text t = new Text((i > 0 ? "\n" : "") + lines[i]);
t.setStyle("-fx-fill: " + TEXT_PRIMARY + ";");
t.setFont(Font.font("Georgia", 12.5));
flow.getChildren().add(t);
}
contentBody.getChildren().add(flow);
}

private boolean isSectionHeader(final String text) {
String stripped = text.replaceAll("[^a-zA-Z]", "");
return !stripped.isEmpty() && stripped.equals(stripped.toUpperCase()) && text.length() < 60;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import edu.ntnu.idi.idatt2003.gruppe42.model.StockFileHandler;
import edu.ntnu.idi.idatt2003.gruppe42.view.apps.SettingsApp;
import edu.ntnu.idi.idatt2003.gruppe42.view.apps.SettingsApp.GradientConfig;

import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -30,6 +29,11 @@ public class SettingsAppController implements AppController {

private final SettingsApp settingsApp;

/**
* Constructor for the SettingsAppController.
*
* @param settingsApp the SettingsApp instance to control
*/
public SettingsAppController(
final SettingsApp settingsApp) {

Expand Down Expand Up @@ -144,6 +148,11 @@ private void wireLoggedInControls() {
});
}

/**
* Sets the logged-in status of the SettingsApp.
*
* @param status the new logged-in status
*/
public void setLoggedIn(boolean status) {
settingsApp.setLoggedIn(status);
wireControls();
Expand All @@ -159,6 +168,11 @@ private boolean isValidStockFile(Path path) {
}
}

/**
* Returns stock file.
*
* @return the selected stock file as an InputStream, or null if no file is selected
*/
public InputStream getSelectedStockStream() {
if (userSelectedPath == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,9 @@ private void handleSell(final Stock stock, final BigDecimal quantity) {
transaction.commit(player);
player.updateStatus();
} catch (Exception e) {
LOGGER.log(System.Logger.Level.WARNING, "Unexpected error during sell transaction", e);
LOGGER.log(
System.Logger.Level.WARNING,
"Unexpected error during sell transaction", e);
}
}
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package edu.ntnu.idi.idatt2003.gruppe42.controller.viewcontrollers;

import edu.ntnu.idi.idatt2003.gruppe42.controller.PopupsController;
import edu.ntnu.idi.idatt2003.gruppe42.controller.TimeAndWeatherController;
import edu.ntnu.idi.idatt2003.gruppe42.controller.appcontrollers.StockAppController;
import edu.ntnu.idi.idatt2003.gruppe42.model.App;
import edu.ntnu.idi.idatt2003.gruppe42.model.Player;
import edu.ntnu.idi.idatt2003.gruppe42.view.views.DesktopView;
import javafx.application.Platform;

/**
* Responsible for binding UI components and listeners to game state in the desktop view.
*/
public record DesktopBindings(DesktopView desktopView, Player player,
TimeAndWeatherController timeAndWeatherController,
StockAppController stockAppController,
PopupsController popupsController,
DesktopDialogController dialogController,
Runnable onAdvanceWeek) {

private static final int SATURDAY_INDEX = 6;
private static final int SUNDAY_INDEX = 0;

/**
* Creates a new DesktopBindings instance.
*
* @param desktopView the desktop view
* @param player the player model
* @param timeAndWeatherController the time and weather controller
* @param stockAppController the stock app controller
* @param popupsController the popups controller
* @param dialogController the dialog controller
* @param onAdvanceWeek callback to advance the week
*/
public DesktopBindings {

}

/**
* Binds all UI components and listeners.
*/
public void setup() {
setupDesktopUi();
setupListeners();
syncInitialState();
}

private void setupDesktopUi() {
desktopView.getNextWeekButton().setOnAction(event -> handleAdvanceWeek());
desktopView.getSettingsButton().setOnAction(event -> popupsController.show(App.SETTINGS));

timeAndWeatherController.dayIndexProperty().addListener((obs, oldDay, newDay) -> {
int day = newDay.intValue();
boolean isWeekend = day == SATURDAY_INDEX || day == SUNDAY_INDEX;
Platform.runLater(() -> stockAppController.setWeekend(isWeekend));
if (day == SATURDAY_INDEX) {
Platform.runLater(dialogController::showWeekendRapport);
}
});
}

private void setupListeners() {
timeAndWeatherController.hourProperty().addListener((obs, ov, nv) -> {
desktopView.updateClock(timeAndWeatherController.getTimeString());
player.updateStatus();
});

timeAndWeatherController.dayIndexProperty().addListener((obs, ov, nv) -> {
String dayName = timeAndWeatherController.getDayOfWeekString();
desktopView.updateDay(dayName, dayName.equals("SUN"));
});

timeAndWeatherController.weekIndexProperty().addListener((obs, ov, nv) ->
desktopView.updateWeek(timeAndWeatherController.getWeekString()));

timeAndWeatherController.weatherProperty().addListener((obs, ov, nv) ->
desktopView.updateWeather(nv));

timeAndWeatherController.temperatureProperty().addListener((obs, ov, nv) ->
desktopView.updateTemperature(String.valueOf(nv)));

player.addNameListener(name ->
Platform.runLater(() -> desktopView.updatePlayerName(name)));

player.updateStatus();
player.addStatusListener(s ->
Platform.runLater(() -> desktopView.updatePlayerStatus(s.name())));
}

private void syncInitialState() {
desktopView.updateClock(timeAndWeatherController.getTimeString());
String startDay = timeAndWeatherController.getDayOfWeekString();
desktopView.updateDay(startDay, startDay.equals("SUN"));
desktopView.updateWeek(timeAndWeatherController.getWeekString());
desktopView.updateWeather(timeAndWeatherController.weatherProperty().get());
desktopView.updateTemperature(
String.valueOf(timeAndWeatherController.temperatureProperty().get()));
desktopView.updatePlayerName(player.getName());
}

private void handleAdvanceWeek() {
if (player.isInDebt()) {
dialogController.showDebtWarning();
} else {
onAdvanceWeek.run();
}
}
}
Loading