Skip to content

Commit

Permalink
Merge pull request #90 from einaskoi/per/stockApp
Browse files Browse the repository at this point in the history
adds receipt functionality with a spinner
  • Loading branch information
einaskoi authored May 12, 2026
2 parents a23fd12 + 40ea68f commit a0cf2be
Show file tree
Hide file tree
Showing 33 changed files with 1,156 additions and 489 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package edu.ntnu.idi.idatt2003.gruppe42.Controller.AppControllers;

/**
* Interface for application controllers that respond to game ticks.
*/
public interface AppController {
/**
* Updates the app state on each simulation tick.
*/
void nextTick();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@

import edu.ntnu.idi.idatt2003.gruppe42.View.Apps.AppStoreApp;

/**
* Controller for the App Store.
*/
public class AppStoreController implements AppController {
public AppStoreController(AppStoreApp appStoreApp) {
/**
* Constructs a new AppStoreController.
*
* @param appStoreApp the app store view
*/
public AppStoreController(final AppStoreApp appStoreApp) {
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,21 @@
import edu.ntnu.idi.idatt2003.gruppe42.Model.Player;
import edu.ntnu.idi.idatt2003.gruppe42.View.Apps.BankApp;

public class BankAppController implements AppController{
private Player player;
private BankApp bankApp;
/**
* Controller for the {@link BankApp}.
* Handles updating the player's financial status and portfolio view.
*/
public final class BankAppController implements AppController {
private final Player player;
private final BankApp bankApp;

public BankAppController(BankApp bankApp, Player player) {
/**
* Constructs a new BankAppController.
*
* @param bankApp the bank app view
* @param player the player model
*/
public BankAppController(final BankApp bankApp, final Player player) {
this.player = player;
this.bankApp = bankApp;
}
Expand All @@ -18,10 +28,12 @@ public void nextTick() {
player.getNetWorth().doubleValue(),
player.getMoney().doubleValue(),
player.getPortfolio().getNetWorth().doubleValue(),
0 // TODO: calculate growth
0
);
System.out.println("[DEBUG] BankAppController.nextTick() - Updating Player Status");
System.out.println("[DEBUG] BankAppController.nextTick() - Updating Status");

bankApp.getPortfolioList().getItems().setAll(player.getPortfolio().getShares());
bankApp.getPortfolioList().getItems().setAll(
player.getPortfolio().getShares()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,107 +2,184 @@

import edu.ntnu.idi.idatt2003.gruppe42.Controller.MarketController;
import edu.ntnu.idi.idatt2003.gruppe42.Model.Player;
import edu.ntnu.idi.idatt2003.gruppe42.Model.Share;
import edu.ntnu.idi.idatt2003.gruppe42.Model.Stock;
import edu.ntnu.idi.idatt2003.gruppe42.Model.Transaction.Transaction;
import edu.ntnu.idi.idatt2003.gruppe42.View.Apps.StockApp;
import java.math.BigDecimal;
import javafx.application.Platform;

/**
* Controller for the {@link StockApp}.
* Handles user interactions for buying and selling stocks,
* and updates the UI in real-time.
*/
public final class StockAppController implements AppController {
private final MarketController marketController;
private final StockApp stockApp;
private final Player player;

public class StockAppController implements AppController {
private MarketController marketController;
private StockApp stockPopup;
private Stock currentStock;

public StockAppController(StockApp stockPopup, MarketController marketController, Player player) {
this.stockPopup = stockPopup;
/**
* Constructs a new StockAppController.
*
* @param stockApp the stock app view
* @param marketController the market controller
* @param player the player performing transactions
*/
public StockAppController(
final StockApp stockApp,
final MarketController marketController,
final Player player
) {
this.stockApp = stockApp;
this.marketController = marketController;
this.player = player;

stockApp.getStockList().getItems().addAll(
marketController.getExchange().getAllStocks()
);

stockApp.getSearchField().textProperty().addListener(
(obs, old, newValue) -> {
if (stockApp.getCurrentStock() != null) {
stockApp.openSearchPage();
}
stockApp.getStockList().getItems().setAll(
marketController.getMarket(newValue)
);
});

stockApp.getQuantitySpinner().valueProperty().addListener(
(obs, old, newValue) -> {
System.out.println("[DEBUG] Quantity changed: " + old + " -> " + newValue);
if (stockApp.getCurrentStock() != null) {
updateReceipt();
}
});

stockApp.getConfirmButton().setOnMouseClicked(event -> {
System.out.println("[DEBUG] Confirm button clicked");
handleTransaction();
});
}

/**
* Handles the buy or sell transaction based on the quantity spinner value.
*/
private void handleTransaction() {
Stock currentStock = stockApp.getCurrentStock();
if (currentStock == null) {
System.out.println("[DEBUG] Transaction failed: No stock selected");
return;
}

stockPopup.getStockList().getItems().addAll(marketController.getExchange().getAllStocks());

stockPopup.getSearchField().textProperty().addListener((
obs, old, newValue) -> {
if (stockPopup.getCurrentStock() != null) {
stockPopup.openSearchPage();
}
stockPopup.getStockList().getItems().setAll(marketController.getMarket(newValue));
});
int quantityValue = stockApp.getQuantitySpinner().getValue();
System.out.println("[DEBUG] Quantity spinner value: " + quantityValue);
if (quantityValue == 0) {
System.out.println("[DEBUG] Transaction skipped: Quantity is 0");
return;
}

stockPopup.getBuyButton().setOnMouseClicked(event -> {
currentStock = stockPopup.getCurrentStock();
if (currentStock == null) {
return;
}
BigDecimal quantity = new BigDecimal(Math.abs(quantityValue));

String quantityText = stockPopup.getQuantityField().getText();
BigDecimal quantity;
try {
quantity = new BigDecimal(quantityText);
if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
return;
}
} catch (NumberFormatException e) {
return;
}
if (quantityValue > 0) {
handleBuy(currentStock, quantity);
} else {
handleSell(currentStock, quantity);
}
}

/**
* Performs a buy transaction.
*
* @param stock the stock to buy
* @param quantity the amount to buy
*/
private void handleBuy(final Stock stock, final BigDecimal quantity) {
System.out.println("[DEBUG] Attempting to buy " + quantity + " of "
+ stock.getSymbol());
try {
Transaction transaction = marketController.getExchange().buy(
currentStock.getSymbol(), quantity, player
stock.getSymbol(), quantity, player
);

if (transaction == null) {
return;
if (transaction != null) {
transaction.commit(player);
player.getPortfolio().addShare(transaction.getShare());
System.out.println("[DEBUG] Buy successful");
} else {
System.out.println("[DEBUG] Buy failed: transaction is null");
}
} catch (Exception e) {
System.out.println("[DEBUG] Buy failed with exception: "
+ e.getMessage());
e.printStackTrace();
}
}

player.getTransactionArchive().add(transaction);
player.getPortfolio().addShare(transaction.getShare());
});

stockPopup.getSellButton().setOnMouseClicked(event -> {
currentStock = stockPopup.getCurrentStock();
if (currentStock == null) {
return;
}

String quantityText = stockPopup.getQuantityField().getText();
BigDecimal quantityToSell;
try {
quantityToSell = new BigDecimal(quantityText);
if (quantityToSell.compareTo(BigDecimal.ZERO) <= 0) {
return;
}
} catch (NumberFormatException e) {
return;
}

player.getPortfolio().getShares().stream()
.filter(s -> s.getStock().getSymbol().equals(currentStock.getSymbol()))
.findFirst()
.ifPresent(existingShare -> {
if (existingShare.getQuantity().compareTo(quantityToSell) < 0) {
return;
}

Transaction transaction = marketController.getExchange().sell(existingShare, quantityToSell, player);
player.getTransactionArchive().add(transaction);
/**
* Performs a sell transaction.
*
* @param stock the stock to sell
* @param quantity the amount to sell
*/
private void handleSell(final Stock stock, final BigDecimal quantity) {
System.out.println("[DEBUG] Attempting to sell " + quantity + " of "
+ stock.getSymbol());
player.getPortfolio().getShares().stream()
.filter(s -> s.getStock().getSymbol().equals(stock.getSymbol()))
.findFirst()
.ifPresentOrElse(existingShare -> {
if (existingShare.getQuantity().compareTo(quantity) < 0) {
System.out.println("[DEBUG] Sell failed: Not enough shares owned. "
+ "Have: " + existingShare.getQuantity() + ", Need: "
+ quantity);
return;
}

Transaction transaction = marketController.getExchange().sell(
existingShare, quantity, player
);
if (transaction != null) {
transaction.commit(player);
player.getPortfolio().removeShare(transaction.getShare());
});
});
System.out.println("[DEBUG] Sell successful");
} else {
System.out.println("[DEBUG] Sell failed: transaction is null");
}
}, () -> System.out.println("[DEBUG] Sell failed: No shares of "
+ stock.getSymbol() + " owned"));
}

/**
* Updates the receipt in the stock app.
*/
private void updateReceipt() {
Stock currentStock = stockApp.getCurrentStock();
if (currentStock != null) {
Platform.runLater(() ->
stockApp.getReceipt().update(
currentStock,
new BigDecimal(stockApp.getQuantitySpinner().getValue())
)
);
}
}

/**
* Updates the app state on each simulation tick.
* Refreshes the market data and updates the price label for the currently viewed stock.
* Refreshes the market data and updates UI components.
*/
@Override
public void nextTick() {
System.out.println("[DEBUG] StockAppController.nextTick() - Updating Market");
System.out.println("[DEBUG] StockAppController.nextTick() triggered");
marketController.updateMarket();
Stock currentStockInView = stockPopup.getCurrentStock();
Stock currentStockInView = stockApp.getCurrentStock();
if (currentStockInView != null) {
System.out.println("[DEBUG] Updating Price Label for: "
+ currentStockInView.getCompany());
stockPopup.updatePriceLabel(currentStockInView);
System.out.println("[DEBUG] Updating UI for stock: "
+ currentStockInView.getSymbol());
stockApp.updatePriceLabel(currentStockInView);
updateReceipt();
// Graph is updated within marketController.updateMarket() if visible
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,44 @@
import java.util.Timer;
import java.util.TimerTask;

public class GameController {

private Player player;
private List<AppController> appControllers = new ArrayList<>();
/**
* Controller for managing the game state and timing.
*/
public final class GameController {
/** The player model. */
private final Player player;
/** List of application controllers. */
private final List<AppController> appControllers = new ArrayList<>();
/** Timer for game ticks. */
private Timer timer;

public GameController(Player player) {
/**
* Constructs a new GameController.
*
* @param player the player model
*/
public GameController(final Player player) {
this.player = player;
}

public void addAppController(AppController appController) {
/**
* Adds an application controller to the list of controllers to be updated.
*
* @param appController the app controller to add
*/
public void addAppController(final AppController appController) {
appControllers.add(appController);
}

/**
* Starts the game simulation timer.
*/
public void startGame() {
timer = new Timer();

final int delay = 0;
final int period = 1000;

timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Expand All @@ -34,6 +55,6 @@ public void run() {
}
System.out.println("[DEBUG] Game Tick Finished");
}
}, 0, 1000);
}, delay, period);
}
}
Loading

0 comments on commit a0cf2be

Please sign in to comment.