mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-14 14:26:43 -04:00
show retry link when failed to fetch version list
This commit is contained in:
parent
7732b21ca2
commit
c76bcb5d15
@ -23,6 +23,7 @@ import org.jackhuang.hmcl.mod.*;
|
|||||||
import org.jackhuang.hmcl.setting.EnumGameDirectory;
|
import org.jackhuang.hmcl.setting.EnumGameDirectory;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.setting.VersionSetting;
|
import org.jackhuang.hmcl.setting.VersionSetting;
|
||||||
|
import org.jackhuang.hmcl.task.FinalizedCallback;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.util.Constants;
|
import org.jackhuang.hmcl.util.Constants;
|
||||||
import org.jackhuang.hmcl.util.FileUtils;
|
import org.jackhuang.hmcl.util.FileUtils;
|
||||||
@ -84,13 +85,13 @@ public final class ModpackHelper {
|
|||||||
public static Task getInstallTask(Profile profile, File zipFile, String name, Modpack modpack) {
|
public static Task getInstallTask(Profile profile, File zipFile, String name, Modpack modpack) {
|
||||||
profile.getRepository().markVersionAsModpack(name);
|
profile.getRepository().markVersionAsModpack(name);
|
||||||
|
|
||||||
Task finalizeTask = Task.of(() -> {
|
FinalizedCallback finalizeTask = (variables, isDependentsSucceeded) -> {
|
||||||
profile.getRepository().refreshVersions();
|
profile.getRepository().refreshVersions();
|
||||||
VersionSetting vs = profile.specializeVersionSetting(name);
|
VersionSetting vs = profile.specializeVersionSetting(name);
|
||||||
profile.getRepository().undoMark(name);
|
profile.getRepository().undoMark(name);
|
||||||
if (vs != null)
|
if (vs != null)
|
||||||
vs.setGameDirType(EnumGameDirectory.VERSION_FOLDER);
|
vs.setGameDirType(EnumGameDirectory.VERSION_FOLDER);
|
||||||
});
|
};
|
||||||
|
|
||||||
if (modpack.getManifest() instanceof CurseManifest)
|
if (modpack.getManifest() instanceof CurseManifest)
|
||||||
return new CurseInstallTask(profile.getDependency(), zipFile, ((CurseManifest) modpack.getManifest()), name)
|
return new CurseInstallTask(profile.getDependency(), zipFile, ((CurseManifest) modpack.getManifest()), name)
|
||||||
|
@ -19,12 +19,15 @@ package org.jackhuang.hmcl.ui.download;
|
|||||||
|
|
||||||
import com.jfoenix.controls.JFXListView;
|
import com.jfoenix.controls.JFXListView;
|
||||||
import com.jfoenix.controls.JFXSpinner;
|
import com.jfoenix.controls.JFXSpinner;
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||||
import org.jackhuang.hmcl.download.RemoteVersion;
|
import org.jackhuang.hmcl.download.RemoteVersion;
|
||||||
import org.jackhuang.hmcl.download.VersionList;
|
import org.jackhuang.hmcl.download.VersionList;
|
||||||
|
import org.jackhuang.hmcl.task.Scheduler;
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.task.TaskExecutor;
|
import org.jackhuang.hmcl.task.TaskExecutor;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
|
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
|
||||||
@ -33,7 +36,9 @@ import org.jackhuang.hmcl.ui.wizard.Refreshable;
|
|||||||
import org.jackhuang.hmcl.ui.wizard.WizardController;
|
import org.jackhuang.hmcl.ui.wizard.WizardController;
|
||||||
import org.jackhuang.hmcl.ui.wizard.WizardPage;
|
import org.jackhuang.hmcl.ui.wizard.WizardPage;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public final class VersionsPage extends StackPane implements WizardPage, Refreshable {
|
public final class VersionsPage extends StackPane implements WizardPage, Refreshable {
|
||||||
private final WizardController controller;
|
private final WizardController controller;
|
||||||
@ -45,7 +50,10 @@ public final class VersionsPage extends StackPane implements WizardPage, Refresh
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private JFXListView<VersionsPageItem> list;
|
private JFXListView<VersionsPageItem> list;
|
||||||
@FXML private JFXSpinner spinner;
|
@FXML
|
||||||
|
private JFXSpinner spinner;
|
||||||
|
@FXML
|
||||||
|
private StackPane failedPane;
|
||||||
|
|
||||||
private final TransitionHandler transitionHandler = new TransitionHandler(this);
|
private final TransitionHandler transitionHandler = new TransitionHandler(this);
|
||||||
private final VersionList<?> versionList;
|
private final VersionList<?> versionList;
|
||||||
@ -62,7 +70,6 @@ public final class VersionsPage extends StackPane implements WizardPage, Refresh
|
|||||||
this.versionList = downloadProvider.getVersionListById(libraryId);
|
this.versionList = downloadProvider.getVersionListById(libraryId);
|
||||||
|
|
||||||
FXUtils.loadFXML(this, "/assets/fxml/download/versions.fxml");
|
FXUtils.loadFXML(this, "/assets/fxml/download/versions.fxml");
|
||||||
getChildren().setAll(spinner);
|
|
||||||
list.getSelectionModel().selectedItemProperty().addListener((a, b, newValue) -> {
|
list.getSelectionModel().selectedItemProperty().addListener((a, b, newValue) -> {
|
||||||
controller.getSettings().put(libraryId, newValue.getRemoteVersion().getSelfVersion());
|
controller.getSettings().put(libraryId, newValue.getRemoteVersion().getSelfVersion());
|
||||||
callback.run();
|
callback.run();
|
||||||
@ -72,15 +79,23 @@ public final class VersionsPage extends StackPane implements WizardPage, Refresh
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refresh() {
|
public void refresh() {
|
||||||
executor = versionList.refreshAsync(downloadProvider).subscribe(Schedulers.javafx(), () -> {
|
getChildren().setAll(spinner);
|
||||||
versionList.getVersions(gameVersion).stream()
|
executor = versionList.refreshAsync(downloadProvider).finalized((variables, isDependentsSucceeded) -> {
|
||||||
.sorted(RemoteVersion.RemoteVersionComparator.INSTANCE)
|
if (isDependentsSucceeded) {
|
||||||
.forEach(version -> {
|
List<VersionsPageItem> items = versionList.getVersions(gameVersion).stream()
|
||||||
list.getItems().add(new VersionsPageItem(version));
|
.sorted(RemoteVersion.RemoteVersionComparator.INSTANCE)
|
||||||
});
|
.map(VersionsPageItem::new).collect(Collectors.toList());
|
||||||
|
|
||||||
transitionHandler.setContent(list, ContainerAnimations.FADE.getAnimationProducer());
|
Platform.runLater(() -> {
|
||||||
});
|
list.getItems().setAll(items);
|
||||||
|
transitionHandler.setContent(list, ContainerAnimations.FADE.getAnimationProducer());
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
transitionHandler.setContent(failedPane, ContainerAnimations.FADE.getAnimationProducer());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).executor().start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -94,4 +109,9 @@ public final class VersionsPage extends StackPane implements WizardPage, Refresh
|
|||||||
if (executor != null)
|
if (executor != null)
|
||||||
executor.cancel();
|
executor.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void onRefresh() {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -899,6 +899,7 @@
|
|||||||
.jfx-spinner > .arc {
|
.jfx-spinner > .arc {
|
||||||
-fx-stroke-width: 3.0;
|
-fx-stroke-width: 3.0;
|
||||||
-fx-fill: transparent;
|
-fx-fill: transparent;
|
||||||
|
-fx-stroke: -fx-base-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.first-spinner {
|
.first-spinner {
|
||||||
@ -957,50 +958,6 @@
|
|||||||
-fx-stroke-width: 5.0;
|
-fx-stroke-width: 5.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blue-spinner .arc {
|
|
||||||
-fx-stroke: #4285f4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.red-spinner .arc {
|
|
||||||
-fx-stroke: #db4437;
|
|
||||||
}
|
|
||||||
|
|
||||||
.green-spinner .arc {
|
|
||||||
-fx-stroke: #f4b400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.yellow-spinner .arc {
|
|
||||||
-fx-stroke: -fx-base-check-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.materialDesign-purple .arc {
|
|
||||||
-fx-stroke: #ab47bc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.materialDesign-blue .arc {
|
|
||||||
-fx-stroke: #2962ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.materialDesign-cyan .arc {
|
|
||||||
-fx-stroke: #00b8d4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.materialDesign-green .arc {
|
|
||||||
-fx-stroke: #00c853;
|
|
||||||
}
|
|
||||||
|
|
||||||
.materialDesign-yellow .arc {
|
|
||||||
-fx-stroke: #ffd600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.materialDesign-orange .arc {
|
|
||||||
-fx-stroke: #ff6d00;
|
|
||||||
}
|
|
||||||
|
|
||||||
.materialDesign-red .arc {
|
|
||||||
-fx-stroke: #d50000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* *
|
* *
|
||||||
* JFX Combo Box *
|
* JFX Combo Box *
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
</JFXListView>
|
</JFXListView>
|
||||||
</StackPane>
|
</StackPane>
|
||||||
|
|
||||||
<HBox alignment="BOTTOM_CENTER" style="-fx-padding: 20;">
|
<HBox alignment="BOTTOM_CENTER" style="-fx-padding: 20;" pickOnBounds="false">
|
||||||
<Label text="%modpack.introduction" />
|
<Label text="%modpack.introduction" />
|
||||||
</HBox>
|
</HBox>
|
||||||
</fx:root>
|
</fx:root>
|
||||||
|
@ -3,11 +3,15 @@
|
|||||||
<?import com.jfoenix.controls.JFXListView?>
|
<?import com.jfoenix.controls.JFXListView?>
|
||||||
<?import com.jfoenix.controls.JFXSpinner?>
|
<?import com.jfoenix.controls.JFXSpinner?>
|
||||||
<?import javafx.scene.layout.StackPane?>
|
<?import javafx.scene.layout.StackPane?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
<fx:root xmlns="http://javafx.com/javafx"
|
<fx:root xmlns="http://javafx.com/javafx"
|
||||||
xmlns:fx="http://javafx.com/fxml"
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
type="StackPane"
|
type="StackPane"
|
||||||
prefHeight="400.0" prefWidth="600.0">
|
prefHeight="400.0" prefWidth="600.0">
|
||||||
<JFXSpinner fx:id="spinner" style="-fx-radius:16" styleClass="materialDesign-purple, first-spinner" />
|
<JFXSpinner fx:id="spinner" styleClass="first-spinner" />
|
||||||
<JFXListView fx:id="list" styleClass="jfx-list-view">
|
<JFXListView fx:id="list" styleClass="jfx-list-view">
|
||||||
</JFXListView>
|
</JFXListView>
|
||||||
|
<StackPane fx:id="failedPane">
|
||||||
|
<Label onMouseClicked="#onRefresh" style="-fx-text-fill: #0079FF; -fx-font-size: 20;" text="%download.failed.refresh" />
|
||||||
|
</StackPane>
|
||||||
</fx:root>
|
</fx:root>
|
||||||
|
@ -105,6 +105,7 @@ crash.user_fault=Your OS or Java environment may not be properly installed resul
|
|||||||
download=Download
|
download=Download
|
||||||
download.BMCL=BMCLAPI (bangbang93, http://bmclapi.bangbang93.com/)
|
download.BMCL=BMCLAPI (bangbang93, http://bmclapi.bangbang93.com/)
|
||||||
download.failed=Failed to download
|
download.failed=Failed to download
|
||||||
|
download.failed.refresh=Unable to load version list. Click here to retry.
|
||||||
download.mojang=Mojang
|
download.mojang=Mojang
|
||||||
download.not_200=Failed to download, the response code is %s.
|
download.not_200=Failed to download, the response code is %s.
|
||||||
download.source=Download Source
|
download.source=Download Source
|
||||||
|
@ -105,6 +105,7 @@ crash.user_fault=您的系统或Java环境可能安装不当导致本软件崩
|
|||||||
download=下载
|
download=下载
|
||||||
download.BMCL=BMCLAPI (bangbang93, http://bmclapi.bangbang93.com/)
|
download.BMCL=BMCLAPI (bangbang93, http://bmclapi.bangbang93.com/)
|
||||||
download.failed=下载失败
|
download.failed=下载失败
|
||||||
|
download.failed.refresh=加载版本列表失败,点击此处重试。
|
||||||
download.mojang=官方
|
download.mojang=官方
|
||||||
download.not_200=下载失败,HTTP状态码:%s.
|
download.not_200=下载失败,HTTP状态码:%s.
|
||||||
download.source=下载源
|
download.source=下载源
|
||||||
|
@ -62,7 +62,7 @@ public class DefaultGameBuilder extends GameBuilder {
|
|||||||
downloadGameAsync(gameVersion, version),
|
downloadGameAsync(gameVersion, version),
|
||||||
new GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries.
|
new GameLibrariesTask(dependencyManager, version) // Game libraries will be downloaded for multiple times partly, this time is for vanilla libraries.
|
||||||
).with(new VersionJsonSaveTask(dependencyManager.getGameRepository(), version)); // using [with] because download failure here are tolerant.
|
).with(new VersionJsonSaveTask(dependencyManager.getGameRepository(), version)); // using [with] because download failure here are tolerant.
|
||||||
|
|
||||||
if (toolVersions.containsKey("forge"))
|
if (toolVersions.containsKey("forge"))
|
||||||
result = result.then(libraryTaskHelper(gameVersion, "forge"));
|
result = result.then(libraryTaskHelper(gameVersion, "forge"));
|
||||||
if (toolVersions.containsKey("liteloader"))
|
if (toolVersions.containsKey("liteloader"))
|
||||||
@ -70,12 +70,9 @@ public class DefaultGameBuilder extends GameBuilder {
|
|||||||
if (toolVersions.containsKey("optifine"))
|
if (toolVersions.containsKey("optifine"))
|
||||||
result = result.then(libraryTaskHelper(gameVersion, "optifine"));
|
result = result.then(libraryTaskHelper(gameVersion, "optifine"));
|
||||||
return result;
|
return result;
|
||||||
}).finalized(new Task() {
|
}).finalized((variables, isDependentsSucceeded) -> {
|
||||||
@Override
|
if (!isDependentsSucceeded)
|
||||||
public void execute() {
|
dependencyManager.getGameRepository().getVersionRoot(name).delete();
|
||||||
if (!isDependentsSucceeded())
|
|
||||||
dependencyManager.getGameRepository().getVersionRoot(name).delete();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher.
|
||||||
|
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||||
|
*
|
||||||
|
* 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 {http://www.gnu.org/licenses/}.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.task;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||||
|
|
||||||
|
public interface FinalizedCallback {
|
||||||
|
void execute(AutoTypingMap<String> variables, boolean isDependentsSucceeded) throws Exception;
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Hello Minecraft! Launcher.
|
||||||
|
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||||
|
*
|
||||||
|
* 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 {http://www.gnu.org/licenses/}.
|
||||||
|
*/
|
||||||
|
package org.jackhuang.hmcl.task;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||||
|
import org.jackhuang.hmcl.util.ExceptionalFunction;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A task that combines two tasks and make sure [pred] runs before succ.
|
||||||
|
*
|
||||||
|
* @author huangyuhui
|
||||||
|
*/
|
||||||
|
final class FinalizedTask extends Task {
|
||||||
|
|
||||||
|
private final Collection<Task> dependents;
|
||||||
|
private final FinalizedCallback callback;
|
||||||
|
private final Scheduler scheduler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A task that combines two tasks and make sure pred runs before succ.
|
||||||
|
*
|
||||||
|
* @param pred the task that runs before succ.
|
||||||
|
* @param callback a callback that returns the task runs after pred, succ will be executed asynchronously. You can do something that relies on the result of pred.
|
||||||
|
*/
|
||||||
|
public FinalizedTask(Task pred, Scheduler scheduler, FinalizedCallback callback) {
|
||||||
|
this.dependents = Collections.singleton(pred);
|
||||||
|
this.scheduler = scheduler;
|
||||||
|
this.callback = callback;
|
||||||
|
|
||||||
|
setSignificance(TaskSignificance.MODERATE);
|
||||||
|
setName(callback.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Scheduler getScheduler() {
|
||||||
|
return scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() throws Exception {
|
||||||
|
setName(callback.toString());
|
||||||
|
callback.execute(getVariables(), isDependentsSucceeded());
|
||||||
|
|
||||||
|
if (!isDependentsSucceeded())
|
||||||
|
throw new SilentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Task> getDependents() {
|
||||||
|
return dependents;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRelyingOnDependents() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -260,12 +260,12 @@ public abstract class Task {
|
|||||||
return new CoupleTask<>(this, b, false, false);
|
return new CoupleTask<>(this, b, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Task finalized(Task b) {
|
public final Task finalized(FinalizedCallback b) {
|
||||||
return finalized(convert(b));
|
return finalized(Schedulers.defaultScheduler(), b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Task finalized(ExceptionalFunction<AutoTypingMap<String>, Task, ?> b) {
|
public final Task finalized(Scheduler scheduler, FinalizedCallback b) {
|
||||||
return new CoupleTask<>(this, b, false, true);
|
return new FinalizedTask(this, scheduler, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task empty() {
|
public static Task empty() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user