From 98cc03cd198e0a1792099bbdd7af64099af7b84a Mon Sep 17 00:00:00 2001 From: EspenTinius Date: Wed, 27 May 2026 06:19:42 +0200 Subject: [PATCH] best/worst preformers of the week --- .../view/widgets/market/MarketActions.java | 2 + .../view/widgets/market/MarketController.java | 7 +++ .../mappe/view/widgets/market/MarketSort.java | 10 +++- .../mappe/view/widgets/market/MarketView.java | 60 +++++++++++++++++-- 4 files changed, 73 insertions(+), 6 deletions(-) diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketActions.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketActions.java index 6282a24..3076b60 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketActions.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketActions.java @@ -15,6 +15,8 @@ public enum MarketActions { SORT_PRICE, /** Cycle the change-filter between winners-only and losers-only. */ SORT_CHANGE, + /** Cycle the week-change filter between best-of-week and worst-of-week. */ + SORT_WEEK_CHANGE, /** Show only stocks the player currently owns. */ SORT_OWNED; } diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketController.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketController.java index 2c6683f..1ae01e5 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketController.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketController.java @@ -90,6 +90,13 @@ protected void initInteractions() { ? MarketSort.LOSERS : MarketSort.WINNERS; getViewElement().setSort(next); }); + getViewElement().setOnAction(MarketActions.SORT_WEEK_CHANGE, + () -> { + MarketSort next = + (getViewElement().getCurrentSort() == MarketSort.BEST_WEEK) + ? MarketSort.WORST_WEEK : MarketSort.BEST_WEEK; + getViewElement().setSort(next); + }); getViewElement().setOnAction(MarketActions.SORT_OWNED, () -> getViewElement().setSort(MarketSort.OWNED)); diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketSort.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketSort.java index 09503ba..5e0df57 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketSort.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketSort.java @@ -5,8 +5,10 @@ * *

