Fixes [stage]

This commit is contained in:
crschnick 2025-04-03 07:43:43 +00:00
parent 345ee30ec3
commit f7ac25a073
14 changed files with 155 additions and 54 deletions

View file

@ -58,7 +58,7 @@ public class SideMenuBarComp extends Comp<CompStructure<VBox>> {
}
{
var b = new IconButtonComp("mdi2u-update", () -> UpdateAvailableDialog.showAndWaitIfNeeded());
var b = new IconButtonComp("mdi2u-update", () -> UpdateAvailableDialog.showIfNeeded(false));
b.tooltipKey("updateAvailableTooltip").accessibleTextKey("updateAvailableTooltip");
var stack = createStyle(null, b);
stack.hide(PlatformThread.sync(Bindings.createBooleanBinding(

View file

@ -262,9 +262,11 @@ public class AppTheme {
String name,
atlantafx.base.theme.Theme theme,
AppFontSizes sizes,
Color baseColor,
Color borderColor,
Supplier<Color> contextMenuColor,
int skipLines) {
super(id, cssId, theme, sizes, contextMenuColor);
super(id, cssId, theme, sizes, baseColor, borderColor, contextMenuColor);
this.name = name;
this.skipLines = skipLines;
}
@ -306,6 +308,8 @@ public class AppTheme {
"primer",
new PrimerLight(),
AppFontSizes.forOs(AppFontSizes.BASE_10_5, AppFontSizes.BASE_10, AppFontSizes.BASE_11),
Color.WHITE,
Color.web("#24292f"),
() -> ColorHelper.withOpacity(
Platform.getPreferences().getAccentColor().darker().desaturate(), 0.3));
public static final Theme PRIMER_DARK = new Theme(
@ -313,6 +317,8 @@ public class AppTheme {
"primer",
new PrimerDark(),
AppFontSizes.forOs(AppFontSizes.BASE_11, AppFontSizes.BASE_10, AppFontSizes.BASE_11),
Color.web("#0d1117"),
Color.web("#c9d1d9"),
() -> ColorHelper.withOpacity(
Platform.getPreferences().getAccentColor().desaturate().desaturate(), 0.2));
public static final Theme NORD_LIGHT = new Theme(
@ -320,6 +326,8 @@ public class AppTheme {
"nord",
new NordLight(),
AppFontSizes.forOs(AppFontSizes.BASE_10_5, AppFontSizes.BASE_10, AppFontSizes.BASE_11),
Color.web("#dadadc"),
Color.web("#2E3440"),
() -> ColorHelper.withOpacity(
Platform.getPreferences().getAccentColor().darker().desaturate(), 0.3));
public static final Theme NORD_DARK = new Theme(
@ -327,6 +335,8 @@ public class AppTheme {
"nord",
new NordDark(),
AppFontSizes.forOs(AppFontSizes.BASE_11, AppFontSizes.BASE_10, AppFontSizes.BASE_11),
Color.web("#2d3137"),
Color.web("#24292f"),
() -> ColorHelper.withOpacity(
Platform.getPreferences().getAccentColor().desaturate().desaturate(), 0.2));
public static final Theme CUPERTINO_LIGHT = new Theme(
@ -334,6 +344,8 @@ public class AppTheme {
"cupertino",
new CupertinoLight(),
AppFontSizes.forOs(AppFontSizes.BASE_10_5, AppFontSizes.BASE_10, AppFontSizes.BASE_11),
Color.WHITE,
Color.BLACK,
() -> ColorHelper.withOpacity(
Platform.getPreferences().getAccentColor().darker().desaturate(), 0.3));
public static final Theme CUPERTINO_DARK = new Theme(
@ -341,6 +353,8 @@ public class AppTheme {
"cupertino",
new CupertinoDark(),
AppFontSizes.forOs(AppFontSizes.BASE_11, AppFontSizes.BASE_10, AppFontSizes.BASE_11),
Color.BLACK,
Color.WHITE,
() -> ColorHelper.withOpacity(
Platform.getPreferences().getAccentColor().desaturate().desaturate(), 0.2));
public static final Theme DRACULA = new Theme(
@ -348,6 +362,8 @@ public class AppTheme {
"dracula",
new Dracula(),
AppFontSizes.forOs(AppFontSizes.BASE_11, AppFontSizes.BASE_10, AppFontSizes.BASE_11),
Color.web("#383f49"),
Color.web("#9580ff"),
() -> ColorHelper.withOpacity(
Platform.getPreferences().getAccentColor().desaturate().desaturate(), 0.2));
public static final Theme MOCHA = new DerivedTheme(
@ -356,6 +372,8 @@ public class AppTheme {
"Mocha",
new PrimerDark(),
AppFontSizes.forOs(AppFontSizes.BASE_11, AppFontSizes.BASE_10, AppFontSizes.BASE_11),
Color.web("#2E2E4EFF"),
Color.web("#CDD6F4FF"),
() -> ColorHelper.withOpacity(
Platform.getPreferences().getAccentColor().desaturate().desaturate(), 0.2),
91);
@ -367,9 +385,11 @@ public class AppTheme {
"Custom",
new PrimerDark(),
AppFontSizes.forOs(AppFontSizes.BASE_10_5, AppFontSizes.BASE_10_5, AppFontSizes.BASE_11),
Color.web("#0d1117"),
Color.web("#24292f"),
() -> ColorHelper.withOpacity(
Platform.getPreferences().getAccentColor().desaturate().desaturate(), 0.2),
115);
91);
// Also include your custom theme here
public static final List<Theme> ALL = List.of(
@ -384,6 +404,12 @@ public class AppTheme {
@Getter
protected final AppFontSizes fontSizes;
@Getter
protected final Color baseColor;
@Getter
protected final Color borderColor;
@Getter
protected final Supplier<Color> contextMenuColor;

View file

@ -70,7 +70,7 @@ public class BaseMode extends OperationMode {
// You can still update manually in the about tab
if (AppPrefs.get().automaticallyUpdate().get()
|| AppPrefs.get().checkForSecurityUpdates().get()) {
UpdateAvailableDialog.showAndWaitIfNeeded();
UpdateAvailableDialog.showIfNeeded(true);
} else {
UpdateNagDialog.showAndWaitIfNeeded();
}

View file

@ -4,6 +4,7 @@ import io.xpipe.app.core.window.AppMainWindow;
import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.util.PlatformThread;
import javafx.application.Platform;
import javafx.stage.Stage;
public class GuiMode extends PlatformMode {
@ -15,7 +16,7 @@ public class GuiMode extends PlatformMode {
@Override
public void onSwitchFrom() {
PlatformThread.runLaterIfNeededBlocking(() -> {
Platform.runLater(() -> {
TrackEvent.info("Closing windows");
Stage.getWindows().stream().toList().forEach(w -> {
w.hide();

View file

@ -8,5 +8,5 @@ import com.fasterxml.jackson.databind.JavaType;
public interface PrefsHandler {
<T> void addSetting(String id, JavaType t, Property<T> property, Comp<?> comp, boolean requiresRestart);
<T> void addSetting(String id, JavaType t, Property<T> property, Comp<?> comp, boolean requiresRestart, boolean log);
}

View file

@ -102,17 +102,33 @@ public class AppPrefs {
mapVaultShared(new SimpleBooleanProperty(false), "dontCachePasswords", Boolean.class, false);
public final BooleanProperty denyTempScriptCreation =
mapVaultShared(new SimpleBooleanProperty(false), "denyTempScriptCreation", Boolean.class, false);
final Property<PasswordManager> passwordManager =
mapLocal(new SimpleObjectProperty<>(), "passwordManager", PasswordManager.class, false);
final Property<ShellScript> terminalInitScript =
mapLocal(new SimpleObjectProperty<>(null), "terminalInitScript", ShellScript.class, false);
final Property<PasswordManager> passwordManager = map(Mapping.builder()
.property(new SimpleObjectProperty<>())
.key("passwordManager")
.valueClass(PasswordManager.class)
.log(false)
.build());
final Property<ShellScript> terminalInitScript = map(Mapping.builder()
.property(new SimpleObjectProperty<>(null))
.key("terminalInitScript")
.valueClass(ShellScript.class)
.log(false)
.build());
final Property<UUID> terminalProxy = mapLocal(new SimpleObjectProperty<>(), "terminalProxy", UUID.class, false);
final Property<TerminalMultiplexer> terminalMultiplexer =
mapLocal(new SimpleObjectProperty<>(null), "terminalMultiplexer", TerminalMultiplexer.class, false);
final Property<TerminalMultiplexer> terminalMultiplexer = map(Mapping.builder()
.property(new SimpleObjectProperty<>(null))
.key("terminalMultiplexer")
.valueClass(TerminalMultiplexer.class)
.log(false)
.build());
final Property<Boolean> terminalPromptForRestart =
mapLocal(new SimpleBooleanProperty(true), "terminalPromptForRestart", Boolean.class, false);
final Property<TerminalPrompt> terminalPrompt =
mapLocal(new SimpleObjectProperty<>(null), "terminalPrompt", TerminalPrompt.class, false);
final Property<TerminalPrompt> terminalPrompt = map(Mapping.builder()
.property(new SimpleObjectProperty<>(null))
.key("terminalPrompt")
.valueClass(TerminalPrompt.class)
.log(false)
.build());
public ObservableValue<TerminalPrompt> terminalPrompt() {
return terminalPrompt;
@ -515,11 +531,11 @@ public class AppPrefs {
}
private <T> T mapLocal(Property<?> o, String name, Class<?> clazz, boolean requiresRestart) {
return map(new Mapping(name, o, clazz, false, requiresRestart));
return map(new Mapping(name, o, clazz, false, requiresRestart, true));
}
private <T> T mapVaultShared(Property<?> o, String name, Class<?> clazz, boolean requiresRestart) {
return map(new Mapping(name, o, clazz, true, requiresRestart));
return map(new Mapping(name, o, clazz, true, requiresRestart, true));
}
public <T> void setFromExternal(ObservableValue<T> prop, T newValue) {
@ -596,7 +612,7 @@ public class AppPrefs {
private <T> T loadValue(AppPrefsStorageHandler handler, Mapping value) {
T def = (T) value.getProperty().getValue();
Property<T> property = (Property<T>) value.getProperty();
var val = handler.loadObject(value.getKey(), value.getValueType(), def);
var val = handler.loadObject(value.getKey(), value.getValueType(), def, value.isLog());
property.setValue(val);
return val;
}
@ -644,24 +660,27 @@ public class AppPrefs {
boolean vaultSpecific;
boolean requiresRestart;
String licenseFeatureId;
boolean log;
public Mapping(
String key, Property<?> property, Class<?> valueType, boolean vaultSpecific, boolean requiresRestart) {
String key, Property<?> property, Class<?> valueType, boolean vaultSpecific, boolean requiresRestart, boolean log) {
this.key = key;
this.property = property;
this.valueType = SimpleType.constructUnsafe(valueType);
this.vaultSpecific = vaultSpecific;
this.requiresRestart = requiresRestart;
this.log = log;
this.licenseFeatureId = null;
}
public Mapping(
String key, Property<?> property, JavaType valueType, boolean vaultSpecific, boolean requiresRestart) {
String key, Property<?> property, JavaType valueType, boolean vaultSpecific, boolean requiresRestart, boolean log) {
this.key = key;
this.property = property;
this.valueType = valueType;
this.vaultSpecific = vaultSpecific;
this.requiresRestart = requiresRestart;
this.log = log;
this.licenseFeatureId = null;
}
@ -678,8 +697,8 @@ public class AppPrefs {
private class PrefsHandlerImpl implements PrefsHandler {
@Override
public <T> void addSetting(String id, JavaType t, Property<T> property, Comp<?> comp, boolean requiresRestart) {
var m = new Mapping(id, property, t, false, requiresRestart);
public <T> void addSetting(String id, JavaType t, Property<T> property, Comp<?> comp, boolean requiresRestart, boolean log) {
var m = new Mapping(id, property, t, false, requiresRestart, log);
customEntries.put(m, comp);
mapping.add(m);
}

View file

@ -95,7 +95,7 @@ public class AppPrefsStorageHandler {
@SuppressWarnings("unchecked")
@SneakyThrows
public <T> T loadObject(String id, JavaType type, T defaultObject) {
public <T> T loadObject(String id, JavaType type, T defaultObject, boolean log) {
var tree = getContent(id);
if (tree == null) {
TrackEvent.withDebug("Preferences value not found")
@ -114,29 +114,31 @@ public class AppPrefsStorageHandler {
.filter(t -> ((PrefsChoiceValue) t).getId().equalsIgnoreCase(in))
.findAny();
if (found.isEmpty()) {
TrackEvent.withWarn("Invalid prefs value found")
.tag("key", id)
.tag("value", in)
.handle();
if (log) {
TrackEvent.withWarn("Invalid prefs value found").tag("key", id).tag("value", in).handle();
}
return defaultObject;
}
var supported = getSupported(cast);
if (!supported.contains(found.get())) {
TrackEvent.withWarn("Unsupported prefs value found")
.tag("key", id)
.tag("value", in)
.handle();
if (log) {
TrackEvent.withWarn("Unsupported prefs value found").tag("key", id).tag("value", in).handle();
}
return defaultObject;
}
TrackEvent.debug("Loading preferences value for key " + id + " from value " + found.get());
if (log) {
TrackEvent.debug("Loading preferences value for key " + id + " from value " + found.get());
}
return found.get();
}
}
try {
TrackEvent.debug("Loading preferences value for key " + id + " from value " + tree);
if (log) {
TrackEvent.debug("Loading preferences value for key " + id + " from value " + tree);
}
T value = JacksonMapper.getDefault().treeToValue(tree, type);
if (value instanceof List<?> l) {
var mod = l.stream().filter(v -> v != null).collect(Collectors.toCollection(ArrayList::new));

View file

@ -12,15 +12,21 @@ import io.xpipe.app.util.OptionsBuilder;
import io.xpipe.core.process.OsType;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.ListCell;
import javafx.scene.control.Slider;
import atlantafx.base.controls.ProgressSliderSkin;
import atlantafx.base.theme.Styles;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
public class AppearanceCategory extends AppPrefsCategory {
@ -39,9 +45,7 @@ public class AppearanceCategory extends AppPrefsCategory {
.addComp(languageChoice(), prefs.language)
.pref(prefs.theme)
.addComp(
ChoiceComp.ofTranslatable(prefs.theme, AppTheme.Theme.ALL, false)
.styleClass("theme-switcher")
.minWidth(getCompWidth() / 2),
themeChoice(),
prefs.theme)
.pref(prefs.performanceMode)
.addToggle(prefs.performanceMode)
@ -72,6 +76,40 @@ public class AppearanceCategory extends AppPrefsCategory {
.buildComp();
}
private Comp<?> themeChoice() {
var prefs = AppPrefs.get();
var c = ChoiceComp.ofTranslatable(prefs.theme, AppTheme.Theme.ALL, false)
.styleClass("theme-switcher");
c.apply(struc -> {
Supplier<ListCell<AppTheme.Theme>> cell = () -> new ListCell<AppTheme.Theme>() {
@Override
protected void updateItem(AppTheme.Theme theme, boolean empty) {
super.updateItem(theme, empty);
setText(theme != null ? theme.toTranslatedString().getValue() : null);
var b = new Circle(7);
b.getStyleClass().add("dot");
b.setFill(theme != null ? theme.getBaseColor() : Color.TRANSPARENT);
var d = new Circle(8);
d.getStyleClass().add("dot");
d.setFill(theme != null ? theme.getBorderColor() : Color.TRANSPARENT);
d.setFill(Color.GRAY);
var s = new StackPane(d, b);
setGraphic(s);
setGraphicTextGap(8);
}
};
struc.get().setButtonCell(cell.get());
struc.get().setCellFactory(themeListView -> {
return cell.get();
});
});
c.minWidth(getCompWidth() / 2);
return c;
}
private Comp<?> languageChoice() {
var prefs = AppPrefs.get();
var c = ChoiceComp.ofTranslatable(prefs.language, Arrays.asList(SupportedLocale.values()), false);

View file

@ -34,7 +34,7 @@ public class UpdateCheckComp extends SimpleComp {
private void showAlert() {
ThreadHelper.runFailableAsync(() -> {
AppDistributionType.get().getUpdateHandler().refreshUpdateCheckSilent(false, false);
UpdateAvailableDialog.showAndWaitIfNeeded();
UpdateAvailableDialog.showIfNeeded(false);
});
}

View file

@ -11,6 +11,7 @@ import io.xpipe.app.util.LocalShell;
import io.xpipe.app.util.ScriptHelper;
import io.xpipe.app.util.ThreadHelper;
import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellDialect;
import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.store.FileNames;
import io.xpipe.core.util.FailableRunnable;
@ -84,20 +85,24 @@ public class AppInstaller {
var logFile = FileNames.join(
logsDir, "installer_" + file.getFileName().toString() + ".log");
var systemWide = isSystemWide();
var command = LocalShell.getShell().getShellDialect().equals(ShellDialects.CMD) && !systemWide
var cmdScript = ProcessControlProvider.get().getEffectiveLocalDialect().equals(ShellDialects.CMD) && !systemWide;
var command = cmdScript
? getCmdCommand(file.toString(), logFile, restartExec)
: getPowershellCommand(file.toString(), logFile, restartExec, systemWide);
String toRun;
if (ProcessControlProvider.get().getEffectiveLocalDialect() == ShellDialects.CMD && !systemWide) {
toRun = "start \"XPipe Updater\" /min cmd /c \"" + ScriptHelper.createLocalExecScript(command)
+ "\"";
} else {
toRun =
"Start-Process -WindowStyle Minimized -FilePath powershell -ArgumentList \"-ExecutionPolicy\", \"Bypass\", \"-File\", \"`\""
+ ScriptHelper.createLocalExecScript(command) + "`\"\"";
}
runAndClose(() -> {
LocalShell.getShell().executeSimpleCommand(toRun);
try (var sc = LocalShell.getShell().start()) {
String toRun;
if (cmdScript) {
toRun = "start \"XPipe Updater\" /min cmd /c \"" + ScriptHelper.createExecScript(ShellDialects.CMD, sc, command)
+ "\"";
} else {
toRun =
"Start-Process -WindowStyle Minimized -FilePath powershell -ArgumentList \"-ExecutionPolicy\", \"Bypass\", \"-File\", \"`\""
+ ScriptHelper.createExecScript(ShellDialects.POWERSHELL, sc, command) + "`\"\"";
}
sc.command(toRun).execute();
}
});
}

View file

@ -9,7 +9,7 @@ import io.xpipe.app.issue.TrackEvent;
public class UpdateAvailableDialog {
public static void showAndWaitIfNeeded() {
public static void showIfNeeded(boolean wait) {
UpdateHandler uh = AppDistributionType.get().getUpdateHandler();
if (uh.getPreparedUpdate().getValue() == null) {
return;
@ -34,6 +34,11 @@ public class UpdateAvailableDialog {
for (var action : uh.createActions()) {
modal.addButton(action);
}
AppDialog.showAndWait(modal);
if (wait) {
modal.showAndWait();
} else {
modal.show();
}
}
}

View file

@ -187,7 +187,7 @@ public abstract class UpdateHandler {
// Show available update in PTB more aggressively
if (AppProperties.get().isStaging() && preparedUpdate.getValue() != null && !OperationMode.isInStartup()) {
UpdateAvailableDialog.showAndWaitIfNeeded();
UpdateAvailableDialog.showIfNeeded(false);
}
} catch (Throwable t) {
ErrorEvent.fromThrowable(t).handle();

View file

@ -28,10 +28,15 @@ public class NodeCallback {
}
window.sceneProperty().subscribe(scene -> {
var root = scene != null ? scene.getRoot() : null;
if (root != null) {
watchPlatformThreadChanges(root);
if (scene == null) {
return;
}
scene.rootProperty().subscribe(root -> {
if (root != null) {
watchPlatformThreadChanges(root);
}
});
});
}
});

View file

@ -1 +1 @@
16.0-10
16.0-11