feat: (modpack download): category & sort.

This commit is contained in:
Yuhui Huang 2021-08-03 22:47:53 +08:00
parent af7cf393dc
commit 37fb9a0d65
7 changed files with 102 additions and 19 deletions

View File

@ -42,7 +42,6 @@ import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
import org.jackhuang.hmcl.ui.construct.PromptDialogPane; import org.jackhuang.hmcl.ui.construct.PromptDialogPane;
import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane; import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane;
import org.jackhuang.hmcl.ui.decorator.DecoratorController; import org.jackhuang.hmcl.ui.decorator.DecoratorController;
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
import org.jackhuang.hmcl.ui.download.ModpackInstallWizardProvider; import org.jackhuang.hmcl.ui.download.ModpackInstallWizardProvider;
import org.jackhuang.hmcl.ui.main.RootPage; import org.jackhuang.hmcl.ui.main.RootPage;
import org.jackhuang.hmcl.ui.versions.GameListPage; import org.jackhuang.hmcl.ui.versions.GameListPage;
@ -84,12 +83,13 @@ public final class Controllers {
private static AuthlibInjectorServersPage serversPage = null; private static AuthlibInjectorServersPage serversPage = null;
private static Lazy<RootPage> rootPage = new Lazy<>(RootPage::new); private static Lazy<RootPage> rootPage = new Lazy<>(RootPage::new);
private static DecoratorController decorator; private static DecoratorController decorator;
private static Lazy<ModDownloadListPage> modDownloadListPage = new Lazy<>(() -> private static Lazy<ModDownloadListPage> modDownloadListPage = new Lazy<>(() -> {
new ModDownloadListPage(CurseModManager.SECTION_MODPACK, Versions::downloadModpackImpl) { return new ModDownloadListPage(CurseModManager.SECTION_MODPACK, Versions::downloadModpackImpl) {
{ {
state.set(State.fromTitle(i18n("modpack.download"))); state.set(State.fromTitle(i18n("modpack.download")));
} }
}); };
});
private Controllers() { private Controllers() {
} }

View File

@ -17,9 +17,7 @@
*/ */
package org.jackhuang.hmcl.ui.versions; package org.jackhuang.hmcl.ui.versions;
import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.*;
import com.jfoenix.controls.JFXListView;
import com.jfoenix.controls.JFXTextField;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.*; import javafx.beans.property.*;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
@ -44,6 +42,7 @@ import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.StringUtils;
import java.io.File; import java.io.File;
import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@ -174,13 +173,37 @@ public class ModDownloadListPage extends Control implements DecoratorPage {
} }
}); });
JFXTextField categoryField = new JFXTextField(); StackPane categoryStackPane = new StackPane();
categoryField.setPromptText(i18n("mods.category")); JFXComboBox<CategoryIndented> categoryComboBox = new JFXComboBox<>();
searchPane.add(categoryField, 0, 1); categoryStackPane.getChildren().setAll(categoryComboBox);
categoryComboBox.prefWidthProperty().bind(categoryStackPane.widthProperty());
categoryComboBox.getStyleClass().add("fit-width");
categoryComboBox.setPromptText(i18n("mods.category"));
Task.supplyAsync(() -> CurseModManager.getCategories(getSkinnable().section))
.thenAcceptAsync(Schedulers.javafx(), categories -> {
List<CategoryIndented> result = new ArrayList<>();
for (CurseModManager.Category category : categories) {
resolveCategory(category, 0, result);
}
categoryComboBox.getItems().setAll(result);
}).start();
searchPane.add(categoryStackPane, 0, 1);
JFXTextField sortField = new JFXTextField(); StackPane sortStackPane = new StackPane();
sortField.setPromptText(i18n("search.sort")); JFXComboBox<String> sortComboBox = new JFXComboBox<>();
searchPane.add(sortField, 1, 1); sortStackPane.getChildren().setAll(sortComboBox);
sortComboBox.prefWidthProperty().bind(sortStackPane.widthProperty());
sortComboBox.getStyleClass().add("fit-width");
sortComboBox.setPromptText(i18n("search.sort"));
sortComboBox.getItems().setAll(
i18n("curse.sort.date_created"),
i18n("curse.sort.popularity"),
i18n("curse.sort.last_updated"),
i18n("curse.sort.name"),
i18n("curse.sort.author"),
i18n("curse.sort.total_downloads"));
sortComboBox.getSelectionModel().select(0);
searchPane.add(sortStackPane, 1, 1);
VBox vbox = new VBox(); VBox vbox = new VBox();
vbox.setAlignment(Pos.CENTER_RIGHT); vbox.setAlignment(Pos.CENTER_RIGHT);
@ -189,7 +212,14 @@ public class ModDownloadListPage extends Control implements DecoratorPage {
JFXButton searchButton = new JFXButton(); JFXButton searchButton = new JFXButton();
searchButton.setText(i18n("search")); searchButton.setText(i18n("search"));
searchButton.setOnAction(e -> { searchButton.setOnAction(e -> {
getSkinnable().search(gameVersionField.getText(), 0, 0, nameField.getText(), 0); getSkinnable().search(gameVersionField.getText(),
Optional.ofNullable(categoryComboBox.getSelectionModel().getSelectedItem())
.map(CategoryIndented::getCategory)
.map(CurseModManager.Category::getId)
.orElse(0),
0,
nameField.getText(),
sortComboBox.getSelectionModel().getSelectedIndex());
}); });
searchPane.add(searchButton, 0, 2); searchPane.add(searchButton, 0, 2);
vbox.getChildren().setAll(searchButton); vbox.getChildren().setAll(searchButton);
@ -256,5 +286,35 @@ public class ModDownloadListPage extends Control implements DecoratorPage {
getChildren().setAll(pane); getChildren().setAll(pane);
} }
private static class CategoryIndented {
private final int indent;
private final CurseModManager.Category category;
public CategoryIndented(int indent, CurseModManager.Category category) {
this.indent = indent;
this.category = category;
}
public int getIndent() {
return indent;
}
public CurseModManager.Category getCategory() {
return category;
}
@Override
public String toString() {
return StringUtils.repeats(' ', indent) + i18n("curse.category." + category.getId());
}
}
private static void resolveCategory(CurseModManager.Category category, int indent, List<CategoryIndented> result) {
result.add(new CategoryIndented(indent, category));
for (CurseModManager.Category subcategory : category.getSubcategories()) {
resolveCategory(subcategory, indent + 1, result);
}
}
} }
} }

