Skip to content

Commit

Permalink
Refactor(Stock MVC): Split code into sections (view (section), viewmo…
Browse files Browse the repository at this point in the history
…del)
  • Loading branch information
pawelsa committed May 16, 2026
1 parent f94ea8f commit a88f6d6
Show file tree
Hide file tree
Showing 7 changed files with 250 additions and 152 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,30 +73,30 @@ public void renderGraph() {
}

private void resetDisplayBuffers() {
model.getBuyPrice().set("0 $");
model.getBuyCost().set("0 $");
model.getTotalPrice().set("0 $");
model.getResultMessage().set("");
model.getResultMessageColorProperty().set(CssUtils.RED);
model.tradeModel().getBuyPrice().set("0 $");
model.tradeModel().getBuyCost().set("0 $");
model.tradeModel().getTotalPrice().set("0 $");
model.tradeModel().getResultMessage().set("");
model.tradeModel().getResultMessageColorProperty().set(CssUtils.RED);
}

private void initHooks() {
resetDisplayBuffers();
model.getBuyInputField().addListener((obervable, oldVal, newVal) -> displayBuyInfo(newVal));
model.tradeModel().getBuyInputField().addListener((obervable, oldVal, newVal) -> displayBuyInfo(newVal));
}

public void buyButtonClicked() {
if (share == null || purchaseCalculator == null) {
resetDisplayBuffers(); // Flush after color change and new press.
model.getResultMessage().set("Invalid purchase.");
model.tradeModel().getResultMessage().set("Invalid purchase.");
return;
}

BigDecimal purchase = session.getPlayer().getMoney().subtract(purchaseCalculator.calculateTotal());
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.tradeModel().getResultMessageColorProperty().set(CssUtils.RED);
model.tradeModel().getResultMessage().set("Balance too low.");
return;
}

Expand All @@ -108,16 +108,16 @@ public void buyButtonClicked() {
boolean result = buyConfirmation.displayAwaitResponse();

if (!result) {
model.getResultMessageColorProperty().set(CssUtils.RED);
model.getResultMessage().set("Transaction canceled.");
model.tradeModel().getResultMessageColorProperty().set(CssUtils.RED);
model.tradeModel().getResultMessage().set("Transaction canceled.");
return;
}

session.getExchange().buy(share.getStock().getSymbol(), share.getQuantity(), session.getPlayer());
this.setOwnedAmount();
this.setTotalProfits();
model.getResultMessageColorProperty().set(CssUtils.GREEN);
model.getResultMessage().set("Purchase completed!");
model.tradeModel().getResultMessageColorProperty().set(CssUtils.GREEN);
model.tradeModel().getResultMessage().set("Purchase completed!");
session.updateGameState();
}

Expand All @@ -133,12 +133,12 @@ private void displayBuyInfo(String amountString) {
try {
value = new BigDecimal(amountString);
} catch (NumberFormatException e) {
model.getResultMessage().set("Only numbers allowed!");
model.tradeModel().getResultMessage().set("Only numbers allowed!");
return;
}

if (value.compareTo(BigDecimal.ZERO) <= 0) {
model.getResultMessage().set("Invalid amount!");
model.tradeModel().getResultMessage().set("Invalid amount!");
return;
}

Expand All @@ -152,13 +152,13 @@ private void displayBuyInfo(String amountString) {
formatter.format(purchaseCalculator.calculateCommision().add(purchaseCalculator.calculateTax())));
String total = String.format("%s $", formatter.format(purchaseCalculator.calculateTotal()));

model.getBuyPrice().set(gross);
model.getBuyCost().set(cost);
model.getTotalPrice().set(total);
model.tradeModel().getBuyPrice().set(gross);
model.tradeModel().getBuyCost().set(cost);
model.tradeModel().getTotalPrice().set(total);
}

public void setCurrentPrice() {
model.getStockPrice().set(String.format("%.2f $", this.stock.getSalesPrice()));
model.priceInfoModel().getStockPrice().set(String.format("%.2f $", this.stock.getSalesPrice()));
}

