添加动画开关 (#2111)

This commit is contained in:
Glavo 2023-02-14 19:12:30 +08:00 committed by GitHub
parent 389d430dbd
commit ab264955f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 135 additions and 45 deletions

View File

@ -191,6 +191,9 @@ public final class Config implements Cloneable, Observable {
@SerializedName("preferredLoginType") @SerializedName("preferredLoginType")
private StringProperty preferredLoginType = new SimpleStringProperty(); private StringProperty preferredLoginType = new SimpleStringProperty();
@SerializedName("animationDisabled")
private BooleanProperty animationDisabled = new SimpleBooleanProperty();
private transient ObservableHelper helper = new ObservableHelper(this); private transient ObservableHelper helper = new ObservableHelper(this);
public Config() { public Config() {
@ -601,6 +604,18 @@ public final class Config implements Cloneable, Observable {
return preferredLoginType; return preferredLoginType;
} }
public boolean isAnimationDisabled() {
return animationDisabled.get();
}
public BooleanProperty animationDisabledProperty() {
return animationDisabled;
}
public void setAnimationDisabled(boolean animationDisabled) {
this.animationDisabled.set(animationDisabled);
}
public boolean isTitleTransparent() { public boolean isTitleTransparent() {
return titleTransparent.get(); return titleTransparent.get();
} }

View File

@ -20,6 +20,7 @@ package org.jackhuang.hmcl.setting;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.game.HMCLCacheRepository; import org.jackhuang.hmcl.game.HMCLCacheRepository;
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
import org.jackhuang.hmcl.util.CacheRepository; import org.jackhuang.hmcl.util.CacheRepository;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
@ -54,6 +55,7 @@ public final class Settings {
Accounts.init(); Accounts.init();
Profiles.init(); Profiles.init();
AuthlibInjectorServers.init(); AuthlibInjectorServers.init();
AnimationUtils.init();
CacheRepository.setInstance(HMCLCacheRepository.REPOSITORY); CacheRepository.setInstance(HMCLCacheRepository.REPOSITORY);
HMCLCacheRepository.REPOSITORY.directoryProperty().bind(Bindings.createStringBinding(() -> { HMCLCacheRepository.REPOSITORY.directoryProperty().bind(Bindings.createStringBinding(() -> {

View File

@ -47,6 +47,7 @@ import javafx.util.Callback;
import javafx.util.Duration; import javafx.util.Duration;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
import org.jackhuang.hmcl.ui.construct.JFXHyperlink; import org.jackhuang.hmcl.ui.construct.JFXHyperlink;
import org.jackhuang.hmcl.util.Holder; import org.jackhuang.hmcl.util.Holder;
import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.Logging;
@ -275,7 +276,8 @@ public final class FXUtils {
} }
public static void smoothScrolling(ScrollPane scrollPane) { public static void smoothScrolling(ScrollPane scrollPane) {
ScrollUtils.addSmoothScrolling(scrollPane); if (AnimationUtils.isAnimationEnabled())
ScrollUtils.addSmoothScrolling(scrollPane);
} }
public static void installFastTooltip(Node node, Tooltip tooltip) { public static void installFastTooltip(Node node, Tooltip tooltip) {

View File

@ -0,0 +1,23 @@
package org.jackhuang.hmcl.ui.animation;
import org.jackhuang.hmcl.setting.ConfigHolder;
public final class AnimationUtils {
private AnimationUtils() {
}
/**
* Trigger initialization of this class.
* Should be called from {@link org.jackhuang.hmcl.setting.Settings#init()}.
*/
@SuppressWarnings("JavadocReference")
public static void init() {
}
private static final boolean enabled = !ConfigHolder.config().isAnimationDisabled();
public static boolean isAnimationEnabled() {
return enabled;
}
}

View File

@ -69,18 +69,23 @@ public class TransitionPane extends StackPane implements AnimationHandler {
return; return;
} }
transition.init(this); if (AnimationUtils.isAnimationEnabled()) {
transition.init(this);
// runLater or "init" will not work // runLater or "init" will not work
Platform.runLater(() -> { Platform.runLater(() -> {
Timeline newAnimation = new Timeline(); Timeline newAnimation = new Timeline();
newAnimation.getKeyFrames().addAll(transition.animate(this)); newAnimation.getKeyFrames().addAll(transition.animate(this));
newAnimation.getKeyFrames().add(new KeyFrame(duration, e -> { newAnimation.getKeyFrames().add(new KeyFrame(duration, e -> {
setMouseTransparent(false); setMouseTransparent(false);
getChildren().remove(previousNode); getChildren().remove(previousNode);
})); }));
FXUtils.playAnimation(this, "transition_pane", newAnimation); FXUtils.playAnimation(this, "transition_pane", newAnimation);
}); });
} else {
setMouseTransparent(false);
getChildren().remove(previousNode);
}
} }
private void updateContent(Node newView) { private void updateContent(Node newView) {

View File

@ -25,6 +25,9 @@ import javafx.animation.Timeline;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.Node; import javafx.scene.Node;
@ -35,6 +38,7 @@ import javafx.util.Duration;
import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
/** /**
* @author huangyuhui * @author huangyuhui
@ -70,6 +74,7 @@ class ComponentListCell extends StackPane {
} }
} }
@SuppressWarnings("unchecked")
private void updateLayout() { private void updateLayout() {
if (content instanceof ComponentList) { if (content instanceof ComponentList) {
ComponentList list = (ComponentList) content; ComponentList list = (ComponentList) content;
@ -134,42 +139,66 @@ class ComponentListCell extends StackPane {
container.getChildren().setAll(content); container.getChildren().setAll(content);
groupNode.getChildren().add(container); groupNode.getChildren().add(container);
Runnable onExpand = () -> { EventHandler<Event> onExpand;
if (expandAnimation != null && expandAnimation.getStatus() == Animation.Status.RUNNING) { if (AnimationUtils.isAnimationEnabled()) {
expandAnimation.stop(); onExpand = e -> {
} if (expandAnimation != null && expandAnimation.getStatus() == Animation.Status.RUNNING) {
expandAnimation.stop();
}
setExpanded(!isExpanded()); setExpanded(!isExpanded());
if (isExpanded()) { if (isExpanded()) {
list.onExpand(); list.onExpand();
list.layout(); list.layout();
} }
Platform.runLater(() -> {
double newAnimatedHeight = (content.prefHeight(-1) + 8 + 10) * (isExpanded() ? 1 : -1);
double newHeight = isExpanded() ? getHeight() + newAnimatedHeight : prefHeight(-1);
double contentHeight = isExpanded() ? newAnimatedHeight : 0;
if (isExpanded()) {
updateClip(newHeight);
}
expandAnimation = new Timeline(new KeyFrame(new Duration(320.0),
new KeyValue(container.minHeightProperty(), contentHeight, FXUtils.SINE),
new KeyValue(container.maxHeightProperty(), contentHeight, FXUtils.SINE)
));
if (!isExpanded()) {
expandAnimation.setOnFinished(e2 -> updateClip(newHeight));
}
expandAnimation.play();
});
};
} else {
onExpand = e -> {
setExpanded(!isExpanded());
Platform.runLater(() -> {
double newAnimatedHeight = (content.prefHeight(-1) + 8 + 10) * (isExpanded() ? 1 : -1); double newAnimatedHeight = (content.prefHeight(-1) + 8 + 10) * (isExpanded() ? 1 : -1);
double newHeight = isExpanded() ? getHeight() + newAnimatedHeight : prefHeight(-1); double newHeight = isExpanded() ? getHeight() + newAnimatedHeight : prefHeight(-1);
double contentHeight = isExpanded() ? newAnimatedHeight : 0; double contentHeight = isExpanded() ? newAnimatedHeight : 0;
if (isExpanded()) { if (isExpanded()) {
list.onExpand();
list.layout();
updateClip(newHeight); updateClip(newHeight);
} }
expandAnimation = new Timeline(new KeyFrame(new Duration(320.0), container.setMinHeight(contentHeight);
new KeyValue(container.minHeightProperty(), contentHeight, FXUtils.SINE), container.setMaxHeight(contentHeight);
new KeyValue(container.maxHeightProperty(), contentHeight, FXUtils.SINE)
));
if (!isExpanded()) { if (!isExpanded()) {
expandAnimation.setOnFinished(e2 -> updateClip(newHeight)); updateClip(newHeight);
} }
};
}
expandAnimation.play(); headerRippler.setOnMouseClicked(onExpand);
}); expandButton.setOnAction((EventHandler<ActionEvent>) (Object) onExpand);
};
headerRippler.setOnMouseClicked(e -> onExpand.run());
expandButton.setOnMouseClicked(e -> onExpand.run());
expandedProperty().addListener((a, b, newValue) -> expandedProperty().addListener((a, b, newValue) ->
expandIcon.setRotate(newValue ? 180 : 0)); expandIcon.setRotate(newValue ? 180 : 0));

View File

@ -45,6 +45,7 @@ import org.jackhuang.hmcl.setting.Theme;
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.SVG; import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.animation.AnimationUtils;
import org.jackhuang.hmcl.ui.construct.AnnouncementCard; import org.jackhuang.hmcl.ui.construct.AnnouncementCard;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane; import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
import org.jackhuang.hmcl.ui.construct.PopupMenu; import org.jackhuang.hmcl.ui.construct.PopupMenu;
@ -254,18 +255,22 @@ public final class MainPage extends StackPane implements DecoratorPage {
} }
private void doAnimation(boolean show) { private void doAnimation(boolean show) {
Duration duration = Duration.millis(320); if (AnimationUtils.isAnimationEnabled()) {
Timeline nowAnimation = new Timeline(); Duration duration = Duration.millis(320);
nowAnimation.getKeyFrames().addAll( Timeline nowAnimation = new Timeline();
new KeyFrame(Duration.ZERO, nowAnimation.getKeyFrames().addAll(
new KeyValue(updatePane.translateXProperty(), show ? 260 : 0, SINE)), new KeyFrame(Duration.ZERO,
new KeyFrame(duration, new KeyValue(updatePane.translateXProperty(), show ? 260 : 0, SINE)),
new KeyValue(updatePane.translateXProperty(), show ? 0 : 260, SINE))); new KeyFrame(duration,
if (show) nowAnimation.getKeyFrames().add( new KeyValue(updatePane.translateXProperty(), show ? 0 : 260, SINE)));
new KeyFrame(Duration.ZERO, e -> updatePane.setVisible(true))); if (show) nowAnimation.getKeyFrames().add(
else nowAnimation.getKeyFrames().add( new KeyFrame(Duration.ZERO, e -> updatePane.setVisible(true)));
new KeyFrame(duration, e -> updatePane.setVisible(false))); else nowAnimation.getKeyFrames().add(
nowAnimation.play(); new KeyFrame(duration, e -> updatePane.setVisible(false)));
nowAnimation.play();
} else {
updatePane.setVisible(show);
}
} }
private void launch() { private void launch() {

View File

@ -88,6 +88,12 @@ public class PersonalizationPage extends StackPane {
titleTransparentButton.selectedProperty().bindBidirectional(config().titleTransparentProperty()); titleTransparentButton.selectedProperty().bindBidirectional(config().titleTransparentProperty());
titleTransparentButton.setTitle(i18n("settings.launcher.title_transparent")); titleTransparentButton.setTitle(i18n("settings.launcher.title_transparent"));
} }
{
OptionToggleButton animationButton = new OptionToggleButton();
themeList.getContent().add(animationButton);
animationButton.selectedProperty().bindBidirectional(config().animationDisabledProperty());
animationButton.setTitle(i18n("settings.launcher.turn_off_animations"));
}
content.getChildren().addAll(ComponentList.createComponentListTitle(i18n("settings.launcher.appearance")), themeList); content.getChildren().addAll(ComponentList.createComponentListTitle(i18n("settings.launcher.appearance")), themeList);
{ {

View File

@ -1066,6 +1066,7 @@ settings.launcher.proxy.socks=SOCKS
settings.launcher.proxy.username=Username settings.launcher.proxy.username=Username
settings.launcher.theme=Theme settings.launcher.theme=Theme
settings.launcher.title_transparent=Transparent titlebar settings.launcher.title_transparent=Transparent titlebar
settings.launcher.turn_off_animations=Turn off animation (applies after restart)
settings.launcher.version_list_source=Version List settings.launcher.version_list_source=Version List
settings.memory=Memory settings.memory=Memory

View File

@ -936,6 +936,7 @@ settings.launcher.proxy.socks=Socks
settings.launcher.proxy.username=帳戶 settings.launcher.proxy.username=帳戶
settings.launcher.theme=主題 settings.launcher.theme=主題
settings.launcher.title_transparent=標題欄透明 settings.launcher.title_transparent=標題欄透明
settings.launcher.turn_off_animations=關閉動畫 (重啟後生效)
settings.launcher.version_list_source=版本列表來源 settings.launcher.version_list_source=版本列表來源
settings.memory=遊戲記憶體 settings.memory=遊戲記憶體

View File

@ -934,6 +934,7 @@ settings.launcher.proxy.socks=Socks
settings.launcher.proxy.username=帐户 settings.launcher.proxy.username=帐户
settings.launcher.theme=主题 settings.launcher.theme=主题
settings.launcher.title_transparent=标题栏透明 settings.launcher.title_transparent=标题栏透明
settings.launcher.turn_off_animations=关闭动画 (重启后生效)
settings.launcher.version_list_source=版本列表源 settings.launcher.version_list_source=版本列表源
settings.memory=游戏内存 settings.memory=游戏内存