feat: directly show game download page in download page.

This commit is contained in:
huanghongxun
2021-09-12 02:23:56 +08:00
parent b689e68d46
commit 475d7f50f1
7 changed files with 144 additions and 31 deletions

View File

@@ -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";
}
}

View File

@@ -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() {

View File

@@ -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);
}
}

View File

@@ -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)) {

View File

@@ -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);

View File

@@ -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),

View File

@@ -34,6 +34,7 @@ public class WizardController implements Navigation {
this.displayer = displayer;
}
@Override
public Map<String, Object> getSettings() {
return settings;
}