Skip to content

Commit

Permalink
[skip ci] Implement a search bar (#4)
Browse files Browse the repository at this point in the history
* Implement search bar in language menu

* Cleanup code

* Update gradle and fix CI

* Add accesswidener to fabric.mod.json

* Pick StateManager changes

* [skip ci] Bump version

* [skip ci] Cleanup code
  • Loading branch information
ChachyDev committed Dec 1, 2021
1 parent ea7918f commit 37749f6
Show file tree
Hide file tree
Showing 18 changed files with 251 additions and 43 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 16
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '16'
java-version: '17'
distribution: 'adopt'
- uses: actions/cache@v2
with:
Expand Down
7 changes: 6 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ java {
withSourcesJar()
}

version = "0.2.5"
version = "0.2.6"
group = "club.chachy"

dependencies {
Expand All @@ -36,4 +36,9 @@ jar {
from("LICENSE") {
rename { "${it}_${project.archivesBaseName}" }
}
}

loom {
def resource = sourceSets.main.resources.srcDirs.first().toPath().resolve("${project.name}.accesswidener")
accessWidenerPath = file(resource)
}
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package club.chachy.lazylanguageloader.client.api.language;

import net.minecraft.client.resource.language.LanguageDefinition;

public interface LanguageMatcher {
boolean matches(String input, LanguageDefinition entry);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package club.chachy.lazylanguageloader.client.api.scroll;

public interface Scrollable {
boolean hasScrolled();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package club.chachy.lazylanguageloader.client.impl.language;

import club.chachy.lazylanguageloader.client.api.language.LanguageMatcher;
import net.minecraft.client.resource.language.LanguageDefinition;

import java.util.Locale;

public class CodeLanguageMatcher implements LanguageMatcher {
@Override
public boolean matches(String input, LanguageDefinition entry) {
return entry.getCode().toLowerCase(Locale.ROOT).contains(input.toLowerCase(Locale.ROOT));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package club.chachy.lazylanguageloader.client.impl.language;

import club.chachy.lazylanguageloader.client.api.language.LanguageMatcher;
import net.minecraft.client.resource.language.LanguageDefinition;

import java.util.Locale;

public class NameLanguageMatcher implements LanguageMatcher {
@Override
public boolean matches(String input, LanguageDefinition entry) {
return entry.getName().toLowerCase(Locale.ROOT).contains(input.toLowerCase(Locale.ROOT));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package club.chachy.lazylanguageloader.client.impl.language;

import club.chachy.lazylanguageloader.client.api.language.LanguageMatcher;
import net.minecraft.client.resource.language.LanguageDefinition;

import java.util.Locale;

public class RegionLanguageMatcher implements LanguageMatcher {
@Override
public boolean matches(String input, LanguageDefinition entry) {
return entry.getRegion().toLowerCase(Locale.ROOT).contains(input.toLowerCase(Locale.ROOT));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package club.chachy.lazylanguageloader.client.impl.state;

import club.chachy.lazylanguageloader.client.api.language.LanguageMatcher;
import club.chachy.lazylanguageloader.client.impl.language.CodeLanguageMatcher;
import club.chachy.lazylanguageloader.client.impl.language.NameLanguageMatcher;
import club.chachy.lazylanguageloader.client.impl.language.RegionLanguageMatcher;
import net.minecraft.client.resource.language.LanguageDefinition;
import net.minecraft.resource.ResourceReloader;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class StateManager {
private static final List<LanguageMatcher> languageMatchers = new ArrayList<>();
private static final List<ResourceReloader> reloaders = new ArrayList<>();
private static boolean resourceLoadViaLanguage = false;

static {
languageMatchers.addAll(Arrays.asList(new CodeLanguageMatcher(), new NameLanguageMatcher(), new RegionLanguageMatcher()));
}

public static boolean isResourceLoadViaLanguage() {
return resourceLoadViaLanguage;
}

public static void setResourceLoadViaLanguage(boolean resourceLoadViaLanguage) {
StateManager.resourceLoadViaLanguage = resourceLoadViaLanguage;
}

public static List<ResourceReloader> getResourceReloaders() {
return reloaders;
}

/**
* If any developer wants to workaround lazy-language-loader you could depend on it via Jitpack and add your resource reloader here
* if not it will not be reloaded. Sadly if your resource reloader doesn't derive from SearchManager or LanguageManager there isn't much
* more I can do to determine that you do stuff with languages...
*
* @param reloader Reloader to be used on language reloads
*/
public static void addResourceReloader(ResourceReloader reloader) {
reloaders.add(reloader);
}

public static boolean isMatchable(String input, LanguageDefinition definition) {
return languageMatchers.stream().anyMatch((m) -> m.matches(input, definition));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package club.chachy.lazylanguageloader.client.mixin;
package club.chachy.lazylanguageloader.client.mixin.optimizations;

import club.chachy.lazylanguageloader.client.state.StateManager;
import club.chachy.lazylanguageloader.client.impl.state.StateManager;
import net.minecraft.client.gui.screen.option.LanguageOptionsScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import org.spongepowered.asm.mixin.Mixin;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package club.chachy.lazylanguageloader.client.mixin;
package club.chachy.lazylanguageloader.client.mixin.optimizations;

import club.chachy.lazylanguageloader.client.state.StateManager;
import club.chachy.lazylanguageloader.client.impl.state.StateManager;
import net.minecraft.client.resource.language.LanguageManager;
import net.minecraft.client.search.SearchManager;
import net.minecraft.resource.ReloadableResourceManagerImpl;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package club.chachy.lazylanguageloader.client.mixin.searchbar;

import club.chachy.lazylanguageloader.client.api.scroll.Scrollable;
import net.minecraft.client.gui.widget.EntryListWidget;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(EntryListWidget.class)
public class MixinEntryListWidget implements Scrollable {
private boolean scrolled;

@Inject(method = "mouseScrolled", at = @At("HEAD"))
private void mouseScrolled(double mouseX, double mouseY, double amount, CallbackInfoReturnable<Boolean> cir) {
scrolled = true;
}

@Override
public boolean hasScrolled() {
return scrolled;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package club.chachy.lazylanguageloader.client.mixin.searchbar;

import club.chachy.lazylanguageloader.client.api.scroll.Scrollable;
import club.chachy.lazylanguageloader.client.impl.state.StateManager;
import club.chachy.lazylanguageloader.client.mixin.searchbar.accessor.LanguageEntryAccessor;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.option.LanguageOptionsScreen;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.client.resource.language.LanguageDefinition;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.util.ArrayList;
import java.util.List;

@Mixin(LanguageOptionsScreen.class)
public class MixinLanguageOptionsScreen extends Screen {
@Shadow
private LanguageOptionsScreen.LanguageSelectionListWidget languageSelectionList;

private List<LanguageOptionsScreen.LanguageSelectionListWidget.LanguageEntry> initialComponents;

protected MixinLanguageOptionsScreen(Text title) {
super(title);
}

@Inject(
method = "init",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/gui/screen/option/LanguageOptionsScreen;addSelectableChild(Lnet/minecraft/client/gui/Element;)Lnet/minecraft/client/gui/Element;",
shift = At.Shift.AFTER
)
)
private void init(CallbackInfo ci) {
initialComponents = new ArrayList<>(languageSelectionList.children());

int w = width / 5;
TextFieldWidget searchText = new TextFieldWidget(textRenderer, width - (w + 5), 11, w, 15, LiteralText.EMPTY);
searchText.setChangedListener(this::handleText);

addDrawableChild(searchText);
}

private void handleText(String text) {
List<LanguageOptionsScreen.LanguageSelectionListWidget.LanguageEntry> children = languageSelectionList.children();

if (text.isBlank() || text.isBlank()) {
int initialSize = initialComponents.size();
int currentSize = children.size();

if (initialSize != currentSize) {
languageSelectionList.replaceEntries(initialComponents);
}
} else {
for (LanguageOptionsScreen.LanguageSelectionListWidget.LanguageEntry entry : initialComponents) {
LanguageDefinition def = ((LanguageEntryAccessor) entry).getLanguageDefinition();

if (StateManager.isMatchable(text, def)) {
safeAdd(entry);
} else {
languageSelectionList.removeEntry(entry);
}
}
}
fixScroll();
}

@Unique
private void fixScroll() {
if (((Scrollable) languageSelectionList).hasScrolled()) {
languageSelectionList.setScrollAmount(languageSelectionList.getScrollAmount());
} else {
languageSelectionList.centerScrollOn(languageSelectionList.getSelectedOrNull());
}
}

@Unique
private void safeAdd(LanguageOptionsScreen.LanguageSelectionListWidget.LanguageEntry entry) {
if (!languageSelectionList.children().contains(entry)) {
languageSelectionList.addEntry(entry);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package club.chachy.lazylanguageloader.client.mixin.searchbar.accessor;

import net.minecraft.client.gui.screen.option.LanguageOptionsScreen;
import net.minecraft.client.resource.language.LanguageDefinition;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

@Mixin(LanguageOptionsScreen.LanguageSelectionListWidget.LanguageEntry.class)
public interface LanguageEntryAccessor {
@Accessor
LanguageDefinition getLanguageDefinition();
}
Original file line number Diff line number Diff line change
@@ -1,33 +0,0 @@
package club.chachy.lazylanguageloader.client.state;

import net.minecraft.resource.ResourceReloader;

import java.util.ArrayList;
import java.util.List;

public class StateManager {
private static boolean resourceLoadViaLanguage = false;
private static final List<ResourceReloader> reloaders = new ArrayList<>();

public static boolean isResourceLoadViaLanguage() {
return resourceLoadViaLanguage;
}

public static void setResourceLoadViaLanguage(boolean resourceLoadViaLanguage) {
StateManager.resourceLoadViaLanguage = resourceLoadViaLanguage;
}

public static List<ResourceReloader> getResourceReloaders() {
return reloaders;
}

/**
* If any developer wants to workaround lazy-language-loader you could depend on it via Jitpack and add your resource reloader here
* if not it will not be reloaded. Sadly if your resource reloader doesn't derive from SearchManager or LanguageManager there isn't much
* more I can do to determine that you do stuff with languages...
* @param reloader Reloader to be used on language reloads
*/
public static void addResourceReloader(ResourceReloader reloader) {
reloaders.add(reloader);
}
}
1 change: 1 addition & 0 deletions src/main/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"lazy-language-loader.mixin.json"
],
"icon": "assets/lazy_language_loader/icon/icon_128.png",
"accessWidener": "lazy-language-loader.accesswidener",
"depends": {
"fabricloader": ">=0.12.3",
"minecraft": "1.x.x",
Expand Down
7 changes: 7 additions & 0 deletions src/main/resources/lazy-language-loader.accesswidener
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
accessWidener v1 named

accessible class net/minecraft/client/gui/screen/option/LanguageOptionsScreen$LanguageSelectionListWidget
accessible method net/minecraft/client/gui/widget/EntryListWidget removeEntry (Lnet/minecraft/client/gui/widget/EntryListWidget$Entry;)Z
accessible method net/minecraft/client/gui/widget/EntryListWidget addEntry (Lnet/minecraft/client/gui/widget/EntryListWidget$Entry;)I
accessible method net/minecraft/client/gui/widget/EntryListWidget centerScrollOn (Lnet/minecraft/client/gui/widget/EntryListWidget$Entry;)V
accessible method net/minecraft/client/gui/widget/EntryListWidget replaceEntries (Ljava/util/Collection;)V
7 changes: 5 additions & 2 deletions src/main/resources/lazy-language-loader.mixin.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
"package": "club.chachy.lazylanguageloader.client.mixin",
"compatibilityLevel": "JAVA_16",
"client": [
"MixinLanguageOptionsScreen",
"MixinReloadableResourceManagerImpl"
"optimizations.MixinLanguageOptionsScreen",
"optimizations.MixinReloadableResourceManagerImpl",
"searchbar.MixinEntryListWidget",
"searchbar.MixinLanguageOptionsScreen",
"searchbar.accessor.LanguageEntryAccessor"
],
"injectors": {
"defaultRequire": 1
Expand Down

0 comments on commit 37749f6

Please sign in to comment.