简化 VersionIconType 相关代码 (#2669)

This commit is contained in:
Glavo
2024-01-23 11:03:25 +08:00
committed by GitHub
parent 9bdf08af1e
commit 308086b876
7 changed files with 56 additions and 57 deletions

View File

@@ -43,7 +43,9 @@ import org.jackhuang.hmcl.util.versioning.VersionNumber;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
@@ -52,7 +54,6 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.newBuiltinImage;
import static org.jackhuang.hmcl.util.Logging.LOG; import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.Pair.pair; import static org.jackhuang.hmcl.util.Pair.pair;
@@ -263,36 +264,43 @@ public class HMCLGameRepository extends DefaultGameRepository {
public Image getVersionIconImage(String id) { public Image getVersionIconImage(String id) {
if (id == null || !isLoaded()) if (id == null || !isLoaded())
return newBuiltinImage("/assets/img/grass.png"); return VersionIconType.DEFAULT.getIcon();
VersionSetting vs = getLocalVersionSettingOrCreate(id); VersionSetting vs = getLocalVersionSettingOrCreate(id);
VersionIconType iconType = Optional.ofNullable(vs).map(VersionSetting::getVersionIcon).orElse(VersionIconType.DEFAULT); VersionIconType iconType = vs != null ? Lang.requireNonNullElse(vs.getVersionIcon(), VersionIconType.DEFAULT) : VersionIconType.DEFAULT;
if (iconType == VersionIconType.DEFAULT) { if (iconType == VersionIconType.DEFAULT) {
Version version = getVersion(id).resolve(this); Version version = getVersion(id).resolve(this);
File iconFile = getVersionIconFile(id); File iconFile = getVersionIconFile(id);
if (iconFile.exists()) if (iconFile.exists()) {
return new Image("file:" + iconFile.getAbsolutePath()); try (InputStream inputStream = new FileInputStream(iconFile)) {
else if (LibraryAnalyzer.isModded(this, version)) { return new Image(inputStream);
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to load version icon of " + id, e);
}
}
if (LibraryAnalyzer.isModded(this, version)) {
LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version); LibraryAnalyzer libraryAnalyzer = LibraryAnalyzer.analyze(version);
if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.FABRIC)) if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.FABRIC))
return newBuiltinImage("/assets/img/fabric.png"); return VersionIconType.FABRIC.getIcon();
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.FORGE)) else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.FORGE))
return newBuiltinImage("/assets/img/forge.png"); return VersionIconType.FORGE.getIcon();
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.NEO_FORGE)) else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.NEO_FORGE))
return newBuiltinImage("/assets/img/neoforge.png"); return VersionIconType.NEO_FORGE.getIcon();
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.QUILT)) else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.QUILT))
return newBuiltinImage("/assets/img/quilt.png"); return VersionIconType.QUILT.getIcon();
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.OPTIFINE)) else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.OPTIFINE))
return newBuiltinImage("/assets/img/command.png"); return VersionIconType.COMMAND.getIcon();
else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.LITELOADER)) else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.LITELOADER))
return newBuiltinImage("/assets/img/chicken.png"); return VersionIconType.CHICKEN.getIcon();
else else
return newBuiltinImage("/assets/img/furnace.png"); return VersionIconType.FURNACE.getIcon();
} else }
return newBuiltinImage("/assets/img/grass.png");
return VersionIconType.DEFAULT.getIcon();
} else { } else {
return newBuiltinImage(iconType.getResourceUrl()); return iconType.getIcon();
} }
} }

View File

@@ -17,6 +17,9 @@
*/ */
package org.jackhuang.hmcl.setting; package org.jackhuang.hmcl.setting;
import javafx.scene.image.Image;
import org.jackhuang.hmcl.ui.FXUtils;
public enum VersionIconType { public enum VersionIconType {
DEFAULT("/assets/img/grass.png"), DEFAULT("/assets/img/grass.png"),
@@ -39,7 +42,7 @@ public enum VersionIconType {
this.resourceUrl = resourceUrl; this.resourceUrl = resourceUrl;
} }
public String getResourceUrl() { public Image getIcon() {
return resourceUrl; return FXUtils.newBuiltinImage(resourceUrl);
} }
} }

