feat: display new version of updated modpack. Closes #748.

This commit is contained in:
yuhuihuang
2020-07-19 15:19:53 +08:00
parent d6859d1956
commit 4ce0a83845
15 changed files with 119 additions and 17 deletions

View File

@@ -77,7 +77,7 @@ public final class HMCLModpackInstallTask extends Task<Void> {
} catch (JsonParseException | IOException ignore) { } catch (JsonParseException | IOException ignore) {
} }
dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/minecraft", it -> !"pack.json".equals(it), config)); dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/minecraft", it -> !"pack.json".equals(it), config));
dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/minecraft", modpack, MODPACK_TYPE, repository.getModpackConfiguration(name)).withStage("hmcl.modpack")); dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/minecraft", modpack, MODPACK_TYPE, modpack.getName(), modpack.getVersion(), repository.getModpackConfiguration(name)).withStage("hmcl.modpack"));
} }
@Override @Override

View File

@@ -17,15 +17,19 @@
*/ */
package org.jackhuang.hmcl.ui.construct; package org.jackhuang.hmcl.ui.construct;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.util.StringUtils;
public class TwoLineListItem extends VBox { public class TwoLineListItem extends VBox {
private static final String DEFAULT_STYLE_CLASS = "two-line-list-item"; private static final String DEFAULT_STYLE_CLASS = "two-line-list-item";
private final StringProperty title = new SimpleStringProperty(this, "title"); private final StringProperty title = new SimpleStringProperty(this, "title");
private final StringProperty tag = new SimpleStringProperty(this, "tag");
private final StringProperty subtitle = new SimpleStringProperty(this, "subtitle"); private final StringProperty subtitle = new SimpleStringProperty(this, "subtitle");
public TwoLineListItem(String titleString, String subtitleString) { public TwoLineListItem(String titleString, String subtitleString) {
@@ -37,15 +41,28 @@ public class TwoLineListItem extends VBox {
public TwoLineListItem() { public TwoLineListItem() {
setMouseTransparent(true); setMouseTransparent(true);
HBox firstLine = new HBox();
Label lblTitle = new Label(); Label lblTitle = new Label();
lblTitle.getStyleClass().add("title"); lblTitle.getStyleClass().add("title");
lblTitle.textProperty().bind(title); lblTitle.textProperty().bind(title);
Label lblTag = new Label();
lblTag.getStyleClass().add("tag");
lblTag.textProperty().bind(tag);
lblTag.visibleProperty().bind(Bindings.createBooleanBinding(
() -> StringUtils.isNotBlank(tag.getValue()),
tag));
firstLine.getChildren().addAll(lblTitle, lblTag);
Label lblSubtitle = new Label(); Label lblSubtitle = new Label();
lblSubtitle.getStyleClass().add("subtitle"); lblSubtitle.getStyleClass().add("subtitle");
lblSubtitle.textProperty().bind(subtitle); lblSubtitle.textProperty().bind(subtitle);
getChildren().setAll(lblTitle, lblSubtitle); getChildren().setAll(firstLine, lblSubtitle);
getStyleClass().add(DEFAULT_STYLE_CLASS); getStyleClass().add(DEFAULT_STYLE_CLASS);
} }
@@ -73,6 +90,18 @@ public class TwoLineListItem extends VBox {
this.subtitle.set(subtitle); this.subtitle.set(subtitle);
} }
public String getTag() {
return tag.get();
}
public StringProperty tagProperty() {
return tag;
}
public void setTag(String tag) {
this.tag.set(tag);
}
@Override @Override
public String toString() { public String toString() {
return getTitle(); return getTitle();

View File

@@ -121,7 +121,7 @@ public final class LocalModpackPage extends StackPane implements WizardPage {
lblModpackLocation.setText(selectedFile.getAbsolutePath()); lblModpackLocation.setText(selectedFile.getAbsolutePath());
if (!name.isPresent()) { if (!name.isPresent()) {
txtModpackName.setText(manifest.getName() + (StringUtils.isBlank(manifest.getVersion()) ? "" : "-" + manifest.getVersion())); txtModpackName.setText(manifest.getName());
txtModpackName.getValidators().addAll( txtModpackName.getValidators().addAll(
new Validator(i18n("install.new_game.already_exists"), str -> !profile.getRepository().hasVersion(str) && StringUtils.isNotBlank(str)), new Validator(i18n("install.new_game.already_exists"), str -> !profile.getRepository().hasVersion(str) && StringUtils.isNotBlank(str)),
new Validator(i18n("version.forbidden_name"), str -> !profile.getRepository().forbidsVersion(str)) new Validator(i18n("version.forbidden_name"), str -> !profile.getRepository().forbidsVersion(str))

View File

@@ -101,7 +101,7 @@ public class RemoteModpackPage extends StackPane implements WizardPage {
lblAuthor.setText(manifest.getAuthor()); lblAuthor.setText(manifest.getAuthor());
if (!name.isPresent()) { if (!name.isPresent()) {
txtModpackName.setText(manifest.getName() + (StringUtils.isBlank(manifest.getVersion()) ? "" : "-" + manifest.getVersion())); txtModpackName.setText(manifest.getName());
txtModpackName.getValidators().addAll( txtModpackName.getValidators().addAll(
new Validator(i18n("install.new_game.already_exists"), str -> !profile.getRepository().hasVersion(str) && StringUtils.isNotBlank(str)), new Validator(i18n("install.new_game.already_exists"), str -> !profile.getRepository().hasVersion(str) && StringUtils.isNotBlank(str)),
new Validator(i18n("version.forbidden_name"), str -> !profile.getRepository().forbidsVersion(str)) new Validator(i18n("version.forbidden_name"), str -> !profile.getRepository().forbidsVersion(str))

View File

@@ -27,16 +27,20 @@ import javafx.scene.control.Skin;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.game.GameVersion; import org.jackhuang.hmcl.game.GameVersion;
import org.jackhuang.hmcl.mod.ModpackConfiguration;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.util.i18n.I18n; import org.jackhuang.hmcl.util.i18n.I18n;
import java.io.IOException;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.MINECRAFT; import static org.jackhuang.hmcl.download.LibraryAnalyzer.LibraryType.MINECRAFT;
import static org.jackhuang.hmcl.util.Lang.handleUncaught; import static org.jackhuang.hmcl.util.Lang.handleUncaught;
import static org.jackhuang.hmcl.util.Lang.threadPool; import static org.jackhuang.hmcl.util.Lang.threadPool;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.StringUtils.removePrefix; import static org.jackhuang.hmcl.util.StringUtils.removePrefix;
import static org.jackhuang.hmcl.util.StringUtils.removeSuffix; import static org.jackhuang.hmcl.util.StringUtils.removeSuffix;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -48,6 +52,7 @@ public class GameItem extends Control {
private final Profile profile; private final Profile profile;
private final String version; private final String version;
private final StringProperty title = new SimpleStringProperty(); private final StringProperty title = new SimpleStringProperty();
private final StringProperty tag = new SimpleStringProperty();
private final StringProperty subtitle = new SimpleStringProperty(); private final StringProperty subtitle = new SimpleStringProperty();
private final ObjectProperty<Image> image = new SimpleObjectProperty<>(); private final ObjectProperty<Image> image = new SimpleObjectProperty<>();
@@ -75,6 +80,17 @@ public class GameItem extends Control {
}, Platform::runLater) }, Platform::runLater)
.exceptionally(handleUncaught); .exceptionally(handleUncaught);
CompletableFuture.runAsync(() -> {
try {
ModpackConfiguration<Void> config = profile.getRepository().readModpackConfiguration(version);
if (config == null) return;
tag.set(config.getVersion());
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to read modpack configuration from ", e);
}
}, Platform::runLater)
.exceptionally(handleUncaught);
title.set(id); title.set(id);
image.set(profile.getRepository().getVersionIconImage(version)); image.set(profile.getRepository().getVersionIconImage(version));
} }
@@ -96,6 +112,10 @@ public class GameItem extends Control {
return title; return title;
} }
public StringProperty tagProperty() {
return tag;
}
public StringProperty subtitleProperty() { public StringProperty subtitleProperty() {
return subtitle; return subtitle;
} }

View File

@@ -45,6 +45,7 @@ public class GameItemSkin extends SkinBase<GameItem> {
TwoLineListItem item = new TwoLineListItem(); TwoLineListItem item = new TwoLineListItem();
item.titleProperty().bind(skinnable.titleProperty()); item.titleProperty().bind(skinnable.titleProperty());
item.tagProperty().bind(skinnable.tagProperty());
item.subtitleProperty().bind(skinnable.subtitleProperty()); item.subtitleProperty().bind(skinnable.subtitleProperty());
BorderPane.setAlignment(item, Pos.CENTER); BorderPane.setAlignment(item, Pos.CENTER);
center.getChildren().setAll(imageView, item); center.getChildren().setAll(imageView, item);

View File

@@ -114,15 +114,26 @@
-fx-padding: 4 0 4 0; -fx-padding: 4 0 4 0;
} }
.two-line-list-item > .title { .two-line-list-item HBox {
-fx-spacing: 8;
-fx-alignment: center-left;
}
.two-line-list-item .title {
-fx-text-fill: #292929; -fx-text-fill: #292929;
-fx-font-size: 15px; -fx-font-size: 15px;
} }
.two-line-list-item > .subtitle { .two-line-list-item .subtitle {
-fx-text-fill: rgba(0, 0, 0, 0.5); -fx-text-fill: rgba(0, 0, 0, 0.5);
} }
.two-line-list-item .tag {
-fx-text-fill: -fx-base-color;
-fx-background-color: -fx-base-rippler-color;
-fx-padding: 2;
}
.bubble { .bubble {
-fx-background-color: rgba(0, 0, 0, 0.5); -fx-background-color: rgba(0, 0, 0, 0.5);
-fx-background-radius: 2px; -fx-background-radius: 2px;

View File

@@ -18,6 +18,7 @@
package org.jackhuang.hmcl.game; package org.jackhuang.hmcl.game;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.download.MaintainTask; import org.jackhuang.hmcl.download.MaintainTask;
import org.jackhuang.hmcl.download.game.VersionJsonSaveTask; import org.jackhuang.hmcl.download.game.VersionJsonSaveTask;
import org.jackhuang.hmcl.event.Event; import org.jackhuang.hmcl.event.Event;
@@ -29,11 +30,13 @@ import org.jackhuang.hmcl.event.RefreshingVersionsEvent;
import org.jackhuang.hmcl.event.RemoveVersionEvent; import org.jackhuang.hmcl.event.RemoveVersionEvent;
import org.jackhuang.hmcl.event.RenameVersionEvent; import org.jackhuang.hmcl.event.RenameVersionEvent;
import org.jackhuang.hmcl.mod.ModManager; import org.jackhuang.hmcl.mod.ModManager;
import org.jackhuang.hmcl.mod.ModpackConfiguration;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.ToStringBuilder; import org.jackhuang.hmcl.util.ToStringBuilder;
import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -437,6 +440,22 @@ public class DefaultGameRepository implements GameRepository {
return new File(getVersionRoot(version), "modpack.json"); return new File(getVersionRoot(version), "modpack.json");
} }
/**
* read modpack configuration for a version.
* @param version version installed as modpack
* @param <M> manifest type of ModpackConfiguration
* @return modpack configuration object, or null if this version is not a modpack.
* @throws VersionNotFoundException if version does not exist.
* @throws IOException if an i/o error occurs.
*/
@Nullable
public <M> ModpackConfiguration<M> readModpackConfiguration(String version) throws IOException, VersionNotFoundException {
if (!hasVersion(version)) throw new VersionNotFoundException(version);
File file = getModpackConfiguration(version);
if (!file.exists()) return null;
return JsonUtils.GSON.fromJson(FileUtils.readText(file), new TypeToken<ModpackConfiguration<M>>(){}.getType());
}
public boolean isModpack(String version) { public boolean isModpack(String version) {
return getModpackConfiguration(version).exists(); return getModpackConfiguration(version).exists();
} }

View File

@@ -41,14 +41,18 @@ public final class MinecraftInstanceTask<T> extends Task<Void> {
private final File jsonFile; private final File jsonFile;
private final T manifest; private final T manifest;
private final String type; private final String type;
private final String name;
private final String version;
public MinecraftInstanceTask(File zipFile, Charset encoding, String subDirectory, T manifest, String type, File jsonFile) { public MinecraftInstanceTask(File zipFile, Charset encoding, String subDirectory, T manifest, String type, String name, String version, File jsonFile) {
this.zipFile = zipFile; this.zipFile = zipFile;
this.encoding = encoding; this.encoding = encoding;
this.subDirectory = FileUtils.normalizePath(subDirectory); this.subDirectory = FileUtils.normalizePath(subDirectory);
this.manifest = manifest; this.manifest = manifest;
this.jsonFile = jsonFile; this.jsonFile = jsonFile;
this.type = type; this.type = type;
this.name = name;
this.version = version;
} }
@Override @Override
@@ -69,6 +73,6 @@ public final class MinecraftInstanceTask<T> extends Task<Void> {
}); });
} }
FileUtils.writeText(jsonFile, JsonUtils.GSON.toJson(new ModpackConfiguration<>(manifest, type, overrides))); FileUtils.writeText(jsonFile, JsonUtils.GSON.toJson(new ModpackConfiguration<>(manifest, type, name, version, overrides)));
} }
} }

View File

@@ -20,6 +20,7 @@ package org.jackhuang.hmcl.mod;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import org.jackhuang.hmcl.util.Immutable; import org.jackhuang.hmcl.util.Immutable;
import org.jackhuang.hmcl.util.gson.Validation; import org.jackhuang.hmcl.util.gson.Validation;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -30,15 +31,19 @@ public final class ModpackConfiguration<T> implements Validation {
private final T manifest; private final T manifest;
private final String type; private final String type;
private final String name;
private final String version;
private final List<FileInformation> overrides; private final List<FileInformation> overrides;
public ModpackConfiguration() { public ModpackConfiguration() {
this(null, null, Collections.emptyList()); this(null, null, "", null, Collections.emptyList());
} }
public ModpackConfiguration(T manifest, String type, List<FileInformation> overrides) { public ModpackConfiguration(T manifest, String type, String name, String version, List<FileInformation> overrides) {
this.manifest = manifest; this.manifest = manifest;
this.type = type; this.type = type;
this.name = name;
this.version = version;
this.overrides = new ArrayList<>(overrides); this.overrides = new ArrayList<>(overrides);
} }
@@ -50,12 +55,25 @@ public final class ModpackConfiguration<T> implements Validation {
return type; return type;
} }
public String getName() {
return name;
}
@Nullable
public String getVersion() {
return version;
}
public ModpackConfiguration<T> setManifest(T manifest) { public ModpackConfiguration<T> setManifest(T manifest) {
return new ModpackConfiguration<>(manifest, type, overrides); return new ModpackConfiguration<>(manifest, type, name, version, overrides);
} }
public ModpackConfiguration<T> setOverrides(List<FileInformation> overrides) { public ModpackConfiguration<T> setOverrides(List<FileInformation> overrides) {
return new ModpackConfiguration<>(manifest, type, overrides); return new ModpackConfiguration<>(manifest, type, name, version, overrides);
}
public ModpackConfiguration<T> setVersion(String version) {
return new ModpackConfiguration<>(manifest, type, name, version, overrides);
} }
public List<FileInformation> getOverrides() { public List<FileInformation> getOverrides() {

View File

@@ -107,7 +107,7 @@ public final class CurseInstallTask extends Task<Void> {
} }
this.config = config; this.config = config;
dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), manifest.getOverrides(), any -> true, config).withStage("hmcl.modpack")); dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), manifest.getOverrides(), any -> true, config).withStage("hmcl.modpack"));
dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), manifest.getOverrides(), manifest, MODPACK_TYPE, repository.getModpackConfiguration(name)).withStage("hmcl.modpack")); dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), manifest.getOverrides(), manifest, MODPACK_TYPE, manifest.getName(), manifest.getVersion(), repository.getModpackConfiguration(name)).withStage("hmcl.modpack"));
dependencies.add(new CurseCompletionTask(dependencyManager, name, manifest).withStage("hmcl.modpack.download")); dependencies.add(new CurseCompletionTask(dependencyManager, name, manifest).withStage("hmcl.modpack.download"));
} }

