From 66524613b44728ecd15afbc479d5b6c03a630c63 Mon Sep 17 00:00:00 2001 From: Glavo Date: Thu, 18 Sep 2025 16:58:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=BB=A5=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E7=9A=84=E6=96=B9=E5=BC=8F=E8=AF=BB=E5=86=99?= =?UTF-8?q?=20Navigation#getSettings()=20(#4504)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../decorator/DecoratorWizardDisplayer.java | 4 +- .../ui/download/AbstractInstallersPage.java | 7 +- .../ui/download/AdditionalInstallersPage.java | 4 +- .../hmcl/ui/download/DownloadPage.java | 29 +++--- .../hmcl/ui/download/InstallersPage.java | 5 +- .../hmcl/ui/download/LocalModpackPage.java | 34 ++++--- .../ModpackInstallWizardProvider.java | 44 ++++----- .../hmcl/ui/download/ModpackPage.java | 4 + .../ui/download/ModpackSelectionPage.java | 14 ++- .../hmcl/ui/download/RemoteModpackPage.java | 26 +++--- .../UpdateInstallerWizardProvider.java | 19 ++-- .../VanillaInstallWizardProvider.java | 24 +++-- .../hmcl/ui/download/VersionsPage.java | 4 +- .../hmcl/ui/export/ExportWizardProvider.java | 16 ++-- .../ui/export/ModpackFileSelectionPage.java | 5 +- .../hmcl/ui/export/ModpackInfoPage.java | 23 ++--- .../ui/export/ModpackTypeSelectionPage.java | 7 +- .../ui/wizard/AbstractWizardDisplayer.java | 4 +- .../jackhuang/hmcl/ui/wizard/Navigation.java | 5 +- .../ui/wizard/SinglePageWizardProvider.java | 8 +- .../TaskExecutorDialogWizardDisplayer.java | 24 ++--- .../hmcl/ui/wizard/WizardController.java | 5 +- .../hmcl/ui/wizard/WizardDisplayer.java | 5 +- .../jackhuang/hmcl/ui/wizard/WizardPage.java | 6 +- .../hmcl/ui/wizard/WizardProvider.java | 13 +-- .../hmcl/ui/wizard/WizardSinglePage.java | 5 +- .../org/jackhuang/hmcl/util/SettingsMap.java | 89 +++++++++++++++++++ 27 files changed, 256 insertions(+), 177 deletions(-) create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/util/SettingsMap.java diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorWizardDisplayer.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorWizardDisplayer.java index e6a6b5b99..ff5edc34f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorWizardDisplayer.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorWizardDisplayer.java @@ -23,8 +23,8 @@ import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.ui.construct.Navigator; import org.jackhuang.hmcl.ui.construct.PageCloseEvent; import org.jackhuang.hmcl.ui.wizard.*; +import org.jackhuang.hmcl.util.SettingsMap; -import java.util.Map; import java.util.concurrent.ConcurrentLinkedQueue; public class DecoratorWizardDisplayer extends DecoratorTransitionPage implements WizardDisplayer { @@ -94,7 +94,7 @@ public class DecoratorWizardDisplayer extends DecoratorTransitionPage implements } @Override - public void handleTask(Map settings, Task task) { + public void handleTask(SettingsMap settings, Task task) { displayer.handleTask(settings, task); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/AbstractInstallersPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/AbstractInstallersPage.java index 79183b9c0..33b1987cf 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/AbstractInstallersPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/AbstractInstallersPage.java @@ -35,8 +35,7 @@ import org.jackhuang.hmcl.ui.InstallerItem; import org.jackhuang.hmcl.ui.construct.MessageDialogPane; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardPage; - -import java.util.Map; +import org.jackhuang.hmcl.util.SettingsMap; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -80,12 +79,12 @@ public abstract class AbstractInstallersPage extends Control implements WizardPa protected abstract void reload(); @Override - public void onNavigate(Map settings) { + public void onNavigate(SettingsMap settings) { reload(); } @Override - public abstract void cleanup(Map settings); + public abstract void cleanup(SettingsMap settings); protected abstract void onInstall(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/AdditionalInstallersPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/AdditionalInstallersPage.java index c20313f7a..7464556d7 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/AdditionalInstallersPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/AdditionalInstallersPage.java @@ -29,8 +29,8 @@ import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.ui.InstallerItem; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.util.Lang; +import org.jackhuang.hmcl.util.SettingsMap; -import java.util.Map; import java.util.Optional; import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.MINECRAFT; @@ -109,6 +109,6 @@ class AdditionalInstallersPage extends AbstractInstallersPage { } @Override - public void cleanup(Map settings) { + public void cleanup(SettingsMap settings) { } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java index 3ea1e84c3..e70a19130 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java @@ -51,14 +51,13 @@ import org.jackhuang.hmcl.ui.versions.Versions; import org.jackhuang.hmcl.ui.wizard.Navigation; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardProvider; +import org.jackhuang.hmcl.util.SettingsMap; import org.jackhuang.hmcl.util.TaskCancellationAction; import org.jackhuang.hmcl.util.io.FileUtils; import org.jetbrains.annotations.Nullable; import java.nio.file.Path; -import java.util.HashMap; import java.util.Locale; -import java.util.Map; import java.util.concurrent.CancellationException; import java.util.function.Supplier; @@ -223,7 +222,7 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage } private static final class DownloadNavigator implements Navigation { - private final Map settings = new HashMap<>(); + private final SettingsMap settings = new SettingsMap(); @Override public void onStart() { @@ -260,7 +259,7 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage } @Override - public Map getSettings() { + public SettingsMap getSettings() { return settings; } @@ -287,37 +286,39 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage } @Override - public void start(Map settings) { - settings.put(PROFILE, profile); + public void start(SettingsMap settings) { + settings.put(ModpackPage.PROFILE, profile); settings.put(LibraryAnalyzer.LibraryType.MINECRAFT.getPatchId(), gameVersion); } - private Task finishVersionDownloadingAsync(Map settings) { + private Task finishVersionDownloadingAsync(SettingsMap settings) { GameBuilder builder = dependencyManager.gameBuilder(); String name = (String) settings.get("name"); builder.name(name); builder.gameVersion(((RemoteVersion) settings.get(LibraryAnalyzer.LibraryType.MINECRAFT.getPatchId())).getGameVersion()); - for (Map.Entry entry : settings.entrySet()) - if (!LibraryAnalyzer.LibraryType.MINECRAFT.getPatchId().equals(entry.getKey()) && entry.getValue() instanceof RemoteVersion) - builder.version((RemoteVersion) entry.getValue()); + settings.asStringMap().forEach((key, value) -> { + if (!LibraryAnalyzer.LibraryType.MINECRAFT.getPatchId().equals(key) + && value instanceof RemoteVersion remoteVersion) + builder.version(remoteVersion); + }); return builder.buildAsync().whenComplete(any -> profile.getRepository().refreshVersions()) .thenRunAsync(Schedulers.javafx(), () -> profile.setSelectedVersion(name)); } @Override - public Object finish(Map settings) { + public Object finish(SettingsMap settings) { settings.put("title", i18n("install.new_game.installation")); settings.put("success_message", i18n("install.success")); - settings.put("failure_callback", (FailureCallback) (settings1, exception, next) -> UpdateInstallerWizardProvider.alertFailureMessage(exception, next)); + settings.put(FailureCallback.KEY, (settings1, exception, next) -> UpdateInstallerWizardProvider.alertFailureMessage(exception, next)); return finishVersionDownloadingAsync(settings); } @Override - public Node createPage(WizardController controller, int step, Map settings) { + public Node createPage(WizardController controller, int step, SettingsMap settings) { switch (step) { case 0: return new InstallersPage(controller, profile.getRepository(), ((RemoteVersion) controller.getSettings().get("game")).getGameVersion(), downloadProvider); @@ -330,7 +331,5 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage public boolean cancel() { return true; } - - public static final String PROFILE = "PROFILE"; } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallersPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallersPage.java index 8dad9704d..346c4a0df 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallersPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/InstallersPage.java @@ -27,8 +27,7 @@ import org.jackhuang.hmcl.ui.construct.MessageDialogPane; import org.jackhuang.hmcl.ui.construct.RequiredValidator; import org.jackhuang.hmcl.ui.construct.Validator; import org.jackhuang.hmcl.ui.wizard.WizardController; - -import java.util.Map; +import org.jackhuang.hmcl.util.SettingsMap; import static javafx.beans.binding.Bindings.createBooleanBinding; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -73,7 +72,7 @@ public class InstallersPage extends AbstractInstallersPage { } @Override - public void cleanup(Map settings) { + public void cleanup(SettingsMap settings) { } private static boolean checkName(String name) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/LocalModpackPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/LocalModpackPage.java index ee684ba1b..ad99b108e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/LocalModpackPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/LocalModpackPage.java @@ -36,16 +36,14 @@ import org.jackhuang.hmcl.ui.construct.MessageDialogPane; import org.jackhuang.hmcl.ui.construct.RequiredValidator; import org.jackhuang.hmcl.ui.construct.Validator; import org.jackhuang.hmcl.ui.wizard.WizardController; +import org.jackhuang.hmcl.util.SettingsMap; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.io.CompressingUtils; import org.jackhuang.hmcl.util.io.FileUtils; import java.nio.charset.Charset; import java.nio.file.Path; -import java.util.Map; -import java.util.Optional; -import static org.jackhuang.hmcl.util.Lang.tryCast; import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -58,11 +56,11 @@ public final class LocalModpackPage extends ModpackPage { public LocalModpackPage(WizardController controller) { super(controller); - Profile profile = (Profile) controller.getSettings().get("PROFILE"); + Profile profile = controller.getSettings().get(ModpackPage.PROFILE); - Optional name = tryCast(controller.getSettings().get(MODPACK_NAME), String.class); - if (name.isPresent()) { - txtModpackName.setText(name.get()); + String name = controller.getSettings().get(MODPACK_NAME); + if (name != null) { + txtModpackName.setText(name); txtModpackName.setDisable(true); } else { FXUtils.onChangeAndOperate(installAsVersion, installAsVersion -> { @@ -83,9 +81,9 @@ public final class LocalModpackPage extends ModpackPage { btnDescription.setVisible(false); Path selectedFile; - Optional filePath = tryCast(controller.getSettings().get(MODPACK_FILE), Path.class); - if (filePath.isPresent()) { - selectedFile = filePath.get(); + Path filePath = controller.getSettings().get(MODPACK_FILE); + if (filePath != null) { + selectedFile = filePath; } else { FileChooser chooser = new FileChooser(); chooser.setTitle(i18n("modpack.choose")); @@ -112,7 +110,7 @@ public final class LocalModpackPage extends ModpackPage { lblName.setText(FileUtils.getName(selectedFile)); installAsVersion.set(false); - if (name.isEmpty()) { + if (name == null) { // trim: https://github.com/HMCL-dev/HMCL/issues/962 txtModpackName.setText(FileUtils.getNameWithoutExtension(selectedFile)); } @@ -133,7 +131,7 @@ public final class LocalModpackPage extends ModpackPage { lblVersion.setText(manifest.getVersion()); lblAuthor.setText(manifest.getAuthor()); - if (name.isEmpty()) { + if (name == null) { // trim: https://github.com/HMCL-dev/HMCL/issues/962 txtModpackName.setText(manifest.getName().trim()); } @@ -144,7 +142,7 @@ public final class LocalModpackPage extends ModpackPage { } @Override - public void cleanup(Map settings) { + public void cleanup(SettingsMap settings) { settings.remove(MODPACK_FILE); } @@ -177,9 +175,9 @@ public final class LocalModpackPage extends ModpackPage { Controllers.navigate(new WebPage(i18n("modpack.description"), manifest.getDescription())); } - public static final String MODPACK_FILE = "MODPACK_FILE"; - public static final String MODPACK_NAME = "MODPACK_NAME"; - public static final String MODPACK_MANIFEST = "MODPACK_MANIFEST"; - public static final String MODPACK_CHARSET = "MODPACK_CHARSET"; - public static final String MODPACK_MANUALLY_CREATED = "MODPACK_MANUALLY_CREATED"; + public static final SettingsMap.Key MODPACK_FILE = new SettingsMap.Key<>("MODPACK_FILE"); + public static final SettingsMap.Key MODPACK_NAME = new SettingsMap.Key<>("MODPACK_NAME"); + public static final SettingsMap.Key MODPACK_MANIFEST = new SettingsMap.Key<>("MODPACK_MANIFEST"); + public static final SettingsMap.Key MODPACK_CHARSET = new SettingsMap.Key<>("MODPACK_CHARSET"); + public static final SettingsMap.Key MODPACK_MANUALLY_CREATED = new SettingsMap.Key<>("MODPACK_MANUALLY_CREATED"); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java index a7d9874d4..c9790bc7a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackInstallWizardProvider.java @@ -32,14 +32,13 @@ import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardProvider; +import org.jackhuang.hmcl.util.SettingsMap; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Path; -import java.util.Map; -import static org.jackhuang.hmcl.util.Lang.tryCast; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public final class ModpackInstallWizardProvider implements WizardProvider { @@ -66,21 +65,21 @@ public final class ModpackInstallWizardProvider implements WizardProvider { } @Override - public void start(Map settings) { + public void start(SettingsMap settings) { if (file != null) settings.put(LocalModpackPage.MODPACK_FILE, file); if (updateVersion != null) settings.put(LocalModpackPage.MODPACK_NAME, updateVersion); - settings.put(PROFILE, profile); + settings.put(ModpackPage.PROFILE, profile); } - private Task finishModpackInstallingAsync(Map settings) { - Path selected = tryCast(settings.get(LocalModpackPage.MODPACK_FILE), Path.class).orElse(null); - ServerModpackManifest serverModpackManifest = tryCast(settings.get(RemoteModpackPage.MODPACK_SERVER_MANIFEST), ServerModpackManifest.class).orElse(null); - Modpack modpack = tryCast(settings.get(LocalModpackPage.MODPACK_MANIFEST), Modpack.class).orElse(null); - String name = tryCast(settings.get(LocalModpackPage.MODPACK_NAME), String.class).orElse(null); - Charset charset = tryCast(settings.get(LocalModpackPage.MODPACK_CHARSET), Charset.class).orElse(null); - boolean isManuallyCreated = tryCast(settings.get(LocalModpackPage.MODPACK_MANUALLY_CREATED), Boolean.class).orElse(false); + private Task finishModpackInstallingAsync(SettingsMap settings) { + Path selected = settings.get(LocalModpackPage.MODPACK_FILE); + ServerModpackManifest serverModpackManifest = settings.get(RemoteModpackPage.MODPACK_SERVER_MANIFEST); + Modpack modpack = settings.get(LocalModpackPage.MODPACK_MANIFEST); + String name = settings.get(LocalModpackPage.MODPACK_NAME); + Charset charset = settings.get(LocalModpackPage.MODPACK_CHARSET); + boolean isManuallyCreated = settings.getOrDefault(LocalModpackPage.MODPACK_MANUALLY_CREATED, false); if (isManuallyCreated) { return ModpackHelper.getInstallManuallyCreatedModpackTask(profile, selected, name, charset); @@ -119,21 +118,18 @@ public final class ModpackInstallWizardProvider implements WizardProvider { } @Override - public Object finish(Map settings) { + public Object finish(SettingsMap settings) { settings.put("title", i18n("install.modpack.installation")); settings.put("success_message", i18n("install.success")); - settings.put("failure_callback", new FailureCallback() { - @Override - public void onFail(Map settings, Exception exception, Runnable next) { - if (exception instanceof ModpackCompletionException) { - if (exception.getCause() instanceof FileNotFoundException) { - Controllers.dialog(i18n("modpack.type.curse.not_found"), i18n("install.failed"), MessageType.ERROR, next); - } else { - Controllers.dialog(i18n("install.success"), i18n("install.success"), MessageType.SUCCESS, next); - } + settings.put(FailureCallback.KEY, (ignored, exception, next) -> { + if (exception instanceof ModpackCompletionException) { + if (exception.getCause() instanceof FileNotFoundException) { + Controllers.dialog(i18n("modpack.type.curse.not_found"), i18n("install.failed"), MessageType.ERROR, next); } else { - UpdateInstallerWizardProvider.alertFailureMessage(exception, next); + Controllers.dialog(i18n("install.success"), i18n("install.success"), MessageType.SUCCESS, next); } + } else { + UpdateInstallerWizardProvider.alertFailureMessage(exception, next); } }); @@ -141,7 +137,7 @@ public final class ModpackInstallWizardProvider implements WizardProvider { } @Override - public Node createPage(WizardController controller, int step, Map settings) { + public Node createPage(WizardController controller, int step, SettingsMap settings) { switch (step) { case 0: return new ModpackSelectionPage(controller); @@ -161,6 +157,4 @@ public final class ModpackInstallWizardProvider implements WizardProvider { public boolean cancel() { return true; } - - public static final String PROFILE = "PROFILE"; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackPage.java index 107429813..c69db9f6c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackPage.java @@ -7,16 +7,20 @@ import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.layout.BorderPane; import javafx.scene.layout.VBox; +import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.construct.ComponentList; import org.jackhuang.hmcl.ui.construct.SpinnerPane; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardPage; +import org.jackhuang.hmcl.util.SettingsMap; import static javafx.beans.binding.Bindings.createBooleanBinding; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public abstract class ModpackPage extends SpinnerPane implements WizardPage { + public static final SettingsMap.Key PROFILE = new SettingsMap.Key<>("PROFILE"); + protected final WizardController controller; protected final Label lblName; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackSelectionPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackSelectionPage.java index 433260393..5a9d22a50 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackSelectionPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackSelectionPage.java @@ -36,6 +36,7 @@ import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardPage; +import org.jackhuang.hmcl.util.SettingsMap; import org.jackhuang.hmcl.util.TaskCancellationAction; import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.FileUtils; @@ -43,13 +44,10 @@ import org.jackhuang.hmcl.util.io.FileUtils; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Map; -import java.util.Optional; import static org.jackhuang.hmcl.ui.download.LocalModpackPage.MODPACK_FILE; import static org.jackhuang.hmcl.ui.download.LocalModpackPage.MODPACK_NAME; import static org.jackhuang.hmcl.ui.download.RemoteModpackPage.MODPACK_SERVER_MANIFEST; -import static org.jackhuang.hmcl.util.Lang.tryCast; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public final class ModpackSelectionPage extends VBox implements WizardPage { @@ -71,9 +69,9 @@ public final class ModpackSelectionPage extends VBox implements WizardPage { createButton("repository", this::onChooseRepository) ); - Optional filePath = tryCast(controller.getSettings().get(MODPACK_FILE), Path.class); - if (filePath.isPresent()) { - controller.getSettings().put(MODPACK_FILE, filePath.get()); + Path filePath = controller.getSettings().get(MODPACK_FILE); + if (filePath != null) { + controller.getSettings().put(MODPACK_FILE, filePath); Platform.runLater(controller::onNext); } @@ -167,14 +165,14 @@ public final class ModpackSelectionPage extends VBox implements WizardPage { } public void onChooseRepository() { - String modPackName = (String) controller.getSettings().get(MODPACK_NAME); + String modPackName = controller.getSettings().get(MODPACK_NAME); DownloadPage downloadPage = new DownloadPage(modPackName); downloadPage.showModpackDownloads(); Controllers.navigate(downloadPage); } @Override - public void cleanup(Map settings) { + public void cleanup(SettingsMap settings) { } @Override diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/RemoteModpackPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/RemoteModpackPage.java index 1123f3fd8..d1d078ec2 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/RemoteModpackPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/RemoteModpackPage.java @@ -19,6 +19,7 @@ package org.jackhuang.hmcl.ui.download; import javafx.application.Platform; import org.jackhuang.hmcl.game.HMCLGameRepository; +import org.jackhuang.hmcl.mod.Modpack; import org.jackhuang.hmcl.mod.server.ServerModpackManifest; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.ui.Controllers; @@ -27,13 +28,11 @@ import org.jackhuang.hmcl.ui.construct.MessageDialogPane; import org.jackhuang.hmcl.ui.construct.RequiredValidator; import org.jackhuang.hmcl.ui.construct.Validator; import org.jackhuang.hmcl.ui.wizard.WizardController; +import org.jackhuang.hmcl.util.SettingsMap; import org.jackhuang.hmcl.util.StringUtils; import java.io.IOException; -import java.util.Map; -import java.util.Optional; -import static org.jackhuang.hmcl.util.Lang.tryCast; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public final class RemoteModpackPage extends ModpackPage { @@ -42,8 +41,9 @@ public final class RemoteModpackPage extends ModpackPage { public RemoteModpackPage(WizardController controller) { super(controller); - manifest = tryCast(controller.getSettings().get(MODPACK_SERVER_MANIFEST), ServerModpackManifest.class) - .orElseThrow(() -> new IllegalStateException("MODPACK_SERVER_MANIFEST should exist")); + manifest = controller.getSettings().get(MODPACK_SERVER_MANIFEST); + if (manifest == null) + throw new IllegalStateException("MODPACK_SERVER_MANIFEST should exist"); try { controller.getSettings().put(MODPACK_MANIFEST, manifest.toModpack(null)); @@ -57,10 +57,10 @@ public final class RemoteModpackPage extends ModpackPage { lblVersion.setText(manifest.getVersion()); lblAuthor.setText(manifest.getAuthor()); - Profile profile = (Profile) controller.getSettings().get("PROFILE"); - Optional name = tryCast(controller.getSettings().get(MODPACK_NAME), String.class); - if (name.isPresent()) { - txtModpackName.setText(name.get()); + Profile profile = controller.getSettings().get(ModpackPage.PROFILE); + String name = controller.getSettings().get(MODPACK_NAME); + if (name != null) { + txtModpackName.setText(name); txtModpackName.setDisable(true); } else { // trim: https://github.com/HMCL-dev/HMCL/issues/962 @@ -75,7 +75,7 @@ public final class RemoteModpackPage extends ModpackPage { } @Override - public void cleanup(Map settings) { + public void cleanup(SettingsMap settings) { settings.remove(MODPACK_SERVER_MANIFEST); } @@ -89,7 +89,7 @@ public final class RemoteModpackPage extends ModpackPage { Controllers.navigate(new WebPage(i18n("modpack.description"), manifest.getDescription())); } - public static final String MODPACK_SERVER_MANIFEST = "MODPACK_SERVER_MANIFEST"; - public static final String MODPACK_NAME = "MODPACK_NAME"; - public static final String MODPACK_MANIFEST = "MODPACK_MANIFEST"; + public static final SettingsMap.Key MODPACK_SERVER_MANIFEST = new SettingsMap.Key<>("MODPACK_SERVER_MANIFEST"); + public static final SettingsMap.Key MODPACK_NAME = new SettingsMap.Key<>("MODPACK_NAME"); + public static final SettingsMap.Key MODPACK_MANIFEST = new SettingsMap.Key<>("MODPACK_MANIFEST"); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/UpdateInstallerWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/UpdateInstallerWizardProvider.java index 4695673b1..0b4f8dbf7 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/UpdateInstallerWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/UpdateInstallerWizardProvider.java @@ -30,6 +30,7 @@ import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.construct.MessageDialogPane; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardProvider; +import org.jackhuang.hmcl.util.SettingsMap; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.i18n.I18n; import org.jackhuang.hmcl.util.io.ResponseCodeException; @@ -40,7 +41,6 @@ import java.net.SocketTimeoutException; import java.net.URI; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.concurrent.CancellationException; import java.util.zip.ZipException; @@ -66,30 +66,29 @@ public final class UpdateInstallerWizardProvider implements WizardProvider { } @Override - public void start(Map settings) { + public void start(SettingsMap settings) { } @Override - public Object finish(Map settings) { + public Object finish(SettingsMap settings) { settings.put("title", i18n("install.change_version.process")); settings.put("success_message", i18n("install.success")); - settings.put("failure_callback", (FailureCallback) (settings1, exception, next) -> alertFailureMessage(exception, next)); + settings.put(FailureCallback.KEY, (settings1, exception, next) -> alertFailureMessage(exception, next)); // We remove library but not save it, // so if installation failed will not break down current version. Task ret = Task.supplyAsync(() -> version); List stages = new ArrayList<>(); - for (Object value : settings.values()) { - if (value instanceof RemoteVersion) { - RemoteVersion remoteVersion = (RemoteVersion) value; + for (Object value : settings.asStringMap().values()) { + if (value instanceof RemoteVersion remoteVersion) { ret = ret.thenComposeAsync(version -> dependencyManager.installLibraryAsync(version, remoteVersion)); stages.add(String.format("hmcl.install.%s:%s", remoteVersion.getLibraryId(), remoteVersion.getSelfVersion())); if ("game".equals(remoteVersion.getLibraryId())) { stages.add("hmcl.install.libraries"); stages.add("hmcl.install.assets"); } - } else if (value instanceof RemoveVersionAction) { - ret = ret.thenComposeAsync(version -> dependencyManager.removeLibraryAsync(version, ((RemoveVersionAction) value).libraryId)); + } else if (value instanceof RemoveVersionAction removeVersionAction) { + ret = ret.thenComposeAsync(version -> dependencyManager.removeLibraryAsync(version, removeVersionAction.libraryId)); } } @@ -97,7 +96,7 @@ public final class UpdateInstallerWizardProvider implements WizardProvider { } @Override - public Node createPage(WizardController controller, int step, Map settings) { + public Node createPage(WizardController controller, int step, SettingsMap settings) { switch (step) { case 0: return new VersionsPage(controller, i18n("install.installer.choose", i18n("install.installer." + libraryId)), gameVersion, downloadProvider, libraryId, () -> { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VanillaInstallWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VanillaInstallWizardProvider.java index fc9091360..03d26e872 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VanillaInstallWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VanillaInstallWizardProvider.java @@ -28,8 +28,7 @@ import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardProvider; - -import java.util.Map; +import org.jackhuang.hmcl.util.SettingsMap; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -45,36 +44,37 @@ public final class VanillaInstallWizardProvider implements WizardProvider { } @Override - public void start(Map settings) { - settings.put(PROFILE, profile); + public void start(SettingsMap settings) { + settings.put(ModpackPage.PROFILE, profile); } - private Task finishVersionDownloadingAsync(Map settings) { + private Task finishVersionDownloadingAsync(SettingsMap settings) { GameBuilder builder = dependencyManager.gameBuilder(); String name = (String) settings.get("name"); builder.name(name); builder.gameVersion(((RemoteVersion) settings.get("game")).getGameVersion()); - for (Map.Entry entry : settings.entrySet()) - if (!"game".equals(entry.getKey()) && entry.getValue() instanceof RemoteVersion) - builder.version((RemoteVersion) entry.getValue()); + settings.asStringMap().forEach((key, value) -> { + if (!"game".equals(key) && value instanceof RemoteVersion remoteVersion) + builder.version(remoteVersion); + }); return builder.buildAsync().whenComplete(any -> profile.getRepository().refreshVersions()) .thenRunAsync(Schedulers.javafx(), () -> profile.setSelectedVersion(name)); } @Override - public Object finish(Map settings) { + public Object finish(SettingsMap settings) { settings.put("title", i18n("install.new_game.installation")); settings.put("success_message", i18n("install.success")); - settings.put("failure_callback", (FailureCallback) (settings1, exception, next) -> UpdateInstallerWizardProvider.alertFailureMessage(exception, next)); + settings.put(FailureCallback.KEY, (settings1, exception, next) -> UpdateInstallerWizardProvider.alertFailureMessage(exception, next)); return finishVersionDownloadingAsync(settings); } @Override - public Node createPage(WizardController controller, int step, Map settings) { + public Node createPage(WizardController controller, int step, SettingsMap settings) { switch (step) { case 0: return new VersionsPage(controller, i18n("install.installer.choose", i18n("install.installer.game")), "", downloadProvider, "game", @@ -88,6 +88,4 @@ public final class VanillaInstallWizardProvider implements WizardProvider { public boolean cancel() { return true; } - - public static final String PROFILE = "PROFILE"; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java index 062edd697..ff5cabd19 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java @@ -54,12 +54,12 @@ import org.jackhuang.hmcl.ui.wizard.Navigation; import org.jackhuang.hmcl.ui.wizard.Refreshable; import org.jackhuang.hmcl.ui.wizard.WizardPage; import org.jackhuang.hmcl.util.Holder; +import org.jackhuang.hmcl.util.SettingsMap; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.i18n.I18n; import org.jackhuang.hmcl.util.versioning.GameVersionNumber; import java.util.Locale; -import java.util.Map; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -124,7 +124,7 @@ public final class VersionsPage extends Control implements WizardPage, Refreshab } @Override - public void cleanup(Map settings) { + public void cleanup(SettingsMap settings) { settings.remove(libraryId); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ExportWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ExportWizardProvider.java index e061c795f..cb7407ee9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ExportWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ExportWizardProvider.java @@ -35,6 +35,7 @@ import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardProvider; import org.jackhuang.hmcl.util.Lang; +import org.jackhuang.hmcl.util.SettingsMap; import org.jackhuang.hmcl.util.io.JarUtils; import org.jackhuang.hmcl.util.io.Zipper; @@ -54,17 +55,16 @@ public final class ExportWizardProvider implements WizardProvider { } @Override - public void start(Map settings) { + public void start(SettingsMap settings) { } @Override - public Object finish(Map settings) { - @SuppressWarnings("unchecked") - List whitelist = (List) settings.get(ModpackFileSelectionPage.MODPACK_FILE_SELECTION); - Path modpackFile = (Path) settings.get(ModpackInfoPage.MODPACK_FILE); - ModpackExportInfo exportInfo = (ModpackExportInfo) settings.get(ModpackInfoPage.MODPACK_INFO); + public Object finish(SettingsMap settings) { + List whitelist = settings.get(ModpackFileSelectionPage.MODPACK_FILE_SELECTION); + Path modpackFile = settings.get(ModpackInfoPage.MODPACK_FILE); + ModpackExportInfo exportInfo = settings.get(ModpackInfoPage.MODPACK_INFO); exportInfo.setWhitelist(whitelist); - String modpackType = (String) settings.get(ModpackTypeSelectionPage.MODPACK_TYPE); + String modpackType = settings.get(ModpackTypeSelectionPage.MODPACK_TYPE); return exportWithLauncher(modpackType, exportInfo, modpackFile); } @@ -278,7 +278,7 @@ public final class ExportWizardProvider implements WizardProvider { } @Override - public Node createPage(WizardController controller, int step, Map settings) { + public Node createPage(WizardController controller, int step, SettingsMap settings) { return switch (step) { case 0 -> new ModpackTypeSelectionPage(controller); case 1 -> new ModpackInfoPage(controller, profile.getRepository(), version); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackFileSelectionPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackFileSelectionPage.java index ddfed5bc3..17d639220 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackFileSelectionPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackFileSelectionPage.java @@ -33,6 +33,7 @@ import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.construct.NoneMultipleSelectionModel; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardPage; +import org.jackhuang.hmcl.util.SettingsMap; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.io.FileUtils; @@ -162,7 +163,7 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard } @Override - public void cleanup(Map settings) { + public void cleanup(SettingsMap settings) { controller.getSettings().remove(MODPACK_FILE_SELECTION); } @@ -178,7 +179,7 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard return i18n("modpack.wizard.step.2.title"); } - public static final String MODPACK_FILE_SELECTION = "modpack.accepted"; + public static final SettingsMap.Key> MODPACK_FILE_SELECTION = new SettingsMap.Key<>("modpack.accepted"); private static final Map TRANSLATION = mapOf( pair("minecraft/hmclversion.cfg", i18n("modpack.files.hmclversion_cfg")), pair("minecraft/servers.dat", i18n("modpack.files.servers_dat")), diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackInfoPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackInfoPage.java index c9e55fbd8..2cdaa1f53 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackInfoPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackInfoPage.java @@ -41,6 +41,7 @@ import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.construct.*; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardPage; +import org.jackhuang.hmcl.util.SettingsMap; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.JarUtils; @@ -57,7 +58,6 @@ import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE_MODRINTH; import static org.jackhuang.hmcl.ui.export.ModpackTypeSelectionPage.MODPACK_TYPE_SERVER; import static org.jackhuang.hmcl.util.DataSizeUnit.MEGABYTES; -import static org.jackhuang.hmcl.util.Lang.tryCast; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public final class ModpackInfoPage extends Control implements WizardPage { @@ -88,10 +88,12 @@ public final class ModpackInfoPage extends Control implements WizardPage { public ModpackInfoPage(WizardController controller, HMCLGameRepository gameRepository, String version) { this.controller = controller; this.gameRepository = gameRepository; - this.options = tryCast(controller.getSettings().get(MODPACK_INFO_OPTION), ModpackExportInfo.Options.class) - .orElseThrow(() -> new IllegalArgumentException("Settings.MODPACK_INFO_OPTION is required")); + this.options = controller.getSettings().get(MODPACK_INFO_OPTION); this.versionName = version; + if (this.options == null) + throw new IllegalArgumentException("Settings.MODPACK_INFO_OPTION is required"); + name.set(version); author.set(Optional.ofNullable(Accounts.getSelectedAccount()).map(Account::getUsername).orElse("")); @@ -111,7 +113,7 @@ public final class ModpackInfoPage extends Control implements WizardPage { fileChooser.setInitialFileName(name.get() + ".mrpack"); } else { fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.zip")); - fileChooser.setInitialFileName(name.get() + ".zip"); + fileChooser.setInitialFileName(name.get() + ".zip"); } Path file = FileUtils.toPath(fileChooser.showSaveDialog(Controllers.getStage())); if (file == null) { @@ -147,7 +149,7 @@ public final class ModpackInfoPage extends Control implements WizardPage { } @Override - public void cleanup(Map settings) { + public void cleanup(SettingsMap settings) { controller.getSettings().remove(MODPACK_INFO); } @@ -161,9 +163,9 @@ public final class ModpackInfoPage extends Control implements WizardPage { return new ModpackInfoPageSkin(this); } - public static final String MODPACK_INFO = "modpack.info"; - public static final String MODPACK_FILE = "modpack.file"; - public static final String MODPACK_INFO_OPTION = "modpack.info.option"; + public static final SettingsMap.Key MODPACK_INFO = new SettingsMap.Key<>("modpack.info"); + public static final SettingsMap.Key MODPACK_FILE = new SettingsMap.Key<>("modpack.file"); + public static final SettingsMap.Key MODPACK_INFO_OPTION = new SettingsMap.Key<>("modpack.info.option"); public static class ModpackInfoPageSkin extends SkinBase { private ObservableList originList; @@ -190,7 +192,8 @@ public final class ModpackInfoPage extends Control implements WizardPage { Hyperlink hyperlink = new Hyperlink(i18n("modpack.wizard.step.initialization.server")); hyperlink.setOnAction(e -> FXUtils.openLink(Metadata.DOCS_URL + "/modpack/serverpack.html")); borderPane.setTop(hyperlink); - } if (skinnable.controller.getSettings().get(MODPACK_TYPE) == MODPACK_TYPE_MODRINTH) { + } + if (skinnable.controller.getSettings().get(MODPACK_TYPE) == MODPACK_TYPE_MODRINTH) { HintPane pane = new HintPane(MessageDialogPane.MessageType.INFO); pane.setText(i18n("modpack.wizard.step.initialization.modrinth.info")); borderPane.setTop(pane); @@ -382,7 +385,7 @@ public final class ModpackInfoPage extends Control implements WizardPage { button.setMaxHeight(16); pane.setRight(button); } - + if (skinnable.options.isRequireNoCreateRemoteFiles()) { BorderPane noCreateRemoteFiles = new BorderPane(); noCreateRemoteFiles.setLeft(new Label(i18n("modpack.wizard.step.initialization.no_create_remote_files"))); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackTypeSelectionPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackTypeSelectionPage.java index 9b09b7772..62da3f0fc 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackTypeSelectionPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/export/ModpackTypeSelectionPage.java @@ -33,8 +33,7 @@ import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardPage; - -import java.util.Map; +import org.jackhuang.hmcl.util.SettingsMap; import static org.jackhuang.hmcl.ui.export.ModpackInfoPage.MODPACK_INFO_OPTION; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -89,7 +88,7 @@ public final class ModpackTypeSelectionPage extends VBox implements WizardPage { } @Override - public void cleanup(Map settings) { + public void cleanup(SettingsMap settings) { } @Override @@ -97,7 +96,7 @@ public final class ModpackTypeSelectionPage extends VBox implements WizardPage { return i18n("modpack.wizard.step.3.title"); } - public static final String MODPACK_TYPE = "modpack.type"; + public static final SettingsMap.Key MODPACK_TYPE = new SettingsMap.Key<>("modpack.type"); public static final String MODPACK_TYPE_MCBBS = "mcbbs"; public static final String MODPACK_TYPE_MULTIMC = "multimc"; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/AbstractWizardDisplayer.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/AbstractWizardDisplayer.java index c122cb0f1..eb7905df8 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/AbstractWizardDisplayer.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/AbstractWizardDisplayer.java @@ -22,8 +22,8 @@ import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.TaskExecutor; import org.jackhuang.hmcl.ui.construct.TaskListPane; +import org.jackhuang.hmcl.util.SettingsMap; -import java.util.Map; import java.util.Queue; public abstract class AbstractWizardDisplayer implements WizardDisplayer { @@ -34,7 +34,7 @@ public abstract class AbstractWizardDisplayer implements WizardDisplayer { } @Override - public void handleTask(Map settings, Task task) { + public void handleTask(SettingsMap settings, Task task) { TaskExecutor executor = task.withRunAsync(Schedulers.javafx(), this::navigateToSuccess).executor(); TaskListPane pane = new TaskListPane(); pane.setExecutor(executor); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Navigation.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Navigation.java index 8e02d88d7..a99f5aac0 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Navigation.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Navigation.java @@ -18,8 +18,7 @@ package org.jackhuang.hmcl.ui.wizard; import org.jackhuang.hmcl.ui.animation.ContainerAnimations; - -import java.util.Map; +import org.jackhuang.hmcl.util.SettingsMap; public interface Navigation { @@ -37,7 +36,7 @@ public interface Navigation { void onCancel(); - Map getSettings(); + SettingsMap getSettings(); enum NavigationDirection { START(ContainerAnimations.NONE), diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/SinglePageWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/SinglePageWizardProvider.java index d5b2da079..c30e41aff 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/SinglePageWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/SinglePageWizardProvider.java @@ -18,8 +18,8 @@ package org.jackhuang.hmcl.ui.wizard; import javafx.scene.Node; +import org.jackhuang.hmcl.util.SettingsMap; -import java.util.Map; import java.util.function.Function; public class SinglePageWizardProvider implements WizardProvider { @@ -32,16 +32,16 @@ public class SinglePageWizardProvider implements WizardProvider { } @Override - public void start(Map settings) { + public void start(SettingsMap settings) { } @Override - public Object finish(Map settings) { + public Object finish(SettingsMap settings) { return page.finish(); } @Override - public Node createPage(WizardController controller, int step, Map settings) { + public Node createPage(WizardController controller, int step, SettingsMap settings) { if (step != 0) throw new IllegalStateException("Step must be 0"); return page = provider.apply(controller); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/TaskExecutorDialogWizardDisplayer.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/TaskExecutorDialogWizardDisplayer.java index 6bfbb5418..cf5f128eb 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/TaskExecutorDialogWizardDisplayer.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/TaskExecutorDialogWizardDisplayer.java @@ -25,10 +25,10 @@ import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane; +import org.jackhuang.hmcl.util.SettingsMap; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.TaskCancellationAction; -import java.util.Map; import java.util.Queue; import java.util.concurrent.CancellationException; @@ -42,7 +42,7 @@ public abstract class TaskExecutorDialogWizardDisplayer extends AbstractWizardDi } @Override - public void handleTask(Map settings, Task task) { + public void handleTask(SettingsMap settings, Task task) { TaskExecutorDialogPane pane = new TaskExecutorDialogPane(new TaskCancellationAction(it -> { it.fireEvent(new DialogCloseEvent()); onEnd(); @@ -51,10 +51,10 @@ public abstract class TaskExecutorDialogWizardDisplayer extends AbstractWizardDi pane.setTitle(i18n("message.doing")); if (settings.containsKey("title")) { Object title = settings.get("title"); - if (title instanceof StringProperty) - pane.titleProperty().bind((StringProperty) title); - else if (title instanceof String) - pane.setTitle((String) title); + if (title instanceof StringProperty titleProperty) + pane.titleProperty().bind(titleProperty); + else if (title instanceof String titleMessage) + pane.setTitle(titleMessage); } runInFX(() -> { @@ -63,8 +63,8 @@ public abstract class TaskExecutorDialogWizardDisplayer extends AbstractWizardDi public void onStop(boolean success, TaskExecutor executor) { runInFX(() -> { if (success) { - if (settings.containsKey("success_message") && settings.get("success_message") instanceof String) - Controllers.dialog((String) settings.get("success_message"), null, MessageType.SUCCESS, () -> onEnd()); + if (settings.get("success_message") instanceof String successMessage) + Controllers.dialog(successMessage, null, MessageType.SUCCESS, () -> onEnd()); else if (!settings.containsKey("forbid_success_message")) Controllers.dialog(i18n("message.success"), null, MessageType.SUCCESS, () -> onEnd()); } else { @@ -77,10 +77,10 @@ public abstract class TaskExecutorDialogWizardDisplayer extends AbstractWizardDi } String appendix = StringUtils.getStackTrace(executor.getException()); - if (settings.get("failure_callback") instanceof WizardProvider.FailureCallback) - ((WizardProvider.FailureCallback) settings.get("failure_callback")).onFail(settings, executor.getException(), () -> onEnd()); - else if (settings.get("failure_message") instanceof String) - Controllers.dialog(appendix, (String) settings.get("failure_message"), MessageType.ERROR, () -> onEnd()); + if (settings.get(WizardProvider.FailureCallback.KEY) != null) + settings.get(WizardProvider.FailureCallback.KEY).onFail(settings, executor.getException(), () -> onEnd()); + else if (settings.get("failure_message") instanceof String failureMessage) + Controllers.dialog(appendix, failureMessage, MessageType.ERROR, () -> onEnd()); else if (!settings.containsKey("forbid_failure_message")) Controllers.dialog(appendix, i18n("wizard.failed"), MessageType.ERROR, () -> onEnd()); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardController.java index 9dbbf156e..b7b8a56c1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardController.java @@ -19,6 +19,7 @@ package org.jackhuang.hmcl.ui.wizard; import javafx.scene.Node; import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.util.SettingsMap; import java.util.*; @@ -27,7 +28,7 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG; public class WizardController implements Navigation { private final WizardDisplayer displayer; private WizardProvider provider = null; - private final Map settings = new HashMap<>(); + private final SettingsMap settings = new SettingsMap(); private final Stack pages = new Stack<>(); private boolean stopped = false; @@ -36,7 +37,7 @@ public class WizardController implements Navigation { } @Override - public Map getSettings() { + public SettingsMap getSettings() { return settings; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardDisplayer.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardDisplayer.java index 1d1cb5c04..b55cb08bc 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardDisplayer.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardDisplayer.java @@ -19,8 +19,7 @@ package org.jackhuang.hmcl.ui.wizard; import javafx.scene.Node; import org.jackhuang.hmcl.task.Task; - -import java.util.Map; +import org.jackhuang.hmcl.util.SettingsMap; public interface WizardDisplayer { default void onStart() { @@ -34,5 +33,5 @@ public interface WizardDisplayer { void navigateTo(Node page, Navigation.NavigationDirection nav); - void handleTask(Map settings, Task task); + void handleTask(SettingsMap settings, Task task); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardPage.java index b9d04ba34..08858e206 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardPage.java @@ -17,13 +17,13 @@ */ package org.jackhuang.hmcl.ui.wizard; -import java.util.Map; +import org.jackhuang.hmcl.util.SettingsMap; public interface WizardPage { - default void onNavigate(Map settings) { + default void onNavigate(SettingsMap settings) { } - default void cleanup(Map settings) { + default void cleanup(SettingsMap settings) { } String getTitle(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardProvider.java index e2ccc5086..f7939181b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardProvider.java @@ -18,15 +18,14 @@ package org.jackhuang.hmcl.ui.wizard; import javafx.scene.Node; - -import java.util.Map; +import org.jackhuang.hmcl.util.SettingsMap; public interface WizardProvider { - void start(Map settings); + void start(SettingsMap settings); - Object finish(Map settings); + Object finish(SettingsMap settings); - Node createPage(WizardController controller, int step, Map settings); + Node createPage(WizardController controller, int step, SettingsMap settings); boolean cancel(); @@ -35,6 +34,8 @@ public interface WizardProvider { } interface FailureCallback { - void onFail(Map settings, Exception exception, Runnable next); + SettingsMap.Key KEY = new SettingsMap.Key<>("failure_callback"); + + void onFail(SettingsMap settings, Exception exception, Runnable next); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardSinglePage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardSinglePage.java index b97379e48..d6c2673c5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardSinglePage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/WizardSinglePage.java @@ -18,8 +18,7 @@ package org.jackhuang.hmcl.ui.wizard; import javafx.scene.control.Control; - -import java.util.Map; +import org.jackhuang.hmcl.util.SettingsMap; public abstract class WizardSinglePage extends Control implements WizardPage { protected final Runnable onFinish; @@ -31,6 +30,6 @@ public abstract class WizardSinglePage extends Control implements WizardPage { protected abstract Object finish(); @Override - public void cleanup(Map settings) { + public void cleanup(SettingsMap settings) { } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/SettingsMap.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/SettingsMap.java new file mode 100644 index 000000000..b92efb9e1 --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/SettingsMap.java @@ -0,0 +1,89 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2025 huangyuhui and contributors + * + * 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 . + */ +package org.jackhuang.hmcl.util; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +/// A wrapper for `Map`, supporting type-safe reading and writing of values. +/// +/// @author Glavo +public final class SettingsMap { + public record Key(String key) { + } + + private final Map map = new HashMap<>(); + + public SettingsMap() { + } + + public Map asStringMap() { + return map; + } + + public boolean containsKey(@NotNull Key key) { + return map.containsKey(key.key); + } + + public boolean containsKey(@NotNull String key) { + return map.containsKey(key); + } + + public @Nullable T get(@NotNull Key key) { + @SuppressWarnings("unchecked") + T value = (T) map.get(key.key); + return value; + } + + public Object get(@NotNull String key) { + return map.get(key); + } + + public T getOrDefault(@NotNull Key key, T defaultValue) { + @SuppressWarnings("unchecked") + T value = (T) map.get(key.key); + return value != null ? value : defaultValue; + } + + public T put(@NotNull Key key, @Nullable T value) { + @SuppressWarnings("unchecked") + T result = (T) map.put(key.key, value); + return result; + } + + public Object put(@NotNull String key, @Nullable Object value) { + return map.put(key, value); + } + + public T remove(@NotNull Key key) { + @SuppressWarnings("unchecked") + T result = (T) map.remove(key.key); + return result; + } + + public Object remove(@NotNull String key) { + return map.remove(key); + } + + public void clear() { + map.clear(); + } +}