View File

@@ -101,11 +101,10 @@ public final class FXUtils {
public static final String DEFAULT_MONOSPACE_FONT = OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? "Consolas" : "Monospace"; public static final String DEFAULT_MONOSPACE_FONT = OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? "Consolas" : "Monospace";
private static final Map<String, Image> builtinImageCache = new ConcurrentHashMap<>(); private static final Map<String, Image> builtinImageCache = new ConcurrentHashMap<>();
private static final Map<String, Path> remoteImageCache = new ConcurrentHashMap<>(); private static final Map<String, Path> remoteImageCache = new ConcurrentHashMap<>();
public static void shutdown() { public static void shutdown() {
for (Map.Entry<String, Path> entry: remoteImageCache.entrySet()) { for (Map.Entry<String, Path> entry : remoteImageCache.entrySet()) {
try { try {
Files.deleteIfExists(entry.getValue()); Files.deleteIfExists(entry.getValue());
} catch (IOException e) { } catch (IOException e) {
@@ -686,13 +685,11 @@ public final class FXUtils {
* @see ResourceNotFoundError * @see ResourceNotFoundError
*/ */
public static Image newBuiltinImage(String url) { public static Image newBuiltinImage(String url) {
return builtinImageCache.computeIfAbsent(url, s -> { try {
try { return builtinImageCache.computeIfAbsent(url, Image::new);
return new Image(s); } catch (IllegalArgumentException e) {
} catch (IllegalArgumentException e) { throw new ResourceNotFoundError("Cannot access image: " + url, e);
throw new ResourceNotFoundError("Cannot access image: " + s, e); }
}
});
} }
/** /**

View File

@@ -35,6 +35,7 @@ import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*; import javafx.scene.layout.*;
import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.setting.VersionIconType;
import org.jackhuang.hmcl.ui.construct.RipplerContainer; import org.jackhuang.hmcl.ui.construct.RipplerContainer;
import org.jackhuang.hmcl.util.i18n.I18n; import org.jackhuang.hmcl.util.i18n.I18n;
@@ -46,7 +47,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
*/ */
public class InstallerItem extends Control { public class InstallerItem extends Control {
private final String id; private final String id;
private final String imageUrl; private final VersionIconType iconType;
public final StringProperty libraryVersion = new SimpleStringProperty(); public final StringProperty libraryVersion = new SimpleStringProperty();
public final StringProperty incompatibleLibraryName = new SimpleStringProperty(); public final StringProperty incompatibleLibraryName = new SimpleStringProperty();
public final StringProperty dependencyName = new SimpleStringProperty(); public final StringProperty dependencyName = new SimpleStringProperty();
@@ -73,30 +74,30 @@ public class InstallerItem extends Control {
switch (id) { switch (id) {
case "game": case "game":
imageUrl = "/assets/img/grass.png"; iconType = VersionIconType.GRASS;
break; break;
case "fabric": case "fabric":
case "fabric-api": case "fabric-api":
imageUrl = "/assets/img/fabric.png"; iconType = VersionIconType.FABRIC;
break; break;
case "forge": case "forge":
imageUrl = "/assets/img/forge.png"; iconType = VersionIconType.FORGE;
break; break;
case "liteloader": case "liteloader":
imageUrl = "/assets/img/chicken.png"; iconType = VersionIconType.CHICKEN;
break; break;
case "optifine": case "optifine":
imageUrl = "/assets/img/command.png"; iconType = VersionIconType.COMMAND;
break; break;
case "quilt": case "quilt":
case "quilt-api": case "quilt-api":
imageUrl = "/assets/img/quilt.png"; iconType = VersionIconType.QUILT;
break; break;
case "neoforge": case "neoforge":
imageUrl = "/assets/img/neoforge.png"; iconType = VersionIconType.NEO_FORGE;
break; break;
default: default:
imageUrl = null; iconType = null;
break; break;
} }
} }
@@ -221,8 +222,8 @@ public class InstallerItem extends Control {
pane.pseudoClassStateChanged(LIST_ITEM, control.style == Style.LIST_ITEM); pane.pseudoClassStateChanged(LIST_ITEM, control.style == Style.LIST_ITEM);
pane.pseudoClassStateChanged(CARD, control.style == Style.CARD); pane.pseudoClassStateChanged(CARD, control.style == Style.CARD);
if (control.imageUrl != null) { if (control.iconType != null) {
ImageView view = new ImageView(FXUtils.newBuiltinImage(control.imageUrl)); ImageView view = new ImageView(control.iconType.getIcon());
Node node = FXUtils.limitingSize(view, 32, 32); Node node = FXUtils.limitingSize(view, 32, 32);
node.setMouseTransparent(true); node.setMouseTransparent(true);
node.getStyleClass().add("installer-item-image"); node.getStyleClass().add("installer-item-image");

View File

@@ -26,7 +26,6 @@ import javafx.beans.InvalidationListener;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.ListCell; import javafx.scene.control.ListCell;
import javafx.scene.image.Image;
import javafx.scene.layout.*; import javafx.scene.layout.*;
import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.download.DownloadProvider;
import org.jackhuang.hmcl.download.RemoteVersion; import org.jackhuang.hmcl.download.RemoteVersion;
@@ -42,7 +41,6 @@ import org.jackhuang.hmcl.download.quilt.QuiltAPIRemoteVersion;
import org.jackhuang.hmcl.download.quilt.QuiltRemoteVersion; import org.jackhuang.hmcl.download.quilt.QuiltRemoteVersion;
import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.setting.VersionIconType; import org.jackhuang.hmcl.setting.VersionIconType;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.animation.ContainerAnimations; import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
import org.jackhuang.hmcl.ui.animation.TransitionPane; import org.jackhuang.hmcl.ui.animation.TransitionPane;
@@ -56,7 +54,6 @@ import org.jackhuang.hmcl.ui.wizard.WizardPage;
import org.jackhuang.hmcl.util.HMCLService; import org.jackhuang.hmcl.util.HMCLService;
import org.jackhuang.hmcl.util.Holder; import org.jackhuang.hmcl.util.Holder;
import java.util.EnumMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -182,8 +179,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
btnRefresh.setGraphic(wrap(SVG.REFRESH.createIcon(Theme.blackFill(), -1, -1))); btnRefresh.setGraphic(wrap(SVG.REFRESH.createIcon(Theme.blackFill(), -1, -1)));
Holder<RemoteVersionListCell> lastCell = new Holder<>(); Holder<RemoteVersionListCell> lastCell = new Holder<>();
EnumMap<VersionIconType, Image> icons = new EnumMap<>(VersionIconType.class); list.setCellFactory(listView -> new RemoteVersionListCell(lastCell));
list.setCellFactory(listView -> new RemoteVersionListCell(lastCell, icons));
list.setOnMouseClicked(e -> { list.setOnMouseClicked(e -> {
if (list.getSelectionModel().getSelectedIndex() < 0) if (list.getSelectionModel().getSelectedIndex() < 0)
@@ -276,21 +272,15 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
final StackPane pane = new StackPane(); final StackPane pane = new StackPane();
private final Holder<RemoteVersionListCell> lastCell; private final Holder<RemoteVersionListCell> lastCell;
private final EnumMap<VersionIconType, Image> icons;
RemoteVersionListCell(Holder<RemoteVersionListCell> lastCell, EnumMap<VersionIconType, Image> icons) { RemoteVersionListCell(Holder<RemoteVersionListCell> lastCell) {
this.lastCell = lastCell; this.lastCell = lastCell;
this.icons = icons;
pane.getStyleClass().add("md-list-cell"); pane.getStyleClass().add("md-list-cell");
StackPane.setMargin(content, new Insets(10, 16, 10, 16)); StackPane.setMargin(content, new Insets(10, 16, 10, 16));
pane.getChildren().setAll(ripplerContainer); pane.getChildren().setAll(ripplerContainer);
} }
private Image getIcon(VersionIconType type) {
return icons.computeIfAbsent(type, iconType -> FXUtils.newBuiltinImage(iconType.getResourceUrl()));
}
@Override @Override
public void updateItem(RemoteVersion remoteVersion, boolean empty) { public void updateItem(RemoteVersion remoteVersion, boolean empty) {
super.updateItem(remoteVersion, empty); super.updateItem(remoteVersion, empty);
@@ -317,15 +307,15 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
switch (remoteVersion.getVersionType()) { switch (remoteVersion.getVersionType()) {
case RELEASE: case RELEASE:
content.getTags().setAll(i18n("version.game.release")); content.getTags().setAll(i18n("version.game.release"));
content.setImage(getIcon(VersionIconType.GRASS)); content.setImage(VersionIconType.GRASS.getIcon());
break; break;
case SNAPSHOT: case SNAPSHOT:
content.getTags().setAll(i18n("version.game.snapshot")); content.getTags().setAll(i18n("version.game.snapshot"));
content.setImage(getIcon(VersionIconType.COMMAND)); content.setImage(VersionIconType.COMMAND.getIcon());
break; break;
default: default:
content.getTags().setAll(i18n("version.game.old")); content.getTags().setAll(i18n("version.game.old"));
content.setImage(getIcon(VersionIconType.CRAFT_TABLE)); content.setImage(VersionIconType.CRAFT_TABLE.getIcon());
break; break;
} }
} else { } else {
@@ -345,7 +335,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres
else else
iconType = null; iconType = null;
content.setImage(iconType != null ? getIcon(iconType) : null); content.setImage(iconType != null ? iconType.getIcon() : null);
if (content.getSubtitle() == null) if (content.getSubtitle() == null)
content.setSubtitle(remoteVersion.getGameVersion()); content.setSubtitle(remoteVersion.getGameVersion());
else else

View File

@@ -23,6 +23,7 @@ import javafx.scene.image.ImageView;
import org.jackhuang.hmcl.event.Event; import org.jackhuang.hmcl.event.Event;
import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Profiles; import org.jackhuang.hmcl.setting.Profiles;
import org.jackhuang.hmcl.setting.VersionIconType;
import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.WeakListenerHolder; import org.jackhuang.hmcl.ui.WeakListenerHolder;
import org.jackhuang.hmcl.ui.construct.AdvancedListItem; import org.jackhuang.hmcl.ui.construct.AdvancedListItem;
@@ -30,7 +31,6 @@ import org.jackhuang.hmcl.util.Pair;
import java.util.function.Consumer; import java.util.function.Consumer;
import static org.jackhuang.hmcl.ui.FXUtils.newBuiltinImage;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class GameAdvancedListItem extends AdvancedListItem { public class GameAdvancedListItem extends AdvancedListItem {
@@ -72,7 +72,7 @@ public class GameAdvancedListItem extends AdvancedListItem {
Tooltip.uninstall(this,tooltip); Tooltip.uninstall(this,tooltip);
setTitle(i18n("version.empty")); setTitle(i18n("version.empty"));
setSubtitle(i18n("version.empty.add")); setSubtitle(i18n("version.empty.add"));
imageView.setImage(newBuiltinImage("/assets/img/grass.png")); imageView.setImage(VersionIconType.DEFAULT.getIcon());
tooltip.setText(""); tooltip.setText("");
} }
} }

View File

@@ -104,7 +104,7 @@ public class VersionIconDialog extends DialogPane {
} }
private Node createIcon(VersionIconType type) { private Node createIcon(VersionIconType type) {
ImageView imageView = new ImageView(FXUtils.newBuiltinImage(type.getResourceUrl())); ImageView imageView = new ImageView(type.getIcon());
imageView.setMouseTransparent(true); imageView.setMouseTransparent(true);
RipplerContainer container = new RipplerContainer(imageView); RipplerContainer container = new RipplerContainer(imageView);
FXUtils.setLimitWidth(container, 36); FXUtils.setLimitWidth(container, 36);