This commit is contained in:
crschnick
2025-06-06 06:51:03 +00:00
parent 4e98d341da
commit 00cdda34c8
11 changed files with 86 additions and 61 deletions

View File

@@ -8,6 +8,7 @@ import io.xpipe.app.comp.SimpleComp;
import io.xpipe.app.comp.base.*;
import io.xpipe.app.comp.store.StoreEntryWrapper;
import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.core.AppLayoutModel;
import io.xpipe.app.core.window.AppMainWindow;
import io.xpipe.app.ext.ShellStore;
@@ -61,9 +62,9 @@ public class BrowserFullSessionComp extends SimpleComp {
.bind(Bindings.createObjectBinding(
() -> new Insets(tabs.getHeaderHeight().get(), 0, 0, 0), tabs.getHeaderHeight()));
});
var loadingIndicator = LoadingOverlayComp.noProgress(Comp.empty(), model.getBusy())
var loadingIndicator = new LoadingIconComp(model.getBusy(), AppFontSizes::xxxl)
.apply(struc -> {
AnchorPane.setTopAnchor(struc.get(), 3.0);
AnchorPane.setTopAnchor(struc.get(), 0.0);
AnchorPane.setRightAnchor(struc.get(), 0.0);
})
.styleClass("tab-loading-indicator");

View File