{@link #WINNERS} and {@link #LOSERS} are mutually exclusive views * of the "change" filter button: pressing the button cycles between - * the two. {@link #OWNED} acts as a "show only owned" filter rather - * than a pure sort.

+ * the two. {@link #BEST_WEEK} and {@link #WORST_WEEK} behave the same + * way on the "week" filter button, but only consider the change from + * the previous week to the current one. {@link #OWNED} acts as a + * "show only owned" filter rather than a pure sort.

* */ public enum MarketSort { /** Alphabetical sort by ticker symbol. */ @@ -17,6 +19,10 @@ public enum MarketSort { WINNERS, /** Show only stocks with negative change, sorted ascending. */ LOSERS, + /** Show only stocks that went up this week, sorted best to worst. */ + BEST_WEEK, + /** Show only stocks that went down this week, sorted worst to best. */ + WORST_WEEK, /** Show only stocks the player currently owns, sorted by quantity. */ OWNED; } diff --git a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketView.java b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketView.java index 09cdf3e..fdd5176 100644 --- a/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketView.java +++ b/src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/view/widgets/market/MarketView.java @@ -42,6 +42,7 @@ public class MarketView extends ViewElement { private Button sortTickerButton; private Button sortPriceButton; private Button sortChangeButton; + private Button sortWeekChangeButton; private Button sortOwnedButton; /** Maps every sort mode to its filter-bar button. Used for active state. */ @@ -113,6 +114,7 @@ private HBox buildFilterBar() { sortTickerButton = new Button("A-Z"); sortPriceButton = new Button("price"); sortChangeButton = new Button("change"); + sortWeekChangeButton = new Button("week"); sortOwnedButton = new Button("owned"); sortButtonMap.put(MarketSort.TICKER, sortTickerButton); @@ -121,16 +123,20 @@ private HBox buildFilterBar() { // between them on each press. sortButtonMap.put(MarketSort.WINNERS, sortChangeButton); sortButtonMap.put(MarketSort.LOSERS, sortChangeButton); + // BEST_WEEK and WORST_WEEK share the week button in the same way. + sortButtonMap.put(MarketSort.BEST_WEEK, sortWeekChangeButton); + sortButtonMap.put(MarketSort.WORST_WEEK, sortWeekChangeButton); sortButtonMap.put(MarketSort.OWNED, sortOwnedButton); registerButton(MarketActions.SORT_TICKER, sortTickerButton); registerButton(MarketActions.SORT_PRICE, sortPriceButton); registerButton(MarketActions.SORT_CHANGE, sortChangeButton); + registerButton(MarketActions.SORT_WEEK_CHANGE, sortWeekChangeButton); registerButton(MarketActions.SORT_OWNED, sortOwnedButton); HBox filterBar = new HBox(8, searchField, sortTickerButton, sortPriceButton, - sortChangeButton, sortOwnedButton); + sortChangeButton, sortWeekChangeButton, sortOwnedButton); filterBar.setAlignment(Pos.CENTER_LEFT); filterBar.setPadding(Insets.EMPTY); @@ -163,7 +169,8 @@ protected void initStyling() { getRootPane().getStyleClass().add("market-container"); searchField.getStyleClass().add("market-search"); - Stream.of(sortTickerButton, sortPriceButton, sortChangeButton, sortOwnedButton) + Stream.of(sortTickerButton, sortPriceButton, sortChangeButton, + sortWeekChangeButton, sortOwnedButton) .forEach(b -> b.getStyleClass().add("market-filter-btn")); stocksScroll.getStyleClass().add("market-scroll"); @@ -223,7 +230,8 @@ public MarketSort getCurrentSort() { * *

The change button doubles as a winners/losers cycle - its label * updates to reflect the active mode so the user can tell which one - * they're currently looking at.

+ * they're currently looking at. The week button does the same for + * best-of-week and worst-of-week.

* * @param sort the new sort mode. * */ @@ -237,6 +245,7 @@ public void setSort(final MarketSort sort) { } } refreshChangeButtonLabel(); + refreshWeekChangeButtonLabel(); renderStocks(); } @@ -256,11 +265,28 @@ private void refreshChangeButtonLabel() { }); } + /** + * Updates the label on the week-change button the same way as + * {@link #refreshChangeButtonLabel()}, but for the best/worst-of-week + * cycle. + * */ + private void refreshWeekChangeButtonLabel() { + if (sortWeekChangeButton == null) { + return; + } + sortWeekChangeButton.setText(switch (currentSort) { + case BEST_WEEK -> "best of week"; + case WORST_WEEK -> "worst of week"; + default -> "week"; + }); + } + /** * Rebuilds the stock card grid based on the current search term and * sort mode. * - *

{@link MarketSort#WINNERS}, {@link MarketSort#LOSERS} and + *

{@link MarketSort#WINNERS}, {@link MarketSort#LOSERS}, + * {@link MarketSort#BEST_WEEK}, {@link MarketSort#WORST_WEEK} and * {@link MarketSort#OWNED} act as filters: in those modes the grid * only shows the matching subset of stocks. The other modes show * every stock that matches the search term.

@@ -301,6 +327,8 @@ private boolean matchesSortFilter(final Stock stock) { return switch (currentSort) { case WINNERS -> changePercent(stock) > 0; case LOSERS -> changePercent(stock) < 0; + case BEST_WEEK -> weekChangePercent(stock) > 0; + case WORST_WEEK -> weekChangePercent(stock) < 0; case OWNED -> ownedLookup.applyAsInt(stock.getSymbol()) > 0; default -> true; }; @@ -315,6 +343,8 @@ private String emptyMessageFor(final MarketSort sort) { return switch (sort) { case WINNERS -> "no winners right now"; case LOSERS -> "no losers right now"; + case BEST_WEEK -> "no stocks went up this week"; + case WORST_WEEK -> "no stocks went down this week"; case OWNED -> "you don't own any stocks yet"; default -> "no stocks match your search"; }; @@ -331,6 +361,10 @@ private Comparator comparatorFor(final MarketSort sort) { (Stock s) -> changePercent(s)).reversed(); case LOSERS -> Comparator.comparingDouble( (Stock s) -> changePercent(s)); + case BEST_WEEK -> Comparator.comparingDouble( + (Stock s) -> weekChangePercent(s)).reversed(); + case WORST_WEEK -> Comparator.comparingDouble( + (Stock s) -> weekChangePercent(s)); case OWNED -> Comparator.comparingInt( (Stock s) -> ownedLookup.applyAsInt(s.getSymbol())).reversed(); }; @@ -353,6 +387,24 @@ private double changePercent(final Stock stock) { return ((end - start) / start) * 100.0; } + /** + * Calculates the change percentage between the previous week's price + * and the current week's price. Each entry in the price history + * represents one week, so this is just the last two prices. + * */ + private double weekChangePercent(final Stock stock) { + List prices = stock.getHistoricalPrices(); + if (prices.size() < 2) { + return 0.0; + } + double previous = prices.get(prices.size() - 2).doubleValue(); + double current = prices.getLast().doubleValue(); + if (previous == 0.0) { + return 0.0; + } + return ((current - previous) / previous) * 100.0; + } + /** * Builds a single stock card. The card is clickable and forwards the * selection to the registered {@code onStockSelected} consumer.