use a framerate-capped interpolated timeline for the server toggle and wallet tab loading pulse animations, and stop any running server toggle pulse before starting a new one

This commit is contained in:
Craig Raw
2026-09-17 10:09:12 +02:00
parent 9e999d3f07
commit 4da29f4e36
2 changed files with 7 additions and 13 deletions
@@ -2650,6 +2650,7 @@ public class AppController implements Initializable {
} }
private void serverToggleStartAnimation() { private void serverToggleStartAnimation() {
serverToggleStopAnimation();
Node thumbArea = serverToggle.lookup(".thumb-area"); Node thumbArea = serverToggle.lookup(".thumb-area");
if(thumbArea != null) { if(thumbArea != null) {
Timeline timeline = AnimationUtil.getPulse(thumbArea, Duration.millis(600), 1.0, 0.25, 8); Timeline timeline = AnimationUtil.getPulse(thumbArea, Duration.millis(600), 1.0, 0.25, 8);
@@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.control;
import javafx.animation.Animation; import javafx.animation.Animation;
import javafx.animation.KeyFrame; import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline; import javafx.animation.Timeline;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.util.Duration; import javafx.util.Duration;
@@ -20,7 +21,11 @@ public class AnimationUtil {
} }
public static Timeline getPulse(Node node, Duration duration, double fromValue, double toValue, int numIncrements) { public static Timeline getPulse(Node node, Duration duration, double fromValue, double toValue, int numIncrements) {
Timeline pulseTimeline = getFade(node, duration, fromValue, toValue, numIncrements); //Cap the framerate so the node is only redrawn numIncrements times per cycle, rather than on every 60Hz pulse
double targetFramerate = numIncrements / duration.toSeconds();
Timeline pulseTimeline = new Timeline(targetFramerate,
new KeyFrame(Duration.ZERO, new KeyValue(node.opacityProperty(), fromValue)),
new KeyFrame(duration, new KeyValue(node.opacityProperty(), toValue)));
pulseTimeline.setCycleCount(Animation.INDEFINITE); pulseTimeline.setCycleCount(Animation.INDEFINITE);
pulseTimeline.setAutoReverse(true); pulseTimeline.setAutoReverse(true);
@@ -28,17 +33,5 @@ public class AnimationUtil {
return pulseTimeline; return pulseTimeline;
} }
public static Timeline getFade(Node node, Duration duration, double fromValue, double toValue, int numIncrements) {
Timeline fadeTimeline = new Timeline();
Duration incrementDuration = duration.divide(numIncrements);
for(int i = 0; i < numIncrements; i++) {
double percent = ((double) numIncrements - i - 1) / numIncrements; //From 99% to 0%
double opacity = (percent * (fromValue - toValue)) + toValue;
fadeTimeline.getKeyFrames().add(new KeyFrame(incrementDuration.multiply(i+1), event -> node.setOpacity(opacity)));
}
return fadeTimeline;
}
public record AnimatedNode (Node node, Timeline timeline) {} public record AnimatedNode (Node node, Timeline timeline) {}
} }