mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-15 14:56:05 -04:00
add: show asset and mod download progress
This commit is contained in:
parent
4f51ab00a1
commit
3efec78732
@ -57,6 +57,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.util.Lang.tryCast;
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
public final class TaskListPane extends StackPane {
|
public final class TaskListPane extends StackPane {
|
||||||
@ -172,12 +173,24 @@ public final class TaskListPane extends StackPane {
|
|||||||
node.setThrowable(throwable);
|
node.setThrowable(throwable);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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)));
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StageNode extends BorderPane {
|
private static class StageNode extends BorderPane {
|
||||||
private final String stage;
|
private final String stage;
|
||||||
private final Label title = new Label();
|
private final Label title = new Label();
|
||||||
|
private final String message;
|
||||||
private boolean started = false;
|
private boolean started = false;
|
||||||
|
|
||||||
public StageNode(String stage) {
|
public StageNode(String stage) {
|
||||||
@ -185,7 +198,6 @@ public final class TaskListPane extends StackPane {
|
|||||||
|
|
||||||
String stageKey = StringUtils.substringBefore(stage, ':');
|
String stageKey = StringUtils.substringBefore(stage, ':');
|
||||||
String stageValue = StringUtils.substringAfter(stage, ':');
|
String stageValue = StringUtils.substringAfter(stage, ':');
|
||||||
String message;
|
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
switch (stageKey) {
|
switch (stageKey) {
|
||||||
@ -222,6 +234,13 @@ public final class TaskListPane extends StackPane {
|
|||||||
public void succeed() {
|
public void succeed() {
|
||||||
setLeft(FXUtils.limitingSize(SVG.check(Theme.blackFillBinding(), 14, 14), 14, 14));
|
setLeft(FXUtils.limitingSize(SVG.check(Theme.blackFillBinding(), 14, 14), 14, 14));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateCounter(int count, int total) {
|
||||||
|
if (total > 0)
|
||||||
|
title.setText(String.format("%s - %d/%d", message, count, total));
|
||||||
|
else
|
||||||
|
title.setText(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ProgressListNode extends BorderPane {
|
private class ProgressListNode extends BorderPane {
|
||||||
|
@ -78,6 +78,7 @@ public class VersionPage extends Control implements DecoratorPage {
|
|||||||
Profiles.registerVersionsListener(this::loadVersions);
|
Profiles.registerVersionsListener(this::loadVersions);
|
||||||
|
|
||||||
listView.getSelectionModel().selectedItemProperty().addListener((a, b, newValue) -> {
|
listView.getSelectionModel().selectedItemProperty().addListener((a, b, newValue) -> {
|
||||||
|
if (newValue != null)
|
||||||
loadVersion(newValue, profile);
|
loadVersion(newValue, profile);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -123,13 +123,17 @@ public final class GameAssetDownloadTask extends Task<Void> {
|
|||||||
.setCacheRepository(dependencyManager.getCacheRepository())
|
.setCacheRepository(dependencyManager.getCacheRepository())
|
||||||
.setCaching(true)
|
.setCaching(true)
|
||||||
.setCandidate(dependencyManager.getCacheRepository().getCommonDirectory()
|
.setCandidate(dependencyManager.getCacheRepository().getCommonDirectory()
|
||||||
.resolve("assets").resolve("objects").resolve(assetObject.getLocation())));
|
.resolve("assets").resolve("objects").resolve(assetObject.getLocation())).withCounter());
|
||||||
} else {
|
} else {
|
||||||
dependencyManager.getCacheRepository().tryCacheFile(file.toPath(), CacheRepository.SHA1, assetObject.getHash());
|
dependencyManager.getCacheRepository().tryCacheFile(file.toPath(), CacheRepository.SHA1, assetObject.getHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
updateProgress(++progress, index.getObjects().size());
|
updateProgress(++progress, index.getObjects().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!dependencies.isEmpty()) {
|
||||||
|
getProperties().put("total", dependencies.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final boolean DOWNLOAD_INDEX_FORCIBLY = true;
|
public static final boolean DOWNLOAD_INDEX_FORCIBLY = true;
|
||||||
|
@ -151,9 +151,13 @@ public final class CurseCompletionTask extends Task<Void> {
|
|||||||
if (!modManager.hasSimpleMod(file.getFileName())) {
|
if (!modManager.hasSimpleMod(file.getFileName())) {
|
||||||
dependencies.add(new FileDownloadTask(file.getUrl(), modManager.getSimpleModPath(file.getFileName()).toFile())
|
dependencies.add(new FileDownloadTask(file.getUrl(), modManager.getSimpleModPath(file.getFileName()).toFile())
|
||||||
.setCacheRepository(dependency.getCacheRepository())
|
.setCacheRepository(dependency.getCacheRepository())
|
||||||
.setCaching(true));
|
.setCaching(true).withCounter());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!dependencies.isEmpty()) {
|
||||||
|
getProperties().put("total", dependencies.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,11 +20,10 @@ package org.jackhuang.hmcl.task;
|
|||||||
import org.jackhuang.hmcl.util.Logging;
|
import org.jackhuang.hmcl.util.Logging;
|
||||||
import org.jackhuang.hmcl.util.function.ExceptionalRunnable;
|
import org.jackhuang.hmcl.util.function.ExceptionalRunnable;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class CancellableTaskExecutor extends TaskExecutor {
|
public class CancellableTaskExecutor extends TaskExecutor {
|
||||||
@ -105,6 +104,19 @@ public class CancellableTaskExecutor extends TaskExecutor {
|
|||||||
return success.get() && !cancelled.get();
|
return success.get() && !cancelled.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized void updateStageProperties(String stage, Map<String, Object> taskProperties) {
|
||||||
|
stageProperties.putIfAbsent(stage, new HashMap<>());
|
||||||
|
Map<String, Object> prop = stageProperties.get(stage);
|
||||||
|
for (Map.Entry<String, Object> entry : taskProperties.entrySet()) {
|
||||||
|
if (entry.getValue() instanceof UnaryOperator) {
|
||||||
|
prop.put(entry.getKey(), ((UnaryOperator) entry.getValue()).apply(prop.get(entry.getKey())));
|
||||||
|
} else {
|
||||||
|
prop.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
taskListeners.forEach(taskListener -> taskListener.onPropertiesUpdate(stageProperties));
|
||||||
|
}
|
||||||
|
|
||||||
private boolean executeTask(Task<?> parentTask, Task<?> task) {
|
private boolean executeTask(Task<?> parentTask, Task<?> task) {
|
||||||
task.setCancelled(this::isCancelled);
|
task.setCancelled(this::isCancelled);
|
||||||
|
|
||||||
@ -161,6 +173,10 @@ public class CancellableTaskExecutor extends TaskExecutor {
|
|||||||
task.setState(Task.TaskState.EXECUTED);
|
task.setState(Task.TaskState.EXECUTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (task.properties != null) {
|
||||||
|
updateStageProperties(task.getStage(), task.properties);
|
||||||
|
}
|
||||||
|
|
||||||
Collection<? extends Task<?>> dependencies = task.getDependencies();
|
Collection<? extends Task<?>> dependencies = task.getDependencies();
|
||||||
boolean doDependenciesSucceeded = executeTasks(task, dependencies);
|
boolean doDependenciesSucceeded = executeTasks(task, dependencies);
|
||||||
Exception dependenciesException = dependencies.stream().map(Task::getException)
|
Exception dependenciesException = dependencies.stream().map(Task::getException)
|
||||||
@ -191,6 +207,10 @@ public class CancellableTaskExecutor extends TaskExecutor {
|
|||||||
Logging.LOG.log(Level.FINER, "Task finished: " + task.getName());
|
Logging.LOG.log(Level.FINER, "Task finished: " + task.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (task.properties != null) {
|
||||||
|
updateStageProperties(task.getStage(), task.properties);
|
||||||
|
}
|
||||||
|
|
||||||
task.onDone().fireEvent(new TaskEvent(this, task, false));
|
task.onDone().fireEvent(new TaskEvent(this, task, false));
|
||||||
taskListeners.forEach(it -> it.onFinished(task));
|
taskListeners.forEach(it -> it.onFinished(task));
|
||||||
} catch (RejectedExecutionException e) {
|
} catch (RejectedExecutionException e) {
|
||||||
|
@ -32,15 +32,13 @@ import org.jackhuang.hmcl.util.function.ExceptionalFunction;
|
|||||||
import org.jackhuang.hmcl.util.function.ExceptionalRunnable;
|
import org.jackhuang.hmcl.util.function.ExceptionalRunnable;
|
||||||
import org.jackhuang.hmcl.util.function.ExceptionalSupplier;
|
import org.jackhuang.hmcl.util.function.ExceptionalSupplier;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
import java.util.function.UnaryOperator;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -107,6 +105,13 @@ public abstract class Task<T> {
|
|||||||
return getStage() == null ? Collections.emptyList() : Collections.singletonList(getStage());
|
return getStage() == null ? Collections.emptyList() : Collections.singletonList(getStage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, Object> properties;
|
||||||
|
|
||||||
|
protected Map<String, Object> getProperties() {
|
||||||
|
if (properties == null) properties = new HashMap<>();
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
// state
|
// state
|
||||||
private TaskState state = TaskState.READY;
|
private TaskState state = TaskState.READY;
|
||||||
|
|
||||||
@ -802,6 +807,10 @@ public abstract class Task<T> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<T> withCounter() {
|
||||||
|
return new CountTask();
|
||||||
|
}
|
||||||
|
|
||||||
public static Task<Void> runAsync(ExceptionalRunnable<?> closure) {
|
public static Task<Void> runAsync(ExceptionalRunnable<?> closure) {
|
||||||
return runAsync(Schedulers.defaultScheduler(), closure);
|
return runAsync(Schedulers.defaultScheduler(), closure);
|
||||||
}
|
}
|
||||||
@ -1063,4 +1072,37 @@ public abstract class Task<T> {
|
|||||||
return Lang.merge(Task.this.getStages(), super.getStages());
|
return Lang.merge(Task.this.getStages(), super.getStages());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class CountTask extends Task<T> {
|
||||||
|
private final UnaryOperator<Integer> COUNTER = a -> {
|
||||||
|
int result = 0;
|
||||||
|
if (a != null) result += a;
|
||||||
|
return result + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Task<?>> getDependents() {
|
||||||
|
return Collections.singleton(Task.this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() throws Exception {
|
||||||
|
setResult(Task.this.getResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean doPostExecute() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postExecute() {
|
||||||
|
getProperties().put("count", COUNTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getStages() {
|
||||||
|
return Lang.merge(Task.this.getStages(), super.getStages());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,10 @@ package org.jackhuang.hmcl.task;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ public abstract class TaskExecutor {
|
|||||||
protected final AtomicBoolean cancelled = new AtomicBoolean(false);
|
protected final AtomicBoolean cancelled = new AtomicBoolean(false);
|
||||||
protected Exception exception;
|
protected Exception exception;
|
||||||
private final List<String> stages;
|
private final List<String> stages;
|
||||||
|
protected final Map<String, Map<String, Object>> stageProperties = new HashMap<>();
|
||||||
|
|
||||||
public TaskExecutor(Task<?> task) {
|
public TaskExecutor(Task<?> task) {
|
||||||
this.firstTask = task;
|
this.firstTask = task;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
package org.jackhuang.hmcl.task;
|
package org.jackhuang.hmcl.task;
|
||||||
|
|
||||||
import java.util.EventListener;
|
import java.util.EventListener;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -78,4 +79,7 @@ public abstract class TaskListener implements EventListener {
|
|||||||
*/
|
*/
|
||||||
public void onStop(boolean success, TaskExecutor executor) {
|
public void onStop(boolean success, TaskExecutor executor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onPropertiesUpdate(Map<String, Map<String, Object>> stageProperties) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user