diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java index 6aaeea1977..d20ac8c1f0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerBox.java @@ -29,6 +29,10 @@ import com.google.common.base.Strings; import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridLayout; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.annotation.Nullable; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingConstants; @@ -39,14 +43,26 @@ import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.FontManager; import net.runelite.client.util.StackFormatter; -@Getter class LootTrackerBox extends JPanel { private static final int ITEMS_PER_ROW = 5; - private final long totalPrice; + private final JPanel itemContainer = new JPanel(); + private final JLabel priceLabel = new JLabel(); + private final JLabel subTitleLabel = new JLabel(); + private final ItemManager itemManager; + private final String id; - LootTrackerBox(final ItemManager itemManager, final String title, final String subTitle, final LootTrackerItemEntry[] items) + @Getter + private final List records = new ArrayList<>(); + + @Getter + private long totalPrice; + + LootTrackerBox(final ItemManager itemManager, final String id, @Nullable final String subtitle) { + this.id = id; + this.itemManager = itemManager; + setLayout(new BorderLayout(0, 1)); setBorder(new EmptyBorder(5, 0, 0, 0)); @@ -54,43 +70,140 @@ class LootTrackerBox extends JPanel logTitle.setBorder(new EmptyBorder(7, 7, 7, 7)); logTitle.setBackground(ColorScheme.DARKER_GRAY_COLOR.darker()); - final JLabel titleLabel = new JLabel(title); + final JLabel titleLabel = new JLabel(id); titleLabel.setFont(FontManager.getRunescapeSmallFont()); titleLabel.setForeground(Color.WHITE); logTitle.add(titleLabel, BorderLayout.WEST); // If we have subtitle, add it - if (!Strings.isNullOrEmpty(subTitle)) + if (!Strings.isNullOrEmpty(subtitle)) { - final JLabel subTitleLabel = new JLabel(subTitle); + subTitleLabel.setText(subtitle); subTitleLabel.setFont(FontManager.getRunescapeSmallFont()); subTitleLabel.setForeground(ColorScheme.LIGHT_GRAY_COLOR); logTitle.add(subTitleLabel, BorderLayout.CENTER); } - totalPrice = calculatePrice(items); + priceLabel.setFont(FontManager.getRunescapeSmallFont()); + priceLabel.setForeground(ColorScheme.LIGHT_GRAY_COLOR); + logTitle.add(priceLabel, BorderLayout.EAST); - if (totalPrice > 0) + add(logTitle, BorderLayout.NORTH); + add(itemContainer, BorderLayout.CENTER); + } + + int getTotalKills() + { + return records.size(); + } + + /** + * Checks if this box matches specified record + * @param record loot record + * @return true if match is made + */ + boolean matches(final LootTrackerRecord record) + { + return record.getTitle().equals(id); + } + + /** + * Checks if this box matches specified id + * @param id other record id + * @return true if match is made + */ + boolean matches(final String id) + { + if (id == null) { - final JLabel priceLabel = new JLabel(StackFormatter.quantityToStackSize(totalPrice) + " gp"); - priceLabel.setFont(FontManager.getRunescapeSmallFont()); - priceLabel.setForeground(ColorScheme.LIGHT_GRAY_COLOR); - logTitle.add(priceLabel, BorderLayout.EAST); + return true; } + return this.id.equals(id); + } + + /** + * Adds an record's data into a loot box. + * This will add new items to the list, re-calculating price and kill count. + */ + void combine(final LootTrackerRecord record) + { + if (!matches(record)) + { + throw new IllegalArgumentException(record.toString()); + } + + records.add(record); + buildItems(); + + priceLabel.setText(StackFormatter.quantityToStackSize(totalPrice) + " gp"); + if (records.size() > 1) + { + subTitleLabel.setText("x " + records.size()); + } + + repaint(); + } + + /** + * This method creates stacked items from the item list, calculates total price and then + * displays all the items in the UI. + */ + private void buildItems() + { + final List allItems = new ArrayList<>(); + final List items = new ArrayList<>(); + totalPrice = 0; + + for (LootTrackerRecord records : records) + { + allItems.addAll(Arrays.asList(records.getItems())); + } + + for (final LootTrackerItem entry : allItems) + { + totalPrice += entry.getPrice(); + + int quantity = 0; + for (final LootTrackerItem i : items) + { + if (i.getId() == entry.getId()) + { + quantity = i.getQuantity(); + items.remove(i); + break; + } + } + if (quantity > 0) + { + int newQuantity = entry.getQuantity() + quantity; + long pricePerItem = entry.getPrice() == 0 ? 0 : (entry.getPrice() / entry.getQuantity()); + + items.add(new LootTrackerItem(entry.getId(), entry.getName(), newQuantity, pricePerItem * newQuantity)); + } + else + { + items.add(entry); + } + } + + items.sort((i1, i2) -> Long.compare(i2.getPrice(), i1.getPrice())); + // Calculates how many rows need to be display to fit all items - final int rowSize = ((items.length % ITEMS_PER_ROW == 0) ? 0 : 1) + items.length / ITEMS_PER_ROW; - final JPanel itemContainer = new JPanel(new GridLayout(rowSize, ITEMS_PER_ROW, 1, 1)); + final int rowSize = ((items.size() % ITEMS_PER_ROW == 0) ? 0 : 1) + items.size() / ITEMS_PER_ROW; + + itemContainer.removeAll(); + itemContainer.setLayout(new GridLayout(rowSize, ITEMS_PER_ROW, 1, 1)); for (int i = 0; i < rowSize * ITEMS_PER_ROW; i++) { final JPanel slotContainer = new JPanel(); slotContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR); - if (i < items.length) + if (i < items.size()) { - final LootTrackerItemEntry item = items[i]; + final LootTrackerItem item = items.get(i); final JLabel imageLabel = new JLabel(); imageLabel.setToolTipText(buildToolTip(item)); imageLabel.setVerticalAlignment(SwingConstants.CENTER); @@ -102,26 +215,14 @@ class LootTrackerBox extends JPanel itemContainer.add(slotContainer); } - add(logTitle, BorderLayout.NORTH); - add(itemContainer, BorderLayout.CENTER); + itemContainer.repaint(); } - private String buildToolTip(LootTrackerItemEntry item) + private static String buildToolTip(LootTrackerItem item) { final String name = item.getName(); final int quantity = item.getQuantity(); final long price = item.getPrice(); - return name + " x " + quantity + " (" + StackFormatter.quantityToStackSize(price) + ")"; } - - private static long calculatePrice(final LootTrackerItemEntry[] itemStacks) - { - long total = 0; - for (LootTrackerItemEntry itemStack : itemStacks) - { - total += itemStack.getPrice(); - } - return total; - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerItemEntry.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerItem.java similarity index 98% rename from runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerItemEntry.java rename to runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerItem.java index 3d18ce9c0b..9e3a36ad86 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerItemEntry.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerItem.java @@ -27,7 +27,7 @@ package net.runelite.client.plugins.loottracker; import lombok.Value; @Value -class LootTrackerItemEntry +class LootTrackerItem { private final int id; private final String name; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java index 88b83775d2..2df6499d18 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPanel.java @@ -26,8 +26,15 @@ package net.runelite.client.plugins.loottracker; import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; import java.awt.GridLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; +import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JLabel; @@ -41,17 +48,27 @@ import net.runelite.client.ui.FontManager; import net.runelite.client.ui.PluginPanel; import net.runelite.client.ui.components.PluginErrorPanel; import net.runelite.client.util.ColorUtil; +import net.runelite.client.util.ImageUtil; import net.runelite.client.util.StackFormatter; class LootTrackerPanel extends PluginPanel { + private static final ImageIcon SINGLE_LOOT_VIEW; + private static final ImageIcon SINGLE_LOOT_VIEW_FADED; + private static final ImageIcon SINGLE_LOOT_VIEW_HOVER; + private static final ImageIcon GROUPED_LOOT_VIEW; + private static final ImageIcon GROUPED_LOOT_VIEW_FADED; + private static final ImageIcon GROUPED_LOOT_VIEW_HOVER; + private static final ImageIcon BACK_ARROW_ICON; + private static final ImageIcon BACK_ARROW_ICON_HOVER; + private static final String HTML_LABEL_TEMPLATE = "%s%s"; // When there is no loot, display this private final PluginErrorPanel errorPanel = new PluginErrorPanel(); - // Handle loot logs + // Handle loot boxes private final JPanel logsContainer = new JPanel(); // Handle overall session data @@ -59,9 +76,39 @@ class LootTrackerPanel extends PluginPanel private final JLabel overallKillsLabel = new JLabel(); private final JLabel overallGpLabel = new JLabel(); private final JLabel overallIcon = new JLabel(); + + // Details and navigation + private final JPanel actionsContainer = new JPanel(); + private final JLabel detailsTitle = new JLabel(); + private final JLabel backBtn = new JLabel(); + private final JLabel singleLootBtn = new JLabel(); + private final JLabel groupedLootBtn = new JLabel(); + + // Log collection + private final List records = new ArrayList<>(); + private final List boxes = new ArrayList<>(); + private final ItemManager itemManager; - private int overallKills; - private int overallGp; + private boolean groupLoot; + private String currentView; + + static + { + final BufferedImage singleLootImg = ImageUtil.getResourceStreamFromClass(LootTrackerPlugin.class, "single_loot_icon.png"); + final BufferedImage groupedLootImg = ImageUtil.getResourceStreamFromClass(LootTrackerPlugin.class, "grouped_loot_icon.png"); + final BufferedImage backArrowImg = ImageUtil.getResourceStreamFromClass(LootTrackerPlugin.class, "back_icon.png"); + + SINGLE_LOOT_VIEW = new ImageIcon(singleLootImg); + SINGLE_LOOT_VIEW_FADED = new ImageIcon(ImageUtil.alphaOffset(singleLootImg, -180)); + SINGLE_LOOT_VIEW_HOVER = new ImageIcon(ImageUtil.alphaOffset(singleLootImg, -220)); + + GROUPED_LOOT_VIEW = new ImageIcon(groupedLootImg); + GROUPED_LOOT_VIEW_FADED = new ImageIcon(ImageUtil.alphaOffset(groupedLootImg, -180)); + GROUPED_LOOT_VIEW_HOVER = new ImageIcon(ImageUtil.alphaOffset(groupedLootImg, -220)); + + BACK_ARROW_ICON = new ImageIcon(backArrowImg); + BACK_ARROW_ICON_HOVER = new ImageIcon(ImageUtil.alphaOffset(backArrowImg, -180)); + } LootTrackerPanel(final ItemManager itemManager) { @@ -75,8 +122,104 @@ class LootTrackerPanel extends PluginPanel layoutPanel.setLayout(new BoxLayout(layoutPanel, BoxLayout.Y_AXIS)); add(layoutPanel, BorderLayout.NORTH); + actionsContainer.setLayout(new BorderLayout()); + actionsContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR); + actionsContainer.setPreferredSize(new Dimension(0, 30)); + actionsContainer.setBorder(new EmptyBorder(5, 5, 5, 10)); + actionsContainer.setVisible(false); + + final JPanel viewControls = new JPanel(new GridLayout(1, 2, 10, 0)); + viewControls.setBackground(ColorScheme.DARKER_GRAY_COLOR); + + singleLootBtn.setIcon(SINGLE_LOOT_VIEW); + singleLootBtn.setToolTipText("Show each kill separately"); + singleLootBtn.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent mouseEvent) + { + changeGrouping(false); + } + + @Override + public void mouseExited(MouseEvent mouseEvent) + { + singleLootBtn.setIcon(groupLoot ? SINGLE_LOOT_VIEW_FADED : SINGLE_LOOT_VIEW); + } + + @Override + public void mouseEntered(MouseEvent mouseEvent) + { + singleLootBtn.setIcon(groupLoot ? SINGLE_LOOT_VIEW_HOVER : SINGLE_LOOT_VIEW); + } + }); + + groupedLootBtn.setIcon(GROUPED_LOOT_VIEW); + groupedLootBtn.setToolTipText("Group loot by source"); + groupedLootBtn.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent mouseEvent) + { + changeGrouping(true); + } + + @Override + public void mouseExited(MouseEvent mouseEvent) + { + groupedLootBtn.setIcon(groupLoot ? GROUPED_LOOT_VIEW : GROUPED_LOOT_VIEW_FADED); + } + + @Override + public void mouseEntered(MouseEvent mouseEvent) + { + groupedLootBtn.setIcon(groupLoot ? GROUPED_LOOT_VIEW : GROUPED_LOOT_VIEW_HOVER); + } + }); + + viewControls.add(groupedLootBtn); + viewControls.add(singleLootBtn); + changeGrouping(true); + + final JPanel leftTitleContainer = new JPanel(new BorderLayout(5, 0)); + leftTitleContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR); + + detailsTitle.setForeground(Color.WHITE); + + backBtn.setIcon(BACK_ARROW_ICON); + backBtn.setVisible(false); + backBtn.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent mouseEvent) + { + currentView = null; + backBtn.setVisible(false); + detailsTitle.setText(""); + rebuild(); + } + + @Override + public void mouseExited(MouseEvent mouseEvent) + { + backBtn.setIcon(BACK_ARROW_ICON); + } + + @Override + public void mouseEntered(MouseEvent mouseEvent) + { + backBtn.setIcon(BACK_ARROW_ICON_HOVER); + } + }); + + leftTitleContainer.add(backBtn, BorderLayout.WEST); + leftTitleContainer.add(detailsTitle, BorderLayout.CENTER); + + actionsContainer.add(leftTitleContainer, BorderLayout.WEST); + actionsContainer.add(viewControls, BorderLayout.EAST); + // Create panel that will contain overall data - overallPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); + overallPanel.setBorder(new EmptyBorder(8, 10, 8, 10)); overallPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); overallPanel.setLayout(new BorderLayout()); overallPanel.setVisible(false); @@ -85,7 +228,7 @@ class LootTrackerPanel extends PluginPanel final JPanel overallInfo = new JPanel(); overallInfo.setBackground(ColorScheme.DARKER_GRAY_COLOR); overallInfo.setLayout(new GridLayout(2, 1)); - overallInfo.setBorder(new EmptyBorder(0, 10, 0, 0)); + overallInfo.setBorder(new EmptyBorder(2, 10, 2, 0)); overallKillsLabel.setFont(FontManager.getRunescapeSmallFont()); overallGpLabel.setFont(FontManager.getRunescapeSmallFont()); overallInfo.add(overallKillsLabel); @@ -97,8 +240,9 @@ class LootTrackerPanel extends PluginPanel final JMenuItem reset = new JMenuItem("Reset All"); reset.addActionListener(e -> { - overallKills = 0; - overallGp = 0; + // If not in detailed view, remove all, otherwise only remove for the currently detailed title + records.removeIf(r -> r.matches(currentView)); + boxes.removeIf(b -> b.matches(currentView)); updateOverall(); logsContainer.removeAll(); logsContainer.repaint(); @@ -110,8 +254,10 @@ class LootTrackerPanel extends PluginPanel popupMenu.add(reset); overallPanel.setComponentPopupMenu(popupMenu); - // Create loot logs wrapper + // Create loot boxes wrapper logsContainer.setLayout(new BoxLayout(logsContainer, BoxLayout.Y_AXIS)); + layoutPanel.add(actionsContainer); + layoutPanel.add(Box.createRigidArea(new Dimension(0, 5))); layoutPanel.add(overallPanel); layoutPanel.add(logsContainer); @@ -125,50 +271,129 @@ class LootTrackerPanel extends PluginPanel overallIcon.setIcon(new ImageIcon(img)); } - private static String htmlLabel(String key, long value) + /** + * Adds a new entry to the plugin. + * Creates a subtitle, adds a new entry and then passes off to the render methods, that will decide + * how to display this new data. + */ + void add(final String eventName, final int actorLevel, LootTrackerItem[] items) { - final String valueStr = StackFormatter.quantityToStackSize(value); - return String.format(HTML_LABEL_TEMPLATE, ColorUtil.toHexColor(ColorScheme.LIGHT_GRAY_COLOR), key, valueStr); + final String subTitle = actorLevel > -1 ? "(lvl-" + actorLevel + ")" : ""; + final LootTrackerRecord record = new LootTrackerRecord(eventName, subTitle, items, System.currentTimeMillis()); + records.add(record); + buildBox(record); } - void addLog(final String eventName, final int actorLevel, LootTrackerItemEntry[] items) + /** + * Changes grouping mode of panel + * @param group if loot should be grouped or not + */ + private void changeGrouping(boolean group) { - // Remove error and show overall + groupLoot = group; + rebuild(); + groupedLootBtn.setIcon(group ? GROUPED_LOOT_VIEW : GROUPED_LOOT_VIEW_FADED); + singleLootBtn.setIcon(group ? SINGLE_LOOT_VIEW_FADED : SINGLE_LOOT_VIEW); + } + + /** + * Rebuilds all the boxes from scratch using existing listed records, depending on the grouping mode. + */ + private void rebuild() + { + logsContainer.removeAll(); + boxes.clear(); + records.forEach(this::buildBox); + updateOverall(); + logsContainer.revalidate(); + logsContainer.repaint(); + } + + /** + * This method decides what to do with a new record, if a similar log exists, it will + * add its items to it, updating the log's overall price and kills. If not, a new log will be created + * to hold this entry's information. + */ + private void buildBox(LootTrackerRecord record) + { + // If this record is not part of current view, return + if (!record.matches(currentView)) + { + return; + } + + // Group all similar loot together + if (groupLoot) + { + for (LootTrackerBox box : boxes) + { + if (box.matches(record)) + { + box.combine(record); + updateOverall(); + return; + } + } + } + + // Show main view remove(errorPanel); + actionsContainer.setVisible(true); overallPanel.setVisible(true); // Create box - final String subTitle = actorLevel > -1 ? "(lvl-" + actorLevel + ")" : ""; - final LootTrackerBox box = new LootTrackerBox(itemManager, eventName, subTitle, items); - logsContainer.add(box, 0); - logsContainer.repaint(); + final LootTrackerBox box = new LootTrackerBox(itemManager, record.getTitle(), record.getSubTitle()); + box.combine(record); - // Update overall - overallGp += box.getTotalPrice(); - overallKills += 1; - updateOverall(); + // Create popup menu + final JPopupMenu popupMenu = new JPopupMenu(); + popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5)); + box.setComponentPopupMenu(popupMenu); // Create reset menu final JMenuItem reset = new JMenuItem("Reset"); reset.addActionListener(e -> { - overallGp -= box.getTotalPrice(); - overallKills -= 1; + records.removeAll(box.getRecords()); + boxes.remove(box); updateOverall(); logsContainer.remove(box); logsContainer.repaint(); }); - // Create popup menu - final JPopupMenu popupMenu = new JPopupMenu(); - popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5)); popupMenu.add(reset); - box.setComponentPopupMenu(popupMenu); + + // Create details menu + final JMenuItem details = new JMenuItem("View details"); + details.addActionListener(e -> + { + currentView = record.getTitle(); + detailsTitle.setText(currentView); + backBtn.setVisible(true); + rebuild(); + }); + + popupMenu.add(details); + + // Add box to panel + boxes.add(box); + logsContainer.add(box, 0); + + // Update overall + updateOverall(); } private void updateOverall() { + final long overallGp = boxes.stream().mapToLong(LootTrackerBox::getTotalPrice).sum(); + final int overallKills = boxes.stream().mapToInt(LootTrackerBox::getTotalKills).sum(); overallKillsLabel.setText(htmlLabel("Total count: ", overallKills)); overallGpLabel.setText(htmlLabel("Total value: ", overallGp)); } + + private static String htmlLabel(String key, long value) + { + final String valueStr = StackFormatter.quantityToStackSize(value); + return String.format(HTML_LABEL_TEMPLATE, ColorUtil.toHexColor(ColorScheme.LIGHT_GRAY_COLOR), key, valueStr); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index 9c359bad1d..2c75c0fd55 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -150,8 +150,8 @@ public class LootTrackerPlugin extends Plugin final Collection items = npcLootReceived.getItems(); final String name = npc.getName(); final int combat = npc.getCombatLevel(); - final LootTrackerItemEntry[] entries = buildEntries(stack(items)); - SwingUtilities.invokeLater(() -> panel.addLog(name, combat, entries)); + final LootTrackerItem[] entries = buildEntries(stack(items)); + SwingUtilities.invokeLater(() -> panel.add(name, combat, entries)); } @Subscribe @@ -161,8 +161,8 @@ public class LootTrackerPlugin extends Plugin final Collection items = playerLootReceived.getItems(); final String name = player.getName(); final int combat = player.getCombatLevel(); - final LootTrackerItemEntry[] entries = buildEntries(stack(items)); - SwingUtilities.invokeLater(() -> panel.addLog(name, combat, entries)); + final LootTrackerItem[] entries = buildEntries(stack(items)); + SwingUtilities.invokeLater(() -> panel.add(name, combat, entries)); } @Subscribe @@ -209,8 +209,8 @@ public class LootTrackerPlugin extends Plugin if (!items.isEmpty()) { - final LootTrackerItemEntry[] entries = buildEntries(stack(items)); - SwingUtilities.invokeLater(() -> panel.addLog(eventType, -1, entries)); + final LootTrackerItem[] entries = buildEntries(stack(items)); + SwingUtilities.invokeLater(() -> panel.add(eventType, -1, entries)); } else { @@ -252,19 +252,19 @@ public class LootTrackerPlugin extends Plugin } } - private LootTrackerItemEntry[] buildEntries(final Collection itemStacks) + private LootTrackerItem[] buildEntries(final Collection itemStacks) { return itemStacks.stream().map(itemStack -> { final ItemComposition itemComposition = itemManager.getItemComposition(itemStack.getId()); final int realItemId = itemComposition.getNote() != -1 ? itemComposition.getLinkedNoteId() : itemStack.getId(); - final long price = (long)itemManager.getItemPrice(realItemId) * (long)itemStack.getQuantity(); + final long price = (long) itemManager.getItemPrice(realItemId) * (long) itemStack.getQuantity(); - return new LootTrackerItemEntry( + return new LootTrackerItem( itemStack.getId(), itemComposition.getName(), itemStack.getQuantity(), price); - }).toArray(LootTrackerItemEntry[]::new); + }).toArray(LootTrackerItem[]::new); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java new file mode 100644 index 0000000000..0d75ec70c3 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018, Psikoi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.loottracker; + +import lombok.Value; + +@Value +class LootTrackerRecord +{ + private final String title; + private final String subTitle; + private final LootTrackerItem[] items; + private final long timestamp; + + /** + * Checks if this record matches specified id + * @param id other record id + * @return true if match is made + */ + boolean matches(final String id) + { + if (id == null) + { + return true; + } + + return title.equals(id); + } +} \ No newline at end of file diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/loottracker/back_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/loottracker/back_icon.png new file mode 100644 index 0000000000..96b9200f60 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/loottracker/back_icon.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/loottracker/grouped_loot_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/loottracker/grouped_loot_icon.png new file mode 100644 index 0000000000..5827719316 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/loottracker/grouped_loot_icon.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/loottracker/single_loot_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/loottracker/single_loot_icon.png new file mode 100644 index 0000000000..6c2214da99 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/loottracker/single_loot_icon.png differ