@@ -48,8 +48,8 @@ public class WorldListItem extends Control {
|
|||||||
this.world = world;
|
this.world = world;
|
||||||
|
|
||||||
title.set(parseColorEscapes(world.getWorldName()));
|
title.set(parseColorEscapes(world.getWorldName()));
|
||||||
|
|
||||||
subtitle.set(i18n("world.description", world.getFileName(), formatDateTime(Instant.ofEpochMilli(world.getLastPlayed())), world.getGameVersion() == null ? i18n("message.unknown") : world.getGameVersion()));
|
subtitle.set(i18n("world.description", world.getFileName(), formatDateTime(Instant.ofEpochMilli(world.getLastPlayed())), world.getGameVersion() == null ? i18n("message.unknown") : world.getGameVersion()));
|
||||||
|
image.set(world.getIcon());
|
||||||
|
|
||||||
FXUtils.onClicked(this, this::showInfo);
|
FXUtils.onClicked(this, this::showInfo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ package org.jackhuang.hmcl.ui.versions;
|
|||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import com.jfoenix.controls.JFXPopup;
|
import com.jfoenix.controls.JFXPopup;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.SkinBase;
|
import javafx.scene.control.SkinBase;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
@@ -38,6 +40,9 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
|||||||
|
|
||||||
public class WorldListItemSkin extends SkinBase<WorldListItem> {
|
public class WorldListItemSkin extends SkinBase<WorldListItem> {
|
||||||
|
|
||||||
|
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
||||||
|
private final ChangeListener<Image> iconListener;
|
||||||
|
|
||||||
public WorldListItemSkin(WorldListItem skinnable) {
|
public WorldListItemSkin(WorldListItem skinnable) {
|
||||||
super(skinnable);
|
super(skinnable);
|
||||||
|
|
||||||
@@ -54,14 +59,15 @@ public class WorldListItemSkin extends SkinBase<WorldListItem> {
|
|||||||
|
|
||||||
ImageView imageView = new ImageView();
|
ImageView imageView = new ImageView();
|
||||||
FXUtils.limitSize(imageView, 32, 32);
|
FXUtils.limitSize(imageView, 32, 32);
|
||||||
imageView.imageProperty().bind(skinnable.imageProperty());
|
iconListener = FXUtils.onWeakChangeAndOperate(skinnable.imageProperty(), image ->
|
||||||
|
imageView.setImage(image == null ? FXUtils.newBuiltinImage("/assets/img/unknown_server.png") : image));
|
||||||
imageViewContainer.getChildren().setAll(imageView);
|
imageViewContainer.getChildren().setAll(imageView);
|
||||||
|
|
||||||
TwoLineListItem item = new TwoLineListItem();
|
TwoLineListItem item = new TwoLineListItem();
|
||||||
item.titleProperty().bind(skinnable.titleProperty());
|
item.titleProperty().bind(skinnable.titleProperty());
|
||||||
item.subtitleProperty().bind(skinnable.subtitleProperty());
|
item.subtitleProperty().bind(skinnable.subtitleProperty());
|
||||||
BorderPane.setAlignment(item, Pos.CENTER);
|
BorderPane.setAlignment(item, Pos.CENTER);
|
||||||
center.getChildren().setAll(imageView, item);
|
center.getChildren().setAll(imageViewContainer, item);
|
||||||
root.setCenter(center);
|
root.setCenter(center);
|
||||||
|
|
||||||
PopupMenu menu = new PopupMenu();
|
PopupMenu menu = new PopupMenu();
|
||||||
|
|||||||
BIN
HMCL/src/main/resources/assets/img/unknown_server.png
Normal file
BIN
HMCL/src/main/resources/assets/img/unknown_server.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
@@ -22,6 +22,7 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
|||||||
import com.github.steveice10.opennbt.tag.builtin.LongTag;
|
import com.github.steveice10.opennbt.tag.builtin.LongTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
import org.jackhuang.hmcl.util.io.Unzipper;
|
import org.jackhuang.hmcl.util.io.Unzipper;
|
||||||
@@ -46,6 +47,7 @@ public class World {
|
|||||||
private String worldName;
|
private String worldName;
|
||||||
private String gameVersion;
|
private String gameVersion;
|
||||||
private long lastPlayed;
|
private long lastPlayed;
|
||||||
|
private Image icon;
|
||||||
|
|
||||||
public World(Path file) throws IOException {
|
public World(Path file) throws IOException {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
@@ -62,6 +64,17 @@ public class World {
|
|||||||
fileName = FileUtils.getName(file);
|
fileName = FileUtils.getName(file);
|
||||||
Path levelDat = file.resolve("level.dat");
|
Path levelDat = file.resolve("level.dat");
|
||||||
getWorldName(levelDat);
|
getWorldName(levelDat);
|
||||||
|
|
||||||
|
Path iconFile = file.resolve("icon.png");
|
||||||
|
if (Files.isRegularFile(iconFile)) {
|
||||||
|
try (InputStream inputStream = Files.newInputStream(iconFile)) {
|
||||||
|
icon = new Image(inputStream, 64, 64, true, false);
|
||||||
|
if (icon.isError())
|
||||||
|
throw icon.getException();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warning("Failed to load world icon", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path getFile() {
|
public Path getFile() {
|
||||||
@@ -88,12 +101,27 @@ public class World {
|
|||||||
return gameVersion;
|
return gameVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Image getIcon() {
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
private void loadFromZipImpl(Path root) throws IOException {
|
private void loadFromZipImpl(Path root) throws IOException {
|
||||||
Path levelDat = root.resolve("level.dat");
|
Path levelDat = root.resolve("level.dat");
|
||||||
if (!Files.exists(levelDat))
|
if (!Files.exists(levelDat))
|
||||||
throw new IOException("Not a valid world zip file since level.dat cannot be found.");
|
throw new IOException("Not a valid world zip file since level.dat cannot be found.");
|
||||||
|
|
||||||
getWorldName(levelDat);
|
getWorldName(levelDat);
|
||||||
|
|
||||||
|
Path iconFile = root.resolve("icon.png");
|
||||||
|
if (Files.isRegularFile(iconFile)) {
|
||||||
|
try (InputStream inputStream = Files.newInputStream(iconFile)) {
|
||||||
|
icon = new Image(inputStream, 64, 64, true, false);
|
||||||
|
if (icon.isError())
|
||||||
|
throw icon.getException();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warning("Failed to load world icon", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadFromZip() throws IOException {
|
private void loadFromZip() throws IOException {
|
||||||
|
|||||||
Reference in New Issue
Block a user