Skip to content

Commit

Permalink
Merge pull request #109 from Team-40-IDATT2003/enhancement/107-stats-…
Browse files Browse the repository at this point in the history
…page

stats side
  • Loading branch information
tommyah authored May 19, 2026
2 parents 30a4bac + 5d450cf commit fa0ba77
Show file tree
Hide file tree
Showing 7 changed files with 1,152 additions and 265 deletions.
74 changes: 42 additions & 32 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.dashboard.DashBoardView;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.market.MarketController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.market.MarketView;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.stats.StatsController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.stats.StatsView;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.topbar.TopBarController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.topbar.TopBarView;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.transactions.TransactionsController;
import edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.transactions.TransactionsView;
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.text.Font;
Expand All @@ -38,10 +39,14 @@
/**
* Main class.
*
* <p>Extends {@link Application}</p>
* <p>
* Extends {@link Application}
* </p>
*
* <p>Initializes the application through the javafx framework.</p>
* */
* <p>
* Initializes the application through the javafx framework.
* </p>
*/
public class Main extends Application {

static void main(String[] args) {
Expand All @@ -50,12 +55,12 @@ static void main(String[] args) {

/**
* {@inheritDoc}
* */
*/
@Override
public void start(final Stage stage) throws Exception {
Scene scene = new Scene(new Pane());
scene.getStylesheets()
.add(Objects.requireNonNull(getClass().getResource("/styles.css")).toExternalForm());
.add(Objects.requireNonNull(getClass().getResource("/styles.css")).toExternalForm());
Font.loadFont(getClass().getResourceAsStream("/Fonts/Aptos.ttf"), 16);
stage.setScene(scene);
stage.setWidth(ConfigValues.VIEWPORT_WIDTH.getValue());
Expand Down Expand Up @@ -85,7 +90,6 @@ public void start(final Stage stage) throws Exception {
SaveGameService saveGameService = new SaveGameService();
playGameView.setSaves(saveGameService.loadSaves());


// Settings
SettingsView settingsView = new SettingsView();
new SettingsController(settingsView, eventManager);
Expand All @@ -102,40 +106,46 @@ public void start(final Stage stage) throws Exception {
TopBarView topBarView2 = new TopBarView();
new TopBarController(topBarView2, eventManager);

// Stats page (dashboard, default center-view in-game)
// Dashboard (default center-view in-game - første siden du ser)
DashBoardView dashBoardView = new DashBoardView();
new DashBoardController(dashBoardView,
eventManager,
player,
exchange,
stocksInFile);
eventManager,
player,
exchange,
stocksInFile);

// Stats page (Stats-knappen i topbaren tar deg hit)
StatsView statsView = new StatsView();
new StatsController(statsView, eventManager, player, exchange);

// Market page (vises i samme InGameView, byttes til via Market-knappen)
// Market page (Market-knappen tar deg hit)
MarketView marketView = new MarketView();
new MarketController(marketView,
eventManager,
player,
exchange,
stocksInFile);

TransactionsView transactionsView = new TransactionsView();
TransactionsController transactionsController = new TransactionsController(
transactionsView,
eventManager,
player.getTransactionArchive());
eventManager,
player,
exchange,
stocksInFile);

// In-game (Change "topBarView" to "topBarView2" if no summary section).
// Dashboard er default center-view.
InGameView inGameView = new InGameView(topBarView, dashBoardView.getRootPane());

// Wire top bar buttons til å bytte mellom dashboard og market.
// Transactions-widgeten finnes ikke enda - bruker dashboardet som
// placeholder slik at TRANSACTIONS-knappen ikke krasjer. Bytt ut når
// den faktiske transactions-widgeten er på plass.
Node transactionsCenter = dashBoardView.getRootPane();
Runnable onTransactionUpdate = () -> {
};

// Wire top bar buttons til å bytte mellom dashboard / stats / market /
// transactions. Stats-knappen tar deg til stats-siden.
topBarController.setMarketIntegration(
inGameView::changeCenterView,
dashBoardView.getRootPane(),
marketView.getRootPane(),
transactionsView.getRootPane(),
transactionsController::refresh
);
inGameView::changeCenterView,
dashBoardView.getRootPane(),
marketView.getRootPane(),
statsView.getRootPane(),
transactionsCenter,
onTransactionUpdate);

// Register all views
viewManager.addView(mainMenuView);
Expand All @@ -146,4 +156,4 @@ public void start(final Stage stage) throws Exception {

stage.show();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.stats;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
* Immutable data carrier for a single holding shown in {@link StatsView}.
*
* <p>Each instance represents an aggregated position in a single stock:
* the total number of shares owned, the weighted average purchase price,
* and the current market price. Derived values (value, cost, P&L) are
* computed on demand.</p>
* */
public final class HoldingData {

/** The stock ticker symbol. */
private final String ticker;

/** Total number of shares owned of this ticker. */
private final BigDecimal shares;

/** Weighted average purchase price per share. */
private final BigDecimal avgPrice;

/** Current market price per share. */
private final BigDecimal currentPrice;

/**
* Creates a new holding data row.
*
* @param ticker the stock ticker symbol.
* @param shares total number of shares owned.
* @param avgPrice weighted average purchase price per share.
* @param currentPrice current market price per share.
*
* @throws IllegalArgumentException if any argument is null.
* */
public HoldingData(final String ticker,
final BigDecimal shares,
final BigDecimal avgPrice,
final BigDecimal currentPrice) throws IllegalArgumentException {
if (ticker == null || shares == null || avgPrice == null || currentPrice == null) {
throw new IllegalArgumentException("Invalid holding data!");
}
this.ticker = ticker;
this.shares = shares;
this.avgPrice = avgPrice;
this.currentPrice = currentPrice;
}

/** @return the ticker symbol. */
public String getTicker() {
return ticker;
}

/** @return total shares owned. */
public BigDecimal getShares() {
return shares;
}

/** @return weighted average purchase price. */
public BigDecimal getAvgPrice() {
return avgPrice;
}

/** @return current market price. */
public BigDecimal getCurrentPrice() {
return currentPrice;
}

/** @return current market value of this position (shares * currentPrice). */
public BigDecimal getValue() {
return shares.multiply(currentPrice);
}

/** @return total cost paid for this position (shares * avgPrice). */
public BigDecimal getCost() {
return shares.multiply(avgPrice);
}

/** @return absolute profit and loss (value - cost). */
public BigDecimal getPnl() {
return getValue().subtract(getCost());
}

/** @return profit and loss as a percentage of cost. */
public double getPnlPct() {
BigDecimal cost = getCost();
if (cost.signum() == 0) {
return 0.0;
}
return getPnl().divide(cost, 6, RoundingMode.HALF_UP).doubleValue() * 100.0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package edu.ntnu.idi.idatt2003.g40.mappe.view.widgets.stats;

/**
* Enum representing all interactable actions in {@link StatsView}.
*
* <p>The stats widget is mostly an informational dashboard, so it currently
* has no top-level buttons of its own. {@code SELECT_HOLDING} is reserved
* for future use when individual holdings rows become clickable.</p>
* */
public enum StatsActions {
/** Reserved for future holding-row click handling. */
SELECT_HOLDING;
}
Loading

0 comments on commit fa0ba77

Please sign in to comment.