Rework loading icon

This commit is contained in:
crschnick
2025-06-06 03:23:47 +00:00
parent 98e6c499ec
commit 4e98d341da
5 changed files with 90 additions and 23 deletions

View File

@@ -2,8 +2,10 @@ package io.xpipe.app.browser;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.SimpleComp;
import io.xpipe.app.comp.base.LoadingIconComp;
import io.xpipe.app.comp.base.PrettyImageHelper;
import io.xpipe.app.core.App;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.util.BooleanScope;
@@ -417,26 +419,15 @@ public class BrowserSessionTabsComp extends SimpleComp {
});
if (tabModel.getIcon() != null) {
var ring = new RingProgressIndicator(0, false);
ring.setMinSize(16, 16);
ring.setPrefSize(16, 16);
ring.setMaxSize(16, 16);
ring.progressProperty()
.bind(Bindings.createDoubleBinding(
() -> tabModel.getBusy().get()
&& !AppPrefs.get().performanceMode().get()
? -1d
: 0,
PlatformThread.sync(tabModel.getBusy()),
AppPrefs.get().performanceMode()));
var loading = new LoadingIconComp(tabModel.getBusy(), AppFontSizes::base).createRegion();
loading.setPrefWidth(16);
loading.setPrefHeight(16);
var image = tabModel.getIcon();
var logo = PrettyImageHelper.ofFixedSizeSquare(image, 16).createRegion();
tab.graphicProperty()
.bind(Bindings.createObjectBinding(
() -> {
return tabModel.getBusy().get() ? ring : logo;
return tabModel.getBusy().get() ? loading : logo;
},
PlatformThread.sync(tabModel.getBusy())));
}
@@ -496,6 +487,7 @@ public class BrowserSessionTabsComp extends SimpleComp {
if (newValue != null) {
Platform.runLater(() -> {
Label l = (Label) tabs.lookup("#" + id + " .tab-label");
l.setGraphicTextGap(7);
var w = l.maxWidthProperty();
l.minWidthProperty().bind(w);
l.prefWidthProperty().bind(w);

View File

@@ -0,0 +1,76 @@
package io.xpipe.app.comp.base;
import atlantafx.base.controls.RingProgressIndicator;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.CompStructure;
import io.xpipe.app.comp.SimpleComp;
import io.xpipe.app.comp.SimpleCompStructure;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.util.PlatformThread;
import io.xpipe.app.util.ThreadHelper;
import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import java.util.function.Consumer;
import java.util.function.Function;
public class LoadingIconComp extends SimpleComp {
private static final char[] chars = new char[] {'⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'};
private final ObservableValue<Boolean> show;
private final Consumer<Node> fontSize;
public LoadingIconComp(ObservableValue<Boolean> show, Consumer<Node> fontSize) {this.show = show;
this.fontSize = fontSize;
}
@Override
protected Region createSimple() {
var label = new Label();
fontSize.accept(label);
label.setAlignment(Pos.CENTER);
label.setText(Character.toString(chars[0]));
label.getStyleClass().add("loading-icon-comp");
var timer = new AnimationTimer() {
long init = 0;
int index = 0;
@Override
public void handle(long now) {
if (init == 0) {
init = now;
}
var nowMs = now;
if ((nowMs - init) > 300 * 1_000_000L) {
label.setText(Character.toString(chars[index]));
init = nowMs;
index = (index + 1) % chars.length;
}
}
};
show.subscribe(val -> {
if (val) {
timer.start();
} else {
timer.stop();
}
});
return label;
}
}

View File

@@ -3,6 +3,7 @@ package io.xpipe.app.comp.base;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.CompStructure;
import io.xpipe.app.comp.SimpleCompStructure;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.util.PlatformThread;
import io.xpipe.app.util.ThreadHelper;
@@ -37,9 +38,7 @@ public class LoadingOverlayComp extends Comp<CompStructure<StackPane>> {
var compStruc = comp.createStructure();
var r = compStruc.get();
var loading = new RingProgressIndicator(0, false);
loading.progressProperty().bind(progress);
loading.visibleProperty().bind(Bindings.not(AppPrefs.get().performanceMode()));
var loading = new LoadingIconComp(showLoading, AppFontSizes::xxxl).createRegion();
var loadingOverlay = new StackPane(loading);
loadingOverlay.getStyleClass().add("loading-comp");

View File

@@ -42,7 +42,7 @@ public class AppFontSizes {
}
public static void xxxl(Node node) {
apply(node, AppFontSizes::getXxl);
apply(node, AppFontSizes::getXxxl);
}
public static void title(Node node) {

View File

@@ -1,12 +1,14 @@
package io.xpipe.app.terminal;
import io.xpipe.app.comp.SimpleComp;
import io.xpipe.app.comp.base.LoadingIconComp;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.window.AppMainWindow;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.util.PlatformThread;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableBooleanValue;
import javafx.beans.value.ObservableValue;
@@ -66,10 +68,8 @@ public class TerminalDockComp extends SimpleComp {
stack.pseudoClassStateChanged(PseudoClass.getPseudoClass("empty"), true);
label.textProperty().bind(AppI18n.observable("terminalStarting"));
if (!AppPrefs.get().performanceMode().get()) {
var i = new RingProgressIndicator(-1.0, false);
i.setMaxWidth(10);
i.setMaxHeight(10);
label.setGraphic(i);
var l = new LoadingIconComp(new SimpleBooleanProperty(true), AppFontSizes::sm).createRegion();
label.setGraphic(l);
}
}
});