mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-04-06 18:20:26 +08:00
add: forbids installation buttons for incompatible libraries. Closes #720.
This commit is contained in:
parent
42d42e9750
commit
a2ef477ae0
@ -19,94 +19,198 @@ package org.jackhuang.hmcl.ui;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.effects.JFXDepthManager;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.control.Control;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Skin;
|
||||
import javafx.scene.control.SkinBase;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||
import org.jackhuang.hmcl.setting.Theme;
|
||||
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
|
||||
import org.jackhuang.hmcl.util.i18n.I18n;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.*;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
/**
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class InstallerItem extends BorderPane {
|
||||
public class InstallerItem extends Control {
|
||||
private final String id;
|
||||
private final String imageUrl;
|
||||
public final StringProperty libraryVersion = new SimpleStringProperty();
|
||||
public final StringProperty incompatibleLibraryName = new SimpleStringProperty();
|
||||
public final BooleanProperty incompatibleWithGame = new SimpleBooleanProperty();
|
||||
public final BooleanProperty removable = new SimpleBooleanProperty();
|
||||
public final BooleanProperty upgradable = new SimpleBooleanProperty(false);
|
||||
public final BooleanProperty installable = new SimpleBooleanProperty(true);
|
||||
public final ObjectProperty<EventHandler<? super MouseEvent>> removeAction = new SimpleObjectProperty<>();
|
||||
public final ObjectProperty<EventHandler<? super MouseEvent>> action = new SimpleObjectProperty<>();
|
||||
|
||||
public InstallerItem(String libraryId, String libraryVersion, @Nullable Runnable upgrade, @Nullable Consumer<InstallerItem> deleteCallback) {
|
||||
getStyleClass().addAll("two-line-list-item", "card");
|
||||
JFXDepthManager.setDepth(this, 1);
|
||||
public InstallerItem(LibraryAnalyzer.LibraryType id) {
|
||||
this(id.getPatchId());
|
||||
}
|
||||
|
||||
String[] urls = new String[]{"/assets/img/grass.png", "/assets/img/fabric.png", "/assets/img/forge.png", "/assets/img/chicken.png", "/assets/img/command.png"};
|
||||
String[] libraryIds = new String[]{"game", "fabric", "forge", "liteloader", "optifine"};
|
||||
public InstallerItem(String id) {
|
||||
this.id = id;
|
||||
|
||||
boolean regularLibrary = false;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
if (libraryIds[i].equals(libraryId)) {
|
||||
setLeft(FXUtils.limitingSize(new ImageView(new Image(urls[i], 32, 32, true, true)), 32, 32));
|
||||
Label label = new Label();
|
||||
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
|
||||
BorderPane.setMargin(label, new Insets(0, 0, 0, 8));
|
||||
if (libraryVersion == null) {
|
||||
label.setText(i18n("install.installer.not_installed", i18n("install.installer." + libraryId)));
|
||||
} else {
|
||||
label.setText(i18n("install.installer.version", i18n("install.installer." + libraryId), libraryVersion));
|
||||
}
|
||||
setCenter(label);
|
||||
regularLibrary = true;
|
||||
switch (id) {
|
||||
case "game":
|
||||
imageUrl = "/assets/img/grass.png";
|
||||
break;
|
||||
case "fabric":
|
||||
imageUrl = "/assets/img/fabric.png";
|
||||
break;
|
||||
case "forge":
|
||||
imageUrl = "/assets/img/forge.png";
|
||||
break;
|
||||
case "liteloader":
|
||||
imageUrl = "/assets/img/chicken.png";
|
||||
break;
|
||||
case "optifine":
|
||||
imageUrl = "/assets/img/command.png";
|
||||
break;
|
||||
default:
|
||||
imageUrl = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!regularLibrary) {
|
||||
String title = I18n.hasKey("install.installer." + libraryId) ? i18n("install.installer." + libraryId) : libraryId;
|
||||
if (libraryVersion != null) {
|
||||
TwoLineListItem item = new TwoLineListItem();
|
||||
item.setTitle(title);
|
||||
item.setSubtitle(i18n("archive.version") + ": " + libraryVersion);
|
||||
setCenter(item);
|
||||
} else {
|
||||
Label label = new Label();
|
||||
label.setStyle("-fx-font-size: 15px;");
|
||||
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
|
||||
setCenter(label);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
HBox hBox = new HBox();
|
||||
|
||||
if (upgrade != null) {
|
||||
JFXButton upgradeButton = new JFXButton();
|
||||
if (libraryVersion == null) {
|
||||
upgradeButton.setGraphic(SVG.arrowRight(Theme.blackFillBinding(), -1, -1));
|
||||
} else {
|
||||
upgradeButton.setGraphic(SVG.update(Theme.blackFillBinding(), -1, -1));
|
||||
}
|
||||
upgradeButton.getStyleClass().add("toggle-icon4");
|
||||
FXUtils.installFastTooltip(upgradeButton, i18n("install.change_version"));
|
||||
upgradeButton.setOnMouseClicked(e -> upgrade.run());
|
||||
hBox.getChildren().add(upgradeButton);
|
||||
}
|
||||
|
||||
if (deleteCallback != null) {
|
||||
JFXButton deleteButton = new JFXButton();
|
||||
deleteButton.setGraphic(SVG.close(Theme.blackFillBinding(), -1, -1));
|
||||
deleteButton.getStyleClass().add("toggle-icon4");
|
||||
deleteButton.setOnMouseClicked(e -> deleteCallback.accept(this));
|
||||
hBox.getChildren().add(deleteButton);
|
||||
}
|
||||
|
||||
hBox.setAlignment(Pos.CENTER_RIGHT);
|
||||
setRight(hBox);
|
||||
}
|
||||
}
|
||||
|
||||
public void setState(String libraryVersion, boolean incompatibleWithGame, boolean removable) {
|
||||
this.libraryVersion.set(libraryVersion);
|
||||
this.incompatibleWithGame.set(incompatibleWithGame);
|
||||
this.removable.set(removable);
|
||||
}
|
||||
|
||||
public String getLibraryId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Skin<?> createDefaultSkin() {
|
||||
return new InstallerItemSkin(this);
|
||||
}
|
||||
|
||||
public static class InstallerItemGroup {
|
||||
public InstallerItem game = new InstallerItem(MINECRAFT);
|
||||
public InstallerItem fabric = new InstallerItem(FABRIC);
|
||||
public InstallerItem forge = new InstallerItem(FORGE);
|
||||
public InstallerItem liteLoader = new InstallerItem(LITELOADER);
|
||||
public InstallerItem optiFine = new InstallerItem(OPTIFINE);
|
||||
|
||||
public InstallerItemGroup() {
|
||||
forge.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> {
|
||||
if (fabric.libraryVersion.get() != null) return FABRIC.getPatchId();
|
||||
return null;
|
||||
}, fabric.libraryVersion));
|
||||
|
||||
liteLoader.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> {
|
||||
if (fabric.libraryVersion.get() != null) return FABRIC.getPatchId();
|
||||
return null;
|
||||
}, fabric.libraryVersion));
|
||||
|
||||
optiFine.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> {
|
||||
if (fabric.libraryVersion.get() != null) return FABRIC.getPatchId();
|
||||
return null;
|
||||
}, fabric.libraryVersion));
|
||||
|
||||
fabric.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> {
|
||||
if (liteLoader.libraryVersion.get() != null) return LITELOADER.getPatchId();
|
||||
if (optiFine.libraryVersion.get() != null) return OPTIFINE.getPatchId();
|
||||
if (forge.libraryVersion.get() != null) return FORGE.getPatchId();
|
||||
return null;
|
||||
}, optiFine.libraryVersion, forge.libraryVersion));
|
||||
}
|
||||
|
||||
public InstallerItem[] getLibraries() {
|
||||
return new InstallerItem[]{game, fabric, forge, liteLoader, optiFine};
|
||||
}
|
||||
}
|
||||
|
||||
public static class InstallerItemSkin extends SkinBase<InstallerItem> {
|
||||
|
||||
InstallerItemSkin(InstallerItem control) {
|
||||
super(control);
|
||||
|
||||
HBox hbox = new HBox();
|
||||
getChildren().setAll(hbox);
|
||||
JFXDepthManager.setDepth(hbox, 1);
|
||||
|
||||
hbox.getStyleClass().add("card");
|
||||
|
||||
hbox.setAlignment(Pos.CENTER_LEFT);
|
||||
|
||||
if (control.imageUrl != null) {
|
||||
hbox.getChildren().add(FXUtils.limitingSize(new ImageView(new Image(control.imageUrl, 32, 32, true, true)), 32, 32));
|
||||
}
|
||||
|
||||
Label nameLabel = new Label();
|
||||
hbox.getChildren().add(nameLabel);
|
||||
nameLabel.setPrefWidth(80);
|
||||
nameLabel.textProperty().set(I18n.hasKey("install.installer." + control.id) ? i18n("install.installer." + control.id) : control.id);
|
||||
HBox.setMargin(nameLabel, new Insets(0, 4, 0, 4));
|
||||
|
||||
Label label = new Label();
|
||||
hbox.getChildren().add(label);
|
||||
label.setMaxWidth(Double.MAX_VALUE);
|
||||
HBox.setHgrow(label, Priority.ALWAYS);
|
||||
label.textProperty().bind(Bindings.createStringBinding(() -> {
|
||||
String incompatibleWith = control.incompatibleLibraryName.get();
|
||||
String version = control.libraryVersion.get();
|
||||
if (control.incompatibleWithGame.get()) {
|
||||
return i18n("install.installer.change_version", version);
|
||||
} else if (incompatibleWith != null) {
|
||||
return i18n("install.installer.incompatible", i18n("install.installer." + incompatibleWith));
|
||||
} else if (version == null) {
|
||||
return i18n("install.installer.not_installed");
|
||||
} else {
|
||||
return i18n("install.installer.version", version);
|
||||
}
|
||||
}, control.incompatibleLibraryName, control.incompatibleWithGame, control.libraryVersion));
|
||||
BorderPane.setMargin(label, new Insets(0, 0, 0, 8));
|
||||
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
|
||||
|
||||
JFXButton closeButton = new JFXButton();
|
||||
closeButton.setGraphic(SVG.close(Theme.blackFillBinding(), -1, -1));
|
||||
closeButton.getStyleClass().add("toggle-icon4");
|
||||
closeButton.visibleProperty().bind(control.removable);
|
||||
closeButton.managedProperty().bind(closeButton.visibleProperty());
|
||||
closeButton.onMouseClickedProperty().bind(control.removeAction);
|
||||
hbox.getChildren().add(closeButton);
|
||||
|
||||
JFXButton arrowButton = new JFXButton();
|
||||
arrowButton.graphicProperty().bind(Bindings.createObjectBinding(() -> control.upgradable.get()
|
||||
? SVG.update(Theme.blackFillBinding(), -1, -1)
|
||||
: SVG.arrowRight(Theme.blackFillBinding(), -1, -1),
|
||||
control.upgradable));
|
||||
arrowButton.getStyleClass().add("toggle-icon4");
|
||||
arrowButton.visibleProperty().bind(Bindings.createBooleanBinding(
|
||||
() -> control.installable.get() && control.incompatibleLibraryName.get() == null,
|
||||
control.installable, control.incompatibleLibraryName));
|
||||
arrowButton.managedProperty().bind(arrowButton.visibleProperty());
|
||||
arrowButton.onMouseClickedProperty().bind(control.action);
|
||||
hbox.getChildren().add(arrowButton);
|
||||
|
||||
FXUtils.onChangeAndOperate(arrowButton.visibleProperty(), clickable -> {
|
||||
if (clickable) {
|
||||
hbox.onMouseClickedProperty().bind(control.action);
|
||||
hbox.setCursor(Cursor.HAND);
|
||||
} else {
|
||||
hbox.onMouseClickedProperty().unbind();
|
||||
hbox.onMouseClickedProperty().set(null);
|
||||
hbox.setCursor(Cursor.DEFAULT);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.game.GameRepository;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.ui.InstallerItem;
|
||||
import org.jackhuang.hmcl.ui.wizard.WizardController;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
|
||||
@ -53,10 +54,8 @@ class AdditionalInstallersPage extends InstallersPage {
|
||||
() -> compatible.get() && txtName.validate(),
|
||||
txtName.textProperty(), compatible));
|
||||
|
||||
InstallerPageItem[] libraries = new InstallerPageItem[]{game, fabric, forge, liteLoader, optiFine};
|
||||
|
||||
for (InstallerPageItem library : libraries) {
|
||||
String libraryId = library.id;
|
||||
for (InstallerItem library : group.getLibraries()) {
|
||||
String libraryId = library.getLibraryId();
|
||||
if (libraryId.equals("game")) continue;
|
||||
library.removeAction.set(e -> {
|
||||
controller.getSettings().put(libraryId, new UpdateInstallerWizardProvider.RemoveVersionAction(libraryId));
|
||||
@ -90,28 +89,25 @@ class AdditionalInstallersPage extends InstallersPage {
|
||||
String liteLoader = analyzer.getVersion(LITELOADER).orElse(null);
|
||||
String optiFine = analyzer.getVersion(OPTIFINE).orElse(null);
|
||||
|
||||
InstallerPageItem[] libraries = new InstallerPageItem[]{this.game, this.fabric, this.forge, this.liteLoader, this.optiFine};
|
||||
InstallerItem[] libraries = group.getLibraries();
|
||||
String[] versions = new String[]{game, fabric, forge, liteLoader, optiFine};
|
||||
|
||||
String currentGameVersion = Lang.nonNull(getVersion("game"), game);
|
||||
|
||||
boolean compatible = true;
|
||||
for (int i = 0; i < libraries.length; ++i) {
|
||||
String libraryId = libraries[i].id;
|
||||
String libraryId = libraries[i].getLibraryId();
|
||||
String libraryVersion = Lang.nonNull(getVersion(libraryId), versions[i]);
|
||||
boolean alreadyInstalled = versions[i] != null && !(controller.getSettings().get(libraryId) instanceof UpdateInstallerWizardProvider.RemoveVersionAction);
|
||||
if (!"game".equals(libraryId) && currentGameVersion != null && !currentGameVersion.equals(game) && getVersion(libraryId) == null && alreadyInstalled) {
|
||||
// For third-party libraries, if game version is being changed, and the library is not being reinstalled,
|
||||
// warns the user that we should update the library.
|
||||
libraries[i].label.set(i18n("install.installer.change_version", i18n("install.installer." + libraryId), libraryVersion));
|
||||
libraries[i].removable.set(true);
|
||||
libraries[i].setState(libraryVersion, /* incompatibleWithGame */ true, /* removable */ true);
|
||||
compatible = false;
|
||||
} else if (alreadyInstalled || getVersion(libraryId) != null) {
|
||||
libraries[i].label.set(i18n("install.installer.version", i18n("install.installer." + libraryId), libraryVersion));
|
||||
libraries[i].removable.set(true);
|
||||
libraries[i].setState(libraryVersion, /* incompatibleWithGame */ false, /* removable */ true);
|
||||
} else {
|
||||
libraries[i].label.set(i18n("install.installer.not_installed", i18n("install.installer." + libraryId)));
|
||||
libraries[i].removable.set(false);
|
||||
libraries[i].setState(/* libraryVersion */ null, /* incompatibleWithGame */ false, /* removable */ false);
|
||||
}
|
||||
}
|
||||
this.compatible.set(compatible);
|
||||
|
@ -19,29 +19,21 @@ package org.jackhuang.hmcl.ui.download;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.controls.JFXTextField;
|
||||
import com.jfoenix.effects.JFXDepthManager;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.control.Control;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Skin;
|
||||
import javafx.scene.control.SkinBase;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.game.GameRepository;
|
||||
import org.jackhuang.hmcl.setting.Theme;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.ui.SVG;
|
||||
import org.jackhuang.hmcl.ui.InstallerItem;
|
||||
import org.jackhuang.hmcl.ui.construct.Validator;
|
||||
import org.jackhuang.hmcl.ui.wizard.WizardController;
|
||||
import org.jackhuang.hmcl.ui.wizard.WizardPage;
|
||||
@ -55,11 +47,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
public class InstallersPage extends Control implements WizardPage {
|
||||
protected final WizardController controller;
|
||||
|
||||
protected InstallerPageItem game = new InstallerPageItem("game");
|
||||
protected InstallerPageItem fabric = new InstallerPageItem("fabric");
|
||||
protected InstallerPageItem forge = new InstallerPageItem("forge");
|
||||
protected InstallerPageItem liteLoader = new InstallerPageItem("liteloader");
|
||||
protected InstallerPageItem optiFine = new InstallerPageItem("optifine");
|
||||
protected InstallerItem.InstallerItemGroup group = new InstallerItem.InstallerItemGroup();
|
||||
protected JFXTextField txtName = new JFXTextField();
|
||||
protected BooleanProperty installable = new SimpleBooleanProperty();
|
||||
|
||||
@ -75,13 +63,15 @@ public class InstallersPage extends Control implements WizardPage {
|
||||
txtName.textProperty()));
|
||||
txtName.setText(gameVersion);
|
||||
|
||||
InstallerPageItem[] libraries = new InstallerPageItem[]{game, fabric, forge, liteLoader, optiFine};
|
||||
group.game.installable.setValue(false);
|
||||
|
||||
for (InstallerPageItem library : libraries) {
|
||||
String libraryId = library.id;
|
||||
for (InstallerItem library : group.getLibraries()) {
|
||||
String libraryId = library.getLibraryId();
|
||||
if (libraryId.equals("game")) continue;
|
||||
library.action.set(e ->
|
||||
controller.onNext(new VersionsPage(controller, i18n("install.installer.choose", i18n("install.installer." + libraryId)), gameVersion, downloadProvider, libraryId, () -> controller.onPrev(false))));
|
||||
library.action.set(e -> {
|
||||
if (library.incompatibleLibraryName.get() == null)
|
||||
controller.onNext(new VersionsPage(controller, i18n("install.installer.choose", i18n("install.installer." + libraryId)), gameVersion, downloadProvider, libraryId, () -> controller.onPrev(false)));
|
||||
});
|
||||
library.removeAction.set(e -> {
|
||||
controller.getSettings().remove(libraryId);
|
||||
reload();
|
||||
@ -99,15 +89,13 @@ public class InstallersPage extends Control implements WizardPage {
|
||||
}
|
||||
|
||||
protected void reload() {
|
||||
InstallerPageItem[] libraries = new InstallerPageItem[]{game, fabric, forge, liteLoader, optiFine};
|
||||
|
||||
for (InstallerPageItem library : libraries) {
|
||||
String libraryId = library.id;
|
||||
for (InstallerItem library : group.getLibraries()) {
|
||||
String libraryId = library.getLibraryId();
|
||||
if (controller.getSettings().containsKey(libraryId)) {
|
||||
library.label.set(i18n("install.installer.version", i18n("install.installer." + libraryId), getVersion(libraryId)));
|
||||
library.libraryVersion.set(getVersion(libraryId));
|
||||
library.removable.set(true);
|
||||
} else {
|
||||
library.label.setValue(i18n("install.installer.not_installed", i18n("install.installer." + libraryId)));
|
||||
library.libraryVersion.set(null);
|
||||
library.removable.set(false);
|
||||
}
|
||||
}
|
||||
@ -133,54 +121,8 @@ public class InstallersPage extends Control implements WizardPage {
|
||||
return new InstallersPageSkin(this);
|
||||
}
|
||||
|
||||
protected static class InstallerPageItem {
|
||||
String id;
|
||||
StringProperty label = new SimpleStringProperty();
|
||||
BooleanProperty removable = new SimpleBooleanProperty();
|
||||
ObjectProperty<EventHandler<? super MouseEvent>> removeAction = new SimpleObjectProperty<>();
|
||||
ObjectProperty<EventHandler<? super MouseEvent>> action = new SimpleObjectProperty<>();
|
||||
|
||||
public InstallerPageItem(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class InstallersPageSkin extends SkinBase<InstallersPage> {
|
||||
|
||||
protected static class InstallersPageItemSkin extends BorderPane {
|
||||
final ImageView imageView;
|
||||
final Label label;
|
||||
|
||||
InstallersPageItemSkin(String imageUrl, InstallerPageItem item, boolean clickable) {
|
||||
getStyleClass().add("card");
|
||||
|
||||
setLeft(FXUtils.limitingSize(imageView = new ImageView(new Image(imageUrl, 32, 32, true, true)), 32, 32));
|
||||
setCenter(label = new Label());
|
||||
label.textProperty().bind(item.label);
|
||||
BorderPane.setMargin(label, new Insets(0, 0, 0, 8));
|
||||
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
|
||||
|
||||
if (clickable) {
|
||||
HBox right = new HBox();
|
||||
right.setAlignment(Pos.CENTER_RIGHT);
|
||||
setRight(right);
|
||||
JFXButton closeButton = new JFXButton();
|
||||
closeButton.setGraphic(SVG.close(Theme.blackFillBinding(), -1, -1));
|
||||
right.getChildren().add(closeButton);
|
||||
closeButton.getStyleClass().add("toggle-icon4");
|
||||
closeButton.visibleProperty().bind(item.removable);
|
||||
closeButton.onMouseClickedProperty().bind(item.removeAction);
|
||||
onMouseClickedProperty().bind(item.action);
|
||||
JFXButton arrowButton = new JFXButton();
|
||||
arrowButton.setGraphic(SVG.arrowRight(Theme.blackFillBinding(), -1, -1));
|
||||
arrowButton.onMouseClickedProperty().bind(item.action);
|
||||
arrowButton.getStyleClass().add("toggle-icon4");
|
||||
right.getChildren().add(arrowButton);
|
||||
setCursor(Cursor.HAND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for all SkinBase instances.
|
||||
*
|
||||
@ -207,13 +149,7 @@ public class InstallersPage extends Control implements WizardPage {
|
||||
list.getChildren().add(versionNamePane);
|
||||
}
|
||||
|
||||
InstallersPageItemSkin game = new InstallersPageItemSkin("/assets/img/grass.png", control.game, false);
|
||||
InstallersPageItemSkin fabric = new InstallersPageItemSkin("/assets/img/fabric.png", control.fabric, true);
|
||||
InstallersPageItemSkin forge = new InstallersPageItemSkin("/assets/img/forge.png", control.forge, true);
|
||||
InstallersPageItemSkin liteLoader = new InstallersPageItemSkin("/assets/img/chicken.png", control.liteLoader, true);
|
||||
InstallersPageItemSkin optiFine = new InstallersPageItemSkin("/assets/img/command.png", control.optiFine, true);
|
||||
list.getChildren().addAll(game, fabric, forge, liteLoader, optiFine);
|
||||
list.getChildren().forEach(node -> JFXDepthManager.setDepth(node, 1));
|
||||
list.getChildren().addAll(control.group.getLibraries());
|
||||
|
||||
{
|
||||
JFXButton installButton = new JFXButton(i18n("button.install"));
|
||||
|
@ -18,6 +18,7 @@
|
||||
package org.jackhuang.hmcl.ui.versions;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Skin;
|
||||
import javafx.stage.FileChooser;
|
||||
@ -42,6 +43,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.*;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
@ -74,7 +76,7 @@ public class InstallerListPage extends ListPageBase<InstallerItem> {
|
||||
|
||||
return LibraryAnalyzer.analyze(profile.getRepository().getResolvedPreservingPatchesVersion(versionId));
|
||||
}).thenAcceptAsync(analyzer -> {
|
||||
Function<String, Consumer<InstallerItem>> removeAction = libraryId -> x -> {
|
||||
Function<String, Runnable> removeAction = libraryId -> () -> {
|
||||
profile.getDependency().removeLibraryAsync(version, libraryId)
|
||||
.thenComposeAsync(profile.getRepository()::saveAsync)
|
||||
.withComposeAsync(profile.getRepository().refreshVersionsAsync())
|
||||
@ -84,15 +86,28 @@ public class InstallerListPage extends ListPageBase<InstallerItem> {
|
||||
|
||||
itemsProperty().clear();
|
||||
|
||||
for (LibraryAnalyzer.LibraryType type : LibraryAnalyzer.LibraryType.values()) {
|
||||
String libraryId = type.getPatchId();
|
||||
String libraryVersion = analyzer.getVersion(type).orElse(null);
|
||||
Consumer<InstallerItem> action = "game".equals(libraryId) || libraryVersion == null ? null : removeAction.apply(libraryId);
|
||||
itemsProperty().add(new InstallerItem(libraryId, libraryVersion, () -> {
|
||||
InstallerItem.InstallerItemGroup group = new InstallerItem.InstallerItemGroup();
|
||||
|
||||
// Conventional libraries: game, fabric, forge, liteloader, optifine
|
||||
for (InstallerItem installerItem : group.getLibraries()) {
|
||||
String libraryId = installerItem.getLibraryId();
|
||||
String libraryVersion = analyzer.getVersion(libraryId).orElse(null);
|
||||
installerItem.libraryVersion.set(libraryVersion);
|
||||
installerItem.upgradable.set(libraryVersion != null);
|
||||
installerItem.installable.set(true);
|
||||
installerItem.action.set(e -> {
|
||||
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, libraryId, libraryVersion));
|
||||
}, action));
|
||||
});
|
||||
boolean removable = !"game".equals(libraryId) && libraryVersion != null;
|
||||
installerItem.removable.set(removable);
|
||||
if (removable) {
|
||||
Runnable action = removeAction.apply(libraryId);
|
||||
installerItem.removeAction.set(e -> action.run());
|
||||
}
|
||||
itemsProperty().add(installerItem);
|
||||
}
|
||||
|
||||
// other third-party libraries which are unable to manage.
|
||||
for (LibraryAnalyzer.LibraryMark mark : analyzer) {
|
||||
String libraryId = mark.getLibraryId();
|
||||
String libraryVersion = mark.getLibraryVersion();
|
||||
@ -101,14 +116,23 @@ public class InstallerListPage extends ListPageBase<InstallerItem> {
|
||||
if (LibraryAnalyzer.LibraryType.fromPatchId(libraryId) != null)
|
||||
continue;
|
||||
|
||||
Consumer<InstallerItem> action = removeAction.apply(libraryId);
|
||||
if (libraryVersion != null && Lang.test(() -> profile.getDependency().getVersionList(libraryId)))
|
||||
itemsProperty().add(
|
||||
new InstallerItem(libraryId, libraryVersion, () -> {
|
||||
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, libraryId, libraryVersion));
|
||||
}, action));
|
||||
else
|
||||
itemsProperty().add(new InstallerItem(libraryId, libraryVersion, null, action));
|
||||
Runnable action = removeAction.apply(libraryId);
|
||||
|
||||
InstallerItem installerItem = new InstallerItem(libraryId);
|
||||
installerItem.libraryVersion.set(libraryVersion);
|
||||
installerItem.installable.set(false);
|
||||
installerItem.upgradable.bind(installerItem.installable);
|
||||
installerItem.removable.set(true);
|
||||
installerItem.removeAction.set(e -> action.run());
|
||||
|
||||
if (libraryVersion != null && Lang.test(() -> profile.getDependency().getVersionList(libraryId))) {
|
||||
installerItem.installable.set(true);
|
||||
installerItem.action.set(e -> {
|
||||
Controllers.getDecorator().startWizard(new UpdateInstallerWizardProvider(profile, gameVersion, version, libraryId, libraryVersion));
|
||||
});
|
||||
}
|
||||
|
||||
itemsProperty().add(installerItem);
|
||||
}
|
||||
}, Platform::runLater);
|
||||
}
|
||||
|
@ -139,11 +139,12 @@ install.failed.install_online=Unable to recognize the provided installer file
|
||||
install.failed.malformed=The files just downloaded a moment ago is malformed. You may switch to other download provider to resolve this problem.
|
||||
install.failed.optifine_conflict=Fabric, OptiFine and Forge are installed simultaneously on Minecraft 1.13
|
||||
install.failed.version_mismatch=The library requires the game version %s, but the actual version is %s.
|
||||
install.installer.change_version=%s version: %s, this version is not compatible with current game version. Click here to choose another one.
|
||||
install.installer.change_version=%s, this version is not compatible with current game version. Click here to choose another one.
|
||||
install.installer.choose=Choose a %s version
|
||||
install.installer.fabric=Fabric
|
||||
install.installer.forge=Forge
|
||||
install.installer.game=Minecraft
|
||||
install.installer.incompatible=Incompatible with %s
|
||||
install.installer.install=Install %s
|
||||
install.installer.install_offline=Install/Upgrade from file
|
||||
install.installer.install_offline.extension=Forge/OptiFine installer
|
||||
@ -151,9 +152,9 @@ install.installer.install_offline.tooltip=Supports import of Forge/OptiFine inst
|
||||
install.installer.install_online=Install Online
|
||||
install.installer.install_online.tooltip=Support installation of Fabric, Forge, OptiFine, LiteLoader.
|
||||
install.installer.liteloader=LiteLoader
|
||||
install.installer.not_installed=%s Version: not installed
|
||||
install.installer.not_installed=Not installed
|
||||
install.installer.optifine=OptiFine
|
||||
install.installer.version=%s Version: %s
|
||||
install.installer.version=%s
|
||||
install.modpack=Install a modpack
|
||||
install.new_game=Install a New Game
|
||||
install.new_game.already_exists=This version already exists.
|
||||
|
@ -140,6 +140,7 @@ install.installer.choose=Escoja una versión de %s
|
||||
install.installer.fabric=Fabric
|
||||
install.installer.forge=Forge
|
||||
install.installer.game=Minecraft
|
||||
install.installer.incompatible=Incompatible with %s
|
||||
install.installer.install=Instalar %s
|
||||
install.installer.install_offline=Instalar/actualizar con archivo local
|
||||
install.installer.install_offline.extension=Instalador de Forge/OptiFine
|
||||
@ -147,9 +148,9 @@ install.installer.install_offline.tooltip=Soporta importación de archivo instal
|
||||
install.installer.install_online=Instalar en línea
|
||||
install.installer.install_online.tooltip=Soporta instalación de Fabric, Forge, OptiFine, LiteLoader
|
||||
install.installer.liteloader=LiteLoader
|
||||
install.installer.not_installed=%s no está instalado
|
||||
install.installer.not_installed=no está instalado
|
||||
install.installer.optifine=OptiFine
|
||||
install.installer.version=Versión %s: %s
|
||||
install.installer.version=%s
|
||||
install.modpack=Instalar un modpack
|
||||
install.new_game=Instalar un juego nuevo
|
||||
install.new_game.already_exists=Esta versión ya existe.
|
||||
|
@ -139,11 +139,12 @@ install.failed.install_online=Невозможно распознать пред
|
||||
install.failed.malformed=Файлы, скачаные минуту назад, неправильно сформированы. Для решения этой проблемы можно переключиться на другого поставщика скачивания.
|
||||
install.failed.optifine_conflict=Fabric, OptiFine и Forge установлены одновременно на Minecraft 1.13
|
||||
install.failed.version_mismatch=Библиотека требует версию игры %s, но фактическая версия %s.
|
||||
install.installer.change_version=Версия %s: %s, эта версия не совместима с текущей версией игры. Что бы выбрать другую, нажмите здесь.
|
||||
install.installer.change_version=%s, эта версия не совместима с текущей версией игры. Что бы выбрать другую, нажмите здесь.
|
||||
install.installer.choose=Выберите версию %s
|
||||
install.installer.fabric=Fabric
|
||||
install.installer.forge=Forge
|
||||
install.installer.game=Minecraft
|
||||
install.installer.incompatible=Incompatible with %s
|
||||
install.installer.install=Установка %s
|
||||
install.installer.install_offline=Установить/обновить из файла
|
||||
install.installer.install_offline.extension=Установщик Forge/OptiFine
|
||||
@ -151,9 +152,9 @@ install.installer.install_offline.tooltip=Поддерживает импорт
|
||||
install.installer.install_online=Установить из сети
|
||||
install.installer.install_online.tooltip=Поддерживается установка Fabric, Forge, OptiFine, LiteLoader.
|
||||
install.installer.liteloader=LiteLoader
|
||||
install.installer.not_installed=%s не установлен
|
||||
install.installer.not_installed=не установлен
|
||||
install.installer.optifine=OptiFine
|
||||
install.installer.version=%s - версия: %s
|
||||
install.installer.version=%s
|
||||
install.modpack=Установить модпак
|
||||
install.new_game=Установка новой игры
|
||||
install.new_game.already_exists=Эта версия уже существует.
|
||||
|
@ -139,11 +139,12 @@ install.failed.install_online=無法識別要安裝的軟體
|
||||
install.failed.malformed=剛才下載的檔案格式損壞。您可以切換到其他下載來源以解決此問題。
|
||||
install.failed.optifine_conflict=暫不支援 OptiFine 與 Forge 同時安裝在 Minecraft 1.13 上
|
||||
install.failed.version_mismatch=該軟體需要的遊戲版本為 %s,但實際的遊戲版本為 %s。
|
||||
install.installer.change_version=%s 版本: %s,該版本與當前遊戲不相容,您需要點擊此處更換版本或刪除
|
||||
install.installer.change_version=%s,該版本與當前遊戲不相容,您需要點擊此處更換版本或刪除
|
||||
install.installer.choose=選擇 %s 版本
|
||||
install.installer.fabric=Fabric
|
||||
install.installer.forge=Forge
|
||||
install.installer.game=Minecraft
|
||||
install.installer.incompatible=與 %s 不相容
|
||||
install.installer.install=安裝%s
|
||||
install.installer.install_offline=從本機檔案安裝或升級
|
||||
install.installer.install_offline.extension=Forge/OptiFine 安裝器
|
||||
@ -151,9 +152,9 @@ install.installer.install_offline.tooltip=支援匯入已經下載好的 Forge/O
|
||||
install.installer.install_online=線上安裝
|
||||
install.installer.install_online.tooltip=支援安裝 Fabric、Forge、OptiFine、LiteLoader
|
||||
install.installer.liteloader=LiteLoader
|
||||
install.installer.not_installed=%s 版本: 不安裝
|
||||
install.installer.not_installed=不安裝
|
||||
install.installer.optifine=OptiFine
|
||||
install.installer.version=%s 版本: %s
|
||||
install.installer.version=%s
|
||||
install.modpack=安裝整合包
|
||||
install.new_game=安裝新遊戲版本
|
||||
install.new_game.already_exists=此版本已經存在,請重新命名
|
||||
|
@ -139,11 +139,12 @@ install.failed.install_online=无法识别要安装的软件
|
||||
install.failed.malformed=刚才下载的文件格式损坏。您可以切换到其他下载源来解决此问题。
|
||||
install.failed.optifine_conflict=暂不支持 OptiFine, Fabric 与 Forge 同时安装在 Minecraft 1.13 及以上版本
|
||||
install.failed.version_mismatch=该软件需要的游戏版本为 %s,但实际的游戏版本为 %s。
|
||||
install.installer.change_version=%s 版本: %s,该版本与当前游戏不兼容,您需要点击此处更换版本或删除
|
||||
install.installer.change_version=%s,该版本与当前游戏不兼容,您需要点击此处更换版本或删除
|
||||
install.installer.choose=选择 %s 版本
|
||||
install.installer.fabric=Fabric
|
||||
install.installer.forge=Forge
|
||||
install.installer.game=Minecraft
|
||||
install.installer.incompatible=与 %s 不兼容
|
||||
install.installer.install=安装 %s
|
||||
install.installer.install_offline=从本地文件安装/升级
|
||||
install.installer.install_offline.extension=Forge/OptiFine 安装器
|
||||
@ -151,9 +152,9 @@ install.installer.install_offline.tooltip=支持导入已经下载好的 Forge/O
|
||||
install.installer.install_online=在线安装
|
||||
install.installer.install_online.tooltip=支持安装 Fabric、Forge、OptiFine、LiteLoader
|
||||
install.installer.liteloader=LiteLoader
|
||||
install.installer.not_installed=%s 版本: 不安装
|
||||
install.installer.not_installed=不安装
|
||||
install.installer.optifine=OptiFine
|
||||
install.installer.version=%s 版本: %s
|
||||
install.installer.version=%s
|
||||
install.modpack=安装整合包
|
||||
install.new_game=安装新游戏版本
|
||||
install.new_game.already_exists=此版本已经存在,请换一个名字
|
||||
|
@ -104,7 +104,7 @@ public final class ForgeInstallTask extends Task<Version> {
|
||||
public void execute() throws IOException, VersionMismatchException, OptiFineInstallTask.UnsupportedOptiFineInstallationException {
|
||||
String originalMainClass = version.resolve(dependencyManager.getGameRepository()).getMainClass();
|
||||
if (VersionNumber.VERSION_COMPARATOR.compare("1.13", remote.getGameVersion()) <= 0) {
|
||||
// Forge 1.13 is not compatible with any other libraries.
|
||||
// Forge 1.13 is not compatible with fabric.
|
||||
if (!LibraryAnalyzer.VANILLA_MAIN.equals(originalMainClass) && !LibraryAnalyzer.MOD_LAUNCHER_MAIN.equals(originalMainClass) && !LibraryAnalyzer.LAUNCH_WRAPPER_MAIN.equals(originalMainClass))
|
||||
throw new OptiFineInstallTask.UnsupportedOptiFineInstallationException();
|
||||
} else {
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-all.zip
|
||||
|
Loading…
x
Reference in New Issue
Block a user