Merge pull request #10894 from loldudester/external-searching

Plugin Hub: Reorder plugin panel and rework the search function
This commit is contained in:
Abex
2020-02-28 12:58:40 -07:00
committed by GitHub
5 changed files with 49 additions and 49 deletions

View File

@@ -29,6 +29,7 @@ import com.google.common.io.Files;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import javax.annotation.Nullable;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import net.runelite.client.RuneLite; import net.runelite.client.RuneLite;
@@ -45,7 +46,9 @@ public class ExternalPluginManifest
private String displayName; private String displayName;
private String version; private String version;
private String author; private String author;
@Nullable
private String description; private String description;
@Nullable
private String[] tags; private String[] tags;
@EqualsAndHashCode.Exclude @EqualsAndHashCode.Exclude
private URL support; private URL support;

View File

@@ -37,7 +37,9 @@ import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@@ -45,7 +47,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.ToDoubleFunction;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -85,8 +86,8 @@ import net.runelite.client.ui.components.IconTextField;
import net.runelite.client.util.ImageUtil; import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.LinkBrowser; import net.runelite.client.util.LinkBrowser;
import net.runelite.client.util.SwingUtil; import net.runelite.client.util.SwingUtil;
import net.runelite.client.util.Text;
import net.runelite.client.util.VerificationException; import net.runelite.client.util.VerificationException;
import org.apache.commons.text.similarity.JaroWinklerDistance;
@Slf4j @Slf4j
@Singleton @Singleton
@@ -98,7 +99,6 @@ class PluginHubPanel extends PluginPanel
private static final ImageIcon CONFIGURE_ICON; private static final ImageIcon CONFIGURE_ICON;
private static final ImageIcon CONFIGURE_ICON_HOVER; private static final ImageIcon CONFIGURE_ICON_HOVER;
private static final Pattern SPACES = Pattern.compile(" +"); private static final Pattern SPACES = Pattern.compile(" +");
private static final JaroWinklerDistance DISTANCE = new JaroWinklerDistance();
static static
{ {
@@ -119,16 +119,13 @@ class PluginHubPanel extends PluginPanel
private static final int HEIGHT = 70; private static final int HEIGHT = 70;
private static final int ICON_WIDTH = 48; private static final int ICON_WIDTH = 48;
private static final int BOTTOM_LINE_HEIGHT = 16; private static final int BOTTOM_LINE_HEIGHT = 16;
static final float MIN_FILTER_SCORE = .8f;
private final ExternalPluginManifest manifest; private final ExternalPluginManifest manifest;
private final List<String> keywords = new ArrayList<>();
@Getter @Getter
private final boolean installed; private final boolean installed;
@Getter
private float filter;
PluginItem(ExternalPluginManifest newManifest, Collection<Plugin> loadedPlugins, boolean installed) PluginItem(ExternalPluginManifest newManifest, Collection<Plugin> loadedPlugins, boolean installed)
{ {
ExternalPluginManifest loaded = null; ExternalPluginManifest loaded = null;
@@ -140,6 +137,23 @@ class PluginHubPanel extends PluginPanel
manifest = newManifest == null ? loaded : newManifest; manifest = newManifest == null ? loaded : newManifest;
this.installed = installed; this.installed = installed;
if (manifest != null)
{
Collections.addAll(keywords, SPACES.split(manifest.getDisplayName().toLowerCase()));
if (manifest.getDescription() != null)
{
Collections.addAll(keywords, SPACES.split(manifest.getDescription().toLowerCase()));
}
Collections.addAll(keywords, manifest.getAuthor().toLowerCase());
if (manifest.getTags() != null)
{
Collections.addAll(keywords, manifest.getTags());
}
}
setBackground(ColorScheme.DARKER_GRAY_COLOR); setBackground(ColorScheme.DARKER_GRAY_COLOR);
setOpaque(true); setOpaque(true);
@@ -302,23 +316,6 @@ class PluginHubPanel extends PluginPanel
.addComponent(addrm, BOTTOM_LINE_HEIGHT, BOTTOM_LINE_HEIGHT, BOTTOM_LINE_HEIGHT)) .addComponent(addrm, BOTTOM_LINE_HEIGHT, BOTTOM_LINE_HEIGHT, BOTTOM_LINE_HEIGHT))
.addGap(5))); .addGap(5)));
} }
float setFilter(String[] filter)
{
ToDoubleFunction<String> match = r -> Stream.of(filter)
.mapToDouble(l -> Math.pow(DISTANCE.apply(l, r), 2))
.max()
.orElse(0.D);
double sim = SPACES.splitAsStream(manifest.getDisplayName()).collect(Collectors.averagingDouble(match)) * 2;
if (manifest.getTags() != null)
{
sim += Stream.of(manifest.getTags()).mapToDouble(match).sum();
}
return this.filter = (float) sim;
}
} }
private final PluginListPanel pluginListPanel; private final PluginListPanel pluginListPanel;
@@ -537,13 +534,13 @@ class PluginHubPanel extends PluginPanel
{ {
String[] searchArray = SPACES.split(search.toLowerCase()); String[] searchArray = SPACES.split(search.toLowerCase());
stream = stream stream = stream
.filter(p -> p.setFilter(searchArray) > PluginItem.MIN_FILTER_SCORE) .filter(p -> Text.matchesSearchTerms(searchArray, p.keywords))
.sorted(Comparator.comparing(PluginItem::getFilter)); .sorted(Comparator.comparing(p -> p.manifest.getDisplayName()));
} }
else else
{ {
stream = stream stream = stream
.sorted(Comparator.comparing(PluginItem::isInstalled)); .sorted(Comparator.comparing(PluginItem::isInstalled).thenComparing(p -> p.manifest.getDisplayName()));
} }
stream.forEach(mainPanel::add); stream.forEach(mainPanel::add);