@@ -4,6 +4,7 @@ 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.comp.base.StackComp;
import io.xpipe.app.core.App;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.core.AppI18n;
@@ -419,17 +420,20 @@ public class BrowserSessionTabsComp extends SimpleComp {
});
if (tabModel.getIcon() != null) {
var loading = new LoadingIconComp(tabModel.getBusy(), AppFontSizes::base).createRegion();
loading.setPrefWidth(16);
loading.setPrefHeight(16);
var loading = new LoadingIconComp(tabModel.getBusy(), AppFontSizes::base);
loading.prefWidth(16);
loading.prefHeight(16);
var image = tabModel.getIcon();
var logo = PrettyImageHelper.ofFixedSizeSquare(image, 16).createRegion();
tab.graphicProperty()
.bind(Bindings.createObjectBinding(
() -> {
return tabModel.getBusy().get() ? loading : logo;
},
PlatformThread.sync(tabModel.getBusy())));
var logo = PrettyImageHelper.ofFixedSizeSquare(image, 16);
logo.apply(struc -> {
struc.get().opacityProperty().bind(PlatformThread.sync(Bindings.createDoubleBinding(() -> {
return !tabModel.getBusy().get() ? 1.0 : 0.15;
}, tabModel.getBusy())));
});
var stack = new StackComp(List.of(logo, loading));
tab.setGraphic(stack.createRegion());
}
if (tabModel.getBrowserModel() instanceof BrowserFullSessionModel sessionModel) {

View File

@@ -43,6 +43,9 @@ public class LoadingIconComp extends SimpleComp {
label.setText(Character.toString(chars[0]));
label.getStyleClass().add("loading-icon-comp");
label.setPrefWidth(16);
label.setPrefHeight(16);
var timer = new AnimationTimer() {
long init = 0;
@@ -55,7 +58,7 @@ public class LoadingIconComp extends SimpleComp {
}
var nowMs = now;
if ((nowMs - init) > 300 * 1_000_000L) {
if ((nowMs - init) > 250 * 1_000_000L) {
label.setText(Character.toString(chars[index]));
init = nowMs;
index = (index + 1) % chars.length;
@@ -64,11 +67,14 @@ public class LoadingIconComp extends SimpleComp {
};
show.subscribe(val -> {
if (val) {
timer.start();
} else {
timer.stop();
}
PlatformThread.runLaterIfNeeded(() -> {
label.setVisible(val);
if (val) {
timer.start();
} else {
timer.stop();
}
});
});
return label;

View File

@@ -4,8 +4,6 @@ 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;
import javafx.application.Platform;
@@ -15,22 +13,16 @@ import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.layout.StackPane;
import atlantafx.base.controls.RingProgressIndicator;
public class LoadingOverlayComp extends Comp<CompStructure<StackPane>> {
private final Comp<?> comp;
private final ObservableValue<Boolean> showLoading;
private final ObservableValue<Number> progress;
private final ObservableValue<Boolean> loading;
private final boolean showIcon;
public LoadingOverlayComp(Comp<?> comp, ObservableValue<Boolean> loading, ObservableValue<Number> progress) {
public LoadingOverlayComp(Comp<?> comp, ObservableValue<Boolean> loading, boolean showIcon) {
this.comp = comp;
this.showLoading = PlatformThread.sync(loading);
this.progress = PlatformThread.sync(progress);
}
public static LoadingOverlayComp noProgress(Comp<?> comp, ObservableValue<Boolean> loading) {
return new LoadingOverlayComp(comp, loading, new SimpleDoubleProperty(-1));
this.loading = loading;
this.showIcon = showIcon;
}
@Override
@@ -38,11 +30,22 @@ public class LoadingOverlayComp extends Comp<CompStructure<StackPane>> {
var compStruc = comp.createStructure();
var r = compStruc.get();
var loading = new LoadingIconComp(showLoading, AppFontSizes::xxxl).createRegion();
var loadingOverlay = new StackPane(loading);
var loadingOverlay = new StackPane();
if (showIcon) {
var loading = new LoadingIconComp(this.loading, AppFontSizes::title).createRegion();
loading.prefWidthProperty()
.bind(Bindings.createDoubleBinding(
() -> {
return Math.min(r.getHeight() - 20, 50);
},
r.heightProperty()));
loading.prefHeightProperty().bind(loading.prefWidthProperty());
loading.managedProperty().bind(loading.visibleProperty());
loadingOverlay.getChildren().add(loading);
}
loadingOverlay.getStyleClass().add("loading-comp");
loadingOverlay.setVisible(showLoading.getValue());
loadingOverlay.setVisible(showIcon && this.loading.getValue());
loadingOverlay.setManaged(showIcon && this.loading.getValue());
var listener = new ChangeListener<Boolean>() {
@Override
@@ -55,7 +58,7 @@ public class LoadingOverlayComp extends Comp<CompStructure<StackPane>> {
} catch (InterruptedException ignored) {
}
if (!showLoading.getValue()) {
if (!LoadingOverlayComp.this.loading.getValue()) {
Platform.runLater(() -> {
loadingOverlay.setVisible(false);
loadingOverlay.setManaged(false);
@@ -69,7 +72,7 @@ public class LoadingOverlayComp extends Comp<CompStructure<StackPane>> {
} catch (InterruptedException ignored) {
}
if (showLoading.getValue()) {
if (LoadingOverlayComp.this.loading.getValue()) {
Platform.runLater(() -> {
loadingOverlay.setVisible(true);
loadingOverlay.setManaged(true);
@@ -79,18 +82,10 @@ public class LoadingOverlayComp extends Comp<CompStructure<StackPane>> {
}
}
};
showLoading.addListener(listener);
this.loading.addListener(listener);
var stack = new StackPane(r, loadingOverlay);
loading.prefWidthProperty()
.bind(Bindings.createDoubleBinding(
() -> {
return Math.min(r.getHeight() - 20, 50);
},
r.heightProperty()));
loading.prefHeightProperty().bind(loading.prefWidthProperty());
stack.prefWidthProperty().bind(r.prefWidthProperty());
stack.prefHeightProperty().bind(r.prefHeightProperty());

View File

@@ -250,7 +250,7 @@ public class ModalOverlayComp extends SimpleComp {
if (newValue.getContent() instanceof ModalOverlayContentComp mocc) {
var busy = mocc.busy();
if (busy != null) {
var loading = LoadingOverlayComp.noProgress(Comp.of(() -> modalBox), busy);
var loading = new LoadingOverlayComp(Comp.of(() -> modalBox), busy, true);
return loading.createRegion();
}
}

View File

@@ -2,6 +2,7 @@ package io.xpipe.app.comp.store;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.augment.GrowAugment;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.util.PlatformThread;
import io.xpipe.core.process.OsType;
@@ -88,7 +89,7 @@ public class DenseStoreEntryComp extends StoreEntryComp {
}
});
var storeIcon = createIcon(28, 24);
var storeIcon = createIcon(28, 24, AppFontSizes::xxxl);
GridPane.setHalignment(storeIcon, HPos.CENTER);
grid.add(storeIcon, 1, 0);
grid.getColumnConstraints().add(new ColumnConstraints(34));

View File

@@ -54,7 +54,7 @@ public class StandardStoreEntryComp extends StoreEntryComp {
}
});
var storeIcon = createIcon(46, 40);
var storeIcon = createIcon(46, 40, AppFontSizes::title);
grid.add(storeIcon, 1, 0, 1, 2);
grid.getColumnConstraints().add(new ColumnConstraints(52));

View File

@@ -5,9 +5,7 @@ import io.xpipe.app.comp.SimpleComp;
import io.xpipe.app.comp.SimpleCompStructure;
import io.xpipe.app.comp.augment.ContextMenuAugment;
import io.xpipe.app.comp.augment.GrowAugment;
import io.xpipe.app.comp.base.IconButtonComp;
import io.xpipe.app.comp.base.LabelComp;
import io.xpipe.app.comp.base.LoadingOverlayComp;
import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.*;
import io.xpipe.app.ext.ActionProvider;
import io.xpipe.app.prefs.AppPrefs;
@@ -20,6 +18,7 @@ import io.xpipe.app.util.*;
import io.xpipe.core.process.OsType;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableDoubleValue;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
@@ -37,6 +36,8 @@ import org.kordamp.ikonli.javafx.FontIcon;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
public abstract class StoreEntryComp extends SimpleComp {
@@ -154,8 +155,8 @@ public abstract class StoreEntryComp extends SimpleComp {
() -> this.createContextMenu())
.augment(button);
var loading = LoadingOverlayComp.noProgress(
Comp.of(() -> button), getWrapper().getEffectiveBusy());
var loading = new LoadingOverlayComp(
Comp.of(() -> button), getWrapper().getEffectiveBusy(), false);
if (OsType.getLocal() == OsType.MACOS) {
AppFontSizes.base(button);
} else if (OsType.getLocal() == OsType.LINUX) {
@@ -212,8 +213,18 @@ public abstract class StoreEntryComp extends SimpleComp {
return button;
}
protected Node createIcon(int w, int h) {
return new StoreIconComp(getWrapper(), w, h).createRegion();
protected Node createIcon(int w, int h, Consumer<Node> fontSize) {
var icon = new StoreIconComp(getWrapper(), w, h);
icon.apply(struc -> {
struc.get().opacityProperty().bind(Bindings.createDoubleBinding(() -> {
return !getWrapper().getEffectiveBusy().get() ? 1.0 : 0.15;
}, getWrapper().getEffectiveBusy()));
});
var loading = new LoadingIconComp(getWrapper().getEffectiveBusy(), fontSize);
loading.prefWidth(w);
loading.prefHeight(h);
var stack = new StackComp(List.of(icon, loading));
return stack.createRegion();
}
protected Region createButtonBar() {

View File

@@ -144,7 +144,7 @@ public class ScanDialogBase {
onUpdate();
entries.addListener((ListChangeListener<? super DataStoreEntryRef<ShellStore>>) c -> onUpdate());
var comp = LoadingOverlayComp.noProgress(Comp.of(() -> stackPane), busy).vgrow();
var comp = new LoadingOverlayComp(Comp.of(() -> stackPane), busy, true).vgrow();
return comp;
}
}

View File

@@ -190,6 +190,14 @@
-fx-text-fill: transparent;
}
.browser .overview .simple-titled-pane-comp {
-fx-background-radius: 4;
}
.root:nord .browser .overview .simple-titled-pane-comp {
-fx-background-radius: 0;
}
.browser .overview-file-list {
-fx-border-width: 0;
}
@@ -231,14 +239,13 @@
-fx-opacity: 0;
}
.browser .tab-loading-indicator .loading-comp {
.browser .tab-loading-indicator {
-fx-min-width: 2.5em;
-fx-pref-width: 2.5em;
-fx-max-width: 2.5em;
-fx-min-height: 2.5em;
-fx-pref-height: 2.5em;
-fx-max-height: 2.5em;
-fx-background-color: transparent;
}
.browser.chooser .left {

View File

@@ -64,11 +64,11 @@
}
.root:light .loading-comp {
-fx-background-color: rgba(100, 100, 100, 0.5);
-fx-background-color: rgba(100, 100, 100, 0.3);
}
.root:dark .loading-comp {
-fx-background-color: rgba(0, 0, 0, 0.5);
-fx-background-color: rgba(0, 0, 0, 0.4);
}
.icon-browser {