Skip to content

UI portfolio screen #49

Merged
merged 8 commits into from
May 14, 2026
Merged
1 change: 1 addition & 0 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
run: mvn clean verify site

- name: Deploy to Github Pages
if: github.event_name == 'push'
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
24 changes: 21 additions & 3 deletions src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package edu.ntnu.idi.idatt.view;

import java.util.ArrayDeque;
import java.util.Deque;

import edu.ntnu.idi.idatt.model.market.Stock;
import edu.ntnu.idi.idatt.session.UserSession;
import edu.ntnu.idi.idatt.view.entry.StartController;
Expand All @@ -19,6 +16,9 @@
import edu.ntnu.idi.idatt.view.primary.transactions.TransactionView;
import javafx.scene.Parent;

import java.util.ArrayDeque;
import java.util.Deque;

public class SceneFactory {

@FunctionalInterface
Expand Down Expand Up @@ -66,6 +66,24 @@ public static Parent createStartView() {
return view.getInstance();

}
public static Parent createPortfolioView(){
Stock stock = new Stock("int", "intel", List.of(new BigDecimal("100")));
Share share = new Share(stock, new BigDecimal("50"), new BigDecimal("100"));
UserSession.getInstance().getPlayer().getPortfolio().addShare(share);
UserSession.getInstance().getPlayer().getPortfolio().addShare(share);
UserSession.getInstance().getPlayer().getPortfolio().addShare(share);
UserSession.getInstance().getPlayer().getPortfolio().addShare(share);
UserSession.getInstance().getPlayer().getPortfolio().addShare(share);
UserSession.getInstance().getPlayer().getPortfolio().addShare(share);
PortfolioModel model = new PortfolioModel();
PortfolioView view = new PortfolioView();
PortfolioController controller = new PortfolioController(model);

view.setModel(model);
view.setController(controller);

return view.getInstance();
}

public static Parent createExchangeView() {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package edu.ntnu.idi.idatt.view.components.elements;

import edu.ntnu.idi.idatt.model.portfolio.Portfolio;
import edu.ntnu.idi.idatt.view.components.ui.UICompositor;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

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");
Label userTitle = new Label("Name Title");
Label netWorth = new Label("Total net worth: "+portfolio.getNetWorth().toString());
Label percentageChange = new Label("Percentage change: ");
Label playerStatus = new Label("Novice");
Label portfolioWorth = new Label("Portfolio net worth: ");
Label totalShares = new Label("Total shares owned: ");

ArrayList<Label> labels = new ArrayList<>();
Collections.addAll(labels, netWorth, percentageChange, playerStatus, portfolioWorth, totalShares);
labels.forEach(e -> e.getStyleClass().add("user-box-text"));
userTitle.getStyleClass().add("user-box-title");

VBox leftColumn = new VBox(userTitle, netWorth, percentageChange, playerStatus);
VBox rightColumn = new VBox(portfolioWorth, totalShares);

UICompositor playerPortfolioComponent = new UICompositor.Builder()
.parent(new HBox())
.growWithAlignment(Pos.CENTER)
.addContent(leftColumn)
.filler()
.addContent(rightColumn)
.build();

this.getChildren().add(playerPortfolioComponent.makeUI());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package edu.ntnu.idi.idatt.view.components.elements;

import edu.ntnu.idi.idatt.model.portfolio.Share;
import edu.ntnu.idi.idatt.view.components.ui.UICompositor;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;


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");
ticker.getStyleClass().add("portfolio-stock-names");
name.getStyleClass().add("portfolio-stock-names");
quantity.getStyleClass().add("portfolio-stock-names");
latestPrice.getStyleClass().add("portfolio-stock-names");
sellButton.getStyleClass().add("button");
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());
}

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

import edu.ntnu.idi.idatt.model.portfolio.Share;
import edu.ntnu.idi.idatt.session.UserSession;
import edu.ntnu.idi.idatt.view.components.AbstractController;
import edu.ntnu.idi.idatt.view.components.elements.ShareComponent;

import java.util.ArrayList;

public class PortfolioController extends AbstractController<PortfolioModel> {
private final ArrayList<ShareComponent> loadedShareComponents = new ArrayList<>();
private UserSession session = UserSession.getInstance();

public PortfolioController(PortfolioModel model){
super(model);
for(Share share: session.getPlayer().getPortfolio().getShares()){
ShareComponent shareComponent = new ShareComponent(share);
loadedShareComponents.add(shareComponent);
}
model.getSharesList().setAll(loadedShareComponents);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package edu.ntnu.idi.idatt.view.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 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;
}
}
77 changes: 77 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt/view/portfolio/PortfolioView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package edu.ntnu.idi.idatt.view.portfolio;

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 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;

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));
root.setTop(userBox);

ScrollPane stockBox = new ScrollPane();
stockBox.setPadding(new Insets(10, 10, 20, 20));
root.setCenter(stockBox);
stockBox.setFitToWidth(true);
stockBox.getStyleClass().add("viewport-colour");
stockBox.getStyleClass().add("primary");
shareBox = new VBox(20);
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){

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public Parent createToolbar() {
public Parent createMenu() {
return UIFactory.createMenu("Account",
List.of(" • Portfolio", " • Transactions"),
() -> System.out.println("Portfolio clicked!"),
() -> SceneManager.switchTo(SceneFactory.createPortfolioView()),
() -> SceneManager.switchTo(SceneFactory.createTransactionView()));

}
Expand Down
35 changes: 35 additions & 0 deletions src/main/resources/themes/default.css
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,27 @@
-fx-cursor: hand;
}

.portfolio-vbox {
-fx-background-color: #A9A9A9;
}

.viewport-colour > .viewport {
-fx-background-color: #3B8C6E;
}

.rowBox {
-fx-background-color: #A9A9A9;
-fx-alignment: center;
}

.portfolio-stock-names {
-fx-font-size: 20px;
-fx-font-weight: 700;
-fx-text-fill: #EEEEEE;
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.3), 10, 0.5, 0, 5);
-fx-padding: 5;
}

.searchbar {
-fx-background-color: #FFFFFF;
-fx-background-radius: 20;
Expand All @@ -87,4 +108,18 @@
-fx-border-radius: 20;
-fx-cursor: hand;
}
.user-box-text{
-fx-font-size: 16px;
-fx-font-weight: 700;
-fx-text-fill: #EEEEEE;
-fx-padding: 10 10 10 10;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 10, 0.5, 0, 5);
}
.user-box-title{
-fx-font-size: 32px;
-fx-font-weight: 700;
-fx-text-fill: #EEEEEE;
-fx-padding: 10 10 0 10;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 10, 0.5, 0, 5);
}

Loading