diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index b1b0b1170..465750ef7 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -43,7 +43,9 @@ import org.jackhuang.hmcl.util.versioning.VersionNumber; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -52,7 +54,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; 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.Pair.pair; @@ -263,36 +264,43 @@ public class HMCLGameRepository extends DefaultGameRepository { public Image getVersionIconImage(String id) { if (id == null || !isLoaded()) - return newBuiltinImage("/assets/img/grass.png"); + return VersionIconType.DEFAULT.getIcon(); 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) { Version version = getVersion(id).resolve(this); File iconFile = getVersionIconFile(id); - if (iconFile.exists()) - return new Image("file:" + iconFile.getAbsolutePath()); - else if (LibraryAnalyzer.isModded(this, version)) { + if (iconFile.exists()) { + try (InputStream inputStream = new FileInputStream(iconFile)) { + 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); if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.FABRIC)) - return newBuiltinImage("/assets/img/fabric.png"); + return VersionIconType.FABRIC.getIcon(); 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)) - return newBuiltinImage("/assets/img/neoforge.png"); + return VersionIconType.NEO_FORGE.getIcon(); else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.QUILT)) - return newBuiltinImage("/assets/img/quilt.png"); + return VersionIconType.QUILT.getIcon(); else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.OPTIFINE)) - return newBuiltinImage("/assets/img/command.png"); + return VersionIconType.COMMAND.getIcon(); else if (libraryAnalyzer.has(LibraryAnalyzer.LibraryType.LITELOADER)) - return newBuiltinImage("/assets/img/chicken.png"); + return VersionIconType.CHICKEN.getIcon(); else - return newBuiltinImage("/assets/img/furnace.png"); - } else - return newBuiltinImage("/assets/img/grass.png"); + return VersionIconType.FURNACE.getIcon(); + } + + return VersionIconType.DEFAULT.getIcon(); } else { - return newBuiltinImage(iconType.getResourceUrl()); + return iconType.getIcon(); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionIconType.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionIconType.java index 1a9c41869..d9b995e9e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionIconType.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionIconType.java @@ -17,6 +17,9 @@ */ package org.jackhuang.hmcl.setting; +import javafx.scene.image.Image; +import org.jackhuang.hmcl.ui.FXUtils; + public enum VersionIconType { DEFAULT("/assets/img/grass.png"), @@ -39,7 +42,7 @@ public enum VersionIconType { this.resourceUrl = resourceUrl; } - public String getResourceUrl() { - return resourceUrl; + public Image getIcon() { + return FXUtils.newBuiltinImage(resourceUrl); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java index 92b5ec2ec..a3c09efa0 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java @@ -101,11 +101,10 @@ public final class FXUtils { public static final String DEFAULT_MONOSPACE_FONT = OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? "Consolas" : "Monospace"; private static final Map builtinImageCache = new ConcurrentHashMap<>(); - private static final Map remoteImageCache = new ConcurrentHashMap<>(); public static void shutdown() { - for (Map.Entry entry: remoteImageCache.entrySet()) { + for (Map.Entry entry : remoteImageCache.entrySet()) { try { Files.deleteIfExists(entry.getValue()); } catch (IOException e) { @@ -686,13 +685,11 @@ public final class FXUtils { * @see ResourceNotFoundError */ public static Image newBuiltinImage(String url) { - return builtinImageCache.computeIfAbsent(url, s -> { - try { - return new Image(s); - } catch (IllegalArgumentException e) { - throw new ResourceNotFoundError("Cannot access image: " + s, e); - } - }); + try { + return builtinImageCache.computeIfAbsent(url, Image::new); + } catch (IllegalArgumentException e) { + throw new ResourceNotFoundError("Cannot access image: " + url, e); + } } /** diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java index 7bc6a2b82..098317374 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java @@ -35,6 +35,7 @@ import javafx.scene.input.MouseEvent; import javafx.scene.layout.*; import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.setting.Theme; +import org.jackhuang.hmcl.setting.VersionIconType; import org.jackhuang.hmcl.ui.construct.RipplerContainer; 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 { private final String id; - private final String imageUrl; + private final VersionIconType iconType; public final StringProperty libraryVersion = new SimpleStringProperty(); public final StringProperty incompatibleLibraryName = new SimpleStringProperty(); public final StringProperty dependencyName = new SimpleStringProperty(); @@ -73,30 +74,30 @@ public class InstallerItem extends Control { switch (id) { case "game": - imageUrl = "/assets/img/grass.png"; + iconType = VersionIconType.GRASS; break; case "fabric": case "fabric-api": - imageUrl = "/assets/img/fabric.png"; + iconType = VersionIconType.FABRIC; break; case "forge": - imageUrl = "/assets/img/forge.png"; + iconType = VersionIconType.FORGE; break; case "liteloader": - imageUrl = "/assets/img/chicken.png"; + iconType = VersionIconType.CHICKEN; break; case "optifine": - imageUrl = "/assets/img/command.png"; + iconType = VersionIconType.COMMAND; break; case "quilt": case "quilt-api": - imageUrl = "/assets/img/quilt.png"; + iconType = VersionIconType.QUILT; break; case "neoforge": - imageUrl = "/assets/img/neoforge.png"; + iconType = VersionIconType.NEO_FORGE; break; default: - imageUrl = null; + iconType = null; break; } } @@ -221,8 +222,8 @@ public class InstallerItem extends Control { pane.pseudoClassStateChanged(LIST_ITEM, control.style == Style.LIST_ITEM); pane.pseudoClassStateChanged(CARD, control.style == Style.CARD); - if (control.imageUrl != null) { - ImageView view = new ImageView(FXUtils.newBuiltinImage(control.imageUrl)); + if (control.iconType != null) { + ImageView view = new ImageView(control.iconType.getIcon()); Node node = FXUtils.limitingSize(view, 32, 32); node.setMouseTransparent(true); node.getStyleClass().add("installer-item-image"); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java index 73b94d5b2..9ac69863b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java @@ -26,7 +26,6 @@ import javafx.beans.InvalidationListener; import javafx.geometry.Insets; import javafx.scene.control.Label; import javafx.scene.control.ListCell; -import javafx.scene.image.Image; import javafx.scene.layout.*; import org.jackhuang.hmcl.download.DownloadProvider; 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.setting.Theme; import org.jackhuang.hmcl.setting.VersionIconType; -import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.animation.ContainerAnimations; 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.Holder; -import java.util.EnumMap; import java.util.List; import java.util.Map; 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))); Holder lastCell = new Holder<>(); - EnumMap icons = new EnumMap<>(VersionIconType.class); - list.setCellFactory(listView -> new RemoteVersionListCell(lastCell, icons)); + list.setCellFactory(listView -> new RemoteVersionListCell(lastCell)); list.setOnMouseClicked(e -> { if (list.getSelectionModel().getSelectedIndex() < 0) @@ -276,21 +272,15 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres final StackPane pane = new StackPane(); private final Holder lastCell; - private final EnumMap icons; - RemoteVersionListCell(Holder lastCell, EnumMap icons) { + RemoteVersionListCell(Holder lastCell) { this.lastCell = lastCell; - this.icons = icons; pane.getStyleClass().add("md-list-cell"); StackPane.setMargin(content, new Insets(10, 16, 10, 16)); pane.getChildren().setAll(ripplerContainer); } - private Image getIcon(VersionIconType type) { - return icons.computeIfAbsent(type, iconType -> FXUtils.newBuiltinImage(iconType.getResourceUrl())); - } - @Override public void updateItem(RemoteVersion remoteVersion, boolean empty) { super.updateItem(remoteVersion, empty); @@ -317,15 +307,15 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres switch (remoteVersion.getVersionType()) { case RELEASE: content.getTags().setAll(i18n("version.game.release")); - content.setImage(getIcon(VersionIconType.GRASS)); + content.setImage(VersionIconType.GRASS.getIcon()); break; case SNAPSHOT: content.getTags().setAll(i18n("version.game.snapshot")); - content.setImage(getIcon(VersionIconType.COMMAND)); + content.setImage(VersionIconType.COMMAND.getIcon()); break; default: content.getTags().setAll(i18n("version.game.old")); - content.setImage(getIcon(VersionIconType.CRAFT_TABLE)); + content.setImage(VersionIconType.CRAFT_TABLE.getIcon()); break; } } else { @@ -345,7 +335,7 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres else iconType = null; - content.setImage(iconType != null ? getIcon(iconType) : null); + content.setImage(iconType != null ? iconType.getIcon() : null); if (content.getSubtitle() == null) content.setSubtitle(remoteVersion.getGameVersion()); else diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItem.java index d6a71f526..da7306d5a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItem.java @@ -23,6 +23,7 @@ import javafx.scene.image.ImageView; import org.jackhuang.hmcl.event.Event; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profiles; +import org.jackhuang.hmcl.setting.VersionIconType; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.WeakListenerHolder; import org.jackhuang.hmcl.ui.construct.AdvancedListItem; @@ -30,7 +31,6 @@ import org.jackhuang.hmcl.util.Pair; import java.util.function.Consumer; -import static org.jackhuang.hmcl.ui.FXUtils.newBuiltinImage; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; public class GameAdvancedListItem extends AdvancedListItem { @@ -72,7 +72,7 @@ public class GameAdvancedListItem extends AdvancedListItem { Tooltip.uninstall(this,tooltip); setTitle(i18n("version.empty")); setSubtitle(i18n("version.empty.add")); - imageView.setImage(newBuiltinImage("/assets/img/grass.png")); + imageView.setImage(VersionIconType.DEFAULT.getIcon()); tooltip.setText(""); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionIconDialog.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionIconDialog.java index cde2d27f2..81375efde 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionIconDialog.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionIconDialog.java @@ -104,7 +104,7 @@ public class VersionIconDialog extends DialogPane { } private Node createIcon(VersionIconType type) { - ImageView imageView = new ImageView(FXUtils.newBuiltinImage(type.getResourceUrl())); + ImageView imageView = new ImageView(type.getIcon()); imageView.setMouseTransparent(true); RipplerContainer container = new RipplerContainer(imageView); FXUtils.setLimitWidth(container, 36);