feat: directly show game download page in download page.
This commit is contained in:
@@ -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<DecoratorPage.State> state = new ReadOnlyObjectWrapper<>(DecoratorPage.State.fromTitle(i18n("download"), -1));
|
||||
private final TabHeader tab;
|
||||
private final TabHeader.Tab<VersionsPage> newGameTab = new TabHeader.Tab<>("newGameTab");
|
||||
private final TabHeader.Tab<DownloadListPage> modTab = new TabHeader.Tab<>("modTab");
|
||||
private final TabHeader.Tab<DownloadListPage> modpackTab = new TabHeader.Tab<>("modpackTab");
|
||||
private final TabHeader.Tab<DownloadListPage> resourcePackTab = new TabHeader.Tab<>("resourcePackTab");
|
||||
private final TabHeader.Tab<DownloadListPage> customizationTab = new TabHeader.Tab<>("customizationTab");
|
||||
private final TabHeader.Tab<DownloadListPage> 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<State> stateProperty() {
|
||||
return state.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
private class DownloadNavigator implements Navigation {
|
||||
private final Map<String, Object> 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<String, Object> 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<String, Object> settings) {
|
||||
settings.put(PROFILE, profile);
|
||||
settings.put(LibraryAnalyzer.LibraryType.MINECRAFT.getPatchId(), gameVersion);
|
||||
}
|
||||
|
||||
private Task<Void> finishVersionDownloadingAsync(Map<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<RemoteVersion> 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() {
|
||||
|
||||
@@ -138,13 +138,6 @@ public class GameListPage extends ListPageBase<GameListItem> 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<GameListItem> 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<GameListItem> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<String, Object> getSettings();
|
||||
|
||||
enum NavigationDirection {
|
||||
START(ContainerAnimations.NONE),
|
||||
PREVIOUS(ContainerAnimations.SWIPE_RIGHT),
|
||||
|
||||
@@ -34,6 +34,7 @@ public class WizardController implements Navigation {
|
||||
this.displayer = displayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user