View File

@ -51,7 +51,6 @@ import java.nio.file.Path;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.logging.Level; import java.util.logging.Level;
import static org.jackhuang.hmcl.ui.download.LocalModpackPage.MODPACK_FILE;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class Versions { public final class Versions {

View File

@ -156,6 +156,13 @@ curse.category.4558=Redstone
curse.category.4843=Automation curse.category.4843=Automation
curse.category.4906=MCreator curse.category.4906=MCreator
curse.sort.author=Author
curse.sort.date_created=Date Created
curse.sort.last_updated=Last Updated
curse.sort.name=Name
curse.sort.popularity=Popularity
curse.sort.total_downloads=Total Downloads
download=Download download=Download
download.code.404=File not found on the remote server: %s download.code.404=File not found on the remote server: %s
download.failed=Failed to download %1$s, response code: %2$d download.failed=Failed to download %1$s, response code: %2$d

View File

@ -157,6 +157,13 @@ curse.category.4558=红石
curse.category.4843=自动化 curse.category.4843=自动化
curse.category.4906=MCreator curse.category.4906=MCreator
curse.sort.author=作者
curse.sort.date_created=创建日期
curse.sort.last_updated=最近更新
curse.sort.name=名称
curse.sort.popularity=热度
curse.sort.total_downloads=下载量
download=下载 download=下载
download.code.404=远程服务器不包含需要下载的文件: %s download.code.404=远程服务器不包含需要下载的文件: %s
download.failed=下载失败: %1$s错误码%2$d download.failed=下载失败: %1$s错误码%2$d

View File

@ -11,7 +11,9 @@ import java.util.*;
import static org.jackhuang.hmcl.util.Lang.mapOf; import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Pair.pair; import static org.jackhuang.hmcl.util.Pair.pair;
public class CurseModManager { public final class CurseModManager {
private CurseModManager() {
}
public static List<CurseAddon> searchPaginated(String gameVersion, int category, int section, int pageOffset, String searchFilter, int sort) throws IOException { public static List<CurseAddon> searchPaginated(String gameVersion, int category, int section, int pageOffset, String searchFilter, int sort) throws IOException {
String response = NetworkUtils.doGet(new URL(NetworkUtils.withQuery("https://addons-ecs.forgesvc.net/api/v2/addon/search", mapOf( String response = NetworkUtils.doGet(new URL(NetworkUtils.withQuery("https://addons-ecs.forgesvc.net/api/v2/addon/search", mapOf(

View File

@ -235,4 +235,12 @@ public final class StringUtils {
} }
return builder.toString(); return builder.toString();
} }
public static String repeats(char ch, int repeat) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < repeat; i++) {
result.append(ch);
}
return result.toString();
}
} }