mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-08-04 03:46:57 -04:00
Merge 33965c9ee0f56901c2e5fe6b3606109b49c6771a into 9969dc60c5278340b6b9a4d7facdde620e99d1f5
This commit is contained in:
commit
44c5b4ab1b
@ -272,6 +272,87 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Task<Image> loadModIcon(LocalModFile modFile, int size) {
|
||||||
|
return Task.supplyAsync(() -> {
|
||||||
|
List<String> iconPaths = new ArrayList<>();
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(modFile.getLogoPath())) {
|
||||||
|
iconPaths.add(modFile.getLogoPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static class ModInfoObject extends RecursiveTreeObject<ModInfoObject> implements Comparable<ModInfoObject> {
|
static class ModInfoObject extends RecursiveTreeObject<ModInfoObject> implements Comparable<ModInfoObject> {
|
||||||
private final BooleanProperty active;
|
private final BooleanProperty active;
|
||||||
private final LocalModFile localModFile;
|
private final LocalModFile localModFile;
|
||||||
@ -284,15 +365,19 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
|||||||
this.active = localModFile.activeProperty();
|
this.active = localModFile.activeProperty();
|
||||||
|
|
||||||
StringBuilder title = new StringBuilder(localModFile.getName());
|
StringBuilder title = new StringBuilder(localModFile.getName());
|
||||||
if (isNotBlank(localModFile.getVersion()))
|
|
||||||
title.append(" ").append(localModFile.getVersion());
|
|
||||||
this.title = title.toString();
|
this.title = title.toString();
|
||||||
|
|
||||||
StringBuilder message = new StringBuilder(localModFile.getFileName());
|
List<String> parts = new ArrayList<>();
|
||||||
if (isNotBlank(localModFile.getGameVersion()))
|
if (isNotBlank(localModFile.getId())) {
|
||||||
message.append(", ").append(i18n("mods.game.version")).append(": ").append(localModFile.getGameVersion());
|
parts.add(localModFile.getId());
|
||||||
if (isNotBlank(localModFile.getAuthors()))
|
}
|
||||||
message.append(", ").append(i18n("archive.author")).append(": ").append(localModFile.getAuthors());
|
if (isNotBlank(localModFile.getVersion())) {
|
||||||
|
parts.add(localModFile.getVersion());
|
||||||
|
}
|
||||||
|
if (isNotBlank(localModFile.getGameVersion())) {
|
||||||
|
parts.add(i18n("game.version") + ": " + localModFile.getGameVersion());
|
||||||
|
}
|
||||||
|
String message = String.join(", ", parts);
|
||||||
this.message = message.toString();
|
this.message = message.toString();
|
||||||
|
|
||||||
this.mod = ModTranslations.MOD.getModById(localModFile.getId());
|
this.mod = ModTranslations.MOD.getModById(localModFile.getId());
|
||||||
@ -326,79 +411,40 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
|||||||
HBox titleContainer = new HBox();
|
HBox titleContainer = new HBox();
|
||||||
titleContainer.setSpacing(8);
|
titleContainer.setSpacing(8);
|
||||||
|
|
||||||
ImageView imageView = new ImageView();
|
ImageView imageView = new ImageView();
|
||||||
Task.supplyAsync(() -> {
|
loadModIcon(modInfo.getModInfo(), 40)
|
||||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modInfo.getModInfo().getFile())) {
|
.whenComplete(Schedulers.javafx(), (image, exception) -> {
|
||||||
String logoPath = modInfo.getModInfo().getLogoPath();
|
|
||||||
if (StringUtils.isNotBlank(logoPath)) {
|
|
||||||
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;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
LOG.warning("Failed to load image " + logoPath, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}).whenComplete(Schedulers.javafx(), (image, exception) -> {
|
|
||||||
if (image != null) {
|
|
||||||
imageView.setImage(image);
|
imageView.setImage(image);
|
||||||
} else {
|
}).start();
|
||||||
imageView.setImage(FXUtils.newBuiltinImage("/assets/img/command.png", 40, 40, true, true));
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
|
|
||||||
TwoLineListItem title = new TwoLineListItem();
|
TwoLineListItem title = new TwoLineListItem();
|
||||||
title.setTitle(modInfo.getModInfo().getName());
|
title.setTitle(modInfo.getModInfo().getName());
|
||||||
if (StringUtils.isNotBlank(modInfo.getModInfo().getVersion())) {
|
if (modInfo.getMod() != null) {
|
||||||
title.getTags().setAll(modInfo.getModInfo().getVersion());
|
title.getTags().add(modInfo.getMod().getDisplayName());
|
||||||
}
|
}
|
||||||
title.setSubtitle(FileUtils.getName(modInfo.getModInfo().getFile()));
|
if (StringUtils.isNotBlank(modInfo.getModInfo().getAuthors())) {
|
||||||
|
title.getTags().add(i18n("archive.author") + ": " + modInfo.getModInfo().getAuthors());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> 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());
|
||||||
|
}
|
||||||
|
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);
|
titleContainer.getChildren().setAll(FXUtils.limitingSize(imageView, 40, 40), title);
|
||||||
setHeading(titleContainer);
|
setHeading(titleContainer);
|
||||||
|
|
||||||
Label description = new Label(modInfo.getModInfo().getDescription().toString());
|
Label description = new Label(modInfo.getModInfo().getDescription().toString());
|
||||||
FXUtils.copyOnDoubleClick(description);
|
FXUtils.copyOnDoubleClick(description);
|
||||||
|
FXUtils.installFastTooltip(description, modInfo.getModInfo().getDescription().toString());
|
||||||
setBody(description);
|
setBody(description);
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(modInfo.getModInfo().getId())) {
|
if (StringUtils.isNotBlank(modInfo.getModInfo().getId())) {
|
||||||
@ -503,6 +549,7 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
|||||||
|
|
||||||
final class ModInfoListCell extends MDListCell<ModInfoObject> {
|
final class ModInfoListCell extends MDListCell<ModInfoObject> {
|
||||||
JFXCheckBox checkBox = new JFXCheckBox();
|
JFXCheckBox checkBox = new JFXCheckBox();
|
||||||
|
ImageView imageView = new ImageView();
|
||||||
TwoLineListItem content = new TwoLineListItem();
|
TwoLineListItem content = new TwoLineListItem();
|
||||||
JFXButton restoreButton = new JFXButton();
|
JFXButton restoreButton = new JFXButton();
|
||||||
JFXButton infoButton = new JFXButton();
|
JFXButton infoButton = new JFXButton();
|
||||||
@ -519,6 +566,11 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
|||||||
content.setMouseTransparent(true);
|
content.setMouseTransparent(true);
|
||||||
setSelectable();
|
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.getStyleClass().add("toggle-icon4");
|
||||||
restoreButton.setGraphic(FXUtils.limitingSize(SVG.RESTORE.createIcon(Theme.blackFill(), 24), 24, 24));
|
restoreButton.setGraphic(FXUtils.limitingSize(SVG.RESTORE.createIcon(Theme.blackFill(), 24), 24, 24));
|
||||||
|
|
||||||
@ -530,7 +582,7 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
|||||||
infoButton.getStyleClass().add("toggle-icon4");
|
infoButton.getStyleClass().add("toggle-icon4");
|
||||||
infoButton.setGraphic(FXUtils.limitingSize(SVG.INFO.createIcon(Theme.blackFill(), 24), 24, 24));
|
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));
|
StackPane.setMargin(container, new Insets(8));
|
||||||
getContainer().getChildren().setAll(container);
|
getContainer().getChildren().setAll(container);
|
||||||
@ -539,6 +591,12 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
|||||||
@Override
|
@Override
|
||||||
protected void updateControl(ModInfoObject dataItem, boolean empty) {
|
protected void updateControl(ModInfoObject dataItem, boolean empty) {
|
||||||
if (empty) return;
|
if (empty) return;
|
||||||
|
|
||||||
|
loadModIcon(dataItem.getModInfo(), 24)
|
||||||
|
.whenComplete(Schedulers.javafx(), (image, exception) -> {
|
||||||
|
imageView.setImage(image);
|
||||||
|
}).start();
|
||||||
|
|
||||||
content.setTitle(dataItem.getTitle());
|
content.setTitle(dataItem.getTitle());
|
||||||
content.getTags().clear();
|
content.getTags().clear();
|
||||||
switch (dataItem.getModInfo().getModLoaderType()) {
|
switch (dataItem.getModInfo().getModLoaderType()) {
|
||||||
@ -559,9 +617,14 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (dataItem.getMod() != null && I18n.isUseChinese()) {
|
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) {
|
if (booleanProperty != null) {
|
||||||
checkBox.selectedProperty().unbindBidirectional(booleanProperty);
|
checkBox.selectedProperty().unbindBidirectional(booleanProperty);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user