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.