From 475d7f50f1adb7dcc2873d0ca06901887454248a Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Sun, 12 Sep 2021 02:23:56 +0800 Subject: [PATCH] feat: directly show game download page in download page. --- .../hmcl/ui/download/DownloadPage.java | 135 +++++++++++++++++- .../hmcl/ui/download/VersionsPage.java | 12 +- .../hmcl/ui/versions/GameListPage.java | 18 +-- .../hmcl/ui/versions/ModTranslations.java | 2 +- .../hmcl/ui/versions/VersionSettingsPage.java | 3 - .../jackhuang/hmcl/ui/wizard/Navigation.java | 4 + .../hmcl/ui/wizard/WizardController.java | 1 + 7 files changed, 144 insertions(+), 31 deletions(-) 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 639484a89..62e3652e5 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 @@ -19,13 +19,18 @@ package org.jackhuang.hmcl.ui.download; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectWrapper; +import javafx.scene.Node; import javafx.scene.layout.BorderPane; +import org.jackhuang.hmcl.download.*; +import org.jackhuang.hmcl.download.game.GameRemoteVersion; import org.jackhuang.hmcl.mod.curse.CurseAddon; import org.jackhuang.hmcl.mod.curse.CurseModManager; +import org.jackhuang.hmcl.setting.DownloadProviders; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profiles; import org.jackhuang.hmcl.setting.Theme; 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; @@ -42,10 +47,15 @@ import org.jackhuang.hmcl.ui.versions.DownloadListPage; import org.jackhuang.hmcl.ui.versions.ModDownloadListPage; import org.jackhuang.hmcl.ui.versions.VersionPage; 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.io.NetworkUtils; import org.jetbrains.annotations.Nullable; import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; import static org.jackhuang.hmcl.ui.FXUtils.runInFX; import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap; @@ -54,26 +64,30 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public class DownloadPage extends BorderPane implements DecoratorPage { private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(DecoratorPage.State.fromTitle(i18n("download"), -1)); private final TabHeader tab; + private final TabHeader.Tab newGameTab = new TabHeader.Tab<>("newGameTab"); private final TabHeader.Tab modTab = new TabHeader.Tab<>("modTab"); private final TabHeader.Tab modpackTab = new TabHeader.Tab<>("modpackTab"); private final TabHeader.Tab resourcePackTab = new TabHeader.Tab<>("resourcePackTab"); private final TabHeader.Tab customizationTab = new TabHeader.Tab<>("customizationTab"); private final TabHeader.Tab worldTab = new TabHeader.Tab<>("worldTab"); private final TransitionPane transitionPane = new TransitionPane(); + private final DownloadNavigator versionPageNavigator = new DownloadNavigator(); private WeakListenerHolder listenerHolder; public DownloadPage() { + newGameTab.setNodeSupplier(() -> new VersionsPage(versionPageNavigator, i18n("install.installer.choose", i18n("install.installer.game")), "", DownloadProviders.getDownloadProvider(), + "game", versionPageNavigator::onGameSelected)); modpackTab.setNodeSupplier(() -> new DownloadListPage(CurseModManager.SECTION_MODPACK, Versions::downloadModpackImpl)); modTab.setNodeSupplier(() -> new ModDownloadListPage(CurseModManager.SECTION_MOD, (profile, version, file) -> download(profile, version, file, "mods"), true)); resourcePackTab.setNodeSupplier(() -> new DownloadListPage(CurseModManager.SECTION_RESOURCE_PACK, (profile, version, file) -> download(profile, version, file, "resourcepacks"))); // customizationTab.setNodeSupplier(() -> new ModDownloadListPage(CurseModManager.SECTION_CUSTOMIZATION, this::download)); worldTab.setNodeSupplier(() -> new DownloadListPage(CurseModManager.SECTION_WORLD)); - tab = new TabHeader(modpackTab, modTab, resourcePackTab, worldTab); + tab = new TabHeader(newGameTab, modpackTab, modTab, resourcePackTab, worldTab); Profiles.registerVersionsListener(this::loadVersions); - tab.getSelectionModel().select(modTab); + tab.getSelectionModel().select(newGameTab); FXUtils.onChangeAndOperate(tab.getSelectionModel().selectedItemProperty(), newValue -> { if (newValue.initializeIfNeeded()) { if (newValue.getNode() instanceof VersionPage.VersionLoadable) { @@ -86,9 +100,10 @@ public class DownloadPage extends BorderPane implements DecoratorPage { { AdvancedListBox sideBar = new AdvancedListBox() .addNavigationDrawerItem(item -> { - item.setTitle(i18n("install.new_game")); + item.setTitle(i18n("game")); item.setLeftGraphic(wrap(SVG.gamepad(Theme.blackFillBinding(), 24, 24))); - item.setOnAction(e -> Versions.addNewGame()); + item.activeProperty().bind(tab.getSelectionModel().selectedItemProperty().isEqualTo(newGameTab)); + item.setOnAction(e -> tab.getSelectionModel().select(newGameTab)); }) .startCategory(i18n("download")) .addNavigationDrawerItem(item -> { @@ -175,4 +190,116 @@ public class DownloadPage extends BorderPane implements DecoratorPage { public ReadOnlyObjectProperty stateProperty() { return state.getReadOnlyProperty(); } + + private class DownloadNavigator implements Navigation { + private final Map settings = new HashMap<>(); + + @Override + public void onStart() { + + } + + @Override + public void onNext() { + + } + + @Override + public void onPrev(boolean cleanUp) { + } + + @Override + public boolean canPrev() { + return false; + } + + @Override + public void onFinish() { + + } + + @Override + public void onEnd() { + + } + + @Override + public void onCancel() { + + } + + @Override + public Map getSettings() { + return settings; + } + + public void onGameSelected() { + Profile profile = Profiles.getSelectedProfile(); + if (profile.getRepository().isLoaded()) { + Controllers.getDecorator().startWizard(new VanillaInstallWizardProvider(profile, (GameRemoteVersion) settings.get("game")), i18n("install.new_game")); + } + } + + } + + private static class VanillaInstallWizardProvider implements WizardProvider { + private final Profile profile; + private final DefaultDependencyManager dependencyManager; + private final DownloadProvider downloadProvider; + private final GameRemoteVersion gameVersion; + + public VanillaInstallWizardProvider(Profile profile, GameRemoteVersion gameVersion) { + this.profile = profile; + this.gameVersion = gameVersion; + this.downloadProvider = DownloadProviders.getDownloadProvider(); + this.dependencyManager = profile.getDependency(downloadProvider); + } + + @Override + public void start(Map settings) { + settings.put(PROFILE, profile); + settings.put(LibraryAnalyzer.LibraryType.MINECRAFT.getPatchId(), gameVersion); + } + + private Task finishVersionDownloadingAsync(Map 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()); + + return builder.buildAsync().whenComplete(any -> profile.getRepository().refreshVersions()) + .thenRunAsync(Schedulers.javafx(), () -> profile.setSelectedVersion(name)); + } + + @Override + public Object finish(Map settings) { + settings.put("title", i18n("install.new_game")); + settings.put("success_message", i18n("install.success")); + settings.put("failure_callback", (FailureCallback) (settings1, exception, next) -> UpdateInstallerWizardProvider.alertFailureMessage(exception, next)); + + return finishVersionDownloadingAsync(settings); + } + + @Override + public Node createPage(WizardController controller, int step, Map settings) { + switch (step) { + case 0: + return new InstallersPage(controller, profile.getRepository(), ((RemoteVersion) controller.getSettings().get("game")).getGameVersion(), downloadProvider); + default: + throw new IllegalStateException("error step " + step + ", settings: " + settings + ", pages: " + controller.getPages()); + } + } + + @Override + 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 875eb010b..fb9a05dd7 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 @@ -45,8 +45,8 @@ import org.jackhuang.hmcl.ui.animation.TransitionPane; import org.jackhuang.hmcl.ui.construct.ComponentList; import org.jackhuang.hmcl.ui.construct.IconedTwoLineListItem; import org.jackhuang.hmcl.ui.construct.RipplerContainer; +import org.jackhuang.hmcl.ui.wizard.Navigation; import org.jackhuang.hmcl.ui.wizard.Refreshable; -import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardPage; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.i18n.Locales; @@ -64,7 +64,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres private final String gameVersion; private final String libraryId; private final String title; - private final WizardController controller; + private final Navigation navigation; @FXML private JFXListView list; @@ -92,11 +92,11 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres private VersionList versionList; private CompletableFuture executor; - public VersionsPage(WizardController controller, String title, String gameVersion, DownloadProvider downloadProvider, String libraryId, Runnable callback) { + public VersionsPage(Navigation navigation, String title, String gameVersion, DownloadProvider downloadProvider, String libraryId, Runnable callback) { this.title = title; this.gameVersion = gameVersion; this.libraryId = libraryId; - this.controller = controller; + this.navigation = navigation; FXUtils.loadFXML(this, "/assets/fxml/download/versions.fxml"); @@ -197,7 +197,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres list.setOnMouseClicked(e -> { if (list.getSelectionModel().getSelectedIndex() < 0) return; - controller.getSettings().put(libraryId, list.getSelectionModel().getSelectedItem()); + navigation.getSettings().put(libraryId, list.getSelectionModel().getSelectedItem()); callback.run(); }); @@ -275,7 +275,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres } @FXML - private void onBack() { controller.onPrev(true); } + private void onBack() { navigation.onPrev(true); } @FXML private void onSponsor() { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPage.java index 0199c83bf..51ae5db31 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListPage.java @@ -138,13 +138,6 @@ public class GameListPage extends ListPageBase implements Decorato } { - AdvancedListItem installNewGameItem = new AdvancedListItem(); - installNewGameItem.getStyleClass().add("navigation-drawer-item"); - installNewGameItem.setTitle(i18n("install.new_game")); - installNewGameItem.setActionButtonVisible(false); - installNewGameItem.setLeftGraphic(VersionPage.wrap(SVG.plusCircleOutline(Theme.blackFillBinding(), 24, 24))); - installNewGameItem.setOnAction(e -> Versions.addNewGame()); - AdvancedListItem installModpackItem = new AdvancedListItem(); installModpackItem.getStyleClass().add("navigation-drawer-item"); installModpackItem.setTitle(i18n("install.modpack")); @@ -152,13 +145,6 @@ public class GameListPage extends ListPageBase implements Decorato installModpackItem.setLeftGraphic(VersionPage.wrap(SVG.pack(Theme.blackFillBinding(), 24, 24))); installModpackItem.setOnAction(e -> Versions.importModpack()); - AdvancedListItem downloadModpackItem = new AdvancedListItem(); - downloadModpackItem.getStyleClass().add("navigation-drawer-item"); - downloadModpackItem.setTitle(i18n("modpack.download")); - downloadModpackItem.setActionButtonVisible(false); - downloadModpackItem.setLeftGraphic(VersionPage.wrap(SVG.fire(Theme.blackFillBinding(), 24, 24))); - downloadModpackItem.setOnAction(e -> Versions.downloadModpack()); - AdvancedListItem refreshItem = new AdvancedListItem(); refreshItem.getStyleClass().add("navigation-drawer-item"); refreshItem.setTitle(i18n("button.refresh")); @@ -174,12 +160,10 @@ public class GameListPage extends ListPageBase implements Decorato globalManageItem.setOnAction(e -> modifyGlobalGameSettings()); AdvancedListBox bottomLeftCornerList = new AdvancedListBox() - .add(installNewGameItem) .add(installModpackItem) - .add(downloadModpackItem) .add(refreshItem) .add(globalManageItem); - FXUtils.setLimitHeight(bottomLeftCornerList, 40 * 5 + 12 * 2); + FXUtils.setLimitHeight(bottomLeftCornerList, 40 * 3 + 12 * 2); left.setBottom(bottomLeftCornerList); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModTranslations.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModTranslations.java index f5d1f40b2..dc8d5a184 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModTranslations.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModTranslations.java @@ -190,7 +190,7 @@ public final class ModTranslations { public String getDisplayName() { StringBuilder builder = new StringBuilder(); if (StringUtils.isNotBlank(abbr)) { - builder.append("[").append(abbr).append("] "); + builder.append("[").append(abbr.trim()).append("] "); } builder.append(name); if (StringUtils.isNotBlank(subname)) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java index cad9395fb..e9ddd97d1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java @@ -354,7 +354,6 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag serverPane.getColumnConstraints().setAll(title, value); txtServerIP = new JFXTextField(); - txtServerIP.setLabelFloat(true); txtServerIP.setPromptText(i18n("settings.advanced.server_ip.prompt")); txtServerIP.getStyleClass().add("fit-width"); FXUtils.setLimitWidth(txtServerIP, 300); @@ -386,7 +385,6 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag pane.getColumnConstraints().setAll(title, value); txtGameArgs = new JFXTextField(); - txtGameArgs.setLabelFloat(true); txtGameArgs.setPromptText(i18n("settings.advanced.minecraft_arguments.prompt")); txtGameArgs.getStyleClass().add("fit-width"); pane.addRow(0, new Label(i18n("settings.advanced.minecraft_arguments")), txtGameArgs); @@ -417,7 +415,6 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag pane.getColumnConstraints().setAll(title, value); txtJVMArgs = new JFXTextField(); - txtJVMArgs.setLabelFloat(true); txtJVMArgs.setPromptText(i18n("settings.advanced.jvm_args.prompt")); txtJVMArgs.getStyleClass().add("fit-width"); pane.addRow(0, new Label(i18n("settings.advanced.jvm_args")), txtJVMArgs); 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 b5b2ecb68..8e02d88d7 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 @@ -19,6 +19,8 @@ package org.jackhuang.hmcl.ui.wizard; import org.jackhuang.hmcl.ui.animation.ContainerAnimations; +import java.util.Map; + public interface Navigation { void onStart(); @@ -35,6 +37,8 @@ public interface Navigation { void onCancel(); + Map getSettings(); + enum NavigationDirection { START(ContainerAnimations.NONE), PREVIOUS(ContainerAnimations.SWIPE_RIGHT), 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 2d97e4a87..3b6332f59 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 @@ -34,6 +34,7 @@ public class WizardController implements Navigation { this.displayer = displayer; } + @Override public Map getSettings() { return settings; }