Repository: pajlads/DinkPlugin (java)

Issue:
WANT: Option to disable GE Prices
Hey! I love what you did with this plugin being an all in one and my only issue Id have to raise is that I am an ironman and don't really care about GE Prices being shown especially when depositing/withdrawing from group storage. So, If you could potentially add an option to disable these that would be fantastic! I also attached an image on exactly what I am talking about!
P.S. Id create a pull request for you but I do not have software to do this :(
![Screenshot_1](https://github.com/pajlads/DinkPlugin/assets/143108932/c212b4d2-992b-45c1-ae20-84587abffc8e)


Pull request description:
feat: add option to disable price in Group Storage notifications
This adds a new setting to the Group Storage notificer called "Price Type" ("Price type" in the screenshot, but has been fixed)
![image](https://github.com/pajlads/DinkPlugin/assets/962989/8c7b964d-2d1a-4a8a-928b-ce5dd7651f6b)

Available options are "Grand Exchange" and "None"
![image](https://github.com/pajlads/DinkPlugin/assets/962989/5efb710d-fed6-4af7-807b-19ef72010e6c)

Bit forward-thinking but I was thinking it could include the high alch price for some notifier in the future

This is what the notification looks like in Discord 
![image](https://github.com/pajlads/DinkPlugin/assets/962989/9f87f6af-4ce7-40e2-82fe-5b3830dfaad6)


This is what the JSON payload looks like:
```json5
{
  "type": "GROUP_STORAGE",
  "playerName": "dank dank",
  "accountType": "HARDCORE_GROUP_IRONMAN",
  "extra": {
    "deposits": [
      { "id": 1603, "quantity": 2, "priceEach": 900, "name": "Ruby" }
    ],
    "withdrawals": [
      { "id": 1609, "quantity": 1, "priceEach": 600, "name": "Opal" }
    ],
    "netValue": 1200,
    "groupName": "Dink QA"
  },
  "embeds": [
    {
      "title": "Group Shared Storage",
      "description": "```diff\ndank dank has deposited:\n+ 2 x Ruby\n\ndank dank has withdrawn:\n- 1 x Opal\n```",
      "author": {
        "name": "dank dank",
        "icon_url": "https://oldschool.runescape.wiki/images/Hardcore_group_ironman_chat_badge.png",
        "url": "https://secure.runescape.com/m\u003dhiscore_oldschool/hiscorepersonal?user1\u003ddank%20dank"
      },
      "color": 15990936,
      "thumbnail": {
        "url": "https://oldschool.runescape.wiki/images/Coins_10000.png"
      },
      "fields": [
        { "name": "Group", "value": "```\nDink QA\n```", "inline": true },
        {
          "name": "Net Value (GE)",
          "value": "```ldif\n1,200 gp\n```",
          "inline": true
        }
      ],
      "footer": {
        "text": "Powered by Dink",
        "icon_url": "https://github.com/pajlads/DinkPlugin/raw/master/icon.png"
      },
      "timestamp": "2023-08-24T16:17:02.019501Z"
    }
  ]
}
```

Fixes #297


Open questions:
How shit is my Java code?
I put the Price Type setting at the bottom, right above the Notification Message. it can still be moved. should it be? :ok_man: 
This does **not** yet disable the "Net Value" field. Should it?

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 83beede..37cc588 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
 ## Unreleased
 
+- Minor: Add option to disable price in Group Storage notifications. (#298)
 - Minor: Add `%TOTAL_LEVEL%` message template for level notifications. (#300)
 - Dev: Update gradle wrapper to v8.3 minor version. (#293)
 
diff --git a/src/main/java/dinkplugin/DinkPluginConfig.java b/src/main/java/dinkplugin/DinkPluginConfig.java
index 0e80dcb..a935fd6 100644
--- a/src/main/java/dinkplugin/DinkPluginConfig.java
+++ b/src/main/java/dinkplugin/DinkPluginConfig.java
@@ -1467,6 +1467,18 @@ public interface DinkPluginConfig extends Config {
         return true;
     }
 
+    @ConfigItem(
+        keyName = "groupStorageIncludePrice",
+        name = "Include Price",
+        description = "Whether price should be included on individual items,<br/>" +
+            "and a Net Value field generated for notifications",
+        position = 144,
+        section = groupStorageSection
+    )
+    default boolean groupStorageIncludePrice() {
+        return true;
+    }
+
     @ConfigItem(
         keyName = "groupStorageNotifyMessage",
         name = "Notification Message",
@@ -1474,7 +1486,7 @@ public interface DinkPluginConfig extends Config {
             "Use %USERNAME% to insert your username<br/>" +
             "Use %DEPOSITED% to insert the list of deposited items<br/>" +
             "Use %WITHDRAWN% to insert the list of withdrawn items",
-        position = 144,
+        position = 145,
         section = groupStorageSection
     )
     default String groupStorageNotifyMessage() {
diff --git a/src/main/java/dinkplugin/notifiers/ClueNotifier.java b/src/main/java/dinkplugin/notifiers/ClueNotifier.java
index 7be2276..b109dd7 100644
--- a/src/main/java/dinkplugin/notifiers/ClueNotifier.java
+++ b/src/main/java/dinkplugin/notifiers/ClueNotifier.java
@@ -140,7 +140,7 @@ public class ClueNotifier extends BaseNotifier {
     private Evaluable getItemMessage(SerializedItemStack item, Collection<Embed> embeds) {
         if (config.clueShowItems())
             embeds.add(Embed.ofImage(ItemUtils.getItemImageUrl(item.getId())));
-        return ItemUtils.templateStack(item);
+        return ItemUtils.templateStack(item, true);
     }
 
     private boolean checkClueTier(String clueType) {
diff --git a/src/main/java/dinkplugin/notifiers/GambleNotifier.java b/src/main/java/dinkplugin/notifiers/GambleNotifier.java
index e8b1404..3b7031a 100644
--- a/src/main/java/dinkplugin/notifiers/GambleNotifier.java
+++ b/src/main/java/dinkplugin/notifiers/GambleNotifier.java
@@ -88,7 +88,7 @@ public class GambleNotifier extends BaseNotifier {
 
     private static Evaluable lootSummary(List<SerializedItemStack> items) {
         JoiningReplacement.JoiningReplacementBuilder builder = JoiningReplacement.builder().delimiter("\n");
-        items.forEach(item -> builder.component(ItemUtils.templateStack(item)));
+        items.forEach(item -> builder.component(ItemUtils.templateStack(item, true)));
         return builder.build();
     }
 
diff --git a/src/main/java/dinkplugin/notifiers/GrandExchangeNotifier.java b/src/main/java/dinkplugin/notifiers/GrandExchangeNotifier.java
index 10c080b..c38ac48 100644
--- a/src/main/java/dinkplugin/notifiers/GrandExchangeNotifier.java
+++ b/src/main/java/dinkplugin/notifiers/GrandExchangeNotifier.java
@@ -107,7 +107,7 @@ public class GrandExchangeNotifier extends BaseNotifier {
             .replacementBoundary("%")
             .replacement("%USERNAME%", Replacements.ofText(playerName))
             .replacement("%TYPE%", Replacements.ofText(type.getDisplayName()))
-            .replacement("%ITEM%", ItemUtils.templateStack(item))
+            .replacement("%ITEM%", ItemUtils.templateStack(item, true))
             .replacement("%STATUS%", Replacements.ofText(getHumanStatus(offer.getState())))
             .build();
         createMessage(config.grandExchangeSendImage(), NotificationBody.builder()
diff --git a/src/main/java/dinkplugin/notifiers/GroupStorageNotifier.java b/src/main/java/dinkplugin/notifiers/GroupStorageNotifier.java
index a504618..a657b73 100644
--- a/src/main/java/dinkplugin/notifiers/GroupStorageNotifier.java
+++ b/src/main/java/dinkplugin/notifiers/GroupStorageNotifier.java
@@ -165,7 +165,7 @@ public class GroupStorageNotifier extends BaseNotifier {
         BiFunction<Collection<SerializedItemStack>, String, String> formatItems = (items, linePrefix) -> {
             if (items.isEmpty()) return EMPTY_TRANSACTION;
             return items.stream()
-                .map(ItemUtils::formatStack)
+                .map(n -> ItemUtils.formatStack(n, config.groupStorageIncludePrice()))
                 .collect(Collectors.joining('\n' + linePrefix, linePrefix, ""));
         };
         String depositString = formatItems.apply(deposits, "+ ");
@@ -188,7 +188,8 @@ public class GroupStorageNotifier extends BaseNotifier {
             deposits,
             withdrawals,
             netValue,
-            getGroupName()
+            getGroupName(),
+            config.groupStorageIncludePrice()
         );
 
         // Fire notification (delayed by a tick for screenshotHideChat reliability)
diff --git a/src/main/java/dinkplugin/notifiers/LootNotifier.java b/src/main/java/dinkplugin/notifiers/LootNotifier.java
index ca76356..ef1a7ff 100644
--- a/src/main/java/dinkplugin/notifiers/LootNotifier.java
+++ b/src/main/java/dinkplugin/notifiers/LootNotifier.java
@@ -141,7 +141,7 @@ public class LootNotifier extends BaseNotifier {
             long totalPrice = stack.getTotalPrice();
             if (totalPrice >= minValue) {
                 sendMessage = true;
-                lootMessage.component(ItemUtils.templateStack(stack));
+                lootMessage.component(ItemUtils.templateStack(stack, true));
                 if (icons) embeds.add(Embed.ofImage(ItemUtils.getItemImageUrl(item.getId())));
                 if (max == null || totalPrice > max.getTotalPrice()) {
                     max = stack;
diff --git a/src/main/java/dinkplugin/notifiers/data/GroupStorageNotificationData.java b/src/main/java/dinkplugin/notifiers/data/GroupStorageNotificationData.java
index 691a9aa..5ef440d 100644
--- a/src/main/java/dinkplugin/notifiers/data/GroupStorageNotificationData.java
+++ b/src/main/java/dinkplugin/notifiers/data/GroupStorageNotificationData.java
@@ -17,13 +17,16 @@ public class GroupStorageNotificationData extends NotificationData {
     Collection<SerializedItemStack> withdrawals;
     long netValue;
     String groupName;
+    transient boolean includePrice;
 
     @Override
     public List<Field> getFields() {
         List<Field> fields = new ArrayList<>(2);
         if (StringUtils.isNotBlank(groupName))
             fields.add(new Field("Group", Field.formatBlock(null, groupName)));
-        fields.add(new Field("Net Value (GE)", ItemUtils.formatGold(netValue)));
+        if (includePrice) {
+            fields.add(new Field("Net Value (GE)", ItemUtils.formatGold(netValue)));
+        }
         return fields;
     }
 }
diff --git a/src/main/java/dinkplugin/util/ItemUtils.java b/src/main/java/dinkplugin/util/ItemUtils.java
index e126f62..74385da 100644
--- a/src/main/java/dinkplugin/util/ItemUtils.java
+++ b/src/main/java/dinkplugin/util/ItemUtils.java
@@ -121,16 +121,28 @@ public class ItemUtils {
         return new SerializedItemStack(id, quantity, price, composition.getName());
     }
 
-    public String formatStack(SerializedItemStack item) {
-        return String.format("%d x %s (%s)", item.getQuantity(), item.getName(), QuantityFormatter.quantityToStackSize(item.getTotalPrice()));
+    public String formatStack(SerializedItemStack item, boolean includePrice) {
+        if (includePrice) {
+            return String.format("%d x %s (%s)", item.getQuantity(), item.getName(), QuantityFormatter.quantityToStackSize(item.getTotalPrice()));
+        }
+
+        return String.format("%d x %s", item.getQuantity(), item.getName());
     }
 
-    public Evaluable templateStack(SerializedItemStack item) {
+    public Evaluable templateStack(SerializedItemStack item, boolean includePrice) {
+        if (includePrice) {
+            return Replacements.ofMultiple("",
+                Replacements.ofText(String.valueOf(item.getQuantity())),
+                Replacements.ofText(" x "),
+                Replacements.ofWiki(item.getName()),
+                Replacements.ofText(" (" + QuantityFormatter.quantityToStackSize(item.getTotalPrice()) + ")")
+            );
+        }
+
         return Replacements.ofMultiple("",
             Replacements.ofText(String.valueOf(item.getQuantity())),
             Replacements.ofText(" x "),
-            Replacements.ofWiki(item.getName()),
-            Replacements.ofText(" (" + QuantityFormatter.quantityToStackSize(item.getTotalPrice()) + ")")
+            Replacements.ofWiki(item.getName())
         );
     }
 


Test patch:
diff --git a/src/test/java/dinkplugin/notifiers/GroupStorageNotifierTest.java b/src/test/java/dinkplugin/notifiers/GroupStorageNotifierTest.java
index a2a6300..6fb98ef 100644
--- a/src/test/java/dinkplugin/notifiers/GroupStorageNotifierTest.java
+++ b/src/test/java/dinkplugin/notifiers/GroupStorageNotifierTest.java
@@ -57,6 +57,7 @@ class GroupStorageNotifierTest extends MockedNotifierTest {
         when(config.notifyGroupStorage()).thenReturn(true);
         when(config.groupStorageSendImage()).thenReturn(false);
         when(config.groupStorageIncludeClan()).thenReturn(true);
+        when(config.groupStorageIncludePrice()).thenReturn(true);
         when(config.groupStorageNotifyMessage())
             .thenReturn("%USERNAME% has deposited:\n%DEPOSITED%\n\n%USERNAME% has withdrawn:\n%WITHDRAWN%");
 
@@ -94,12 +95,41 @@ class GroupStorageNotifierTest extends MockedNotifierTest {
             Collections.singletonList(new SerializedItemStack(ItemID.RUBY, 1, RUBY_PRICE, "Ruby")),
             Collections.singletonList(new SerializedItemStack(ItemID.OPAL, 1, OPAL_PRICE, "Opal")),
             RUBY_PRICE - OPAL_PRICE,
-            GROUP_NAME
+            GROUP_NAME,
+            true
         );
 
         verifyNotification(extra, "+ 1 x Ruby (" + RUBY_PRICE + ")", "- 1 x Opal (" + OPAL_PRICE + ")");
     }
 
+    @Test
+    void testNotifyNonePrice() {
+        when(config.groupStorageIncludePrice()).thenReturn(false);
+
+        // mock initial inventory state
+        Item[] initialItems = { new Item(ItemID.RUBY, 2), new Item(ItemID.TUNA, 1) };
+        mockContainer(initialItems);
+        notifier.onWidgetLoad(LOAD_EVENT);
+
+        // mock updated inventory
+        Item[] updatedItems = { new Item(ItemID.TUNA, 1), new Item(ItemID.OPAL, 1) };
+        mockContainer(updatedItems);
+
+        mockSaveWidget();
+        notifier.onWidgetClose(CLOSE_EVENT);
+
+        // verify notification message
+        GroupStorageNotificationData extra = new GroupStorageNotificationData(
+            Collections.singletonList(new SerializedItemStack(ItemID.RUBY, 2, RUBY_PRICE, "Ruby")),
+            Collections.singletonList(new SerializedItemStack(ItemID.OPAL, 1, OPAL_PRICE, "Opal")),
+            (2*RUBY_PRICE) - OPAL_PRICE,
+            GROUP_NAME,
+            false
+        );
+
+        verifyNotification(extra, "+ 2 x Ruby", "- 1 x Opal");
+    }
+
     @Test
     void testNotifyCoins() {
         // mock initial inventory state
@@ -119,7 +149,8 @@ class GroupStorageNotifierTest extends MockedNotifierTest {
             Collections.emptyList(),
             Collections.singletonList(new SerializedItemStack(ItemID.COINS_995, 900, 1, "Coins")),
             -900,
-            GROUP_NAME
+            GROUP_NAME,
+            true
         );
 
         verifyNotification(extra, EMPTY_TRANSACTION, "- 900 x Coins (900)");
@@ -144,7 +175,8 @@ class GroupStorageNotifierTest extends MockedNotifierTest {
             Collections.emptyList(),
             Collections.singletonList(new SerializedItemStack(ItemID.COINS_995, 800, 1, "Coins")),
             -800,
-            GROUP_NAME
+            GROUP_NAME,
+            true
         );
 
         verifyNotification(extra, EMPTY_TRANSACTION, "- 800 x Coins (800)");
@@ -168,7 +200,8 @@ class GroupStorageNotifierTest extends MockedNotifierTest {
             Arrays.asList(new SerializedItemStack(ItemID.RUBY, 1, RUBY_PRICE, "Ruby"), new SerializedItemStack(ItemID.OPAL, 1, OPAL_PRICE, "Opal")),
             Collections.emptyList(),
             RUBY_PRICE + OPAL_PRICE,
-            GROUP_NAME
+            GROUP_NAME,
+            true
         );
 
         verifyNotification(extra, "+ 1 x Ruby (" + RUBY_PRICE + ")\n+ 1 x Opal (" + OPAL_PRICE + ")", EMPTY_TRANSACTION);
@@ -192,7 +225,8 @@ class GroupStorageNotifierTest extends MockedNotifierTest {
             Collections.emptyList(),
             Arrays.asList(new SerializedItemStack(ItemID.RUBY, 1, RUBY_PRICE, "Ruby"), new SerializedItemStack(ItemID.OPAL, 1, OPAL_PRICE, "Opal")),
             -(RUBY_PRICE + OPAL_PRICE),
-            GROUP_NAME
+            GROUP_NAME,
+            true
         );
 
         verifyNotification(extra, EMPTY_TRANSACTION, "- 1 x Ruby (" + RUBY_PRICE + ")\n- 1 x Opal (" + OPAL_PRICE + ")");
@@ -217,7 +251,8 @@ class GroupStorageNotifierTest extends MockedNotifierTest {
             Collections.emptyList(),
             Collections.singletonList(new SerializedItemStack(ItemID.TUNA, 1, TUNA_PRICE, "Tuna")),
             -TUNA_PRICE,
-            GROUP_NAME
+            GROUP_NAME,
+            true
         );
 
         verifyNotification(extra, EMPTY_TRANSACTION, "- 1 x Tuna (" + TUNA_PRICE + ")");
@@ -245,7 +280,8 @@ class GroupStorageNotifierTest extends MockedNotifierTest {
             Collections.singletonList(new SerializedItemStack(ItemID.RUBY, 1, RUBY_PRICE, "Ruby")),
             Collections.singletonList(new SerializedItemStack(ItemID.OPAL, 1, OPAL_PRICE, "Opal")),
             RUBY_PRICE - OPAL_PRICE,
-            null
+            null,
+            true
         );
 
         verifyNotification(extra, "+ 1 x Ruby (" + RUBY_PRICE + ")", "- 1 x Opal (" + OPAL_PRICE + ")");