@@ -19,6 +19,7 @@ package org.jackhuang.hmcl.ui;
|
|||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import com.jfoenix.controls.JFXDialogLayout;
|
import com.jfoenix.controls.JFXDialogLayout;
|
||||||
|
import com.jfoenix.validation.base.ValidatorBase;
|
||||||
import javafx.animation.KeyFrame;
|
import javafx.animation.KeyFrame;
|
||||||
import javafx.animation.KeyValue;
|
import javafx.animation.KeyValue;
|
||||||
import javafx.animation.Timeline;
|
import javafx.animation.Timeline;
|
||||||
@@ -72,9 +73,10 @@ import java.nio.file.Path;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.setting.ConfigHolder.*;
|
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
import static org.jackhuang.hmcl.setting.ConfigHolder.globalConfig;
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||||
|
|
||||||
public final class Controllers {
|
public final class Controllers {
|
||||||
public static final String JAVA_VERSION_TIP = "javaVersion";
|
public static final String JAVA_VERSION_TIP = "javaVersion";
|
||||||
@@ -505,8 +507,8 @@ public final class Controllers {
|
|||||||
return prompt(title, onResult, "");
|
return prompt(title, onResult, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompletableFuture<String> prompt(String title, FutureCallback<String> onResult, String initialValue) {
|
public static CompletableFuture<String> prompt(String title, FutureCallback<String> onResult, String initialValue, ValidatorBase... validators) {
|
||||||
InputDialogPane pane = new InputDialogPane(title, initialValue, onResult);
|
InputDialogPane pane = new InputDialogPane(title, initialValue, onResult, validators);
|
||||||
dialog(pane);
|
dialog(pane);
|
||||||
return pane.getCompletableFuture();
|
return pane.getCompletableFuture();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,11 +25,10 @@ import javafx.scene.layout.*;
|
|||||||
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
|
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
|
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
|
||||||
import org.jackhuang.hmcl.ui.animation.TransitionPane;
|
import org.jackhuang.hmcl.ui.animation.TransitionPane;
|
||||||
import org.jackhuang.hmcl.ui.construct.DialogAware;
|
import org.jackhuang.hmcl.ui.construct.*;
|
||||||
import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
|
|
||||||
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
|
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
|
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
@@ -88,6 +87,10 @@ public final class AddAuthlibInjectorServerPane extends TransitionPane implement
|
|||||||
|
|
||||||
addServerPane.setBody(txtServerUrl);
|
addServerPane.setBody(txtServerUrl);
|
||||||
addServerPane.setActions(lblCreationWarning, actions);
|
addServerPane.setActions(lblCreationWarning, actions);
|
||||||
|
|
||||||
|
txtServerUrl.getValidators().addAll(new RequiredValidator(), new URLValidator());
|
||||||
|
FXUtils.setValidateWhileTextChanged(txtServerUrl, true);
|
||||||
|
btnAddNext.disableProperty().bind(txtServerUrl.activeValidatorProperty().isNotNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
confirmServerPane = new JFXDialogLayout();
|
confirmServerPane = new JFXDialogLayout();
|
||||||
@@ -149,7 +152,6 @@ public final class AddAuthlibInjectorServerPane extends TransitionPane implement
|
|||||||
this.setContent(addServerPane, ContainerAnimations.NONE);
|
this.setContent(addServerPane, ContainerAnimations.NONE);
|
||||||
|
|
||||||
lblCreationWarning.maxWidthProperty().bind(((FlowPane) lblCreationWarning.getParent()).widthProperty());
|
lblCreationWarning.maxWidthProperty().bind(((FlowPane) lblCreationWarning.getParent()).widthProperty());
|
||||||
btnAddNext.disableProperty().bind(txtServerUrl.textProperty().isEmpty());
|
|
||||||
nextPane.hideSpinner();
|
nextPane.hideSpinner();
|
||||||
|
|
||||||
onEscPressed(this, this::onAddCancel);
|
onEscPressed(this, this::onAddCancel);
|
||||||
|
|||||||
@@ -20,9 +20,11 @@ package org.jackhuang.hmcl.ui.construct;
|
|||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import com.jfoenix.controls.JFXDialogLayout;
|
import com.jfoenix.controls.JFXDialogLayout;
|
||||||
import com.jfoenix.controls.JFXTextField;
|
import com.jfoenix.controls.JFXTextField;
|
||||||
|
import com.jfoenix.validation.base.ValidatorBase;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.util.FutureCallback;
|
import org.jackhuang.hmcl.util.FutureCallback;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@@ -36,6 +38,16 @@ public class InputDialogPane extends JFXDialogLayout implements DialogAware {
|
|||||||
private final JFXTextField textField;
|
private final JFXTextField textField;
|
||||||
private final Label lblCreationWarning;
|
private final Label lblCreationWarning;
|
||||||
private final SpinnerPane acceptPane;
|
private final SpinnerPane acceptPane;
|
||||||
|
private final JFXButton acceptButton;
|
||||||
|
|
||||||
|
public InputDialogPane(String text, String initialValue, FutureCallback<String> onResult, ValidatorBase... validators) {
|
||||||
|
this(text, initialValue, onResult);
|
||||||
|
if (validators != null && validators.length > 0) {
|
||||||
|
textField.getValidators().addAll(validators);
|
||||||
|
FXUtils.setValidateWhileTextChanged(textField, true);
|
||||||
|
acceptButton.disableProperty().bind(textField.activeValidatorProperty().isNotNull());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public InputDialogPane(String text, String initialValue, FutureCallback<String> onResult) {
|
public InputDialogPane(String text, String initialValue, FutureCallback<String> onResult) {
|
||||||
textField = new JFXTextField(initialValue);
|
textField = new JFXTextField(initialValue);
|
||||||
@@ -47,7 +59,7 @@ public class InputDialogPane extends JFXDialogLayout implements DialogAware {
|
|||||||
|
|
||||||
acceptPane = new SpinnerPane();
|
acceptPane = new SpinnerPane();
|
||||||
acceptPane.getStyleClass().add("small-spinner-pane");
|
acceptPane.getStyleClass().add("small-spinner-pane");
|
||||||
JFXButton acceptButton = new JFXButton(i18n("button.ok"));
|
acceptButton = new JFXButton(i18n("button.ok"));
|
||||||
acceptButton.getStyleClass().add("dialog-accept");
|
acceptButton.getStyleClass().add("dialog-accept");
|
||||||
acceptPane.setContent(acceptButton);
|
acceptPane.setContent(acceptButton);
|
||||||
|
|
||||||
@@ -69,7 +81,6 @@ public class InputDialogPane extends JFXDialogLayout implements DialogAware {
|
|||||||
lblCreationWarning.setText(msg);
|
lblCreationWarning.setText(msg);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
textField.setOnAction(event -> acceptButton.fire());
|
textField.setOnAction(event -> acceptButton.fire());
|
||||||
onEscPressed(this, cancelButton::fire);
|
onEscPressed(this, cancelButton::fire);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import org.jackhuang.hmcl.ui.animation.TransitionPane;
|
|||||||
import org.jackhuang.hmcl.ui.construct.AdvancedListBox;
|
import org.jackhuang.hmcl.ui.construct.AdvancedListBox;
|
||||||
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
|
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
|
||||||
import org.jackhuang.hmcl.ui.construct.TabHeader;
|
import org.jackhuang.hmcl.ui.construct.TabHeader;
|
||||||
|
import org.jackhuang.hmcl.ui.construct.Validator;
|
||||||
import org.jackhuang.hmcl.ui.decorator.DecoratorAnimatedPage;
|
import org.jackhuang.hmcl.ui.decorator.DecoratorAnimatedPage;
|
||||||
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
|
||||||
import org.jackhuang.hmcl.ui.versions.DownloadListPage;
|
import org.jackhuang.hmcl.ui.versions.DownloadListPage;
|
||||||
@@ -134,10 +135,6 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage
|
|||||||
Path runDirectory = profile.getRepository().hasVersion(version) ? profile.getRepository().getRunDirectory(version) : profile.getRepository().getBaseDirectory();
|
Path runDirectory = profile.getRepository().hasVersion(version) ? profile.getRepository().getRunDirectory(version) : profile.getRepository().getBaseDirectory();
|
||||||
|
|
||||||
Controllers.prompt(i18n("archive.file.name"), (result, resolve, reject) -> {
|
Controllers.prompt(i18n("archive.file.name"), (result, resolve, reject) -> {
|
||||||
if (!FileUtils.isNameValid(result)) {
|
|
||||||
reject.accept(i18n("install.new_game.malformed"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Path dest = runDirectory.resolve(subdirectoryName).resolve(result);
|
Path dest = runDirectory.resolve(subdirectoryName).resolve(result);
|
||||||
|
|
||||||
Controllers.taskDialog(Task.composeAsync(() -> {
|
Controllers.taskDialog(Task.composeAsync(() -> {
|
||||||
@@ -155,9 +152,8 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage
|
|||||||
Controllers.showToast(i18n("install.success"));
|
Controllers.showToast(i18n("install.success"));
|
||||||
}
|
}
|
||||||
}), i18n("message.downloading"), TaskCancellationAction.NORMAL);
|
}), i18n("message.downloading"), TaskCancellationAction.NORMAL);
|
||||||
|
|
||||||
resolve.run();
|
resolve.run();
|
||||||
}, file.getFile().getFilename());
|
}, file.getFile().getFilename(), new Validator(i18n("install.new_game.malformed"), FileUtils::isNameValid));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,11 +29,14 @@ import javafx.scene.shape.SVGPath;
|
|||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.jackhuang.hmcl.game.ModpackHelper;
|
import org.jackhuang.hmcl.game.ModpackHelper;
|
||||||
import org.jackhuang.hmcl.mod.server.ServerModpackManifest;
|
import org.jackhuang.hmcl.mod.server.ServerModpackManifest;
|
||||||
import org.jackhuang.hmcl.task.*;
|
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||||
|
import org.jackhuang.hmcl.task.GetTask;
|
||||||
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.SVG;
|
import org.jackhuang.hmcl.ui.SVG;
|
||||||
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
|
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
|
||||||
|
import org.jackhuang.hmcl.ui.construct.URLValidator;
|
||||||
import org.jackhuang.hmcl.ui.wizard.WizardController;
|
import org.jackhuang.hmcl.ui.wizard.WizardController;
|
||||||
import org.jackhuang.hmcl.ui.wizard.WizardPage;
|
import org.jackhuang.hmcl.ui.wizard.WizardPage;
|
||||||
import org.jackhuang.hmcl.util.SettingsMap;
|
import org.jackhuang.hmcl.util.SettingsMap;
|
||||||
@@ -161,7 +164,7 @@ public final class ModpackSelectionPage extends VBox implements WizardPage {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
reject.accept(e.getMessage());
|
reject.accept(e.getMessage());
|
||||||
}
|
}
|
||||||
});
|
}, "", new URLValidator());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onChooseRepository() {
|
public void onChooseRepository() {
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ import org.jackhuang.hmcl.download.game.GameAssetDownloadTask;
|
|||||||
import org.jackhuang.hmcl.game.*;
|
import org.jackhuang.hmcl.game.*;
|
||||||
import org.jackhuang.hmcl.mod.RemoteMod;
|
import org.jackhuang.hmcl.mod.RemoteMod;
|
||||||
import org.jackhuang.hmcl.setting.*;
|
import org.jackhuang.hmcl.setting.*;
|
||||||
import org.jackhuang.hmcl.task.*;
|
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||||
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
|
import org.jackhuang.hmcl.task.Task;
|
||||||
|
import org.jackhuang.hmcl.task.TaskExecutor;
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.account.CreateAccountPane;
|
import org.jackhuang.hmcl.ui.account.CreateAccountPane;
|
||||||
@@ -50,8 +53,8 @@ import java.util.concurrent.CancellationException;
|
|||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||||
|
|
||||||
public final class Versions {
|
public final class Versions {
|
||||||
private Versions() {
|
private Versions() {
|
||||||
@@ -124,10 +127,6 @@ public final class Versions {
|
|||||||
|
|
||||||
public static CompletableFuture<String> renameVersion(Profile profile, String version) {
|
public static CompletableFuture<String> renameVersion(Profile profile, String version) {
|
||||||
return Controllers.prompt(i18n("version.manage.rename.message"), (newName, resolve, reject) -> {
|
return Controllers.prompt(i18n("version.manage.rename.message"), (newName, resolve, reject) -> {
|
||||||
if (!HMCLGameRepository.isValidVersionId(newName)) {
|
|
||||||
reject.accept(i18n("install.new_game.malformed"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (profile.getRepository().renameVersion(version, newName)) {
|
if (profile.getRepository().renameVersion(version, newName)) {
|
||||||
resolve.run();
|
resolve.run();
|
||||||
profile.getRepository().refreshVersionsAsync()
|
profile.getRepository().refreshVersionsAsync()
|
||||||
@@ -139,7 +138,8 @@ public final class Versions {
|
|||||||
} else {
|
} else {
|
||||||
reject.accept(i18n("version.manage.rename.fail"));
|
reject.accept(i18n("version.manage.rename.fail"));
|
||||||
}
|
}
|
||||||
}, version);
|
}, version, new Validator(i18n("install.new_game.malformed"), HMCLGameRepository::isValidVersionId),
|
||||||
|
new Validator(i18n("install.new_game.already_exists"), newVersionName -> !profile.getRepository().versionIdConflicts(newVersionName)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void exportVersion(Profile profile, String version) {
|
public static void exportVersion(Profile profile, String version) {
|
||||||
@@ -155,10 +155,6 @@ public final class Versions {
|
|||||||
new PromptDialogPane.Builder(i18n("version.manage.duplicate.prompt"), (res, resolve, reject) -> {
|
new PromptDialogPane.Builder(i18n("version.manage.duplicate.prompt"), (res, resolve, reject) -> {
|
||||||
String newVersionName = ((PromptDialogPane.Builder.StringQuestion) res.get(1)).getValue();
|
String newVersionName = ((PromptDialogPane.Builder.StringQuestion) res.get(1)).getValue();
|
||||||
boolean copySaves = ((PromptDialogPane.Builder.BooleanQuestion) res.get(2)).getValue();
|
boolean copySaves = ((PromptDialogPane.Builder.BooleanQuestion) res.get(2)).getValue();
|
||||||
if (!HMCLGameRepository.isValidVersionId(newVersionName)) {
|
|
||||||
reject.accept(i18n("install.new_game.malformed"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Task.runAsync(() -> profile.getRepository().duplicateVersion(version, newVersionName, copySaves))
|
Task.runAsync(() -> profile.getRepository().duplicateVersion(version, newVersionName, copySaves))
|
||||||
.thenComposeAsync(profile.getRepository().refreshVersionsAsync())
|
.thenComposeAsync(profile.getRepository().refreshVersionsAsync())
|
||||||
.whenComplete(Schedulers.javafx(), (result, exception) -> {
|
.whenComplete(Schedulers.javafx(), (result, exception) -> {
|
||||||
@@ -174,6 +170,7 @@ public final class Versions {
|
|||||||
})
|
})
|
||||||
.addQuestion(new PromptDialogPane.Builder.HintQuestion(i18n("version.manage.duplicate.confirm")))
|
.addQuestion(new PromptDialogPane.Builder.HintQuestion(i18n("version.manage.duplicate.confirm")))
|
||||||
.addQuestion(new PromptDialogPane.Builder.StringQuestion(null, version,
|
.addQuestion(new PromptDialogPane.Builder.StringQuestion(null, version,
|
||||||
|
new Validator(i18n("install.new_game.malformed"), HMCLGameRepository::isValidVersionId),
|
||||||
new Validator(i18n("install.new_game.already_exists"), newVersionName -> !profile.getRepository().versionIdConflicts(newVersionName))))
|
new Validator(i18n("install.new_game.already_exists"), newVersionName -> !profile.getRepository().versionIdConflicts(newVersionName))))
|
||||||
.addQuestion(new PromptDialogPane.Builder.BooleanQuestion(i18n("version.manage.duplicate.duplicate_save"), false)));
|
.addQuestion(new PromptDialogPane.Builder.BooleanQuestion(i18n("version.manage.duplicate.duplicate_save"), false)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.jackhuang.hmcl.setting.Profile;
|
|||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.ui.*;
|
import org.jackhuang.hmcl.ui.*;
|
||||||
|
import org.jackhuang.hmcl.ui.construct.Validator;
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
|
import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
|
||||||
|
|
||||||
@@ -141,7 +142,7 @@ public final class WorldListPage extends ListPageBase<WorldListItem> implements
|
|||||||
else
|
else
|
||||||
reject.accept(i18n("world.import.failed", e.getClass().getName() + ": " + e.getLocalizedMessage()));
|
reject.accept(i18n("world.import.failed", e.getClass().getName() + ": " + e.getLocalizedMessage()));
|
||||||
}).start();
|
}).start();
|
||||||
}, world.getWorldName());
|
}, world.getWorldName(), new Validator(i18n("install.new_game.malformed"), FileUtils::isNameValid));
|
||||||
}, e -> {
|
}, e -> {
|
||||||
LOG.warning("Unable to parse world file " + zipFile, e);
|
LOG.warning("Unable to parse world file " + zipFile, e);
|
||||||
Controllers.dialog(i18n("world.import.invalid"));
|
Controllers.dialog(i18n("world.import.invalid"));
|
||||||
|
|||||||
Reference in New Issue
Block a user