Merge commit '9bef8b432b9095bdb470f7a1e7c1ce8fcab37c01' into javafx
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Hello Minecraft! Launcher
|
* Hello Minecraft! Launcher
|
||||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
* Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -20,14 +20,13 @@ package org.jackhuang.hmcl.game;
|
|||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.binding.ObjectBinding;
|
import javafx.beans.binding.ObjectBinding;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.PixelWriter;
|
|
||||||
import javafx.scene.image.WritableImage;
|
|
||||||
import org.jackhuang.hmcl.Metadata;
|
import org.jackhuang.hmcl.Metadata;
|
||||||
import org.jackhuang.hmcl.auth.Account;
|
import org.jackhuang.hmcl.auth.Account;
|
||||||
import org.jackhuang.hmcl.auth.ServerResponseMalformedException;
|
import org.jackhuang.hmcl.auth.ServerResponseMalformedException;
|
||||||
import org.jackhuang.hmcl.auth.microsoft.MicrosoftAccount;
|
import org.jackhuang.hmcl.auth.microsoft.MicrosoftAccount;
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.*;
|
import org.jackhuang.hmcl.auth.yggdrasil.*;
|
||||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||||
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.util.ResourceNotFoundError;
|
import org.jackhuang.hmcl.util.ResourceNotFoundError;
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
||||||
@@ -231,34 +230,18 @@ public final class TexturesLoader {
|
|||||||
public static ObjectBinding<Image> fxAvatarBinding(YggdrasilService service, UUID uuid, int size) {
|
public static ObjectBinding<Image> fxAvatarBinding(YggdrasilService service, UUID uuid, int size) {
|
||||||
return BindingMapping.of(skinBinding(service, uuid))
|
return BindingMapping.of(skinBinding(service, uuid))
|
||||||
.map(it -> toAvatar(it.image, size))
|
.map(it -> toAvatar(it.image, size))
|
||||||
.map(TexturesLoader::toFXImage);
|
.map(FXUtils::toFXImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ObjectBinding<Image> fxAvatarBinding(Account account, int size) {
|
public static ObjectBinding<Image> fxAvatarBinding(Account account, int size) {
|
||||||
if (account instanceof YggdrasilAccount || account instanceof MicrosoftAccount) {
|
if (account instanceof YggdrasilAccount || account instanceof MicrosoftAccount) {
|
||||||
return BindingMapping.of(skinBinding(account))
|
return BindingMapping.of(skinBinding(account))
|
||||||
.map(it -> toAvatar(it.image, size))
|
.map(it -> toAvatar(it.image, size))
|
||||||
.map(TexturesLoader::toFXImage);
|
.map(FXUtils::toFXImage);
|
||||||
} else {
|
} else {
|
||||||
return Bindings.createObjectBinding(
|
return Bindings.createObjectBinding(
|
||||||
() -> toFXImage(toAvatar(getDefaultSkin(TextureModel.detectUUID(account.getUUID())).image, size)));
|
() -> FXUtils.toFXImage(toAvatar(getDefaultSkin(TextureModel.detectUUID(account.getUUID())).image, size)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
|
||||||
// Based on https://stackoverflow.com/a/57552025
|
|
||||||
// Fix #874: Use it instead of SwingFXUtils.toFXImage
|
|
||||||
private static WritableImage toFXImage(BufferedImage image) {
|
|
||||||
WritableImage wr = new WritableImage(image.getWidth(), image.getHeight());
|
|
||||||
PixelWriter pw = wr.getPixelWriter();
|
|
||||||
|
|
||||||
final int iw = image.getWidth();
|
|
||||||
final int ih = image.getHeight();
|
|
||||||
for (int x = 0; x < iw; x++) {
|
|
||||||
for (int y = 0; y < ih; y++) {
|
|
||||||
pw.setArgb(x, y, image.getRGB(x, y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return wr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ import javafx.scene.Node;
|
|||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.image.PixelWriter;
|
||||||
|
import javafx.scene.image.WritableImage;
|
||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.input.TransferMode;
|
import javafx.scene.input.TransferMode;
|
||||||
@@ -55,6 +57,7 @@ import org.jackhuang.hmcl.util.javafx.ExtendedProperties;
|
|||||||
import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
|
import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
|
||||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -552,4 +555,20 @@ public final class FXUtils {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Based on https://stackoverflow.com/a/57552025
|
||||||
|
// Fix #874: Use it instead of SwingFXUtils.toFXImage
|
||||||
|
public static WritableImage toFXImage(BufferedImage image) {
|
||||||
|
WritableImage wr = new WritableImage(image.getWidth(), image.getHeight());
|
||||||
|
PixelWriter pw = wr.getPixelWriter();
|
||||||
|
|
||||||
|
final int iw = image.getWidth();
|
||||||
|
final int ih = image.getHeight();
|
||||||
|
for (int x = 0; x < iw; x++) {
|
||||||
|
for (int y = 0; y < ih; y++) {
|
||||||
|
pw.setArgb(x, y, image.getRGB(x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Hello Minecraft! Launcher
|
* Hello Minecraft! Launcher
|
||||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
* Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -20,6 +20,7 @@ package org.jackhuang.hmcl.ui.account;
|
|||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Tooltip;
|
import javafx.scene.control.Tooltip;
|
||||||
@@ -27,14 +28,19 @@ import javafx.scene.image.ImageView;
|
|||||||
import org.jackhuang.hmcl.auth.Account;
|
import org.jackhuang.hmcl.auth.Account;
|
||||||
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorAccount;
|
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorAccount;
|
||||||
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
|
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
|
||||||
|
import org.jackhuang.hmcl.auth.yggdrasil.TextureModel;
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
||||||
import org.jackhuang.hmcl.game.TexturesLoader;
|
import org.jackhuang.hmcl.game.TexturesLoader;
|
||||||
import org.jackhuang.hmcl.setting.Accounts;
|
import org.jackhuang.hmcl.setting.Accounts;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.construct.AdvancedListItem;
|
import org.jackhuang.hmcl.ui.construct.AdvancedListItem;
|
||||||
import org.jackhuang.hmcl.util.Pair;
|
import org.jackhuang.hmcl.util.Pair;
|
||||||
|
import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.ui.FXUtils.newImage;
|
import static javafx.beans.binding.Bindings.createStringBinding;
|
||||||
|
import static org.jackhuang.hmcl.setting.Accounts.getAccountFactory;
|
||||||
|
import static org.jackhuang.hmcl.setting.Accounts.getLocalizedLoginTypeName;
|
||||||
|
import static org.jackhuang.hmcl.ui.FXUtils.toFXImage;
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
public class AccountAdvancedListItem extends AdvancedListItem {
|
public class AccountAdvancedListItem extends AdvancedListItem {
|
||||||
@@ -48,16 +54,18 @@ public class AccountAdvancedListItem extends AdvancedListItem {
|
|||||||
Account account = get();
|
Account account = get();
|
||||||
if (account == null) {
|
if (account == null) {
|
||||||
titleProperty().unbind();
|
titleProperty().unbind();
|
||||||
|
subtitleProperty().unbind();
|
||||||
|
imageView.imageProperty().unbind();
|
||||||
|
tooltip.textProperty().unbind();
|
||||||
setTitle(i18n("account.missing"));
|
setTitle(i18n("account.missing"));
|
||||||
setSubtitle(i18n("account.missing.add"));
|
setSubtitle(i18n("account.missing.add"));
|
||||||
imageView.imageProperty().unbind();
|
imageView.setImage(toFXImage(TexturesLoader.toAvatar(TexturesLoader.getDefaultSkin(TextureModel.STEVE).getImage(), 32)));
|
||||||
imageView.setImage(newImage("/assets/img/steve.png"));
|
tooltip.setText(i18n("account.create"));
|
||||||
tooltip.setText("");
|
|
||||||
} else {
|
} else {
|
||||||
titleProperty().bind(Bindings.createStringBinding(account::getCharacter, account));
|
titleProperty().bind(BindingMapping.of(account, Account::getCharacter));
|
||||||
setSubtitle(accountSubtitle(account));
|
subtitleProperty().bind(accountSubtitle(account));
|
||||||
imageView.imageProperty().bind(TexturesLoader.fxAvatarBinding(account, 32));
|
imageView.imageProperty().bind(TexturesLoader.fxAvatarBinding(account, 32));
|
||||||
tooltip.setText(account.getCharacter() + " " + accountTooltip(account));
|
tooltip.textProperty().bind(accountTooltip(account));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -88,23 +96,27 @@ public class AccountAdvancedListItem extends AdvancedListItem {
|
|||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String accountSubtitle(Account account) {
|
private static ObservableValue<String> accountSubtitle(Account account) {
|
||||||
String loginTypeName = Accounts.getLocalizedLoginTypeName(Accounts.getAccountFactory(account));
|
|
||||||
if (account instanceof AuthlibInjectorAccount) {
|
if (account instanceof AuthlibInjectorAccount) {
|
||||||
return ((AuthlibInjectorAccount) account).getServer().getName();
|
return BindingMapping.of(((AuthlibInjectorAccount) account).getServer(), AuthlibInjectorServer::getName);
|
||||||
} else {
|
} else {
|
||||||
return loginTypeName;
|
return createStringBinding(() -> getLocalizedLoginTypeName(getAccountFactory(account)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String accountTooltip(Account account) {
|
private static ObservableValue<String> accountTooltip(Account account) {
|
||||||
if (account instanceof AuthlibInjectorAccount) {
|
if (account instanceof AuthlibInjectorAccount) {
|
||||||
AuthlibInjectorServer server = ((AuthlibInjectorAccount) account).getServer();
|
AuthlibInjectorServer server = ((AuthlibInjectorAccount) account).getServer();
|
||||||
return account.getUsername() + ", " + i18n("account.injector.server") + ": " + server.getName();
|
return Bindings.format("%s (%s) (%s)",
|
||||||
|
BindingMapping.of(account, Account::getCharacter),
|
||||||
|
account.getUsername(),
|
||||||
|
BindingMapping.of(server, AuthlibInjectorServer::getName));
|
||||||
} else if (account instanceof YggdrasilAccount) {
|
} else if (account instanceof YggdrasilAccount) {
|
||||||
return account.getUsername();
|
return Bindings.format("%s (%s)",
|
||||||
|
BindingMapping.of(account, Account::getCharacter),
|
||||||
|
account.getUsername());
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return BindingMapping.of(account, Account::getCharacter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ import static java.util.logging.Level.WARNING;
|
|||||||
import static java.util.stream.Collectors.toList;
|
import static java.util.stream.Collectors.toList;
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||||
import static org.jackhuang.hmcl.ui.FXUtils.newImage;
|
import static org.jackhuang.hmcl.ui.FXUtils.newImage;
|
||||||
|
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
|
||||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||||
import static org.jackhuang.hmcl.util.io.FileUtils.getExtension;
|
import static org.jackhuang.hmcl.util.io.FileUtils.getExtension;
|
||||||
|
|
||||||
@@ -86,33 +87,39 @@ public class DecoratorController {
|
|||||||
|
|
||||||
setupAuthlibInjectorDnD();
|
setupAuthlibInjectorDnD();
|
||||||
|
|
||||||
// pass key events to current dialog
|
// pass key events to current dialog / current page
|
||||||
decorator.addEventFilter(KeyEvent.ANY, e -> {
|
decorator.addEventFilter(KeyEvent.ANY, e -> {
|
||||||
if (dialogPane == null || !dialogPane.peek().isPresent()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Node currentDialog = dialogPane.peek().get();
|
|
||||||
|
|
||||||
if (!(e.getTarget() instanceof Node)) {
|
if (!(e.getTarget() instanceof Node)) {
|
||||||
return;
|
return; // event source can't be determined
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean targetInDialog = false;
|
Node newTarget;
|
||||||
|
if (dialogPane != null && dialogPane.peek().isPresent()) {
|
||||||
|
newTarget = dialogPane.peek().get(); // current dialog
|
||||||
|
} else {
|
||||||
|
newTarget = navigator.getCurrentPage(); // current page
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean needsRedirect = true;
|
||||||
Node t = (Node) e.getTarget();
|
Node t = (Node) e.getTarget();
|
||||||
while (t != null) {
|
while (t != null) {
|
||||||
if (t == currentDialog) {
|
if (t == newTarget) {
|
||||||
targetInDialog = true;
|
// current event target is in newTarget
|
||||||
|
needsRedirect = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
t = t.getParent();
|
t = t.getParent();
|
||||||
}
|
}
|
||||||
if (targetInDialog) {
|
if (!needsRedirect) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.consume();
|
e.consume();
|
||||||
currentDialog.fireEvent(e.copyFor(e.getSource(), currentDialog));
|
newTarget.fireEvent(e.copyFor(e.getSource(), newTarget));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// press ESC to go back
|
||||||
|
onEscPressed(navigator, this::back);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Decorator getDecorator() {
|
public Decorator getDecorator() {
|
||||||
@@ -229,10 +236,15 @@ public class DecoratorController {
|
|||||||
if (navigator.getCurrentPage() instanceof DecoratorPage) {
|
if (navigator.getCurrentPage() instanceof DecoratorPage) {
|
||||||
DecoratorPage page = (DecoratorPage) navigator.getCurrentPage();
|
DecoratorPage page = (DecoratorPage) navigator.getCurrentPage();
|
||||||
|
|
||||||
if (page.back())
|
if (page.back()) {
|
||||||
navigator.close();
|
if (navigator.canGoBack()) {
|
||||||
|
navigator.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
navigator.close();
|
if (navigator.canGoBack()) {
|
||||||
|
navigator.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Hello Minecraft! Launcher
|
* Hello Minecraft! Launcher
|
||||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
* Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -66,7 +66,8 @@ public class RootPage extends DecoratorTabPage {
|
|||||||
public RootPage() {
|
public RootPage() {
|
||||||
setLeftPaneWidth(200);
|
setLeftPaneWidth(200);
|
||||||
|
|
||||||
EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).register(event -> onRefreshedVersions((HMCLGameRepository) event.getSource()));
|
EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class)
|
||||||
|
.register(event -> onRefreshedVersions((HMCLGameRepository) event.getSource()));
|
||||||
|
|
||||||
Profile profile = Profiles.getSelectedProfile();
|
Profile profile = Profiles.getSelectedProfile();
|
||||||
if (profile != null && profile.getRepository().isLoaded())
|
if (profile != null && profile.getRepository().isLoaded())
|
||||||
@@ -78,7 +79,8 @@ public class RootPage extends DecoratorTabPage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean back() {
|
public boolean back() {
|
||||||
if (mainTab.isSelected()) return true;
|
if (mainTab.isSelected())
|
||||||
|
return true;
|
||||||
else {
|
else {
|
||||||
getSelectionModel().select(mainTab);
|
getSelectionModel().select(mainTab);
|
||||||
return false;
|
return false;
|
||||||
@@ -102,20 +104,23 @@ public class RootPage extends DecoratorTabPage {
|
|||||||
MainPage mainPage = new MainPage();
|
MainPage mainPage = new MainPage();
|
||||||
FXUtils.applyDragListener(mainPage, it -> "zip".equals(FileUtils.getExtension(it)), modpacks -> {
|
FXUtils.applyDragListener(mainPage, it -> "zip".equals(FileUtils.getExtension(it)), modpacks -> {
|
||||||
File modpack = modpacks.get(0);
|
File modpack = modpacks.get(0);
|
||||||
Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), modpack), i18n("install.modpack"));
|
Controllers.getDecorator().startWizard(
|
||||||
|
new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), modpack),
|
||||||
|
i18n("install.modpack"));
|
||||||
});
|
});
|
||||||
|
|
||||||
FXUtils.onChangeAndOperate(Profiles.selectedVersionProperty(), mainPage::setCurrentGame);
|
FXUtils.onChangeAndOperate(Profiles.selectedVersionProperty(), mainPage::setCurrentGame);
|
||||||
mainPage.showUpdateProperty().bind(UpdateChecker.outdatedProperty());
|
mainPage.showUpdateProperty().bind(UpdateChecker.outdatedProperty());
|
||||||
mainPage.latestVersionProperty().bind(
|
mainPage.latestVersionProperty().bind(BindingMapping.of(UpdateChecker.latestVersionProperty())
|
||||||
BindingMapping.of(UpdateChecker.latestVersionProperty())
|
.map(version -> version == null ? "" : i18n("update.bubble.title", version.getVersion())));
|
||||||
.map(version -> version == null ? "" : i18n("update.bubble.title", version.getVersion())));
|
|
||||||
|
|
||||||
Profiles.registerVersionsListener(profile -> {
|
Profiles.registerVersionsListener(profile -> {
|
||||||
HMCLGameRepository repository = profile.getRepository();
|
HMCLGameRepository repository = profile.getRepository();
|
||||||
List<Version> children = repository.getVersions().parallelStream()
|
List<Version> children = repository.getVersions().parallelStream()
|
||||||
.filter(version -> !version.isHidden())
|
.filter(version -> !version.isHidden())
|
||||||
.sorted(Comparator.comparing((Version version) -> version.getReleaseTime() == null ? new Date(0L) : version.getReleaseTime())
|
.sorted(Comparator
|
||||||
|
.comparing((Version version) -> version.getReleaseTime() == null ? new Date(0L)
|
||||||
|
: version.getReleaseTime())
|
||||||
.thenComparing(a -> VersionNumber.asVersion(a.getId())))
|
.thenComparing(a -> VersionNumber.asVersion(a.getId())))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
runInFX(() -> {
|
runInFX(() -> {
|
||||||
@@ -135,7 +140,13 @@ public class RootPage extends DecoratorTabPage {
|
|||||||
|
|
||||||
// first item in left sidebar
|
// first item in left sidebar
|
||||||
AccountAdvancedListItem accountListItem = new AccountAdvancedListItem();
|
AccountAdvancedListItem accountListItem = new AccountAdvancedListItem();
|
||||||
accountListItem.setOnAction(e -> Controllers.navigate(Controllers.getAccountListPage()));
|
accountListItem.setOnAction(e -> {
|
||||||
|
Controllers.navigate(Controllers.getAccountListPage());
|
||||||
|
|
||||||
|
if (Accounts.getAccounts().isEmpty()) {
|
||||||
|
Controllers.dialog(new AddAccountPane());
|
||||||
|
}
|
||||||
|
});
|
||||||
accountListItem.accountProperty().bind(Accounts.selectedAccountProperty());
|
accountListItem.accountProperty().bind(Accounts.selectedAccountProperty());
|
||||||
|
|
||||||
// second item in left sidebar
|
// second item in left sidebar
|
||||||
@@ -158,20 +169,16 @@ public class RootPage extends DecoratorTabPage {
|
|||||||
|
|
||||||
// fifth item in left sidebar
|
// fifth item in left sidebar
|
||||||
AdvancedListItem launcherSettingsItem = new AdvancedListItem();
|
AdvancedListItem launcherSettingsItem = new AdvancedListItem();
|
||||||
launcherSettingsItem.setLeftGraphic(AdvancedListItem.createImageView(newImage("/assets/img/command.png")).getKey());
|
launcherSettingsItem
|
||||||
|
.setLeftGraphic(AdvancedListItem.createImageView(newImage("/assets/img/command.png")).getKey());
|
||||||
launcherSettingsItem.setActionButtonVisible(false);
|
launcherSettingsItem.setActionButtonVisible(false);
|
||||||
launcherSettingsItem.setTitle(i18n("settings.launcher"));
|
launcherSettingsItem.setTitle(i18n("settings.launcher"));
|
||||||
launcherSettingsItem.setOnAction(e -> Controllers.navigate(Controllers.getSettingsPage()));
|
launcherSettingsItem.setOnAction(e -> Controllers.navigate(Controllers.getSettingsPage()));
|
||||||
|
|
||||||
// the left sidebar
|
// the left sidebar
|
||||||
AdvancedListBox sideBar = new AdvancedListBox()
|
AdvancedListBox sideBar = new AdvancedListBox().startCategory(i18n("account").toUpperCase())
|
||||||
.startCategory(i18n("account").toUpperCase())
|
.add(accountListItem).startCategory(i18n("version").toUpperCase()).add(gameListItem).add(gameItem)
|
||||||
.add(accountListItem)
|
.startCategory(i18n("launcher").toUpperCase()).add(launcherSettingsItem);
|
||||||
.startCategory(i18n("version").toUpperCase())
|
|
||||||
.add(gameListItem)
|
|
||||||
.add(gameItem)
|
|
||||||
.startCategory(i18n("launcher").toUpperCase())
|
|
||||||
.add(launcherSettingsItem);
|
|
||||||
|
|
||||||
// the root page, with the sidebar in left, navigator in center.
|
// the root page, with the sidebar in left, navigator in center.
|
||||||
BorderPane root = new BorderPane();
|
BorderPane root = new BorderPane();
|
||||||
@@ -195,7 +202,8 @@ public class RootPage extends DecoratorTabPage {
|
|||||||
private boolean checkedAccont = false;
|
private boolean checkedAccont = false;
|
||||||
|
|
||||||
public void checkAccount() {
|
public void checkAccount() {
|
||||||
if (checkedAccont) return;
|
if (checkedAccont)
|
||||||
|
return;
|
||||||
checkedAccont = true;
|
checkedAccont = true;
|
||||||
if (Accounts.getAccounts().isEmpty())
|
if (Accounts.getAccounts().isEmpty())
|
||||||
Platform.runLater(this::addNewAccount);
|
Platform.runLater(this::addNewAccount);
|
||||||
@@ -217,8 +225,11 @@ public class RootPage extends DecoratorTabPage {
|
|||||||
File modpackFile = new File("modpack.zip").getAbsoluteFile();
|
File modpackFile = new File("modpack.zip").getAbsoluteFile();
|
||||||
if (modpackFile.exists()) {
|
if (modpackFile.exists()) {
|
||||||
Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(modpackFile.toPath()))
|
Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(modpackFile.toPath()))
|
||||||
.thenApplyAsync(encoding -> ModpackHelper.readModpackManifest(modpackFile.toPath(), encoding))
|
.thenApplyAsync(
|
||||||
.thenApplyAsync(modpack -> ModpackHelper.getInstallTask(repository.getProfile(), modpackFile, modpack.getName(), modpack)
|
encoding -> ModpackHelper.readModpackManifest(modpackFile.toPath(), encoding))
|
||||||
|
.thenApplyAsync(modpack -> ModpackHelper
|
||||||
|
.getInstallTask(repository.getProfile(), modpackFile, modpack.getName(),
|
||||||
|
modpack)
|
||||||
.withRunAsync(Schedulers.javafx(), this::checkAccount).executor())
|
.withRunAsync(Schedulers.javafx(), this::checkAccount).executor())
|
||||||
.thenAcceptAsync(Schedulers.javafx(), executor -> {
|
.thenAcceptAsync(Schedulers.javafx(), executor -> {
|
||||||
Controllers.taskDialog(executor, i18n("modpack.installing"));
|
Controllers.taskDialog(executor, i18n("modpack.installing"));
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public final class SelfDependencyPatcher {
|
|||||||
|
|
||||||
static class DependencyDescriptor {
|
static class DependencyDescriptor {
|
||||||
|
|
||||||
private static final String REPOSITORY_URL = "https://maven.aliyun.com/repository/central/";
|
private static final String REPOSITORY_URL = System.getProperty("hmcl.openjfx.repo", "https://maven.aliyun.com/repository/central/");
|
||||||
private static final Path DEPENDENCIES_DIR_PATH = HMCL_DIRECTORY.resolve("dependencies");
|
private static final Path DEPENDENCIES_DIR_PATH = HMCL_DIRECTORY.resolve("dependencies");
|
||||||
|
|
||||||
private static String currentArchClassifier() {
|
private static String currentArchClassifier() {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public class LaunchOptions implements Serializable {
|
|||||||
private String preLaunchCommand;
|
private String preLaunchCommand;
|
||||||
private NativesDirectoryType nativesDirType;
|
private NativesDirectoryType nativesDirType;
|
||||||
private String nativesDir;
|
private String nativesDir;
|
||||||
private ProcessPriority processPriority;
|
private ProcessPriority processPriority = ProcessPriority.NORMAL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The game directory
|
* The game directory
|
||||||
@@ -497,7 +497,7 @@ public class LaunchOptions implements Serializable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setProcessPriority(ProcessPriority processPriority) {
|
public Builder setProcessPriority(@NotNull ProcessPriority processPriority) {
|
||||||
options.processPriority = processPriority;
|
options.processPriority = processPriority;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,3 +53,4 @@ Make sure you have Java installed with JavaFX 8 at least. Liberica full JDK 8~16
|
|||||||
|`-Dhmcl.version.override=<version>`|Override the version number.|
|
|`-Dhmcl.version.override=<version>`|Override the version number.|
|
||||||
|`-Dhmcl.update_source.override=<url>`|Override the update source.|
|
|`-Dhmcl.update_source.override=<url>`|Override the update source.|
|
||||||
|`-Dhmcl.authlibinjector.location=<path>`|Use specified authlib-injector (instead of downloading one).|
|
|`-Dhmcl.authlibinjector.location=<path>`|Use specified authlib-injector (instead of downloading one).|
|
||||||
|
|`-Dhmcl.openjfx.repo=<maven repository url>`|Download OpenJFX from specified Maven repository. Default value is `https://maven.aliyun.com/repository/central/`.|
|
||||||
|
|||||||
Reference in New Issue
Block a user