feat: (WIP) Curse mod/modpack download

This commit is contained in:
Yuhui Huang
2021-08-02 23:11:30 +08:00
parent 0939ed819e
commit 7a20af462b
11 changed files with 830 additions and 4 deletions

View File

@@ -61,10 +61,9 @@ public class ListPageSkin extends SkinBase<ListPage<?>> {
VBox vBox = new VBox();
{
vBox.getStyleClass().add("card-list");
vBox.setAlignment(Pos.BOTTOM_RIGHT);
vBox.setPickOnBounds(false);
vBox.setPadding(new Insets(15));
vBox.setSpacing(15);
JFXButton btnAdd = new JFXButton();
FXUtils.setLimitWidth(btnAdd, 40);

View File

@@ -19,7 +19,6 @@ package org.jackhuang.hmcl.ui.profile;
import com.jfoenix.controls.JFXButton;
import javafx.css.PseudoClass;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.SkinBase;

View File

@@ -0,0 +1,153 @@
package org.jackhuang.hmcl.ui.versions;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXTextField;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Pos;
import javafx.scene.control.Control;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Skin;
import javafx.scene.control.SkinBase;
import javafx.scene.layout.*;
import org.jackhuang.hmcl.mod.curse.CurseModManager;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.animation.TransitionPane;
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class ModDownloadListPage extends Control {
private final BooleanProperty loading = new SimpleBooleanProperty(false);
private final BooleanProperty failed = new SimpleBooleanProperty(false);
/**
* @see org.jackhuang.hmcl.mod.curse.CurseModManager#SECTION_MODPACK
* @see org.jackhuang.hmcl.mod.curse.CurseModManager#SECTION_MOD
*/
private final int section;
private Profile profile;
private String version;
public ModDownloadListPage(int section) {
this.section = section;
}
public void loadVersion(Profile profile, String version) {
this.profile = profile;
this.version = version;
setLoading(false);
setFailed(false);
}
public boolean isFailed() {
return failed.get();
}
public BooleanProperty failedProperty() {
return failed;
}
public void setFailed(boolean failed) {
this.failed.set(failed);
}
public boolean isLoading() {
return loading.get();
}
public BooleanProperty loadingProperty() {
return loading;
}
public void setLoading(boolean loading) {
this.loading.set(loading);
}
public void search(String gameVersion, int category, int pageOffset, String searchFilter, int sort) {
setLoading(true);
Task.supplyAsync(() -> CurseModManager.searchPaginated(gameVersion, category, section, pageOffset, searchFilter, sort))
.whenComplete(Schedulers.javafx(), (exception, result) -> {
setLoading(false);
if (exception == null) {
} else {
}
});
}
@Override
protected Skin<?> createDefaultSkin() {
return new ModDownloadListPageSkin(this);
}
private static class ModDownloadListPageSkin extends SkinBase<ModDownloadListPage> {
protected ModDownloadListPageSkin(ModDownloadListPage control) {
super(control);
VBox pane = new VBox();
pane.getStyleClass().add("card-list");
GridPane searchPane = new GridPane();
searchPane.getStyleClass().add("card");
ColumnConstraints column1 = new ColumnConstraints();
column1.setPercentWidth(50);
column1.setHgrow(Priority.ALWAYS);
ColumnConstraints column2 = new ColumnConstraints();
column2.setHgrow(Priority.ALWAYS);
column2.setPercentWidth(50);
searchPane.getColumnConstraints().setAll(column1, column2);
searchPane.setHgap(16);
searchPane.setVgap(10);
{
JFXTextField nameField = new JFXTextField();
nameField.setPromptText(i18n("mods.name"));
searchPane.add(nameField, 0, 0);
JFXTextField gameVersionField = new JFXTextField();
gameVersionField.setPromptText(i18n("world.game_version"));
searchPane.add(gameVersionField, 1, 0);
JFXTextField categoryField = new JFXTextField();
categoryField.setPromptText(i18n("mods.category"));
searchPane.add(categoryField, 0, 1);
JFXTextField sortField = new JFXTextField();
sortField.setPromptText(i18n("search.sort"));
searchPane.add(sortField, 1, 1);
VBox vbox = new VBox();
vbox.setAlignment(Pos.CENTER_RIGHT);
searchPane.add(vbox, 0, 2, 2, 1);
JFXButton searchButton = new JFXButton();
searchButton.setText(i18n("search"));
searchButton.setOnAction(e -> {
getSkinnable().search(gameVersionField.getText(), categoryField.getText(), 0, nameField.getText(), sortField.getText())
.whenComplete();
});
searchPane.add(searchButton, 0, 2);
vbox.getChildren().setAll(searchButton);
}
TransitionPane transitionPane = new TransitionPane();
{
SpinnerPane spinnerPane = new SpinnerPane();
spinnerPane.loadingProperty().bind(getSkinnable().loadingProperty());
}
pane.getChildren().setAll(searchPane, transitionPane);
getChildren().setAll(pane);
}
}
}

View File

@@ -0,0 +1,38 @@
package org.jackhuang.hmcl.ui.versions;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.scene.control.Control;
import javafx.scene.control.Skin;
import javafx.scene.control.SkinBase;
import org.jackhuang.hmcl.game.Version;
import org.jackhuang.hmcl.mod.curse.CurseAddon;
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
public class ModDownloadPage extends Control implements DecoratorPage {
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>();
private final CurseAddon addon;
private final Version version;
public ModDownloadPage(CurseAddon addon, Version version) {
this.addon = addon;
this.version = version;
}
@Override
public ReadOnlyObjectProperty<State> stateProperty() {
return state.getReadOnlyProperty();
}
@Override
protected Skin<?> createDefaultSkin() {
return new ModDownloadPageSkin(this);
}
private static class ModDownloadPageSkin extends SkinBase<ModDownloadPage> {
protected ModDownloadPageSkin(ModDownloadPage control) {
super(control);
}
}
}

View File

@@ -50,6 +50,8 @@ public class VersionPage extends Control implements DecoratorPage {
private final VersionSettingsPage versionSettingsPage = new VersionSettingsPage();
private final TabHeader.Tab modListTab = new TabHeader.Tab("modListTab");
private final ModListPage modListPage = new ModListPage(modListTab);
private final TabHeader.Tab curseModListTab = new TabHeader.Tab("modListTab");
private final ModDownloadListPage curseModListPage = new ModDownloadListPage();
private final TabHeader.Tab installerListTab = new TabHeader.Tab("installerListTab");
private final InstallerListPage installerListPage = new InstallerListPage();
private final TabHeader.Tab worldListTab = new TabHeader.Tab("worldList");
@@ -64,6 +66,7 @@ public class VersionPage extends Control implements DecoratorPage {
{
versionSettingsTab.setNode(versionSettingsPage);
modListTab.setNode(modListPage);
curseModListTab.setNode(curseModListPage);
installerListTab.setNode(installerListPage);
worldListTab.setNode(worldListPage);
@@ -92,6 +95,7 @@ public class VersionPage extends Control implements DecoratorPage {
preferredVersionName = version;
versionSettingsPage.loadVersion(profile, version);
curseModListPage.loadVersion(profile, version);
currentVersionUpgradable.set(profile.getRepository().isModpack(version));
CompletableFuture.allOf(
@@ -245,6 +249,14 @@ public class VersionPage extends Control implements DecoratorPage {
modListItem.activeProperty().bind(control.selectedTab.isEqualTo(control.modListTab));
modListItem.setOnAction(e -> control.selectedTab.set(control.modListTab));
AdvancedListItem curseModListItem = new AdvancedListItem();
curseModListItem.getStyleClass().add("navigation-drawer-item");
curseModListItem.setTitle(i18n("mods.download"));
curseModListItem.setLeftGraphic(wrap(SVG.fire(Theme.blackFillBinding(), 20, 20)));
curseModListItem.setActionButtonVisible(false);
curseModListItem.activeProperty().bind(control.selectedTab.isEqualTo(control.curseModListTab));
curseModListItem.setOnAction(e -> control.selectedTab.set(control.curseModListTab));
AdvancedListItem installerListItem = new AdvancedListItem();
installerListItem.getStyleClass().add("navigation-drawer-item");
installerListItem.setTitle(i18n("settings.tabs.installers"));
@@ -264,6 +276,7 @@ public class VersionPage extends Control implements DecoratorPage {
AdvancedListBox sideBar = new AdvancedListBox()
.add(versionSettingsItem)
.add(modListItem)
.add(curseModListItem)
.add(installerListItem)
.add(worldListItem);
left.setCenter(sideBar);

View File

@@ -783,6 +783,11 @@
-fx-background-color: derive(-fx-base-color, 60%);
}
.card-list {
-fx-padding: 10;
-fx-spacing: 10;
}
.options-sublist {
-fx-background-color: white;
}

View File

@@ -11,7 +11,7 @@
xmlns:fx="http://javafx.com/fxml"
type="StackPane">
<ScrollPane fx:id="scroll" fitToHeight="true" fitToWidth="true" vbarPolicy="ALWAYS">
<VBox fx:id="rootPane" style="-fx-padding: 10;" spacing="12">
<VBox fx:id="rootPane" styleClass="card-list">
<ComponentList fx:id="iconPickerItemWrapper">
<ImagePickerItem fx:id="iconPickerItem" title="%settings.icon" onSelectButtonClicked="#onExploreIcon" onDeleteButtonClicked="#onDeleteIcon">

View File

@@ -307,6 +307,7 @@ mods.add=Install mods
mods.add.failed=Failed to install mods %s.
mods.add.success=Successfully installed mods %s.
mods.choose_mod=Choose your mods
mods.download=Mod Downloads
mods.enable=Enable
mods.disable=Disable
mods.name=Name

View File

@@ -98,6 +98,63 @@ color.custom=自定义颜色
crash.NoClassDefFound=请确认 Hello Minecraft! Launcher 本体是否完整,或更新您的 Java。
crash.user_fault=您的系统或 Java 环境可能安装不当导致本软件崩溃,请检查您的 Java 环境或您的电脑!可以尝试重新安装 Java。
curse.category.modpack.sci-fi=科幻
curse.category.modpack.small-light=轻量整合包
curse.category.modpack.combat-pvp=战斗 PVP
curse.category.modpack.mini-game=小游戏
curse.category.modpack.quests=任务
curse.category.modpack.multiplayer=多人
curse.category.modpack.exploration=探索
curse.category.modpack.skyblock=空岛
curse.category.modpack.adventure-and-rpg=冒险 RPG
curse.category.modpack.ftb-official-pack=FTB 整合包
curse.category.modpack.map-based=有特定地图
curse.category.modpack.hardcore=高难度
curse.category.modpack.extra-large=大型整合包
curse.category.modpack.tech=科技
curse.category.modpack.magic=魔法
curse.category.mod.map-information=信息展示
curse.category.mod.mc-addons=模组扩展
curse.category.mod.armor-weapons-tools=装备武器
curse.category.mod.world-structures=自然生成
curse.category.mod.blood-magic=血魔法
curse.category.mod.storage=存储
curse.category.mod.addons-industrialcraft=工业 (Industrialcraft)
curse.category.mod.magic=魔法
curse.category.mod.technology=科技
curse.category.mod.[4557]redstone=红石
curse.category.mod.addons-tinkers-construct=匠魂
curse.category.mod.technology-player-transport=交通运输
curse.category.mod.[4486]lucky-blocks=Lucky Blocks
curse.category.mod.addons-buildcraft=建筑 (Buildcraft)
curse.category.mod.technology-genetics=基因
curse.category.mod.twitch-integration=Twitch
curse.category.mod.world-ores-resources=矿物资源
curse.category.mod.crafttweaker=CraftTweaker
curse.category.mod.addons-thaumcraft=神秘 (Thaumcraft)
curse.category.mod.adventure-rpg=冒险 RPG
curse.category.mod.technology-processing=机器处理
curse.category.mod.technology-energy=能源
curse.category.mod.technology-item-fluid-energy-transport=物流运输
curse.category.mod.addons-forestry=林业 (Forestry)
curse.category.mod.mc-miscellaneous=其他
curse.category.mod.applied-energistics-2=应用能源 2 (Applied Energistics 2)
curse.category.mod.technology-farming=农业
curse.category.mod.library-api=支持库
curse.category.mod.fabric=Fabric
curse.category.mod.cosmetic=装饰
curse.category.mod.world-gen=世界生成
curse.category.mod.server-utility=服务器
curse.category.mod.world-mobs=生物
curse.category.mod.world-biomes=生物群系
curse.category.mod.addons-thermalexpansion=热力膨胀 (Thermal Expansion)
curse.category.mod.world-dimensions=维度
curse.category.mod.mc-food=食物
curse.category.mod.redstone=红石
curse.category.mod.technology-automation=自动化
curse.category.mod.mc-creator=MCreator
download=下载
download.code.404=远程服务器不包含需要下载的文件: %s
download.failed=下载失败: %1$s错误码%2$d
@@ -307,9 +364,11 @@ mods.add=添加模组
mods.add.failed=添加模组 %s 失败。
mods.add.success=成功添加模组 %s。
mods.choose_mod=选择模组
mods.download=模组下载
mods.enable=启用
mods.disable=禁用
mods.name=名称
mods.category=类别
mods.not_modded=你需要先在自动安装页面安装 Fabric、Forge 或 LiteLoader 才能进行模组管理。
datapack=数据包
@@ -352,6 +411,9 @@ profile.title=游戏目录
profile.selected=已选中
profile.use_relative_path=若可能,游戏目录使用相对路径
search=搜索
search.sort=排序
selector.choose=选择
selector.choose_file=选择文件
selector.custom=自定义