From 7263ecd79302689a3e79838bb655cb40796c7187 Mon Sep 17 00:00:00 2001 From: pawelsa Date: Thu, 14 May 2026 21:50:05 +0200 Subject: [PATCH 01/10] feat(Stock): Added toString method --- src/main/java/edu/ntnu/idi/idatt/model/market/Stock.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/edu/ntnu/idi/idatt/model/market/Stock.java b/src/main/java/edu/ntnu/idi/idatt/model/market/Stock.java index c7c65c4..cff8ad3 100644 --- a/src/main/java/edu/ntnu/idi/idatt/model/market/Stock.java +++ b/src/main/java/edu/ntnu/idi/idatt/model/market/Stock.java @@ -119,4 +119,10 @@ public void addNewSalesPrice(BigDecimal price) { prices.add(price); } + // TODO: JavaDocs + @Override + public String toString() { + return this.getCompany() + " (" + this.getSymbol() + ")"; + } + } From bb979918e8574ed67dfc2c81a0e6d28250b5afbb Mon Sep 17 00:00:00 2001 From: pawelsa Date: Thu, 14 May 2026 21:51:35 +0200 Subject: [PATCH 02/10] feat: Simplify searching with toString --- .../view/primary/exchange/ExchangeController.java | 5 +---- .../primary/transactions/TransactionController.java | 11 +++-------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/exchange/ExchangeController.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/exchange/ExchangeController.java index 5725e60..eece896 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/primary/exchange/ExchangeController.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/exchange/ExchangeController.java @@ -44,10 +44,7 @@ public void handleSearchQuery(String query) { } List stocksFound = stocksSorted.stream() - .filter(stock -> { - String name = stock.getCompany() + " (" + stock.getSymbol() + ")"; - return name.contains(query); - }).toList(); + .filter(stock -> stock.toString().contains(query)).toList(); setStocksModel(stocksFound); diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/transactions/TransactionController.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/transactions/TransactionController.java index ed7c640..5de890c 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/primary/transactions/TransactionController.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/transactions/TransactionController.java @@ -48,12 +48,7 @@ public void handleSearchQuery(String query) { } List transactionsFound = transactionsSorted.stream() - .filter(transaction -> { - String name = transaction.getShare().getStock().getCompany() + " (" - + transaction.getShare().getStock().getSymbol() - + ")"; - return name.contains(query); - }).toList(); + .filter(transaction -> transaction.getShare().getStock().toString().contains(query)).toList(); setTransactionModel(transactionsFound); } @@ -70,7 +65,7 @@ public void sortTransactionsBy(SortAction action) { } case NEWEST_DESCENDING: { - for (int i = 1; i <= currentWeek; i++) { // Exchanges start at week 1. + for (int i = currentWeek; i >= 1; i--) { // Exchanges start at week 1. List getCurrentTransactions = session.getPlayer().getTransactionArchive().getTransactions(i); transactionsSorted.addAll(getCurrentTransactions); } @@ -78,7 +73,7 @@ public void sortTransactionsBy(SortAction action) { } case OLDEST_ASCENDING: { - for (int i = currentWeek; i >= 1; i--) { + for (int i = 1; i <= currentWeek; i++) { List getCurrentTransactions = session.getPlayer().getTransactionArchive().getTransactions(i); transactionsSorted.addAll(getCurrentTransactions); } From ba9eabe7054000493437117a786e633674c25ae8 Mon Sep 17 00:00:00 2001 From: pawelsa Date: Thu, 14 May 2026 21:51:56 +0200 Subject: [PATCH 03/10] refactor(CssUtils): Add variations to generateValueColors method --- src/main/java/edu/ntnu/idi/idatt/view/util/CssUtils.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/edu/ntnu/idi/idatt/view/util/CssUtils.java b/src/main/java/edu/ntnu/idi/idatt/view/util/CssUtils.java index f689a60..4615da6 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/util/CssUtils.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/util/CssUtils.java @@ -1,5 +1,7 @@ package edu.ntnu.idi.idatt.view.util; +import java.math.BigDecimal; + import javafx.scene.Parent; public class CssUtils { @@ -19,6 +21,10 @@ public static void set(Parent parent, String cssClass) { parent.getStyleClass().add(cssClass); } + public static String generateValueColors(BigDecimal value) { + return value.compareTo(BigDecimal.ZERO) >= 0 ? GREEN : RED; + } + public static String generateValueColors(double value) { return value >= 0 ? GREEN : RED; } From 9c2f8856b45c72ffb7a4ca49e957d0d0e09d889b Mon Sep 17 00:00:00 2001 From: pawelsa Date: Thu, 14 May 2026 21:52:20 +0200 Subject: [PATCH 04/10] feat: Implement UIAlert class for transaction alerts --- .../idi/idatt/view/components/ui/UIAlert.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/java/edu/ntnu/idi/idatt/view/components/ui/UIAlert.java diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/ui/UIAlert.java b/src/main/java/edu/ntnu/idi/idatt/view/components/ui/UIAlert.java new file mode 100644 index 0000000..78c7341 --- /dev/null +++ b/src/main/java/edu/ntnu/idi/idatt/view/components/ui/UIAlert.java @@ -0,0 +1,26 @@ +package edu.ntnu.idi.idatt.view.components.ui; + +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.ButtonType; + +public class UIAlert { + + Alert alert = new Alert(AlertType.CONFIRMATION); + ButtonType confirm = new ButtonType("Confirm"); + ButtonType cancel = new ButtonType("Cancel"); + + public UIAlert(String title, String header, String content) { + alert.setTitle(title); + alert.setHeaderText(header); + alert.setContentText(content); + + alert.getButtonTypes().setAll(confirm, cancel); + } + + public boolean displayAwaitResponse() { + ButtonType type = alert.showAndWait().orElse(cancel); + return type == confirm ? true : false; + } + +} From 848b98bf56743c975ae2a4936494e0236eded632 Mon Sep 17 00:00:00 2001 From: pawelsa Date: Thu, 14 May 2026 21:52:51 +0200 Subject: [PATCH 05/10] refactor(..Component): Use toString method --- .../idi/idatt/view/components/elements/StockComponent.java | 2 +- .../view/components/elements/TransactionComponent.java | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/StockComponent.java b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/StockComponent.java index 2edb0c8..fe29fdc 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/StockComponent.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/StockComponent.java @@ -24,7 +24,7 @@ public StockComponent(Stock stock) { this.setStyle("-fx-background-color: #404950;"); - Label title = new Label(String.format("%s (%s)", stock.getCompany(), stock.getSymbol())); + Label title = new Label(stock.toString()); Label latestText = new Label("Latest"); Label latestValue = new Label(String.format("%.2f USD", stock.getSalesPrice())); diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/TransactionComponent.java b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/TransactionComponent.java index 1864b15..26fd7d1 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/TransactionComponent.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/TransactionComponent.java @@ -20,20 +20,23 @@ public class TransactionComponent extends VBox { public TransactionComponent(Transaction transaction) { Stock stock = transaction.getShare().getStock(); + TransactionCalculator calculator = transaction.getCalculator(); Label title; - Label name = new Label(stock.getCompany() + " (" + stock.getSymbol() + ")"); + Label name = new Label(stock.toString()); Label totalValue; Label taxComissionValue; Label grossValue; Label amountOfShares; Label saleProfit; - TransactionCalculator calculator = transaction.getCalculator(); totalValue = new Label(String.format("Total: %.2f USD", calculator.calculateTotal())); + taxComissionValue = new Label(String.format( "Tax & Comission: %.2f USD", calculator.calculateTax().add(calculator.calculateCommision()))); + grossValue = new Label(String.format("Gross: %.2f USD", calculator.calculateGross())); + amountOfShares = new Label( String.format("Shares: %.2f [%s]", transaction.getShare().getQuantity(), stock.getSymbol())); From c821d693e8c20058a4ee70c9c4a4eb4ac8b631c4 Mon Sep 17 00:00:00 2001 From: pawelsa Date: Thu, 14 May 2026 21:54:26 +0200 Subject: [PATCH 06/10] refactor: Correct model-view hooks. --- .../ntnu/idi/idatt/model/player/Player.java | 10 ------ .../ntnu/idi/idatt/session/UserSession.java | 21 +++++++++---- .../idatt/view/components/ui/UIFactory.java | 1 + .../view/primary/stock/StockController.java | 31 +++++++++++++------ 4 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/main/java/edu/ntnu/idi/idatt/model/player/Player.java b/src/main/java/edu/ntnu/idi/idatt/model/player/Player.java index 7af1065..f75b184 100644 --- a/src/main/java/edu/ntnu/idi/idatt/model/player/Player.java +++ b/src/main/java/edu/ntnu/idi/idatt/model/player/Player.java @@ -2,7 +2,6 @@ import edu.ntnu.idi.idatt.model.portfolio.Portfolio; import edu.ntnu.idi.idatt.model.transaction.TransactionArchive; -import edu.ntnu.idi.idatt.session.UserSession; import java.math.BigDecimal; @@ -50,19 +49,10 @@ public TransactionArchive getTransactionArchive() { public void addMoney(BigDecimal amount) { this.money = this.money.add(amount); - UserSession.getInstance().moneyProperty().set(this.money.doubleValue()); // Workaround instead of PropertyChange due - // to JSON saving - UserSession.getInstance().netWorthProperty().set(this.getNetWorth().doubleValue()); // Portfolio doesnt change - // without monetary change - // (either buy or sale) so thats - // the decision to hook net - // worth here and under. } public void withdrawMoney(BigDecimal amount) { this.money = this.money.subtract(amount); - UserSession.getInstance().moneyProperty().set(this.money.doubleValue()); // Hooks - UserSession.getInstance().netWorthProperty().set(this.getNetWorth().doubleValue()); } /** diff --git a/src/main/java/edu/ntnu/idi/idatt/session/UserSession.java b/src/main/java/edu/ntnu/idi/idatt/session/UserSession.java index 3dcf5ab..2fef3e5 100644 --- a/src/main/java/edu/ntnu/idi/idatt/session/UserSession.java +++ b/src/main/java/edu/ntnu/idi/idatt/session/UserSession.java @@ -1,8 +1,11 @@ package edu.ntnu.idi.idatt.session; +import java.math.BigDecimal; + import edu.ntnu.idi.idatt.model.Exchange; import edu.ntnu.idi.idatt.model.player.Player; -import javafx.beans.property.SimpleDoubleProperty; +import edu.ntnu.idi.idatt.storage.SessionManager; +import javafx.beans.property.SimpleObjectProperty; public class UserSession { @@ -29,7 +32,7 @@ public Player getPlayer() { public void setPlayer(Player player) { this.player = player; - moneyProperty.set(player.getMoney().doubleValue()); // Startup hook + updateGameState(); // Startup hook } public Exchange getExchange() { @@ -40,17 +43,23 @@ public void setExchange(Exchange exchange) { this.exchange = exchange; } - private final SimpleDoubleProperty moneyProperty = new SimpleDoubleProperty(); - private final SimpleDoubleProperty netWorthProperty = new SimpleDoubleProperty(); + private final SimpleObjectProperty moneyProperty = new SimpleObjectProperty<>(BigDecimal.ZERO); + private final SimpleObjectProperty netWorthProperty = new SimpleObjectProperty<>(BigDecimal.ZERO); - public SimpleDoubleProperty moneyProperty() { + public SimpleObjectProperty moneyProperty() { return moneyProperty; } - public SimpleDoubleProperty netWorthProperty() { + public SimpleObjectProperty netWorthProperty() { return netWorthProperty; } + public void updateGameState() { + moneyProperty.set(player.getMoney()); + netWorthProperty.set(player.getNetWorth()); + SessionManager.saveSession(); + } + public SessionBundle getSession() { return new SessionBundle(player, exchange); } diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/ui/UIFactory.java b/src/main/java/edu/ntnu/idi/idatt/view/components/ui/UIFactory.java index ed6aeab..2be519b 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/components/ui/UIFactory.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/components/ui/UIFactory.java @@ -144,6 +144,7 @@ public static Parent createMenu(String title, List buttonLables, ActionE Button progress = new Button("Advance to next week"); progress.setOnAction((e) -> { UserSession.getInstance().getExchange().advance(); + UserSession.getInstance().updateGameState(); SceneFactory.reloadCurrent(); }); diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockController.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockController.java index 078074a..0d80656 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockController.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockController.java @@ -9,6 +9,7 @@ import edu.ntnu.idi.idatt.session.UserSession; import edu.ntnu.idi.idatt.storage.SessionManager; import edu.ntnu.idi.idatt.view.components.AbstractController; +import edu.ntnu.idi.idatt.view.components.ui.UIAlert; import edu.ntnu.idi.idatt.view.util.CssUtils; import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; @@ -95,7 +96,20 @@ public void buyButtonClicked() { if (purchase.compareTo(BigDecimal.ZERO) <= 0) { // Flush after color change and new press, while still calculating everything. model.getResultMessageColorProperty().set(CssUtils.RED); - model.getResultMessage().set("Balance too low!"); + model.getResultMessage().set("Balance too low."); + return; + } + + UIAlert buyConfirmation = new UIAlert("Confirmation required", + "Do you wish to proceed the purchase?", + String.format("Purchasing %.2f [%s] for %.2f $", + share.getQuantity(), share.getStock().getSymbol(), purchaseCalculator.calculateTotal())); + + boolean result = buyConfirmation.displayAwaitResponse(); + + if (!result) { + model.getResultMessageColorProperty().set(CssUtils.RED); + model.getResultMessage().set("Transaction canceled."); return; } @@ -104,8 +118,7 @@ public void buyButtonClicked() { this.setTotalProfits(); model.getResultMessageColorProperty().set(CssUtils.GREEN); model.getResultMessage().set("Purchase completed!"); - SessionManager.saveSession(); - + session.updateGameState(); } private void displayBuyInfo(String amountString) { @@ -168,8 +181,8 @@ public void setAllTimeScore() { } public void setOwnedAmount() { - double ownedAmount = session.getPlayer().getPortfolio().getOwnedAmount( - this.stock.getSymbol()).doubleValue(); + BigDecimal ownedAmount = session.getPlayer().getPortfolio().getOwnedAmount( + this.stock.getSymbol()); String symbol = this.stock.getSymbol(); String format = String.format("%.2f [%s]", ownedAmount, symbol); @@ -178,10 +191,10 @@ public void setOwnedAmount() { } public void setTotalProfits() { - double profit = session.getPlayer().getPortfolio().getProfitFromStock( - this.stock.getSymbol()).doubleValue(); - double profitPercent = session.getPlayer().getPortfolio().getChangeFromStock( - this.stock.getSymbol()).doubleValue(); + BigDecimal profit = session.getPlayer().getPortfolio().getProfitFromStock( + this.stock.getSymbol()); + BigDecimal profitPercent = session.getPlayer().getPortfolio().getChangeFromStock( + this.stock.getSymbol()); String format = String.format("%.2f $ (%.2f %%)", profit, profitPercent); From 72fce323c5ed6f424001abaa415f3af777e2cd6a Mon Sep 17 00:00:00 2001 From: pawelsa Date: Thu, 14 May 2026 21:54:58 +0200 Subject: [PATCH 07/10] fix: Remove hooks. --- .../edu/ntnu/idi/idatt/model/Exchange.java | 7 +-- .../edu/ntnu/idi/idatt/view/SceneFactory.java | 17 ++--- .../elements/PlayerPortfolioComponent.java | 62 +++++++++---------- 3 files changed, 41 insertions(+), 45 deletions(-) diff --git a/src/main/java/edu/ntnu/idi/idatt/model/Exchange.java b/src/main/java/edu/ntnu/idi/idatt/model/Exchange.java index 3b96c81..e41a2c0 100644 --- a/src/main/java/edu/ntnu/idi/idatt/model/Exchange.java +++ b/src/main/java/edu/ntnu/idi/idatt/model/Exchange.java @@ -1,7 +1,6 @@ package edu.ntnu.idi.idatt.model; import java.math.BigDecimal; -import java.math.MathContext; import java.math.RoundingMode; import java.util.*; @@ -11,7 +10,6 @@ import edu.ntnu.idi.idatt.model.transaction.Purchase; import edu.ntnu.idi.idatt.model.transaction.Sale; import edu.ntnu.idi.idatt.model.transaction.Transaction; -import edu.ntnu.idi.idatt.session.UserSession; /** * Exchange class @@ -201,10 +199,7 @@ public void advance() { Random random = new Random(); stockMap.values() .forEach(s -> s.addNewSalesPrice(s.getSalesPrice() - .multiply(BigDecimal.valueOf(random.nextDouble(0.8, 1.4)).setScale(2, RoundingMode.HALF_UP)))); - UserSession.getInstance().netWorthProperty().set( - UserSession.getInstance().getPlayer().getNetWorth().doubleValue()); // TODO: Remove hook from here, just for - // testing + .multiply(BigDecimal.valueOf(random.nextDouble(0.8, 1.4))).setScale(2, RoundingMode.HALF_UP))); } } diff --git a/src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java b/src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java index cd14152..350fa89 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java @@ -20,19 +20,17 @@ import edu.ntnu.idi.idatt.view.primary.transactions.TransactionView; import javafx.scene.Parent; -import java.math.BigDecimal; import java.util.ArrayDeque; import java.util.Deque; -import java.util.List; public class SceneFactory { @FunctionalInterface - public interface MVCInitializer { + public interface MVCInitInterface { Parent execute(); } - private static Deque navigation = new ArrayDeque<>(); + private static Deque navigation = new ArrayDeque<>(); private static boolean navigatingBack = false; public static void goBack() { @@ -50,7 +48,7 @@ public static void reloadCurrent() { navigatingBack = false; } - private static void mark(MVCInitializer initializer) { + private static void mark(MVCInitInterface initializer) { if (!navigatingBack) { navigation.push(initializer); } @@ -62,6 +60,8 @@ public static boolean isFinal() { public static Parent createStartView() { + navigation.clear(); + StartModel model = new StartModel(); StartView view = new StartView(); StartController controller = new StartController(model); @@ -72,13 +72,14 @@ public static Parent createStartView() { return view.getInstance(); } - public static Parent createPortfolioView(){ + + public static Parent createPortfolioView() { mark(() -> createPortfolioView()); - + PortfolioModel model = new PortfolioModel(); PortfolioView view = new PortfolioView(); - PortfolioController controller = new PortfolioController(model); + PortfolioController controller = new PortfolioController(model); view.setModel(model); view.setController(controller); diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/PlayerPortfolioComponent.java b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/PlayerPortfolioComponent.java index 7457d36..6744dd4 100644 --- a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/PlayerPortfolioComponent.java +++ b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/PlayerPortfolioComponent.java @@ -8,42 +8,42 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; -import java.math.BigDecimal; -import java.math.RoundingMode; import java.util.ArrayList; import java.util.Collections; public class PlayerPortfolioComponent extends HBox { - public PlayerPortfolioComponent(Portfolio portfolio){ - this.setMaxSize(Double.MAX_VALUE, 500); - this.getStyleClass().add("light"); + public PlayerPortfolioComponent(Portfolio portfolio) { + this.setMaxSize(Double.MAX_VALUE, 500); + this.getStyleClass().add("light"); - Label userTitle = new Label(String.format("%s's Portfolio", UserSession.getInstance().getPlayer().getName())); - Label netWorth = new Label(); - netWorth.textProperty().bind( - UserSession.getInstance().netWorthProperty().asString("Net Worth: %.2f $")); - Label percentageChange = new Label("Percentage change: "+ UserSession.getInstance().netWorthProperty().doubleValue()); - Label playerStatus = new Label("Player status: "+ UserSession.getInstance().getPlayer().getStatus()); - Label totalShares = new Label("Total shares owned: "+ UserSession.getInstance().getPlayer().getPortfolio().getShares().size()); - ArrayList