From 792f2140b2df6553f64e06c02384d27ed5459ef0 Mon Sep 17 00:00:00 2001
From: pawelsa
Date: Sun, 24 May 2026 00:11:45 +0200
Subject: [PATCH 01/34] refactor(SaleCalculator): Remove negative taxes.
---
.../edu/ntnu/idi/idatt/service/transaction/SaleCalculator.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/service/transaction/SaleCalculator.java b/src/main/java/edu/ntnu/idi/idatt/service/transaction/SaleCalculator.java
index 47819d5..f9552fa 100644
--- a/src/main/java/edu/ntnu/idi/idatt/service/transaction/SaleCalculator.java
+++ b/src/main/java/edu/ntnu/idi/idatt/service/transaction/SaleCalculator.java
@@ -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);
}
From d147b8390497601ed7d07bf540d1bbd0cbe5b556 Mon Sep 17 00:00:00 2001
From: pawelsa
Date: Sun, 24 May 2026 00:14:20 +0200
Subject: [PATCH 02/34] refactor: Sizing and naming in Launcher
---
src/main/java/edu/ntnu/idi/idatt/Launcher.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/Launcher.java b/src/main/java/edu/ntnu/idi/idatt/Launcher.java
index 18c49a6..a7030b1 100644
--- a/src/main/java/edu/ntnu/idi/idatt/Launcher.java
+++ b/src/main/java/edu/ntnu/idi/idatt/Launcher.java
@@ -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();
From 68e9dd397c742e839a99e7818f1ef5fa00e5278d Mon Sep 17 00:00:00 2001
From: pawelsa
Date: Sun, 24 May 2026 00:14:39 +0200
Subject: [PATCH 03/34] refactor(AbstractViewUI): Size up navigation
---
.../edu/ntnu/idi/idatt/view/components/AbstractViewUI.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/AbstractViewUI.java b/src/main/java/edu/ntnu/idi/idatt/view/components/AbstractViewUI.java
index 8c1a119..1f45c17 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/components/AbstractViewUI.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/components/AbstractViewUI.java
@@ -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");
From 2d8e70c8ed1808c466422bcdf22bb0978d26368c Mon Sep 17 00:00:00 2001
From: pawelsa
Date: Sun, 24 May 2026 00:15:00 +0200
Subject: [PATCH 04/34] feat(RecipeComponent): Add a component for transaction
reciepts
---
.../components/elements/RecieptComponent.java | 104 ++++++++++++++++++
1 file changed, 104 insertions(+)
create mode 100644 src/main/java/edu/ntnu/idi/idatt/view/components/elements/RecieptComponent.java
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/RecieptComponent.java b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/RecieptComponent.java
new file mode 100644
index 0000000..fc156d1
--- /dev/null
+++ b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/RecieptComponent.java
@@ -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
*/
@Test
- void PTBuy() {
+ void buy_shouldFulfillTransaction() {
Transaction transaction = exchange.buy("AAPL", new BigDecimal("1"), player);
assertEquals(transaction, player.getTransactionArchive().getTransactions(1).getLast());
@@ -110,7 +106,7 @@ void PTBuy() {
*
*/
@Test
- void PTSell() {
+ void sell_shouldFulfillTransaction() {
// Player has to have a share to sell it.
exchange.buy("AAPL", new BigDecimal("1"), player);
exchange.getStock("AAPL").addNewSalesPrice(new BigDecimal("40")); // Simulate increase of AAPL stock price
@@ -123,15 +119,17 @@ void PTSell() {
}
@Test
- void PTAdvance() {
- // TODO: do
+ void advance_shouldIncrementWeek() {
+ int week = exchange.getWeek();
+ exchange.advance();
+ assertNotEquals(week, exchange.getWeek());
}
/**
* Test for obtaining the gainers and loosers.
*/
@Test
- void PTgetGainers_Losers() {
+ void getGainers_Loosers_shouldReturnStocks() {
// Simulate price change
stocks.get(0).addNewSalesPrice(new BigDecimal("4333"));
stocks.get(1).addNewSalesPrice(new BigDecimal("10"));
@@ -154,7 +152,7 @@ void PTgetGainers_Losers() {
*
*/
@Test
- void NTFindStock() {
+ void hasStock_NoMatchShouldThrowException() {
assertFalse(exchange.hasStock("Test"));
assertThrows(IllegalArgumentException.class, () -> exchange.getStock("thiswillnotwork"));
diff --git a/src/test/java/edu/ntnu/idi/idatt/model/enums/NewspaperEnumTest.java b/src/test/java/edu/ntnu/idi/idatt/model/enums/NewspaperEnumTest.java
new file mode 100644
index 0000000..874629d
--- /dev/null
+++ b/src/test/java/edu/ntnu/idi/idatt/model/enums/NewspaperEnumTest.java
@@ -0,0 +1,39 @@
+package edu.ntnu.idi.idatt.model.enums;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+public class NewspaperEnumTest {
+
+ @Test
+ void testGetTitle() {
+ NewspaperEnum event = NewspaperEnum.FRAUD;
+
+ assertEquals("Fraud investigation!", event.getTitle());
+ }
+
+ @Test
+ void testGetDescription() {
+ NewspaperEnum event = NewspaperEnum.FRAUD;
+
+ assertEquals(
+ "The company's CEO is under investigation for potential fraud!",
+ event.getDescription());
+ }
+
+ @Test
+ void testGetTrend() {
+ NewspaperEnum event = NewspaperEnum.FRAUD;
+
+ assertEquals(-0.05, event.getTrend());
+ }
+
+ @Test
+ void testGetVolatility() {
+ NewspaperEnum event = NewspaperEnum.FRAUD;
+
+ assertEquals(0.12, event.getVolatility());
+ }
+
+}
diff --git a/src/test/java/edu/ntnu/idi/idatt/model/market/NewspaperTest.java b/src/test/java/edu/ntnu/idi/idatt/model/market/NewspaperTest.java
new file mode 100644
index 0000000..1bdd5f1
--- /dev/null
+++ b/src/test/java/edu/ntnu/idi/idatt/model/market/NewspaperTest.java
@@ -0,0 +1,102 @@
+package edu.ntnu.idi.idatt.model.market;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import edu.ntnu.idi.idatt.model.enums.NewspaperEnum;
+
+public class NewspaperTest {
+
+ private Newspaper newspaper;
+
+ @BeforeEach
+ void setup() {
+ newspaper = new Newspaper();
+ }
+
+ @Test
+ void testNewsInitiallyContainsNoneEvent() {
+ List news = newspaper.getNews();
+
+ assertEquals(1, news.size());
+ assertEquals(NewspaperEnum.NONE_EVENT, news.getFirst());
+ }
+
+ @Test
+ void testMakeNewsAddsNewsEntry() {
+ int before = newspaper.getNews().size();
+
+ newspaper.makeNews();
+
+ int after = newspaper.getNews().size();
+
+ assertEquals(before + 1, after);
+ }
+
+ @Test
+ void testMakeNewsNeverReturnsNull() {
+ NewspaperEnum event = newspaper.makeNews();
+
+ assertNotNull(event);
+ }
+
+ @Test
+ void testHasNewNewsReturnsFalseWhenLastIsNoneEvent() {
+ newspaper.getNews().add(NewspaperEnum.NONE_EVENT);
+
+ assertFalse(newspaper.hasNewNews());
+ }
+
+ @Test
+ void testHasNewNewsReturnsTrueWhenLastIsRealEvent() {
+ newspaper.getNews().add(NewspaperEnum.DISASTER);
+
+ assertTrue(newspaper.hasNewNews());
+ }
+
+ @Test
+ void testGetNewsReturnsSameListReference() {
+ List news = newspaper.getNews();
+
+ assertNotNull(news);
+ assertEquals(newspaper.getNews(), news);
+ }
+
+ @Test
+ void testGetNewsStringsEmptyWhenOnlyNoneEvents() {
+ newspaper.getNews().clear();
+ newspaper.getNews().add(NewspaperEnum.NONE_EVENT);
+ newspaper.getNews().add(NewspaperEnum.NONE_EVENT);
+
+ List strings = newspaper.getNewsStrings();
+
+ assertTrue(strings.isEmpty());
+ }
+
+ @Test
+ void testGetNewsStringsFormatsCorrectly() {
+ newspaper.getNews().clear();
+
+ newspaper.getNews().add(NewspaperEnum.NONE_EVENT); // Week 1
+ newspaper.getNews().add(NewspaperEnum.DISASTER); // Week 2
+
+ List strings = newspaper.getNewsStrings();
+
+ assertEquals(1, strings.size());
+
+ String expected = String.format(
+ "Week: %d - %s [%s]",
+ 2,
+ NewspaperEnum.DISASTER.getTitle(),
+ NewspaperEnum.DISASTER.getDescription());
+
+ assertEquals(expected, strings.getFirst());
+ }
+}
diff --git a/src/test/java/edu/ntnu/idi/idatt/model/market/StockTest.java b/src/test/java/edu/ntnu/idi/idatt/model/market/StockTest.java
index 5b27600..0e8af44 100644
--- a/src/test/java/edu/ntnu/idi/idatt/model/market/StockTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt/model/market/StockTest.java
@@ -1,8 +1,11 @@
package edu.ntnu.idi.idatt.model.market;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.math.BigDecimal;
+import java.math.RoundingMode;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
@@ -14,7 +17,7 @@ public class StockTest {
private List prices;
@BeforeEach
- public void PT_setup() {
+ public void setup() {
prices = List.of(new BigDecimal("46.2"),
new BigDecimal("40.0"),
new BigDecimal("39.5"),
@@ -25,14 +28,14 @@ public void PT_setup() {
}
@Test
- void constructorTest() {
+ void constructor_shouldCreateStock() {
assertEquals("AAPL", stock.getSymbol());
assertEquals("Apple Inc.", stock.getCompany());
assertEquals(new BigDecimal("43.4"), stock.getSalesPrice());
}
@Test
- void PTgetPrices() {
+ void getHistoricalPrices_shouldReturnStockPrices() {
assertEquals(prices, stock.getHistoricalPrices());
assertEquals(new BigDecimal("39.5"), stock.getLowestPrice());
assertEquals(new BigDecimal("51.2"), stock.getHighestPrice());
@@ -40,7 +43,7 @@ void PTgetPrices() {
}
@Test
- void NTgetLatestPriceChange() {
+ void latestPriceChange_shouldBeNull() {
Stock noPrice = new Stock("NVDA", "Nvidia", List.of());
Stock onePrice = new Stock("TSLA", "Tesla Inc.", List.of(
BigDecimal.TEN));
@@ -50,11 +53,70 @@ void NTgetLatestPriceChange() {
}
@Test
- void addNewSalesPriceTest() {
+ void addNewSalesPrice_shouldAddNewPrice() {
BigDecimal value = new BigDecimal("15.6");
stock.addNewSalesPrice(value);
assertEquals(value, stock.getSalesPrice());
}
+ @Test
+ void getNewspaper() {
+
+ assertNotNull(stock.getNewspaper());
+ }
+
+ @Test
+ void advancePrice() {
+
+ BigDecimal previousPrice = stock.getSalesPrice();
+
+ stock.advancePrice();
+
+ BigDecimal newPrice = stock.getSalesPrice();
+
+ assertNotEquals(previousPrice, newPrice);
+ assertEquals(2, newPrice.scale());
+ }
+
+ @Test
+ void advancePrice_AddsNewPriceToHistory() {
+
+ int previousSize = stock.getHistoricalPrices().size();
+
+ stock.advancePrice();
+
+ assertEquals(previousSize + 1, stock.getHistoricalPrices().size());
+ }
+
+ @Test
+ void getLatestPriceChangePercent() {
+
+ BigDecimal expected = stock.getLatestPriceChange().multiply(new BigDecimal("100"))
+ .divide(new BigDecimal("51.2"), 2, RoundingMode.HALF_UP);
+
+ assertEquals(expected, stock.getLatestPriceChangePercent());
+ }
+
+ @Test
+ void getLatestPriceChangePercentNoPrices() {
+
+ Stock emptyStock = new Stock(
+ "MSFT",
+ "Microsoft",
+ List.of());
+
+ assertEquals(
+ BigDecimal.ZERO,
+ emptyStock.getLatestPriceChangePercent());
+ }
+
+ @Test
+ void stockToString() {
+
+ assertEquals(
+ "Apple Inc. (AAPL)",
+ stock.toString());
+ }
+
}
diff --git a/src/test/java/edu/ntnu/idi/idatt/model/player/PlayerTest.java b/src/test/java/edu/ntnu/idi/idatt/model/player/PlayerTest.java
index 16bbb95..c858ce9 100644
--- a/src/test/java/edu/ntnu/idi/idatt/model/player/PlayerTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt/model/player/PlayerTest.java
@@ -18,14 +18,14 @@ class PlayerTest {
private Player player;
@BeforeEach
- public void PT_setup() {
+ public void setup() {
player = new Player("TestPlayer", new BigDecimal("500"));
}
@Test
- void PTConstructor() {
+ void constructor_shouldCreatePlayer() {
assertEquals("TestPlayer", player.getName());
assertEquals(new BigDecimal("500"), player.getMoney());
assertNotNull(player.getPortfolio());
@@ -33,7 +33,7 @@ void PTConstructor() {
}
@Test
- void PTaddMoney() {
+ void addMoney_shouldAddMoney() {
player.addMoney(new BigDecimal("200"));
assertEquals(new BigDecimal("700"), player.getMoney());
@@ -41,13 +41,18 @@ void PTaddMoney() {
}
@Test
- void PTwithdrawMoney() {
+ void getStartingMoney() {
+ assertEquals(new BigDecimal("500"), player.getStartingMoney());
+ }
+
+ @Test
+ void withdrawMoney_shouldSubtractMoney() {
player.withdrawMoney(new BigDecimal("200"));
assertEquals(new BigDecimal("300"), player.getMoney());
}
@Test
- void PTgetNetWorth() {
+ void getNetWorth_shouldReturnTotalNetWorth() {
assertEquals(player.getNetWorth(), new BigDecimal("500"));
// Add to player portfolio
@@ -61,7 +66,7 @@ void PTgetNetWorth() {
}
@Test
- void PTgetStatus() {
+ void getStatus_shouldBeAllStatuses() {
assertEquals("Novice", player.getStatus());
// Simulate progress
diff --git a/src/test/java/edu/ntnu/idi/idatt/model/portfolio/PortfolioTest.java b/src/test/java/edu/ntnu/idi/idatt/model/portfolio/PortfolioTest.java
index 743963f..857cf1d 100644
--- a/src/test/java/edu/ntnu/idi/idatt/model/portfolio/PortfolioTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt/model/portfolio/PortfolioTest.java
@@ -6,6 +6,7 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.math.BigDecimal;
+import java.math.RoundingMode;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
@@ -21,7 +22,7 @@ public class PortfolioTest {
private Portfolio portfolio;
@BeforeEach
- public void PT_setup() {
+ public void setup() {
// stock instance and parameters
List prices = List.of(new BigDecimal("46.2"),
new BigDecimal("40.0"));
@@ -36,20 +37,30 @@ public void PT_setup() {
}
@Test
- void PTaddShare() {
+ void addShare_shouldAddToPortfolio() {
assertTrue(portfolio.addShare(share));
assertEquals(List.of(share), portfolio.getShares());
}
- void addDefaultShare() { // Since PTaddShare test works, we will use this to initialize
+ @Test
+ void getShares() {
+
+ addDefaultShare();
+
+ assertEquals(
+ List.of(share),
+ portfolio.getShares());
+ }
+
+ void addDefaultShare() { // Since test over works, we will use this to initialize
// the rest of the tests under.
portfolio.addShare(share);
}
@Test
- void PTgetSharesBySymbol() {
+ void getSharesBySymbol_shouldReturnShares() {
addDefaultShare();
assertEquals(List.of(), portfolio.getShares("SYMBL"));
@@ -58,7 +69,7 @@ void PTgetSharesBySymbol() {
}
@Test
- void PTremoveShare() {
+ void removeShareBySymbol_shouldRemoveShare() {
addDefaultShare();
assertTrue(portfolio.removeShare(share));
@@ -67,7 +78,7 @@ void PTremoveShare() {
}
@Test
- void PTContains() {
+ void testContainsShare() {
assertFalse(portfolio.contains(share));
portfolio.addShare(share);
@@ -76,16 +87,23 @@ void PTContains() {
}
@Test
- void NTremoveShare() {
+ void removeShareBySymbol_shouldThrowException() {
Share exception = new Share(stock, new BigDecimal("2.3"), stock.getSalesPrice());
assertThrows(IllegalArgumentException.class, () -> portfolio.removeShare(exception));
}
- /**
- * Positive test for finding net value of the players shares.
- */
@Test
- void PTgetNetWorth() {
+ void removeShares_shouldClearPortfolio() {
+
+ addDefaultShare();
+
+ portfolio.removeShares();
+
+ assertTrue(portfolio.getShares().isEmpty());
+ }
+
+ @Test
+ void getNetWorth_shouldReturnNetWorth() {
Share share1 = new Share(stock, new BigDecimal("1"), new BigDecimal("135.8"));
Share share2 = new Share(stock, new BigDecimal("2"), new BigDecimal("254"));
portfolio.addShare(share1);
@@ -94,4 +112,116 @@ void PTgetNetWorth() {
portfolio.getNetWorth());
}
+ @Test
+ void getNetWorthEmptyPortfolio() {
+
+ assertEquals(
+ BigDecimal.ZERO,
+ portfolio.getNetWorth());
+ }
+
+ @Test
+ void getOwnedAmountBySymbol() {
+
+ addDefaultShare();
+
+ assertEquals(
+ new BigDecimal("3.3"),
+ portfolio.getOwnedAmount("AAPL"));
+ }
+
+ @Test
+ void getOwnedAmountBySymbolNoMatch() {
+
+ assertEquals(
+ BigDecimal.ZERO,
+ portfolio.getOwnedAmount("MSFT"));
+ }
+
+ @Test
+ void getOwnedAmount() {
+
+ addDefaultShare();
+
+ assertEquals(
+ new BigDecimal("3.3"),
+ portfolio.getOwnedAmount());
+ }
+
+ @Test
+ void getProfitFromStock() {
+
+ addDefaultShare();
+
+ BigDecimal expected = share.getProfit();
+
+ assertEquals(
+ expected,
+ portfolio.getProfitFromStock("AAPL"));
+ }
+
+ @Test
+ void getProfitFromStockNoMatch() {
+
+ assertEquals(
+ BigDecimal.ZERO,
+ portfolio.getProfitFromStock("MSFT"));
+ }
+
+ @Test
+ void getProfitFromPortfolio() {
+
+ addDefaultShare();
+
+ BigDecimal expected = share.getProfit();
+
+ assertEquals(
+ expected,
+ portfolio.getProfitFromStock());
+ }
+
+ @Test
+ void getChangeFromStock_shouldReturnCorrectPercentageChange() {
+
+ addDefaultShare();
+
+ BigDecimal profit = portfolio.getProfitFromStock("AAPL");
+
+ BigDecimal totalCost = share.getTotalPurchasePrice();
+
+ BigDecimal expected = profit
+ .divide(totalCost, 2, java.math.RoundingMode.HALF_UP)
+ .multiply(BigDecimal.valueOf(100));
+
+ assertEquals(
+ expected,
+ portfolio.getChangeFromStock("AAPL"));
+ }
+
+ @Test
+ void getChangeFromStock_shouldReturnZeroWhenNoSharesExist() {
+
+ assertEquals(
+ BigDecimal.ZERO,
+ portfolio.getChangeFromStock("MSFT"));
+ }
+
+ @Test
+ void getChangeFromStock_shouldReturnTotalFromPortfolioChange() {
+
+ addDefaultShare();
+
+ BigDecimal profit = portfolio.getProfitFromStock();
+
+ BigDecimal totalCost = share.getTotalPurchasePrice();
+
+ BigDecimal expected = profit
+ .divide(totalCost, 2, RoundingMode.HALF_UP)
+ .multiply(BigDecimal.valueOf(100));
+
+ assertEquals(
+ expected,
+ portfolio.getChangeFromStock());
+ }
+
}
diff --git a/src/test/java/edu/ntnu/idi/idatt/model/portfolio/ShareTest.java b/src/test/java/edu/ntnu/idi/idatt/model/portfolio/ShareTest.java
index cefea8b..b0d261a 100644
--- a/src/test/java/edu/ntnu/idi/idatt/model/portfolio/ShareTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt/model/portfolio/ShareTest.java
@@ -16,7 +16,7 @@ public class ShareTest {
private Stock stock;
@BeforeEach
- public void PT_setup() {
+ public void setup() {
List prices = List.of(new BigDecimal("46.2"),
new BigDecimal("40.0"));
stock = new Stock("AAPL", "Apple Inc.", prices);
@@ -36,4 +36,104 @@ void constructorTest() {
}
+ @Test
+ void testGetTotalPurchasePrice() {
+ BigDecimal expected = new BigDecimal("132.00");
+
+ assertEquals(0,
+ expected.compareTo(share.getTotalPurchasePrice()));
+ }
+
+ @Test
+ void testGetProfit() {
+
+ /*
+ * Current stock price = 40.0
+ * Purchase price = 40.0
+ * Quantity = 3.3
+ *
+ * Gross = 132.0
+ * Purchase total = 132.0
+ * Profit = 0
+ */
+
+ BigDecimal expected = BigDecimal.ZERO;
+
+ assertEquals(0,
+ expected.compareTo(share.getProfit()));
+ }
+
+ @Test
+ void testGetProfitPercent() {
+
+ /*
+ * Profit is 0, therefore percentage should also be 0
+ */
+
+ BigDecimal expected = BigDecimal.ZERO;
+
+ assertEquals(0,
+ expected.compareTo(share.getProfitPercent()));
+ }
+
+ @Test
+ void testGetProfitPositive() {
+
+ /*
+ * Simulate stock price increase
+ * Latest price becomes 50.0
+ */
+
+ Stock increasedStock = new Stock(
+ "AAPL",
+ "Apple Inc.",
+ List.of(
+ new BigDecimal("40.0"),
+ new BigDecimal("50.0")));
+
+ Share profitableShare = new Share(
+ increasedStock,
+ new BigDecimal("2"),
+ new BigDecimal("40.0"));
+
+ /*
+ * Gross = 50 * 2 = 100
+ * Purchase total = 40 * 2 = 80
+ * Profit = 20
+ */
+
+ BigDecimal expected = new BigDecimal("20.0");
+
+ assertEquals(0,
+ expected.compareTo(profitableShare.getProfit()));
+ }
+
+ @Test
+ void testGetProfitPercentPositive() {
+
+ Stock increasedStock = new Stock(
+ "AAPL",
+ "Apple Inc.",
+ List.of(
+ new BigDecimal("40.0"),
+ new BigDecimal("50.0")));
+
+ Share profitableShare = new Share(
+ increasedStock,
+ new BigDecimal("2"),
+ new BigDecimal("40.0"));
+
+ /*
+ * Profit = 20
+ * Purchase total = 80
+ *
+ * 20 / 80 * 100 = 25.00
+ */
+
+ BigDecimal expected = new BigDecimal("25.00");
+
+ assertEquals(0,
+ expected.compareTo(profitableShare.getProfitPercent()));
+ }
+
}
diff --git a/src/test/java/edu/ntnu/idi/idatt/model/transaction/PurchaseTest.java b/src/test/java/edu/ntnu/idi/idatt/model/transaction/PurchaseTest.java
index caf44c1..eab98aa 100644
--- a/src/test/java/edu/ntnu/idi/idatt/model/transaction/PurchaseTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt/model/transaction/PurchaseTest.java
@@ -37,7 +37,7 @@ class PurchaseTest {
private Purchase purchase;
@BeforeEach
- public void PT_setup() {
+ public void setup() {
// stock instance and parameters
List prices = List.of(new BigDecimal("46.2"),
new BigDecimal("40.0"));
diff --git a/src/test/java/edu/ntnu/idi/idatt/model/transaction/SaleTest.java b/src/test/java/edu/ntnu/idi/idatt/model/transaction/SaleTest.java
index 1bd944e..ac360aa 100644
--- a/src/test/java/edu/ntnu/idi/idatt/model/transaction/SaleTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt/model/transaction/SaleTest.java
@@ -39,7 +39,7 @@ class SaleTest {
private Sale sale;
@BeforeEach
- public void PT_setup() {
+ public void setup() {
// stock instance and parameters
List prices = List.of(new BigDecimal("46.2"),
new BigDecimal("40.0"));
@@ -65,7 +65,7 @@ public void PT_setup() {
* it will singlehandedly validate the methods of this class.
*/
@Test
- void PTconstructorTest() {
+ void constructorTest() {
assertEquals(share, sale.getShare());
assertEquals(1, sale.getWeek());
diff --git a/src/test/java/edu/ntnu/idi/idatt/model/transaction/TransactionArchiveTest.java b/src/test/java/edu/ntnu/idi/idatt/model/transaction/TransactionArchiveTest.java
index 32739ae..6550d87 100644
--- a/src/test/java/edu/ntnu/idi/idatt/model/transaction/TransactionArchiveTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt/model/transaction/TransactionArchiveTest.java
@@ -19,7 +19,7 @@ class TransactionArchiveTest {
TransactionArchive transactionArchive;
@BeforeEach
- public void getDefaultValues() {
+ public void setup() {
Stock AAPL = new Stock("AAPL", "Apple Inc.", List.of(new BigDecimal("32")));
Stock NVDA = new Stock("NVDA", "NVIDIA", List.of(new BigDecimal("182.81")));
@@ -44,7 +44,7 @@ public void getDefaultValues() {
}
@Test
- void PTaddTransactions() {
+ void addTransaction_shouldAddToArchive() {
TransactionArchive archive = new TransactionArchive();
assertTrue(archive.add(transactions.get(0)));
@@ -55,7 +55,7 @@ void PTaddTransactions() {
}
@Test
- void PTisEmpty() {
+ void isEmpty_shouldBeTrue() {
TransactionArchive archive = new TransactionArchive();
@@ -76,7 +76,7 @@ void PTisEmpty() {
*/
@Test
- void PTgetTransactions() {
+ void getTransactionsProper() {
assertEquals(2, transactionArchive.getTransactions(1).size()); // First week all transactions
assertEquals(2, transactionArchive.getTransactions(2).size());
@@ -87,16 +87,31 @@ void PTgetTransactions() {
}
+ @Test
+ void getTransactions_shouldReturnArray() {
+ assertEquals(transactions, transactionArchive.getTransactions());
+ }
+
+ @Test
+ void getPurchases_allPurchases() {
+ assertEquals(List.of(transactions.get(0), transactions.get(1)), transactionArchive.getPurchases());
+ }
+
+ @Test
+ void getSales_allSales() {
+ assertEquals(List.of(transactions.get(2), transactions.get(3)), transactionArchive.getSales());
+ }
+
/**
* Tests for countDistinctWeeks().
*/
@Test
- void PTcountDistinctWeeks() {
+ void countDistinctWeeks() {
assertEquals(2, transactionArchive.countDistinctWeeks());
}
@Test
- void NTcountDistinctWeeks() {
+ void countDistinctWeeks_shouldBeZero() {
TransactionArchive tArchive = new TransactionArchive();
assertEquals(0, tArchive.countDistinctWeeks());
}
diff --git a/src/test/java/edu/ntnu/idi/idatt/service/transaction/PurchaseCalculatorTest.java b/src/test/java/edu/ntnu/idi/idatt/service/transaction/PurchaseCalculatorTest.java
index 7870ea4..69f2537 100644
--- a/src/test/java/edu/ntnu/idi/idatt/service/transaction/PurchaseCalculatorTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt/service/transaction/PurchaseCalculatorTest.java
@@ -18,7 +18,7 @@ class PurchaseCalculatorTest {
private PurchaseCalculator purchaseCalculator;
@BeforeEach
- public void PT_setup() {
+ public void setup() {
// stock instance and parameters
List prices = List.of(new BigDecimal("46.2"),
new BigDecimal("40.0"));
@@ -39,7 +39,7 @@ public void PT_setup() {
* it will singlehandedly validate the methods of this class.
*/
@Test
- void PT_calculationTotal() {
+ void calculationTotalTest() {
BigDecimal expected = new BigDecimal("40.0")
.multiply(new BigDecimal("3.3"))
diff --git a/src/test/java/edu/ntnu/idi/idatt/service/transaction/SaleCalculatorTest.java b/src/test/java/edu/ntnu/idi/idatt/service/transaction/SaleCalculatorTest.java
index eacc8e2..e940b03 100644
--- a/src/test/java/edu/ntnu/idi/idatt/service/transaction/SaleCalculatorTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt/service/transaction/SaleCalculatorTest.java
@@ -18,7 +18,7 @@ class SaleCalculatorTest {
private SaleCalculator saleCalculator;
@BeforeEach
- public void PT_setup() {
+ public void setup() {
// stock instance and parameters
List prices = List.of(new BigDecimal("46.2"),
new BigDecimal("40.0"));
@@ -41,7 +41,7 @@ public void PT_setup() {
* @see SaleCalculator
*/
@Test
- void PT_calculationTotal() {
+ void calculateAllTest() {
// For imitation, let's add a new weeks stock price.
stock.addNewSalesPrice(new BigDecimal("47.8"));
@@ -69,9 +69,11 @@ void PT_calculationTotal() {
.multiply(share.getQuantity()))
.multiply(new BigDecimal("0.3"));
- BigDecimal expected = gross.subtract(commision).subtract(tax);
- assertEquals(expected, saleCalculator.calculateTotal());
+ BigDecimal total = gross.subtract(commision).subtract(tax);
+ assertEquals(total, saleCalculator.calculateTotal());
+ BigDecimal profit = gross.subtract(share.getTotalPurchasePrice());
+ assertEquals(profit, saleCalculator.calculateProfit());
}
}
From ca21db440009de6cad0aa704abf4910525a04d26 Mon Sep 17 00:00:00 2001
From: PawelSapula
Date: Mon, 25 May 2026 15:47:10 +0200
Subject: [PATCH 16/34] chore: Delete tests which are user interaction
centered.
---
.../idi/idatt/storage/StockParserTest.java | 68 -------------------
src/test/resources/stocks.csv | 7 --
2 files changed, 75 deletions(-)
delete mode 100644 src/test/java/edu/ntnu/idi/idatt/storage/StockParserTest.java
delete mode 100644 src/test/resources/stocks.csv
diff --git a/src/test/java/edu/ntnu/idi/idatt/storage/StockParserTest.java b/src/test/java/edu/ntnu/idi/idatt/storage/StockParserTest.java
deleted file mode 100644
index 570a2fa..0000000
--- a/src/test/java/edu/ntnu/idi/idatt/storage/StockParserTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package edu.ntnu.idi.idatt.storage;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.util.List;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import edu.ntnu.idi.idatt.model.market.Stock;
-
-/**
- * Test class for ExchangeLoader
- *
- *
- * Tests the loading and saving of stock data.
- *
- */
-class StockParserTest {
-
- String file;
-
- @BeforeEach
- public void PT_setup() throws IOException {
-
- InputStream is = getClass()
- .getClassLoader()
- .getResourceAsStream("stocks.csv");
-
- Path tempFile = Files.createTempFile("stocks", ".csv");
- Files.copy(is, tempFile, StandardCopyOption.REPLACE_EXISTING);
-
- file = tempFile.toFile().toPath().toString();
-
- }
-
- /**
- * Positive test for loading/reading stocks
- */
- @Test
- void PT_load() {
- List stocks = null;
- try {
- stocks = StockParser.loadFromFile(file);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- assertEquals(4, stocks.size());
-
- }
-
- /**
- * Negative tests reading stocks.
- */
- @Test
- void NT_IllegalArgumentException_Constructor() {
- assertThrows(IOException.class,
- () -> StockParser.loadFromFile("resources/notexistantfile.csv"));
- }
-
-}
diff --git a/src/test/resources/stocks.csv b/src/test/resources/stocks.csv
deleted file mode 100644
index 275ddb0..0000000
--- a/src/test/resources/stocks.csv
+++ /dev/null
@@ -1,7 +0,0 @@
-# Ticker,Name,Price
-AAPL,Apple Inc,32
-NVDA,NVIDIA,182.81
-TSLA,Tesla,417.44
-AMD,Advanced Micro Devices,207.32
-
-
From 50a713186d87fa6338e464da5834c5e58a461b68 Mon Sep 17 00:00:00 2001
From: PawelSapula
Date: Mon, 25 May 2026 15:47:20 +0200
Subject: [PATCH 17/34] chore: Delete test resources.
---
src/main/resources/stocks.csv | 509 +++++++++++++++++++++++++++++++++-
1 file changed, 504 insertions(+), 5 deletions(-)
diff --git a/src/main/resources/stocks.csv b/src/main/resources/stocks.csv
index f9b7ff5..d9cec61 100644
--- a/src/main/resources/stocks.csv
+++ b/src/main/resources/stocks.csv
@@ -1,7 +1,506 @@
+# S&P 500 Companies by Market Cap
# Ticker,Name,Price
-AMD,Advanced Micro Devices,202.68
-MSI,Micro-Star International,92.80
-INTC,Intel,45.58
-NVDA,Nvidia,182.65
-EQNR,Equinor,32.43
+NVDA,Nvidia,191.27
+AAPL,Apple Inc.,276.43
+MSFT,Microsoft,404.68
+AMZN,Amazon,204.62
+GOOGL,Alphabet Inc. (Class A),311.20
+GOOG,Alphabet Inc. (Class C),311.62
+META,Meta Platforms,669.41
+AVGO,Broadcom,343.35
+TSLA,Tesla Inc.,426.52
+BRK.B,Berkshire Hathaway,501.05
+WMT,Walmart,128.75
+LLY,Lilly (Eli),1014.43
+JPM,JPMorgan Chase,311.14
+XOM,ExxonMobil,155.28
+V,Visa Inc.,329.54
+JNJ,Johnson & Johnson,240.70
+MA,Mastercard,539.52
+MU,Micron Technology,411.25
+ORCL,Oracle Corporation,157.08
+COST,Costco,979.71
+BAC,Bank of America,54.06
+ABBV,AbbVie,220.17
+HD,Home Depot (The),389.46
+PG,Procter & Gamble,159.45
+CVX,Chevron Corporation,185.66
+CAT,Caterpillar Inc.,773.53
+AMD,Advanced Micro Devices,213.00
+CSCO,Cisco,85.82
+KO,Coca-Cola Company (The),78.51
+NFLX,Netflix,79.94
+GE,GE Aerospace,314.37
+PLTR,Palantir Technologies,135.59
+LRCX,Lam Research,236.60
+MRK,Merck & Co.,118.79
+PM,Philip Morris International,185.99
+GS,Goldman Sachs,949.29
+MS,Morgan Stanley,176.86
+WFC,Wells Fargo,89.07
+AMAT,Applied Materials,342.19
+RTX,RTX Corporation,197.56
+IBM,IBM,273.86
+UNH,UnitedHealth Group,278.79
+AXP,American Express,355.18
+INTC,Intel,47.85
+TMUS,T-Mobile US,207.62
+PEP,PepsiCo,168.71
+MCD,McDonald's,323.50
+GEV,GE Vernova,822.50
+LIN,Linde plc,466.04
+C,Citigroup,117.93
+TXN,Texas Instruments,226.34
+VZ,Verizon,48.55
+T,AT&T,28.21
+TMO,Thermo Fisher Scientific,525.00
+AMGN,Amgen,364.77
+ABT,Abbott Laboratories,112.97
+KLAC,KLA Corporation,1492.27
+GILD,Gilead Sciences,155.71
+DIS,Walt Disney Company (The),108.30
+NEE,NextEra Energy,91.19
+BA,Boeing,236.98
+ANET,Arista Networks,141.06
+APH,Amphenol,144.60
+ISRG,Intuitive Surgical,496.14
+CRM,Salesforce,184.94
+SCHW,Charles Schwab Corporation,95.50
+BLK,BlackRock,1083.35
+TJX,TJX Companies,150.56
+DE,Deere & Company,610.03
+ADI,Analog Devices,336.71
+LOW,Lowe's,286.57
+PFE,Pfizer,27.77
+UNP,Union Pacific Corporation,261.95
+DHR,Danaher Corporation,219.80
+APP,AppLovin Corporation,459.27
+HON,Honeywell,243.56
+ETN,Eaton Corporation,394.94
+QCOM,Qualcomm,141.90
+UBER,Uber,70.72
+LMT,Lockheed Martin,630.54
+WELL,Welltower,208.65
+ACN,Accenture,230.79
+BKNG,Booking Holdings,4322.85
+SYK,Stryker Corporation,362.53
+COP,ConocoPhillips,110.75
+NEM,Newmont,123.89
+COF,Capital One,214.93
+PLD,Prologis,140.35
+MDT,Medtronic,100.87
+CB,Chubb Limited,328.82
+PH,Parker Hannifin,998.24
+PGR,Progressive Corporation,209.33
+BMY,Bristol Myers Squibb,60.18
+HCA,HCA Healthcare,531.83
+SPGI,S&P Global,396.65
+CMCSA,Comcast,32.53
+VRTX,Vertex Pharmaceuticals,459.93
+MCK,McKesson Corporation,944.20
+PANW,Palo Alto Networks,165.49
+GLW,Corning Inc.,134.16
+SBUX,Starbucks,99.03
+INTU,Intuit,401.05
+MO,Altria,65.72
+BSX,Boston Scientific,73.76
+CME,CME Group,303.44
+NOW,ServiceNow,101.55
+ADBE,Adobe Inc.,258.39
+TT,Trane Technologies,473.75
+CRWD,CrowdStrike,414.94
+BX,Blackstone Inc.,133.29
+UPS,United Parcel Service,119.93
+SO,Southern Company,90.86
+CEG,Constellation Energy,274.37
+DUK,Duke Energy,124.86
+CVS,CVS Health,76.36
+MAR,Marriott International,360.71
+NOC,Northrop Grumman,680.45
+PNC,PNC Financial Services,237.28
+WM,Waste Management,234.67
+GD,General Dynamics,348.79
+WDC,Western Digital,277.26
+KKR,KKR,105.28
+HWM,Howmet Aerospace,233.13
+FCX,Freeport-McMoRan,65.30
+NKE,Nike Inc.,62.43
+USB,U.S. Bancorp,59.25
+MMM,3M,173.46
+SHW,Sherwin-Williams,364.16
+RCL,Royal Caribbean Group,331.76
+SNDK,Sandisk Corporation,607.86
+STX,Seagate Technology,409.41
+EMR,Emerson Electric,156.30
+ADP,Automatic Data Processing,217.59
+WMB,Williams Companies,71.48
+ICE,Intercontinental Exchange,153.60
+FDX,FedEx,368.49
+ITW,Illinois Tool Works,298.50
+JCI,Johnson Controls,140.75
+CRH,CRH plc,127.89
+ECL,Ecolab,301.35
+EQIX,Equinix,863.66
+BK,BNY Mellon,122.83
+MRSH,Marsh & McLennan Companies Inc.,174.09
+AMT,American Tower,179.46
+CMI,Cummins,601.45
+SNPS,Synopsys,433.56
+REGN,Regeneron Pharmaceuticals,780.09
+DELL,Dell Technologies,124.37
+CDNS,Cadence Design Systems,298.74
+CTAS,Cintas,201.10
+ORLY,O'Reilly Auto Parts,93.87
+MNST,Monster Beverage,80.88
+MDLZ,Mondelez International,61.45
+PWR,Quanta Services,523.69
+CI,Cigna,292.46
+CSX,CSX Corporation,41.30
+CL,Colgate-Palmolive,95.04
+SLB,Schlumberger,51.14
+HLT,Hilton Worldwide,327.38
+DASH,DoorDash,175.41
+TDG,TransDigm Group,1325.26
+MCO,Moody's Corporation,415.20
+APO,Apollo Global Management,127.53
+ELV,Elevance Health,329.59
+ABNB,Airbnb,119.56
+GM,General Motors,79.78
+NSC,Norfolk Southern Railway,316.73
+COR,Cencora,365.43
+MSI,Motorola Solutions,423.10
+KMI,Kinder Morgan,31.64
+RSG,Republic Services,226.72
+HOOD,Robinhood Markets Inc.,77.55
+WBD,Warner Bros. Discovery,28.01
+TFC,Truist Financial,54.42
+PCAR,Paccar,129.93
+AON,Aon,314.02
+TEL,TE Connectivity,227.16
+APD,Air Products,293.38
+AEP,American Electric Power,122.18
+FTNT,Fortinet,87.72
+TRV,Travelers Companies (The),299.75
+PSX,Phillips 66,161.13
+LHX,L3Harris,341.14
+EOG,EOG Resources,117.39
+SPG,Simon Property Group,195.66
+NXPI,NXP Semiconductors,249.26
+ROST,Ross Stores,192.31
+VLO,Valero Energy,203.89
+AZO,AutoZone,3733.09
+MPC,Marathon Petroleum,207.85
+BKR,Baker Hughes,61.16
+AFL,Aflac,116.20
+DLR,Digital Realty,174.16
+SRE,Sempra,90.83
+O,Realty Income,64.39
+MPWR,Monolithic Power Systems,1197.55
+GWW,W. W. Grainger,1202.13
+ZTS,Zoetis,128.19
+CARR,Carrier Global,66.80
+D,Dominion Energy,64.61
+F,Ford Motor Company,13.78
+URI,United Rentals,870.17
+AME,Ametek,236.33
+VST,Vistra Corp.,160.43
+FAST,Fastenal,47.14
+ALL,Allstate,205.91
+OKE,ONEOK,85.03
+AJG,Arthur J. Gallagher & Co.,207.61
+CAH,Cardinal Health,225.15
+CVNA,Carvana Co.,365.94
+IDXX,Idexx Laboratories,647.63
+MET,MetLife,78.87
+TGT,Target Corporation,114.12
+PSA,Public Storage,293.33
+BDX,Becton Dickinson,179.62
+CTVA,Corteva,75.48
+TER,Teradyne,323.92
+EA,Electronic Arts,201.72
+ADSK,Autodesk,232.93
+FITB,Fifth Third Bancorp,54.59
+CMG,Chipotle Mexican Grill,37.35
+FANG,Diamondback Energy,168.93
+TRGP,Targa Resources,222.03
+FIX,Comfort Systems USA Inc.,1345.62
+DHI,D. R. Horton,163.35
+HSY,Hershey Company (The),231.46
+OXY,Occidental Petroleum,47.34
+DAL,Delta Air Lines,71.16
+ROK,Rockwell Automation,413.43
+NDAQ,Nasdaq Inc.,81.05
+XEL,Xcel Energy,77.79
+EW,Edwards Lifesciences,78.67
+CCL,Carnival,32.80
+CBRE,CBRE Group,151.76
+ETR,Entergy,100.79
+EXC,Exelon,44.57
+AMP,Ameriprise Financial,489.27
+NUE,Nucor,194.78
+DDOG,Datadog,126.70
+YUM,Yum! Brands,160.35
+MCHP,Microchip Technology,80.90
+WAB,Wabtec,255.15
+KR,Kroger,68.68
+AIG,American International Group,79.36
+VMC,Vulcan Materials Company,321.01
+CIEN,Ciena Corporation,301.11
+SYY,Sysco,88.04
+PEG,Public Service Enterprise Group,83.85
+COIN,Coinbase Global,152.61
+ODFL,Old Dominion,195.74
+KEYS,Keysight Technologies,237.88
+KDP,Keurig Dr Pepper,29.84
+VTR,Ventas,85.29
+MLM,Martin Marietta Materials,663.38
+GRMN,Garmin,206.52
+ED,Consolidated Edison,109.36
+HIG,Hartford (The),142.02
+LVS,Las Vegas Sands,57.75
+CPRT,Copart,39.73
+EL,Estée Lauder Companies (The),106.09
+IR,Ingersoll Rand,96.98
+WDAY,Workday Inc.,145.19
+MSCI,MSCI,519.16
+TTWO,Take-Two Interactive,204.25
+RMD,ResMed,259.29
+EBAY,eBay,82.95
+PCG,PG&E Corporation,17.02
+CCI,Crown Castle,85.66
+PYPL,PayPal,40.26
+PRU,Prudential Financial,105.34
+WEC,WEC Energy Group,113.19
+UAL,United Airlines Holdings,113.50
+STT,State Street Corporation,131.37
+HBAN,Huntington Bancshares,18.02
+A,Agilent Technologies,128.22
+GEHC,GE HealthCare,79.29
+MTB,M&T Bank,235.06
+EME,EMCOR Group Inc.,803.53
+ACGL,Arch Capital Group,98.49
+KMB,Kimberly-Clark,107.35
+ROP,Roper Technologies,333.96
+EQT,EQT Corporation,56.73
+KVUE,Kenvue,18.44
+LYV,Live Nation Entertainment,150.60
+OTIS,Otis Worldwide,89.85
+AXON,Axon Enterprise,436.36
+NRG,NRG Energy,160.11
+CTSH,Cognizant,71.22
+IBKR,Interactive Brokers Group,76.54
+PAYX,Paychex,94.49
+FISV,Fiserv Inc.,62.72
+ADM,Archer Daniels Midland,69.24
+XYZ,Block Inc.,53.87
+FICO,Fair Isaac,1369.86
+DG,Dollar General,147.49
+DOV,Dover Corporation,232.52
+ROL,Rollins Inc.,65.74
+HPE,Hewlett Packard Enterprise,23.62
+RJF,Raymond James Financial,159.60
+TPR,Tapestry Inc.,154.43
+VICI,Vici Properties,29.18
+TDY,Teledyne Technologies,657.92
+XYL,Xylem Inc.,126.71
+CHTR,Charter Communications,241.08
+ARES,Ares Management Corporation,137.90
+ULTA,Ulta Beauty,684.25
+STLD,Steel Dynamics,206.43
+EXR,Extra Space Storage,142.02
+LEN,Lennar,120.76
+IQV,IQVIA,175.80
+IRM,Iron Mountain,99.67
+KHC,Kraft Heinz,24.88
+PPG,PPG Industries,130.53
+HAL,Halliburton,34.84
+ATO,Atmos Energy,175.22
+DTE,DTE Energy,139.17
+TSCO,Tractor Supply,54.53
+EXPE,Expedia Group,235.08
+CFG,Citizens Financial Group,66.87
+AEE,Ameren,106.08
+TPL,Texas Pacific Land Corporation,416.14
+CBOE,Cboe Global Markets,271.99
+ON,ON Semiconductor,70.68
+MTD,Mettler Toledo,1391.33
+STZ,Constellation Brands,163.02
+BIIB,Biogen,191.29
+DVN,Devon Energy,44.78
+FE,FirstEnergy,47.94
+JBL,Jabil,260.92
+NTRS,Northern Trust,147.45
+HUBB,Hubbell Incorporated,513.63
+WTW,Willis Towers Watson,282.86
+WRB,W. R. Berkley Corporation,71.20
+RF,Regions Financial Corporation,30.86
+PHM,PulteGroup,139.04
+CNP,CenterPoint Energy,40.91
+PPL,PPL Corporation,35.97
+DXCM,Dexcom,68.19
+SW,Smurfit WestRock,50.23
+ES,Eversource Energy,69.77
+GIS,General Mills,48.40
+EIX,Edison International,66.94
+IP,International Paper,48.64
+WSM,Williams-Sonoma,214.52
+CINF,Cincinnati Financial,164.11
+LUV,Southwest Airlines,51.66
+AVB,AvalonBay Communities,179.80
+SYF,Synchrony Financial,72.95
+FIS,Fidelity National Information Services,48.73
+KEY,KeyCorp,22.67
+DLTR,Dollar Tree,125.35
+EQR,Equity Residential,65.09
+EXE,Expand Energy,103.09
+DRI,Darden Restaurants,212.58
+FSLR,First Solar,227.60
+DOW,Dow Inc.,33.98
+CPAY,Corpay,346.25
+AWK,American Water Works,123.54
+CHD,Church & Dwight,100.17
+LH,LabCorp,289.08
+VRSK,Verisk Analytics,171.87
+Q,Qnity Electronics,114.06
+CTRA,Coterra,31.48
+STE,Steris,243.09
+EFX,Equifax,197.29
+VLTO,Veralto,95.33
+BG,Bunge Global,121.39
+DGX,Quest Diagnostics,209.53
+CHRW,C.H. Robinson,196.77
+AMCR,Amcor,49.62
+TSN,Tyson Foods,64.52
+L,Loews Corporation,110.15
+CMS,CMS Energy,74.16
+BRO,Brown & Brown,67.07
+LDOS,Leidos,174.83
+PKG,Packaging Corporation of America,244.06
+JBHT,J.B. Hunt,231.62
+OMC,Omnicom Group,69.53
+EXPD,Expeditors International,163.06
+RL,Ralph Lauren Corporation,359.55
+NVR,NVR Inc.,8082.38
+DD,DuPont,51.29
+HUM,Humana,176.34
+NI,NiSource,44.78
+NTAP,NetApp,105.69
+GPC,Genuine Parts Company,149.43
+LULU,Lululemon Athletica,176.88
+ALB,Albemarle Corporation,176.03
+TROW,T. Rowe Price,94.24
+PFG,Principal Financial Group,92.86
+CSGP,CoStar Group,48.09
+GPN,Global Payments,72.67
+SBAC,SBA Communications,190.43
+SNA,Snap-on,383.21
+CNC,Centene Corporation,40.26
+VRSN,Verisign,215.66
+WAT,Waters Corporation,331.52
+IFF,International Flavors & Fragrances,76.65
+BR,Broadridge Financial Solutions,167.88
+WY,Weyerhaeuser,27.09
+INCY,Incyte,99.35
+LII,Lennox International,553.57
+LYB,LyondellBasell,59.29
+SMCI,Supermicro,31.69
+MKC,McCormick & Company,70.30
+ZBH,Zimmer Biomet,95.21
+PTC,PTC Inc.,155.52
+FTV,Fortive,58.93
+VTRS,Viatris,16.02
+EVRG,Evergy,78.94
+BALL,Ball Corporation,67.29
+HPQ,HP Inc.,19.63
+WST,West Pharmaceutical Services,247.87
+PODD,Insulet Corporation,253.09
+APTV,Aptiv,83.64
+CDW,CDW,135.32
+LNT,Alliant Energy,68.17
+TXT,Textron,96.68
+ESS,Essex Property Trust,262.76
+HOLX,Hologic,75.11
+J,Jacobs Solutions,142.70
+INVH,Invitation Homes,27.16
+TKO,TKO Group Holdings,210.88
+NDSN,Nordson Corporation,295.64
+DECK,Deckers Brands,115.15
+PNR,Pentair,99.79
+COO,Cooper Companies (The),82.84
+MAA,Mid-America Apartment Communities,136.74
+FFIV,F5 Inc.,282.22
+MAS,Masco,76.24
+IEX,IDEX Corporation,211.28
+MRNA,Moderna,40.21
+TRMB,Trimble Inc.,65.06
+ALLE,Allegion,179.40
+HII,Huntington Ingalls Industries,392.15
+CLX,Clorox,125.65
+CF,CF Industries,97.23
+GEN,Gen Digital,24.64
+AVY,Avery Dennison,192.77
+KIM,Kimco Realty,21.96
+HAS,Hasbro,105.26
+ERIE,Erie Indemnity,279.84
+TYL,Tyler Technologies,339.51
+UHS,Universal Health Services,231.22
+BEN,Franklin Resources,27.64
+ALGN,Align Technology,197.24
+SOLV,Solventum,81.25
+BBY,Best Buy,66.84
+REG,Regency Centers,76.49
+SWK,Stanley Black & Decker,90.31
+BF.B,Brown–Forman,30.11
+BLDR,Builders FirstSource,125.44
+HST,Host Hotels & Resorts,19.98
+AKAM,Akamai Technologies,95.00
+EG,Everest Group,331.67
+UDR,UDR Inc.,39.84
+TTD,The Trade Desk Inc.,27.19
+HRL,Hormel Foods,23.79
+DPZ,Domino's,385.50
+ZBRA,Zebra Technologies,250.71
+GNRC,Generac,214.94
+FOX,Fox Corporation (Class B),56.02
+FOXA,Fox Corporation (Class A),61.76
+GDDY,GoDaddy,91.44
+PSKY,Paramount Skydance Corp,10.96
+WYNN,Wynn Resorts,115.18
+JKHY,Jack Henry & Associates,165.63
+CPT,Camden Property Trust,111.66
+DOC,Healthpeak Properties,16.95
+SJM,J.M. Smucker Company (The),109.98
+IVZ,Invesco,26.42
+AES,AES Corporation,16.45
+IT,Gartner,160.21
+GL,Globe Life,144.35
+BAX,Baxter International,22.30
+PNW,Pinnacle West,95.57
+RVTY,Revvity,100.89
+AOS,A. O. Smith,80.03
+AIZ,Assurant,216.77
+TAP,Molson Coors Beverage Company,52.98
+NCLH,Norwegian Cruise Line Holdings,22.76
+POOL,Pool Corporation,270.70
+EPAM,EPAM Systems,180.79
+APA,APA Corporation,28.11
+TECH,Bio-Techne,63.46
+MOS,Mosaic Company (The),31.21
+BXP,BXP Inc.,61.61
+DVA,DaVita,144.55
+SWKS,Skyworks Solutions,63.62
+HSIC,Henry Schein,81.21
+CAG,Conagra Brands,19.95
+MGM,MGM Resorts,36.39
+ARE,Alexandria Real Estate Equities,53.92
+FRT,Federal Realty Investment Trust,107.14
+CPB,Campbell Soup Company,29.16
+NWSA,News Corp (Class A),23.30
+CRL,Charles River Laboratories,164.83
+MTCH,Match Group,31.27
+FDS,FactSet,193.29
+LW,Lamb Weston,50.33
+PAYC,Paycom,117.68
+MOH,Molina Healthcare,122.46
+NWS,News Corp (Class B),26.91
From 5c86b15ad5c0b277a1c4010c49680f19f6e30d84 Mon Sep 17 00:00:00 2001
From: PawelSapula
Date: Mon, 25 May 2026 15:47:42 +0200
Subject: [PATCH 18/34] refactor: Model classes based on test results.
---
src/main/java/edu/ntnu/idi/idatt/model/market/Newspaper.java | 2 --
src/main/java/edu/ntnu/idi/idatt/model/market/Stock.java | 4 ++--
.../java/edu/ntnu/idi/idatt/model/portfolio/Portfolio.java | 3 ---
.../idi/idatt/view/components/elements/StockComponent.java | 2 +-
4 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/model/market/Newspaper.java b/src/main/java/edu/ntnu/idi/idatt/model/market/Newspaper.java
index 95681cf..a8ad9a7 100644
--- a/src/main/java/edu/ntnu/idi/idatt/model/market/Newspaper.java
+++ b/src/main/java/edu/ntnu/idi/idatt/model/market/Newspaper.java
@@ -6,8 +6,6 @@
import edu.ntnu.idi.idatt.model.enums.NewspaperEnum;
-//TODO: junit
-
/**
* Newspaper class
*
diff --git a/src/main/java/edu/ntnu/idi/idatt/model/market/Stock.java b/src/main/java/edu/ntnu/idi/idatt/model/market/Stock.java
index 92fddbd..077174c 100644
--- a/src/main/java/edu/ntnu/idi/idatt/model/market/Stock.java
+++ b/src/main/java/edu/ntnu/idi/idatt/model/market/Stock.java
@@ -123,8 +123,8 @@ public BigDecimal getLatestPriceChangePercent() {
return BigDecimal.ZERO;
}
- return (getLatestPriceChange().divide(prices.get(prices.size() - 2), 2, RoundingMode.HALF_UP))
- .multiply(new BigDecimal("100"));
+ return (getLatestPriceChange().multiply(new BigDecimal("100"))
+ .divide(prices.get(prices.size() - 2), 2, RoundingMode.HALF_UP));
}
/**
diff --git a/src/main/java/edu/ntnu/idi/idatt/model/portfolio/Portfolio.java b/src/main/java/edu/ntnu/idi/idatt/model/portfolio/Portfolio.java
index 1d37e10..9ba3bdc 100644
--- a/src/main/java/edu/ntnu/idi/idatt/model/portfolio/Portfolio.java
+++ b/src/main/java/edu/ntnu/idi/idatt/model/portfolio/Portfolio.java
@@ -142,9 +142,6 @@ public BigDecimal getChangeFromStock() {
BigDecimal costTotal = getShares().stream().map(s -> s.getTotalPurchasePrice())
.reduce(BigDecimal.ZERO, BigDecimal::add);
- if (costTotal.compareTo(BigDecimal.ZERO) <= 0)
- return BigDecimal.ZERO;
-
return profitTotal.divide(costTotal, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
}
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/StockComponent.java b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/StockComponent.java
index 4298b60..4bc55a9 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/StockComponent.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/StockComponent.java
@@ -54,7 +54,7 @@ public StockComponent(Stock stock) {
CssUtils.apply(title, CssUtils.BIG_TEXT_32);
labels.forEach(l -> CssUtils.apply(l, CssUtils.MED_TEXT_16));
- String color = CssUtils.generateValueColors(stock.getLatestPriceChange().doubleValue());
+ String color = CssUtils.generateValueColors(stock.getLatestPriceChange());
CssUtils.apply(changeValue, color);
CssUtils.apply(changeValuePercent, color);
From a5166a7cf7a8d0290056992f40bbf277accc7c95 Mon Sep 17 00:00:00 2001
From: PawelSapula
Date: Mon, 25 May 2026 17:11:34 +0200
Subject: [PATCH 19/34] chore: Restore method lines for checking if divisor is
null (Empty portfolio).
---
.../idi/idatt/model/portfolio/Portfolio.java | 4 ++++
.../idatt/model/portfolio/PortfolioTest.java | 19 +++++++++++++------
2 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/model/portfolio/Portfolio.java b/src/main/java/edu/ntnu/idi/idatt/model/portfolio/Portfolio.java
index 9ba3bdc..77c738a 100644
--- a/src/main/java/edu/ntnu/idi/idatt/model/portfolio/Portfolio.java
+++ b/src/main/java/edu/ntnu/idi/idatt/model/portfolio/Portfolio.java
@@ -142,6 +142,10 @@ public BigDecimal getChangeFromStock() {
BigDecimal costTotal = getShares().stream().map(s -> s.getTotalPurchasePrice())
.reduce(BigDecimal.ZERO, BigDecimal::add);
+ if (costTotal.compareTo(BigDecimal.ZERO) <= 0) {
+ return BigDecimal.ZERO;
+ }
+
return profitTotal.divide(costTotal, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
}
diff --git a/src/test/java/edu/ntnu/idi/idatt/model/portfolio/PortfolioTest.java b/src/test/java/edu/ntnu/idi/idatt/model/portfolio/PortfolioTest.java
index 857cf1d..872b55e 100644
--- a/src/test/java/edu/ntnu/idi/idatt/model/portfolio/PortfolioTest.java
+++ b/src/test/java/edu/ntnu/idi/idatt/model/portfolio/PortfolioTest.java
@@ -44,6 +44,11 @@ void addShare_shouldAddToPortfolio() {
}
+ void addDefaultShare() { // Since test over works, we will use this to initialize
+ // the rest of the tests under.
+ portfolio.addShare(share);
+ }
+
@Test
void getShares() {
@@ -54,11 +59,6 @@ void getShares() {
portfolio.getShares());
}
- void addDefaultShare() { // Since test over works, we will use this to initialize
- // the rest of the tests under.
- portfolio.addShare(share);
- }
-
@Test
void getSharesBySymbol_shouldReturnShares() {
addDefaultShare();
@@ -217,11 +217,18 @@ void getChangeFromStock_shouldReturnTotalFromPortfolioChange() {
BigDecimal expected = profit
.divide(totalCost, 2, RoundingMode.HALF_UP)
- .multiply(BigDecimal.valueOf(100));
+ .multiply(new BigDecimal("100"));
assertEquals(
expected,
portfolio.getChangeFromStock());
}
+ @Test
+ void getChangeFromStock_emptyPortfolio() {
+
+ assertEquals(BigDecimal.ZERO, portfolio.getChangeFromStock());
+
+ }
+
}
From 851c6c97e5409904aca8c641257fa9feaa52a6df Mon Sep 17 00:00:00 2001
From: PawelSapula
Date: Mon, 25 May 2026 17:19:58 +0200
Subject: [PATCH 20/34] feat: Add clickable share to go to stock.
---
.../components/elements/ShareComponent.java | 17 ++++++++++++++++-
.../primary/portfolio/PortfolioController.java | 1 +
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/ShareComponent.java b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/ShareComponent.java
index ca44eee..20b05c6 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/ShareComponent.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/ShareComponent.java
@@ -1,10 +1,12 @@
package edu.ntnu.idi.idatt.view.components.elements;
import edu.ntnu.idi.idatt.model.portfolio.Share;
+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.Cursor;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
@@ -27,6 +29,7 @@ public class ShareComponent extends HBox {
private final Share share;
private Button sellButton;
+ private HBox shareComponentUI;
/**
* Constructor for ShareComponent.
@@ -69,7 +72,10 @@ public ShareComponent(Share share) {
.addContent(sellButton)
.build();
- this.getChildren().add(shareComponent.makeUI());
+ shareComponentUI = (HBox) shareComponent.makeUI();
+ shareComponentUI.setCursor(Cursor.HAND);
+
+ this.getChildren().add(shareComponentUI);
}
/**
@@ -81,4 +87,13 @@ public void onShareSellButton(Consumer handler) {
sellButton.setOnAction((e) -> handler.accept(share));
}
+ /**
+ * Method for handeling share component click.
+ *
+ * @param handler - Functional interface with stock symbol reference.
+ */
+ public void onShareClick(Consumer handler) {
+ shareComponentUI.setOnMouseClicked(e -> handler.accept(share.getStock().getSymbol()));
+ }
+
}
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/portfolio/PortfolioController.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/portfolio/PortfolioController.java
index ec7e2ef..4a56307 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/primary/portfolio/PortfolioController.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/portfolio/PortfolioController.java
@@ -72,6 +72,7 @@ public void setShareModel(List shareList) {
for (Share share : shareList) {
ShareComponent shareComponent = new ShareComponent(share);
shareComponent.onShareSellButton((sellShare) -> holdingSale(sellShare));
+ shareComponent.onShareClick((stockSymbol) -> SceneManager.switchTo(SceneFactory.createStockView(stockSymbol)));
model.getShareList().add(shareComponent);
}
}
From 4fa891f21d7508bec4783d94a53d0c9691cea8ae Mon Sep 17 00:00:00 2001
From: PawelSapula
Date: Mon, 25 May 2026 17:48:26 +0200
Subject: [PATCH 21/34] feat(Exchange): Set gainers/losers to percent change
instead of change value.
---
.../java/edu/ntnu/idi/idatt/model/Exchange.java | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/model/Exchange.java b/src/main/java/edu/ntnu/idi/idatt/model/Exchange.java
index 2680bc6..8ee1e18 100644
--- a/src/main/java/edu/ntnu/idi/idatt/model/Exchange.java
+++ b/src/main/java/edu/ntnu/idi/idatt/model/Exchange.java
@@ -114,7 +114,7 @@ public List findStocks(String searchTerm) {
*
*
* Returns the stocks that have done it the best
- * in the latest week.
+ * (percent change) in the latest week.
*
*
* @param limit - Amount of stocks to be returned.
@@ -122,8 +122,8 @@ public List findStocks(String searchTerm) {
*/
public List getGainers(int limit) {
return stockMap.values().stream()
- .filter(stock -> stock.getLatestPriceChange().compareTo(BigDecimal.ZERO) > 0)
- .sorted(Comparator.comparing(Stock::getLatestPriceChange).reversed())
+ .filter(stock -> stock.getLatestPriceChangePercent().compareTo(BigDecimal.ZERO) > 0)
+ .sorted(Comparator.comparing(Stock::getLatestPriceChangePercent).reversed())
.limit(limit)
.toList();
}
@@ -133,16 +133,16 @@ public List getGainers(int limit) {
*
*
* Returns the stocks that have done it the worst
- * in value in the latest week.
+ * in percent change in the latest week.
*
*
* @param limit - Amount of stocks to be returned.
- * @return A list of stocks sorted in inclining order.
+ * @return A list of stocks sorted in ascending order.
*/
public List getLosers(int limit) {
return stockMap.values().stream()
- .filter(stock -> stock.getLatestPriceChange().compareTo(BigDecimal.ZERO) < 0)
- .sorted(Comparator.comparing(Stock::getLatestPriceChange))
+ .filter(stock -> stock.getLatestPriceChangePercent().compareTo(BigDecimal.ZERO) < 0)
+ .sorted(Comparator.comparing(Stock::getLatestPriceChangePercent))
.limit(limit)
.toList();
}
From e9196e821b4c56e0c5eb4c506eb15ecb81c3406d Mon Sep 17 00:00:00 2001
From: PawelSapula
Date: Mon, 25 May 2026 17:48:55 +0200
Subject: [PATCH 22/34] feat(SceneFactory): Optional marking for ExchangeView
---
src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java b/src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java
index 1ef5a6a..4c80524 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java
@@ -137,9 +137,14 @@ public static Parent createPortfolioView() {
*
* @return View's root.
*/
- public static Parent createExchangeView() {
+ public static Parent createExchangeView(boolean markValue) {
- mark(() -> createExchangeView());
+ if (markValue) {
+ mark(() -> createExchangeView(true));
+ } else {
+ navigation.clear();
+ mark(() -> createExchangeView(true));
+ }
ExchangeModel model = new ExchangeModel();
ExchangeView view = new ExchangeView();
From f1eebb7994fccaffbd5a0a69c52e4a8df246ea4b Mon Sep 17 00:00:00 2001
From: PawelSapula
Date: Mon, 25 May 2026 17:49:34 +0200
Subject: [PATCH 23/34] feat: Add Home button
---
.../java/edu/ntnu/idi/idatt/view/entry/StartController.java | 4 ++--
.../ntnu/idi/idatt/view/primary/newspaper/NewspaperView.java | 4 +++-
.../ntnu/idi/idatt/view/primary/portfolio/PortfolioView.java | 4 ++--
.../edu/ntnu/idi/idatt/view/primary/stock/StockView.java | 5 ++++-
.../idi/idatt/view/primary/transactions/TransactionView.java | 4 +++-
5 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/entry/StartController.java b/src/main/java/edu/ntnu/idi/idatt/view/entry/StartController.java
index 84a9c5e..da6a0e3 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/entry/StartController.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/entry/StartController.java
@@ -65,7 +65,7 @@ public void initializeGame() {
boolean loadResult = SessionManager.loadSession(model.getName().get());
if (loadResult) {
- SceneManager.switchTo(SceneFactory.createExchangeView());
+ SceneManager.switchTo(SceneFactory.createExchangeView(true));
return;
} else {
model.isNewGame().set(true);
@@ -130,7 +130,7 @@ public void initializeGame() {
Exchange exchange = new Exchange(player.getName(), stocks);
SessionManager.newSession(player, exchange);
SessionManager.saveSession();
- SceneManager.switchTo(SceneFactory.createExchangeView());
+ SceneManager.switchTo(SceneFactory.createExchangeView(true));
}
}
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/newspaper/NewspaperView.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/newspaper/NewspaperView.java
index 71a3fc5..6c900f2 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/primary/newspaper/NewspaperView.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/newspaper/NewspaperView.java
@@ -64,7 +64,9 @@ public Parent createContent() {
*/
@Override
public Parent createNavigation() {
- return UIFactory.createNavigation(" Newspaper", List.of());
+ return UIFactory.createNavigation(" Newspaper",
+ List.of("Home"),
+ () -> SceneManager.switchTo(SceneFactory.createExchangeView(false)));
}
/**
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/portfolio/PortfolioView.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/portfolio/PortfolioView.java
index 1a476b7..71f928d 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/primary/portfolio/PortfolioView.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/portfolio/PortfolioView.java
@@ -58,8 +58,8 @@ public Parent createContent() {
@Override
public Parent createNavigation() {
return UIFactory.createNavigation("Portfolio",
- List.of(" • Title"),
- () -> System.out.println("Newspaper clicked"));
+ List.of("Home"),
+ () -> SceneManager.switchTo(SceneFactory.createExchangeView(false)));
}
/**
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockView.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockView.java
index 1263fc1..950808f 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockView.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockView.java
@@ -74,7 +74,10 @@ public Parent createContent() {
@Override
public Parent createNavigation() {
return UIFactory.createNavigation(title = new Label(),
- List.of(" • Newspaper"),
+ List.of(
+ "Home",
+ " • Newspaper"),
+ () -> SceneManager.switchTo(SceneFactory.createExchangeView(false)),
() -> SceneManager.switchTo(SceneFactory.createNewspaperView(stockSymbol)));
}
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/transactions/TransactionView.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/transactions/TransactionView.java
index 5cd6f1e..6e8cce5 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/primary/transactions/TransactionView.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/transactions/TransactionView.java
@@ -55,7 +55,9 @@ public Parent createContent() {
*/
@Override
public Parent createNavigation() {
- return UIFactory.createNavigation("Transactions", List.of());
+ return UIFactory.createNavigation("Transactions",
+ List.of("Home"),
+ () -> SceneManager.switchTo(SceneFactory.createExchangeView(false)));
}
/**
From 853f9a93c38c4ac115ddb5a17c90d330a3018da0 Mon Sep 17 00:00:00 2001
From: PawelSapula
Date: Mon, 25 May 2026 17:49:56 +0200
Subject: [PATCH 24/34] feat(Exchange MVC): Sort by if stock has new news
---
.../idatt/view/primary/exchange/ExchangeController.java | 9 ++++++++-
.../idi/idatt/view/primary/exchange/ExchangeView.java | 2 ++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/exchange/ExchangeController.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/exchange/ExchangeController.java
index d197f9c..8ce104e 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/primary/exchange/ExchangeController.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/exchange/ExchangeController.java
@@ -31,6 +31,7 @@ public class ExchangeController extends AbstractController {
*/
public enum SortAction {
NONE,
+ NEWS,
GAINERS,
LOSERS
}
@@ -129,8 +130,14 @@ public void sortStocksBy(SortAction action) {
break;
}
+ case NEWS: {
+ stocksSorted.addAll(session.getExchange().getStocks()
+ .stream().filter(s -> s.getNewspaper().hasNewNews()).toList());
+ break;
+ }
+
case GAINERS: {
- stocksSorted.addAll(session.getExchange().getGainers(Integer.MAX_VALUE)); // TODO: fix?
+ stocksSorted.addAll(session.getExchange().getGainers(Integer.MAX_VALUE));
break;
}
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/exchange/ExchangeView.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/exchange/ExchangeView.java
index 029d3c8..9f779a4 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/primary/exchange/ExchangeView.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/exchange/ExchangeView.java
@@ -73,9 +73,11 @@ public Parent createHeader() {
query -> searchQueryHandler.accept(query),
List.of(
"None",
+ "New news",
"Gainers (week)",
"Losers (week)"),
() -> sortHandle.accept(SortAction.NONE),
+ () -> sortHandle.accept(SortAction.NEWS),
() -> sortHandle.accept(SortAction.GAINERS),
() -> sortHandle.accept(SortAction.LOSERS));
}
From 3d4fc0de540d4c3b6123979e74eb8d4a90aa6ae2 Mon Sep 17 00:00:00 2001
From: pawelsa
Date: Mon, 25 May 2026 19:36:22 +0200
Subject: [PATCH 25/34] feat: Create wrappers for view initialization
---
.../edu/ntnu/idi/idatt/view/SceneFactory.java | 91 ++++++++++++++++---
1 file changed, 80 insertions(+), 11 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java b/src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java
index 4c80524..154e11b 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/SceneFactory.java
@@ -25,6 +25,7 @@
import edu.ntnu.idi.idatt.view.primary.transactions.TransactionModel;
import edu.ntnu.idi.idatt.view.primary.transactions.TransactionView;
import javafx.scene.Parent;
+import javafx.util.Pair;
import java.util.ArrayDeque;
import java.util.Deque;
@@ -114,13 +115,11 @@ public static Parent createStartView() {
}
/**
- * Initialization method for Portfolio View.
+ * Initialization method for all Portfolio views.
*
- * @return View's root.
+ * @return View's root and controller.
*/
- public static Parent createPortfolioView() {
-
- mark(() -> createPortfolioView());
+ private static Pair createDefaultPortfolioView() {
PortfolioModel model = new PortfolioModel();
PortfolioView view = new PortfolioView();
@@ -129,7 +128,51 @@ public static Parent createPortfolioView() {
view.setModel(model);
view.setController(controller);
- return view.getInstance();
+ return new Pair(view.getInstance(), controller);
+ }
+
+ /**
+ * Wrapper for Portfolio View initialization method.
+ *
+ *
+ * Initializes a default portfolio.
+ *
+ *
+ * @return View's root.
+ */
+ public static Parent createPortfolioView() {
+
+ mark(() -> createPortfolioView());
+
+ Pair vc = createDefaultPortfolioView();
+ return vc.getKey(); // View
+ }
+
+ /**
+ * Wrapper for Portfolio View initialization method.
+ *
+ *
+ * Initializes a portfolio with a search query.
+ *
+ *
+ * @param initialSearch - Initial search query
+ * @return View's root
+ */
+ public static Parent createPortfolioView(String initialSearch) {
+
+ mark(() -> createPortfolioView(initialSearch));
+
+ Pair vc = createDefaultPortfolioView();
+ Parent view = vc.getKey();
+
+ if (initialSearch == null || initialSearch.isEmpty()) {
+ return view;
+ }
+
+ PortfolioController controller = vc.getValue();
+ controller.handleSearchQuery(initialSearch);
+ return view;
+
}
/**
@@ -137,15 +180,14 @@ public static Parent createPortfolioView() {
*
* @return View's root.
*/
- public static Parent createExchangeView(boolean markValue) {
+ private static Parent createDefaultExchangeView(boolean clean) {
- if (markValue) {
- mark(() -> createExchangeView(true));
- } else {
+ if (clean) {
navigation.clear();
- mark(() -> createExchangeView(true));
}
+ mark(() -> createDefaultExchangeView(false));
+
ExchangeModel model = new ExchangeModel();
ExchangeView view = new ExchangeView();
ExchangeController controller = new ExchangeController(model);
@@ -157,6 +199,33 @@ public static Parent createExchangeView(boolean markValue) {
}
+ /**
+ * Wrapper for Exchange View initialization method.
+ *
+ *
+ * Initializes a default exchange view.
+ *
+ *
+ * @return View's root
+ */
+ public static Parent createExchangeView() {
+ return createDefaultExchangeView(false);
+ }
+
+ /**
+ * Wrapper for Exchange View initialization method.
+ *
+ *
+ * Initializes a default exchange view with the clean parameter.
+ *
+ *
+ * @param clean - should it reset the page stack.
+ * @rteturn View's root
+ */
+ public static Parent createExchangeView(boolean clean) {
+ return createDefaultExchangeView(clean);
+ }
+
/**
* Initialization method for Stock View.
*
From d7d92fd98d4099e4cca321644fcd1f5c218fc65a Mon Sep 17 00:00:00 2001
From: pawelsa
Date: Mon, 25 May 2026 19:37:02 +0200
Subject: [PATCH 26/34] feat(Stock MVC): 'Sell in portfolio' button
functionality
---
.../idatt/view/primary/stock/StockController.java | 12 ++++++++++++
.../ntnu/idi/idatt/view/primary/stock/StockView.java | 3 ++-
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockController.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockController.java
index 62a4556..cfd7b42 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockController.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockController.java
@@ -8,6 +8,8 @@
import edu.ntnu.idi.idatt.model.transaction.Purchase;
import edu.ntnu.idi.idatt.service.transaction.PurchaseCalculator;
import edu.ntnu.idi.idatt.session.UserSession;
+import edu.ntnu.idi.idatt.view.SceneFactory;
+import edu.ntnu.idi.idatt.view.SceneManager;
import edu.ntnu.idi.idatt.view.components.AbstractController;
import edu.ntnu.idi.idatt.view.components.elements.RecieptComponent;
import edu.ntnu.idi.idatt.view.components.ui.UIAlert;
@@ -169,6 +171,16 @@ public void buyButtonClicked() {
showReciept(purchase);
}
+ /**
+ * Method to execute on portfolio button clicked.
+ *
+ * Navigates to portfolio with this stock as deafult search.
+ *
+ */
+ public void portfolioButtonClicked() {
+ SceneManager.switchTo(SceneFactory.createPortfolioView(getSymbol()));
+ }
+
/**
* Method for showing transaction reciept.
*
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockView.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockView.java
index 950808f..b1378bf 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockView.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/stock/StockView.java
@@ -77,7 +77,7 @@ public Parent createNavigation() {
List.of(
"Home",
" • Newspaper"),
- () -> SceneManager.switchTo(SceneFactory.createExchangeView(false)),
+ () -> SceneManager.switchTo(SceneFactory.createExchangeView(true)),
() -> SceneManager.switchTo(SceneFactory.createNewspaperView(stockSymbol)));
}
@@ -188,6 +188,7 @@ public void setController(StockController controller) {
title.setText(controller.getSymbol());
stockSymbol = controller.getSymbol();
tradeSection.getBuyButton().setOnAction((e) -> controller.buyButtonClicked());
+ tradeSection.getPortfolioButton().setOnAction((e) -> controller.portfolioButtonClicked());
}
}
From e1537643e88ca0529446fa40a782dedb097aec0f Mon Sep 17 00:00:00 2001
From: pawelsa
Date: Mon, 25 May 2026 19:37:23 +0200
Subject: [PATCH 27/34] refactor: Apply SceneFactory wrappers
---
.../java/edu/ntnu/idi/idatt/view/entry/StartController.java | 4 ++--
.../ntnu/idi/idatt/view/primary/newspaper/NewspaperView.java | 2 +-
.../ntnu/idi/idatt/view/primary/portfolio/PortfolioView.java | 2 +-
.../idi/idatt/view/primary/transactions/TransactionView.java | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/entry/StartController.java b/src/main/java/edu/ntnu/idi/idatt/view/entry/StartController.java
index da6a0e3..84a9c5e 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/entry/StartController.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/entry/StartController.java
@@ -65,7 +65,7 @@ public void initializeGame() {
boolean loadResult = SessionManager.loadSession(model.getName().get());
if (loadResult) {
- SceneManager.switchTo(SceneFactory.createExchangeView(true));
+ SceneManager.switchTo(SceneFactory.createExchangeView());
return;
} else {
model.isNewGame().set(true);
@@ -130,7 +130,7 @@ public void initializeGame() {
Exchange exchange = new Exchange(player.getName(), stocks);
SessionManager.newSession(player, exchange);
SessionManager.saveSession();
- SceneManager.switchTo(SceneFactory.createExchangeView(true));
+ SceneManager.switchTo(SceneFactory.createExchangeView());
}
}
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/newspaper/NewspaperView.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/newspaper/NewspaperView.java
index 6c900f2..56c2144 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/primary/newspaper/NewspaperView.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/newspaper/NewspaperView.java
@@ -66,7 +66,7 @@ public Parent createContent() {
public Parent createNavigation() {
return UIFactory.createNavigation(" Newspaper",
List.of("Home"),
- () -> SceneManager.switchTo(SceneFactory.createExchangeView(false)));
+ () -> SceneManager.switchTo(SceneFactory.createExchangeView(true)));
}
/**
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/portfolio/PortfolioView.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/portfolio/PortfolioView.java
index 71f928d..e987722 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/primary/portfolio/PortfolioView.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/portfolio/PortfolioView.java
@@ -59,7 +59,7 @@ public Parent createContent() {
public Parent createNavigation() {
return UIFactory.createNavigation("Portfolio",
List.of("Home"),
- () -> SceneManager.switchTo(SceneFactory.createExchangeView(false)));
+ () -> SceneManager.switchTo(SceneFactory.createExchangeView(true)));
}
/**
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/primary/transactions/TransactionView.java b/src/main/java/edu/ntnu/idi/idatt/view/primary/transactions/TransactionView.java
index 6e8cce5..438f004 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/primary/transactions/TransactionView.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/primary/transactions/TransactionView.java
@@ -57,7 +57,7 @@ public Parent createContent() {
public Parent createNavigation() {
return UIFactory.createNavigation("Transactions",
List.of("Home"),
- () -> SceneManager.switchTo(SceneFactory.createExchangeView(false)));
+ () -> SceneManager.switchTo(SceneFactory.createExchangeView(true)));
}
/**
From a54e919ed5d4b049447b44acde185d0aa350cd1c Mon Sep 17 00:00:00 2001
From: pawelsa
Date: Mon, 25 May 2026 22:00:13 +0200
Subject: [PATCH 28/34] feat: Style and layout enchancements
---
.../components/elements/RecieptComponent.java | 10 +-
.../elements/SearchBarComponent.java | 43 ++----
.../components/elements/ShareComponent.java | 5 +-
.../elements/TransactionComponent.java | 5 +-
.../idatt/view/components/ui/UIFactory.java | 124 ++++++++++++------
.../ntnu/idi/idatt/view/util/CssUtils.java | 2 +
.../idi/idatt/view/util/ResourceUtils.java | 2 -
src/main/resources/themes/default.css | 68 +++++-----
8 files changed, 145 insertions(+), 114 deletions(-)
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/RecieptComponent.java b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/RecieptComponent.java
index 16e39d4..8ada10f 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/RecieptComponent.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/RecieptComponent.java
@@ -41,7 +41,9 @@ public RecieptComponent(Transaction transaction) {
CssUtils.apply(title, CssUtils.BIG_TEXT_32);
Label operation = new Label();
- String operationString = "Transaction type: %s, week: %d";
+ String operationString = "Transaction type: %s";
+
+ Label week = new Label(String.format("Week: %s", transaction.getWeek()));
Label shareName = new Label(String.format("Share: %s", transaction.getShare().getStock().toString()));
Label shareAmount = new Label(String.format("Amount: %.3f", transaction.getShare().getQuantity()));
@@ -60,14 +62,14 @@ public RecieptComponent(Transaction transaction) {
Label profits = new Label();
- List labels = List.of(shareName, operation, shareAmount,
+ List labels = List.of(week, 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()));
+ operation.setText(String.format(operationString, "Purchase"));
gross.setText(String.format(grossString, calc.calculateGross()));
tax.setText(String.format(taxString, calc.calculateTax()));
comission.setText(String.format(comissionString, calc.calculateCommision()));
@@ -91,6 +93,7 @@ public RecieptComponent(Transaction transaction) {
.growWithAlignment(Pos.CENTER)
.addAllContent(title,
operation,
+ week,
new Label(" "), // Small filler
shareName,
shareAmount,
@@ -104,6 +107,7 @@ public RecieptComponent(Transaction transaction) {
this.getChildren().add(uiReciept.makeUI());
this.getStyleClass().add("dark");
+ this.setStyle("-fx-background-radius: 20;");
this.setMaxSize(700, 500);
this.setPrefWidth(700);
StackPane.setAlignment(this, Pos.CENTER);
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/SearchBarComponent.java b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/SearchBarComponent.java
index 1c671dd..b589909 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/SearchBarComponent.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/SearchBarComponent.java
@@ -1,11 +1,9 @@
package edu.ntnu.idi.idatt.view.components.elements;
-import edu.ntnu.idi.idatt.view.components.primitives.ActionEventHandler;
import javafx.beans.property.SimpleStringProperty;
-import javafx.beans.property.StringProperty;
+import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.TextField;
-import javafx.scene.image.Image;
import javafx.scene.layout.HBox;
/**
@@ -13,13 +11,12 @@
*
*
* JavaFX Component for handeling repetative tasks.
- * Creates a searchbar with search icon.
+ * Creates a searchbar.
*
*/
public class SearchBarComponent extends HBox {
- private final StringProperty query = new SimpleStringProperty();
- private final IconComponent searchIcon;
+ private final SimpleStringProperty query = new SimpleStringProperty();
/**
* Constructor for SearchBarComponent.
@@ -28,44 +25,26 @@ public class SearchBarComponent extends HBox {
*/
public SearchBarComponent(String placeholder) {
- HBox wrapper = new HBox();
- wrapper.getStyleClass().add("searchbar");
- wrapper.setAlignment(Pos.CENTER);
+ this.setAlignment(Pos.CENTER);
TextField searchBar = new TextField();
searchBar.getStyleClass().add("searchbar-field");
searchBar.setPromptText(placeholder);
- searchBar.setMaxHeight(Double.MAX_VALUE);
searchBar.textProperty().bindBidirectional(query);
searchBar.setFocusTraversable(false);
+ searchBar.setPadding(new Insets(10));
+ searchBar.setMinWidth(300);
- Image image = new Image(this.getClass().getResource("/icons/search.png").toExternalForm());
- searchIcon = new IconComponent(image, null, 32);
-
- wrapper.getChildren().addAll(searchBar, searchIcon);
-
- this.getChildren().addAll(wrapper);
- }
-
- /**
- * Getter for query content.
- *
- * Returns the current input of the searchbar.
- *
- *
- * @return String;
- */
- public String getQuery() {
- return query.get();
+ this.getChildren().addAll(searchBar);
}
/**
- * Method for handeling search icon click.
+ * Getter for query property.
*
- * @param handler - Functional interface.
+ * @return SimpleStringProperty;
*/
- public void onSearchQuery(ActionEventHandler handler) {
- this.searchIcon.onIconClick(() -> handler.handle());
+ public SimpleStringProperty getQuery() {
+ return query;
}
}
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/ShareComponent.java b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/ShareComponent.java
index 20b05c6..f961998 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/ShareComponent.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/ShareComponent.java
@@ -1,7 +1,6 @@
package edu.ntnu.idi.idatt.view.components.elements;
import edu.ntnu.idi.idatt.model.portfolio.Share;
-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;
@@ -41,7 +40,7 @@ public ShareComponent(Share share) {
this.setMaxSize(Double.MAX_VALUE, 300);
this.setPadding(new Insets(30));
- this.getStyleClass().add("rowBox");
+ CssUtils.apply(this, CssUtils.GRAY);
Label title = new Label(share.getStock().toString());
Label quantity = new Label("Owned shares: " + share.getQuantity().toString());
@@ -49,7 +48,7 @@ public ShareComponent(Share share) {
Label latestValue = new Label(String.format("%.2f $", share.getProfit()));
Label latestValueChange = new Label(String.format("%.2f %%", share.getProfitPercent()));
- sellButton = new Button("Sell");
+ sellButton = new Button("Sell Share");
List labels = List.of(title, quantity, latestValueLabel, latestValue, latestValueChange);
labels.forEach(e -> e.getStyleClass().add("portfolio-box-text"));
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/TransactionComponent.java b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/TransactionComponent.java
index 9d022e8..760b748 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/components/elements/TransactionComponent.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/components/elements/TransactionComponent.java
@@ -89,11 +89,10 @@ public TransactionComponent(Transaction transaction) {
this.setPadding(new Insets(40));
this.setAlignment(Pos.TOP_CENTER);
- // TODO: CHANGE AND IN STOCKComponent
- this.setStyle("-fx-background-color: #404950;");
+ CssUtils.apply(this, CssUtils.GRAY);
CssUtils.apply(title, CssUtils.BIG_TEXT_32);
- CssUtils.apply(name, CssUtils.BIG_TEXT_32);
+ CssUtils.apply(name, CssUtils.MED_TEXT_24);
List labels = List.of(totalValue, taxComissionValue, grossValue, amountOfShares, saleProfit);
labels.forEach(l -> CssUtils.apply(l, CssUtils.MED_TEXT_16));
diff --git a/src/main/java/edu/ntnu/idi/idatt/view/components/ui/UIFactory.java b/src/main/java/edu/ntnu/idi/idatt/view/components/ui/UIFactory.java
index b6c6120..d852d6c 100644
--- a/src/main/java/edu/ntnu/idi/idatt/view/components/ui/UIFactory.java
+++ b/src/main/java/edu/ntnu/idi/idatt/view/components/ui/UIFactory.java
@@ -1,5 +1,6 @@
package edu.ntnu.idi.idatt.view.components.ui;
+import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
@@ -11,14 +12,19 @@
import edu.ntnu.idi.idatt.view.components.primitives.ActionEventHandler;
import edu.ntnu.idi.idatt.view.util.CssUtils;
import edu.ntnu.idi.idatt.view.util.ResourceUtils;
+import javafx.beans.binding.Bindings;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
+import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
/**
@@ -40,12 +46,12 @@ public class UIFactory {
* Creates a simple header containing a searchbar.
*
*
- * @param placeholder - Placeholder for searchbar.
- * @param onSearchQuery - Input functional interface of searchbar.
+ * @param placeholder - Placeholder for searchbar.
+ * @param searchQuery - Functional interface of searchbar input property.
* @return header element.
*/
- public static Parent createHeader(String placeholder, Consumer onSearchQuery) {
- return createDefaultHeader(placeholder, onSearchQuery);
+ public static Parent createHeader(String placeholder, Consumer searchQuery) {
+ return createDefaultHeader(placeholder, searchQuery);
}
/**
@@ -55,13 +61,14 @@ public static Parent createHeader(String placeholder, Consumer onSearchQ
* Creates a header with searchbar with sorting ability.
*
*
- * @param placeholder - Placeholder for searchbar.
- * @param onSearchQuery - Input functional interface of searchbar.
- * @param sortItems - List of available sorting labels.
- * @param sortHandlers - List of functional interfaces to react to the items.
+ * @param placeholder - Placeholder for searchbar.
+ * @param searchQuery - Functional interface of searchbar input property.
+ * @param sortItems - List of available sorting labels.
+ * @param sortHandlers - List of functional interfaces to react to the items.
* @return header element.
*/
- public static Parent createHeader(String placeholder, Consumer onSearchQuery, List sortItems,
+ public static Parent createHeader(String placeholder, Consumer searchQuery,
+ List sortItems,
ActionEventHandler... sortHandlers) {
if (sortItems.size() != sortHandlers.length) {
@@ -70,7 +77,7 @@ public static Parent createHeader(String placeholder, Consumer onSearchQ
}
MenuButton menu = new MenuButton("Sort by..");
- HBox.setMargin(menu, new Insets(20));
+ menu.getStyleClass().add("menu-button");
sortItems.forEach(item -> {
MenuItem m = new MenuItem(item);
@@ -78,7 +85,7 @@ public static Parent createHeader(String placeholder, Consumer onSearchQ
menu.getItems().add(m);
});
- return createDefaultHeader(placeholder, onSearchQuery, menu);
+ return createDefaultHeader(placeholder, searchQuery, menu);
}
/**
@@ -88,12 +95,14 @@ public static Parent createHeader(String placeholder, Consumer onSearchQ
* This method is used for creating all headers through the public wrappers.
*
*
- * @param placeholder - Placeholder for searchbar.
- * @param onSearchQuery - Input functional interface of searchbar.
- * @param addons - Parent objects to add to the left site header
+ * @param placeholder - Placeholder for searchbar.
+ * @param searchQuery - Functional interface of searchbar input property.
+ * @param addons - Parent objects to add to the left site header
* @return header element.
*/
- private static Parent createDefaultHeader(String placeholder, Consumer onSearchQuery, Parent... addons) {
+ private static Parent createDefaultHeader(String placeholder, Consumer searchQuery,
+ Parent... addons) {
+
SearchBarComponent bar = new SearchBarComponent(placeholder);
HBox.setMargin(bar, new Insets(20));
@@ -101,13 +110,17 @@ private static Parent createDefaultHeader(String placeholder, Consumer o
UICompositor header = new UICompositor.Builder()
.parent(new HBox())
.growWithAlignment(Pos.CENTER)
+ .properties(parent -> parent.setPadding(new Insets(0, 10, 0, 10)))
.addAllContent(addons)
.filler()
+ .filler()
.addContent(bar)
.filler()
+ .filler()
+ .filler()
.build();
- bar.onSearchQuery(() -> onSearchQuery.accept(bar.getQuery())); // Remake?
+ searchQuery.accept(bar.getQuery());
return header.makeUI();
}
@@ -171,25 +184,43 @@ private static Parent createDefaultNavigation(Label titleLabel, List but
buttons.add(new Button(buttonLabel));
}
buttons.forEach(b -> {
- CssUtils.apply(b, CssUtils.MED_TEXT_16);
b.setOnAction((e) -> handlers[buttons.indexOf(b)].handle());
});
UICompositor.Builder navigationBuilder = new UICompositor.Builder()
- .parent(new VBox())
+ .parent(new VBox(10))
.growWithAlignment(Pos.CENTER)
+ .properties(nav -> nav.setPadding(new Insets(40)))
.addContent(titleLabel);
buttons.forEach(b -> navigationBuilder.addContent(b));
- navigationBuilder.filler();
+ navigationBuilder
+ .filler();
if (!SceneFactory.isFinal()) {
- Button previous = new Button("Previous");
+ Button previous = new Button("Previous Page");
previous.setOnAction((e) -> SceneFactory.goBack());
navigationBuilder.addContent(previous);
}
+ Button progress = new Button("Advance to next week");
+ progress.setOnAction((e) -> {
+ UserSession.getInstance().getExchange().advance();
+ UserSession.getInstance().updateGameState();
+ SceneFactory.reloadCurrent();
+ });
+
+ navigationBuilder.addContent(progress);
+
+ // Styles and properties of childs
+ navigationBuilder.properties(nav -> nav.getChildren()
+ .filtered(c -> !(c instanceof Label))
+ .forEach(c -> ((Region) c).setMaxWidth(Double.MAX_VALUE)));
+ navigationBuilder.properties(nav -> nav.getChildren()
+ .filtered(c -> c instanceof Button)
+ .forEach(c -> c.getStyleClass().add("button-outlined")));
+
UICompositor navigation = navigationBuilder.build();
return navigation.makeUI();
@@ -213,35 +244,33 @@ public static Parent createMenu(String title, List buttonLables, ActionE
System.out.println("Failed to build menu!");
}
- IconComponent menuIcon = new IconComponent(ResourceUtils.MENU_ICON, title, 60);
- CssUtils.apply(menuIcon, CssUtils.BIG_TEXT_32);
+ Label titleLabel = new Label(title);
+ CssUtils.apply(titleLabel, CssUtils.BIG_TEXT_32);
ArrayList