diff --git a/src/main/java/world/bentobox/challenges/panel/util/ChallengeSelector.java b/src/main/java/world/bentobox/challenges/panel/util/ChallengeSelector.java index ab70595..c582e76 100644 --- a/src/main/java/world/bentobox/challenges/panel/util/ChallengeSelector.java +++ b/src/main/java/world/bentobox/challenges/panel/util/ChallengeSelector.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.BiConsumer; +import java.util.stream.Collectors; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -35,6 +36,7 @@ public class ChallengeSelector extends PagedSelector this.elements = challengesDescriptionMap.keySet().stream().toList(); this.selectedElements = new HashSet<>(this.elements.size()); + this.filterElements = this.elements; } @@ -61,7 +63,7 @@ public class ChallengeSelector extends PagedSelector GuiUtils.fillBorder(panelBuilder, this.border); - this.populateElements(panelBuilder, this.elements); + this.populateElements(panelBuilder, this.filterElements); panelBuilder.item(3, this.createButton(Button.ACCEPT_SELECTED)); panelBuilder.item(5, this.createButton(Button.CANCEL)); @@ -70,6 +72,32 @@ public class ChallengeSelector extends PagedSelector } + /** + * This method is called when filter value is updated. + */ + @Override + protected void updateFilters() + { + if (this.searchString == null || this.searchString.isBlank()) + { + this.filterElements = this.elements; + } + else + { + this.filterElements = this.elements.stream(). + filter(element -> { + // If element name is set and name contains search field, then do not filter out. + return element.getUniqueId().toLowerCase(). + contains(this.searchString.toLowerCase()) || + element.getFriendlyName().toLowerCase(). + contains(this.searchString.toLowerCase()); + }). + distinct(). + collect(Collectors.toList()); + } + } + + /** * This method creates PanelItem button of requested type. * @param button Button which must be created. @@ -218,4 +246,9 @@ public class ChallengeSelector extends PagedSelector * Border Material. */ private final Material border; + + /** + * Current value. + */ + private List filterElements; } diff --git a/src/main/java/world/bentobox/challenges/panel/util/MultiBlockSelector.java b/src/main/java/world/bentobox/challenges/panel/util/MultiBlockSelector.java index 37ffe5b..d945f6e 100644 --- a/src/main/java/world/bentobox/challenges/panel/util/MultiBlockSelector.java +++ b/src/main/java/world/bentobox/challenges/panel/util/MultiBlockSelector.java @@ -58,7 +58,11 @@ public class MultiBlockSelector extends PagedSelector } } }). + // Sort by name + sorted(Comparator.comparing(Material::name)). collect(Collectors.toList()); + // Init without filters applied. + this.filterElements = this.elements; } @@ -102,7 +106,7 @@ public class MultiBlockSelector extends PagedSelector GuiUtils.fillBorder(panelBuilder, Material.BLUE_STAINED_GLASS_PANE); - this.populateElements(panelBuilder, this.elements); + this.populateElements(panelBuilder, this.filterElements); panelBuilder.item(3, this.createButton(Button.ACCEPT_SELECTED)); panelBuilder.item(5, this.createButton(Button.CANCEL)); @@ -111,6 +115,29 @@ public class MultiBlockSelector extends PagedSelector } + /** + * This method is called when filter value is updated. + */ + @Override + protected void updateFilters() + { + if (this.searchString == null || this.searchString.isBlank()) + { + this.filterElements = this.elements; + } + else + { + this.filterElements = this.elements.stream(). + filter(element -> { + // If element name is set and name contains search field, then do not filter out. + return element.name().toLowerCase().contains(this.searchString.toLowerCase()); + }). + distinct(). + collect(Collectors.toList()); + } + } + + /** * This method creates PanelItem button of requested type. * @param button Button which must be created. @@ -260,4 +287,9 @@ public class MultiBlockSelector extends PagedSelector * This variable stores consumer. */ private final BiConsumer> consumer; + + /** + * Stores filtered items. + */ + private List filterElements; } diff --git a/src/main/java/world/bentobox/challenges/panel/util/MultiEntitySelector.java b/src/main/java/world/bentobox/challenges/panel/util/MultiEntitySelector.java index 1cb6c3d..affd355 100644 --- a/src/main/java/world/bentobox/challenges/panel/util/MultiEntitySelector.java +++ b/src/main/java/world/bentobox/challenges/panel/util/MultiEntitySelector.java @@ -43,7 +43,11 @@ public class MultiEntitySelector extends PagedSelector return true; } }). + // Sort by name + sorted(Comparator.comparing(EntityType::name)). collect(Collectors.toList()); + // Init without filters applied. + this.filterElements = this.elements; } @@ -86,7 +90,7 @@ public class MultiEntitySelector extends PagedSelector GuiUtils.fillBorder(panelBuilder, Material.BLUE_STAINED_GLASS_PANE); - this.populateElements(panelBuilder, this.elements); + this.populateElements(panelBuilder, this.filterElements); panelBuilder.item(3, this.createButton(Button.ACCEPT_SELECTED)); panelBuilder.item(5, this.createButton(Button.CANCEL)); @@ -95,6 +99,29 @@ public class MultiEntitySelector extends PagedSelector } + /** + * This method is called when filter value is updated. + */ + @Override + protected void updateFilters() + { + if (this.searchString == null || this.searchString.isBlank()) + { + this.filterElements = this.elements; + } + else + { + this.filterElements = this.elements.stream(). + filter(element -> { + // If element name is set and name contains search field, then do not filter out. + return element.name().toLowerCase().contains(this.searchString.toLowerCase()); + }). + distinct(). + collect(Collectors.toList()); + } + } + + /** * This method creates PanelItem button of requested type. * @param button Button which must be created. @@ -248,4 +275,9 @@ public class MultiEntitySelector extends PagedSelector * Indicates that entity must be displayed as egg. */ private final boolean asEgg; + + /** + * Stores filtered items. + */ + private List filterElements; } diff --git a/src/main/java/world/bentobox/challenges/panel/util/PagedSelector.java b/src/main/java/world/bentobox/challenges/panel/util/PagedSelector.java index af6c6d9..31d00a4 100644 --- a/src/main/java/world/bentobox/challenges/panel/util/PagedSelector.java +++ b/src/main/java/world/bentobox/challenges/panel/util/PagedSelector.java @@ -11,11 +11,13 @@ import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import world.bentobox.bentobox.api.panels.PanelItem; import world.bentobox.bentobox.api.panels.builders.PanelBuilder; import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder; import world.bentobox.bentobox.api.user.User; +import world.bentobox.challenges.panel.ConversationUtils; import world.bentobox.challenges.utils.Constants; @@ -32,6 +34,7 @@ public abstract class PagedSelector protected PagedSelector(User user) { this.user = user; + this.searchString = ""; } @@ -50,6 +53,12 @@ public abstract class PagedSelector protected abstract PanelItem createElementButton(T object); + /** + * This method is called when filter value is updated. + */ + protected abstract void updateFilters(); + + /** * Populate elements. * @@ -87,16 +96,26 @@ public abstract class PagedSelector index++; } + // Add next page button if there are more than MAX_ELEMENTS objects and pageIndex + 1 is + // larger or equal to the max page count. if (size > MAX_ELEMENTS && !(1.0 * size / MAX_ELEMENTS <= this.pageIndex + 1)) { panelBuilder.item(26, this.getButton(CommonButtons.NEXT)); } + // Add previous page button if pageIndex is not 0. if (this.pageIndex > 0) { panelBuilder.item(18, this.getButton(CommonButtons.PREVIOUS)); } + + // Add search button only if there is more than MAX_ELEMENTS objects or searchString + // is not blank. + if (!this.searchString.isBlank() || objectList.size() > MAX_ELEMENTS) + { + panelBuilder.item(40, this.getButton(CommonButtons.SEARCH)); + } } @@ -120,6 +139,9 @@ public abstract class PagedSelector description.add(this.user.getTranslation(reference + "description", Constants.PARAMETER_NUMBER, String.valueOf(this.pageIndex + 2))); + description.add(""); + description.add(this.user.getTranslation(Constants.TIPS + "click-to-next")); + icon = new ItemStack(Material.OAK_SIGN, this.pageIndex + 2); clickHandler = (panel, user, clickType, slot) -> { @@ -133,6 +155,9 @@ public abstract class PagedSelector description.add(this.user.getTranslation(reference + "description", Constants.PARAMETER_NUMBER, String.valueOf(this.pageIndex))); + description.add(""); + description.add(this.user.getTranslation(Constants.TIPS + "click-to-previous")); + icon = new ItemStack(Material.OAK_SIGN, Math.max(1, this.pageIndex)); clickHandler = (panel, user, clickType, slot) -> { @@ -141,6 +166,59 @@ public abstract class PagedSelector return true; }; } + else if (button == CommonButtons.SEARCH) + { + description.add(this.user.getTranslation(reference + "description")); + + if (this.searchString != null && !this.searchString.isEmpty()) + { + description.add(this.user.getTranslation(reference + "search", + Constants.PARAMETER_VALUE, this.searchString)); + } + + description.add(""); + description.add(this.user.getTranslation(Constants.TIPS + "left-click-to-edit")); + + if (!this.searchString.isEmpty()) + { + description.add(this.user.getTranslation(Constants.TIPS + "right-click-to-clear")); + } + + icon = new ItemStack(Material.ANVIL); + + clickHandler = (panel, user, clickType, slot) -> { + if (clickType.isRightClick()) + { + // Clear string. + this.searchString = ""; + this.updateFilters(); + // Rebuild gui. + this.build(); + } + else + { + // Create consumer that process description change + Consumer consumer = value -> + { + if (value != null) + { + this.searchString = value; + this.updateFilters(); + } + + this.build(); + }; + + // start conversation + ConversationUtils.createStringInput(consumer, + user, + user.getTranslation(Constants.CONVERSATIONS + "write-search"), + user.getTranslation(Constants.CONVERSATIONS + "search-updated")); + } + + return true; + }; + } else { icon = new ItemStack(Material.PAPER); @@ -162,7 +240,8 @@ public abstract class PagedSelector private enum CommonButtons { NEXT, - PREVIOUS + PREVIOUS, + SEARCH } @@ -175,4 +254,9 @@ public abstract class PagedSelector * User who opens gui. */ protected final User user; + + /** + * Text that contains filter string. + */ + protected String searchString; } diff --git a/src/main/java/world/bentobox/challenges/panel/util/SingleBlockSelector.java b/src/main/java/world/bentobox/challenges/panel/util/SingleBlockSelector.java index 50092ef..2400722 100644 --- a/src/main/java/world/bentobox/challenges/panel/util/SingleBlockSelector.java +++ b/src/main/java/world/bentobox/challenges/panel/util/SingleBlockSelector.java @@ -38,6 +38,7 @@ public class SingleBlockSelector extends PagedSelector // Barrier cannot be accessible to user. excluded.add(Material.BARRIER); + excluded.add(Material.STRUCTURE_VOID); this.elements = Arrays.stream(Material.values()). filter(material -> !excluded.contains(material)). @@ -55,7 +56,11 @@ public class SingleBlockSelector extends PagedSelector } } }). + // Sort by name + sorted(Comparator.comparing(Material::name)). collect(Collectors.toList()); + // Init without filters applied. + this.filterElements = this.elements; } @@ -103,6 +108,7 @@ public class SingleBlockSelector extends PagedSelector /** * This method builds all necessary elements in GUI panel. */ + @Override protected void build() { PanelBuilder panelBuilder = new PanelBuilder().user(this.user); @@ -110,7 +116,7 @@ public class SingleBlockSelector extends PagedSelector GuiUtils.fillBorder(panelBuilder, Material.BLUE_STAINED_GLASS_PANE); - this.populateElements(panelBuilder, this.elements); + this.populateElements(panelBuilder, this.filterElements); panelBuilder.item(4, this.createButton()); @@ -118,6 +124,29 @@ public class SingleBlockSelector extends PagedSelector } + /** + * This method is called when filter value is updated. + */ + @Override + protected void updateFilters() + { + if (this.searchString == null || this.searchString.isBlank()) + { + this.filterElements = this.elements; + } + else + { + this.filterElements = this.elements.stream(). + filter(element -> { + // If element name is set and name contains search field, then do not filter out. + return element.name().toLowerCase().contains(this.searchString.toLowerCase()); + }). + distinct(). + collect(Collectors.toList()); + } + } + + /** * This method creates PanelItem button of requested type. * @return new PanelItem with requested functionality. @@ -204,4 +233,9 @@ public class SingleBlockSelector extends PagedSelector * This variable stores consumer. */ private final BiConsumer consumer; + + /** + * Stores filtered items. + */ + private List filterElements; } diff --git a/src/main/java/world/bentobox/challenges/panel/util/SingleEntitySelector.java b/src/main/java/world/bentobox/challenges/panel/util/SingleEntitySelector.java index 02c12fa..06c2667 100644 --- a/src/main/java/world/bentobox/challenges/panel/util/SingleEntitySelector.java +++ b/src/main/java/world/bentobox/challenges/panel/util/SingleEntitySelector.java @@ -5,7 +5,6 @@ import java.util.*; import java.util.function.BiConsumer; import java.util.stream.Collectors; -import org.apache.commons.lang.WordUtils; import org.bukkit.Material; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; @@ -50,7 +49,11 @@ public class SingleEntitySelector extends PagedSelector return true; } }). + // Sort by names + sorted(Comparator.comparing(EntityType::name)). collect(Collectors.toList()); + // Init without filters applied. + this.filterElements = this.elements; } @@ -106,7 +109,7 @@ public class SingleEntitySelector extends PagedSelector GuiUtils.fillBorder(panelBuilder, Material.BLUE_STAINED_GLASS_PANE); - this.populateElements(panelBuilder, this.elements); + this.populateElements(panelBuilder, this.filterElements); panelBuilder.item(4, this.createButton()); @@ -114,6 +117,29 @@ public class SingleEntitySelector extends PagedSelector } + /** + * This method is called when filter value is updated. + */ + @Override + protected void updateFilters() + { + if (this.searchString == null || this.searchString.isBlank()) + { + this.filterElements = this.elements; + } + else + { + this.filterElements = this.elements.stream(). + filter(element -> { + // If element name is set and name contains search field, then do not filter out. + return element.name().toLowerCase().contains(this.searchString.toLowerCase()); + }). + distinct(). + collect(Collectors.toList()); + } + } + + /** * This method builds PanelItem for given entity. * @param entity Entity which PanelItem must be created. @@ -204,4 +230,9 @@ public class SingleEntitySelector extends PagedSelector * This variable stores consumer. */ private final BiConsumer consumer; + + /** + * Stores filtered items. + */ + private List filterElements; } diff --git a/src/main/java/world/bentobox/challenges/panel/util/StatisticSelector.java b/src/main/java/world/bentobox/challenges/panel/util/StatisticSelector.java index 378427a..afabe65 100644 --- a/src/main/java/world/bentobox/challenges/panel/util/StatisticSelector.java +++ b/src/main/java/world/bentobox/challenges/panel/util/StatisticSelector.java @@ -3,10 +3,12 @@ package world.bentobox.challenges.panel.util; import org.bukkit.Material; import org.bukkit.Statistic; +import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import java.util.*; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.stream.Collectors; import world.bentobox.bentobox.api.panels.PanelItem; import world.bentobox.bentobox.api.panels.builders.PanelBuilder; @@ -36,6 +38,9 @@ public class StatisticSelector extends PagedSelector this.consumer = consumer; this.elements = new ArrayList<>(Arrays.asList(Statistic.values())); this.elements.sort(Comparator.comparing(Statistic::name)); + + // Init without filters applied. + this.filterElements = this.elements; } @@ -67,7 +72,7 @@ public class StatisticSelector extends PagedSelector GuiUtils.fillBorder(panelBuilder, Material.BLUE_STAINED_GLASS_PANE); - this.populateElements(panelBuilder, this.elements); + this.populateElements(panelBuilder, this.filterElements); panelBuilder.item(4, this.createButton()); @@ -75,6 +80,29 @@ public class StatisticSelector extends PagedSelector } + /** + * This method is called when filter value is updated. + */ + @Override + protected void updateFilters() + { + if (this.searchString == null || this.searchString.isBlank()) + { + this.filterElements = this.elements; + } + else + { + this.filterElements = this.elements.stream(). + filter(element -> { + // If element name is set and name contains search field, then do not filter out. + return element.name().toLowerCase().contains(this.searchString.toLowerCase()); + }). + distinct(). + collect(Collectors.toList()); + } + } + + /** * This method creates PanelItem that represents given statistic. * Some materials is not displayable in Inventory GUI, so they are replaced with "placeholder" items. @@ -156,4 +184,9 @@ public class StatisticSelector extends PagedSelector * This variable stores consumer. */ private final BiConsumer consumer; + + /** + * Stores filtered items. + */ + private List filterElements; }