Skip to content

Enhancements #63

Merged
merged 11 commits into from
May 24, 2026
10 changes: 5 additions & 5 deletions src/main/java/edu/ntnu/idi/idatt/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ public final class Launcher {
* Entry point of application.
*/
static void main() {
Application.launch(StockGame.class);
Application.launch(Millions.class);
}

public static final class StockGame extends Application {
public static final class Millions extends Application {

@Override
public void start(Stage stage) {
stage.setWidth(1200);
stage.setHeight(700);
stage.setTitle("Stock Game");
stage.setWidth(1440);
stage.setHeight(820);
stage.setTitle("Millions");

SceneManager.init(stage, SceneFactory.createStartView());
stage.show();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package edu.ntnu.idi.idatt.model;
package edu.ntnu.idi.idatt.model.market;

import java.util.ArrayList;
import java.util.List;
Expand Down
1 change: 0 additions & 1 deletion src/main/java/edu/ntnu/idi/idatt/model/market/Stock.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.util.List;
import java.util.Random;

import edu.ntnu.idi.idatt.model.Newspaper;
import edu.ntnu.idi.idatt.model.enums.NewspaperEnum;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public BigDecimal calculateTax() {
BigDecimal profit = calculateGross().subtract(purchasePrice.multiply(quantity))
.subtract(calculateCommision()); // (gross - tax - buy costs)

return profit.multiply(taxPercentage);
return profit.max(BigDecimal.ZERO).multiply(taxPercentage);

}

Expand Down
30 changes: 30 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt/storage/SessionManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,36 @@ public static boolean loadSession(String playerName) {
return false;
}

/**
* Method to remove current session
*/
public static void removeSession() {
// don't save if current session is null accidentally
if (UserSession.getInstance().getPlayer() == null || UserSession.getInstance().getExchange() == null) {
return;
}

// Load all sessions
List<SessionBundle> bundles = loadAllSessions();

try (Writer writer = new FileWriter(StorageFile.getStorageFile().toFile())) {

// Append current session
SessionBundle existing = bundles.stream()
.filter(s -> s.getPlayer().getName().equals(UserSession.getInstance().getPlayer().getName()))
.findFirst().orElse(null);

if (existing != null) {
bundles.remove(bundles.indexOf(existing));
}

gson.toJson(bundles, writer);

} catch (IOException e) {
throw new RuntimeException("Failed to remove current session!", e);
}
}

/**
* Method for serialization of all sessions.
*
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import edu.ntnu.idi.idatt.model.market.Stock;
import edu.ntnu.idi.idatt.session.UserSession;
import edu.ntnu.idi.idatt.storage.SessionManager;
import edu.ntnu.idi.idatt.view.entry.StartController;
import edu.ntnu.idi.idatt.view.entry.StartModel;
import edu.ntnu.idi.idatt.view.entry.StartView;
Expand All @@ -14,6 +15,9 @@
import edu.ntnu.idi.idatt.view.primary.exchange.ExchangeController;
import edu.ntnu.idi.idatt.view.primary.exchange.ExchangeModel;
import edu.ntnu.idi.idatt.view.primary.exchange.ExchangeView;
import edu.ntnu.idi.idatt.view.primary.finish.FinishController;
import edu.ntnu.idi.idatt.view.primary.finish.FinishModel;
import edu.ntnu.idi.idatt.view.primary.finish.FinishView;
import edu.ntnu.idi.idatt.view.primary.stock.StockController;
import edu.ntnu.idi.idatt.view.primary.stock.StockModel;
import edu.ntnu.idi.idatt.view.primary.stock.StockView;
Expand Down Expand Up @@ -148,4 +152,16 @@ public static Parent createNewspaperView(String symbol) {
return view.getInstance();
}

public static Parent createFinishView() {

FinishModel model = new FinishModel();
FinishView view = new FinishView();
FinishController controller = new FinishController(model);

view.setController(controller);

SessionManager.removeSession();
return view.getInstance();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ public void createUIComponents() {
navigation = new VBox();
navigation.setMaxHeight(Double.MAX_VALUE);
navigation.getStyleClass().add("dark");
navigation.setPrefWidth(150); // ScrollPane's affect this massively
navigation.setMaxWidth(150);
navigation.setMinWidth(150);
navigation.setPrefWidth(300); // ScrollPane's affect this massively
navigation.setMaxWidth(300);
navigation.setMinWidth(300);

header = new HBox();
header.getStyleClass().add("light");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package edu.ntnu.idi.idatt.view.components.elements;

import java.util.List;

import edu.ntnu.idi.idatt.model.transaction.Purchase;
import edu.ntnu.idi.idatt.model.transaction.Sale;
import edu.ntnu.idi.idatt.model.transaction.Transaction;
import edu.ntnu.idi.idatt.service.transaction.PurchaseCalculator;
import edu.ntnu.idi.idatt.service.transaction.SaleCalculator;
import edu.ntnu.idi.idatt.view.components.primitives.ActionEventHandler;
import edu.ntnu.idi.idatt.view.components.ui.UICompositor;
import edu.ntnu.idi.idatt.view.util.CssUtils;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;

public class RecieptComponent extends VBox {

private Button doneButton;

public RecieptComponent(Transaction transaction) {

Label title = new Label("Reciept");
CssUtils.apply(title, CssUtils.BIG_TEXT_32);

Label operation = new Label();
String operationString = "Transaction type: %s, week: %d";

Label shareName = new Label(String.format("Share: %s", transaction.getShare().getStock().toString()));
Label shareAmount = new Label(String.format("Amount: %.3f", transaction.getShare().getQuantity()));

Label gross = new Label();
String grossString = "Gross: %.2f $";

Label tax = new Label();
String taxString = "Taxes: %.2f $";

Label comission = new Label();
String comissionString = "Comission: %.2f $";

Label total = new Label();
String totalString = "Total: %.2f $";

Label profits = new Label();

List<Label> labels = List.of(shareName, operation, shareAmount,
gross, tax, comission, total, profits);

labels.forEach(l -> CssUtils.apply(l, CssUtils.MED_TEXT_16));

if (transaction instanceof Purchase) {
PurchaseCalculator calc = (PurchaseCalculator) transaction.getCalculator();
operation.setText(String.format(operationString, "Purchase", transaction.getWeek()));
gross.setText(String.format(grossString, calc.calculateGross()));
tax.setText(String.format(taxString, calc.calculateTax()));
comission.setText(String.format(comissionString, calc.calculateCommision()));
total.setText(String.format(totalString, calc.calculateTotal()));
} else if (transaction instanceof Sale) {
SaleCalculator calc = (SaleCalculator) transaction.getCalculator();
operation.setText(String.format(operationString, "Sale", transaction.getWeek()));
gross.setText(String.format(grossString, calc.calculateGross()));
tax.setText(String.format(taxString, calc.calculateTax()));
comission.setText(String.format(comissionString, calc.calculateCommision()));
total.setText(String.format(totalString, calc.calculateTotal()));
profits.setText(String.format("Profits: %.2f $", calc.calculateProfit()));
CssUtils.apply(profits, CssUtils.generateValueColors(calc.calculateProfit()));
}

doneButton = new Button("Alright!");
doneButton.getStyleClass().add("button");

UICompositor uiReciept = new UICompositor.Builder()
.parent(new VBox())
.growWithAlignment(Pos.CENTER)
.addAllContent(title,
operation,
new Label(" "), // Small filler
shareName,
shareAmount,
gross,
tax,
comission,
total,
profits,
doneButton)
.build();

this.getChildren().add(uiReciept.makeUI());
this.getStyleClass().add("dark");
this.setMaxSize(700, 500);
this.setPrefWidth(700);
StackPane.setAlignment(this, Pos.CENTER);

}

public void onExitButton(ActionEventHandler handler) {
doneButton.setOnMouseClicked((e) -> handler.handle());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public void initializeGame() {
model.isNewGame().set(true);
}

if (model.isFirstNewGame()) {
model.getError().set("No player with this name found. Create new player.");
model.setFirstNewGame(false);
return;
}

if (model.getBalance().get() == null) {
model.getError().set("Balance field can't be empty");
return;
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt/view/entry/StartModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ public class StartModel implements Model {
private final StringProperty fileName = new SimpleStringProperty();

private final BooleanProperty newGame = new SimpleBooleanProperty();
private boolean firstNewGame = false;
private final BooleanProperty predefinedCSV = new SimpleBooleanProperty(true);

public StartModel() {
newGame.addListener((obs) -> {
firstNewGame = true;
});
}

public StringProperty getName() {
return name;
}
Expand All @@ -36,6 +43,14 @@ public BooleanProperty isNewGame() {
return newGame;
}

public boolean isFirstNewGame() {
return firstNewGame;
}

public void setFirstNewGame(boolean val) {
firstNewGame = val;
}

public BooleanProperty isPredefinedCSV() {
return predefinedCSV;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package edu.ntnu.idi.idatt.view.primary.finish;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;

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.util.CssUtils;
import javafx.scene.Parent;

public class FinishController extends AbstractController<FinishModel> {

private UserSession session = UserSession.getInstance();

public FinishController(FinishModel model) {
super(model);
makeFinishedGameState();
}

public void makeFinishedGameState() {
// Sell all shares

// Copy shares (Avoid ConcurrentModificationException)
ArrayList<Share> holdings = new ArrayList<>(session.getPlayer().getPortfolio().getShares());

// Sell
holdings.forEach(share -> session.getExchange().sell(share, session.getPlayer()));

// Update gamestate
session.updateGameState();

}

public String getWeek() {
return String.format("Week: %d", session.getExchange().getWeek());
}

public String getTransactionAmount() {
return String.format("Transactions made: %d",
session.getPlayer().getTransactionArchive().getTransactions().size());
}

public String getPlayerStatus() {
return String.format("Player status: %s",
session.getPlayer().getStatus());
}

public String getPlayerName() {
return String.format("Player name: %s", session.getPlayer().getName());
}

public String getTotalNetWorth() {
return String.format("Total net worth: %.2f $",
session.getPlayer().getMoney());
}

private BigDecimal calculateProfits() {
BigDecimal profit = session.getPlayer().getMoney().subtract(
session.getPlayer().getStartingMoney());
return profit;
}

private BigDecimal calculateROI() {
BigDecimal profit = session.getPlayer().getMoney().subtract(
session.getPlayer().getStartingMoney());
BigDecimal profitPercent = profit.divide(session.getPlayer().getStartingMoney()).setScale(2, RoundingMode.HALF_UP);

BigDecimal returnOfInvestement = profitPercent.multiply(new BigDecimal("100"));

return returnOfInvestement;
}

public String getProfits() {
return String.format("Total profits: %.2f $",
calculateProfits());
}

public String getROI() {
return String.format("Return of investement: %.2f %%", calculateROI());
}

public void setProfitsColor(Parent profitsLabel) {
CssUtils.apply(profitsLabel, CssUtils.generateValueColors(calculateProfits()));
}

public void setRoiColor(Parent roiLabel) {
CssUtils.apply(roiLabel, CssUtils.generateValueColors(calculateROI()));
}

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

import edu.ntnu.idi.idatt.view.components.Model;

public class FinishModel implements Model {

}
Loading