View File

@@ -52,12 +52,9 @@ import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.PluginPanel; import net.runelite.client.ui.PluginPanel;
import net.runelite.client.util.ImageUtil; import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.SwingUtil; import net.runelite.client.util.SwingUtil;
import org.apache.commons.text.similarity.JaroWinklerDistance;
class PluginListItem extends JPanel class PluginListItem extends JPanel
{ {
private static final JaroWinklerDistance DISTANCE = new JaroWinklerDistance();
private static final ImageIcon CONFIG_ICON; private static final ImageIcon CONFIG_ICON;
private static final ImageIcon CONFIG_ICON_HOVER; private static final ImageIcon CONFIG_ICON_HOVER;
private static final ImageIcon ON_STAR; private static final ImageIcon ON_STAR;
@@ -68,6 +65,7 @@ class PluginListItem extends JPanel
@Getter @Getter
private final PluginConfigurationDescriptor pluginConfig; private final PluginConfigurationDescriptor pluginConfig;
@Getter
private final List<String> keywords = new ArrayList<>(); private final List<String> keywords = new ArrayList<>();
private final JToggleButton pinButton; private final JToggleButton pinButton;
@@ -202,24 +200,6 @@ class PluginListItem extends JPanel
onOffToggle.setSelected(enabled); onOffToggle.setSelected(enabled);
} }
/**
* Checks if all the search terms in the given list matches at least one keyword.
*
* @return true if all search terms matches at least one keyword, or false if otherwise.
*/
boolean matchesSearchTerms(String[] searchTerms)
{
for (String term : searchTerms)
{
if (keywords.stream().noneMatch((t) -> t.contains(term) ||
DISTANCE.apply(t, term) > 0.9))
{
return false;
}
}
return true;
}
private void openGroupConfigPanel() private void openGroupConfigPanel()
{ {
pluginListPanel.openConfigurationPanel(pluginConfig); pluginListPanel.openConfigurationPanel(pluginConfig);

View File

@@ -271,7 +271,7 @@ class PluginListPanel extends PluginPanel
final String[] searchTerms = text.toLowerCase().split(" "); final String[] searchTerms = text.toLowerCase().split(" ");
pluginList.forEach(listItem -> pluginList.forEach(listItem ->
{ {
if (pinned == listItem.isPinned() && listItem.matchesSearchTerms(searchTerms)) if (pinned == listItem.isPinned() && Text.matchesSearchTerms(searchTerms, listItem.getKeywords()))
{ {
mainPanel.add(listItem); mainPanel.add(listItem);
} }

View File

@@ -32,12 +32,14 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.commons.text.WordUtils; import org.apache.commons.text.WordUtils;
import org.apache.commons.text.similarity.JaroWinklerDistance;
/** /**
* A set of utilities to use when dealing with text. * A set of utilities to use when dealing with text.
*/ */
public class Text public class Text
{ {
private static final JaroWinklerDistance DISTANCE = new JaroWinklerDistance();
private static final Pattern TAG_REGEXP = Pattern.compile("<[^>]*>"); private static final Pattern TAG_REGEXP = Pattern.compile("<[^>]*>");
private static final Splitter COMMA_SPLITTER = Splitter private static final Splitter COMMA_SPLITTER = Splitter
.on(",") .on(",")
@@ -186,4 +188,22 @@ public class Text
return toString; return toString;
} }
/**
* Checks if all the search terms in the given list matches at least one keyword.
*
* @return true if all search terms matches at least one keyword, or false if otherwise.
*/
public static boolean matchesSearchTerms(String[] searchTerms, final Collection<String> keywords)
{
for (String term : searchTerms)
{
if (keywords.stream().noneMatch((t) -> t.contains(term) ||
DISTANCE.apply(t, term) > 0.9))
{
return false;
}
}
return true;
}
} }