mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-09-23 00:45:35 +00:00
Cleanup
This commit is contained in:
@@ -9,8 +9,11 @@ import com.sun.net.httpserver.HttpExchange;
|
||||
public class DaemonFocusExchangeImpl extends DaemonFocusExchange {
|
||||
|
||||
@Override
|
||||
public Object handle(HttpExchange exchange, Request msg) {
|
||||
AppOperationMode.switchUp(AppOperationMode.GUI);
|
||||
public Object handle(HttpExchange exchange, Request msg) throws Throwable {
|
||||
if (AppOperationMode.GUI.isSupported()) {
|
||||
AppOperationMode.switchToSyncOrThrow(AppOperationMode.GUI);
|
||||
}
|
||||
|
||||
var w = AppMainWindow.get();
|
||||
if (w != null) {
|
||||
w.focus();
|
||||
|
||||
@@ -10,7 +10,7 @@ import javafx.beans.property.SimpleObjectProperty;
|
||||
|
||||
public class BrowserDialogs {
|
||||
|
||||
public static FileConflictChoice showFileConflictAlert(FilePath file, boolean multiple) {
|
||||
public static FileConflictChoice showFileConflictDialog(FilePath file, boolean multiple) {
|
||||
var choice = new SimpleObjectProperty<FileConflictChoice>();
|
||||
var key = multiple ? "fileConflictAlertContentMultiple" : "fileConflictAlertContent";
|
||||
var w = multiple ? 1050 : 400;
|
||||
|
||||
@@ -109,7 +109,7 @@ public class BrowserFileTransferOperation {
|
||||
return BrowserDialogs.FileConflictChoice.SKIP;
|
||||
}
|
||||
|
||||
var choice = BrowserDialogs.showFileConflictAlert(target, multiple);
|
||||
var choice = BrowserDialogs.showFileConflictDialog(target, multiple);
|
||||
if (choice == BrowserDialogs.FileConflictChoice.CANCEL) {
|
||||
lastConflictChoice = BrowserDialogs.FileConflictChoice.CANCEL;
|
||||
return BrowserDialogs.FileConflictChoice.CANCEL;
|
||||
|
||||
@@ -21,7 +21,7 @@ public class App extends Application {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void start(Stage primaryStage) {
|
||||
TrackEvent.info("Application launched");
|
||||
TrackEvent.info("Platform application started");
|
||||
APP = this;
|
||||
stage = primaryStage;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import io.xpipe.app.storage.DataStorageSyncHandler;
|
||||
import io.xpipe.app.terminal.TerminalLauncherManager;
|
||||
import io.xpipe.app.terminal.TerminalView;
|
||||
import io.xpipe.app.update.UpdateAvailableDialog;
|
||||
import io.xpipe.app.update.UpdateChangelogAlert;
|
||||
import io.xpipe.app.update.UpdateChangelogDialog;
|
||||
import io.xpipe.app.update.UpdateNagDialog;
|
||||
import io.xpipe.app.util.*;
|
||||
import io.xpipe.core.XPipeDaemonMode;
|
||||
@@ -167,7 +167,7 @@ public class AppBaseMode extends AppOperationMode {
|
||||
AppGreetingsDialog.showAndWaitIfNeeded();
|
||||
TrackEvent.info("Waiting for startup dialogs to close");
|
||||
AppDialog.waitForAllDialogsClose();
|
||||
UpdateChangelogAlert.showIfNeeded();
|
||||
UpdateChangelogDialog.showIfNeeded();
|
||||
|
||||
ActionProvider.initProviders();
|
||||
DataStoreProviders.init();
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.xpipe.app.core.mode;
|
||||
|
||||
import io.xpipe.app.core.window.AppMainWindow;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.app.platform.PlatformInit;
|
||||
import io.xpipe.app.platform.PlatformThread;
|
||||
import io.xpipe.app.util.LicenseProvider;
|
||||
import io.xpipe.core.OsType;
|
||||
@@ -9,7 +10,14 @@ import io.xpipe.core.OsType;
|
||||
import javafx.application.Platform;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class AppGuiMode extends AppPlatformMode {
|
||||
public class AppGuiMode extends AppOperationMode {
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
// We force GUI to be supported and fail with a terminal
|
||||
// exception if we can't initialize the platform
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
@@ -32,7 +40,8 @@ public class AppGuiMode extends AppPlatformMode {
|
||||
|
||||
@Override
|
||||
public void onSwitchTo() throws Throwable {
|
||||
super.onSwitchTo();
|
||||
AppOperationMode.BACKGROUND.onSwitchTo();
|
||||
PlatformInit.init(true);
|
||||
|
||||
// Refresh license check
|
||||
// In case our exit behavior is set to continue in background,
|
||||
@@ -43,4 +52,10 @@ public class AppGuiMode extends AppPlatformMode {
|
||||
AppMainWindow.get().show();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalTeardown() throws Throwable {
|
||||
onSwitchFrom();
|
||||
BACKGROUND.finalTeardown();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import io.xpipe.app.core.*;
|
||||
import io.xpipe.app.core.check.AppDebugModeCheck;
|
||||
import io.xpipe.app.core.window.AppMainWindow;
|
||||
import io.xpipe.app.issue.*;
|
||||
import io.xpipe.app.platform.NodeCallback;
|
||||
import io.xpipe.app.platform.PlatformThreadWatcher;
|
||||
import io.xpipe.app.platform.PlatformInit;
|
||||
import io.xpipe.app.platform.PlatformState;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
@@ -111,7 +111,7 @@ public abstract class AppOperationMode {
|
||||
AppMainWindow.loadingText("initializingApp");
|
||||
GlobalTimer.init();
|
||||
AppProperties.init(args);
|
||||
NodeCallback.init();
|
||||
PlatformThreadWatcher.init();
|
||||
AppLogs.init();
|
||||
AppDebugModeCheck.printIfNeeded();
|
||||
AppProperties.get().logArguments();
|
||||
@@ -222,23 +222,6 @@ public abstract class AppOperationMode {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void switchUp(AppOperationMode newMode) {
|
||||
if (newMode == BACKGROUND) {
|
||||
return;
|
||||
}
|
||||
|
||||
TrackEvent.info("Attempting to switch mode up to " + newMode.getId());
|
||||
|
||||
if (newMode.equals(TRAY) && TRAY.isSupported() && AppOperationMode.get() == BACKGROUND) {
|
||||
set(TRAY);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newMode.equals(GUI) && GUI.isSupported()) {
|
||||
set(GUI);
|
||||
}
|
||||
}
|
||||
|
||||
public static void close() {
|
||||
set(null);
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package io.xpipe.app.core.mode;
|
||||
|
||||
import io.xpipe.app.platform.PlatformInit;
|
||||
|
||||
public abstract class AppPlatformMode extends AppOperationMode {
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwitchTo() throws Throwable {
|
||||
AppOperationMode.BACKGROUND.onSwitchTo();
|
||||
PlatformInit.init(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalTeardown() throws Throwable {
|
||||
onSwitchFrom();
|
||||
BACKGROUND.finalTeardown();
|
||||
}
|
||||
}
|
||||
@@ -2,24 +2,26 @@ package io.xpipe.app.core.mode;
|
||||
|
||||
import io.xpipe.app.core.AppTray;
|
||||
import io.xpipe.app.issue.*;
|
||||
import io.xpipe.app.platform.PlatformInit;
|
||||
import io.xpipe.app.platform.PlatformThread;
|
||||
import io.xpipe.core.OsType;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class AppTrayMode extends AppPlatformMode {
|
||||
public class AppTrayMode extends AppOperationMode {
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return OsType.getLocal() == OsType.WINDOWS
|
||||
&& super.isSupported()
|
||||
&& Desktop.isDesktopSupported()
|
||||
&& SystemTray.isSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwitchTo() throws Throwable {
|
||||
super.onSwitchTo();
|
||||
AppOperationMode.BACKGROUND.onSwitchTo();
|
||||
PlatformInit.init(true);
|
||||
|
||||
PlatformThread.runLaterIfNeededBlocking(() -> {
|
||||
if (AppTray.get() == null) {
|
||||
TrackEvent.info("Initializing tray");
|
||||
@@ -56,4 +58,10 @@ public class AppTrayMode extends AppPlatformMode {
|
||||
ErrorAction.ignore().handle(event);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalTeardown() throws Throwable {
|
||||
onSwitchFrom();
|
||||
BACKGROUND.finalTeardown();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,6 @@ public class AppDialog {
|
||||
@Getter
|
||||
private static final ObservableList<ModalOverlay> modalOverlays = FXCollections.observableArrayList();
|
||||
|
||||
private static void showMainWindow() {
|
||||
PlatformInit.init(true);
|
||||
AppMainWindow.init(true);
|
||||
}
|
||||
|
||||
public static void closeDialog(ModalOverlay overlay) {
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
synchronized (modalOverlays) {
|
||||
@@ -67,7 +62,9 @@ public class AppDialog {
|
||||
}
|
||||
|
||||
public static void show(ModalOverlay o, boolean wait) {
|
||||
showMainWindow();
|
||||
PlatformInit.init(true);
|
||||
AppMainWindow.init(true);
|
||||
|
||||
if (!Platform.isFxApplicationThread()) {
|
||||
PlatformThread.runLaterIfNeededBlocking(() -> {
|
||||
synchronized (modalOverlays) {
|
||||
|
||||
@@ -105,7 +105,7 @@ public class AppMainWindow {
|
||||
}
|
||||
AppWindowStyle.addIcons(stage);
|
||||
AppWindowStyle.addStylesheets(stage.getScene());
|
||||
AppWindowStyle.addNavigationStyleClasses(stage.getScene());
|
||||
AppWindowStyle.addNavigationPseudoClasses(stage.getScene());
|
||||
AppWindowStyle.addClickShield(stage);
|
||||
AppWindowStyle.addMaximizedPseudoClass(stage);
|
||||
AppWindowStyle.addFontSize(stage);
|
||||
|
||||
@@ -91,7 +91,7 @@ public class AppSideWindow {
|
||||
AppModifiedStage.prepareStage(stage);
|
||||
AppWindowStyle.addIcons(stage);
|
||||
AppWindowStyle.addStylesheets(alert.getDialogPane().getScene());
|
||||
AppWindowStyle.addNavigationStyleClasses(alert.getDialogPane().getScene());
|
||||
AppWindowStyle.addNavigationPseudoClasses(alert.getDialogPane().getScene());
|
||||
return alert;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class AppWindowStyle {
|
||||
});
|
||||
}
|
||||
|
||||
public static void addNavigationStyleClasses(Scene scene) {
|
||||
public static void addNavigationPseudoClasses(Scene scene) {
|
||||
Consumer<Boolean> onInput = kb -> {
|
||||
var r = scene.getRoot();
|
||||
if (r != null) {
|
||||
|
||||
@@ -8,23 +8,10 @@ import io.xpipe.core.FailableSupplier;
|
||||
public interface ErrorAction {
|
||||
|
||||
static ErrorAction openDocumentation(String link) {
|
||||
return new ErrorAction() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return AppI18n.get("openDocumentation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return AppI18n.get("openDocumentationDescription");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(ErrorEvent event) {
|
||||
Hyperlinks.open(link);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return translated("openDocumentation", () -> {
|
||||
Hyperlinks.open(link);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
static ErrorAction translated(String key, FailableSupplier<Boolean> r) {
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package io.xpipe.app.issue;
|
||||
|
||||
import io.xpipe.app.comp.Comp;
|
||||
import io.xpipe.app.comp.SimpleComp;
|
||||
import io.xpipe.app.core.AppFontSizes;
|
||||
import io.xpipe.app.util.Deobfuscator;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class ErrorDetailsComp extends SimpleComp {
|
||||
|
||||
private ErrorEvent event;
|
||||
|
||||
private Region createStrackTraceContent() {
|
||||
if (event.getThrowable() != null) {
|
||||
String stackTrace = Deobfuscator.deobfuscateToString(event.getThrowable());
|
||||
stackTrace = stackTrace.replace("\t", "");
|
||||
var tf = new TextArea(stackTrace);
|
||||
AppFontSizes.xs(tf);
|
||||
tf.setWrapText(true);
|
||||
tf.setEditable(false);
|
||||
tf.setPadding(new Insets(10, 0, 10, 0));
|
||||
return tf;
|
||||
}
|
||||
|
||||
return new Region();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
var tb = Comp.of(this::createStrackTraceContent);
|
||||
tb.apply(r -> AppFontSizes.xs(r.get()));
|
||||
return tb.createRegion();
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,17 @@ package io.xpipe.app.issue;
|
||||
import io.xpipe.app.comp.Comp;
|
||||
import io.xpipe.app.comp.base.ModalButton;
|
||||
import io.xpipe.app.comp.base.ModalOverlay;
|
||||
import io.xpipe.app.core.AppFontSizes;
|
||||
import io.xpipe.app.core.mode.AppOperationMode;
|
||||
import io.xpipe.app.core.window.AppDialog;
|
||||
import io.xpipe.app.platform.LabelGraphic;
|
||||
|
||||
import io.xpipe.app.util.Deobfuscator;
|
||||
import javafx.application.Platform;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.layout.Region;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -39,9 +44,12 @@ public class ErrorHandlerDialog {
|
||||
errorModal.addButton(new ModalButton(
|
||||
"stackTrace",
|
||||
() -> {
|
||||
var content =
|
||||
new ErrorDetailsComp(event).prefWidth(650).prefHeight(750);
|
||||
var detailsModal = ModalOverlay.of("errorDetails", content);
|
||||
var detailsModal = ModalOverlay.of("errorDetails", Comp.of(() -> {
|
||||
var content = createStrackTraceContent(event);
|
||||
content.setPrefWidth(650);
|
||||
content.setPrefHeight(750);
|
||||
return content;
|
||||
}));
|
||||
detailsModal.show();
|
||||
},
|
||||
false,
|
||||
@@ -76,4 +84,20 @@ public class ErrorHandlerDialog {
|
||||
ErrorAction.ignore().handle(event);
|
||||
}
|
||||
}
|
||||
|
||||
private static Region createStrackTraceContent(ErrorEvent event) {
|
||||
if (event.getThrowable() != null) {
|
||||
String stackTrace = Deobfuscator.deobfuscateToString(event.getThrowable());
|
||||
stackTrace = stackTrace.replace("\t", "");
|
||||
var tf = new TextArea(stackTrace);
|
||||
AppFontSizes.xs(tf);
|
||||
tf.setWrapText(true);
|
||||
tf.setEditable(false);
|
||||
tf.setPadding(new Insets(10, 0, 10, 0));
|
||||
return tf;
|
||||
}
|
||||
|
||||
return new Region();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ public class LogErrorHandler implements ErrorHandler {
|
||||
System.err.println(event.getDescription());
|
||||
}
|
||||
if (event.getThrowable() != null) {
|
||||
Deobfuscator.printStackTrace(event.getThrowable());
|
||||
var s = Deobfuscator.deobfuscateToString(event.getThrowable());
|
||||
System.err.println(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import java.util.stream.Collectors;
|
||||
@Getter
|
||||
public class TrackEvent {
|
||||
|
||||
private final Thread thread = Thread.currentThread();
|
||||
private final Instant instant = Instant.now();
|
||||
private String type;
|
||||
private String message;
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class NodeCallback {
|
||||
public class PlatformThreadWatcher {
|
||||
|
||||
private static final Set<Window> windows = new HashSet<>();
|
||||
private static final Set<Node> nodes = new HashSet<>();
|
||||
@@ -47,6 +47,36 @@ public final class AppPrefs {
|
||||
private static AppPrefs INSTANCE;
|
||||
private final List<Mapping> mapping = new ArrayList<>();
|
||||
|
||||
public static void initLocal() {
|
||||
INSTANCE = new AppPrefs();
|
||||
PrefsProvider.getAll().forEach(prov -> prov.addPrefs(INSTANCE.extensionHandler));
|
||||
INSTANCE.loadLocal();
|
||||
INSTANCE.vaultStorageHandler =
|
||||
new AppPrefsStorageHandler(DataStorage.getStorageDirectory().resolve("preferences.json"));
|
||||
INSTANCE.fixLocalValues();
|
||||
}
|
||||
|
||||
public static void initSynced() throws Exception {
|
||||
INSTANCE.loadSharedRemote();
|
||||
INSTANCE.encryptAllVaultData.addListener((observableValue, aBoolean, t1) -> {
|
||||
if (DataStorage.get() != null) {
|
||||
DataStorage.get().forceRewrite();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
INSTANCE.save();
|
||||
|
||||
// Keep instance as we might need some values on shutdown, e.g. on update with terminals
|
||||
// INSTANCE = null;
|
||||
}
|
||||
|
||||
public static AppPrefs get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
|
||||
@Getter
|
||||
private final BooleanProperty requiresRestart = new GlobalBooleanProperty(false);
|
||||
|
||||
@@ -83,22 +113,54 @@ public final class AppPrefs {
|
||||
.documentationLink(DocumentationLink.MCP)
|
||||
.build());
|
||||
final BooleanProperty enableMcpMutationTools =
|
||||
mapLocal(new GlobalBooleanProperty(false), "enableMcpMutationTools", Boolean.class, false);
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalBooleanProperty(false))
|
||||
.key("enableMcpMutationTools")
|
||||
.valueClass(Boolean.class)
|
||||
.build());
|
||||
final BooleanProperty dontAutomaticallyStartVmSshServer =
|
||||
mapVaultShared(new GlobalBooleanProperty(false), "dontAutomaticallyStartVmSshServer", Boolean.class, false);
|
||||
final BooleanProperty dontAcceptNewHostKeys =
|
||||
mapVaultShared(new GlobalBooleanProperty(false), "dontAcceptNewHostKeys", Boolean.class, false);
|
||||
public final BooleanProperty performanceMode =
|
||||
mapLocal(new GlobalBooleanProperty(), "performanceMode", Boolean.class, false);
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalObjectProperty<>())
|
||||
.key("performanceMode")
|
||||
.valueClass(Boolean.class)
|
||||
.build());
|
||||
public final ObjectProperty<AppTheme.Theme> theme =
|
||||
mapLocal(new GlobalObjectProperty<>(), "theme", AppTheme.Theme.class, false);
|
||||
final BooleanProperty useSystemFont = mapLocal(
|
||||
new GlobalBooleanProperty(OsType.getLocal() != OsType.MACOS), "useSystemFont", Boolean.class, false);
|
||||
final Property<Integer> uiScale = mapLocal(new GlobalObjectProperty<>(null), "uiScale", Integer.class, true);
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalObjectProperty<>())
|
||||
.key("theme")
|
||||
.valueClass(AppTheme.Theme.class)
|
||||
.build());
|
||||
final BooleanProperty useSystemFont =
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalBooleanProperty(OsType.getLocal() != OsType.MACOS))
|
||||
.key("useSystemFont")
|
||||
.valueClass(Boolean.class)
|
||||
.build());
|
||||
final Property<Integer> uiScale =
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalObjectProperty<>())
|
||||
.key("uiScale")
|
||||
.valueClass(Integer.class)
|
||||
.requiresRestart(true)
|
||||
.build());
|
||||
final BooleanProperty saveWindowLocation =
|
||||
mapLocal(new GlobalBooleanProperty(true), "saveWindowLocation", Boolean.class, false);
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalBooleanProperty(true))
|
||||
.key("saveWindowLocation")
|
||||
.valueClass(Boolean.class)
|
||||
.requiresRestart(false)
|
||||
.build());
|
||||
final BooleanProperty preferTerminalTabs =
|
||||
mapLocal(new GlobalBooleanProperty(true), "preferTerminalTabs", Boolean.class, false);
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalBooleanProperty(true))
|
||||
.key("preferTerminalTabs")
|
||||
.valueClass(Boolean.class)
|
||||
.requiresRestart(false)
|
||||
.build());
|
||||
final ObjectProperty<ExternalTerminalType> terminalType = map(Mapping.builder()
|
||||
.property(new GlobalObjectProperty<>())
|
||||
.key("terminalType")
|
||||
@@ -113,11 +175,27 @@ public final class AppPrefs {
|
||||
.requiresRestart(false)
|
||||
.documentationLink(DocumentationLink.RDP)
|
||||
.build());
|
||||
final DoubleProperty windowOpacity = mapLocal(new GlobalDoubleProperty(1.0), "windowOpacity", Double.class, false);
|
||||
final DoubleProperty windowOpacity =
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalDoubleProperty(1.0))
|
||||
.key("windowOpacity")
|
||||
.valueClass(Double.class)
|
||||
.requiresRestart(false)
|
||||
.build());
|
||||
final StringProperty customTerminalCommand =
|
||||
mapLocal(new GlobalStringProperty(null), "customTerminalCommand", String.class, false);
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalStringProperty(null))
|
||||
.key("customTerminalCommand")
|
||||
.valueClass(String.class)
|
||||
.requiresRestart(false)
|
||||
.build());
|
||||
final BooleanProperty clearTerminalOnInit =
|
||||
mapLocal(new GlobalBooleanProperty(true), "clearTerminalOnInit", Boolean.class, false);
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalBooleanProperty(true))
|
||||
.key("clearTerminalOnInit")
|
||||
.valueClass(Boolean.class)
|
||||
.requiresRestart(false)
|
||||
.build());
|
||||
final Property<List<SystemIconSource>> iconSources = map(Mapping.builder()
|
||||
.property(new GlobalObjectProperty<>(new ArrayList<>()))
|
||||
.key("iconSources")
|
||||
@@ -125,9 +203,18 @@ public final class AppPrefs {
|
||||
.vaultSpecific(true)
|
||||
.build());
|
||||
public final BooleanProperty disableCertutilUse =
|
||||
mapLocal(new GlobalBooleanProperty(false), "disableCertutilUse", Boolean.class, false);
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalBooleanProperty(false))
|
||||
.key("disableCertutilUse")
|
||||
.valueClass(Boolean.class)
|
||||
.build());
|
||||
public final BooleanProperty useLocalFallbackShell =
|
||||
mapLocal(new GlobalBooleanProperty(false), "useLocalFallbackShell", Boolean.class, true);
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalBooleanProperty(false))
|
||||
.key("useLocalFallbackShell")
|
||||
.valueClass(Boolean.class)
|
||||
.requiresRestart(true)
|
||||
.build());
|
||||
final Property<ShellDialect> localShellDialect = map(Mapping.builder()
|
||||
.property(new GlobalObjectProperty<>(
|
||||
ProcessControlProvider.get().getAvailableLocalDialects().getFirst()))
|
||||
@@ -142,7 +229,11 @@ public final class AppPrefs {
|
||||
public final Property<Boolean> alwaysConfirmElevation =
|
||||
mapVaultShared(new GlobalObjectProperty<>(false), "alwaysConfirmElevation", Boolean.class, false);
|
||||
public final BooleanProperty focusWindowOnNotifications =
|
||||
mapLocal(new GlobalBooleanProperty(true), "focusWindowOnNotifications", Boolean.class, false);
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalBooleanProperty(false))
|
||||
.key("focusWindowOnNotifications")
|
||||
.valueClass(Boolean.class)
|
||||
.build());
|
||||
public final BooleanProperty dontCachePasswords =
|
||||
mapVaultShared(new GlobalBooleanProperty(false), "dontCachePasswords", Boolean.class, false);
|
||||
public final Property<ExternalVncClient> vncClient = map(Mapping.builder()
|
||||
@@ -178,7 +269,11 @@ public final class AppPrefs {
|
||||
.documentationLink(DocumentationLink.TERMINAL_MULTIPLEXER)
|
||||
.build());
|
||||
final Property<Boolean> terminalAlwaysPauseOnExit =
|
||||
mapLocal(new GlobalBooleanProperty(true), "terminalAlwaysPauseOnExit", Boolean.class, false);
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalBooleanProperty(false))
|
||||
.key("terminalAlwaysPauseOnExit")
|
||||
.valueClass(Boolean.class)
|
||||
.build());
|
||||
final Property<TerminalPrompt> terminalPrompt = map(Mapping.builder()
|
||||
.property(new GlobalObjectProperty<>(null))
|
||||
.key("terminalPrompt")
|
||||
@@ -186,8 +281,13 @@ public final class AppPrefs {
|
||||
.log(false)
|
||||
.documentationLink(DocumentationLink.TERMINAL_PROMPT)
|
||||
.build());
|
||||
final ObjectProperty<StartupBehaviour> startupBehaviour = mapLocal(
|
||||
new GlobalObjectProperty<>(StartupBehaviour.GUI), "startupBehaviour", StartupBehaviour.class, true);
|
||||
final ObjectProperty<StartupBehaviour> startupBehaviour =
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalObjectProperty<>(StartupBehaviour.GUI))
|
||||
.key("startupBehaviour")
|
||||
.valueClass(StartupBehaviour.class)
|
||||
.requiresRestart(true)
|
||||
.build());
|
||||
public final BooleanProperty enableGitStorage = map(Mapping.builder()
|
||||
.property(new GlobalBooleanProperty(false))
|
||||
.key("enableGitStorage")
|
||||
@@ -203,7 +303,11 @@ public final class AppPrefs {
|
||||
.documentationLink(DocumentationLink.SYNC)
|
||||
.build());
|
||||
final ObjectProperty<CloseBehaviour> closeBehaviour =
|
||||
mapLocal(new GlobalObjectProperty<>(CloseBehaviour.QUIT), "closeBehaviour", CloseBehaviour.class, false);
|
||||
map(Mapping.builder()
|
||||
.property(new GlobalObjectProperty<>(CloseBehaviour.QUIT))
|
||||
.key("closeBehaviour")
|
||||
.valueClass(CloseBehaviour.class)
|
||||
.build());
|
||||
final ObjectProperty<ExternalEditorType> externalEditor =
|
||||
mapLocal(new GlobalObjectProperty<>(), "externalEditor", ExternalEditorType.class, false);
|
||||
final StringProperty customEditorCommand =
|
||||
@@ -288,75 +392,42 @@ public final class AppPrefs {
|
||||
mapVaultShared(new GlobalStringProperty(), "workspaceLock", String.class, true);
|
||||
|
||||
@Getter
|
||||
private final List<AppPrefsCategory> categories;
|
||||
private final List<AppPrefsCategory> categories = List.of(
|
||||
new AboutCategory(),
|
||||
new AppearanceCategory(),
|
||||
new VaultCategory(),
|
||||
new SyncCategory(),
|
||||
new PasswordManagerCategory(),
|
||||
new TerminalCategory(),
|
||||
new LoggingCategory(),
|
||||
new EditorCategory(),
|
||||
new RdpCategory(),
|
||||
new VncCategory(),
|
||||
new SshCategory(),
|
||||
new ConnectionHubCategory(),
|
||||
new FileBrowserCategory(),
|
||||
new IconsCategory(),
|
||||
new SystemCategory(),
|
||||
new ApiCategory(),
|
||||
new McpCategory(),
|
||||
new UpdatesCategory(),
|
||||
new SecurityCategory(),
|
||||
new WorkspacesCategory(),
|
||||
new DeveloperCategory(),
|
||||
new TroubleshootCategory(),
|
||||
new LinksCategory());
|
||||
|
||||
private final AppPrefsStorageHandler globalStorageHandler = new AppPrefsStorageHandler(
|
||||
AppProperties.get().getDataDir().resolve("settings").resolve("preferences.json"));
|
||||
private final Map<Mapping, OptionsBuilder> customEntries = new LinkedHashMap<>();
|
||||
|
||||
@Getter
|
||||
private final Property<AppPrefsCategory> selectedCategory;
|
||||
private final Property<AppPrefsCategory> selectedCategory = new GlobalObjectProperty<>(categories.getFirst());
|
||||
|
||||
private final PrefsHandler extensionHandler = new PrefsHandlerImpl();
|
||||
private AppPrefsStorageHandler vaultStorageHandler;
|
||||
|
||||
private AppPrefs() {
|
||||
this.categories = Stream.of(
|
||||
new AboutCategory(),
|
||||
new AppearanceCategory(),
|
||||
new VaultCategory(),
|
||||
new SyncCategory(),
|
||||
new PasswordManagerCategory(),
|
||||
new TerminalCategory(),
|
||||
new LoggingCategory(),
|
||||
new EditorCategory(),
|
||||
new RdpCategory(),
|
||||
new VncCategory(),
|
||||
new SshCategory(),
|
||||
new ConnectionHubCategory(),
|
||||
new FileBrowserCategory(),
|
||||
new IconsCategory(),
|
||||
new SystemCategory(),
|
||||
new ApiCategory(),
|
||||
new McpCategory(),
|
||||
new UpdatesCategory(),
|
||||
new SecurityCategory(),
|
||||
new WorkspacesCategory(),
|
||||
new DeveloperCategory(),
|
||||
new TroubleshootCategory(),
|
||||
new LinksCategory())
|
||||
.toList();
|
||||
this.selectedCategory = new GlobalObjectProperty<>(categories.getFirst());
|
||||
}
|
||||
|
||||
public static void initLocal() {
|
||||
INSTANCE = new AppPrefs();
|
||||
PrefsProvider.getAll().forEach(prov -> prov.addPrefs(INSTANCE.extensionHandler));
|
||||
INSTANCE.loadLocal();
|
||||
INSTANCE.vaultStorageHandler =
|
||||
new AppPrefsStorageHandler(DataStorage.getStorageDirectory().resolve("preferences.json"));
|
||||
INSTANCE.fixLocalValues();
|
||||
}
|
||||
|
||||
public static void initSynced() throws Exception {
|
||||
INSTANCE.loadSharedRemote();
|
||||
INSTANCE.encryptAllVaultData.addListener((observableValue, aBoolean, t1) -> {
|
||||
if (DataStorage.get() != null) {
|
||||
DataStorage.get().forceRewrite();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
INSTANCE.save();
|
||||
|
||||
// Keep instance as we might need some values on shutdown, e.g. on update with terminals
|
||||
// INSTANCE = null;
|
||||
}
|
||||
|
||||
public static AppPrefs get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
private AppPrefs() {}
|
||||
|
||||
public ObservableBooleanValue disableHardwareAcceleration() {
|
||||
return disableHardwareAcceleration;
|
||||
@@ -647,8 +718,8 @@ public final class AppPrefs {
|
||||
var writable = (Property<T>) prop;
|
||||
PlatformThread.runLaterIfNeededBlocking(() -> {
|
||||
writable.setValue(newValue);
|
||||
save();
|
||||
});
|
||||
save();
|
||||
}
|
||||
|
||||
private void fixLocalValues() {
|
||||
@@ -751,7 +822,7 @@ public final class AppPrefs {
|
||||
return val;
|
||||
}
|
||||
|
||||
public void save() {
|
||||
public synchronized void save() {
|
||||
for (Mapping m : mapping) {
|
||||
AppPrefsStorageHandler handler = m.isVaultSpecific() ? vaultStorageHandler : globalStorageHandler;
|
||||
// It might be possible that we save while the vault handler is not initialized yet / has no file or
|
||||
|
||||
@@ -23,8 +23,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class AppPrefsSidebarComp extends SimpleComp {
|
||||
|
||||
private static final PseudoClass SELECTED = PseudoClass.getPseudoClass("selected");
|
||||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
var effectiveCategories = AppPrefs.get().getCategories().stream()
|
||||
@@ -43,7 +41,7 @@ public class AppPrefsSidebarComp extends SimpleComp {
|
||||
struc.get().setTextAlignment(TextAlignment.LEFT);
|
||||
struc.get().setAlignment(Pos.CENTER_LEFT);
|
||||
AppPrefs.get().getSelectedCategory().subscribe(val -> {
|
||||
struc.get().pseudoClassStateChanged(SELECTED, appPrefsCategory.equals(val));
|
||||
struc.get().pseudoClassStateChanged(PseudoClass.getPseudoClass("selected"), appPrefsCategory.equals(val));
|
||||
});
|
||||
})
|
||||
.grow(true, false);
|
||||
|
||||
@@ -12,7 +12,7 @@ import javafx.scene.layout.Region;
|
||||
|
||||
public class UpdateCheckComp extends SimpleComp {
|
||||
|
||||
private void showAlert() {
|
||||
private void showDialog() {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
AppDistributionType.get().getUpdateHandler().refreshUpdateCheckSilent(false, false);
|
||||
UpdateAvailableDialog.showIfNeeded(false);
|
||||
@@ -96,7 +96,7 @@ public class UpdateCheckComp extends SimpleComp {
|
||||
return new TileButtonComp(name, description, graphic, actionEvent -> {
|
||||
actionEvent.consume();
|
||||
if (uh.getPreparedUpdate().getValue() != null) {
|
||||
showAlert();
|
||||
showDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+5
-19
@@ -7,12 +7,11 @@ import io.xpipe.app.comp.base.ModalOverlay;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.window.AppDialog;
|
||||
import io.xpipe.app.issue.ErrorAction;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.util.DocumentationLink;
|
||||
import io.xpipe.app.util.Hyperlinks;
|
||||
|
||||
public class UpdateChangelogAlert {
|
||||
public class UpdateChangelogDialog {
|
||||
|
||||
private static boolean shown = false;
|
||||
|
||||
@@ -21,23 +20,10 @@ public class UpdateChangelogAlert {
|
||||
if (update != null && !AppDistributionType.get().getUpdateHandler().isUpdateSucceeded()) {
|
||||
ErrorEventFactory.fromMessage(AppI18n.get("updateFail"))
|
||||
.documentationLink(DocumentationLink.UPDATE_FAIL)
|
||||
.customAction(new ErrorAction() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return AppI18n.get("updateFailAction");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return AppI18n.get("updateFailActionDescription");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(ErrorEvent event) {
|
||||
Hyperlinks.open(Hyperlinks.GITHUB_LATEST);
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.customAction(ErrorAction.translated("updateFailAction", () -> {
|
||||
Hyperlinks.open(Hyperlinks.GITHUB_LATEST);
|
||||
return true;
|
||||
}))
|
||||
.handle();
|
||||
return;
|
||||
}
|
||||
@@ -45,11 +45,6 @@ public class Deobfuscator {
|
||||
return stackTrace;
|
||||
}
|
||||
|
||||
public static void printStackTrace(Throwable t) {
|
||||
var s = deobfuscateToString(t);
|
||||
System.err.println(s);
|
||||
}
|
||||
|
||||
private static boolean canDeobfuscate() {
|
||||
if (!System.getenv().containsKey("XPIPE_MAPPING")) {
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user