public void setLatestChange() {
Expand All @@ -167,8 +167,8 @@ public void setLatestChange() {

String format = String.format("%.2f $ ( %.2f %%)", change, changePercent);

model.getLatestChange().set(format);
model.getLatestChangeColorProperty().set(CssUtils.generateValueColors(change.doubleValue()));
model.priceInfoModel().getLatestChange().set(format);
model.priceInfoModel().getLatestChangeColorProperty().set(CssUtils.generateValueColors(change.doubleValue()));
}

public void setAllTimeScore() {
Expand All @@ -177,7 +177,7 @@ public void setAllTimeScore() {

String format = String.format("%.2f / %.2f", highest, lowest);

model.getAllTimeScore().set(format);
model.priceInfoModel().getAllTimeScore().set(format);
}

public void setOwnedAmount() {
Expand All @@ -187,7 +187,7 @@ public void setOwnedAmount() {

String format = String.format("%.2f [%s]", ownedAmount, symbol);

model.getOwnedAmount().set(format);
model.priceInfoModel().getOwnedAmount().set(format);
}

public void setTotalProfits() {
Expand All @@ -198,7 +198,7 @@ public void setTotalProfits() {

String format = String.format("%.2f $ (%.2f %%)", profit, profitPercent);

model.getTotalProfits().set(format);
model.getTotalProfitsColorProperty().set(CssUtils.generateValueColors(profit));
model.priceInfoModel().getTotalProfits().set(format);
model.priceInfoModel().getTotalProfitsColorProperty().set(CssUtils.generateValueColors(profit));
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package edu.ntnu.idi.idatt.view.primary.stock;

import edu.ntnu.idi.idatt.view.components.Model;
import javafx.beans.property.SimpleStringProperty;
import edu.ntnu.idi.idatt.view.primary.stock.viewmodel.PriceInfoModel;
import edu.ntnu.idi.idatt.view.primary.stock.viewmodel.TradeModel;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Node;
Expand All @@ -12,80 +13,21 @@ public class StockModel implements Model {
private final ObservableList<Node> graphNodes = FXCollections.observableArrayList();

// Price properties
private final SimpleStringProperty stockPrice = new SimpleStringProperty();

private final SimpleStringProperty latestChange = new SimpleStringProperty();
private final SimpleStringProperty latestChangeColorProperty = new SimpleStringProperty();

private final SimpleStringProperty allTimeScore = new SimpleStringProperty();

private final SimpleStringProperty ownedAmount = new SimpleStringProperty();

private final SimpleStringProperty totalProfits = new SimpleStringProperty();
private final SimpleStringProperty totalProfitsColorProperty = new SimpleStringProperty();
private final PriceInfoModel priceInfoModel = new PriceInfoModel();

// Trade properties
private final SimpleStringProperty buyInputField = new SimpleStringProperty();
private final SimpleStringProperty resultMessage = new SimpleStringProperty();
private final SimpleStringProperty resultMessageColorProperty = new SimpleStringProperty();
private final SimpleStringProperty buyPrice = new SimpleStringProperty();
private final SimpleStringProperty buyCost = new SimpleStringProperty();
private final SimpleStringProperty totalPrice = new SimpleStringProperty();
private final TradeModel tradeModel = new TradeModel();

public ObservableList<Node> getGraphNodes() {
return this.graphNodes;
}

public SimpleStringProperty getStockPrice() {
return stockPrice;
}

public SimpleStringProperty getLatestChange() {
return latestChange;
}

public SimpleStringProperty getLatestChangeColorProperty() {
return latestChangeColorProperty;
}

public SimpleStringProperty getAllTimeScore() {
return allTimeScore;
}

public SimpleStringProperty getOwnedAmount() {
return ownedAmount;
}

public SimpleStringProperty getTotalProfits() {
return totalProfits;
}

public SimpleStringProperty getTotalProfitsColorProperty() {
return totalProfitsColorProperty;
}

public SimpleStringProperty getBuyInputField() {
return buyInputField;
}

public SimpleStringProperty getResultMessage() {
return resultMessage;
}

public SimpleStringProperty getResultMessageColorProperty() {
return resultMessageColorProperty;
}

public SimpleStringProperty getBuyPrice() {
return buyPrice;
}

public SimpleStringProperty getBuyCost() {
return buyCost;
public PriceInfoModel priceInfoModel() {
return priceInfoModel;
}

public SimpleStringProperty getTotalPrice() {
return totalPrice;
public TradeModel tradeModel() {
return tradeModel;
}

}
93 changes: 32 additions & 61 deletions src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockView.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
import edu.ntnu.idi.idatt.view.SceneFactory;
import edu.ntnu.idi.idatt.view.SceneManager;
import edu.ntnu.idi.idatt.view.components.AbstractViewUI;
import edu.ntnu.idi.idatt.view.components.elements.TextValueComponent;
import edu.ntnu.idi.idatt.view.components.ui.UICompositor;
import edu.ntnu.idi.idatt.view.components.ui.UIFactory;
import edu.ntnu.idi.idatt.view.primary.stock.sections.PriceInfoSection;
import edu.ntnu.idi.idatt.view.primary.stock.sections.TradeSection;
import edu.ntnu.idi.idatt.view.primary.stock.viewmodel.PriceInfoModel;
import edu.ntnu.idi.idatt.view.primary.stock.viewmodel.TradeModel;
import edu.ntnu.idi.idatt.view.util.CssUtils;
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
Expand All @@ -25,20 +26,10 @@ public class StockView extends AbstractViewUI {
private Label title;

// Prices
TextValueComponent stockPrice;
TextValueComponent latestChange;
TextValueComponent allTimeScore;
TextValueComponent ownedAmount;
TextValueComponent totalProfits;
private PriceInfoSection priceInfoSection;

// Trade menu
Button buyButton;
Button portfolioButton;
TextField buyInputField;
TextValueComponent buyPrice;
TextValueComponent buyCost;
TextValueComponent totalPrice;
TextValueComponent resultMessage;
private TradeSection tradeSection;

@Override
public Parent createContent() {
Expand All @@ -57,40 +48,11 @@ public Parent createContent() {
.parent(new HBox())
.growWithAlignment(Pos.TOP_CENTER)
.properties((parent) -> parent.setPadding(new Insets(20.0)))

.wrap(new VBox())
.addContent(stockPrice = new TextValueComponent("Current price: "))
.addContent(latestChange = new TextValueComponent("Latest Price Change: "))
.addContent(allTimeScore = new TextValueComponent("All time H/L: "))
.addContent(ownedAmount = new TextValueComponent("Owned amount: "))
.addContent(totalProfits = new TextValueComponent("Total profits: "))
.unwrap()

.addContent(priceInfoSection = new PriceInfoSection())
.filler()

.wrap(new VBox())

.wrap(new HBox())
.addContent(buyButton = new Button("Buy"))
.addContent(portfolioButton = new Button("Sell in portfolio..."))
.properties((wrapper) -> ((HBox) wrapper).setSpacing(20.0))
.unwrap()

.wrap(new VBox())
.properties((wrapper) -> wrapper.setPadding(new Insets(20)))
.properties((wrapper) -> wrapper.setMaxWidth(400))
.addContent(buyInputField = new TextField())
.addContent(buyPrice = new TextValueComponent("Price: "))
.addContent(buyCost = new TextValueComponent("Taxes & commision: "))
.addContent(totalPrice = new TextValueComponent("Total: "))
.unwrap()
.addContent(resultMessage = new TextValueComponent(""))
.unwrap()
.addContent(tradeSection = new TradeSection())
.build();

// Detailing
buyInputField.setPromptText("Amount of stocks...");

root.getChildren().addAll(graphContainer, userSection.makeUI());
return root;
}
Expand Down Expand Up @@ -127,31 +89,40 @@ public void setModel(StockModel model) {
Bindings.bindContent(graphContainer.getChildren(), model.getGraphNodes());

// Price display bindings
stockPrice.valueProperty().bind(model.getStockPrice());
setPriceInfoSectionModel(model.priceInfoModel());

latestChange.valueProperty().bind(model.getLatestChange());
latestChange.colorProperty().bind(model.getLatestChangeColorProperty());
// Trade section bindings
setTradeSectionModel(model.tradeModel());

allTimeScore.valueProperty().bind(model.getAllTimeScore());
}

ownedAmount.valueProperty().bind(model.getOwnedAmount());
public void setPriceInfoSectionModel(PriceInfoModel model) {
priceInfoSection.getStockPrice().valueProperty().bind(model.getStockPrice());

totalProfits.valueProperty().bind(model.getTotalProfits());
totalProfits.colorProperty().bind(model.getTotalProfitsColorProperty());
priceInfoSection.getLatestChange().valueProperty().bind(model.getLatestChange());
priceInfoSection.getLatestChange().colorProperty().bind(model.getLatestChangeColorProperty());

priceInfoSection.getAllTimeScore().valueProperty().bind(model.getAllTimeScore());

priceInfoSection.getOwnedAmount().valueProperty().bind(model.getOwnedAmount());

priceInfoSection.getTotalProfits().valueProperty().bind(model.getTotalProfits());
priceInfoSection.getTotalProfits().colorProperty().bind(model.getTotalProfitsColorProperty());
}

// Trade menu bindings
buyInputField.textProperty().bindBidirectional(model.getBuyInputField());
buyPrice.valueProperty().bind(model.getBuyPrice());
buyCost.valueProperty().bind(model.getBuyCost());
totalPrice.valueProperty().bind(model.getTotalPrice());
resultMessage.valueProperty().bind(model.getResultMessage());
resultMessage.colorProperty().bind(model.getResultMessageColorProperty());
public void setTradeSectionModel(TradeModel model) {
tradeSection.getBuyInputField().textProperty().bindBidirectional(model.getBuyInputField());
tradeSection.getBuyPrice().valueProperty().bind(model.getBuyPrice());
tradeSection.getBuyCost().valueProperty().bind(model.getBuyCost());
tradeSection.getTotalPrice().valueProperty().bind(model.getTotalPrice());

tradeSection.getResultMessage().valueProperty().bind(model.getResultMessage());
tradeSection.getResultMessage().colorProperty().bind(model.getResultMessageColorProperty());
}

public void setController(StockController controller) {
title.setText(controller.getSymbol());
buyButton.setOnAction((e) -> controller.buyButtonClicked());
tradeSection.getBuyButton().setOnAction((e) -> controller.buyButtonClicked());
}

}
Loading

0 comments on commit a88f6d6

Please sign in to comment.