View File

@@ -131,7 +131,7 @@ public final class MultiMCModpackInstallTask extends Task<Void> {
dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/" + manifest.getName() + "/minecraft", any -> true, config).withStage("hmcl.modpack")); dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/" + manifest.getName() + "/minecraft", any -> true, config).withStage("hmcl.modpack"));
} }
dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/" + manifest.getName() + "/minecraft", manifest, MODPACK_TYPE, repository.getModpackConfiguration(name)).withStage("hmcl.modpack")); dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/" + manifest.getName() + "/minecraft", manifest, MODPACK_TYPE, manifest.getName(), null, repository.getModpackConfiguration(name)).withStage("hmcl.modpack"));
} }
@Override @Override

View File

@@ -158,6 +158,6 @@ public class ServerModpackCompletionTask extends Task<Void> {
public void postExecute() throws Exception { public void postExecute() throws Exception {
if (manifest == null || StringUtils.isBlank(manifest.getManifest().getFileApi())) return; if (manifest == null || StringUtils.isBlank(manifest.getManifest().getFileApi())) return;
File manifestFile = repository.getModpackConfiguration(version); File manifestFile = repository.getModpackConfiguration(version);
FileUtils.writeText(manifestFile, JsonUtils.GSON.toJson(new ModpackConfiguration<>(remoteManifest, this.manifest.getType(), remoteManifest.getFiles()))); FileUtils.writeText(manifestFile, JsonUtils.GSON.toJson(new ModpackConfiguration<>(remoteManifest, this.manifest.getType(), this.manifest.getName(), this.manifest.getVersion(), remoteManifest.getFiles())));
} }
} }

