Skip to content

Commit

Permalink
feat: Portfolio-view related classes refactored.
Browse files Browse the repository at this point in the history
  • Loading branch information
pawelsa committed May 16, 2026
1 parent 6074d58 commit ffe6939
Show file tree
Hide file tree
Showing 6 changed files with 266 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public PlayerPortfolioComponent(Portfolio portfolio) {
BigDecimal startingMoney = UserSession.getInstance().getPlayer().getStartingMoney();
BigDecimal netMoney = UserSession.getInstance().getPlayer().getNetWorth();
BigDecimal netPercentage = netMoney.divide(startingMoney)
.multiply(new BigDecimal("100"))
.setScale(2, RoundingMode.HALF_UP)
.subtract(new BigDecimal("100"));
.multiply(new BigDecimal("100"))
.setScale(2, RoundingMode.HALF_UP)
.subtract(new BigDecimal("100"));

Label userTitle = new Label(String.format("%s's Portfolio", UserSession.getInstance().getPlayer().getName()));
Label netWorth = new Label();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,57 @@
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

import java.util.ArrayList;
import java.util.Collections;

import java.util.List;
import java.util.function.Consumer;

public class ShareComponent extends HBox {

public ShareComponent(Share share){
this.setMaxSize(Double.MAX_VALUE, 300);
this.setPadding(new Insets(30));
this.getStyleClass().add("rowBox");

Label name = new Label(share.getStock().getCompany());
Label quantity = new Label("Owned shares: "+share.getQuantity().toString());
Label ticker = new Label("("+share.getStock().getSymbol()+")");
Label latestPrice = new Label("Latest price: "+share.getStock().getSalesPrice().toString());
Button sellButton = new Button("Sell");

ArrayList<Label> labels = new ArrayList<>();
Collections.addAll(labels, name, quantity, ticker, latestPrice);
labels.forEach(e -> e.getStyleClass().add("portfolio-box-text"));
sellButton.getStyleClass().add("button");
String color = CssUtils.generateValueColors(share.getProfit().doubleValue());
CssUtils.apply(latestPrice, color);

UICompositor shareComponent = new UICompositor.Builder()
.parent(new HBox())
.growWithAlignment(Pos.CENTER)
.addAllContent(name, ticker)
.filler()
.addContent(latestPrice)
.filler()
.addContent(quantity)
.filler()
.addContent(sellButton)
.build();

this.getChildren().add(shareComponent.makeUI());
}
private final Share share;
private Button sellButton;

public ShareComponent(Share share) {
this.share = share;

this.setMaxSize(Double.MAX_VALUE, 300);
this.setPadding(new Insets(30));
this.getStyleClass().add("rowBox");

Label title = new Label(share.getStock().toString());
Label quantity = new Label("Owned shares: " + share.getQuantity().toString());
Label latestValueLabel = new Label("Net profit:");
Label latestValue = new Label(String.format("%.2f $", share.getProfit()));
Label latestValueChange = new Label(String.format("%.2f %%", share.getProfitPercent()));

sellButton = new Button("Sell");

List<Label> labels = List.of(title, quantity, latestValueLabel, latestValue, latestValueChange);
labels.forEach(e -> e.getStyleClass().add("portfolio-box-text"));
sellButton.getStyleClass().add("button");
String color = CssUtils.generateValueColors(share.getProfit());
CssUtils.apply(latestValue, color);
CssUtils.apply(latestValueChange, color);

UICompositor shareComponent = new UICompositor.Builder()
.parent(new HBox())
.growWithAlignment(Pos.CENTER)
.addContent(title)
.filler()
.wrap(new VBox())
.addAllContent(latestValueLabel, latestValue, latestValueChange)
.unwrap()
.filler()
.addContent(quantity)
.filler()
.addContent(sellButton)
.build();

this.getChildren().add(shareComponent.makeUI());
}

public void onShareSellButton(Consumer<Share> handler) {
sellButton.setOnAction((e) -> handler.accept(share));
}

}
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package edu.ntnu.idi.idatt.view.primary.portfolio;

import edu.ntnu.idi.idatt.model.portfolio.Portfolio;
import edu.ntnu.idi.idatt.view.components.Model;
import edu.ntnu.idi.idatt.view.components.elements.ShareComponent;
import edu.ntnu.idi.idatt.view.primary.portfolio.viewmodel.PlayerInfoModel;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class PortfolioModel implements Model {
private final ObservableList<ShareComponent> sharesList = FXCollections.observableArrayList();
private final Portfolio portfolio = new Portfolio();

public Portfolio getPortfolio() {
return portfolio;
}
public ObservableList<ShareComponent> getSharesList(){
return sharesList;
}
}
private final ObservableList<ShareComponent> shareList = FXCollections.observableArrayList();
private final PlayerInfoModel playerInfoModel = new PlayerInfoModel();

public ObservableList<ShareComponent> getShareList() {
return shareList;
}

public PlayerInfoModel playerInfoModel() {
return playerInfoModel;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,101 @@
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.PlayerPortfolioComponent;
import edu.ntnu.idi.idatt.view.components.ui.UIFactory;
import edu.ntnu.idi.idatt.view.primary.portfolio.PortfolioController.SortAction;
import edu.ntnu.idi.idatt.view.primary.portfolio.sections.PlayerInfoSection;
import edu.ntnu.idi.idatt.view.primary.portfolio.viewmodel.PlayerInfoModel;
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.*;

import java.util.List;
import java.util.function.Consumer;

public class PortfolioView extends AbstractViewUI {
private VBox shareBox;
private VBox userBox;

@Override
public Parent createContent() {
BorderPane root = new BorderPane();
userBox = new VBox(20);
root.getStyleClass().add("primary");

VBox.setVgrow(userBox, Priority.ALWAYS);
userBox.setPadding(new Insets(20));
ScrollPane stockBox = new ScrollPane();
stockBox.setPadding(new Insets(0, 10, 0, 20));
shareBox = new VBox(20);

stockBox.setFitToWidth(true);
stockBox.getStyleClass().add("viewport-colour");
stockBox.getStyleClass().add("primary");
root.setTop(userBox);
root.setCenter(stockBox);
stockBox.setContent(shareBox);
return root;
}

@Override
public Parent createNavigation() {
return UIFactory.createNavigation("Portfolio",
List.of(" • Title"),
() -> System.out.println("Newspaper clicked"));
}

@Override
public Parent createHeader() {
return UIFactory.createHeader("Search",
query -> System.out.println(query));
}

@Override
public Parent createToolbar() {
return UIFactory.createToolbar(() -> this.toggleMenu(),
() -> SceneManager.switchTo(SceneFactory.createStartView()));
}

@Override
public Parent createMenu() {
return UIFactory.createMenu("Account",
List.of(" • Portfolio", " • Transactions"),
() -> SceneManager.switchTo(SceneFactory.createPortfolioView()),
() -> System.out.println("Transaction clicked!"));
}
public void setModel(PortfolioModel model){
userBox.getChildren().clear();
PlayerPortfolioComponent portfolioComponent = new PlayerPortfolioComponent(model.getPortfolio());
userBox.getChildren().add(portfolioComponent);
Bindings.bindContent(shareBox.getChildren(), model.getSharesList());
}

public void setController(PortfolioController controller){

}

Consumer<String> searchQueryHandler;
Consumer<SortAction> sortHandle;

private VBox shareList;
private PlayerInfoSection playerInfoSection;

@Override
public Parent createContent() {
BorderPane root = new BorderPane();
root.getStyleClass().add("primary");

ScrollPane scroll = new ScrollPane();
scroll.setPadding(new Insets(0, 20, 0, 20));

scroll.setFitToWidth(true);
scroll.getStyleClass().add("viewport-colour");
scroll.getStyleClass().add("primary");
scroll.setContent(shareList = new VBox(20));

root.setTop(playerInfoSection = new PlayerInfoSection());
root.setCenter(scroll);
return root;
}

@Override
public Parent createNavigation() {
return UIFactory.createNavigation("Portfolio",
List.of(" • Title"),
() -> System.out.println("Newspaper clicked"));
}

@Override
public Parent createHeader() {
return UIFactory.createHeader("Search after holdings..",
query -> searchQueryHandler.accept(query),
List.of(
"Oldest first",
"Newest first",
"Highest profit",
"Highest loss"),
() -> sortHandle.accept(SortAction.OLDEST),
() -> sortHandle.accept(SortAction.NEWEST),
() -> sortHandle.accept(SortAction.PROFIT),
() -> sortHandle.accept(SortAction.LOSS));
}

@Override
public Parent createToolbar() {
return UIFactory.createToolbar(() -> this.toggleMenu(),
() -> SceneManager.switchTo(SceneFactory.createStartView()));
}

@Override
public Parent createMenu() {
return UIFactory.createMenu("Account",
List.of(" • Portfolio", " • Transactions"),
() -> {
},
() -> SceneManager.switchTo(SceneFactory.createTransactionView()));
}

public void setModel(PortfolioModel model) {
Bindings.bindContent(shareList.getChildren(), model.getShareList());

setPlayerInfoSectionModel(model.playerInfoModel());
}

public void setPlayerInfoSectionModel(PlayerInfoModel model) {
playerInfoSection.getTitle().textProperty().bind(model.getTitle());
playerInfoSection.getNetWorth().textProperty().bind(model.getNetWorth());

playerInfoSection.getNetWorthTotalChange().valueProperty().bind(model.getNetWorthTotalChange());
playerInfoSection.getNetWorthTotalChange().colorProperty().bind(model.getNetWorthTotalChangeColor());

playerInfoSection.getPlayerStatus().textProperty().bind(model.getPlayerStatus());
playerInfoSection.getTotalSharesOwned().textProperty().bind(model.getTotalSharesOwned());
}

public void setController(PortfolioController controller) {
searchQueryHandler = (query) -> controller.handleSearchQuery(query);
sortHandle = (sortAction) -> controller.sortSharesBy(sortAction);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package edu.ntnu.idi.idatt.view.primary.portfolio.sections;

import java.util.List;

import edu.ntnu.idi.idatt.view.components.elements.TextValueComponent;
import edu.ntnu.idi.idatt.view.components.ui.UICompositor;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;

public class PlayerInfoSection extends VBox {

Label title = new Label();
Label netWorth = new Label();
TextValueComponent netWorthTotalChange = new TextValueComponent("Total Net Worth change: ");
Label playerStatus = new Label();
Label totalSharesOwned = new Label();

public PlayerInfoSection() {

title.getStyleClass().add("portfolio-box-title");

List<Label> labels = List.of(netWorth, playerStatus, totalSharesOwned);
labels.forEach(l -> l.getStyleClass().add("portfolio-box-text"));

new UICompositor.Builder()
.parent(this)
.properties((parent) -> {
VBox.setVgrow(parent, Priority.ALWAYS);
parent.setPadding(new Insets(20));
})
.wrap(new HBox())
.properties((parent) -> {
parent.setMaxSize(Double.MAX_VALUE, 500);
parent.getStyleClass().add("light");
parent.setPadding(new Insets(20));
})
.growWithAlignment(Pos.CENTER)
.wrap(new VBox())
.addAllContent(title, netWorth, netWorthTotalChange)
.unwrap()
.filler()
.wrap(new VBox())
.growWithAlignment(Pos.BOTTOM_CENTER)
.addAllContent(playerStatus, totalSharesOwned)
.unwrap()
.unwrap()
.build();

}

public Label getTitle() {
return title;
}

public Label getNetWorth() {
return netWorth;
}

public TextValueComponent getNetWorthTotalChange() {
return netWorthTotalChange;
}

public Label getPlayerStatus() {
return playerStatus;
}

public Label getTotalSharesOwned() {
return totalSharesOwned;
}

}
Loading

0 comments on commit ffe6939

Please sign in to comment.