-
Notifications
You must be signed in to change notification settings - Fork 111
Description
At the moment the design for the ProgressBar-Library is such that the ProgressState must actively be changed by calling library code - either implicitly via some wrapper or by using stepBy(), stepTo() etc.
However, in some cases it might be more performant and easier if the ProgressBar would pick up the changing progress state right before rendering from some source that must implement a corresponding interface like:
public interface GSProgressUpdate {
public long current();
public long max();
}In some cases this is more efficient than actively updating the progress state via stepBy(), stepTo(), since GSProgressUpdate would only be consulted right before rendering. I was able to implement this as a sort of "workaround" without changing existing library code. But it would be nicer if such an approach was already integrated in the library as an option. Here is a renderer that uses the above give interface:
private static class GSProgressBarRenderer extends DefaultProgressBarRenderer {
private final GSProgressUpdate progressUpdate;
private ProgressBar progressBar;
protected GSProgressBarRenderer(String unitName, GSProgressUpdate progressUpdateProvider) {
super(ProgressBarStyle.ASCII, unitName, 1, false, null, null, true, GSProgressBarRenderer::linearEta);
this.progressUpdate = progressUpdateProvider;
}
public void setProgressBar(ProgressBar progressBar) {
this.progressBar = progressBar;
}
@Override
public String render(ProgressState progress, int maxLength) {
if (progressUpdate != null) {
progressBar.maxHint(progressUpdate.max());
progressBar.stepTo(progressUpdate.current());
}
return super.render(progress, maxLength);
}
static Optional<Duration> linearEta(ProgressState progress) {
if (progress.getMax() <= 0 || progress.isIndefinite()) return Optional.empty();
else if (progress.getCurrent() - progress.getStart() == 0) return Optional.empty();
else return Optional.of(
progress.getElapsedAfterStart()
.dividedBy(progress.getCurrent() - progress.getStart())
.multipliedBy(progress.getMax() - progress.getCurrent())
);
}
}Creating a matching progress bar in the context of this workaround as follows:
public static ProgressBar newGSProgressBar(String task, int updateIntervalMillis, String unitName, GSProgressUpdate progressUpdate, Log log) {
GSProgressBarRenderer renderer = new GSProgressBarRenderer(unitName, progressUpdate);
ProgressBarBuilder progressBarBuilder = new ProgressBarBuilder().
setTaskName(task).setUpdateIntervalMillis(updateIntervalMillis).
setUnit(unitName, 1).setRenderer(renderer).setMaxRenderedLength(100).continuousUpdate();
if (log != null && log.isInfoEnabled()) {
progressBarBuilder.setConsumer(new DelegatingProgressBarConsumer(log::info));
}
ProgressBar progressBar = progressBarBuilder.build();
renderer.setProgressBar(progressBar);
return progressBar;
}