Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d7bc0b593 | ||
|
|
473c6f2b3c | ||
|
|
484ce6c895 | ||
|
|
eeccdbca72 | ||
|
|
552238676c | ||
|
|
c9e7bf7ca5 | ||
|
|
8d1e335abf | ||
|
|
c76bcb5d15 |
No files matched your search
@@ -20,10 +20,7 @@ package org.jackhuang.hmcl.game;
|
||||
import com.jfoenix.concurrency.JFXUtilities;
|
||||
import javafx.application.Platform;
|
||||
import org.jackhuang.hmcl.Main;
|
||||
import org.jackhuang.hmcl.auth.Account;
|
||||
import org.jackhuang.hmcl.auth.AuthInfo;
|
||||
import org.jackhuang.hmcl.auth.AuthenticationException;
|
||||
import org.jackhuang.hmcl.auth.SpecificCharacterSelector;
|
||||
import org.jackhuang.hmcl.auth.*;
|
||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.launch.*;
|
||||
import org.jackhuang.hmcl.mod.CurseCompletionTask;
|
||||
@@ -76,6 +73,7 @@ public final class LauncherHelper {
|
||||
Version version = repository.getVersion(selectedVersion);
|
||||
Account account = Settings.INSTANCE.getSelectedAccount();
|
||||
VersionSetting setting = profile.getVersionSetting(selectedVersion);
|
||||
Optional<String> gameVersion = GameVersion.minecraftVersion(repository.getVersionJar(version));
|
||||
|
||||
executor = Task.of(Schedulers.javafx(), () -> Controllers.dialog(launchingStepsPane))
|
||||
.then(Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.DEPENDENCIES)))
|
||||
@@ -90,7 +88,14 @@ public final class LauncherHelper {
|
||||
.then(Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.LOGGING_IN)))
|
||||
.then(Task.of(Main.i18n("account.methods"), variables -> {
|
||||
try {
|
||||
variables.set("account", account.logIn(new SpecificCharacterSelector(Accounts.getCurrentCharacter(account)), Settings.INSTANCE.getProxy()));
|
||||
try {
|
||||
variables.set("account", account.logIn(new SpecificCharacterSelector(Accounts.getCurrentCharacter(account)), Settings.INSTANCE.getProxy()));
|
||||
} catch (ServerDisconnectException e) {
|
||||
if (account.canPlayOffline())
|
||||
variables.set("account", account.playOffline());
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
} catch (AuthenticationException e) {
|
||||
variables.set("account", DialogController.logIn(account));
|
||||
JFXUtilities.runInFX(() -> Controllers.dialog(launchingStepsPane));
|
||||
@@ -99,7 +104,7 @@ public final class LauncherHelper {
|
||||
.then(Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.LAUNCHING)))
|
||||
.then(Task.of(variables -> {
|
||||
variables.set("launcher", new HMCLGameLauncher(
|
||||
repository, selectedVersion, variables.get("account"), setting.toLaunchOptions(profile.getGameDir()), new HMCLProcessListener(variables.get("account"), setting)
|
||||
repository, selectedVersion, variables.get("account"), setting.toLaunchOptions(profile.getGameDir()), new HMCLProcessListener(variables.get("account"), setting, gameVersion.isPresent())
|
||||
));
|
||||
}))
|
||||
.then(variables -> {
|
||||
@@ -282,11 +287,13 @@ public final class LauncherHelper {
|
||||
private ManagedProcess process;
|
||||
private boolean lwjgl;
|
||||
private LogWindow logWindow;
|
||||
private final boolean detectWindow;
|
||||
private final LinkedList<Pair<String, Log4jLevel>> logs;
|
||||
private final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
public HMCLProcessListener(AuthInfo authInfo, VersionSetting setting) {
|
||||
public HMCLProcessListener(AuthInfo authInfo, VersionSetting setting, boolean detectWindow) {
|
||||
this.setting = setting;
|
||||
this.detectWindow = detectWindow;
|
||||
|
||||
if (authInfo == null)
|
||||
forbiddenTokens = Collections.emptyMap();
|
||||
@@ -337,8 +344,7 @@ public final class LauncherHelper {
|
||||
Platform.runLater(() -> logWindow.logLine(log, level));
|
||||
}
|
||||
|
||||
|
||||
if (!lwjgl && log.contains("LWJGL Version: ")) {
|
||||
if (!lwjgl && log.contains("LWJGL Version: ") || !detectWindow) {
|
||||
lwjgl = true;
|
||||
switch (visibility) {
|
||||
case HIDE_AND_REOPEN:
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.jackhuang.hmcl.mod.*;
|
||||
import org.jackhuang.hmcl.setting.EnumGameDirectory;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
import org.jackhuang.hmcl.setting.VersionSetting;
|
||||
import org.jackhuang.hmcl.task.FinalizedCallback;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.FileUtils;
|
||||
@@ -84,13 +85,13 @@ public final class ModpackHelper {
|
||||
public static Task getInstallTask(Profile profile, File zipFile, String name, Modpack modpack) {
|
||||
profile.getRepository().markVersionAsModpack(name);
|
||||
|
||||
Task finalizeTask = Task.of(() -> {
|
||||
FinalizedCallback finalizeTask = (variables, isDependentsSucceeded) -> {
|
||||
profile.getRepository().refreshVersions();
|
||||
VersionSetting vs = profile.specializeVersionSetting(name);
|
||||
profile.getRepository().undoMark(name);
|
||||
if (vs != null)
|
||||
vs.setGameDirType(EnumGameDirectory.VERSION_FOLDER);
|
||||
});
|
||||
};
|
||||
|
||||
if (modpack.getManifest() instanceof CurseManifest)
|
||||
return new CurseInstallTask(profile.getDependency(), zipFile, ((CurseManifest) modpack.getManifest()), name)
|
||||
|
||||
@@ -40,6 +40,12 @@ public final class Config {
|
||||
@SerializedName("commonpath")
|
||||
private String commonDirectory = Main.MINECRAFT_DIRECTORY.getAbsolutePath();
|
||||
|
||||
@SerializedName("hasProxy")
|
||||
private boolean hasProxy = false;
|
||||
|
||||
@SerializedName("hasProxyAuth")
|
||||
private boolean hasProxyAuth = false;
|
||||
|
||||
@SerializedName("proxyType")
|
||||
private int proxyType = 0;
|
||||
|
||||
@@ -121,6 +127,24 @@ public final class Config {
|
||||
Settings.INSTANCE.save();
|
||||
}
|
||||
|
||||
public boolean isHasProxy() {
|
||||
return hasProxy;
|
||||
}
|
||||
|
||||
public void setHasProxy(boolean hasProxy) {
|
||||
this.hasProxy = hasProxy;
|
||||
Settings.INSTANCE.save();
|
||||
}
|
||||
|
||||
public boolean isHasProxyAuth() {
|
||||
return hasProxyAuth;
|
||||
}
|
||||
|
||||
public void setHasProxyAuth(boolean hasProxyAuth) {
|
||||
this.hasProxyAuth = hasProxyAuth;
|
||||
Settings.INSTANCE.save();
|
||||
}
|
||||
|
||||
public int getProxyType() {
|
||||
return proxyType;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <[email protected]>
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.setting;
|
||||
|
||||
import org.jackhuang.hmcl.Main;
|
||||
|
||||
public final class Profiles {
|
||||
private Profiles() {
|
||||
}
|
||||
|
||||
public static String getProfileDisplayName(Profile profile) {
|
||||
switch (profile.getName()) {
|
||||
case Settings.DEFAULT_PROFILE:
|
||||
return Main.i18n("profile.default");
|
||||
case Settings.HOME_PROFILE:
|
||||
return Main.i18n("profile.home");
|
||||
default:
|
||||
return profile.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,11 +124,6 @@ public class Settings {
|
||||
} catch (Exception e) {
|
||||
Logging.LOG.log(Level.WARNING, "Something happened wrongly when load settings.", e);
|
||||
}
|
||||
else {
|
||||
Logging.LOG.config("No settings file here, may be first loading.");
|
||||
if (!c.getConfigurations().containsKey(HOME_PROFILE))
|
||||
c.getConfigurations().put(HOME_PROFILE, new Profile(HOME_PROFILE, Main.MINECRAFT_DIRECTORY));
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -229,22 +224,27 @@ public class Settings {
|
||||
SETTINGS.setProxyPass(proxyPass);
|
||||
}
|
||||
|
||||
public boolean hasProxy() { return SETTINGS.isHasProxy(); }
|
||||
|
||||
public void setHasProxy(boolean hasProxy) { SETTINGS.setHasProxy(hasProxy); }
|
||||
|
||||
public boolean hasProxyAuth() { return SETTINGS.isHasProxyAuth(); }
|
||||
|
||||
public void setHasProxyAuth(boolean hasProxyAuth) { SETTINGS.setHasProxyAuth(hasProxyAuth); }
|
||||
|
||||
private void loadProxy() {
|
||||
String host = getProxyHost();
|
||||
Integer port = Lang.toIntOrNull(getProxyPort());
|
||||
if (StringUtils.isBlank(host) || port == null)
|
||||
if (!hasProxy() || StringUtils.isBlank(host) || port == null || getProxyType() == Proxy.Type.DIRECT)
|
||||
proxy = Proxy.NO_PROXY;
|
||||
else {
|
||||
System.setProperty("http.proxyHost", getProxyHost());
|
||||
System.setProperty("http.proxyPort", getProxyPort());
|
||||
if (getProxyType() == Proxy.Type.DIRECT)
|
||||
proxy = Proxy.NO_PROXY;
|
||||
else
|
||||
proxy = new Proxy(proxyType, new InetSocketAddress(host, port));
|
||||
proxy = new Proxy(proxyType, new InetSocketAddress(host, port));
|
||||
|
||||
String user = getProxyUser();
|
||||
String pass = getProxyPass();
|
||||
if (StringUtils.isNotBlank(user) && StringUtils.isNotBlank(pass)) {
|
||||
if (hasProxyAuth() && StringUtils.isNotBlank(user) && StringUtils.isNotBlank(pass)) {
|
||||
System.setProperty("http.proxyUser", user);
|
||||
System.setProperty("http.proxyPassword", pass);
|
||||
|
||||
@@ -463,7 +463,7 @@ public class Settings {
|
||||
}
|
||||
|
||||
public boolean hasProfile(String name) {
|
||||
return getProfileMap().containsKey(Lang.nonNull(name, DEFAULT_PROFILE));
|
||||
return getProfileMap().containsKey(name);
|
||||
}
|
||||
|
||||
public Map<String, Profile> getProfileMap() {
|
||||
@@ -494,8 +494,10 @@ public class Settings {
|
||||
}
|
||||
|
||||
private void checkProfileMap() {
|
||||
if (getProfileMap().isEmpty())
|
||||
if (getProfileMap().isEmpty()) {
|
||||
getProfileMap().put(DEFAULT_PROFILE, new Profile(DEFAULT_PROFILE));
|
||||
getProfileMap().put(HOME_PROFILE, new Profile(HOME_PROFILE, Main.MINECRAFT_DIRECTORY));
|
||||
}
|
||||
}
|
||||
|
||||
private void onProfileChanged() {
|
||||
|
||||
@@ -67,9 +67,6 @@ public final class AccountItem extends StackPane {
|
||||
|
||||
FXUtils.loadFXML(this, "/assets/fxml/account-item.fxml");
|
||||
|
||||
FXUtils.limitWidth(this, 160);
|
||||
FXUtils.limitHeight(this, 156);
|
||||
|
||||
setEffect(new DropShadow(BlurType.GAUSSIAN, Color.rgb(0, 0, 0, 0.26), 5.0, 0.12, -0.5, 1.0));
|
||||
|
||||
chkSelected.setToggleGroup(toggleGroup);
|
||||
|
||||
@@ -73,8 +73,6 @@ public final class AccountsPage extends StackPane implements DecoratorPage {
|
||||
dialog.setDialogContainer(this);
|
||||
|
||||
FXUtils.smoothScrolling(scrollPane);
|
||||
FXUtils.setValidateWhileTextChanged(txtUsername);
|
||||
FXUtils.setValidateWhileTextChanged(txtPassword);
|
||||
|
||||
cboType.getItems().setAll(Main.i18n("account.methods.offline"), Main.i18n("account.methods.yggdrasil"));
|
||||
cboType.getSelectionModel().selectedIndexProperty().addListener((a, b, newValue) -> {
|
||||
@@ -160,20 +158,10 @@ public final class AccountsPage extends StackPane implements DecoratorPage {
|
||||
Settings.INSTANCE.addAccount((Account) account);
|
||||
dialog.close();
|
||||
loadAccounts();
|
||||
} else if (account instanceof InvalidCredentialsException) {
|
||||
lblCreationWarning.setText(Main.i18n("account.failed.wrong_password"));
|
||||
} else if (account instanceof NoCharacterException) {
|
||||
lblCreationWarning.setText(Main.i18n("account.failed.no_charactor"));
|
||||
} else if (account instanceof ServerDisconnectException) {
|
||||
lblCreationWarning.setText(Main.i18n("account.failed.connect_authentication_server"));
|
||||
} else if (account instanceof InvalidTokenException) {
|
||||
lblCreationWarning.setText(Main.i18n("account.failed.invalid_token"));
|
||||
} else if (account instanceof InvalidPasswordException) {
|
||||
lblCreationWarning.setText(Main.i18n("account.failed.invalid_password"));
|
||||
} else if (account instanceof NoSelectedCharacterException) {
|
||||
dialog.close();
|
||||
} else if (account instanceof Exception) {
|
||||
lblCreationWarning.setText(account.getClass() + ": " + ((Exception) account).getLocalizedMessage());
|
||||
lblCreationWarning.setText(accountException((Exception) account));
|
||||
}
|
||||
progressBar.setVisible(false);
|
||||
});
|
||||
@@ -197,6 +185,22 @@ public final class AccountsPage extends StackPane implements DecoratorPage {
|
||||
this.title.set(title);
|
||||
}
|
||||
|
||||
public static String accountException(Exception account) {
|
||||
if (account instanceof InvalidCredentialsException) {
|
||||
return Main.i18n("account.failed.invalid_credentials");
|
||||
} else if (account instanceof NoCharacterException) {
|
||||
return Main.i18n("account.failed.no_charactor");
|
||||
} else if (account instanceof ServerDisconnectException) {
|
||||
return Main.i18n("account.failed.connect_authentication_server");
|
||||
} else if (account instanceof InvalidTokenException) {
|
||||
return Main.i18n("account.failed.invalid_token");
|
||||
} else if (account instanceof InvalidPasswordException) {
|
||||
return Main.i18n("account.failed.invalid_password");
|
||||
} else {
|
||||
return account.getClass() + ": " + ((Exception) account).getLocalizedMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public static String accountType(Account account) {
|
||||
if (account instanceof OfflineAccount) return Main.i18n("account.methods.offline");
|
||||
else if (account instanceof YggdrasilAccount) return Main.i18n("account.methods.yggdrasil");
|
||||
|
||||
@@ -180,9 +180,6 @@ public final class Decorator extends StackPane implements TaskExecutorDialogWiza
|
||||
|
||||
animationHandler = new TransitionHandler(contentPlaceHolder);
|
||||
|
||||
FXUtils.setOverflowHidden((Pane) lookup("#contentPlaceHolderRoot"));
|
||||
FXUtils.setOverflowHidden(drawerWrapper);
|
||||
|
||||
loadBackground();
|
||||
}
|
||||
|
||||
@@ -487,7 +484,7 @@ public final class Decorator extends StackPane implements TaskExecutorDialogWiza
|
||||
|
||||
if (content instanceof Region) {
|
||||
((Region) content).setMinSize(0, 0);
|
||||
FXUtils.setOverflowHidden((Region) content);
|
||||
FXUtils.setOverflowHidden((Region) content, true);
|
||||
}
|
||||
|
||||
if (content instanceof Refreshable)
|
||||
|
||||
@@ -38,6 +38,7 @@ import javafx.scene.image.ImageView;
|
||||
import javafx.scene.image.WritableImage;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.input.ScrollEvent;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import javafx.util.Duration;
|
||||
@@ -45,6 +46,7 @@ import org.jackhuang.hmcl.Main;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.Logging;
|
||||
import org.jackhuang.hmcl.util.OperatingSystem;
|
||||
import org.jackhuang.hmcl.util.Pair;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -92,35 +94,79 @@ public final class FXUtils {
|
||||
});
|
||||
}
|
||||
|
||||
public static void setValidateWhileTextChanged(JFXTextField field) {
|
||||
field.textProperty().addListener(o -> field.validate());
|
||||
field.validate();
|
||||
public static <T> void addListener(Node node, String key, ObservableValue<T> value, Consumer<T> callback) {
|
||||
ChangeListener<T> listener = (a, b, newValue) -> callback.accept(newValue);
|
||||
node.getProperties().put(key, new Pair<>(callback, listener));
|
||||
value.addListener(listener);
|
||||
}
|
||||
|
||||
public static void setValidateWhileTextChanged(JFXPasswordField field) {
|
||||
field.textProperty().addListener(o -> field.validate());
|
||||
field.validate();
|
||||
public static <T> void removeListener(Node node, String key) {
|
||||
if (node.getProperties().get(key) instanceof Pair) {
|
||||
Pair pair = (Pair) node.getProperties().get(key);
|
||||
if (pair.getValue() instanceof ObservableValue && pair.getKey() instanceof ChangeListener) {
|
||||
((ObservableValue) pair.getValue()).removeListener((ChangeListener) pair.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setOverflowHidden(Region region) {
|
||||
Rectangle rectangle = new Rectangle();
|
||||
rectangle.widthProperty().bind(region.widthProperty());
|
||||
rectangle.heightProperty().bind(region.heightProperty());
|
||||
region.setClip(rectangle);
|
||||
public static void setValidateWhileTextChanged(Node field, boolean validate) {
|
||||
if (field instanceof JFXTextField) {
|
||||
if (validate) {
|
||||
addListener(field, "FXUtils.validation", ((JFXTextField) field).textProperty(), o -> ((JFXTextField) field).validate());
|
||||
} else {
|
||||
removeListener(field, "FXUtils.validation");
|
||||
}
|
||||
((JFXTextField) field).validate();
|
||||
} else if (field instanceof JFXPasswordField) {
|
||||
if (validate) {
|
||||
addListener(field, "FXUtils.validation", ((JFXPasswordField) field).textProperty(), o -> ((JFXPasswordField) field).validate());
|
||||
} else {
|
||||
removeListener(field, "FXUtils.validation");
|
||||
}
|
||||
((JFXPasswordField) field).validate();
|
||||
} else
|
||||
throw new IllegalArgumentException("Only JFXTextField and JFXPasswordField allowed");
|
||||
}
|
||||
|
||||
public static void limitWidth(Region region, double width) {
|
||||
public static boolean getValidateWhileTextChanged(Node field) {
|
||||
return field.getProperties().containsKey("FXUtils.validation");
|
||||
}
|
||||
|
||||
public static void setOverflowHidden(Region region, boolean hidden) {
|
||||
if (hidden) {
|
||||
Rectangle rectangle = new Rectangle();
|
||||
rectangle.widthProperty().bind(region.widthProperty());
|
||||
rectangle.heightProperty().bind(region.heightProperty());
|
||||
region.setClip(rectangle);
|
||||
} else {
|
||||
region.setClip(null);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean getOverflowHidden(Region region) {
|
||||
return region.getClip() != null;
|
||||
}
|
||||
|
||||
public static void setLimitWidth(Region region, double width) {
|
||||
region.setMaxWidth(width);
|
||||
region.setMinWidth(width);
|
||||
region.setPrefWidth(width);
|
||||
}
|
||||
|
||||
public static void limitHeight(Region region, double height) {
|
||||
public static double getLimitWidth(Region region) {
|
||||
return region.getMaxWidth();
|
||||
}
|
||||
|
||||
public static void setLimitHeight(Region region, double height) {
|
||||
region.setMaxHeight(height);
|
||||
region.setMinHeight(height);
|
||||
region.setPrefHeight(height);
|
||||
}
|
||||
|
||||
public static double getLimitHeight(Region region) {
|
||||
return region.getMaxHeight();
|
||||
}
|
||||
|
||||
public static void smoothScrolling(ScrollPane scrollPane) {
|
||||
JFXScrollPane.smoothScrolling(scrollPane);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.jackhuang.hmcl.mod.Modpack;
|
||||
import org.jackhuang.hmcl.mod.UnsupportedModpackException;
|
||||
import org.jackhuang.hmcl.setting.Accounts;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
import org.jackhuang.hmcl.setting.Profiles;
|
||||
import org.jackhuang.hmcl.setting.Settings;
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
@@ -122,7 +123,7 @@ public final class LeftPaneController {
|
||||
private void onProfilesLoading() {
|
||||
LinkedList<RipplerContainer> list = new LinkedList<>();
|
||||
for (Profile profile : Settings.INSTANCE.getProfiles()) {
|
||||
VersionListItem item = new VersionListItem(profile.getName());
|
||||
VersionListItem item = new VersionListItem(Profiles.getProfileDisplayName(profile));
|
||||
RipplerContainer ripplerContainer = new RipplerContainer(item);
|
||||
item.setOnSettingsButtonClicked(() -> Controllers.getDecorator().showPage(new ProfilePage(profile)));
|
||||
ripplerContainer.setOnMouseClicked(e -> Settings.INSTANCE.setSelectedProfile(profile));
|
||||
|
||||
@@ -32,14 +32,13 @@ import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.stage.FileChooser;
|
||||
import org.jackhuang.hmcl.Main;
|
||||
import org.jackhuang.hmcl.download.MaintainTask;
|
||||
import org.jackhuang.hmcl.download.game.VersionJsonSaveTask;
|
||||
import org.jackhuang.hmcl.event.EventBus;
|
||||
import org.jackhuang.hmcl.event.ProfileChangedEvent;
|
||||
import org.jackhuang.hmcl.event.ProfileLoadingEvent;
|
||||
import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
|
||||
import org.jackhuang.hmcl.game.GameVersion;
|
||||
import org.jackhuang.hmcl.game.LauncherHelper;
|
||||
import org.jackhuang.hmcl.game.ModpackHelper;
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
import org.jackhuang.hmcl.game.*;
|
||||
import org.jackhuang.hmcl.mod.MismatchedModpackTypeException;
|
||||
import org.jackhuang.hmcl.mod.UnsupportedModpackException;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
@@ -53,11 +52,13 @@ import org.jackhuang.hmcl.ui.download.DownloadWizardProvider;
|
||||
import org.jackhuang.hmcl.ui.wizard.DecoratorPage;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.OperatingSystem;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class MainPage extends StackPane implements DecoratorPage {
|
||||
|
||||
@@ -101,6 +102,21 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
||||
item.setUpdate(profile.getRepository().isModpack(version));
|
||||
item.setGameVersion(game);
|
||||
item.setVersionName(version);
|
||||
|
||||
StringBuilder libraries = new StringBuilder();
|
||||
for (Library library : profile.getRepository().getVersion(version).getLibraries()) {
|
||||
if (library.getGroupId().equalsIgnoreCase("net.minecraftforge") && library.getArtifactId().equalsIgnoreCase("forge")) {
|
||||
libraries.append(Main.i18n("install.installer.forge")).append(": ").append(StringUtils.removeSuffix(StringUtils.removePrefix(library.getVersion().replaceAll("(?i)forge", "").replace(game, "").trim(), "-"), "-")).append("\n");
|
||||
}
|
||||
if (library.getGroupId().equalsIgnoreCase("com.mumfrey") && library.getArtifactId().equalsIgnoreCase("liteloader")) {
|
||||
libraries.append(Main.i18n("install.installer.liteloader")).append(": ").append(StringUtils.removeSuffix(StringUtils.removePrefix(library.getVersion().replaceAll("(?i)liteloader", "").replace(game, "").trim(), "-"), "-")).append("\n");
|
||||
}
|
||||
if (library.getGroupId().equalsIgnoreCase("net.optifine") && library.getArtifactId().equalsIgnoreCase("optifine")) {
|
||||
libraries.append(Main.i18n("install.installer.optifine")).append(": ").append(StringUtils.removeSuffix(StringUtils.removePrefix(library.getVersion().replaceAll("(?i)optifine", "").replace(game, "").trim(), "-"), "-")).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
item.setLibraries(libraries.toString());
|
||||
item.setOnLaunchButtonClicked(e -> {
|
||||
if (Settings.INSTANCE.getSelectedAccount() == null)
|
||||
Controllers.dialog(Main.i18n("login.empty_username"));
|
||||
|
||||
@@ -25,6 +25,7 @@ import javafx.fxml.FXML;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import org.jackhuang.hmcl.Main;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
import org.jackhuang.hmcl.setting.Profiles;
|
||||
import org.jackhuang.hmcl.setting.Settings;
|
||||
import org.jackhuang.hmcl.ui.construct.FileItem;
|
||||
import org.jackhuang.hmcl.ui.wizard.DecoratorPage;
|
||||
@@ -58,7 +59,7 @@ public final class ProfilePage extends StackPane implements DecoratorPage {
|
||||
|
||||
FXUtils.loadFXML(this, "/assets/fxml/profile.fxml");
|
||||
|
||||
txtProfileName.setText(Optional.ofNullable(profile).map(Profile::getName).orElse(""));
|
||||
txtProfileName.setText(Optional.ofNullable(profile).map(Profiles::getProfileDisplayName).orElse(""));
|
||||
FXUtils.onChangeAndOperate(txtProfileName.textProperty(), it -> {
|
||||
btnSave.setDisable(!txtProfileName.validate() || StringUtils.isBlank(getLocation()));
|
||||
});
|
||||
|
||||
@@ -17,18 +17,16 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.ui;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.controls.JFXComboBox;
|
||||
import com.jfoenix.controls.JFXTextField;
|
||||
import com.jfoenix.controls.*;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.text.Font;
|
||||
import org.jackhuang.hmcl.Main;
|
||||
@@ -40,6 +38,7 @@ import org.jackhuang.hmcl.ui.construct.Validator;
|
||||
import org.jackhuang.hmcl.ui.wizard.DecoratorPage;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
|
||||
import java.net.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -53,12 +52,10 @@ public final class SettingsPage extends StackPane implements DecoratorPage {
|
||||
@FXML
|
||||
private JFXTextField txtProxyUsername;
|
||||
@FXML
|
||||
private JFXTextField txtProxyPassword;
|
||||
private JFXPasswordField txtProxyPassword;
|
||||
@FXML
|
||||
private JFXTextField txtFontSize;
|
||||
@FXML
|
||||
private JFXComboBox<?> cboProxyType;
|
||||
@FXML
|
||||
private JFXComboBox<Label> cboLanguage;
|
||||
@FXML
|
||||
private JFXComboBox<?> cboDownloadSource;
|
||||
@@ -80,13 +77,24 @@ public final class SettingsPage extends StackPane implements DecoratorPage {
|
||||
private MultiFileItem backgroundItem;
|
||||
@FXML
|
||||
private MultiFileItem themeItem;
|
||||
@FXML
|
||||
private JFXRadioButton chkNoProxy;
|
||||
@FXML
|
||||
private JFXRadioButton chkManualProxy;
|
||||
@FXML
|
||||
private JFXRadioButton chkProxyHttp;
|
||||
@FXML
|
||||
private JFXRadioButton chkProxySocks;
|
||||
@FXML
|
||||
private JFXCheckBox chkProxyAuthentication;
|
||||
@FXML
|
||||
private GridPane authPane;
|
||||
@FXML
|
||||
private Pane proxyPane;
|
||||
|
||||
{
|
||||
FXUtils.loadFXML(this, "/assets/fxml/setting.fxml");
|
||||
|
||||
FXUtils.limitWidth(cboLanguage, 400);
|
||||
FXUtils.limitWidth(cboDownloadSource, 400);
|
||||
|
||||
FXUtils.smoothScrolling(scroll);
|
||||
|
||||
txtProxyHost.setText(Settings.INSTANCE.getProxyHost());
|
||||
@@ -131,8 +139,37 @@ public final class SettingsPage extends StackPane implements DecoratorPage {
|
||||
cboLanguage.getSelectionModel().select(Locales.LOCALES.indexOf(Settings.INSTANCE.getLocale()));
|
||||
cboLanguage.getSelectionModel().selectedIndexProperty().addListener((a, b, newValue) -> Settings.INSTANCE.setLocale(Locales.getLocale(newValue.intValue())));
|
||||
|
||||
cboProxyType.getSelectionModel().select(Proxies.PROXIES.indexOf(Settings.INSTANCE.getProxyType()));
|
||||
cboProxyType.getSelectionModel().selectedIndexProperty().addListener((a, b, newValue) -> Settings.INSTANCE.setProxyType(Proxies.getProxyType(newValue.intValue())));
|
||||
|
||||
ToggleGroup proxyConfigurationGroup = new ToggleGroup();
|
||||
chkProxyHttp.setUserData(Proxy.Type.HTTP);
|
||||
chkProxyHttp.setToggleGroup(proxyConfigurationGroup);
|
||||
chkProxySocks.setUserData(Proxy.Type.SOCKS);
|
||||
chkProxySocks.setToggleGroup(proxyConfigurationGroup);
|
||||
|
||||
for (Toggle toggle : proxyConfigurationGroup.getToggles())
|
||||
if (toggle.getUserData() == Settings.INSTANCE.getProxyType())
|
||||
toggle.setSelected(true);
|
||||
|
||||
ToggleGroup hasProxyGroup = new ToggleGroup();
|
||||
chkNoProxy.setToggleGroup(hasProxyGroup);
|
||||
chkManualProxy.setToggleGroup(hasProxyGroup);
|
||||
if (!Settings.INSTANCE.hasProxy())
|
||||
chkNoProxy.setSelected(true);
|
||||
else
|
||||
chkManualProxy.setSelected(true);
|
||||
proxyPane.disableProperty().bind(chkNoProxy.selectedProperty());
|
||||
|
||||
hasProxyGroup.selectedToggleProperty().addListener((a, b, newValue) -> {
|
||||
Settings.INSTANCE.setHasProxy(newValue != chkNoProxy);
|
||||
});
|
||||
|
||||
proxyConfigurationGroup.selectedToggleProperty().addListener((a, b, newValue) -> {
|
||||
Settings.INSTANCE.setProxyType((Proxy.Type) newValue.getUserData());
|
||||
});
|
||||
|
||||
chkProxyAuthentication.setSelected(Settings.INSTANCE.hasProxyAuth());
|
||||
chkProxyAuthentication.selectedProperty().addListener((a, b, newValue) -> Settings.INSTANCE.setHasProxyAuth(newValue));
|
||||
authPane.disableProperty().bind(chkProxyAuthentication.selectedProperty().not());
|
||||
|
||||
fileCommonLocation.setProperty(Settings.INSTANCE.commonPathProperty());
|
||||
|
||||
|
||||
@@ -59,14 +59,14 @@ public final class VersionItem extends StackPane {
|
||||
@FXML
|
||||
private Label lblGameVersion;
|
||||
@FXML
|
||||
private Label lblLibraries;
|
||||
@FXML
|
||||
private ImageView iconView;
|
||||
|
||||
private EventHandler<? super MouseEvent> launchClickedHandler = null;
|
||||
|
||||
public VersionItem() {
|
||||
FXUtils.loadFXML(this, "/assets/fxml/version-item.fxml");
|
||||
FXUtils.limitWidth(this, 160);
|
||||
FXUtils.limitHeight(this, 156);
|
||||
setEffect(new DropShadow(BlurType.GAUSSIAN, Color.rgb(0, 0, 0, 0.26), 5.0, 0.12, -1.0, 1.0));
|
||||
btnSettings.setGraphic(SVG.gear("black", 15, 15));
|
||||
btnUpdate.setGraphic(SVG.update("black", 15, 15));
|
||||
@@ -100,6 +100,10 @@ public final class VersionItem extends StackPane {
|
||||
lblGameVersion.setText(gameVersion);
|
||||
}
|
||||
|
||||
public void setLibraries(String libraries) {
|
||||
lblLibraries.setText(libraries);
|
||||
}
|
||||
|
||||
public void setImage(Image image) {
|
||||
iconView.setImage(image);
|
||||
}
|
||||
|
||||
@@ -46,8 +46,6 @@ public final class VersionListItem extends StackPane {
|
||||
lblGameVersion.setText(gameVersion);
|
||||
|
||||
FXUtils.limitSize(imageView, 32, 32);
|
||||
FXUtils.limitWidth(imageViewContainer, 32);
|
||||
FXUtils.limitHeight(imageViewContainer, 32);
|
||||
}
|
||||
|
||||
@FXML
|
||||
|
||||
@@ -85,28 +85,6 @@ public final class VersionSettingsController {
|
||||
|
||||
FXUtils.smoothScrolling(scroll);
|
||||
|
||||
double limitWidth = 300;
|
||||
FXUtils.limitWidth(txtMaxMemory, limitWidth);
|
||||
FXUtils.limitWidth(cboLauncherVisibility, limitWidth);
|
||||
|
||||
double limitHeight = 10;
|
||||
FXUtils.limitHeight(chkNoJVMArgs, limitHeight);
|
||||
FXUtils.limitHeight(chkNoCommon, limitHeight);
|
||||
FXUtils.limitHeight(chkNoGameCheck, limitHeight);
|
||||
FXUtils.limitHeight(chkShowLogs, limitHeight);
|
||||
|
||||
NumberValidator nonnull = new NumberValidator("Must be a number.", false);
|
||||
NumberValidator nullable = new NumberValidator("Must be a number.", true);
|
||||
|
||||
txtWidth.setValidators(nonnull);
|
||||
FXUtils.setValidateWhileTextChanged(txtWidth);
|
||||
txtHeight.setValidators(nonnull);
|
||||
FXUtils.setValidateWhileTextChanged(txtHeight);
|
||||
txtMaxMemory.setValidators(nonnull);
|
||||
FXUtils.setValidateWhileTextChanged(txtMaxMemory);
|
||||
txtMetaspace.setValidators(nullable);
|
||||
FXUtils.setValidateWhileTextChanged(txtMetaspace);
|
||||
|
||||
Task.of(variables -> {
|
||||
variables.set("list", JavaVersion.getJREs().values().stream().map(javaVersion ->
|
||||
javaItem.createChildren(javaVersion.getVersion(), javaVersion.getBinary().getAbsolutePath(), javaVersion)
|
||||
|
||||
@@ -24,10 +24,7 @@ import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import org.jackhuang.hmcl.Main;
|
||||
import org.jackhuang.hmcl.auth.Account;
|
||||
import org.jackhuang.hmcl.auth.AuthInfo;
|
||||
import org.jackhuang.hmcl.auth.SpecificCharacterSelector;
|
||||
import org.jackhuang.hmcl.auth.InvalidCredentialsException;
|
||||
import org.jackhuang.hmcl.auth.*;
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccountFactory;
|
||||
import org.jackhuang.hmcl.setting.Accounts;
|
||||
@@ -78,10 +75,10 @@ public class YggdrasilAccountLoginPane extends StackPane {
|
||||
if (account instanceof AuthInfo) {
|
||||
success.accept(((AuthInfo) account));
|
||||
dialog.close();
|
||||
} else if (account instanceof InvalidCredentialsException) {
|
||||
lblCreationWarning.setText(Main.i18n("account.failed.wrong_password"));
|
||||
} else if (account instanceof NoSelectedCharacterException) {
|
||||
dialog.close();
|
||||
} else if (account instanceof Exception) {
|
||||
lblCreationWarning.setText(account.getClass().toString() + ": " + ((Exception) account).getLocalizedMessage());
|
||||
lblCreationWarning.setText(AccountsPage.accountException((Exception) account));
|
||||
}
|
||||
|
||||
progressBar.setVisible(false);
|
||||
|
||||
@@ -103,7 +103,7 @@ public class ComponentListCell extends StackPane {
|
||||
|
||||
VBox container = new VBox();
|
||||
container.setStyle("-fx-padding: 8 0 0 0;");
|
||||
FXUtils.limitHeight(container, 0);
|
||||
FXUtils.setLimitHeight(container, 0);
|
||||
Rectangle clipRect = new Rectangle();
|
||||
clipRect.widthProperty().bind(container.widthProperty());
|
||||
clipRect.heightProperty().bind(container.heightProperty());
|
||||
|
||||
@@ -96,7 +96,7 @@ public class MultiFileItem extends ComponentList {
|
||||
right.setSpacing(3);
|
||||
right.getChildren().addAll(txtCustom, btnSelect);
|
||||
custom.setRight(right);
|
||||
FXUtils.limitHeight(custom, 20);
|
||||
FXUtils.setLimitHeight(custom, 20);
|
||||
|
||||
pane.setStyle("-fx-padding: 0 0 10 0;");
|
||||
pane.setSpacing(8);
|
||||
@@ -122,7 +122,7 @@ public class MultiFileItem extends ComponentList {
|
||||
public Node createChildren(String title, String subtitle, Object userData) {
|
||||
BorderPane pane = new BorderPane();
|
||||
pane.setStyle("-fx-padding: 3;");
|
||||
FXUtils.limitHeight(pane, 20);
|
||||
FXUtils.setLimitHeight(pane, 20);
|
||||
|
||||
JFXRadioButton left = new JFXRadioButton(title);
|
||||
left.setToggleGroup(group);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package org.jackhuang.hmcl.ui.construct;
|
||||
|
||||
import com.jfoenix.validation.base.ValidatorBase;
|
||||
import javafx.beans.NamedArg;
|
||||
import javafx.scene.control.TextInputControl;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
@@ -28,11 +29,11 @@ public class NumberValidator extends ValidatorBase {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public NumberValidator(boolean nullable) {
|
||||
public NumberValidator(@NamedArg("nullable") boolean nullable) {
|
||||
this.nullable = nullable;
|
||||
}
|
||||
|
||||
public NumberValidator(String message, boolean nullable) {
|
||||
public NumberValidator(@NamedArg("message") String message, @NamedArg("nullable") boolean nullable) {
|
||||
super(message);
|
||||
this.nullable = nullable;
|
||||
}
|
||||
|
||||
@@ -47,9 +47,6 @@ public class TaskExecutorDialogPane extends StackPane {
|
||||
public TaskExecutorDialogPane(Runnable cancel) {
|
||||
FXUtils.loadFXML(this, "/assets/fxml/task-dialog.fxml");
|
||||
|
||||
FXUtils.limitHeight(this, 200);
|
||||
FXUtils.limitWidth(this, 400);
|
||||
|
||||
setCancel(cancel);
|
||||
|
||||
btnCancel.setOnMouseClicked(e -> {
|
||||
|
||||
@@ -64,7 +64,7 @@ public final class DownloadWizardProvider implements WizardProvider {
|
||||
if (settings.containsKey("optifine"))
|
||||
builder.version("optifine", (String) settings.get("optifine"));
|
||||
|
||||
return builder.buildAsync();
|
||||
return builder.buildAsync().finalized((a, b) -> profile.getRepository().refreshVersions());
|
||||
}
|
||||
|
||||
private Task finishModpackInstallingAsync(Map<String, Object> settings) {
|
||||
|
||||
@@ -99,9 +99,6 @@ public final class ModpackPage extends StackPane implements WizardPage {
|
||||
txtModpackName.setText(Main.i18n("modpack.task.install.error"));
|
||||
}
|
||||
}
|
||||
|
||||
//FXUtils.limitHeight(borderPane, 100.0);
|
||||
FXUtils.limitWidth(borderPane, 500.0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,14 +17,20 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.ui.download;
|
||||
|
||||
import com.jfoenix.controls.JFXCheckBox;
|
||||
import com.jfoenix.controls.JFXListView;
|
||||
import com.jfoenix.controls.JFXSpinner;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.download.VersionList;
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
import org.jackhuang.hmcl.download.game.GameRemoteVersionTag;
|
||||
import org.jackhuang.hmcl.download.game.GameVersionList;
|
||||
import org.jackhuang.hmcl.task.TaskExecutor;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
|
||||
@@ -33,7 +39,10 @@ import org.jackhuang.hmcl.ui.wizard.Refreshable;
|
||||
import org.jackhuang.hmcl.ui.wizard.WizardController;
|
||||
import org.jackhuang.hmcl.ui.wizard.WizardPage;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class VersionsPage extends StackPane implements WizardPage, Refreshable {
|
||||
private final WizardController controller;
|
||||
@@ -45,7 +54,20 @@ public final class VersionsPage extends StackPane implements WizardPage, Refresh
|
||||
|
||||
@FXML
|
||||
private JFXListView<VersionsPageItem> list;
|
||||
@FXML private JFXSpinner spinner;
|
||||
@FXML
|
||||
private JFXSpinner spinner;
|
||||
@FXML
|
||||
private StackPane failedPane;
|
||||
@FXML
|
||||
private JFXCheckBox chkRelease;
|
||||
@FXML
|
||||
private JFXCheckBox chkSnapshot;
|
||||
@FXML
|
||||
private JFXCheckBox chkOld;
|
||||
@FXML
|
||||
private HBox checkPane;
|
||||
@FXML
|
||||
private VBox centrePane;
|
||||
|
||||
private final TransitionHandler transitionHandler = new TransitionHandler(this);
|
||||
private final VersionList<?> versionList;
|
||||
@@ -58,11 +80,20 @@ public final class VersionsPage extends StackPane implements WizardPage, Refresh
|
||||
this.downloadProvider = downloadProvider;
|
||||
this.libraryId = libraryId;
|
||||
this.callback = callback;
|
||||
|
||||
this.versionList = downloadProvider.getVersionListById(libraryId);
|
||||
|
||||
FXUtils.loadFXML(this, "/assets/fxml/download/versions.fxml");
|
||||
getChildren().setAll(spinner);
|
||||
|
||||
if (versionList instanceof GameVersionList) {
|
||||
centrePane.getChildren().setAll(checkPane, list);
|
||||
} else
|
||||
centrePane.getChildren().setAll(list);
|
||||
|
||||
InvalidationListener listener = o -> list.getItems().setAll(loadVersions());
|
||||
chkRelease.selectedProperty().addListener(listener);
|
||||
chkSnapshot.selectedProperty().addListener(listener);
|
||||
chkOld.selectedProperty().addListener(listener);
|
||||
|
||||
list.getSelectionModel().selectedItemProperty().addListener((a, b, newValue) -> {
|
||||
controller.getSettings().put(libraryId, newValue.getRemoteVersion().getSelfVersion());
|
||||
callback.run();
|
||||
@@ -70,17 +101,42 @@ public final class VersionsPage extends StackPane implements WizardPage, Refresh
|
||||
refresh();
|
||||
}
|
||||
|
||||
private List<VersionsPageItem> loadVersions() {
|
||||
boolean isGameVersionList = versionList instanceof GameVersionList;
|
||||
return versionList.getVersions(gameVersion).stream()
|
||||
.filter(it -> {
|
||||
if (isGameVersionList)
|
||||
switch (((GameRemoteVersionTag) it.getTag()).getType()) {
|
||||
case RELEASE:
|
||||
return chkRelease.isSelected();
|
||||
case SNAPSHOT:
|
||||
return chkSnapshot.isSelected();
|
||||
default:
|
||||
return chkOld.isSelected();
|
||||
}
|
||||
else return true;
|
||||
})
|
||||
.sorted()
|
||||
.map(VersionsPageItem::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
executor = versionList.refreshAsync(downloadProvider).subscribe(Schedulers.javafx(), () -> {
|
||||
versionList.getVersions(gameVersion).stream()
|
||||
.sorted(RemoteVersion.RemoteVersionComparator.INSTANCE)
|
||||
.forEach(version -> {
|
||||
list.getItems().add(new VersionsPageItem(version));
|
||||
});
|
||||
getChildren().setAll(spinner);
|
||||
executor = versionList.refreshAsync(downloadProvider).finalized((variables, isDependentsSucceeded) -> {
|
||||
if (isDependentsSucceeded) {
|
||||
List<VersionsPageItem> items = loadVersions();
|
||||
|
||||
transitionHandler.setContent(list, ContainerAnimations.FADE.getAnimationProducer());
|
||||
});
|
||||
Platform.runLater(() -> {
|
||||
list.getItems().setAll(items);
|
||||
transitionHandler.setContent(centrePane, ContainerAnimations.FADE.getAnimationProducer());
|
||||
});
|
||||
} else {
|
||||
Platform.runLater(() -> {
|
||||
transitionHandler.setContent(failedPane, ContainerAnimations.FADE.getAnimationProducer());
|
||||
});
|
||||
}
|
||||
}).executor().start();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,4 +150,9 @@ public final class VersionsPage extends StackPane implements WizardPage, Refresh
|
||||
if (executor != null)
|
||||
executor.cancel();
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onRefresh() {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,9 @@ package org.jackhuang.hmcl.ui.download;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import org.jackhuang.hmcl.Main;
|
||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||
import org.jackhuang.hmcl.download.game.GameRemoteVersionTag;
|
||||
import org.jackhuang.hmcl.ui.FXUtils;
|
||||
|
||||
/**
|
||||
@@ -38,7 +40,22 @@ public final class VersionsPageItem extends StackPane {
|
||||
|
||||
FXUtils.loadFXML(this, "/assets/fxml/download/versions-list-item.fxml");
|
||||
lblSelfVersion.setText(remoteVersion.getSelfVersion());
|
||||
lblGameVersion.setText(remoteVersion.getGameVersion());
|
||||
|
||||
if (remoteVersion.getTag() instanceof GameRemoteVersionTag) {
|
||||
switch (((GameRemoteVersionTag) remoteVersion.getTag()).getType()) {
|
||||
case RELEASE:
|
||||
lblGameVersion.setText(Main.i18n("version.game.release"));
|
||||
break;
|
||||
case SNAPSHOT:
|
||||
lblGameVersion.setText(Main.i18n("version.game.snapshot"));
|
||||
break;
|
||||
default:
|
||||
lblGameVersion.setText(Main.i18n("version.game.old"));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
lblGameVersion.setText(remoteVersion.getGameVersion());
|
||||
}
|
||||
}
|
||||
|
||||
public RemoteVersion<?> getRemoteVersion() {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
.root {
|
||||
-fx-font-family: "微软雅黑", "Roboto";
|
||||
-fx-font-family: "微软雅黑", "Microsoft YaHei", "Roboto";
|
||||
}
|
||||
|
||||
.disabled Label {
|
||||
@@ -899,6 +899,7 @@
|
||||
.jfx-spinner > .arc {
|
||||
-fx-stroke-width: 3.0;
|
||||
-fx-fill: transparent;
|
||||
-fx-stroke: -fx-base-color;
|
||||
}
|
||||
|
||||
.first-spinner {
|
||||
@@ -957,50 +958,6 @@
|
||||
-fx-stroke-width: 5.0;
|
||||
}
|
||||
|
||||
.blue-spinner .arc {
|
||||
-fx-stroke: #4285f4;
|
||||
}
|
||||
|
||||
.red-spinner .arc {
|
||||
-fx-stroke: #db4437;
|
||||
}
|
||||
|
||||
.green-spinner .arc {
|
||||
-fx-stroke: #f4b400;
|
||||
}
|
||||
|
||||
.yellow-spinner .arc {
|
||||
-fx-stroke: -fx-base-check-color;
|
||||
}
|
||||
|
||||
.materialDesign-purple .arc {
|
||||
-fx-stroke: #ab47bc;
|
||||
}
|
||||
|
||||
.materialDesign-blue .arc {
|
||||
-fx-stroke: #2962ff;
|
||||
}
|
||||
|
||||
.materialDesign-cyan .arc {
|
||||
-fx-stroke: #00b8d4;
|
||||
}
|
||||
|
||||
.materialDesign-green .arc {
|
||||
-fx-stroke: #00c853;
|
||||
}
|
||||
|
||||
.materialDesign-yellow .arc {
|
||||
-fx-stroke: #ffd600;
|
||||
}
|
||||
|
||||
.materialDesign-orange .arc {
|
||||
-fx-stroke: #ff6d00;
|
||||
}
|
||||
|
||||
.materialDesign-red .arc {
|
||||
-fx-stroke: #d50000;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* JFX Combo Box *
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
<?import javafx.scene.image.Image?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import org.jackhuang.hmcl.ui.FXUtils?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
type="StackPane">
|
||||
type="StackPane" FXUtils.limitWidth="160" FXUtils.limitHeight="156">
|
||||
<VBox fx:id="content">
|
||||
<StackPane fx:id="header" VBox.vgrow="ALWAYS">
|
||||
<BorderPane>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.ScrollPane?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import java.lang.String?>
|
||||
<?import org.jackhuang.hmcl.ui.FXUtils?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
type="StackPane">
|
||||
@@ -38,13 +38,13 @@
|
||||
|
||||
<JFXComboBox fx:id="cboType" GridPane.columnIndex="1" GridPane.rowIndex="0" />
|
||||
|
||||
<JFXTextField fx:id="txtUsername" promptText="%account.username" labelFloat="true" GridPane.columnIndex="0" GridPane.rowIndex="1" GridPane.columnSpan="2">
|
||||
<JFXTextField fx:id="txtUsername" promptText="%account.username" labelFloat="true" GridPane.columnIndex="0" GridPane.rowIndex="1" GridPane.columnSpan="2" FXUtils.validateWhileTextChanged="true">
|
||||
<validators>
|
||||
<RequiredFieldValidator message="%input.not_empty">
|
||||
</RequiredFieldValidator>
|
||||
</validators>
|
||||
</JFXTextField>
|
||||
<JFXPasswordField fx:id="txtPassword" promptText="%account.password" labelFloat="true" GridPane.columnIndex="0" GridPane.rowIndex="2" GridPane.columnSpan="2">
|
||||
<JFXPasswordField fx:id="txtPassword" promptText="%account.password" labelFloat="true" GridPane.columnIndex="0" GridPane.rowIndex="2" GridPane.columnSpan="2" FXUtils.validateWhileTextChanged="true">
|
||||
<validators>
|
||||
<RequiredFieldValidator message="%input.not_empty">
|
||||
</RequiredFieldValidator>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<?import javafx.scene.shape.Rectangle?>
|
||||
<?import org.jackhuang.hmcl.ui.construct.AdvancedListBox?>
|
||||
<?import java.lang.String?>
|
||||
<?import org.jackhuang.hmcl.ui.FXUtils?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
type="StackPane"
|
||||
xmlns:fx="http://javafx.com/fxml">
|
||||
@@ -18,7 +19,7 @@
|
||||
maxHeight="519"
|
||||
maxWidth="800">
|
||||
<center>
|
||||
<StackPane fx:id="drawerWrapper" styleClass="jfx-decorator-drawer">
|
||||
<StackPane fx:id="drawerWrapper" styleClass="jfx-decorator-drawer" FXUtils.overflowHidden="true">
|
||||
<JFXDialog fx:id="dialog" overlayClose="false" />
|
||||
<BorderPane>
|
||||
<left>
|
||||
@@ -47,7 +48,7 @@
|
||||
</StackPane>
|
||||
</left>
|
||||
<center>
|
||||
<StackPane fx:id="contentPlaceHolderRoot" styleClass="jfx-decorator-content-container"
|
||||
<StackPane fx:id="contentPlaceHolderRoot" styleClass="jfx-decorator-content-container" FXUtils.overflowHidden="true"
|
||||
VBox.vgrow="ALWAYS">
|
||||
<StackPane fx:id="contentPlaceHolder" styleClass="jfx-decorator-content-container">
|
||||
<!-- Node -->
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</JFXListView>
|
||||
</StackPane>
|
||||
|
||||
<HBox alignment="BOTTOM_CENTER" style="-fx-padding: 20;">
|
||||
<HBox alignment="BOTTOM_CENTER" style="-fx-padding: 20;" pickOnBounds="false">
|
||||
<Label text="%modpack.introduction" />
|
||||
</HBox>
|
||||
</fx:root>
|
||||
@@ -6,13 +6,14 @@
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import org.jackhuang.hmcl.ui.construct.ComponentList?>
|
||||
<?import org.jackhuang.hmcl.ui.FXUtils?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
type="StackPane">
|
||||
<fx:define>
|
||||
<Insets fx:id="insets" bottom="12" />
|
||||
</fx:define>
|
||||
<VBox fx:id="borderPane" alignment="CENTER">
|
||||
<VBox fx:id="borderPane" alignment="CENTER" FXUtils.limitWidth="500">
|
||||
<HBox style="-fx-padding: 0 0 16 5;"><Label text="%modpack.task.install" /></HBox>
|
||||
<ComponentList>
|
||||
<BorderPane><left><Label text="%modpack.task.install.will" /></left><right><Label fx:id="lblModpackLocation" /></right></BorderPane>
|
||||
|
||||
@@ -3,11 +3,25 @@
|
||||
<?import com.jfoenix.controls.JFXListView?>
|
||||
<?import com.jfoenix.controls.JFXSpinner?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import com.jfoenix.controls.JFXCheckBox?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
type="StackPane"
|
||||
prefHeight="400.0" prefWidth="600.0">
|
||||
<JFXSpinner fx:id="spinner" style="-fx-radius:16" styleClass="materialDesign-purple, first-spinner" />
|
||||
<JFXListView fx:id="list" styleClass="jfx-list-view">
|
||||
</JFXListView>
|
||||
<JFXSpinner fx:id="spinner" styleClass="first-spinner" />
|
||||
<VBox fx:id="centrePane">
|
||||
<HBox fx:id="checkPane" spacing="10" style="-fx-padding: 10;">
|
||||
<JFXCheckBox fx:id="chkRelease" text="%version.game.release" selected="true" />
|
||||
<JFXCheckBox fx:id="chkSnapshot" text="%version.game.snapshot" />
|
||||
<JFXCheckBox fx:id="chkOld" text="%version.game.old" />
|
||||
</HBox>
|
||||
<JFXListView fx:id="list" styleClass="jfx-list-view" VBox.vgrow="ALWAYS">
|
||||
</JFXListView>
|
||||
</VBox>
|
||||
<StackPane fx:id="failedPane">
|
||||
<Label onMouseClicked="#onRefresh" style="-fx-text-fill: #0079FF; -fx-font-size: 20;" text="%download.failed.refresh" />
|
||||
</StackPane>
|
||||
</fx:root>
|
||||
@@ -8,6 +8,8 @@
|
||||
<?import org.jackhuang.hmcl.ui.construct.FileItem?>
|
||||
<?import org.jackhuang.hmcl.ui.construct.FontComboBox?>
|
||||
<?import org.jackhuang.hmcl.ui.construct.MultiFileItem?>
|
||||
<?import org.jackhuang.hmcl.ui.construct.NumberValidator?>
|
||||
<?import org.jackhuang.hmcl.ui.FXUtils?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
type="StackPane">
|
||||
@@ -38,7 +40,7 @@
|
||||
<MultiFileItem fx:id="backgroundItem" title="%launcher.background" chooserTitle="%launcher.background.choose"
|
||||
hasSubtitle="true" customText="%settings.custom" />
|
||||
|
||||
<BorderPane><left><Label text="%settings.launcher.download_source" BorderPane.alignment="CENTER_LEFT" /></left><right><JFXComboBox fx:id="cboDownloadSource">
|
||||
<BorderPane><left><Label text="%settings.launcher.download_source" BorderPane.alignment="CENTER_LEFT" /></left><right><JFXComboBox fx:id="cboDownloadSource" FXUtils.limitWidth="400">
|
||||
<items>
|
||||
<FXCollections fx:factory="observableArrayList">
|
||||
<Label text="%download.mojang" />
|
||||
@@ -46,26 +48,69 @@
|
||||
</FXCollections>
|
||||
</items>
|
||||
</JFXComboBox></right></BorderPane>
|
||||
<BorderPane><left><Label text="%settings.launcher.language" BorderPane.alignment="CENTER_LEFT" /></left><right><JFXComboBox fx:id="cboLanguage" /></right></BorderPane>
|
||||
<BorderPane><left><Label text="%settings.launcher.proxy" BorderPane.alignment="CENTER_LEFT" /></left><right><HBox alignment="CENTER_LEFT" spacing="5">
|
||||
<JFXComboBox fx:id="cboProxyType">
|
||||
<items>
|
||||
<FXCollections fx:factory="observableArrayList">
|
||||
<Label text="%settings.launcher.proxy.direct" />
|
||||
<Label text="HTTP" />
|
||||
<Label text="Socks" />
|
||||
</FXCollections>
|
||||
</items>
|
||||
</JFXComboBox>
|
||||
<Label text="%settings.launcher.proxy.host" />
|
||||
<JFXTextField fx:id="txtProxyHost" maxWidth="50" />
|
||||
<Label text="%settings.launcher.proxy.port" />
|
||||
<JFXTextField fx:id="txtProxyPort" maxWidth="50" />
|
||||
<Label text="%settings.launcher.proxy.username" />
|
||||
<JFXTextField fx:id="txtProxyUsername" maxWidth="50" />
|
||||
<Label text="%settings.launcher.proxy.password" />
|
||||
<JFXTextField fx:id="txtProxyPassword" maxWidth="50" />
|
||||
</HBox></right></BorderPane>
|
||||
<BorderPane>
|
||||
<left>
|
||||
<Label text="%settings.launcher.language" BorderPane.alignment="CENTER_LEFT" />
|
||||
</left>
|
||||
<right>
|
||||
<JFXComboBox fx:id="cboLanguage" FXUtils.limitWidth="400" />
|
||||
</right>
|
||||
</BorderPane>
|
||||
|
||||
<ComponentList title="%settings.launcher.proxy"> <!-- proxy -->
|
||||
<VBox spacing="10">
|
||||
<JFXRadioButton fx:id="chkNoProxy" text="%settings.launcher.proxy.no_proxy" />
|
||||
<JFXRadioButton fx:id="chkManualProxy" text="%settings.launcher.proxy.has_proxy" />
|
||||
<VBox fx:id="proxyPane" style="-fx-padding: 0 0 0 30;">
|
||||
<HBox>
|
||||
<JFXRadioButton fx:id="chkProxyHttp" text="%settings.launcher.proxy.http" />
|
||||
<JFXRadioButton fx:id="chkProxySocks" text="%settings.launcher.proxy.socks" />
|
||||
</HBox>
|
||||
<GridPane hgap="20" vgap="10" style="-fx-padding: 0 0 0 15;">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints />
|
||||
<ColumnConstraints hgrow="ALWAYS" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints />
|
||||
<RowConstraints />
|
||||
</rowConstraints>
|
||||
|
||||
<Label text="%settings.launcher.proxy.host" GridPane.rowIndex="1" GridPane.columnIndex="0" GridPane.halignment="RIGHT" />
|
||||
<JFXTextField fx:id="txtProxyHost" styleClass="fit-width" GridPane.rowIndex="1" GridPane.columnIndex="1" />
|
||||
|
||||
<Label text="%settings.launcher.proxy.port" GridPane.rowIndex="2" GridPane.columnIndex="0" GridPane.halignment="RIGHT" />
|
||||
<JFXTextField fx:id="txtProxyPort" styleClass="fit-width" GridPane.rowIndex="2" GridPane.columnIndex="1" FXUtils.validateWhileTextChanged="true">
|
||||
<validators>
|
||||
<NumberValidator message="%input.number" nullable="false" />
|
||||
</validators>
|
||||
</JFXTextField>
|
||||
|
||||
</GridPane>
|
||||
|
||||
<VBox style="-fx-padding: 20 0 20 5;">
|
||||
<JFXCheckBox fx:id="chkProxyAuthentication" text="%settings.launcher.proxy.authentication" />
|
||||
</VBox>
|
||||
|
||||
<GridPane fx:id="authPane" hgap="20" vgap="10" style="-fx-padding: 0 0 0 15;">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints />
|
||||
<ColumnConstraints hgrow="ALWAYS" />
|
||||
</columnConstraints>
|
||||
|
||||
<rowConstraints>
|
||||
<RowConstraints />
|
||||
<RowConstraints />
|
||||
</rowConstraints>
|
||||
|
||||
<Label fx:id="" text="%settings.launcher.proxy.username" GridPane.rowIndex="0" GridPane.columnIndex="0" />
|
||||
<JFXTextField fx:id="txtProxyUsername" styleClass="fit-width" GridPane.rowIndex="0" GridPane.columnIndex="1" />
|
||||
<Label text="%settings.launcher.proxy.password" GridPane.rowIndex="1" GridPane.columnIndex="0" />
|
||||
<JFXPasswordField fx:id="txtProxyPassword" styleClass="fit-width" GridPane.rowIndex="1" GridPane.columnIndex="1" />
|
||||
</GridPane>
|
||||
</VBox>
|
||||
</VBox>
|
||||
</ComponentList>
|
||||
|
||||
<MultiFileItem fx:id="themeItem" title="%settings.launcher.theme" hasSubtitle="true" hasCustom="false" />
|
||||
|
||||
@@ -88,17 +133,17 @@
|
||||
<RowConstraints minHeight="-Infinity" valignment="TOP" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="-Infinity" valignment="TOP" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<Label text="%about.copyright" style="-fx-font-weight: bold;" GridPane.columnIndex="0" GridPane.rowIndex="0" />
|
||||
<Label text="%about.copyright" GridPane.columnIndex="0" GridPane.rowIndex="0" />
|
||||
<Label wrapText="true" text="%about.copyright.statement" GridPane.columnIndex="1" GridPane.rowIndex="0" />
|
||||
<Label text="%about.author" style="-fx-font-weight: bold;" GridPane.columnIndex="0" GridPane.rowIndex="1" />
|
||||
<Label text="%about.author" GridPane.columnIndex="0" GridPane.rowIndex="1" />
|
||||
<Label wrapText="true" text="%about.author.statement" GridPane.columnIndex="1" GridPane.rowIndex="1" />
|
||||
<Label text="%about.thanks_to" style="-fx-font-weight: bold;" GridPane.columnIndex="0" GridPane.rowIndex="2" />
|
||||
<Label text="%about.thanks_to" GridPane.columnIndex="0" GridPane.rowIndex="2" />
|
||||
<Label wrapText="true" text="%about.thanks_to.statement" GridPane.columnIndex="1" GridPane.rowIndex="2" />
|
||||
<Label text="%about.dependency" style="-fx-font-weight: bold;" GridPane.columnIndex="0" GridPane.rowIndex="3" />
|
||||
<Label text="%about.dependency" GridPane.columnIndex="0" GridPane.rowIndex="3" />
|
||||
<Label wrapText="true" text="%about.dependency.statement" GridPane.columnIndex="1" GridPane.rowIndex="3" />
|
||||
<Label text="%about.claim" style="-fx-font-weight: bold;" GridPane.columnIndex="0" GridPane.rowIndex="4" />
|
||||
<Label text="%about.claim" GridPane.columnIndex="0" GridPane.rowIndex="4" />
|
||||
<Label textAlignment="JUSTIFY" wrapText="true" text="%about.claim.statement" GridPane.columnIndex="1" GridPane.rowIndex="4" />
|
||||
<Label text="%about.open_source" style="-fx-font-weight: bold;" GridPane.columnIndex="0" GridPane.rowIndex="5" />
|
||||
<Label text="%about.open_source" GridPane.columnIndex="0" GridPane.rowIndex="5" />
|
||||
<Label wrapText="true" text="%about.open_source.statement" GridPane.columnIndex="1" GridPane.rowIndex="5" />
|
||||
</GridPane>
|
||||
</StackPane>
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.control.ScrollPane?>
|
||||
<?import org.jackhuang.hmcl.ui.FXUtils?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
type="StackPane">
|
||||
type="StackPane" FXUtils.limitWidth="400" FXUtils.limitHeight="200">
|
||||
<BorderPane>
|
||||
<top>
|
||||
<JFXProgressBar fx:id="progressBar" StackPane.alignment="TOP_CENTER" />
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
<?import javafx.scene.image.Image?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.control.Tooltip?>
|
||||
<?import org.jackhuang.hmcl.ui.FXUtils?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
type="StackPane" pickOnBounds="false">
|
||||
type="StackPane" pickOnBounds="false" FXUtils.limitWidth="160" FXUtils.limitHeight="156">
|
||||
<VBox fx:id="content" pickOnBounds="false">
|
||||
<StackPane fx:id="header" VBox.vgrow="ALWAYS" pickOnBounds="false" style="-fx-background-radius: 2 2 0 0; -fx-background-color: rgb(255,255,255,0.87); -fx-padding: 8;">
|
||||
<BorderPane>
|
||||
@@ -21,6 +21,7 @@
|
||||
<VBox style="-fx-padding: 8 8 0 8;">
|
||||
<Label fx:id="lblVersionName" style="-fx-font-size: 15;" textAlignment="JUSTIFY" wrapText="true" />
|
||||
<Label fx:id="lblGameVersion" style="-fx-font-size: 10;" textAlignment="JUSTIFY" wrapText="true" />
|
||||
<Label fx:id="lblLibraries" style="-fx-font-size: 10; -fx-text-fill: gray;" textAlignment="JUSTIFY" wrapText="true" />
|
||||
</VBox>
|
||||
</center>
|
||||
</BorderPane>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<?import javafx.scene.image.Image?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import org.jackhuang.hmcl.ui.FXUtils?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
styleClass="transparent"
|
||||
@@ -13,10 +14,10 @@
|
||||
<BorderPane pickOnBounds="false">
|
||||
<left>
|
||||
<HBox alignment="CENTER" mouseTransparent="true">
|
||||
<StackPane fx:id="imageViewContainer">
|
||||
<ImageView preserveRatio="true" fx:id="imageView" smooth="false">
|
||||
<Image url="/assets/img/icon.png" />
|
||||
</ImageView>
|
||||
<StackPane fx:id="imageViewContainer" FXUtils.limitWidth="32" FXUtils.limitHeight="32">
|
||||
<ImageView preserveRatio="true" fx:id="imageView" smooth="false">
|
||||
<Image url="/assets/img/icon.png" />
|
||||
</ImageView>
|
||||
</StackPane>
|
||||
<BorderPane style="-fx-padding: 0 0 0 10;">
|
||||
<top>
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import org.jackhuang.hmcl.ui.construct.ComponentList?>
|
||||
<?import org.jackhuang.hmcl.ui.construct.MultiFileItem?>
|
||||
<?import org.jackhuang.hmcl.ui.construct.NumberValidator?>
|
||||
<?import org.jackhuang.hmcl.ui.FXUtils?>
|
||||
<StackPane xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="org.jackhuang.hmcl.ui.VersionSettingsController">
|
||||
@@ -56,7 +58,11 @@
|
||||
</VBox>
|
||||
</left>
|
||||
<right>
|
||||
<JFXTextField fx:id="txtMaxMemory" BorderPane.alignment="CENTER_RIGHT"/>
|
||||
<JFXTextField fx:id="txtMaxMemory" BorderPane.alignment="CENTER_RIGHT" FXUtils.validateWhileTextChanged="true" FXUtils.limitWidth="300">
|
||||
<validators>
|
||||
<NumberValidator message="%input.number" nullable="false" />
|
||||
</validators>
|
||||
</JFXTextField>
|
||||
</right>
|
||||
</BorderPane>
|
||||
|
||||
@@ -65,7 +71,7 @@
|
||||
<Label text="%settings.advanced.launcher_visible" BorderPane.alignment="CENTER_LEFT"/>
|
||||
</left>
|
||||
<right>
|
||||
<JFXComboBox fx:id="cboLauncherVisibility" BorderPane.alignment="CENTER_RIGHT">
|
||||
<JFXComboBox fx:id="cboLauncherVisibility" BorderPane.alignment="CENTER_RIGHT" FXUtils.limitWidth="300">
|
||||
<items>
|
||||
<FXCollections fx:factory="observableArrayList">
|
||||
<Label text="%settings.advanced.launcher_visibility.close"/>
|
||||
@@ -86,9 +92,17 @@
|
||||
<BorderPane>
|
||||
<left>
|
||||
<HBox prefWidth="210" spacing="3" alignment="CENTER" BorderPane.alignment="CENTER">
|
||||
<JFXTextField fx:id="txtWidth" promptText="800" prefWidth="100"/>
|
||||
<JFXTextField fx:id="txtWidth" promptText="800" prefWidth="100" FXUtils.validateWhileTextChanged="true">
|
||||
<validators>
|
||||
<NumberValidator message="%input.number" nullable="false" />
|
||||
</validators>
|
||||
</JFXTextField>
|
||||
<Label>x</Label>
|
||||
<JFXTextField fx:id="txtHeight" promptText="480" prefWidth="100"/>
|
||||
<JFXTextField fx:id="txtHeight" promptText="480" prefWidth="100" FXUtils.validateWhileTextChanged="true">
|
||||
<validators>
|
||||
<NumberValidator message="%input.number" nullable="false" />
|
||||
</validators>
|
||||
</JFXTextField>
|
||||
</HBox>
|
||||
</left>
|
||||
<right>
|
||||
@@ -108,7 +122,7 @@
|
||||
<Label text="%settings.show_log"/>
|
||||
</left>
|
||||
<right>
|
||||
<JFXToggleButton fx:id="chkShowLogs" size="7"/>
|
||||
<JFXToggleButton fx:id="chkShowLogs" size="7" FXUtils.limitHeight="10" />
|
||||
</right>
|
||||
</BorderPane>
|
||||
</ComponentList>
|
||||
@@ -128,7 +142,11 @@
|
||||
<JFXTextField labelFloat="true" promptText="%settings.advanced.minecraft_arguments"
|
||||
styleClass="fit-width" fx:id="txtGameArgs" StackPane.margin="$insets"/>
|
||||
<JFXTextField labelFloat="true" promptText="%settings.advanced.java_permanent_generation_space"
|
||||
styleClass="fit-width" fx:id="txtMetaspace" StackPane.margin="$insets"/>
|
||||
styleClass="fit-width" fx:id="txtMetaspace" StackPane.margin="$insets" FXUtils.validateWhileTextChanged="true">
|
||||
<validators>
|
||||
<NumberValidator message="%input.number" nullable="true" />
|
||||
</validators>
|
||||
</JFXTextField>
|
||||
<JFXTextField labelFloat="true" promptText="%settings.advanced.wrapper_launcher" styleClass="fit-width"
|
||||
fx:id="txtWrapper" StackPane.margin="$insets"/>
|
||||
<JFXTextField labelFloat="true" promptText="%settings.advanced.precall_command" styleClass="fit-width"
|
||||
@@ -140,7 +158,7 @@
|
||||
<Label text="%settings.advanced.no_jvm_args"/>
|
||||
</left>
|
||||
<right>
|
||||
<JFXToggleButton fx:id="chkNoJVMArgs" size="7"/>
|
||||
<JFXToggleButton fx:id="chkNoJVMArgs" size="7" FXUtils.limitHeight="10" />
|
||||
</right>
|
||||
</BorderPane>
|
||||
<BorderPane>
|
||||
@@ -148,7 +166,7 @@
|
||||
<Label text="%settings.advanced.no_common"/>
|
||||
</left>
|
||||
<right>
|
||||
<JFXToggleButton fx:id="chkNoCommon" size="7"/>
|
||||
<JFXToggleButton fx:id="chkNoCommon" size="7" FXUtils.limitHeight="10" />
|
||||
</right>
|
||||
</BorderPane>
|
||||
<BorderPane>
|
||||
@@ -156,7 +174,7 @@
|
||||
<Label text="%settings.advanced.dont_check_game_completeness"/>
|
||||
</left>
|
||||
<right>
|
||||
<JFXToggleButton fx:id="chkNoGameCheck" size="7"/>
|
||||
<JFXToggleButton fx:id="chkNoGameCheck" size="7" FXUtils.limitHeight="10" />
|
||||
</right>
|
||||
</BorderPane>
|
||||
</ComponentList>
|
||||
|
||||
@@ -34,10 +34,10 @@ account.current=Current account
|
||||
account.create=Create a new account
|
||||
account.email=Email
|
||||
account.failed.connect_authentication_server=Cannot connect the authentication server. Check your network.
|
||||
account.failed.invalid_credentials=Incorrect password. Or forbidden to log in temporarily.
|
||||
account.failed.invalid_password=Invalid password
|
||||
account.failed.invalid_token=Please log out and re-input your password to log in.
|
||||
account.failed.no_charactor=No character in this account.
|
||||
account.failed.wrong_password=Incorrect password or username
|
||||
account.methods=Login Type
|
||||
account.methods.no_method=No login method
|
||||
account.methods.offline=Offline
|
||||
@@ -105,6 +105,7 @@ crash.user_fault=Your OS or Java environment may not be properly installed resul
|
||||
download=Download
|
||||
download.BMCL=BMCLAPI (bangbang93, http://bmclapi.bangbang93.com/)
|
||||
download.failed=Failed to download
|
||||
download.failed.refresh=Unable to load version list. Click here to retry.
|
||||
download.mojang=Mojang
|
||||
download.not_200=Failed to download, the response code is %s.
|
||||
download.source=Download Source
|
||||
@@ -124,6 +125,7 @@ folder.saves=Saves
|
||||
folder.screenshots=Screenshots
|
||||
|
||||
input.email=The username must be an e-mail.
|
||||
input.number=Must be a number.
|
||||
input.not_empty=Input Requrired!
|
||||
|
||||
install=Install New Game
|
||||
@@ -295,13 +297,14 @@ operation.confirm_stop=Terminate the operations?
|
||||
operation.stopped=The operation was aborted.
|
||||
|
||||
profile=Profile
|
||||
profile.copy_from=Copy From:
|
||||
profile.default=Current directory
|
||||
profile.home=User home
|
||||
profile.instance_directory=Game Directory
|
||||
profile.new=New Config
|
||||
profile.new_name=New Profile Name:
|
||||
profile.remove=Sure to remove profile %s?
|
||||
profile.title=Game Directories
|
||||
profile.selected=Current directory
|
||||
profile.selected=Selected
|
||||
|
||||
selector.choose=Choose
|
||||
selector.choose_file=Select a file
|
||||
@@ -350,10 +353,14 @@ settings.launcher.download_source=Download Source
|
||||
settings.launcher.language=Language
|
||||
settings.launcher.log_font=Log Font
|
||||
settings.launcher.proxy=Proxy
|
||||
settings.launcher.proxy.direct=Direct
|
||||
settings.launcher.proxy.authentication=Proxy Authentication
|
||||
settings.launcher.proxy.no_proxy=No proxy
|
||||
settings.launcher.proxy.has_proxy=Proxy configuration
|
||||
settings.launcher.proxy.host=Host
|
||||
settings.launcher.proxy.http=HTTP
|
||||
settings.launcher.proxy.password=Password
|
||||
settings.launcher.proxy.port=Port
|
||||
settings.launcher.proxy.socks=Socks
|
||||
settings.launcher.proxy.username=Account
|
||||
settings.launcher.theme=Theme
|
||||
|
||||
@@ -381,8 +388,7 @@ update.tooltip=Update
|
||||
|
||||
version.cannot_read=Unable to gather the game version. Cannot continue auto-installing.
|
||||
version.forbidden_name=Forbidden name, do not use this.
|
||||
version.game.old_alpha=Old Alpha
|
||||
version.game.old_beta=Beta
|
||||
version.game.old=Old
|
||||
version.game.release=Release
|
||||
version.game.snapshot=Snapshot
|
||||
version.launch=Play
|
||||
|
||||
@@ -34,10 +34,10 @@ account.current=当前账户
|
||||
account.create=新建账户
|
||||
account.email=邮箱
|
||||
account.failed.connect_authentication_server=无法连接认证服务器,可能是网络问题
|
||||
account.failed.invalid_credentials=您的用户名或密码错误,或者登录次数过多被暂时禁止登录,请稍后再试
|
||||
account.failed.invalid_password=无效的密码
|
||||
account.failed.invalid_token=请尝试登出并重新输入密码登录
|
||||
account.failed.no_charactor=该帐号没有角色
|
||||
account.failed.wrong_password=可能是您的用户名或密码错误
|
||||
account.methods=登录方式
|
||||
account.methods.no_method=没有登入方式...
|
||||
account.methods.offline=离线模式
|
||||
@@ -105,6 +105,7 @@ crash.user_fault=您的系统或Java环境可能安装不当导致本软件崩
|
||||
download=下载
|
||||
download.BMCL=BMCLAPI (bangbang93, http://bmclapi.bangbang93.com/)
|
||||
download.failed=下载失败
|
||||
download.failed.refresh=加载版本列表失败,点击此处重试。
|
||||
download.mojang=官方
|
||||
download.not_200=下载失败,HTTP状态码:%s.
|
||||
download.source=下载源
|
||||
@@ -124,6 +125,7 @@ folder.saves=存档文件夹
|
||||
folder.screenshots=截图文件夹
|
||||
|
||||
input.email=用户名必须是邮箱
|
||||
input.number=必须是数字
|
||||
input.not_empty=必填项
|
||||
|
||||
install=添加游戏
|
||||
@@ -295,13 +297,14 @@ operation.confirm_stop=真的要终止操作吗?
|
||||
operation.stopped=操作被强行终止
|
||||
|
||||
profile=配置
|
||||
profile.copy_from=复制配置:
|
||||
profile.default=当前目录
|
||||
profile.home=主文件夹
|
||||
profile.instance_directory=游戏路径
|
||||
profile.new=新建配置
|
||||
profile.new_name=新配置名:
|
||||
profile.remove=真的要删除配置%s吗?
|
||||
profile.title=游戏目录
|
||||
profile.selected=当前目录
|
||||
profile.selected=已选中
|
||||
|
||||
selector.choose=选择
|
||||
selector.choose_file=选择文件
|
||||
@@ -350,10 +353,14 @@ settings.launcher.download_source=下载源
|
||||
settings.launcher.language=语言
|
||||
settings.launcher.log_font=日志字体
|
||||
settings.launcher.proxy=代理
|
||||
settings.launcher.proxy.direct=直连
|
||||
settings.launcher.proxy.authentication=代理账户
|
||||
settings.launcher.proxy.no_proxy=直连
|
||||
settings.launcher.proxy.has_proxy=启用验证
|
||||
settings.launcher.proxy.host=主机
|
||||
settings.launcher.proxy.http=HTTP
|
||||
settings.launcher.proxy.password=密码
|
||||
settings.launcher.proxy.port=端口
|
||||
settings.launcher.proxy.socks=Socks
|
||||
settings.launcher.proxy.username=账户
|
||||
settings.launcher.theme=主题
|
||||
|
||||
@@ -381,10 +388,9 @@ update.tooltip=更新
|
||||
|
||||
version.cannot_read=读取游戏版本失败,无法进行自动安装
|
||||
version.forbidden_name=此版本名称不受支持,请换一个名字
|
||||
version.game.old_alpha=远古版
|
||||
version.game.old_beta=测试版
|
||||
version.game.old=远古版
|
||||
version.game.release=稳定版
|
||||
version.game.snapshot=快照版
|
||||
version.game.snapshot=测试版
|
||||
version.launch=启动游戏
|
||||
version.launch_script=生成启动脚本
|
||||
version.launch_script.failed=生成启动脚本失败
|
||||
|
||||
@@ -57,6 +57,14 @@ public abstract class Account {
|
||||
*/
|
||||
public abstract AuthInfo logIn(MultiCharacterSelector selector, Proxy proxy) throws AuthenticationException;
|
||||
|
||||
public abstract boolean canPlayOffline();
|
||||
|
||||
/**
|
||||
* Play offline.
|
||||
* @return the specific offline player's info.
|
||||
*/
|
||||
public abstract AuthInfo playOffline();
|
||||
|
||||
public abstract void logOut();
|
||||
|
||||
protected abstract Map<Object, Object> toStorageImpl();
|
||||
|
||||
@@ -69,6 +69,16 @@ public class OfflineAccount extends Account {
|
||||
// Offline account need not log out.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlayOffline() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthInfo playOffline() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Object> toStorageImpl() {
|
||||
return Lang.mapOf(
|
||||
|
||||
@@ -171,6 +171,19 @@ public final class YggdrasilAccount extends Account {
|
||||
userProperties.putAll(user.getProperties());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlayOffline() {
|
||||
return isLoggedIn() && getSelectedProfile() != null && !canPlayOnline();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthInfo playOffline() {
|
||||
if (!canPlayOffline())
|
||||
throw new IllegalStateException("Current account " + this + " cannot play offline.");
|
||||
|
||||
return new AuthInfo(selectedProfile, accessToken, userType, GSON.toJson(userProperties));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logOut() {
|
||||
password = null;
|
||||
|
||||
@@ -62,7 +62,7 @@ public class DefaultGameBuilder extends GameBuilder {
|
||||
downloadGameAsync(gameVersion, version),
|
||||
new GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries.
|
||||
).with(new VersionJsonSaveTask(dependencyManager.getGameRepository(), version)); // using [with] because download failure here are tolerant.
|
||||
|
||||
|
||||
if (toolVersions.containsKey("forge"))
|
||||
result = result.then(libraryTaskHelper(gameVersion, "forge"));
|
||||
if (toolVersions.containsKey("liteloader"))
|
||||
@@ -70,12 +70,9 @@ public class DefaultGameBuilder extends GameBuilder {
|
||||
if (toolVersions.containsKey("optifine"))
|
||||
result = result.then(libraryTaskHelper(gameVersion, "optifine"));
|
||||
return result;
|
||||
}).finalized(new Task() {
|
||||
@Override
|
||||
public void execute() {
|
||||
if (!isDependentsSucceeded())
|
||||
dependencyManager.getGameRepository().getVersionRoot(name).delete();
|
||||
}
|
||||
}).finalized((variables, isDependentsSucceeded) -> {
|
||||
if (!isDependentsSucceeded)
|
||||
dependencyManager.getGameRepository().getVersionRoot(name).delete();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -78,20 +78,6 @@ public class RemoteVersion<T> implements Comparable<RemoteVersion<T>> {
|
||||
@Override
|
||||
public int compareTo(RemoteVersion<T> o) {
|
||||
// newer versions are smaller than older versions
|
||||
return -selfVersion.compareTo(o.selfVersion);
|
||||
}
|
||||
|
||||
public static class RemoteVersionComparator implements Comparator<RemoteVersion<?>> {
|
||||
|
||||
public static final RemoteVersionComparator INSTANCE = new RemoteVersionComparator();
|
||||
|
||||
private RemoteVersionComparator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(RemoteVersion<?> o1, RemoteVersion<?> o2) {
|
||||
return -VersionNumber.asVersion(o1.selfVersion).compareTo(VersionNumber.asVersion(o2.selfVersion));
|
||||
}
|
||||
|
||||
return -VersionNumber.asVersion(selfVersion).compareTo(VersionNumber.asVersion(o.selfVersion));
|
||||
}
|
||||
}
|
||||
@@ -56,10 +56,7 @@ public final class GameVersionList extends VersionList<GameRemoteVersionTag> {
|
||||
|
||||
GameRemoteVersions root = Constants.GSON.fromJson(task.getResult(), GameRemoteVersions.class);
|
||||
for (GameRemoteVersion remoteVersion : root.getVersions()) {
|
||||
Optional<String> gameVersion = VersionNumber.parseVersion(remoteVersion.getGameVersion());
|
||||
if (!gameVersion.isPresent())
|
||||
continue;
|
||||
versions.put(gameVersion.get(), new RemoteVersion<>(
|
||||
versions.put(remoteVersion.getGameVersion(), new RemoteVersionGame(
|
||||
remoteVersion.getGameVersion(),
|
||||
remoteVersion.getGameVersion(),
|
||||
remoteVersion.getUrl(),
|
||||
@@ -70,4 +67,14 @@ public final class GameVersionList extends VersionList<GameRemoteVersionTag> {
|
||||
};
|
||||
}
|
||||
|
||||
private static class RemoteVersionGame extends RemoteVersion<GameRemoteVersionTag> {
|
||||
public RemoteVersionGame(String gameVersion, String selfVersion, String url, GameRemoteVersionTag tag) {
|
||||
super(gameVersion, selfVersion, url, tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(RemoteVersion<GameRemoteVersionTag> o) {
|
||||
return -getTag().getTime().compareTo(o.getTag().getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package org.jackhuang.hmcl.mod;
|
||||
|
||||
import org.jackhuang.hmcl.util.FileUtils;
|
||||
import org.jackhuang.hmcl.util.ImmediateBooleanProperty;
|
||||
import org.jackhuang.hmcl.util.Logging;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
@@ -59,11 +60,16 @@ public final class ModInfo implements Comparable<ModInfo> {
|
||||
activeProperty = new ImmediateBooleanProperty(this, "active", !DISABLED_EXTENSION.equals(FileUtils.getExtension(file))) {
|
||||
@Override
|
||||
protected void invalidated() {
|
||||
File f = file.getAbsoluteFile(), newF;
|
||||
File f = ModInfo.this.file.getAbsoluteFile(), newF;
|
||||
if (DISABLED_EXTENSION.equals(FileUtils.getExtension(f)))
|
||||
newF = new File(f.getParentFile(), FileUtils.getNameWithoutExtension(f));
|
||||
else
|
||||
newF = new File(f.getParentFile(), f.getName() + ".disabled");
|
||||
|
||||
if (f.renameTo(newF))
|
||||
ModInfo.this.file = newF;
|
||||
else
|
||||
Logging.LOG.severe("Unable to rename file " + f + " to " + newF);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <[email protected]>
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.task;
|
||||
|
||||
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||
|
||||
public interface FinalizedCallback {
|
||||
void execute(AutoTypingMap<String> variables, boolean isDependentsSucceeded) throws Exception;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <[email protected]>
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.task;
|
||||
|
||||
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||
import org.jackhuang.hmcl.util.ExceptionalFunction;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A task that combines two tasks and make sure [pred] runs before succ.
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
final class FinalizedTask extends Task {
|
||||
|
||||
private final Collection<Task> dependents;
|
||||
private final FinalizedCallback callback;
|
||||
private final Scheduler scheduler;
|
||||
|
||||
/**
|
||||
* A task that combines two tasks and make sure pred runs before succ.
|
||||
*
|
||||
* @param pred the task that runs before succ.
|
||||
* @param callback a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred.
|
||||
*/
|
||||
public FinalizedTask(Task pred, Scheduler scheduler, FinalizedCallback callback) {
|
||||
this.dependents = Collections.singleton(pred);
|
||||
this.scheduler = scheduler;
|
||||
this.callback = callback;
|
||||
|
||||
setSignificance(TaskSignificance.MODERATE);
|
||||
setName(callback.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scheduler getScheduler() {
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
setName(callback.toString());
|
||||
callback.execute(getVariables(), isDependentsSucceeded());
|
||||
|
||||
if (!isDependentsSucceeded())
|
||||
throw new SilentException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task> getDependents() {
|
||||
return dependents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRelyingOnDependents() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,12 +260,12 @@ public abstract class Task {
|
||||
return new CoupleTask<>(this, b, false, false);
|
||||
}
|
||||
|
||||
public final Task finalized(Task b) {
|
||||
return finalized(convert(b));
|
||||
public final Task finalized(FinalizedCallback b) {
|
||||
return finalized(Schedulers.defaultScheduler(), b);
|
||||
}
|
||||
|
||||
public final Task finalized(ExceptionalFunction<AutoTypingMap<String>, Task, ?> b) {
|
||||
return new CoupleTask<>(this, b, false, true);
|
||||
public final Task finalized(Scheduler scheduler, FinalizedCallback b) {
|
||||
return new FinalizedTask(this, scheduler, b);
|
||||
}
|
||||
|
||||
public static Task empty() {
|
||||
|
||||
Reference in new issue
Block a user