View File

@@ -82,7 +82,7 @@ public class ServerModpackLocalInstallTask extends Task<Void> {
} catch (JsonParseException | IOException ignore) { } catch (JsonParseException | IOException ignore) {
} }
dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/overrides", any -> true, config).withStage("hmcl.modpack")); dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/overrides", any -> true, config).withStage("hmcl.modpack"));
dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/overrides", manifest, MODPACK_TYPE, repository.getModpackConfiguration(name)).withStage("hmcl.modpack")); dependents.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/overrides", manifest, MODPACK_TYPE, modpack.getName(), modpack.getVersion(), repository.getModpackConfiguration(name)).withStage("hmcl.modpack"));
} }
@Override @Override

View File

@@ -88,7 +88,7 @@ public class ServerModpackRemoteInstallTask extends Task<Void> {
@Override @Override
public void execute() throws Exception { public void execute() throws Exception {
dependencies.add(new ServerModpackCompletionTask(dependency, name, new ModpackConfiguration<>(manifest, MODPACK_TYPE, Collections.emptyList()))); dependencies.add(new ServerModpackCompletionTask(dependency, name, new ModpackConfiguration<>(manifest, MODPACK_TYPE, manifest.getName(), manifest.getVersion(), Collections.emptyList())));
} }
public static final String MODPACK_TYPE = "Server"; public static final String MODPACK_TYPE = "Server";