refactor(task): fix stage progress.

This commit is contained in:
huanghongxun
2021-10-04 23:49:03 +08:00
parent 31327d685b
commit ba0a7ddfa8
34 changed files with 511 additions and 194 deletions

View File

@@ -35,8 +35,6 @@ import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public final class HMCLModpackInstallTask extends Task<Void> {
private final File zipFile;
@@ -107,13 +105,5 @@ public final class HMCLModpackInstallTask extends Task<Void> {
dependencies.add(libraryTask.thenComposeAsync(repository::saveAsync));
}
@Override
public List<String> getStages() {
return Stream.concat(
dependents.stream().flatMap(task -> task.getStages().stream()),
Stream.of("hmcl.modpack")
).collect(Collectors.toList());
}
public static final String MODPACK_TYPE = "HMCL";
}

View File

@@ -50,6 +50,7 @@ import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
@@ -167,7 +168,8 @@ public final class ModpackHelper {
};
return new ServerModpackRemoteInstallTask(profile.getDependency(), manifest, name)
.whenComplete(Schedulers.defaultScheduler(), success, failure);
.whenComplete(Schedulers.defaultScheduler(), success, failure)
.withStagesHint(Arrays.asList("hmcl.modpack", "hmcl.modpack.download"));
}
public static boolean isExternalGameNameConflicts(String name) {
@@ -223,7 +225,8 @@ public final class ModpackHelper {
public static Task<Void> getUpdateTask(Profile profile, ServerModpackManifest manifest, Charset charset, String name, ModpackConfiguration<?> configuration) throws UnsupportedModpackException {
switch (configuration.getType()) {
case ServerModpackRemoteInstallTask.MODPACK_TYPE:
return new ModpackUpdateTask(profile.getRepository(), name, new ServerModpackRemoteInstallTask(profile.getDependency(), manifest, name));
return new ModpackUpdateTask(profile.getRepository(), name, new ServerModpackRemoteInstallTask(profile.getDependency(), manifest, name))
.withStagesHint(Arrays.asList("hmcl.modpack", "hmcl.modpack.download"));
default:
throw new UnsupportedModpackException();
}

View File

@@ -275,6 +275,16 @@ public final class Controllers {
return pane;
}
public static TaskExecutorDialogPane taskDialog(Task<?> task, String title, Consumer<Region> onCancel) {
TaskExecutor executor = task.executor();
TaskExecutorDialogPane pane = new TaskExecutorDialogPane(onCancel);
pane.setTitle(title);
pane.setExecutor(executor);
dialog(pane);
executor.start();
return pane;
}
public static void navigate(Node node) {
decorator.getNavigator().navigate(node, ContainerAnimations.FADE.getAnimationProducer());
}

View File

@@ -61,6 +61,7 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.util.Lang.tryCast;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -96,7 +97,7 @@ public final class TaskListPane extends StackPane {
@Override
public void onReady(Task<?> task) {
if (task instanceof Task.StageTask) {
if (task.getStage() != null) {
Platform.runLater(() -> {
stageNodes.stream().filter(x -> x.stage.equals(task.getStage())).findAny().ifPresent(StageNode::begin);
});
@@ -150,7 +151,7 @@ public final class TaskListPane extends StackPane {
@Override
public void onFinished(Task<?> task) {
if (task instanceof Task.StageTask) {
if (task.getStage() != null) {
Platform.runLater(() -> {
stageNodes.stream().filter(x -> x.stage.equals(task.getStage())).findAny().ifPresent(StageNode::succeed);
});
@@ -167,7 +168,7 @@ public final class TaskListPane extends StackPane {
@Override
public void onFailed(Task<?> task, Throwable throwable) {
if (task instanceof Task.StageTask) {
if (task.getStage() != null) {
Platform.runLater(() -> {
stageNodes.stream().filter(x -> x.stage.equals(task.getStage())).findAny().ifPresent(StageNode::fail);
});
@@ -181,14 +182,29 @@ public final class TaskListPane extends StackPane {
}
@Override
public void onPropertiesUpdate(Map<String, Map<String, Object>> stageProperties) {
stageProperties.forEach((stage, properties) -> {
int count = tryCast(properties.get("count"), Integer.class).orElse(0),
total = tryCast(properties.get("total"), Integer.class).orElse(0);
if (total > 0)
Platform.runLater(() ->
stageNodes.stream().filter(x -> x.stage.equals(stage)).findAny().ifPresent(stageNode -> stageNode.updateCounter(count, total)));
});
public void onPropertiesUpdate(Task<?> task) {
if (task instanceof Task.CountTask) {
runInFX(() -> {
stageNodes.stream()
.filter(x -> x.stage.equals(((Task.CountTask) task).getCountStage()))
.findAny()
.ifPresent(StageNode::count);
});
return;
}
if (task.getStage() != null) {
int total = tryCast(task.getProperties().get("total"), Integer.class).orElse(0);
runInFX(() -> {
stageNodes.stream()
.filter(x -> x.stage.equals(task.getStage()))
.findAny()
.ifPresent(stageNode -> {
stageNode.setTotal(total);
});
});
}
}
});
}
@@ -197,6 +213,8 @@ public final class TaskListPane extends StackPane {
private final String stage;
private final Label title = new Label();
private final String message;
private int count = 0;
private int total = 0;
private boolean started = false;
public StageNode(String stage) {
@@ -242,6 +260,15 @@ public final class TaskListPane extends StackPane {
setLeft(FXUtils.limitingSize(SVG.check(Theme.blackFillBinding(), 14, 14), 14, 14));
}
public void count() {
updateCounter(++count, total);
}
public void setTotal(int total) {
this.total = total;
updateCounter(count, total);
}
public void updateCounter(int count, int total) {
if (total > 0)
title.setText(String.format("%s - %d/%d", message, count, total));

View File

@@ -17,6 +17,7 @@
*/
package org.jackhuang.hmcl.ui.versions;
import org.jackhuang.hmcl.mod.LocalMod;
import org.jackhuang.hmcl.mod.RemoteMod;
import org.jackhuang.hmcl.mod.RemoteModRepository;
import org.jackhuang.hmcl.mod.curse.CurseForgeRemoteModRepository;
@@ -76,11 +77,6 @@ public class ModDownloadListPage extends DownloadListPage {
}
}
@Override
public Optional<RemoteMod.Version> getRemoteVersionByLocalFile(Path file) {
throw new UnsupportedOperationException();
}
@Override
public Stream<Category> getCategories() throws IOException {
if ("mods.modrinth".equals(downloadSource.get())) {
@@ -89,6 +85,21 @@ public class ModDownloadListPage extends DownloadListPage {
return CurseForgeRemoteModRepository.MODS.getCategories();
}
}
@Override
public Optional<RemoteMod.Version> getRemoteVersionByLocalFile(LocalMod localMod, Path file) {
throw new UnsupportedOperationException();
}
@Override
public RemoteMod getModById(String id) {
throw new UnsupportedOperationException();
}
@Override
public Stream<RemoteMod.Version> getRemoteVersionsById(String id) throws IOException {
throw new UnsupportedOperationException();
}
}
@Override

View File

@@ -32,16 +32,14 @@ import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.ListPageBase;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.stream.Collectors;
@@ -176,6 +174,27 @@ public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObjec
FXUtils.openFolder(new File(profile.getRepository().getRunDirectory(versionId), "mods"));
}
public void checkUpdates() {
Controllers.taskDialog(
Task.composeAsync(() -> {
Optional<String> gameVersion = profile.getRepository().getGameVersion(versionId);
if (gameVersion.isPresent()) {
return new ModUpdateTask(gameVersion.get(), modManager.getMods());
}
return null;
})
.whenComplete(Schedulers.javafx(), (result, exception) -> {
if (exception != null) {
Controllers.dialog("Failed to check updates", "failed", MessageDialogPane.MessageType.ERROR);
} else {
Controllers.dialog(new ModUpdatesDialog(result));
}
})
.withStagesHint(Collections.singletonList("mods.check_updates"))
, i18n("update.checking"), pane -> {
});
}
public boolean isModded() {
return modded.get();
}

View File

@@ -92,7 +92,9 @@ class ModListPageSkin extends SkinBase<ModListPage> {
createToolbarButton2(i18n("mods.disable"), SVG::close, () ->
skinnable.disableSelected(listView.getSelectionModel().getSelectedItems())),
createToolbarButton2(i18n("folder.mod"), SVG::folderOpen, () ->
skinnable.openModFolder()));
skinnable.openModFolder()),
createToolbarButton2(i18n("mods.check_updates"), SVG::update, () ->
skinnable.checkUpdates()));
root.getContent().add(toolbar);
}

View File

@@ -0,0 +1,75 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui.versions;
import org.jackhuang.hmcl.mod.LocalMod;
import org.jackhuang.hmcl.mod.curse.CurseForgeRemoteModRepository;
import org.jackhuang.hmcl.task.Task;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
public class ModUpdateTask extends Task<List<LocalMod.ModUpdate>> {
private final String gameVersion;
private final Collection<LocalMod> mods;
private final Collection<Task<LocalMod.ModUpdate>> dependents;
public ModUpdateTask(String gameVersion, Collection<LocalMod> mods) {
this.gameVersion = gameVersion;
this.mods = mods;
dependents = mods.stream()
.map(mod -> Task.supplyAsync(() -> {
return mod.checkUpdates(gameVersion, CurseForgeRemoteModRepository.MODS);
}).setSignificance(TaskSignificance.MAJOR).withCounter("mods.check_updates"))
.collect(Collectors.toList());
setStage("mods.check_updates");
getProperties().put("total", dependents.size());
}
@Override
public boolean doPreExecute() {
return true;
}
@Override
public void preExecute() throws Exception {
notifyPropertiesChanged();
}
@Override
public Collection<? extends Task<?>> getDependents() {
return dependents;
}
@Override
public boolean isRelyingOnDependents() {
return false;
}
@Override
public void execute() throws Exception {
setResult(dependents.stream()
.filter(task -> task.getResult() != null)
.map(Task::getResult)
.collect(Collectors.toList()));
}
}

View File

@@ -0,0 +1,67 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui.versions;
import com.jfoenix.controls.JFXListView;
import org.jackhuang.hmcl.mod.LocalMod;
import org.jackhuang.hmcl.mod.curse.CurseAddon;
import org.jackhuang.hmcl.mod.modrinth.ModrinthRemoteModRepository;
import org.jackhuang.hmcl.ui.construct.DialogPane;
import org.jackhuang.hmcl.ui.construct.MDListCell;
import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
import java.util.List;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class ModUpdatesDialog extends DialogPane {
public ModUpdatesDialog(List<LocalMod.ModUpdate> updates) {
setTitle(i18n("mods.check_updates"));
JFXListView<LocalMod.ModUpdate> listView = new JFXListView<>();
listView.getItems().setAll(updates);
listView.setCellFactory(l -> new ModUpdateCell(listView));
setBody(listView);
}
public static class ModUpdateCell extends MDListCell<LocalMod.ModUpdate> {
TwoLineListItem content = new TwoLineListItem();
public ModUpdateCell(JFXListView<LocalMod.ModUpdate> listView) {
super(listView);
getContainer().getChildren().setAll(content);
}
@Override
protected void updateControl(LocalMod.ModUpdate item, boolean empty) {
if (empty) return;
ModTranslations.Mod mod = ModTranslations.getModById(item.getLocalMod().getId());
content.setTitle(mod != null ? mod.getDisplayName() : item.getCurrentVersion().getName());
content.setSubtitle(item.getLocalMod().getFileName());
content.getTags().setAll();
if (item.getCurrentVersion().getSelf() instanceof CurseAddon.LatestFile) {
content.getTags().add("Curseforge");
} else if (item.getCurrentVersion().getSelf() instanceof ModrinthRemoteModRepository.ModVersion) {
content.getTags().add("Modrinth");
}
}
}
}

View File

@@ -18,7 +18,7 @@ public class JavaRuntimeDownloadTask extends Task<Void> {
}
@Override
public Collection<Task<?>> getDependencies() {
public Collection<? extends Task<?>> getDependencies() {
return super.getDependencies();
}

View File

@@ -580,6 +580,7 @@ mods.add=Install mods
mods.add.failed=Failed to install mods %s.
mods.add.success=Successfully installed mods %s.
mods.category=Category
mods.check_updates=Check updates
mods.choose_mod=Choose your mods
mods.curseforge=CurseForge
mods.dependencies=Dependencies

View File

@@ -580,6 +580,7 @@ mods.add=新增模組
mods.add.failed=新增模組 %s 失敗。
mods.add.success=成功新增模組 %s。
mods.category=類別
mods.check_updates=檢查模組更新
mods.choose_mod=選擇模組
mods.curseforge=CurseForge
mods.dependencies=前置 Mod

View File

@@ -580,6 +580,7 @@ mods.add=添加模组
mods.add.failed=添加模组 %s 失败。
mods.add.success=成功添加模组 %s。
mods.category=类别
mods.check_updates=检查模组更新
mods.choose_mod=选择模组
mods.curseforge=CurseForge
mods.dependencies=前置 Mod