This commit is contained in:
Glavo
2023-02-14 19:08:26 +08:00
committed by GitHub
parent 8b98932ae8
commit 389d430dbd

View File

@@ -20,7 +20,8 @@ package org.jackhuang.hmcl.ui.decorator;
import com.jfoenix.controls.JFXDialog; import com.jfoenix.controls.JFXDialog;
import com.jfoenix.controls.JFXSnackbar; import com.jfoenix.controls.JFXSnackbar;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.binding.Bindings; import javafx.beans.InvalidationListener;
import javafx.beans.WeakInvalidationListener;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler; import javafx.event.EventHandler;
@@ -35,6 +36,7 @@ import javafx.stage.Stage;
import org.jackhuang.hmcl.Launcher; import org.jackhuang.hmcl.Launcher;
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorDnD; import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorDnD;
import org.jackhuang.hmcl.setting.EnumBackgroundImage; import org.jackhuang.hmcl.setting.EnumBackgroundImage;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.account.AddAuthlibInjectorServerPane; import org.jackhuang.hmcl.ui.account.AddAuthlibInjectorServerPane;
@@ -55,6 +57,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Optional; import java.util.Optional;
import java.util.Random; import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -89,10 +92,23 @@ public class DecoratorController {
decorator.onBackNavButtonActionProperty().set(e -> back()); decorator.onBackNavButtonActionProperty().set(e -> back());
decorator.onRefreshNavButtonActionProperty().set(e -> refresh()); decorator.onRefreshNavButtonActionProperty().set(e -> refresh());
setupBackground();
setupAuthlibInjectorDnD(); setupAuthlibInjectorDnD();
// Setup background
decorator.setContentBackground(getBackground());
changeBackgroundListener = o -> {
final int currentCount = ++this.changeBackgroundCount;
CompletableFuture.supplyAsync(this::getBackground, Schedulers.io())
.thenAcceptAsync(background -> {
if (this.changeBackgroundCount == currentCount)
decorator.setContentBackground(background);
}, Schedulers.javafx());
};
WeakInvalidationListener weakListener = new WeakInvalidationListener(changeBackgroundListener);
config().backgroundImageTypeProperty().addListener(weakListener);
config().backgroundImageProperty().addListener(weakListener);
config().backgroundImageUrlProperty().addListener(weakListener);
// pass key events to current dialog / current page // pass key events to current dialog / current page
decorator.addEventFilter(KeyEvent.ANY, e -> { decorator.addEventFilter(KeyEvent.ANY, e -> {
if (!(e.getTarget() instanceof Node)) { if (!(e.getTarget() instanceof Node)) {
@@ -134,37 +150,40 @@ public class DecoratorController {
// ==== Background ==== // ==== Background ====
private void setupBackground() { //FXThread
decorator.contentBackgroundProperty().bind( private int changeBackgroundCount = 0;
Bindings.createObjectBinding(
() -> { @SuppressWarnings("FieldCanBeLocal") // Strong reference
Image image = null; private final InvalidationListener changeBackgroundListener;
if (config().getBackgroundImageType() == EnumBackgroundImage.CUSTOM && config().getBackgroundImage() != null) {
image = tryLoadImage(Paths.get(config().getBackgroundImage())) private Background getBackground() {
.orElse(null); EnumBackgroundImage imageType = config().getBackgroundImageType();
}
if (config().getBackgroundImageType() == EnumBackgroundImage.NETWORK) { Image image = null;
if (!NetworkUtils.isURL(config().getBackgroundImageUrl())) { switch (imageType) {
image = loadDefaultBackgroundImage(); case CUSTOM:
} else { String backgroundImage = config().getBackgroundImage();
image = new Image(config().getBackgroundImageUrl(), true); if (backgroundImage != null)
} image = tryLoadImage(Paths.get(backgroundImage)).orElse(null);
} else if (config().getBackgroundImageType() == EnumBackgroundImage.CLASSIC) { break;
image = newImage("/assets/img/background-classic.jpg"); case NETWORK:
} else if (config().getBackgroundImageType() == EnumBackgroundImage.TRANSLUCENT) { String backgroundImageUrl = config().getBackgroundImageUrl();
return new Background(new BackgroundFill(new Color(1, 1, 1, 0.5), CornerRadii.EMPTY, Insets.EMPTY)); if (backgroundImageUrl != null && NetworkUtils.isURL(backgroundImageUrl))
} image = tryLoadImage(backgroundImageUrl).orElse(null);
if (image == null) { break;
image = loadDefaultBackgroundImage(); case CLASSIC:
} image = newImage("/assets/img/background-classic.jpg");
return new Background(new BackgroundImage(image, BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.DEFAULT, new BackgroundSize(800, 480, false, false, true, true))); break;
}, case TRANSLUCENT:
config().backgroundImageTypeProperty(), return new Background(new BackgroundFill(new Color(1, 1, 1, 0.5), CornerRadii.EMPTY, Insets.EMPTY));
config().backgroundImageProperty(), }
config().backgroundImageUrlProperty())); if (image == null) {
image = loadDefaultBackgroundImage();
}
return new Background(new BackgroundImage(image, BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.DEFAULT, new BackgroundSize(800, 480, false, false, true, true)));
} }
private Image defaultBackground; private volatile Image defaultBackground;
/** /**
* Load background image from bg/, background.png, background.jpg, background.gif * Load background image from bg/, background.png, background.jpg, background.gif
@@ -196,7 +215,7 @@ public class DecoratorController {
List<Path> candidates; List<Path> candidates;
try (Stream<Path> stream = Files.list(imageDir)) { try (Stream<Path> stream = Files.list(imageDir)) {
candidates = stream candidates = stream
.filter(Files::isReadable) .filter(Files::isReadable)
.filter(it -> { .filter(it -> {
String ext = getExtension(it).toLowerCase(Locale.ROOT); String ext = getExtension(it).toLowerCase(Locale.ROOT);
return ext.equals("png") || ext.equals("jpg") || ext.equals("gif"); return ext.equals("png") || ext.equals("jpg") || ext.equals("gif");
@@ -224,9 +243,13 @@ public class DecoratorController {
if (!Files.isReadable(path)) if (!Files.isReadable(path))
return Optional.empty(); return Optional.empty();
return tryLoadImage(path.toAbsolutePath().toUri().toString());
}
private Optional<Image> tryLoadImage(String url) {
Image img; Image img;
try { try {
img = new Image(path.toAbsolutePath().toUri().toString()); img = new Image(url);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
LOG.log(WARNING, "Couldn't load background image", e); LOG.log(WARNING, "Couldn't load background image", e);
return Optional.empty(); return Optional.empty();