mirror of
https://github.com/SKCraft/Launcher.git
synced 2024-11-27 12:46:22 +01:00
Add progress bars
This commit is contained in:
parent
badd91d2b8
commit
9640cd8dcf
@ -6,6 +6,7 @@ import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.skcraft.concurrency.DefaultProgress;
|
||||
import com.skcraft.concurrency.ObservableFuture;
|
||||
import com.skcraft.launcher.creator.model.creator.Pack;
|
||||
import com.skcraft.launcher.creator.plugin.MenuContext;
|
||||
import com.skcraft.launcher.creator.plugin.PluginMenu;
|
||||
@ -28,6 +29,7 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Consumer;
|
||||
@ -39,14 +41,17 @@ public class CurseModsDialog extends JDialog {
|
||||
private final CursePack cursePack;
|
||||
|
||||
private final JPanel panel = new JPanel(new BorderLayout(0, 5));
|
||||
private final JLabel title = new JLabel("Search for mods on CurseForge:");
|
||||
private final JTextField searchBox = new JTextField();
|
||||
private final JButton searchButton = new JButton("Search");
|
||||
private final JProgressBar progressBar = new JProgressBar(0, 1000);
|
||||
private final JList<CurseProject> searchPane = new JList<>();
|
||||
private final JList<AddedMod> selectedPane = new JList<>();
|
||||
private final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(searchPane), new JScrollPane(selectedPane));
|
||||
private final JButton addMod = new JButton("Add Mods >>");
|
||||
private final JButton removeMod = new JButton("<< Remove Mods");
|
||||
private final JButton done = new JButton("Done");
|
||||
private Timer activeTimer;
|
||||
|
||||
private final CurseProjectListRenderer projectRenderer = new CurseProjectListRenderer();
|
||||
|
||||
@ -94,10 +99,17 @@ public class CurseModsDialog extends JDialog {
|
||||
buttonsPanel.addElement(removeMod);
|
||||
buttonsPanel.setAlignmentX(CENTER_ALIGNMENT);
|
||||
|
||||
panel.add(searchBarPanel, BorderLayout.NORTH);
|
||||
LinedBoxPanel topPanel = new LinedBoxPanel(false);
|
||||
topPanel.addElement(title);
|
||||
topPanel.addElement(searchBarPanel);
|
||||
topPanel.addElement(progressBar);
|
||||
topPanel.setAlignmentX(CENTER_ALIGNMENT);
|
||||
|
||||
panel.add(topPanel, BorderLayout.NORTH);
|
||||
panel.add(Box.createVerticalStrut(5));
|
||||
panel.add(splitPane, BorderLayout.CENTER);
|
||||
panel.add(buttonsPanel, BorderLayout.SOUTH);
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
|
||||
|
||||
add(panel);
|
||||
|
||||
@ -105,24 +117,41 @@ public class CurseModsDialog extends JDialog {
|
||||
searchButton.addActionListener(e -> search());
|
||||
|
||||
addMod.addActionListener(e -> {
|
||||
ListenableFuture<Object> future = executor.submit(cursePack.addMany(searchPane.getSelectedValuesList()));
|
||||
CursePack.AddModsCall call = cursePack.addMany(searchPane.getSelectedValuesList());
|
||||
ListenableFuture<Object> future = executor.submit(call);
|
||||
|
||||
// TODO: Update a progress bar built in to the dialog.
|
||||
setProgressItem(new ObservableFuture<>(future, call));
|
||||
SwingHelper.addErrorDialogCallback(getOwner(), future);
|
||||
});
|
||||
|
||||
removeMod.addActionListener(e -> {
|
||||
ListenableFuture<Object> future = executor.submit(
|
||||
cursePack.removeMany(selectedPane.getSelectedValuesList()));
|
||||
CursePack.RemoveModsCall call = cursePack.removeMany(selectedPane.getSelectedValuesList());
|
||||
ListenableFuture<Object> future = executor.submit(call);
|
||||
|
||||
setProgressItem(new ObservableFuture<>(future, call));
|
||||
SwingHelper.addErrorDialogCallback(getOwner(), future);
|
||||
});
|
||||
|
||||
done.addActionListener(e -> dispose());
|
||||
}
|
||||
|
||||
private void setProgressItem(ObservableFuture<?> observable) {
|
||||
if (activeTimer != null) {
|
||||
activeTimer.stop();
|
||||
}
|
||||
|
||||
activeTimer = new Timer(400, e -> progressBar.setValue((int) (1000 * observable.getProgress())));
|
||||
activeTimer.setInitialDelay(0);
|
||||
activeTimer.start();
|
||||
|
||||
observable.addListener(() -> activeTimer.stop(), SwingExecutor.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (activeTimer != null) {
|
||||
activeTimer.stop();
|
||||
}
|
||||
// Let's make sure the image cache is emptied
|
||||
projectRenderer.clearCache();
|
||||
super.dispose();
|
||||
@ -173,16 +202,24 @@ public class CurseModsDialog extends JDialog {
|
||||
}
|
||||
|
||||
private static class CurseProjectListRenderer extends JLabel implements ListCellRenderer<ProjectHolder> {
|
||||
private HashMap<String, BufferedImage> cache;
|
||||
private final HashMap<String, BufferedImage> cache;
|
||||
private final HashSet<String> pending;
|
||||
|
||||
public CurseProjectListRenderer() {
|
||||
this.cache = new HashMap<>();
|
||||
this.pending = new HashSet<>();
|
||||
}
|
||||
|
||||
private BufferedImage getCachedIcon(String imgUrl, Runnable cb) {
|
||||
if (!cache.containsKey(imgUrl)) {
|
||||
if (pending.contains(imgUrl)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
pending.add(imgUrl);
|
||||
ImageWorker.downloadImage(imgUrl, img -> {
|
||||
cache.put(imgUrl, img);
|
||||
pending.remove(imgUrl);
|
||||
cb.run();
|
||||
});
|
||||
|
||||
@ -261,9 +298,11 @@ public class CurseModsDialog extends JDialog {
|
||||
ListenableFuture<?> future = ctx.getExecutor().submit(() -> {
|
||||
File target = new File(pack.getDirectory(), "cursemods");
|
||||
|
||||
if (target.isDirectory()) {
|
||||
scanner.walk(target);
|
||||
if (!target.isDirectory()) {
|
||||
target.mkdirs();
|
||||
}
|
||||
|
||||
scanner.walk(target);
|
||||
return null;
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.skcraft.plugin.curse.creator;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.skcraft.concurrency.ProgressObservable;
|
||||
import com.skcraft.concurrency.SettableProgress;
|
||||
import com.skcraft.launcher.creator.model.creator.Pack;
|
||||
@ -18,13 +20,13 @@ import java.util.concurrent.Callable;
|
||||
public class CursePack {
|
||||
@Getter private final CurseSearchResults searchResults = new CurseSearchResults();
|
||||
@Getter private final AddedModList modList = new AddedModList();
|
||||
private final ObjectMapper mapper;
|
||||
private final ObjectWriter writer;
|
||||
|
||||
private final String gameVersion;
|
||||
private final File curseModsDir;
|
||||
|
||||
public CursePack(ObjectMapper mapper, Pack pack) {
|
||||
this.mapper = mapper;
|
||||
this.writer = mapper.writerWithDefaultPrettyPrinter().without(SerializationFeature.WRITE_NULL_MAP_VALUES);
|
||||
this.gameVersion = pack.getCachedConfig().getGameVersion();
|
||||
this.curseModsDir = new File(pack.getDirectory(), "cursemods");
|
||||
}
|
||||
@ -41,7 +43,7 @@ public class CursePack {
|
||||
|
||||
File target = loadedMod.getDiskLocation(curseModsDir);
|
||||
log.info(String.format("Saving mod %s", target.getName()));
|
||||
mapper.writeValue(target, loadedMod.getMod());
|
||||
writer.writeValue(target, loadedMod.getMod());
|
||||
}
|
||||
|
||||
public void removeMod(AddedMod mod) throws IOException {
|
||||
@ -63,7 +65,7 @@ public class CursePack {
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private class AddModsCall implements Callable<Object>, ProgressObservable {
|
||||
class AddModsCall implements Callable<Object>, ProgressObservable {
|
||||
private final List<CurseProject> projects;
|
||||
private final SettableProgress progress = new SettableProgress("", -1);
|
||||
|
||||
@ -73,7 +75,7 @@ public class CursePack {
|
||||
int total = projects.size();
|
||||
|
||||
for (CurseProject project : projects) {
|
||||
progress.set(String.format("Adding mod %s", project.getName()), 100 * (double) current / total);
|
||||
progress.set(String.format("Adding mod %s", project.getName()), (double) current / total);
|
||||
|
||||
addMod(project);
|
||||
current++;
|
||||
@ -94,7 +96,7 @@ public class CursePack {
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private class RemoveModsCall implements Callable<Object>, ProgressObservable {
|
||||
class RemoveModsCall implements Callable<Object>, ProgressObservable {
|
||||
private final List<AddedMod> mods;
|
||||
private final SettableProgress progress = new SettableProgress("", -1);
|
||||
|
||||
@ -105,7 +107,7 @@ public class CursePack {
|
||||
|
||||
for (AddedMod mod : mods) {
|
||||
progress.set(String.format("Removing mod %s", mod.getProject().getName()),
|
||||
100 * (double) current / total);
|
||||
(double) current / total);
|
||||
|
||||
removeMod(mod);
|
||||
current++;
|
||||
|
Loading…
Reference in New Issue
Block a user