Skip to content

adds receipt functionality with a spinner #90

Merged
merged 1 commit into from
May 12, 2026
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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