From ac3c04a3a7cfe203209d50d57046e484578849ff Mon Sep 17 00:00:00 2001 From: Zkitefly <2573874409@qq.com> Date: Mon, 12 Aug 2024 21:33:11 +0800 Subject: [PATCH 01/19] Update ModListPageSkin.java --- .../hmcl/ui/versions/ModListPageSkin.java | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index acd647a5f..6bc273c11 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -254,15 +254,21 @@ class ModListPageSkin extends SkinBase { this.active = localModFile.activeProperty(); StringBuilder title = new StringBuilder(localModFile.getName()); - if (isNotBlank(localModFile.getVersion())) - title.append(" ").append(localModFile.getVersion()); this.title = title.toString(); - StringBuilder message = new StringBuilder(localModFile.getFileName()); - if (isNotBlank(localModFile.getGameVersion())) - message.append(", ").append(i18n("game.version")).append(": ").append(localModFile.getGameVersion()); - if (isNotBlank(localModFile.getAuthors())) - message.append(", ").append(i18n("archive.author")).append(": ").append(localModFile.getAuthors()); + StringBuilder message = new StringBuilder(localModFile.getId()); + if (isNotBlank(localModFile.getVersion())) { + if (isNotBlank(localModFile.getId())) { + message.append(", "); + } + message.append(localModFile.getVersion()); + } + if (isNotBlank(localModFile.getGameVersion())) { + if (isNotBlank(localModFile.getVersion())) { + message.append(", "); + } + message.append(i18n("game.version")).append(": ").append(localModFile.getGameVersion()); + } this.message = message.toString(); this.mod = ModTranslations.MOD.getModById(localModFile.getId()); @@ -319,8 +325,18 @@ class ModListPageSkin extends SkinBase { TwoLineListItem title = new TwoLineListItem(); title.setTitle(modInfo.getModInfo().getName()); + if (modInfo.getMod() != null) { + title.getTags().setAll(modInfo.mod.getModIds()); + title.getTags().add(modInfo.getMod().getDisplayName()); + } + if (StringUtils.isNotBlank(modInfo.getModInfo().getGameVersion())) { + title.getTags().add(i18n("game.version") + ": " + modInfo.getModInfo().getGameVersion()); + } if (StringUtils.isNotBlank(modInfo.getModInfo().getVersion())) { - title.getTags().setAll(modInfo.getModInfo().getVersion()); + title.getTags().add(modInfo.getModInfo().getVersion()); + } + if (StringUtils.isNotBlank(modInfo.getModInfo().getAuthors())) { + title.getTags().add(i18n("archive.author") + ": " + modInfo.getModInfo().getAuthors()); } title.setSubtitle(FileUtils.getName(modInfo.getModInfo().getFile())); @@ -488,9 +504,14 @@ class ModListPageSkin extends SkinBase { break; } if (dataItem.getMod() != null && I18n.isUseChinese()) { - content.getTags().add(dataItem.getMod().getDisplayName()); + if (isNotBlank(dataItem.getSubtitle())) { + content.setSubtitle(dataItem.getSubtitle() + ", " + dataItem.getMod().getDisplayName()); + } else { + content.setSubtitle(dataItem.getMod().getDisplayName()); + } + } else { + content.setSubtitle(dataItem.getSubtitle()); } - content.setSubtitle(dataItem.getSubtitle()); if (booleanProperty != null) { checkBox.selectedProperty().unbindBidirectional(booleanProperty); } From b9ac132d8d34c702285ac4f8ae31fd8e361de6b0 Mon Sep 17 00:00:00 2001 From: Zkitefly <2573874409@qq.com> Date: Fri, 16 Aug 2024 12:24:32 +0800 Subject: [PATCH 02/19] =?UTF-8?q?=E4=B8=8D=E5=86=8D=E6=98=BE=E7=A4=BA=20au?= =?UTF-8?q?thor=20=E6=A0=87=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 这玩意太大了会折叠 https://github.com/user-attachments/assets/e1a63cc2-57f6-4b91-ae8f-36a6f89f1944 --- .../org/jackhuang/hmcl/ui/versions/ModListPageSkin.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 6bc273c11..7870b0071 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -335,9 +335,9 @@ class ModListPageSkin extends SkinBase { if (StringUtils.isNotBlank(modInfo.getModInfo().getVersion())) { title.getTags().add(modInfo.getModInfo().getVersion()); } - if (StringUtils.isNotBlank(modInfo.getModInfo().getAuthors())) { - title.getTags().add(i18n("archive.author") + ": " + modInfo.getModInfo().getAuthors()); - } +// if (StringUtils.isNotBlank(modInfo.getModInfo().getAuthors())) { +// title.getTags().add(i18n("archive.author") + ": " + modInfo.getModInfo().getAuthors()); +// } title.setSubtitle(FileUtils.getName(modInfo.getModInfo().getFile())); titleContainer.getChildren().setAll(FXUtils.limitingSize(imageView, 40, 40), title); From dba4f35375eee8632bf9c704c482b5581d036bbb Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Sun, 9 Feb 2025 15:54:36 +0000 Subject: [PATCH 03/19] update --- .../hmcl/ui/versions/ModListPageSkin.java | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 7870b0071..500ba7b21 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -66,6 +66,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.List; +import java.util.ArrayList; import java.util.Locale; import java.util.Optional; import java.util.function.Predicate; @@ -256,19 +257,17 @@ class ModListPageSkin extends SkinBase { StringBuilder title = new StringBuilder(localModFile.getName()); this.title = title.toString(); - StringBuilder message = new StringBuilder(localModFile.getId()); + List parts = new ArrayList<>(); + if (isNotBlank(localModFile.getId())) { + parts.add(localModFile.getId()); + } if (isNotBlank(localModFile.getVersion())) { - if (isNotBlank(localModFile.getId())) { - message.append(", "); - } - message.append(localModFile.getVersion()); + parts.add(localModFile.getVersion()); } if (isNotBlank(localModFile.getGameVersion())) { - if (isNotBlank(localModFile.getVersion())) { - message.append(", "); - } - message.append(i18n("game.version")).append(": ").append(localModFile.getGameVersion()); + parts.add(i18n("game.version") + ": " + localModFile.getGameVersion()); } + String message = String.join(", ", parts); this.message = message.toString(); this.mod = ModTranslations.MOD.getModById(localModFile.getId()); @@ -326,7 +325,6 @@ class ModListPageSkin extends SkinBase { TwoLineListItem title = new TwoLineListItem(); title.setTitle(modInfo.getModInfo().getName()); if (modInfo.getMod() != null) { - title.getTags().setAll(modInfo.mod.getModIds()); title.getTags().add(modInfo.getMod().getDisplayName()); } if (StringUtils.isNotBlank(modInfo.getModInfo().getGameVersion())) { @@ -335,9 +333,9 @@ class ModListPageSkin extends SkinBase { if (StringUtils.isNotBlank(modInfo.getModInfo().getVersion())) { title.getTags().add(modInfo.getModInfo().getVersion()); } -// if (StringUtils.isNotBlank(modInfo.getModInfo().getAuthors())) { -// title.getTags().add(i18n("archive.author") + ": " + modInfo.getModInfo().getAuthors()); -// } + if (StringUtils.isNotBlank(modInfo.getModInfo().getAuthors())) { + title.getTags().add(i18n("archive.author") + ": " + modInfo.getModInfo().getAuthors()); + } title.setSubtitle(FileUtils.getName(modInfo.getModInfo().getFile())); titleContainer.getChildren().setAll(FXUtils.limitingSize(imageView, 40, 40), title); From f5d09afba5e026ce8540f0614f69808e16ffdbd9 Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Sun, 9 Feb 2025 17:14:48 +0000 Subject: [PATCH 04/19] =?UTF-8?q?=E4=B8=BA=20ModListPageSkin=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20mod=20=E5=9B=BE=E6=A0=87=E6=94=AF=E6=8C=81=EF=BC=8C?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E8=87=AA=E5=AE=9A=E4=B9=89=E5=9B=BE=E6=A0=87?= =?UTF-8?q?=E5=B9=B6=E6=A0=B9=E6=8D=AE=E6=A8=A1=E7=BB=84=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=BB=98=E8=AE=A4=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hmcl/ui/versions/ModListPageSkin.java | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 500ba7b21..4d8c26ee1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -446,6 +446,7 @@ class ModListPageSkin extends SkinBase { final class ModInfoListCell extends MDListCell { JFXCheckBox checkBox = new JFXCheckBox(); + ImageView imageView = new ImageView(); TwoLineListItem content = new TwoLineListItem(); JFXButton restoreButton = new JFXButton(); JFXButton infoButton = new JFXButton(); @@ -462,6 +463,13 @@ class ModListPageSkin extends SkinBase { content.setMouseTransparent(true); setSelectable(); + // 配置图标大小 + imageView.setFitWidth(24); + imageView.setFitHeight(24); + imageView.setPreserveRatio(true); + // 设置默认图标 + imageView.setImage(FXUtils.newBuiltinImage("/assets/img/command.png", 24, 24, true, true)); + restoreButton.getStyleClass().add("toggle-icon4"); restoreButton.setGraphic(FXUtils.limitingSize(SVG.RESTORE.createIcon(Theme.blackFill(), 24, 24), 24, 24)); @@ -473,7 +481,7 @@ class ModListPageSkin extends SkinBase { infoButton.getStyleClass().add("toggle-icon4"); infoButton.setGraphic(FXUtils.limitingSize(SVG.INFORMATION_OUTLINE.createIcon(Theme.blackFill(), 24, 24), 24, 24)); - container.getChildren().setAll(checkBox, content, restoreButton, revealButton, infoButton); + container.getChildren().setAll(checkBox, imageView, content, restoreButton, revealButton, infoButton); StackPane.setMargin(container, new Insets(8)); getContainer().getChildren().setAll(container); @@ -482,6 +490,32 @@ class ModListPageSkin extends SkinBase { @Override protected void updateControl(ModInfoObject dataItem, boolean empty) { if (empty) return; + + // 加载 mod 图标 + if (StringUtils.isNotBlank(dataItem.getModInfo().getLogoPath())) { + Task.supplyAsync(() -> { + try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(dataItem.getModInfo().getFile())) { + Path iconPath = fs.getPath(dataItem.getModInfo().getLogoPath()); + if (Files.exists(iconPath)) { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Files.copy(iconPath, stream); + return new ByteArrayInputStream(stream.toByteArray()); + } + } + return null; + }).whenComplete(Schedulers.javafx(), (stream, exception) -> { + if (stream != null) { + imageView.setImage(new Image(stream, 24, 24, true, true)); + } else { + // 如果无法加载自定义图标,根据模组类型设置默认图标 + setDefaultModIcon(dataItem.getModInfo().getModLoaderType()); + } + }).start(); + } else { + // 没有自定义图标,根据模组类型设置默认图标 + setDefaultModIcon(dataItem.getModInfo().getModLoaderType()); + } + content.setTitle(dataItem.getTitle()); content.getTags().clear(); switch (dataItem.getModInfo().getModLoaderType()) { @@ -532,5 +566,30 @@ class ModListPageSkin extends SkinBase { Controllers.dialog(new ModInfoDialog(dataItem)); }); } + + private void setDefaultModIcon(ModLoaderType modLoaderType) { + String iconPath; + switch (modLoaderType) { + case FORGE: + iconPath = "/assets/img/forge.png"; + break; + case NEO_FORGED: + iconPath = "/assets/img/neoforge.png"; + break; + case FABRIC: + iconPath = "/assets/img/fabric.png"; + break; + case QUILT: + iconPath = "/assets/img/quilt.png"; + break; + case LITE_LOADER: + iconPath = "/assets/img/liteloader.png"; + break; + default: + iconPath = "/assets/img/command.png"; + break; + } + imageView.setImage(FXUtils.newBuiltinImage(iconPath, 24, 24, true, true)); + } } } From 56e2f032135098d5877f73da4e1c76fc9aaa96be Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Sun, 9 Feb 2025 17:28:06 +0000 Subject: [PATCH 05/19] update --- .../java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 4d8c26ee1..382abcd94 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -463,11 +463,9 @@ class ModListPageSkin extends SkinBase { content.setMouseTransparent(true); setSelectable(); - // 配置图标大小 imageView.setFitWidth(24); imageView.setFitHeight(24); imageView.setPreserveRatio(true); - // 设置默认图标 imageView.setImage(FXUtils.newBuiltinImage("/assets/img/command.png", 24, 24, true, true)); restoreButton.getStyleClass().add("toggle-icon4"); @@ -491,7 +489,6 @@ class ModListPageSkin extends SkinBase { protected void updateControl(ModInfoObject dataItem, boolean empty) { if (empty) return; - // 加载 mod 图标 if (StringUtils.isNotBlank(dataItem.getModInfo().getLogoPath())) { Task.supplyAsync(() -> { try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(dataItem.getModInfo().getFile())) { @@ -507,12 +504,10 @@ class ModListPageSkin extends SkinBase { if (stream != null) { imageView.setImage(new Image(stream, 24, 24, true, true)); } else { - // 如果无法加载自定义图标,根据模组类型设置默认图标 setDefaultModIcon(dataItem.getModInfo().getModLoaderType()); } }).start(); } else { - // 没有自定义图标,根据模组类型设置默认图标 setDefaultModIcon(dataItem.getModInfo().getModLoaderType()); } From 68ec788bab88e245d6db6522a0da1141fb60b763 Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Sun, 9 Feb 2025 17:14:48 +0000 Subject: [PATCH 06/19] =?UTF-8?q?=E4=B8=BA=20ModListPageSkin=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=20mod=20=E5=9B=BE=E6=A0=87=E6=94=AF=E6=8C=81=EF=BC=8C?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E8=87=AA=E5=AE=9A=E4=B9=89=E5=9B=BE=E6=A0=87?= =?UTF-8?q?=E5=B9=B6=E6=A0=B9=E6=8D=AE=E6=A8=A1=E7=BB=84=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=BB=98=E8=AE=A4=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit update --- .../hmcl/ui/versions/ModListPageSkin.java | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 500ba7b21..382abcd94 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -446,6 +446,7 @@ class ModListPageSkin extends SkinBase { final class ModInfoListCell extends MDListCell { JFXCheckBox checkBox = new JFXCheckBox(); + ImageView imageView = new ImageView(); TwoLineListItem content = new TwoLineListItem(); JFXButton restoreButton = new JFXButton(); JFXButton infoButton = new JFXButton(); @@ -462,6 +463,11 @@ class ModListPageSkin extends SkinBase { content.setMouseTransparent(true); setSelectable(); + imageView.setFitWidth(24); + imageView.setFitHeight(24); + imageView.setPreserveRatio(true); + imageView.setImage(FXUtils.newBuiltinImage("/assets/img/command.png", 24, 24, true, true)); + restoreButton.getStyleClass().add("toggle-icon4"); restoreButton.setGraphic(FXUtils.limitingSize(SVG.RESTORE.createIcon(Theme.blackFill(), 24, 24), 24, 24)); @@ -473,7 +479,7 @@ class ModListPageSkin extends SkinBase { infoButton.getStyleClass().add("toggle-icon4"); infoButton.setGraphic(FXUtils.limitingSize(SVG.INFORMATION_OUTLINE.createIcon(Theme.blackFill(), 24, 24), 24, 24)); - container.getChildren().setAll(checkBox, content, restoreButton, revealButton, infoButton); + container.getChildren().setAll(checkBox, imageView, content, restoreButton, revealButton, infoButton); StackPane.setMargin(container, new Insets(8)); getContainer().getChildren().setAll(container); @@ -482,6 +488,29 @@ class ModListPageSkin extends SkinBase { @Override protected void updateControl(ModInfoObject dataItem, boolean empty) { if (empty) return; + + if (StringUtils.isNotBlank(dataItem.getModInfo().getLogoPath())) { + Task.supplyAsync(() -> { + try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(dataItem.getModInfo().getFile())) { + Path iconPath = fs.getPath(dataItem.getModInfo().getLogoPath()); + if (Files.exists(iconPath)) { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Files.copy(iconPath, stream); + return new ByteArrayInputStream(stream.toByteArray()); + } + } + return null; + }).whenComplete(Schedulers.javafx(), (stream, exception) -> { + if (stream != null) { + imageView.setImage(new Image(stream, 24, 24, true, true)); + } else { + setDefaultModIcon(dataItem.getModInfo().getModLoaderType()); + } + }).start(); + } else { + setDefaultModIcon(dataItem.getModInfo().getModLoaderType()); + } + content.setTitle(dataItem.getTitle()); content.getTags().clear(); switch (dataItem.getModInfo().getModLoaderType()) { @@ -532,5 +561,30 @@ class ModListPageSkin extends SkinBase { Controllers.dialog(new ModInfoDialog(dataItem)); }); } + + private void setDefaultModIcon(ModLoaderType modLoaderType) { + String iconPath; + switch (modLoaderType) { + case FORGE: + iconPath = "/assets/img/forge.png"; + break; + case NEO_FORGED: + iconPath = "/assets/img/neoforge.png"; + break; + case FABRIC: + iconPath = "/assets/img/fabric.png"; + break; + case QUILT: + iconPath = "/assets/img/quilt.png"; + break; + case LITE_LOADER: + iconPath = "/assets/img/liteloader.png"; + break; + default: + iconPath = "/assets/img/command.png"; + break; + } + imageView.setImage(FXUtils.newBuiltinImage(iconPath, 24, 24, true, true)); + } } } From fdb050971f8b65505067abc50b200c4af3180afe Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Mon, 10 Feb 2025 11:24:39 +0800 Subject: [PATCH 07/19] =?UTF-8?q?Revert=20"=E4=B8=BA=20ModListPageSkin=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20mod=20=E5=9B=BE=E6=A0=87=E6=94=AF=E6=8C=81?= =?UTF-8?q?=EF=BC=8C=E5=8A=A0=E8=BD=BD=E8=87=AA=E5=AE=9A=E4=B9=89=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=E5=B9=B6=E6=A0=B9=E6=8D=AE=E6=A8=A1=E7=BB=84=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E8=AE=BE=E7=BD=AE=E9=BB=98=E8=AE=A4=E5=9B=BE=E6=A0=87?= =?UTF-8?q?"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 68ec788bab88e245d6db6522a0da1141fb60b763. --- .../hmcl/ui/versions/ModListPageSkin.java | 56 +------------------ 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 382abcd94..500ba7b21 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -446,7 +446,6 @@ class ModListPageSkin extends SkinBase { final class ModInfoListCell extends MDListCell { JFXCheckBox checkBox = new JFXCheckBox(); - ImageView imageView = new ImageView(); TwoLineListItem content = new TwoLineListItem(); JFXButton restoreButton = new JFXButton(); JFXButton infoButton = new JFXButton(); @@ -463,11 +462,6 @@ class ModListPageSkin extends SkinBase { content.setMouseTransparent(true); setSelectable(); - imageView.setFitWidth(24); - imageView.setFitHeight(24); - imageView.setPreserveRatio(true); - imageView.setImage(FXUtils.newBuiltinImage("/assets/img/command.png", 24, 24, true, true)); - restoreButton.getStyleClass().add("toggle-icon4"); restoreButton.setGraphic(FXUtils.limitingSize(SVG.RESTORE.createIcon(Theme.blackFill(), 24, 24), 24, 24)); @@ -479,7 +473,7 @@ class ModListPageSkin extends SkinBase { infoButton.getStyleClass().add("toggle-icon4"); infoButton.setGraphic(FXUtils.limitingSize(SVG.INFORMATION_OUTLINE.createIcon(Theme.blackFill(), 24, 24), 24, 24)); - container.getChildren().setAll(checkBox, imageView, content, restoreButton, revealButton, infoButton); + container.getChildren().setAll(checkBox, content, restoreButton, revealButton, infoButton); StackPane.setMargin(container, new Insets(8)); getContainer().getChildren().setAll(container); @@ -488,29 +482,6 @@ class ModListPageSkin extends SkinBase { @Override protected void updateControl(ModInfoObject dataItem, boolean empty) { if (empty) return; - - if (StringUtils.isNotBlank(dataItem.getModInfo().getLogoPath())) { - Task.supplyAsync(() -> { - try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(dataItem.getModInfo().getFile())) { - Path iconPath = fs.getPath(dataItem.getModInfo().getLogoPath()); - if (Files.exists(iconPath)) { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - Files.copy(iconPath, stream); - return new ByteArrayInputStream(stream.toByteArray()); - } - } - return null; - }).whenComplete(Schedulers.javafx(), (stream, exception) -> { - if (stream != null) { - imageView.setImage(new Image(stream, 24, 24, true, true)); - } else { - setDefaultModIcon(dataItem.getModInfo().getModLoaderType()); - } - }).start(); - } else { - setDefaultModIcon(dataItem.getModInfo().getModLoaderType()); - } - content.setTitle(dataItem.getTitle()); content.getTags().clear(); switch (dataItem.getModInfo().getModLoaderType()) { @@ -561,30 +532,5 @@ class ModListPageSkin extends SkinBase { Controllers.dialog(new ModInfoDialog(dataItem)); }); } - - private void setDefaultModIcon(ModLoaderType modLoaderType) { - String iconPath; - switch (modLoaderType) { - case FORGE: - iconPath = "/assets/img/forge.png"; - break; - case NEO_FORGED: - iconPath = "/assets/img/neoforge.png"; - break; - case FABRIC: - iconPath = "/assets/img/fabric.png"; - break; - case QUILT: - iconPath = "/assets/img/quilt.png"; - break; - case LITE_LOADER: - iconPath = "/assets/img/liteloader.png"; - break; - default: - iconPath = "/assets/img/command.png"; - break; - } - imageView.setImage(FXUtils.newBuiltinImage(iconPath, 24, 24, true, true)); - } } } From d84c8d08f96dfba2a6b2f4461b446ad8b8f36eb8 Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Mon, 10 Feb 2025 14:51:38 +0800 Subject: [PATCH 08/19] Update ModListPageSkin.java --- .../java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 8dcc0eb0c..c285e4d69 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -71,6 +71,8 @@ import java.util.*; import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import static org.jackhuang.hmcl.ui.FXUtils.ignoreEvent; import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed; From f80afdb15b02d9e0e787019e57f3c99780cd4ccd Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Mon, 10 Feb 2025 14:52:08 +0800 Subject: [PATCH 09/19] Revert "Merge branch 'mods_manage-info' of https://github.com/zkitefly/HMCL into mods_manage-info" This reverts commit d41dcd3d6c7e98def2b3d8a6d44ea909a7a93fda, reversing changes made to fdb050971f8b65505067abc50b200c4af3180afe. --- .../hmcl/ui/versions/ModListPageSkin.java | 56 +------------------ 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index c285e4d69..d6a092292 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -517,7 +517,6 @@ class ModListPageSkin extends SkinBase { final class ModInfoListCell extends MDListCell { JFXCheckBox checkBox = new JFXCheckBox(); - ImageView imageView = new ImageView(); TwoLineListItem content = new TwoLineListItem(); JFXButton restoreButton = new JFXButton(); JFXButton infoButton = new JFXButton(); @@ -534,11 +533,6 @@ class ModListPageSkin extends SkinBase { content.setMouseTransparent(true); setSelectable(); - imageView.setFitWidth(24); - imageView.setFitHeight(24); - imageView.setPreserveRatio(true); - imageView.setImage(FXUtils.newBuiltinImage("/assets/img/command.png", 24, 24, true, true)); - restoreButton.getStyleClass().add("toggle-icon4"); restoreButton.setGraphic(FXUtils.limitingSize(SVG.RESTORE.createIcon(Theme.blackFill(), 24, 24), 24, 24)); @@ -550,7 +544,7 @@ class ModListPageSkin extends SkinBase { infoButton.getStyleClass().add("toggle-icon4"); infoButton.setGraphic(FXUtils.limitingSize(SVG.INFORMATION_OUTLINE.createIcon(Theme.blackFill(), 24, 24), 24, 24)); - container.getChildren().setAll(checkBox, imageView, content, restoreButton, revealButton, infoButton); + container.getChildren().setAll(checkBox, content, restoreButton, revealButton, infoButton); StackPane.setMargin(container, new Insets(8)); getContainer().getChildren().setAll(container); @@ -559,29 +553,6 @@ class ModListPageSkin extends SkinBase { @Override protected void updateControl(ModInfoObject dataItem, boolean empty) { if (empty) return; - - if (StringUtils.isNotBlank(dataItem.getModInfo().getLogoPath())) { - Task.supplyAsync(() -> { - try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(dataItem.getModInfo().getFile())) { - Path iconPath = fs.getPath(dataItem.getModInfo().getLogoPath()); - if (Files.exists(iconPath)) { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - Files.copy(iconPath, stream); - return new ByteArrayInputStream(stream.toByteArray()); - } - } - return null; - }).whenComplete(Schedulers.javafx(), (stream, exception) -> { - if (stream != null) { - imageView.setImage(new Image(stream, 24, 24, true, true)); - } else { - setDefaultModIcon(dataItem.getModInfo().getModLoaderType()); - } - }).start(); - } else { - setDefaultModIcon(dataItem.getModInfo().getModLoaderType()); - } - content.setTitle(dataItem.getTitle()); content.getTags().clear(); switch (dataItem.getModInfo().getModLoaderType()) { @@ -628,30 +599,5 @@ class ModListPageSkin extends SkinBase { revealButton.setOnAction(e -> FXUtils.showFileInExplorer(dataItem.getModInfo().getFile())); infoButton.setOnAction(e -> Controllers.dialog(new ModInfoDialog(dataItem))); } - - private void setDefaultModIcon(ModLoaderType modLoaderType) { - String iconPath; - switch (modLoaderType) { - case FORGE: - iconPath = "/assets/img/forge.png"; - break; - case NEO_FORGED: - iconPath = "/assets/img/neoforge.png"; - break; - case FABRIC: - iconPath = "/assets/img/fabric.png"; - break; - case QUILT: - iconPath = "/assets/img/quilt.png"; - break; - case LITE_LOADER: - iconPath = "/assets/img/liteloader.png"; - break; - default: - iconPath = "/assets/img/command.png"; - break; - } - imageView.setImage(FXUtils.newBuiltinImage(iconPath, 24, 24, true, true)); - } } } From 1b741636dfd416c6d37b050aee95d826445e45c1 Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Mon, 10 Feb 2025 14:56:27 +0800 Subject: [PATCH 10/19] Update ModListPageSkin.java --- .../java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index d6a092292..a4bbae9e9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -71,8 +71,6 @@ import java.util.*; import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import static org.jackhuang.hmcl.ui.FXUtils.ignoreEvent; import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed; From cb01e8198bc9b701919e5c723564f13ed920d184 Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Mon, 30 Jun 2025 19:01:12 +0800 Subject: [PATCH 11/19] update --- .../hmcl/ui/versions/ModListPageSkin.java | 36 +------- .../org/jackhuang/hmcl/mod/LocalModFile.java | 92 ++++++++++++++++++- 2 files changed, 92 insertions(+), 36 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index f1243a778..5508291dd 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -338,46 +338,12 @@ class ModListPageSkin extends SkinBase { Path iconPath = fs.getPath(logoPath); if (Files.exists(iconPath)) { try (InputStream stream = Files.newInputStream(iconPath)) { - Image image = new Image(stream, 40, 40, true, true); - if (!image.isError() && image.getWidth() == image.getHeight()) - return image; + return new Image(stream, 40, 40, true, true); } catch (Throwable e) { LOG.warning("Failed to load image " + logoPath, e); } } } - - List defaultPaths = new ArrayList<>(Arrays.asList( - "icon.png", - "logo.png", - "mod_logo.png", - "pack.png", - "logoFile.png" - )); - - String id = modInfo.getModInfo().getId(); - if (StringUtils.isNotBlank(id)) { - defaultPaths.addAll(Arrays.asList( - "assets/" + id + "/icon.png", - "assets/" + id.replace("-", "") + "/icon.png", - id + ".png", - id + "-logo.png", - id + "-icon.png", - id + "_logo.png", - id + "_icon.png" - )); - } - - for (String path : defaultPaths) { - Path iconPath = fs.getPath(path); - if (Files.exists(iconPath)) { - try (InputStream stream = Files.newInputStream(iconPath)) { - Image image = new Image(stream, 40, 40, true, true); - if (!image.isError() && image.getWidth() == image.getHeight()) - return image; - } - } - } } catch (Exception e) { LOG.warning("Failed to load icon", e); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/LocalModFile.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/LocalModFile.java index 0f05a684b..679570caf 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/LocalModFile.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/LocalModFile.java @@ -19,13 +19,21 @@ package org.jackhuang.hmcl.mod; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; +import javafx.scene.image.Image; + +import org.jackhuang.hmcl.util.StringUtils; +import org.jackhuang.hmcl.util.io.CompressingUtils; import org.jackhuang.hmcl.util.io.FileUtils; import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileSystem; +import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; + import static org.jackhuang.hmcl.util.logging.Logger.LOG; /** @@ -61,7 +69,13 @@ public final class LocalModFile implements Comparable { this.version = version; this.gameVersion = gameVersion; this.url = url; - this.logoPath = logoPath; + + String validatedLogoPath = validateLogoPath(file, logoPath); + if (validatedLogoPath != null) { + this.logoPath = validatedLogoPath; + } else { + this.logoPath = findLogoPath(file, mod.getId()); + } activeProperty = new SimpleBooleanProperty(this, "active", !modManager.isDisabled(file)) { @Override @@ -202,6 +216,82 @@ public final class LocalModFile implements Comparable { return Objects.hash(getFileName()); } + private String validateLogoPath(Path modFile, String path) { + if (StringUtils.isBlank(path)) return null; + + try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile)) { + Path iconPath = fs.getPath(path); + if (!Files.exists(iconPath)) return null; + + try (InputStream stream = Files.newInputStream(iconPath)) { + Image image = new Image(stream, 40, 40, true, true); + + if (!image.isError() && + image.getWidth() > 0 && + image.getHeight() > 0 && + Math.abs(image.getWidth() - image.getHeight()) < 1) { + return path; + } + } catch (Exception e) { + LOG.warning("Failed to validate mod icon from: " + path, e); + } + } catch (IOException e) { + LOG.warning("Failed to access mod file for icon validation: " + path, e); + } + + return null; + } + + private String findLogoPath(Path modFile, String modId) { + List defaultPaths = new ArrayList<>(Arrays.asList( + "icon.png", + "logo.png", + "mod_logo.png", + "pack.png", + "logoFile.png", + "assets/icon.png", + "assets/logo.png", + "assets/mod_icon.png", + "assets/mod_logo.png", + "META-INF/icon.png", + "META-INF/logo.png", + "META-INF/mod_icon.png", + "textures/icon.png", + "textures/logo.png", + "textures/mod_icon.png", + "resources/icon.png", + "resources/logo.png", + "resources/mod_icon.png" + )); + + if (StringUtils.isNotBlank(modId)) { + defaultPaths.addAll(Arrays.asList( + "assets/" + modId + "/icon.png", + "assets/" + modId + "/logo.png", + "assets/" + modId.replace("-", "") + "/icon.png", + "assets/" + modId.replace("-", "") + "/logo.png", + modId + ".png", + modId + "-logo.png", + modId + "-icon.png", + modId + "_logo.png", + modId + "_icon.png", + "textures/" + modId + "/icon.png", + "textures/" + modId + "/logo.png", + "resources/" + modId + "/icon.png", + "resources/" + modId + "/logo.png" + )); + } + + for (String path : defaultPaths) { + String validatedPath = validateLogoPath(modFile, path); + if (validatedPath != null) { + return validatedPath; + } + } + + return null; + } + public static class ModUpdate { private final LocalModFile localModFile; private final RemoteMod.Version currentVersion; From 3043a37414a00ec24bfe7fdf071286a1426f8e9c Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Mon, 30 Jun 2025 19:15:13 +0800 Subject: [PATCH 12/19] update --- .../org/jackhuang/hmcl/mod/LocalModFile.java | 92 +------------------ 1 file changed, 1 insertion(+), 91 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/LocalModFile.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/LocalModFile.java index 679570caf..0f05a684b 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/LocalModFile.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/LocalModFile.java @@ -19,21 +19,13 @@ package org.jackhuang.hmcl.mod; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; -import javafx.scene.image.Image; - -import org.jackhuang.hmcl.util.StringUtils; -import org.jackhuang.hmcl.util.io.CompressingUtils; import org.jackhuang.hmcl.util.io.FileUtils; import java.io.IOException; -import java.io.InputStream; -import java.nio.file.FileSystem; -import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; - import static org.jackhuang.hmcl.util.logging.Logger.LOG; /** @@ -69,13 +61,7 @@ public final class LocalModFile implements Comparable { this.version = version; this.gameVersion = gameVersion; this.url = url; - - String validatedLogoPath = validateLogoPath(file, logoPath); - if (validatedLogoPath != null) { - this.logoPath = validatedLogoPath; - } else { - this.logoPath = findLogoPath(file, mod.getId()); - } + this.logoPath = logoPath; activeProperty = new SimpleBooleanProperty(this, "active", !modManager.isDisabled(file)) { @Override @@ -216,82 +202,6 @@ public final class LocalModFile implements Comparable { return Objects.hash(getFileName()); } - private String validateLogoPath(Path modFile, String path) { - if (StringUtils.isBlank(path)) return null; - - try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile)) { - Path iconPath = fs.getPath(path); - if (!Files.exists(iconPath)) return null; - - try (InputStream stream = Files.newInputStream(iconPath)) { - Image image = new Image(stream, 40, 40, true, true); - - if (!image.isError() && - image.getWidth() > 0 && - image.getHeight() > 0 && - Math.abs(image.getWidth() - image.getHeight()) < 1) { - return path; - } - } catch (Exception e) { - LOG.warning("Failed to validate mod icon from: " + path, e); - } - } catch (IOException e) { - LOG.warning("Failed to access mod file for icon validation: " + path, e); - } - - return null; - } - - private String findLogoPath(Path modFile, String modId) { - List defaultPaths = new ArrayList<>(Arrays.asList( - "icon.png", - "logo.png", - "mod_logo.png", - "pack.png", - "logoFile.png", - "assets/icon.png", - "assets/logo.png", - "assets/mod_icon.png", - "assets/mod_logo.png", - "META-INF/icon.png", - "META-INF/logo.png", - "META-INF/mod_icon.png", - "textures/icon.png", - "textures/logo.png", - "textures/mod_icon.png", - "resources/icon.png", - "resources/logo.png", - "resources/mod_icon.png" - )); - - if (StringUtils.isNotBlank(modId)) { - defaultPaths.addAll(Arrays.asList( - "assets/" + modId + "/icon.png", - "assets/" + modId + "/logo.png", - "assets/" + modId.replace("-", "") + "/icon.png", - "assets/" + modId.replace("-", "") + "/logo.png", - modId + ".png", - modId + "-logo.png", - modId + "-icon.png", - modId + "_logo.png", - modId + "_icon.png", - "textures/" + modId + "/icon.png", - "textures/" + modId + "/logo.png", - "resources/" + modId + "/icon.png", - "resources/" + modId + "/logo.png" - )); - } - - for (String path : defaultPaths) { - String validatedPath = validateLogoPath(modFile, path); - if (validatedPath != null) { - return validatedPath; - } - } - - return null; - } - public static class ModUpdate { private final LocalModFile localModFile; private final RemoteMod.Version currentVersion; From 5e9372021c9e608abb88f5d2606ea95af6d50203 Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Mon, 30 Jun 2025 19:48:18 +0800 Subject: [PATCH 13/19] update --- .../hmcl/ui/versions/ModListPageSkin.java | 58 +++++++++++-------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 5508291dd..5c67c39ca 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -272,6 +272,35 @@ class ModListPageSkin extends SkinBase { } } + private static Task loadModIcon(LocalModFile modFile) { + int size = 40; + return Task.supplyAsync(() -> { + if (StringUtils.isNotBlank(modFile.getLogoPath())) { + try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.getFile())) { + Path iconPath = fs.getPath(modFile.getLogoPath()); + if (Files.exists(iconPath)) { + try (InputStream stream = Files.newInputStream(iconPath)) { + return new Image(stream, size, size, true, true); + } + } + } catch (Exception e) { + LOG.warning("Failed to load image " + modFile.getLogoPath(), e); + } + } + + String iconPath; + switch (modFile.getModLoaderType()) { + case FORGE: iconPath = "/assets/img/forge.png"; break; + case NEO_FORGED: iconPath = "/assets/img/neoforge.png"; break; + case FABRIC: iconPath = "/assets/img/fabric.png"; break; + case QUILT: iconPath = "/assets/img/quilt.png"; break; + case LITE_LOADER: iconPath = "/assets/img/liteloader.png"; break; + default: iconPath = "/assets/img/command.png"; break; + } + return FXUtils.newBuiltinImage(iconPath, size, size, true, true); + }); + } + static class ModInfoObject extends RecursiveTreeObject implements Comparable { private final BooleanProperty active; private final LocalModFile localModFile; @@ -330,32 +359,11 @@ class ModListPageSkin extends SkinBase { HBox titleContainer = new HBox(); titleContainer.setSpacing(8); - ImageView imageView = new ImageView(); - Task.supplyAsync(() -> { - try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modInfo.getModInfo().getFile())) { - String logoPath = modInfo.getModInfo().getLogoPath(); - if (StringUtils.isNotBlank(logoPath)) { - Path iconPath = fs.getPath(logoPath); - if (Files.exists(iconPath)) { - try (InputStream stream = Files.newInputStream(iconPath)) { - return new Image(stream, 40, 40, true, true); - } catch (Throwable e) { - LOG.warning("Failed to load image " + logoPath, e); - } - } - } - } catch (Exception e) { - LOG.warning("Failed to load icon", e); - } - - return null; - }).whenComplete(Schedulers.javafx(), (image, exception) -> { - if (image != null) { + ImageView imageView = new ImageView(); + loadModIcon(modInfo.getModInfo()) + .whenComplete(Schedulers.javafx(), (image, exception) -> { imageView.setImage(image); - } else { - imageView.setImage(FXUtils.newBuiltinImage("/assets/img/command.png", 40, 40, true, true)); - } - }).start(); + }).start(); TwoLineListItem title = new TwoLineListItem(); title.setTitle(modInfo.getModInfo().getName()); From 73bf2d6c63040963e493e65b68499e7ff11f79bd Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Mon, 30 Jun 2025 19:53:27 +0800 Subject: [PATCH 14/19] Update ModListPageSkin.java --- .../java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 5c67c39ca..ce8932c29 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -280,7 +280,7 @@ class ModListPageSkin extends SkinBase { Path iconPath = fs.getPath(modFile.getLogoPath()); if (Files.exists(iconPath)) { try (InputStream stream = Files.newInputStream(iconPath)) { - return new Image(stream, size, size, true, true); + return new Image(stream, size, size, true, true); } } } catch (Exception e) { From e79f83e3fa785ecfe5ab093569528c165c42b0bb Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Mon, 30 Jun 2025 20:01:37 +0800 Subject: [PATCH 15/19] Update ModListPageSkin.java --- .../hmcl/ui/versions/ModListPageSkin.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index ce8932c29..0729d29d3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -272,8 +272,7 @@ class ModListPageSkin extends SkinBase { } } - private static Task loadModIcon(LocalModFile modFile) { - int size = 40; + private static Task loadModIcon(LocalModFile modFile, int size) { return Task.supplyAsync(() -> { if (StringUtils.isNotBlank(modFile.getLogoPath())) { try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.getFile())) { @@ -360,7 +359,7 @@ class ModListPageSkin extends SkinBase { titleContainer.setSpacing(8); ImageView imageView = new ImageView(); - loadModIcon(modInfo.getModInfo()) + loadModIcon(modInfo.getModInfo(), 40) .whenComplete(Schedulers.javafx(), (image, exception) -> { imageView.setImage(image); }).start(); @@ -490,6 +489,7 @@ class ModListPageSkin extends SkinBase { final class ModInfoListCell extends MDListCell { JFXCheckBox checkBox = new JFXCheckBox(); + ImageView imageView = new ImageView(); TwoLineListItem content = new TwoLineListItem(); JFXButton restoreButton = new JFXButton(); JFXButton infoButton = new JFXButton(); @@ -506,6 +506,11 @@ class ModListPageSkin extends SkinBase { content.setMouseTransparent(true); setSelectable(); + imageView.setFitWidth(24); + imageView.setFitHeight(24); + imageView.setPreserveRatio(true); + imageView.setImage(FXUtils.newBuiltinImage("/assets/img/command.png", 24, 24, true, true)); + restoreButton.getStyleClass().add("toggle-icon4"); restoreButton.setGraphic(FXUtils.limitingSize(SVG.RESTORE.createIcon(Theme.blackFill(), 24), 24, 24)); @@ -517,7 +522,7 @@ class ModListPageSkin extends SkinBase { infoButton.getStyleClass().add("toggle-icon4"); infoButton.setGraphic(FXUtils.limitingSize(SVG.INFO.createIcon(Theme.blackFill(), 24), 24, 24)); - container.getChildren().setAll(checkBox, content, restoreButton, revealButton, infoButton); + container.getChildren().setAll(checkBox, imageView, content, restoreButton, revealButton, infoButton); StackPane.setMargin(container, new Insets(8)); getContainer().getChildren().setAll(container); @@ -526,6 +531,12 @@ class ModListPageSkin extends SkinBase { @Override protected void updateControl(ModInfoObject dataItem, boolean empty) { if (empty) return; + + loadModIcon(dataItem.getModInfo(), 24) + .whenComplete(Schedulers.javafx(), (image, exception) -> { + imageView.setImage(image); + }).start(); + content.setTitle(dataItem.getTitle()); content.getTags().clear(); switch (dataItem.getModInfo().getModLoaderType()) { From f43e0c0d8068f11be68ed05cdd300466d25b4546 Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Mon, 30 Jun 2025 21:06:16 +0800 Subject: [PATCH 16/19] Update ModListPageSkin.java --- .../hmcl/ui/versions/ModListPageSkin.java | 91 +++++++++++++++---- 1 file changed, 72 insertions(+), 19 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 0729d29d3..9372abe76 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -274,29 +274,82 @@ class ModListPageSkin extends SkinBase { private static Task loadModIcon(LocalModFile modFile, int size) { return Task.supplyAsync(() -> { + List iconPaths = new ArrayList<>(); + if (StringUtils.isNotBlank(modFile.getLogoPath())) { - try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.getFile())) { - Path iconPath = fs.getPath(modFile.getLogoPath()); - if (Files.exists(iconPath)) { - try (InputStream stream = Files.newInputStream(iconPath)) { - return new Image(stream, size, size, true, true); - } - } - } catch (Exception e) { - LOG.warning("Failed to load image " + modFile.getLogoPath(), e); - } + iconPaths.add(modFile.getLogoPath()); } - String iconPath; - switch (modFile.getModLoaderType()) { - case FORGE: iconPath = "/assets/img/forge.png"; break; - case NEO_FORGED: iconPath = "/assets/img/neoforge.png"; break; - case FABRIC: iconPath = "/assets/img/fabric.png"; break; - case QUILT: iconPath = "/assets/img/quilt.png"; break; - case LITE_LOADER: iconPath = "/assets/img/liteloader.png"; break; - default: iconPath = "/assets/img/command.png"; break; + iconPaths.addAll(Arrays.asList( + "icon.png", + "logo.png", + "mod_logo.png", + "pack.png", + "logoFile.png", + "assets/icon.png", + "assets/logo.png", + "assets/mod_icon.png", + "assets/mod_logo.png", + "META-INF/icon.png", + "META-INF/logo.png", + "META-INF/mod_icon.png", + "textures/icon.png", + "textures/logo.png", + "textures/mod_icon.png", + "resources/icon.png", + "resources/logo.png", + "resources/mod_icon.png" + )); + + String modId = modFile.getId(); + if (StringUtils.isNotBlank(modId)) { + iconPaths.addAll(Arrays.asList( + "assets/" + modId + "/icon.png", + "assets/" + modId + "/logo.png", + "assets/" + modId.replace("-", "") + "/icon.png", + "assets/" + modId.replace("-", "") + "/logo.png", + modId + ".png", + modId + "-logo.png", + modId + "-icon.png", + modId + "_logo.png", + modId + "_icon.png", + "textures/" + modId + "/icon.png", + "textures/" + modId + "/logo.png", + "resources/" + modId + "/icon.png", + "resources/" + modId + "/logo.png" + )); } - return FXUtils.newBuiltinImage(iconPath, size, size, true, true); + + try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modFile.getFile())) { + for (String path : iconPaths) { + Path iconPath = fs.getPath(path); + if (Files.exists(iconPath)) { + try (InputStream stream = Files.newInputStream(iconPath)) { + Image image = new Image(stream, size, size, true, true); + if (!image.isError() && + image.getWidth() > 0 && + image.getHeight() > 0 && + Math.abs(image.getWidth() - image.getHeight()) < 1) { + return image; + } + } + } + } + } catch (Exception e) { + LOG.warning("Failed to load mod icons", e); + } + + String defaultIcon; + switch (modFile.getModLoaderType()) { + case FORGE: defaultIcon = "/assets/img/forge.png"; break; + case NEO_FORGED: defaultIcon = "/assets/img/neoforge.png"; break; + case FABRIC: defaultIcon = "/assets/img/fabric.png"; break; + case QUILT: defaultIcon = "/assets/img/quilt.png"; break; + case LITE_LOADER: defaultIcon = "/assets/img/liteloader.png"; break; + default: defaultIcon = "/assets/img/command.png"; break; + } + + return FXUtils.newBuiltinImage(defaultIcon, size, size, true, true); }); } From 3e8c4d67d940f2ecf590c35e7a7d34bff18ae792 Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Mon, 30 Jun 2025 21:18:52 +0800 Subject: [PATCH 17/19] Update ModListPageSkin.java --- .../hmcl/ui/versions/ModListPageSkin.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 9372abe76..f5dbd501b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -422,16 +422,19 @@ class ModListPageSkin extends SkinBase { if (modInfo.getMod() != null) { title.getTags().add(modInfo.getMod().getDisplayName()); } - if (StringUtils.isNotBlank(modInfo.getModInfo().getGameVersion())) { - title.getTags().add(i18n("game.version") + ": " + modInfo.getModInfo().getGameVersion()); - } - if (StringUtils.isNotBlank(modInfo.getModInfo().getVersion())) { - title.getTags().add(modInfo.getModInfo().getVersion()); - } if (StringUtils.isNotBlank(modInfo.getModInfo().getAuthors())) { title.getTags().add(i18n("archive.author") + ": " + modInfo.getModInfo().getAuthors()); } - title.setSubtitle(FileUtils.getName(modInfo.getModInfo().getFile())); + + List subtitleParts = new ArrayList<>(); + subtitleParts.add(FileUtils.getName(modInfo.getModInfo().getFile())); + if (StringUtils.isNotBlank(modInfo.getModInfo().getGameVersion())) { + subtitleParts.add(modInfo.getModInfo().getGameVersion()); + } + if (StringUtils.isNotBlank(modInfo.getModInfo().getVersion())) { + subtitleParts.add(modInfo.getModInfo().getVersion()); + } + title.setSubtitle(String.join(", ", subtitleParts)); titleContainer.getChildren().setAll(FXUtils.limitingSize(imageView, 40, 40), title); setHeading(titleContainer); From e0e888a76b8aa625269e5d82e5221405c938888b Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Mon, 30 Jun 2025 21:24:12 +0800 Subject: [PATCH 18/19] Update ModListPageSkin.java --- .../java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java | 1 + 1 file changed, 1 insertion(+) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index f5dbd501b..1347b1646 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -441,6 +441,7 @@ class ModListPageSkin extends SkinBase { Label description = new Label(modInfo.getModInfo().getDescription().toString()); FXUtils.copyOnDoubleClick(description); + FXUtils.installFastTooltip(description, modInfo.getModInfo().getDescription().toString()); setBody(description); if (StringUtils.isNotBlank(modInfo.getModInfo().getId())) { From 33965c9ee0f56901c2e5fe6b3606109b49c6771a Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Mon, 30 Jun 2025 22:00:51 +0800 Subject: [PATCH 19/19] Update ModListPageSkin.java --- .../java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 1347b1646..6f89cbfb8 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -434,6 +434,9 @@ class ModListPageSkin extends SkinBase { if (StringUtils.isNotBlank(modInfo.getModInfo().getVersion())) { subtitleParts.add(modInfo.getModInfo().getVersion()); } + if (StringUtils.isNotBlank(modInfo.getModInfo().getAuthors())) { + subtitleParts.add(i18n("archive.author") + ": " + modInfo.getModInfo().getAuthors()); + } title.setSubtitle(String.join(", ", subtitleParts)); titleContainer.getChildren().setAll(FXUtils.limitingSize(imageView, 40, 40), title);