diff --git a/app/src/main/java/io/xpipe/app/core/AppStyle.java b/app/src/main/java/io/xpipe/app/core/AppStyle.java index ac792051f..e009c3f4b 100644 --- a/app/src/main/java/io/xpipe/app/core/AppStyle.java +++ b/app/src/main/java/io/xpipe/app/core/AppStyle.java @@ -103,6 +103,12 @@ public class AppStyle { STYLESHEET_CONTENTS.values().forEach(s -> { scene.getStylesheets().add(s); }); + if (AppPrefs.get() != null) { + var t = AppPrefs.get().theme.get(); + if (t != null) { + scene.getStylesheets().addAll(t.getAdditionalStylesheets()); + } + } TrackEvent.debug("Added stylesheets for scene"); scenes.add(scene); diff --git a/app/src/main/java/io/xpipe/app/core/AppTheme.java b/app/src/main/java/io/xpipe/app/core/AppTheme.java index 236749bae..34f84ac85 100644 --- a/app/src/main/java/io/xpipe/app/core/AppTheme.java +++ b/app/src/main/java/io/xpipe/app/core/AppTheme.java @@ -59,6 +59,8 @@ public class AppTheme { } stage.getScene().getRoot().getStyleClass().add(t.getCssId()); + stage.getScene().getStylesheets().removeAll(t.getAdditionalStylesheets()); + stage.getScene().getStylesheets().addAll(t.getAdditionalStylesheets()); stage.getScene().getRoot().pseudoClassStateChanged(LIGHT, !t.isDark()); stage.getScene().getRoot().pseudoClassStateChanged(DARK, t.isDark()); }); @@ -257,6 +259,15 @@ public class AppTheme { Application.setUserAgentStylesheet(theme.getUserAgentStylesheetBSS()); } + public List getAdditionalStylesheets() { + var r = AppResources.getResourceURL(AppResources.XPIPE_MODULE, "theme/" + getId() + ".css"); + if (r.isEmpty()) { + return List.of(); + } else { + return List.of(r.get().toString()); + } + } + @Override public ObservableValue toTranslatedString() { return new SimpleStringProperty(theme.getName()); diff --git a/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java b/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java index 874a45420..10e6f9950 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/OperationMode.java @@ -94,13 +94,15 @@ public abstract class OperationMode { // Handle uncaught exceptions Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> { + // It seems like a few exceptions are thrown in the quantum renderer + // when in shutdown. We can ignore these + if (OperationMode.isInShutdown() && Platform.isFxApplicationThread() && ex instanceof NullPointerException) { + return; + } + ErrorEvent.fromThrowable(ex).unhandled(true).build().handle(); }); - // if (true) { - // throw new OutOfMemoryError(); - // } - TrackEvent.info("Initial setup"); AppProperties.init(); AppState.init(); diff --git a/app/src/main/java/io/xpipe/app/util/PlatformState.java b/app/src/main/java/io/xpipe/app/util/PlatformState.java index 7223122c5..377ba10b0 100644 --- a/app/src/main/java/io/xpipe/app/util/PlatformState.java +++ b/app/src/main/java/io/xpipe/app/util/PlatformState.java @@ -6,15 +6,12 @@ import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.core.process.OsType; - import javafx.application.Platform; - import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.SystemUtils; import java.awt.*; -import java.util.Optional; import java.util.concurrent.CountDownLatch; public enum PlatformState { @@ -26,8 +23,15 @@ public enum PlatformState { @Setter private static PlatformState current = PlatformState.NOT_INITIALIZED; - @Getter - private static Exception lastError; + private static Throwable lastError; + private static boolean expectedError; + + public static Throwable getLastError() { + if (expectedError) { + ErrorEvent.expected(lastError); + } + return lastError; + } public static void teardown() { // This is bad and can get sometimes stuck @@ -48,26 +52,25 @@ public enum PlatformState { public static void initPlatformOrThrow() throws Exception { initPlatformIfNeeded(); if (lastError != null) { - throw lastError; + throw lastError instanceof Exception e ? e : new Exception(lastError); } } public static boolean initPlatformIfNeeded() { if (current == NOT_INITIALIZED) { - var t = PlatformState.initPlatform().orElse(null); - lastError = t instanceof Exception e ? e : t != null ? new Exception(t) : null; + PlatformState.initPlatform(); } - return current == RUNNING; } - private static Optional initPlatform() { + private static void initPlatform() { if (current == EXITED) { - return Optional.of(new IllegalStateException("Platform has already exited")); + lastError = new IllegalStateException("Platform has already exited"); + return; } if (current == RUNNING) { - return Optional.empty(); + return; } try { @@ -87,11 +90,14 @@ public enum PlatformState { + " You don't have to install XPipe on any system like a server, a WSL distribution, a hypervisor, etc.," + " to have full access to that system, a shell connection to it is enough for XPipe to work from your local machine."; PlatformState.setCurrent(PlatformState.EXITED); - return Optional.of(ErrorEvent.expected(new UnsupportedOperationException(msg))); + expectedError = true; + lastError = new UnsupportedOperationException(msg); + return; } catch (Throwable t) { TrackEvent.warn(t.getMessage()); PlatformState.setCurrent(PlatformState.EXITED); - return Optional.of(t); + lastError = t; + return; } // Check if we have no fonts and set properties to load bundled ones @@ -128,23 +134,26 @@ public enum PlatformState { try { latch.await(); PlatformState.setCurrent(PlatformState.RUNNING); - return Optional.empty(); + return; } catch (InterruptedException e) { - return Optional.of(e); + lastError = e; + return; } } catch (Throwable t) { // Check if we already exited if ("Platform.exit has been called".equals(t.getMessage())) { PlatformState.setCurrent(PlatformState.EXITED); - return Optional.of(t); + lastError = t; + return; } else if ("Toolkit already initialized".equals(t.getMessage())) { PlatformState.setCurrent(PlatformState.RUNNING); - return Optional.empty(); + return; } else { // Platform initialization has failed in this case PlatformState.setCurrent(PlatformState.EXITED); TrackEvent.error(t.getMessage()); - return Optional.of(t); + lastError =t; + return; } } } diff --git a/app/src/main/resources/io/xpipe/app/resources/style/browser.css b/app/src/main/resources/io/xpipe/app/resources/style/browser.css index fcaf4e34e..f293bee56 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/browser.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/browser.css @@ -51,8 +51,9 @@ } .browser .welcome { - -fx-background-color: -color-bg-inset, -color-border-default, -color-bg-default; - -fx-background-insets: 0, 2.65em 0 0 0, 2.70em 0 0 0; + -fx-border-color: -color-bg-inset, -color-border-default; + -fx-border-width: 2.65em 0 0 0, 0.05em 0 0 0; + -fx-border-insets: 0, 2.65em 0 0 0; } .root:seamless-frame .browser .welcome { diff --git a/app/src/main/resources/io/xpipe/app/resources/style/style.css b/app/src/main/resources/io/xpipe/app/resources/style/style.css index d63e07ad4..a19000a00 100644 --- a/app/src/main/resources/io/xpipe/app/resources/style/style.css +++ b/app/src/main/resources/io/xpipe/app/resources/style/style.css @@ -9,22 +9,40 @@ -fx-background-color: transparent; } -.root:dark .background { +.root:dark:separate-frame .background { -fx-background-color: derive(-color-bg-default, 1%); } -.root:light .background { +.root:light:separate-frame .background { -fx-background-color: derive(-color-bg-default, -9%); } -.root:dark.background { +.root:dark:separate-frame.background { -fx-background-color: derive(-color-bg-default, 1%); } -.root:light.background { +.root:light:separate-frame.background { -fx-background-color: derive(-color-bg-default, -9%); } + + +.root:dark:seamless-frame .background { + -fx-background-color: derive(-color-bg-default-transparent, 1%); +} + +.root:light:seamless-frame .background { + -fx-background-color: derive(-color-bg-default-transparent, -9%); +} + +.root:dark:seamless-frame.background { + -fx-background-color: derive(-color-bg-default-transparent, 1%); +} + +.root:light:seamless-frame.background { + -fx-background-color: derive(-color-bg-default-transparent, -9%); +} + .root:seamless-frame.layout > .background { -fx-background-insets: 5 0 0 0; -fx-border-insets: 5 0 0 0; diff --git a/app/src/main/resources/io/xpipe/app/resources/theme/cupertinoDark.css b/app/src/main/resources/io/xpipe/app/resources/theme/cupertinoDark.css new file mode 100644 index 000000000..e27a340b5 --- /dev/null +++ b/app/src/main/resources/io/xpipe/app/resources/theme/cupertinoDark.css @@ -0,0 +1 @@ +.root { -color-bg-default-transparent: #0d1117d2; } \ No newline at end of file diff --git a/app/src/main/resources/io/xpipe/app/resources/theme/dark.css b/app/src/main/resources/io/xpipe/app/resources/theme/dark.css new file mode 100644 index 000000000..e27a340b5 --- /dev/null +++ b/app/src/main/resources/io/xpipe/app/resources/theme/dark.css @@ -0,0 +1 @@ +.root { -color-bg-default-transparent: #0d1117d2; } \ No newline at end of file diff --git a/app/src/main/resources/io/xpipe/app/resources/theme/light.css b/app/src/main/resources/io/xpipe/app/resources/theme/light.css new file mode 100644 index 000000000..ea72bdf67 --- /dev/null +++ b/app/src/main/resources/io/xpipe/app/resources/theme/light.css @@ -0,0 +1 @@ +.root { -color-bg-default-transparent: #FFFFFF99; } \ No newline at end of file diff --git a/app/src/main/resources/io/xpipe/app/resources/theme/nordDark.css b/app/src/main/resources/io/xpipe/app/resources/theme/nordDark.css new file mode 100644 index 000000000..e27a340b5 --- /dev/null +++ b/app/src/main/resources/io/xpipe/app/resources/theme/nordDark.css @@ -0,0 +1 @@ +.root { -color-bg-default-transparent: #0d1117d2; } \ No newline at end of file diff --git a/lang/proc/strings/translations_da.properties b/lang/proc/strings/translations_da.properties index fcc52fe74..526340f7f 100644 --- a/lang/proc/strings/translations_da.properties +++ b/lang/proc/strings/translations_da.properties @@ -357,3 +357,5 @@ vmActions=VM-handlinger dockerContextActions=Kontekst-handlinger k8sPodActions=Pod-handlinger openVnc=Sæt VNC op +commandGroup.displayName=Kommandogruppe +commandGroup.displayDescription=Grupper tilgængelige kommandoer for et system diff --git a/lang/proc/strings/translations_de.properties b/lang/proc/strings/translations_de.properties index 771a30605..8d8b8cc05 100644 --- a/lang/proc/strings/translations_de.properties +++ b/lang/proc/strings/translations_de.properties @@ -335,3 +335,5 @@ vmActions=VM-Aktionen dockerContextActions=Kontextbezogene Aktionen k8sPodActions=Pod-Aktionen openVnc=VNC einrichten +commandGroup.displayName=Befehlsgruppe +commandGroup.displayDescription=Verfügbare Befehle für ein System gruppieren diff --git a/lang/proc/strings/translations_en.properties b/lang/proc/strings/translations_en.properties index cb7164d17..8d9905f74 100644 --- a/lang/proc/strings/translations_en.properties +++ b/lang/proc/strings/translations_en.properties @@ -332,4 +332,6 @@ containerActions=Container actions vmActions=VM actions dockerContextActions=Context actions k8sPodActions=Pod actions -openVnc=Set up VNC \ No newline at end of file +openVnc=Set up VNC +commandGroup.displayName=Command group +commandGroup.displayDescription=Group available commands for a system \ No newline at end of file diff --git a/lang/proc/strings/translations_es.properties b/lang/proc/strings/translations_es.properties index 0e02e909b..83a12ac97 100644 --- a/lang/proc/strings/translations_es.properties +++ b/lang/proc/strings/translations_es.properties @@ -331,3 +331,5 @@ vmActions=Acciones VM dockerContextActions=Acciones contextuales k8sPodActions=Acciones del pod openVnc=Configurar VNC +commandGroup.displayName=Grupo de comandos +commandGroup.displayDescription=Agrupa los comandos disponibles para un sistema diff --git a/lang/proc/strings/translations_fr.properties b/lang/proc/strings/translations_fr.properties index 2fd9315c2..20b4cc865 100644 --- a/lang/proc/strings/translations_fr.properties +++ b/lang/proc/strings/translations_fr.properties @@ -331,3 +331,5 @@ vmActions=Actions VM dockerContextActions=Actions contextuelles k8sPodActions=Actions de pods openVnc=Configurer VNC +commandGroup.displayName=Groupe de commande +commandGroup.displayDescription=Groupe de commandes disponibles pour un système diff --git a/lang/proc/strings/translations_it.properties b/lang/proc/strings/translations_it.properties index 7a0be9bb9..dbef50ac6 100644 --- a/lang/proc/strings/translations_it.properties +++ b/lang/proc/strings/translations_it.properties @@ -331,3 +331,5 @@ vmActions=Azioni della VM dockerContextActions=Azioni contestuali k8sPodActions=Azioni del pod openVnc=Configurare VNC +commandGroup.displayName=Gruppo di comando +commandGroup.displayDescription=Gruppo di comandi disponibili per un sistema diff --git a/lang/proc/strings/translations_ja.properties b/lang/proc/strings/translations_ja.properties index 9eb9681c9..79c161735 100644 --- a/lang/proc/strings/translations_ja.properties +++ b/lang/proc/strings/translations_ja.properties @@ -331,3 +331,5 @@ vmActions=VMアクション dockerContextActions=コンテキストアクション k8sPodActions=ポッドアクション openVnc=VNCを設定する +commandGroup.displayName=コマンドグループ +commandGroup.displayDescription=システムで使用可能なコマンドをグループ化する diff --git a/lang/proc/strings/translations_nl.properties b/lang/proc/strings/translations_nl.properties index a7d9c7f4a..7ea31c90b 100644 --- a/lang/proc/strings/translations_nl.properties +++ b/lang/proc/strings/translations_nl.properties @@ -331,3 +331,5 @@ vmActions=VM-acties dockerContextActions=Context acties k8sPodActions=Pod acties openVnc=VNC instellen +commandGroup.displayName=Opdrachtgroep +commandGroup.displayDescription=Groep beschikbare commando's voor een systeem diff --git a/lang/proc/strings/translations_pt.properties b/lang/proc/strings/translations_pt.properties index f700213bb..2d495a348 100644 --- a/lang/proc/strings/translations_pt.properties +++ b/lang/proc/strings/translations_pt.properties @@ -331,3 +331,5 @@ vmActions=Acções VM dockerContextActions=Acções de contexto k8sPodActions=Acções de pod openVnc=Configura o VNC +commandGroup.displayName=Grupo de comandos +commandGroup.displayDescription=Agrupa os comandos disponíveis para um sistema diff --git a/lang/proc/strings/translations_ru.properties b/lang/proc/strings/translations_ru.properties index a064f9a89..9b528e587 100644 --- a/lang/proc/strings/translations_ru.properties +++ b/lang/proc/strings/translations_ru.properties @@ -331,3 +331,5 @@ vmActions=Действия виртуальной машины dockerContextActions=Контекстные действия k8sPodActions=Действия в капсуле openVnc=Настройте VNC +commandGroup.displayName=Группа команд +commandGroup.displayDescription=Группа доступных команд для системы diff --git a/lang/proc/strings/translations_tr.properties b/lang/proc/strings/translations_tr.properties index 23214c0da..ce0890001 100644 --- a/lang/proc/strings/translations_tr.properties +++ b/lang/proc/strings/translations_tr.properties @@ -331,3 +331,5 @@ vmActions=VM eylemleri dockerContextActions=Bağlam eylemleri k8sPodActions=Pod eylemleri openVnc=VNC'yi ayarlama +commandGroup.displayName=Komuta grubu +commandGroup.displayDescription=Bir sistem için mevcut komutları gruplama diff --git a/lang/proc/strings/translations_zh.properties b/lang/proc/strings/translations_zh.properties index e46e8790c..36ba085f9 100644 --- a/lang/proc/strings/translations_zh.properties +++ b/lang/proc/strings/translations_zh.properties @@ -331,3 +331,5 @@ vmActions=虚拟机操作 dockerContextActions=上下文操作 k8sPodActions=Pod 操作 openVnc=设置 VNC +commandGroup.displayName=命令组 +commandGroup.displayDescription=系统可用命令组