diff --git a/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java b/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java index 68fcc7fd6..2809e023a 100644 --- a/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java +++ b/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java @@ -1,7 +1,5 @@ package io.xpipe.app.beacon; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpServer; import io.xpipe.app.core.AppResources; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; @@ -10,6 +8,9 @@ import io.xpipe.app.util.MarkdownHelper; import io.xpipe.beacon.BeaconConfig; import io.xpipe.beacon.BeaconInterface; import io.xpipe.core.util.XPipeInstallation; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpServer; import lombok.Getter; import java.io.IOException; @@ -22,16 +23,22 @@ import java.util.concurrent.Executors; public class AppBeaconServer { private static AppBeaconServer INSTANCE; + @Getter private final int port; + @Getter private final boolean propertyPort; + private boolean running; private HttpServer server; + @Getter private final Set sessions = new HashSet<>(); + @Getter private final Set shellSessions = new HashSet<>(); + @Getter private String localAuthSecret; @@ -122,8 +129,7 @@ public class AppBeaconServer { "openapi.yaml", "misc/openapi.yaml", "markdown.css", "misc/github-markdown-dark.css", "highlight.min.js", "misc/highlight.min.js", - "github-dark.min.css", "misc/github-dark.min.css" - ); + "github-dark.min.css", "misc/github-dark.min.css"); resourceMap.forEach((s, s2) -> { server.createContext("/" + s, exchange -> { handleResource(exchange, s2); @@ -145,7 +151,7 @@ public class AppBeaconServer { }); } var body = resources.get(resource).getBytes(StandardCharsets.UTF_8); - exchange.sendResponseHeaders(200,body.length); + exchange.sendResponseHeaders(200, body.length); try (var out = exchange.getResponseBody()) { out.write(body); } @@ -154,19 +160,21 @@ public class AppBeaconServer { private void handleCatchAll(HttpExchange exchange) throws IOException { if (notFoundHtml == null) { AppResources.with(AppResources.XPIPE_MODULE, "misc/api.md", file -> { - notFoundHtml = MarkdownHelper.toHtml(Files.readString(file), head -> { - return head + "\n" + - "" + "\n" + - "" + "\n" + - "" + "\n" + - ""; - }, s -> { - return "
" + s + "
"; - }); + notFoundHtml = MarkdownHelper.toHtml( + Files.readString(file), + head -> { + return head + "\n" + "" + + "\n" + "" + + "\n" + "" + + "\n" + ""; + }, + s -> { + return "
" + s + "
"; + }); }); } var body = notFoundHtml.getBytes(StandardCharsets.UTF_8); - exchange.sendResponseHeaders(200,body.length); + exchange.sendResponseHeaders(200, body.length); try (var out = exchange.getResponseBody()) { out.write(body); } diff --git a/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java b/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java index ce713fe73..0ac65aa3a 100644 --- a/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java +++ b/app/src/main/java/io/xpipe/app/beacon/BeaconRequestHandler.java @@ -1,12 +1,13 @@ package io.xpipe.app.beacon; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.beacon.*; import io.xpipe.core.util.JacksonMapper; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; import lombok.SneakyThrows; import java.io.IOException; @@ -18,10 +19,12 @@ public class BeaconRequestHandler implements HttpHandler { private final BeaconInterface beaconInterface; - public BeaconRequestHandler(BeaconInterface beaconInterface) {this.beaconInterface = beaconInterface;} + public BeaconRequestHandler(BeaconInterface beaconInterface) { + this.beaconInterface = beaconInterface; + } @Override - public void handle(HttpExchange exchange) throws IOException { + public void handle(HttpExchange exchange) { if (!AppPrefs.get().disableApiAuthentication().get() && beaconInterface.requiresAuthentication()) { var auth = exchange.getRequestHeaders().getFirst("Authorization"); if (auth == null) { @@ -30,7 +33,10 @@ public class BeaconRequestHandler implements HttpHandler { } var token = auth.replace("Bearer ", ""); - var session = AppBeaconServer.get().getSessions().stream().filter(s -> s.getToken().equals(token)).findFirst().orElse(null); + var session = AppBeaconServer.get().getSessions().stream() + .filter(s -> s.getToken().equals(token)) + .findFirst() + .orElse(null); if (session == null) { writeError(exchange, new BeaconClientErrorResponse("Unknown token"), 403); return; @@ -47,8 +53,11 @@ public class BeaconRequestHandler implements HttpHandler { try (InputStream is = exchange.getRequestBody()) { var tree = JacksonMapper.getDefault().readTree(is); TrackEvent.trace("Parsed raw request:\n" + tree.toPrettyString()); - var emptyRequestClass = tree.isEmpty() && beaconInterface.getRequestClass().getDeclaredFields().length == 0; - object = emptyRequestClass ? createDefaultRequest(beaconInterface) : JacksonMapper.getDefault().treeToValue(tree, beaconInterface.getRequestClass()); + var emptyRequestClass = + tree.isEmpty() && beaconInterface.getRequestClass().getDeclaredFields().length == 0; + object = emptyRequestClass + ? createDefaultRequest(beaconInterface) + : JacksonMapper.getDefault().treeToValue(tree, beaconInterface.getRequestClass()); TrackEvent.trace("Parsed request object:\n" + object); } response = beaconInterface.handle(exchange, object); @@ -62,7 +71,8 @@ public class BeaconRequestHandler implements HttpHandler { writeError(exchange, new BeaconServerErrorResponse(cause), 500); return; } catch (IOException ex) { - // Handle serialization errors as normal exceptions and other IO exceptions as assuming that the connection is broken + // Handle serialization errors as normal exceptions and other IO exceptions as assuming that the connection + // is broken if (!ex.getClass().getName().contains("jackson")) { ErrorEvent.fromThrowable(ex).omit().expected().handle(); } else { @@ -76,32 +86,32 @@ public class BeaconRequestHandler implements HttpHandler { return; } - try { - var emptyResponseClass = beaconInterface.getResponseClass().getDeclaredFields().length == 0; - if (!emptyResponseClass && response != null) { - TrackEvent.trace("Sending response:\n" + object); - var tree = JacksonMapper.getDefault().valueToTree(response); - TrackEvent.trace("Sending raw response:\n" + tree.toPrettyString()); - var bytes = tree.toPrettyString().getBytes(StandardCharsets.UTF_8); - exchange.sendResponseHeaders(200, bytes.length); - try (OutputStream os = exchange.getResponseBody()) { - os.write(bytes); - } - } else { - exchange.sendResponseHeaders(200, -1); + try { + var emptyResponseClass = beaconInterface.getResponseClass().getDeclaredFields().length == 0; + if (!emptyResponseClass && response != null) { + TrackEvent.trace("Sending response:\n" + object); + var tree = JacksonMapper.getDefault().valueToTree(response); + TrackEvent.trace("Sending raw response:\n" + tree.toPrettyString()); + var bytes = tree.toPrettyString().getBytes(StandardCharsets.UTF_8); + exchange.sendResponseHeaders(200, bytes.length); + try (OutputStream os = exchange.getResponseBody()) { + os.write(bytes); } - } catch (IOException ioException) { - ErrorEvent.fromThrowable(ioException).omit().expected().handle(); - } catch (Throwable other) { - ErrorEvent.fromThrowable(other).handle(); - writeError(exchange, new BeaconServerErrorResponse(other), 500); - return; + } else { + exchange.sendResponseHeaders(200, -1); } + } catch (IOException ioException) { + ErrorEvent.fromThrowable(ioException).omit().expected().handle(); + } catch (Throwable other) { + ErrorEvent.fromThrowable(other).handle(); + writeError(exchange, new BeaconServerErrorResponse(other), 500); + } } private void writeError(HttpExchange exchange, Object errorMessage, int code) { try { - var bytes = JacksonMapper.getDefault().writeValueAsString(errorMessage).getBytes(StandardCharsets.UTF_8); + var bytes = + JacksonMapper.getDefault().writeValueAsString(errorMessage).getBytes(StandardCharsets.UTF_8); exchange.sendResponseHeaders(code, bytes.length); try (OutputStream os = exchange.getResponseBody()) { os.write(bytes); diff --git a/app/src/main/java/io/xpipe/app/beacon/BeaconSession.java b/app/src/main/java/io/xpipe/app/beacon/BeaconSession.java index 38cec0f23..69c549147 100644 --- a/app/src/main/java/io/xpipe/app/beacon/BeaconSession.java +++ b/app/src/main/java/io/xpipe/app/beacon/BeaconSession.java @@ -1,6 +1,7 @@ package io.xpipe.app.beacon; import io.xpipe.beacon.BeaconClientInformation; + import lombok.Value; @Value diff --git a/app/src/main/java/io/xpipe/app/beacon/BeaconShellSession.java b/app/src/main/java/io/xpipe/app/beacon/BeaconShellSession.java index a92415a7a..6bc7c891a 100644 --- a/app/src/main/java/io/xpipe/app/beacon/BeaconShellSession.java +++ b/app/src/main/java/io/xpipe/app/beacon/BeaconShellSession.java @@ -2,6 +2,7 @@ package io.xpipe.app.beacon; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.core.process.ShellControl; + import lombok.Value; @Value diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java index e3fa224b5..4abf377f5 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/AskpassExchangeImpl.java @@ -1,18 +1,19 @@ package io.xpipe.app.beacon.impl; -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.util.AskpassAlert; import io.xpipe.app.util.SecretManager; import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.AskpassExchange; +import com.sun.net.httpserver.HttpExchange; + import java.io.IOException; public class AskpassExchangeImpl extends AskpassExchange { @Override - public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + public Object handle(HttpExchange exchange, Request msg) { if (msg.getRequest() == null) { var r = AskpassAlert.queryRaw(msg.getPrompt(), null); return Response.builder().value(r.getSecret()).build(); diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionQueryExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionQueryExchangeImpl.java index 2fca86f76..eeabbb079 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionQueryExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/ConnectionQueryExchangeImpl.java @@ -1,6 +1,5 @@ package io.xpipe.app.beacon.impl; -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.beacon.BeaconClientException; @@ -8,6 +7,8 @@ import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.ConnectionQueryExchange; import io.xpipe.core.store.StorePath; +import com.sun.net.httpserver.HttpExchange; + import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -16,7 +17,7 @@ import java.util.regex.Pattern; public class ConnectionQueryExchangeImpl extends ConnectionQueryExchange { @Override - public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + public Object handle(HttpExchange exchange, Request msg) { var catMatcher = Pattern.compile(toRegex("all connections/" + msg.getCategoryFilter())); var conMatcher = Pattern.compile(toRegex(msg.getConnectionFilter())); @@ -31,7 +32,9 @@ public class ConnectionQueryExchangeImpl extends ConnectionQueryExchange { continue; } - var cat = DataStorage.get().getStoreCategoryIfPresent(storeEntry.getCategoryUuid()).orElse(null); + var cat = DataStorage.get() + .getStoreCategoryIfPresent(storeEntry.getCategoryUuid()) + .orElse(null); if (cat == null) { continue; } @@ -46,11 +49,18 @@ public class ConnectionQueryExchangeImpl extends ConnectionQueryExchange { var mapped = new ArrayList(); for (DataStoreEntry e : found) { - var names = DataStorage.get().getStorePath(DataStorage.get().getStoreCategoryIfPresent(e.getCategoryUuid()).orElseThrow()).getNames(); + var names = DataStorage.get() + .getStorePath(DataStorage.get() + .getStoreCategoryIfPresent(e.getCategoryUuid()) + .orElseThrow()) + .getNames(); var cat = new StorePath(names.subList(1, names.size())); var obj = ConnectionQueryExchange.QueryResponse.builder() - .uuid(e.getUuid()).category(cat).connection(DataStorage.get() - .getStorePath(e)).type(e.getProvider().getId()).build(); + .uuid(e.getUuid()) + .category(cat) + .connection(DataStorage.get().getStorePath(e)) + .type(e.getProvider().getId()) + .build(); mapped.add(obj); } return Response.builder().found(mapped).build(); @@ -86,20 +96,16 @@ public class ConnectionQueryExchangeImpl extends ConnectionQueryExchange { } break; case '*': - if (inClass == 0) - sb.append(".*"); - else - sb.append('*'); + if (inClass == 0) sb.append(".*"); + else sb.append('*'); break; case '?': - if (inClass == 0) - sb.append('.'); - else - sb.append('?'); + if (inClass == 0) sb.append('.'); + else sb.append('?'); break; case '[': inClass++; - firstIndexInClass = i+1; + firstIndexInClass = i + 1; sb.append('['); break; case ']': @@ -115,15 +121,12 @@ public class ConnectionQueryExchangeImpl extends ConnectionQueryExchange { case '$': case '@': case '%': - if (inClass == 0 || (firstIndexInClass == i && ch == '^')) - sb.append('\\'); + if (inClass == 0 || (firstIndexInClass == i && ch == '^')) sb.append('\\'); sb.append(ch); break; case '!': - if (firstIndexInClass == i) - sb.append('^'); - else - sb.append('!'); + if (firstIndexInClass == i) sb.append('^'); + else sb.append('!'); break; case '{': inGroup++; @@ -134,10 +137,8 @@ public class ConnectionQueryExchangeImpl extends ConnectionQueryExchange { sb.append(')'); break; case ',': - if (inGroup > 0) - sb.append('|'); - else - sb.append(','); + if (inGroup > 0) sb.append('|'); + else sb.append(','); break; default: sb.append(ch); diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonFocusExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonFocusExchangeImpl.java index 1a25af89e..1d3e4aff8 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonFocusExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonFocusExchangeImpl.java @@ -1,20 +1,20 @@ package io.xpipe.app.beacon.impl; -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.core.mode.OperationMode; import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.DaemonFocusExchange; +import com.sun.net.httpserver.HttpExchange; + import java.io.IOException; public class DaemonFocusExchangeImpl extends DaemonFocusExchange { + @Override + public Object handle(HttpExchange exchange, Request msg) { -@Override -public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { - - OperationMode.switchUp(OperationMode.map(msg.getMode())); - return Response.builder().build(); -} + OperationMode.switchUp(OperationMode.map(msg.getMode())); + return Response.builder().build(); + } } diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonModeExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonModeExchangeImpl.java index ab7de9958..cf866f8b2 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonModeExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonModeExchangeImpl.java @@ -1,17 +1,19 @@ package io.xpipe.app.beacon.impl; -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.util.ThreadHelper; import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.DaemonModeExchange; +import com.sun.net.httpserver.HttpExchange; + import java.io.IOException; public class DaemonModeExchangeImpl extends DaemonModeExchange { @Override - public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + public Object handle(HttpExchange exchange, Request msg) + throws BeaconClientException { // Wait for startup while (OperationMode.get() == null) { ThreadHelper.sleep(100); @@ -21,11 +23,11 @@ public class DaemonModeExchangeImpl extends DaemonModeExchange { if (!mode.isSupported()) { throw new BeaconClientException("Unsupported mode: " + msg.getMode().getDisplayName() + ". Supported: " + String.join( - ", ", - OperationMode.getAll().stream() - .filter(OperationMode::isSupported) - .map(OperationMode::getId) - .toList())); + ", ", + OperationMode.getAll().stream() + .filter(OperationMode::isSupported) + .map(OperationMode::getId) + .toList())); } OperationMode.switchToSyncIfPossible(mode); diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonOpenExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonOpenExchangeImpl.java index 8a89878ec..2c2c8222e 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonOpenExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonOpenExchangeImpl.java @@ -1,6 +1,5 @@ package io.xpipe.app.beacon.impl; -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.launcher.LauncherInput; import io.xpipe.app.util.PlatformState; @@ -8,11 +7,14 @@ import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.DaemonOpenExchange; +import com.sun.net.httpserver.HttpExchange; + import java.io.IOException; public class DaemonOpenExchangeImpl extends DaemonOpenExchange { @Override - public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + public Object handle(HttpExchange exchange, Request msg) + throws BeaconServerException { if (msg.getArguments().isEmpty()) { if (!OperationMode.switchToSyncIfPossible(OperationMode.GUI)) { throw new BeaconServerException(PlatformState.getLastError()); diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStatusExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStatusExchangeImpl.java index 77eadf156..402ea1c99 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStatusExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStatusExchangeImpl.java @@ -1,18 +1,18 @@ package io.xpipe.app.beacon.impl; - -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.core.mode.OperationMode; import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.DaemonStatusExchange; +import com.sun.net.httpserver.HttpExchange; + import java.io.IOException; public class DaemonStatusExchangeImpl extends DaemonStatusExchange { @Override - public Object handle(HttpExchange exchange, Request body) throws IOException, BeaconClientException, BeaconServerException { + public Object handle(HttpExchange exchange, Request body) { String mode; if (OperationMode.get() == null) { mode = "none"; diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStopExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStopExchangeImpl.java index 0189350c2..c4fec7cdb 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStopExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonStopExchangeImpl.java @@ -1,18 +1,19 @@ package io.xpipe.app.beacon.impl; -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.core.mode.OperationMode; import io.xpipe.app.util.ThreadHelper; import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.DaemonStopExchange; +import com.sun.net.httpserver.HttpExchange; + import java.io.IOException; public class DaemonStopExchangeImpl extends DaemonStopExchange { @Override - public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + public Object handle(HttpExchange exchange, Request msg) { ThreadHelper.runAsync(() -> { ThreadHelper.sleep(1000); OperationMode.close(); diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonVersionExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonVersionExchangeImpl.java index f6ba986c4..5ba3b8a2d 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/DaemonVersionExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/DaemonVersionExchangeImpl.java @@ -1,17 +1,18 @@ package io.xpipe.app.beacon.impl; -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.core.AppProperties; import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.DaemonVersionExchange; +import com.sun.net.httpserver.HttpExchange; + import java.io.IOException; public class DaemonVersionExchangeImpl extends DaemonVersionExchange { @Override - public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + public Object handle(HttpExchange exchange, Request msg) { var jvmVersion = System.getProperty("java.vm.vendor") + " " + System.getProperty("java.vm.name") + " (" + System.getProperty("java.vm.version") + ")"; diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/HandshakeExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/HandshakeExchangeImpl.java index 2e10a773c..96d1a6a69 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/HandshakeExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/HandshakeExchangeImpl.java @@ -1,7 +1,5 @@ package io.xpipe.app.beacon.impl; - -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.beacon.BeaconSession; import io.xpipe.app.prefs.AppPrefs; @@ -10,13 +8,16 @@ import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.HandshakeExchange; +import com.sun.net.httpserver.HttpExchange; + import java.io.IOException; import java.util.UUID; public class HandshakeExchangeImpl extends HandshakeExchange { @Override - public Object handle(HttpExchange exchange, Request body) throws IOException, BeaconClientException, BeaconServerException { + public Object handle(HttpExchange exchange, Request body) + throws BeaconClientException { if (!checkAuth(body.getAuth())) { throw new BeaconClientException("Authentication failed"); } diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/ShellExecExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/ShellExecExchangeImpl.java index ad72fed64..218b5f764 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/ShellExecExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/ShellExecExchangeImpl.java @@ -1,11 +1,12 @@ package io.xpipe.app.beacon.impl; -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.storage.DataStorage; import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.ShellExecExchange; + +import com.sun.net.httpserver.HttpExchange; import lombok.SneakyThrows; import java.io.IOException; @@ -15,9 +16,13 @@ public class ShellExecExchangeImpl extends ShellExecExchange { @Override @SneakyThrows - public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { - var e = DataStorage.get().getStoreEntryIfPresent(msg.getConnection()).orElseThrow(() -> new IllegalArgumentException("Unknown connection")); - var existing = AppBeaconServer.get().getShellSessions().stream().filter(beaconShellSession -> beaconShellSession.getEntry().equals(e)).findFirst(); + public Object handle(HttpExchange exchange, Request msg) { + var e = DataStorage.get() + .getStoreEntryIfPresent(msg.getConnection()) + .orElseThrow(() -> new IllegalArgumentException("Unknown connection")); + var existing = AppBeaconServer.get().getShellSessions().stream() + .filter(beaconShellSession -> beaconShellSession.getEntry().equals(e)) + .findFirst(); if (existing.isEmpty()) { throw new BeaconClientException("No shell session active for connection"); } @@ -30,6 +35,10 @@ public class ShellExecExchangeImpl extends ShellExecExchange { command.accumulateStderr(s -> err.set(s)); exitCode = command.getExitCode(); } - return Response.builder().stdout(out.get()).stderr(err.get()).exitCode(exitCode).build(); + return Response.builder() + .stdout(out.get()) + .stderr(err.get()) + .exitCode(exitCode) + .build(); } } diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/ShellStartExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/ShellStartExchangeImpl.java index 085b8e714..611ec45e2 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/ShellStartExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/ShellStartExchangeImpl.java @@ -1,6 +1,5 @@ package io.xpipe.app.beacon.impl; -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.beacon.BeaconShellSession; import io.xpipe.app.storage.DataStorage; @@ -8,6 +7,8 @@ import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.ShellStartExchange; import io.xpipe.core.store.ShellStore; + +import com.sun.net.httpserver.HttpExchange; import lombok.SneakyThrows; import java.io.IOException; @@ -16,13 +17,17 @@ public class ShellStartExchangeImpl extends ShellStartExchange { @Override @SneakyThrows - public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { - var e = DataStorage.get().getStoreEntryIfPresent(msg.getConnection()).orElseThrow(() -> new IllegalArgumentException("Unknown connection")); + public Object handle(HttpExchange exchange, Request msg) { + var e = DataStorage.get() + .getStoreEntryIfPresent(msg.getConnection()) + .orElseThrow(() -> new IllegalArgumentException("Unknown connection")); if (!(e.getStore() instanceof ShellStore s)) { throw new BeaconClientException("Not a shell connection"); } - var existing = AppBeaconServer.get().getShellSessions().stream().filter(beaconShellSession -> beaconShellSession.getEntry().equals(e)).findFirst(); + var existing = AppBeaconServer.get().getShellSessions().stream() + .filter(beaconShellSession -> beaconShellSession.getEntry().equals(e)) + .findFirst(); if (existing.isPresent()) { return Response.builder().build(); } diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/ShellStopExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/ShellStopExchangeImpl.java index 07f07eb8d..35bef009a 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/ShellStopExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/ShellStopExchangeImpl.java @@ -1,11 +1,12 @@ package io.xpipe.app.beacon.impl; -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.beacon.AppBeaconServer; import io.xpipe.app.storage.DataStorage; import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.ShellStopExchange; + +import com.sun.net.httpserver.HttpExchange; import lombok.SneakyThrows; import java.io.IOException; @@ -14,9 +15,13 @@ public class ShellStopExchangeImpl extends ShellStopExchange { @Override @SneakyThrows - public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { - var e = DataStorage.get().getStoreEntryIfPresent(msg.getConnection()).orElseThrow(() -> new IllegalArgumentException("Unknown connection")); - var existing = AppBeaconServer.get().getShellSessions().stream().filter(beaconShellSession -> beaconShellSession.getEntry().equals(e)).findFirst(); + public Object handle(HttpExchange exchange, Request msg) { + var e = DataStorage.get() + .getStoreEntryIfPresent(msg.getConnection()) + .orElseThrow(() -> new IllegalArgumentException("Unknown connection")); + var existing = AppBeaconServer.get().getShellSessions().stream() + .filter(beaconShellSession -> beaconShellSession.getEntry().equals(e)) + .findFirst(); if (existing.isPresent()) { existing.get().getControl().close(); AppBeaconServer.get().getShellSessions().remove(existing.get()); diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/TerminalLaunchExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/TerminalLaunchExchangeImpl.java index 097486bcc..f7ea8d7d5 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/TerminalLaunchExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/TerminalLaunchExchangeImpl.java @@ -1,16 +1,18 @@ package io.xpipe.app.beacon.impl; -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.util.TerminalLauncherManager; import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.TerminalLaunchExchange; +import com.sun.net.httpserver.HttpExchange; + import java.io.IOException; public class TerminalLaunchExchangeImpl extends TerminalLaunchExchange { @Override - public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + public Object handle(HttpExchange exchange, Request msg) + throws BeaconClientException { var r = TerminalLauncherManager.performLaunch(msg.getRequest()); return Response.builder().targetFile(r).build(); } diff --git a/app/src/main/java/io/xpipe/app/beacon/impl/TerminalWaitExchangeImpl.java b/app/src/main/java/io/xpipe/app/beacon/impl/TerminalWaitExchangeImpl.java index 2114dacbd..ca0db72fa 100644 --- a/app/src/main/java/io/xpipe/app/beacon/impl/TerminalWaitExchangeImpl.java +++ b/app/src/main/java/io/xpipe/app/beacon/impl/TerminalWaitExchangeImpl.java @@ -1,16 +1,18 @@ package io.xpipe.app.beacon.impl; -import com.sun.net.httpserver.HttpExchange; import io.xpipe.app.util.TerminalLauncherManager; import io.xpipe.beacon.BeaconClientException; import io.xpipe.beacon.BeaconServerException; import io.xpipe.beacon.api.TerminalWaitExchange; +import com.sun.net.httpserver.HttpExchange; + import java.io.IOException; public class TerminalWaitExchangeImpl extends TerminalWaitExchange { @Override - public Object handle(HttpExchange exchange, Request msg) throws IOException, BeaconClientException, BeaconServerException { + public Object handle(HttpExchange exchange, Request msg) + throws BeaconClientException, BeaconServerException { TerminalLauncherManager.waitForCompletion(msg.getRequest()); return Response.builder().build(); } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserClipboard.java b/app/src/main/java/io/xpipe/app/browser/BrowserClipboard.java index 52265e633..2e4b2bef3 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserClipboard.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserClipboard.java @@ -8,11 +8,13 @@ import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.process.ProcessControlProvider; import io.xpipe.core.store.FileSystem; import io.xpipe.core.util.FailableRunnable; + import javafx.beans.property.Property; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.input.ClipboardContent; import javafx.scene.input.DataFormat; import javafx.scene.input.Dragboard; + import lombok.SneakyThrows; import lombok.Value; @@ -46,8 +48,7 @@ public class BrowserClipboard { } List data = (List) clipboard.getData(DataFlavor.javaFileListFlavor); - var files = - data.stream().map(f -> f.toPath()).toList(); + var files = data.stream().map(f -> f.toPath()).toList(); if (files.size() == 0) { return; } @@ -57,7 +58,8 @@ public class BrowserClipboard { entries.add(LocalFileSystem.getLocalBrowserEntry(file)); } - currentCopyClipboard.setValue(new Instance(UUID.randomUUID(), null, entries, BrowserFileTransferMode.COPY)); + currentCopyClipboard.setValue( + new Instance(UUID.randomUUID(), null, entries, BrowserFileTransferMode.COPY)); } catch (Exception e) { ErrorEvent.fromThrowable(e).expected().omit().handle(); } @@ -66,7 +68,8 @@ public class BrowserClipboard { } @SneakyThrows - public static ClipboardContent startDrag(FileSystem.FileEntry base, List selected, BrowserFileTransferMode mode) { + public static ClipboardContent startDrag( + FileSystem.FileEntry base, List selected, BrowserFileTransferMode mode) { if (selected.isEmpty()) { return null; } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFileOpener.java b/app/src/main/java/io/xpipe/app/browser/BrowserFileOpener.java index 2fbaec2bd..fb500e77f 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFileOpener.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFileOpener.java @@ -21,14 +21,14 @@ public class BrowserFileOpener { key, new BooleanScope(model.getBusy()).exclusive(), () -> { - return entry.getFileSystem().openInput(file); + return entry.getFileSystem().openInput(file); }, (size) -> { if (model.isClosed()) { return OutputStream.nullOutputStream(); } - return entry.getFileSystem().openOutput(file, size); + return entry.getFileSystem().openOutput(file, size); }, s -> FileOpener.openWithAnyApplication(s)); } @@ -42,14 +42,14 @@ public class BrowserFileOpener { key, new BooleanScope(model.getBusy()).exclusive(), () -> { - return entry.getFileSystem().openInput(file); + return entry.getFileSystem().openInput(file); }, (size) -> { if (model.isClosed()) { return OutputStream.nullOutputStream(); } - return entry.getFileSystem().openOutput(file, size); + return entry.getFileSystem().openOutput(file, size); }, s -> FileOpener.openInDefaultApplication(s)); } @@ -68,15 +68,14 @@ public class BrowserFileOpener { key, new BooleanScope(model.getBusy()).exclusive(), () -> { - return entry.getFileSystem().openInput(file); - + return entry.getFileSystem().openInput(file); }, (size) -> { if (model.isClosed()) { return OutputStream.nullOutputStream(); } - return entry.getFileSystem().openOutput(file, size); + return entry.getFileSystem().openOutput(file, size); }, FileOpener::openInTextEditor); } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserFilterComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserFilterComp.java index ed4725719..2aeb38bd5 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserFilterComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserFilterComp.java @@ -1,12 +1,12 @@ package io.xpipe.app.browser; -import atlantafx.base.theme.Styles; import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.impl.TextFieldComp; import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.util.InputHelper; + import javafx.beans.property.Property; import javafx.beans.property.SimpleBooleanProperty; import javafx.geometry.Pos; @@ -16,6 +16,8 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javafx.scene.input.KeyCombination; import javafx.scene.layout.HBox; + +import atlantafx.base.theme.Styles; import org.kordamp.ikonli.javafx.FontIcon; public class BrowserFilterComp extends Comp { @@ -40,7 +42,8 @@ public class BrowserFilterComp extends Comp { button.fire(); keyEvent.consume(); }); - new TooltipAugment<>("app.search", new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN)).augment(button); + new TooltipAugment<>("app.search", new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN)) + .augment(button); text.focusedProperty().addListener((observable, oldValue, newValue) -> { if (!newValue && filterString.getValue() == null) { if (button.isFocused()) { @@ -110,7 +113,7 @@ public class BrowserFilterComp extends Comp { button.minWidthProperty().bind(text.heightProperty()); button.maxHeightProperty().bind(text.heightProperty()); button.maxWidthProperty().bind(text.heightProperty()); - return new Structure(box, (TextField) text, button); + return new Structure(box, text, button); } public record Structure(HBox box, TextField textField, Button toggleButton) implements CompStructure { diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserNavBar.java b/app/src/main/java/io/xpipe/app/browser/BrowserNavBar.java index f43f8b984..9dad14518 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserNavBar.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserNavBar.java @@ -1,6 +1,5 @@ package io.xpipe.app.browser; -import atlantafx.base.theme.Styles; import io.xpipe.app.browser.file.BrowserContextMenu; import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.browser.icon.FileIconManager; @@ -13,6 +12,7 @@ import io.xpipe.app.fxcomps.impl.TextFieldComp; import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.util.BooleanScope; import io.xpipe.app.util.ThreadHelper; + import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleStringProperty; @@ -28,6 +28,8 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; + +import atlantafx.base.theme.Styles; import org.kordamp.ikonli.javafx.FontIcon; public class BrowserNavBar extends Comp { @@ -94,8 +96,8 @@ public class BrowserNavBar extends Comp { homeButton.getStyleClass().add(Styles.LEFT_PILL); homeButton.getStyleClass().add("path-graphic-button"); new ContextMenuAugment<>(event -> event.getButton() == MouseButton.PRIMARY, null, () -> { - return model.getInOverview().get() ? null : new BrowserContextMenu(model, null, false); - }) + return model.getInOverview().get() ? null : new BrowserContextMenu(model, null, false); + }) .augment(new SimpleCompStructure<>(homeButton)); var historyButton = new Button(null, new FontIcon("mdi2h-history")); @@ -103,7 +105,8 @@ public class BrowserNavBar extends Comp { historyButton.getStyleClass().add(Styles.RIGHT_PILL); new ContextMenuAugment<>(event -> event.getButton() == MouseButton.PRIMARY, null, this::createContextMenu) .augment(new SimpleCompStructure<>(historyButton)); - new TooltipAugment<>("history", new KeyCodeCombination(KeyCode.H, KeyCombination.ALT_DOWN)).augment(historyButton); + new TooltipAugment<>("history", new KeyCodeCombination(KeyCode.H, KeyCombination.ALT_DOWN)) + .augment(historyButton); var breadcrumbs = new BrowserBreadcrumbBar(model).grow(false, true); @@ -114,7 +117,8 @@ public class BrowserNavBar extends Comp { event.consume(); }); breadcrumbsRegion.setFocusTraversable(false); - breadcrumbsRegion.visibleProperty() + breadcrumbsRegion + .visibleProperty() .bind(Bindings.createBooleanBinding( () -> { return !pathRegion.isFocused() diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserOverviewComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserOverviewComp.java index 7d83c935e..6931e634a 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserOverviewComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserOverviewComp.java @@ -11,11 +11,13 @@ import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.process.ShellControl; import io.xpipe.core.store.FileSystem; + import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; + import lombok.SneakyThrows; import java.util.List; @@ -68,8 +70,9 @@ public class BrowserOverviewComp extends SimpleComp { var rootsOverview = new BrowserFileOverviewComp(model, FXCollections.observableArrayList(roots), false); var rootsPane = new SimpleTitledPaneComp(AppI18n.observable("roots"), rootsOverview); - var recent = new DerivedObservableList<>(model.getSavedState().getRecentDirectories(), true).mapped( - s -> FileSystem.FileEntry.ofDirectory(model.getFileSystem(), s.getDirectory())).getList(); + var recent = new DerivedObservableList<>(model.getSavedState().getRecentDirectories(), true) + .mapped(s -> FileSystem.FileEntry.ofDirectory(model.getFileSystem(), s.getDirectory())) + .getList(); var recentOverview = new BrowserFileOverviewComp(model, recent, true); var recentPane = new SimpleTitledPaneComp(AppI18n.observable("recent"), recentOverview); diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserSelectionListComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserSelectionListComp.java index 02edb3d4e..decdb829b 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserSelectionListComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserSelectionListComp.java @@ -8,6 +8,7 @@ import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.impl.PrettyImageHelper; import io.xpipe.app.fxcomps.util.PlatformThread; + import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableValue; import javafx.collections.ObservableList; @@ -18,6 +19,7 @@ import javafx.scene.control.OverrunStyle; import javafx.scene.image.Image; import javafx.scene.layout.Region; import javafx.scene.paint.Color; + import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Value; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java index a323b7fad..55f1a8871 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserStatusBarComp.java @@ -1,6 +1,5 @@ package io.xpipe.app.browser; -import atlantafx.base.controls.Spacer; import io.xpipe.app.browser.file.BrowserContextMenu; import io.xpipe.app.browser.file.BrowserFileListCompEntry; import io.xpipe.app.browser.fs.OpenFileSystemModel; @@ -12,10 +11,13 @@ import io.xpipe.app.fxcomps.augment.ContextMenuAugment; import io.xpipe.app.fxcomps.impl.LabelComp; import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.util.HumanReadableFormat; + import javafx.beans.binding.Bindings; import javafx.scene.control.ToolBar; import javafx.scene.input.MouseButton; import javafx.scene.layout.Region; + +import atlantafx.base.controls.Spacer; import lombok.EqualsAndHashCode; import lombok.Value; @@ -57,8 +59,10 @@ public class BrowserStatusBarComp extends SimpleComp { var transferred = HumanReadableFormat.progressByteCount(p.getTransferred()); var all = HumanReadableFormat.byteCount(p.getTotal()); var name = (p.getName() != null ? " @ " + p.getName() + " " : ""); - var time = p.getTotal() > 50_000_000 && p.elapsedTime().compareTo(Duration.of(200, ChronoUnit.MILLIS)) > 0 ? " | " - + HumanReadableFormat.duration(p.expectedTimeRemaining()) : " | ..."; + var time = + p.getTotal() > 50_000_000 && p.elapsedTime().compareTo(Duration.of(200, ChronoUnit.MILLIS)) > 0 + ? " | " + HumanReadableFormat.duration(p.expectedTimeRemaining()) + : " | ..."; return transferred + " / " + all + name + time; } }); diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java index 553aae3d0..c31dab7f7 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserTransferComp.java @@ -10,6 +10,7 @@ import io.xpipe.app.fxcomps.augment.DragOverPseudoClassAugment; import io.xpipe.app.fxcomps.impl.*; import io.xpipe.app.fxcomps.util.DerivedObservableList; import io.xpipe.app.fxcomps.util.PlatformThread; + import javafx.beans.binding.Bindings; import javafx.collections.FXCollections; import javafx.geometry.Insets; @@ -18,6 +19,7 @@ import javafx.scene.input.Dragboard; import javafx.scene.input.TransferMode; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Region; + import org.kordamp.ikonli.javafx.FontIcon; import java.io.File; @@ -46,7 +48,9 @@ public class BrowserTransferComp extends SimpleComp { var backgroundStack = new StackComp(List.of(background)).grow(true, true).styleClass("download-background"); - var binding = new DerivedObservableList<>(syncItems, true).mapped(item -> item.getBrowserEntry()).getList(); + var binding = new DerivedObservableList<>(syncItems, true) + .mapped(item -> item.getBrowserEntry()) + .getList(); var list = new BrowserSelectionListComp( binding, entry -> Bindings.createStringBinding( @@ -57,9 +61,15 @@ public class BrowserTransferComp extends SimpleComp { if (sourceItem.isEmpty()) { return "?"; } - var name = entry.getModel() == null || sourceItem.get().downloadFinished().get() - ? "Local" - : entry.getModel().getFileSystemModel().getName(); + var name = entry.getModel() == null + || sourceItem + .get() + .downloadFinished() + .get() + ? "Local" + : entry.getModel() + .getFileSystemModel() + .getName(); return entry.getFileName() + " (" + name + ")"; }, syncAllDownloaded)) diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java b/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java index a7b174170..60c763cc1 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserTransferModel.java @@ -9,6 +9,7 @@ import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.util.BooleanScope; import io.xpipe.app.util.ShellTemp; + import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; import javafx.beans.property.Property; @@ -17,6 +18,7 @@ import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableBooleanValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; + import lombok.Value; import org.apache.commons.io.FileUtils; @@ -95,7 +97,8 @@ public class BrowserTransferModel { } var item = new Item(null, name, entry, path); - item.progress.setValue(BrowserTransferProgress.finished(entry.getFileName(), entry.getRawFileEntry().getSize())); + item.progress.setValue(BrowserTransferProgress.finished( + entry.getFileName(), entry.getRawFileEntry().getSize())); items.add(item); } } catch (Exception ex) { @@ -155,8 +158,7 @@ public class BrowserTransferModel { Path localFile; Property progress; - public Item( - OpenFileSystemModel openFileSystemModel, String name, BrowserEntry browserEntry, Path localFile) { + public Item(OpenFileSystemModel openFileSystemModel, String name, BrowserEntry browserEntry, Path localFile) { this.openFileSystemModel = openFileSystemModel; this.name = name; this.browserEntry = browserEntry; diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserTransferProgress.java b/app/src/main/java/io/xpipe/app/browser/BrowserTransferProgress.java index 36d7e2a87..5deb42634 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserTransferProgress.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserTransferProgress.java @@ -32,7 +32,7 @@ public class BrowserTransferProgress { public Duration elapsedTime() { var now = Instant.now(); - var elapsed = Duration.between(start,now); + var elapsed = Duration.between(start, now); return elapsed; } diff --git a/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java b/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java index e0f71d5c3..5a8cd7afc 100644 --- a/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java +++ b/app/src/main/java/io/xpipe/app/browser/BrowserWelcomeComp.java @@ -1,7 +1,5 @@ package io.xpipe.app.browser; -import atlantafx.base.controls.Spacer; -import atlantafx.base.theme.Styles; import io.xpipe.app.browser.session.BrowserSessionModel; import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.comp.base.ListBoxViewComp; @@ -18,6 +16,7 @@ import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.DerivedObservableList; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.util.ThreadHelper; + import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -31,6 +30,9 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; +import atlantafx.base.controls.Spacer; +import atlantafx.base.theme.Styles; + import java.util.List; public class BrowserWelcomeComp extends SimpleComp { @@ -65,18 +67,20 @@ public class BrowserWelcomeComp extends SimpleComp { return new VBox(hbox); } - var list = new DerivedObservableList<>(state.getEntries(), true).filtered(e -> { - var entry = DataStorage.get().getStoreEntryIfPresent(e.getUuid()); - if (entry.isEmpty()) { - return false; - } + var list = new DerivedObservableList<>(state.getEntries(), true) + .filtered(e -> { + var entry = DataStorage.get().getStoreEntryIfPresent(e.getUuid()); + if (entry.isEmpty()) { + return false; + } - if (!entry.get().getValidity().isUsable()) { - return false; - } + if (!entry.get().getValidity().isUsable()) { + return false; + } - return true; - }).getList(); + return true; + }) + .getList(); var empty = Bindings.createBooleanBinding(() -> list.isEmpty(), list); var headerBinding = BindingsHelper.flatMap(empty, b -> { diff --git a/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java b/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java index c9e65f2d8..91cc5adcd 100644 --- a/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java +++ b/app/src/main/java/io/xpipe/app/browser/action/LeafAction.java @@ -7,10 +7,12 @@ import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.util.BooleanScope; import io.xpipe.app.util.LicenseProvider; import io.xpipe.app.util.ThreadHelper; + import javafx.scene.control.Button; import javafx.scene.control.MenuItem; import javafx.scene.input.KeyEvent; import javafx.scene.layout.Region; + import org.kordamp.ikonli.javafx.FontIcon; import java.util.List; diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserContextMenu.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserContextMenu.java index f6df6d318..6e33b03b8 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserContextMenu.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserContextMenu.java @@ -33,9 +33,8 @@ public final class BrowserContextMenu extends ContextMenu { private static List resolveIfNeeded(BrowserAction action, List selected) { return action.automaticallyResolveLinks() ? selected.stream() - .map(browserEntry -> new BrowserEntry( - browserEntry.getRawFileEntry().resolved(), - browserEntry.getModel())) + .map(browserEntry -> + new BrowserEntry(browserEntry.getRawFileEntry().resolved(), browserEntry.getModel())) .toList() : selected; } diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java index 7a7ef6d08..efec57ebb 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListComp.java @@ -1,7 +1,5 @@ package io.xpipe.app.browser.file; -import atlantafx.base.controls.Spacer; -import atlantafx.base.theme.Styles; import io.xpipe.app.browser.action.BrowserAction; import io.xpipe.app.comp.base.LazyTextFieldComp; import io.xpipe.app.core.AppI18n; @@ -15,6 +13,7 @@ import io.xpipe.core.process.OsType; import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileNames; import io.xpipe.core.store.FileSystem; + import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.*; @@ -38,6 +37,9 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.Region; +import atlantafx.base.controls.Spacer; +import atlantafx.base.theme.Styles; + import java.time.Instant; import java.time.ZoneId; import java.util.ArrayList; @@ -159,16 +161,18 @@ public final class BrowserFileListComp extends SimpleComp { private void prepareTableShortcuts(TableView table) { table.setOnKeyPressed(event -> { var selected = fileList.getSelection(); - var action = BrowserAction.getFlattened(fileList.getFileSystemModel(), selected).stream().filter( - browserAction -> browserAction.isApplicable(fileList.getFileSystemModel(), selected) && - browserAction.isActive(fileList.getFileSystemModel(), selected)).filter( - browserAction -> browserAction.getShortcut() != null).filter(browserAction -> browserAction.getShortcut().match(event)).findAny(); + var action = BrowserAction.getFlattened(fileList.getFileSystemModel(), selected).stream() + .filter(browserAction -> browserAction.isApplicable(fileList.getFileSystemModel(), selected) + && browserAction.isActive(fileList.getFileSystemModel(), selected)) + .filter(browserAction -> browserAction.getShortcut() != null) + .filter(browserAction -> browserAction.getShortcut().match(event)) + .findAny(); action.ifPresent(browserAction -> { - ThreadHelper.runFailableAsync(() -> { - browserAction.execute(fileList.getFileSystemModel(), selected); - }); - event.consume(); - }); + ThreadHelper.runFailableAsync(() -> { + browserAction.execute(fileList.getFileSystemModel(), selected); + }); + event.consume(); + }); if (action.isPresent()) { return; } @@ -326,7 +330,9 @@ public final class BrowserFileListComp extends SimpleComp { Platform.runLater(() -> { var newItems = new ArrayList<>(fileList.getShown().getValue()); - var hasModifiedDate = newItems.size() == 0 || newItems.stream().anyMatch(entry -> entry.getRawFileEntry().getDate() != null); + var hasModifiedDate = newItems.size() == 0 + || newItems.stream() + .anyMatch(entry -> entry.getRawFileEntry().getDate() != null); if (!hasModifiedDate) { table.getColumns().remove(mtimeCol); } else { @@ -336,7 +342,10 @@ public final class BrowserFileListComp extends SimpleComp { } if (fileList.getFileSystemModel().getFileSystem() != null) { - var shell = fileList.getFileSystemModel().getFileSystem().getShell().orElseThrow(); + var shell = fileList.getFileSystemModel() + .getFileSystem() + .getShell() + .orElseThrow(); var hasAttributes = !OsType.WINDOWS.equals(shell.getOsType()); if (!hasAttributes) { table.getColumns().remove(modeCol); @@ -357,8 +366,10 @@ public final class BrowserFileListComp extends SimpleComp { if (!Objects.equals(lastDir.get(), currentDirectory)) { TableViewSkin skin = (TableViewSkin) table.getSkin(); if (skin != null) { - VirtualFlow flow = (VirtualFlow) skin.getChildren().get(1); - ScrollBar vbar = (ScrollBar) flow.getChildrenUnmodifiable().get(2); + VirtualFlow flow = + (VirtualFlow) skin.getChildren().get(1); + ScrollBar vbar = + (ScrollBar) flow.getChildrenUnmodifiable().get(2); if (vbar.getValue() != 0.0) { table.scrollTo(0); } @@ -541,7 +552,8 @@ public final class BrowserFileListComp extends SimpleComp { var selected = fileList.getSelection(); // Only show one menu across all selected entries if (selected.size() > 0 && selected.getLast() == getTableRow().getItem()) { - var cm = new BrowserContextMenu(fileList.getFileSystemModel(), getTableRow().getItem(), false); + var cm = new BrowserContextMenu( + fileList.getFileSystemModel(), getTableRow().getItem(), false); ContextMenuHelper.toggleShow(cm, this, Side.RIGHT); event.consume(); } diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListCompEntry.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListCompEntry.java index eb3457a1e..fec64696c 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListCompEntry.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListCompEntry.java @@ -3,11 +3,13 @@ package io.xpipe.app.browser.file; import io.xpipe.app.browser.BrowserClipboard; import io.xpipe.app.browser.BrowserSelectionListComp; import io.xpipe.core.store.FileKind; + import javafx.geometry.Point2D; import javafx.scene.Node; import javafx.scene.control.TableView; import javafx.scene.image.Image; import javafx.scene.input.*; + import lombok.Getter; import java.io.File; @@ -154,7 +156,13 @@ public class BrowserFileListCompEntry { var target = item != null && item.getRawFileEntry().getKind() == FileKind.DIRECTORY ? item.getRawFileEntry() : model.getFileSystemModel().getCurrentDirectory(); - model.getFileSystemModel().dropFilesIntoAsync(target, files.stream().map(browserEntry -> browserEntry.getRawFileEntry()).toList(), db.getMode()); + model.getFileSystemModel() + .dropFilesIntoAsync( + target, + files.stream() + .map(browserEntry -> browserEntry.getRawFileEntry()) + .toList(), + db.getMode()); event.setDropCompleted(true); event.consume(); } @@ -180,7 +188,10 @@ public class BrowserFileListCompEntry { var selected = model.getSelection(); Dragboard db = row.startDragAndDrop(TransferMode.COPY); - db.setContent(BrowserClipboard.startDrag(model.getFileSystemModel().getCurrentDirectory(), selected, event.isAltDown() ? BrowserFileTransferMode.MOVE : BrowserFileTransferMode.NORMAL)); + db.setContent(BrowserClipboard.startDrag( + model.getFileSystemModel().getCurrentDirectory(), + selected, + event.isAltDown() ? BrowserFileTransferMode.MOVE : BrowserFileTransferMode.NORMAL)); Image image = BrowserSelectionListComp.snapshot(selected); db.setDragView(image, -20, 15); diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListModel.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListModel.java index 33fc472af..13ccd86b1 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListModel.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileListModel.java @@ -5,12 +5,14 @@ import io.xpipe.app.issue.ErrorEvent; import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileNames; import io.xpipe.core.store.FileSystem; + import javafx.beans.property.Property; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; + import lombok.Getter; import java.util.ArrayList; @@ -54,7 +56,8 @@ public final class BrowserFileListModel { public void setAll(Stream newFiles) { try (var s = newFiles) { - var l = s.filter(entry -> entry != null).map(entry -> new BrowserEntry(entry, this)) + var l = s.filter(entry -> entry != null) + .map(entry -> new BrowserEntry(entry, this)) .toList(); all.setValue(l); refreshShown(); @@ -90,9 +93,7 @@ public final class BrowserFileListModel { path -> path.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY); var comp = comparatorProperty.getValue(); - Comparator us = comp != null - ? dirsFirst.thenComparing(comp) - : dirsFirst; + Comparator us = comp != null ? dirsFirst.thenComparing(comp) : dirsFirst; return us; } @@ -120,7 +121,11 @@ public final class BrowserFileListModel { try { fileSystemModel.getFileSystem().move(fullPath, newFullPath); fileSystemModel.refresh(); - var b = all.getValue().stream().filter(browserEntry -> browserEntry.getRawFileEntry().getPath().equals(newFullPath)).findFirst().orElse(old); + var b = all.getValue().stream() + .filter(browserEntry -> + browserEntry.getRawFileEntry().getPath().equals(newFullPath)) + .findFirst() + .orElse(old); return b; } catch (Exception e) { ErrorEvent.fromThrowable(e).handle(); diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java index 863a80d30..b451f16c1 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileOverviewComp.java @@ -36,8 +36,7 @@ public class BrowserFileOverviewComp extends SimpleComp { var icon = BrowserIcons.createIcon(entry); var graphic = new HorizontalComp(List.of( icon, - new BrowserQuickAccessButtonComp( - () -> new BrowserEntry(entry, model.getFileList()), model))); + new BrowserQuickAccessButtonComp(() -> new BrowserEntry(entry, model.getFileList()), model))); var l = new Button(entry.getPath(), graphic.createRegion()); l.setGraphicTextGap(1); l.setOnAction(event -> { diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileTransferMode.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileTransferMode.java index a01cd5b4f..867d8b0fc 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileTransferMode.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileTransferMode.java @@ -1,7 +1,6 @@ package io.xpipe.app.browser.file; public enum BrowserFileTransferMode { - NORMAL, COPY, MOVE diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileTransferOperation.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileTransferOperation.java index 0cfc72260..95814d77b 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserFileTransferOperation.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserFileTransferOperation.java @@ -28,9 +28,12 @@ public class BrowserFileTransferOperation { BrowserAlerts.FileConflictChoice lastConflictChoice; - public BrowserFileTransferOperation(FileSystem.FileEntry target, List files, BrowserFileTransferMode transferMode, boolean checkConflicts, - Consumer progress - ) { + public BrowserFileTransferOperation( + FileSystem.FileEntry target, + List files, + BrowserFileTransferMode transferMode, + boolean checkConflicts, + Consumer progress) { this.target = target; this.files = files; this.transferMode = transferMode; @@ -38,7 +41,12 @@ public class BrowserFileTransferOperation { this.progress = progress; } - public static BrowserFileTransferOperation ofLocal(FileSystem.FileEntry target, List files, BrowserFileTransferMode transferMode, boolean checkConflicts, Consumer progress) { + public static BrowserFileTransferOperation ofLocal( + FileSystem.FileEntry target, + List files, + BrowserFileTransferMode transferMode, + boolean checkConflicts, + Consumer progress) { var entries = files.stream() .map(path -> { if (!Files.exists(path)) { @@ -60,11 +68,7 @@ public class BrowserFileTransferOperation { this.progress.accept(progress); } - private boolean handleChoice( - FileSystem fileSystem, - String target, - boolean multiple) - throws Exception { + private boolean handleChoice(FileSystem fileSystem, String target, boolean multiple) throws Exception { if (lastConflictChoice == BrowserAlerts.FileConflictChoice.CANCEL) { return false; } @@ -101,15 +105,15 @@ public class BrowserFileTransferOperation { return true; } - public void execute() - throws Exception { + public void execute() throws Exception { if (files.isEmpty()) { updateProgress(BrowserTransferProgress.empty()); return; } var same = files.getFirst().getFileSystem().equals(target.getFileSystem()); - var doesMove = transferMode == BrowserFileTransferMode.MOVE || (same && transferMode == BrowserFileTransferMode.NORMAL); + var doesMove = transferMode == BrowserFileTransferMode.MOVE + || (same && transferMode == BrowserFileTransferMode.NORMAL); if (doesMove) { if (!BrowserAlerts.showMoveAlert(files, target)) { return; @@ -132,8 +136,7 @@ public class BrowserFileTransferOperation { } } - private void handleSingleOnSameFileSystem(FileSystem.FileEntry source) - throws Exception { + private void handleSingleOnSameFileSystem(FileSystem.FileEntry source) throws Exception { // Prevent dropping directory into itself if (source.getPath().equals(target.getPath())) { return; @@ -163,8 +166,7 @@ public class BrowserFileTransferOperation { } } - private void handleSingleAcrossFileSystems(FileSystem.FileEntry source) - throws Exception { + private void handleSingleAcrossFileSystems(FileSystem.FileEntry source) throws Exception { if (target.getKind() != FileKind.DIRECTORY) { throw new IllegalStateException("Target " + target.getPath() + " is not a directory"); } @@ -214,9 +216,7 @@ public class BrowserFileTransferOperation { } else if (sourceFile.getKind() == FileKind.FILE) { if (checkConflicts && !handleChoice( - target.getFileSystem(), - targetFile, - files.size() > 1 || flatFiles.size() > 1)) { + target.getFileSystem(), targetFile, files.size() > 1 || flatFiles.size() > 1)) { continue; } diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessButtonComp.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessButtonComp.java index 629c094b7..77b756e1e 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessButtonComp.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessButtonComp.java @@ -4,6 +4,7 @@ import io.xpipe.app.browser.fs.OpenFileSystemModel; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.impl.IconButtonComp; import io.xpipe.app.util.InputHelper; + import javafx.scene.layout.Region; import java.util.function.Supplier; diff --git a/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java b/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java index d6ddae403..dc4f4b3f1 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java +++ b/app/src/main/java/io/xpipe/app/browser/file/BrowserQuickAccessContextMenu.java @@ -8,6 +8,7 @@ import io.xpipe.app.util.InputHelper; import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.store.FileKind; import io.xpipe.core.store.FileSystem; + import javafx.application.Platform; import javafx.beans.property.SimpleBooleanProperty; import javafx.geometry.Side; @@ -19,6 +20,7 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Region; + import lombok.Getter; import java.util.ArrayList; @@ -139,8 +141,10 @@ public class BrowserQuickAccessContextMenu extends ContextMenu { this.browserEntry = browserEntry; this.menu = new Menu( // Use original name, not the link target - browserEntry.getRawFileEntry().getName(), PrettyImageHelper.ofFixedRasterized( - FileIconManager.getFileIcon(browserEntry.getRawFileEntry(), false), 24, 24).createRegion()); + browserEntry.getRawFileEntry().getName(), + PrettyImageHelper.ofFixedRasterized( + FileIconManager.getFileIcon(browserEntry.getRawFileEntry(), false), 24, 24) + .createRegion()); createMenu(); addInputListeners(); } @@ -243,7 +247,8 @@ public class BrowserQuickAccessContextMenu extends ContextMenu { if (contextMenu != null) { contextMenu.addEventFilter(KeyEvent.KEY_PRESSED, event -> { keyBasedNavigation = true; - if (event.getCode().equals(KeyCode.SPACE) || event.getCode().equals(KeyCode.ENTER)) { + if (event.getCode().equals(KeyCode.SPACE) + || event.getCode().equals(KeyCode.ENTER)) { expandBrowserActionMenuKey = true; } else { expandBrowserActionMenuKey = false; diff --git a/app/src/main/java/io/xpipe/app/browser/file/FileSystemHelper.java b/app/src/main/java/io/xpipe/app/browser/file/FileSystemHelper.java index fd408e2ee..ee6931a43 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/FileSystemHelper.java +++ b/app/src/main/java/io/xpipe/app/browser/file/FileSystemHelper.java @@ -66,7 +66,8 @@ public class FileSystemHelper { } } - public static String resolveDirectoryPath(OpenFileSystemModel model, String path, boolean allowRewrite) throws Exception { + public static String resolveDirectoryPath(OpenFileSystemModel model, String path, boolean allowRewrite) + throws Exception { if (path == null) { return null; } @@ -97,7 +98,8 @@ public class FileSystemHelper { return FileNames.toDirectory(resolved); } - public static void validateDirectoryPath(OpenFileSystemModel model, String path, boolean verifyExists) throws Exception { + public static void validateDirectoryPath(OpenFileSystemModel model, String path, boolean verifyExists) + throws Exception { if (path == null) { return; } diff --git a/app/src/main/java/io/xpipe/app/browser/file/LocalFileSystem.java b/app/src/main/java/io/xpipe/app/browser/file/LocalFileSystem.java index 50650aadd..c3b9ccac4 100644 --- a/app/src/main/java/io/xpipe/app/browser/file/LocalFileSystem.java +++ b/app/src/main/java/io/xpipe/app/browser/file/LocalFileSystem.java @@ -36,6 +36,6 @@ public class LocalFileSystem { public static BrowserEntry getLocalBrowserEntry(Path file) throws Exception { var e = getLocalFileEntry(file); - return new BrowserEntry(e,null); + return new BrowserEntry(e, null); } } diff --git a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java index 8eba337c2..f1b5d36f6 100644 --- a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java +++ b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemComp.java @@ -1,6 +1,5 @@ package io.xpipe.app.browser.fs; -import atlantafx.base.controls.Spacer; import io.xpipe.app.browser.BrowserFilterComp; import io.xpipe.app.browser.BrowserNavBar; import io.xpipe.app.browser.BrowserOverviewComp; @@ -17,6 +16,7 @@ import io.xpipe.app.fxcomps.augment.ContextMenuAugment; import io.xpipe.app.fxcomps.impl.TooltipAugment; import io.xpipe.app.fxcomps.impl.VerticalComp; import io.xpipe.app.util.InputHelper; + import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.control.MenuButton; @@ -28,6 +28,8 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; + +import atlantafx.base.controls.Spacer; import org.kordamp.ikonli.javafx.FontIcon; import java.util.ArrayList; @@ -54,13 +56,15 @@ public class OpenFileSystemComp extends SimpleComp { var root = new VBox(); var overview = new Button(null, new FontIcon("mdi2m-monitor")); overview.setOnAction(e -> model.cdAsync(null)); - new TooltipAugment<>("overview", new KeyCodeCombination(KeyCode.HOME, KeyCombination.ALT_DOWN)).augment(overview); + new TooltipAugment<>("overview", new KeyCodeCombination(KeyCode.HOME, KeyCombination.ALT_DOWN)) + .augment(overview); overview.disableProperty().bind(model.getInOverview()); overview.setAccessibleText("System overview"); - InputHelper.onKeyCombination(root, new KeyCodeCombination(KeyCode.HOME, KeyCombination.ALT_DOWN), true, keyEvent -> { - overview.fire(); - keyEvent.consume(); - }); + InputHelper.onKeyCombination( + root, new KeyCodeCombination(KeyCode.HOME, KeyCombination.ALT_DOWN), true, keyEvent -> { + overview.fire(); + keyEvent.consume(); + }); var backBtn = BrowserAction.byId("back", model, List.of()).toButton(root, model, List.of()); var forthBtn = BrowserAction.byId("forward", model, List.of()).toButton(root, model, List.of()); @@ -95,12 +99,12 @@ public class OpenFileSystemComp extends SimpleComp { refreshBtn, terminalBtn, menuButton); - squaredSize(navBar.get(),overview,true); - squaredSize(navBar.get(),backBtn,true); - squaredSize(navBar.get(),forthBtn,true); - squaredSize(navBar.get(),refreshBtn,true); - squaredSize(navBar.get(),terminalBtn,true); - squaredSize(navBar.get(),menuButton,false); + squaredSize(navBar.get(), overview, true); + squaredSize(navBar.get(), backBtn, true); + squaredSize(navBar.get(), forthBtn, true); + squaredSize(navBar.get(), refreshBtn, true); + squaredSize(navBar.get(), terminalBtn, true); + squaredSize(navBar.get(), menuButton, false); var content = createFileListContent(); root.getChildren().addAll(topBar, content); @@ -111,26 +115,30 @@ public class OpenFileSystemComp extends SimpleComp { } }); - InputHelper.onKeyCombination(root, new KeyCodeCombination(KeyCode.F, KeyCombination.CONTROL_DOWN), true, keyEvent -> { - filter.toggleButton().fire(); - filter.textField().requestFocus(); - keyEvent.consume(); - }); - InputHelper.onKeyCombination(root, new KeyCodeCombination(KeyCode.L, KeyCombination.CONTROL_DOWN), true, keyEvent -> { - navBar.textField().requestFocus(); - keyEvent.consume(); - }); - InputHelper.onKeyCombination(root, new KeyCodeCombination(KeyCode.H, KeyCombination.ALT_DOWN), true, keyEvent -> { - navBar.historyButton().fire(); - keyEvent.consume(); - }); - InputHelper.onKeyCombination(root, new KeyCodeCombination(KeyCode.UP, KeyCombination.ALT_DOWN), true, keyEvent -> { - var p = model.getCurrentParentDirectory(); - if (p != null) { - model.cdAsync(p.getPath()); - } - keyEvent.consume(); - }); + InputHelper.onKeyCombination( + root, new KeyCodeCombination(KeyCode.F, KeyCombination.CONTROL_DOWN), true, keyEvent -> { + filter.toggleButton().fire(); + filter.textField().requestFocus(); + keyEvent.consume(); + }); + InputHelper.onKeyCombination( + root, new KeyCodeCombination(KeyCode.L, KeyCombination.CONTROL_DOWN), true, keyEvent -> { + navBar.textField().requestFocus(); + keyEvent.consume(); + }); + InputHelper.onKeyCombination( + root, new KeyCodeCombination(KeyCode.H, KeyCombination.ALT_DOWN), true, keyEvent -> { + navBar.historyButton().fire(); + keyEvent.consume(); + }); + InputHelper.onKeyCombination( + root, new KeyCodeCombination(KeyCode.UP, KeyCombination.ALT_DOWN), true, keyEvent -> { + var p = model.getCurrentParentDirectory(); + if (p != null) { + model.cdAsync(p.getPath()); + } + keyEvent.consume(); + }); return root; } diff --git a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java index ce47ba26d..e3bd9efd3 100644 --- a/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java +++ b/app/src/main/java/io/xpipe/app/browser/fs/OpenFileSystemModel.java @@ -24,8 +24,10 @@ import io.xpipe.core.process.ShellDialects; import io.xpipe.core.process.ShellOpenFunction; import io.xpipe.core.store.*; import io.xpipe.core.util.FailableConsumer; + import javafx.beans.binding.Bindings; import javafx.beans.property.*; + import lombok.Getter; import lombok.SneakyThrows; @@ -345,7 +347,8 @@ public final class OpenFileSystemModel extends BrowserSessionTab files, BrowserFileTransferMode mode - ) { + FileSystem.FileEntry target, List files, BrowserFileTransferMode mode) { // We don't have to do anything in this case if (files.isEmpty()) { return; @@ -367,7 +369,7 @@ public final class OpenFileSystemModel extends BrowserSessionTab> { .map(menuItem -> menuItem.getGraphic().visibleProperty()) .toList(); button.visibleProperty() - .bind(Bindings.createBooleanBinding(() -> { - return l.stream().anyMatch(booleanObservableValue -> booleanObservableValue.getValue()); - }, l.toArray(ObservableValue[]::new))); + .bind(Bindings.createBooleanBinding( + () -> { + return l.stream().anyMatch(booleanObservableValue -> booleanObservableValue.getValue()); + }, + l.toArray(ObservableValue[]::new))); var graphic = new FontIcon("mdi2c-chevron-double-down"); button.fontProperty().subscribe(c -> { diff --git a/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java b/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java index 0469ce596..5105b1a9e 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/IntegratedTextAreaComp.java @@ -1,11 +1,11 @@ package io.xpipe.app.comp.base; -import atlantafx.base.theme.Styles; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.impl.IconButtonComp; import io.xpipe.app.fxcomps.impl.TextAreaComp; import io.xpipe.app.util.FileOpener; + import javafx.application.Platform; import javafx.beans.property.Property; import javafx.beans.value.ObservableValue; @@ -13,6 +13,8 @@ import javafx.scene.control.TextArea; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; + +import atlantafx.base.theme.Styles; import lombok.Builder; import lombok.Value; @@ -50,21 +52,23 @@ public class IntegratedTextAreaComp extends Comp(new Comp() { - @Override - public TextAreaStructure createBase() { - var textArea = new TextAreaComp(value, lazy).createStructure(); - var copyButton = createOpenButton(); - var pane = new AnchorPane(copyButton); - pane.setPickOnBounds(false); - AnchorPane.setTopAnchor(copyButton, 10.0); - AnchorPane.setRightAnchor(copyButton, 10.0); + var fileDrop = new FileDropOverlayComp<>( + new Comp() { + @Override + public TextAreaStructure createBase() { + var textArea = new TextAreaComp(value, lazy).createStructure(); + var copyButton = createOpenButton(); + var pane = new AnchorPane(copyButton); + pane.setPickOnBounds(false); + AnchorPane.setTopAnchor(copyButton, 10.0); + AnchorPane.setRightAnchor(copyButton, 10.0); - var c = new StackPane(); - c.getChildren().addAll(textArea.get(), pane); - return new TextAreaStructure(c, textArea.getTextArea()); - } - }, paths -> value.setValue(Files.readString(paths.getFirst()))); + var c = new StackPane(); + c.getChildren().addAll(textArea.get(), pane); + return new TextAreaStructure(c, textArea.getTextArea()); + } + }, + paths -> value.setValue(Files.readString(paths.getFirst()))); var struc = fileDrop.createStructure(); return new Structure(struc.get(), struc.getCompStructure().getTextArea()); } diff --git a/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java b/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java index b64fcac05..fc7bdda06 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/ListBoxViewComp.java @@ -5,6 +5,7 @@ import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.SimpleCompStructure; import io.xpipe.app.fxcomps.util.DerivedObservableList; import io.xpipe.app.fxcomps.util.PlatformThread; + import javafx.application.Platform; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; diff --git a/app/src/main/java/io/xpipe/app/comp/base/MarkdownEditorComp.java b/app/src/main/java/io/xpipe/app/comp/base/MarkdownEditorComp.java index 2a0c4bb0b..5d94bec81 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/MarkdownEditorComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/MarkdownEditorComp.java @@ -1,10 +1,10 @@ package io.xpipe.app.comp.base; -import atlantafx.base.theme.Styles; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.impl.IconButtonComp; import io.xpipe.app.util.FileOpener; + import javafx.application.Platform; import javafx.beans.property.Property; import javafx.scene.control.Button; @@ -12,6 +12,8 @@ import javafx.scene.control.TextArea; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; + +import atlantafx.base.theme.Styles; import lombok.Builder; import lombok.Value; @@ -20,20 +22,15 @@ public class MarkdownEditorComp extends Comp { private final Property value; private final String identifier; - public MarkdownEditorComp( - Property value, String identifier) { + public MarkdownEditorComp(Property value, String identifier) { this.value = value; this.identifier = identifier; } private Button createOpenButton() { return new IconButtonComp( - "mdal-edit", - () -> FileOpener.openString( - identifier + ".md", - this, - value.getValue(), - (s) -> { + "mdal-edit", + () -> FileOpener.openString(identifier + ".md", this, value.getValue(), (s) -> { Platform.runLater(() -> value.setValue(s)); })) .styleClass("edit-button") diff --git a/app/src/main/java/io/xpipe/app/comp/base/ModalOverlayComp.java b/app/src/main/java/io/xpipe/app/comp/base/ModalOverlayComp.java index 405c20d36..56417598a 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/ModalOverlayComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/ModalOverlayComp.java @@ -1,13 +1,11 @@ package io.xpipe.app.comp.base; -import atlantafx.base.controls.ModalPane; -import atlantafx.base.layout.ModalBox; -import atlantafx.base.theme.Styles; import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.util.PlatformThread; + import javafx.application.Platform; import javafx.beans.property.Property; import javafx.geometry.Insets; @@ -19,6 +17,10 @@ import javafx.scene.input.KeyEvent; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; + +import atlantafx.base.controls.ModalPane; +import atlantafx.base.layout.ModalBox; +import atlantafx.base.theme.Styles; import lombok.Value; public class ModalOverlayComp extends SimpleComp { diff --git a/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java b/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java index abc5f00fd..641f22730 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/SideMenuBarComp.java @@ -159,7 +159,10 @@ public class SideMenuBarComp extends Comp> { } { - var b = new IconButtonComp("mdi2c-code-json", () -> Hyperlinks.open("http://localhost:" + AppPrefs.get().httpServerPort().getValue())) + var b = new IconButtonComp( + "mdi2c-code-json", + () -> Hyperlinks.open("http://localhost:" + + AppPrefs.get().httpServerPort().getValue())) .tooltipKey("api") .apply(simpleBorders) .accessibleTextKey("api"); diff --git a/app/src/main/java/io/xpipe/app/comp/base/StoreToggleComp.java b/app/src/main/java/io/xpipe/app/comp/base/StoreToggleComp.java index 210920b8c..502336500 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/StoreToggleComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/StoreToggleComp.java @@ -8,12 +8,14 @@ import io.xpipe.app.fxcomps.util.LabelGraphic; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.store.DataStore; + import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ObservableValue; import javafx.scene.layout.Region; + import lombok.AllArgsConstructor; import lombok.Setter; @@ -34,7 +36,11 @@ public class StoreToggleComp extends SimpleComp { private ObservableValue customVisibility = new SimpleBooleanProperty(true); public static StoreToggleComp simpleToggle( - String nameKey, ObservableValue graphic, StoreSection section, Function initial, BiConsumer setter) { + String nameKey, + ObservableValue graphic, + StoreSection section, + Function initial, + BiConsumer setter) { return new StoreToggleComp( nameKey, graphic, @@ -49,8 +55,9 @@ public class StoreToggleComp extends SimpleComp { public static StoreToggleComp enableToggle( String nameKey, StoreSection section, Function initial, BiConsumer setter) { var val = new SimpleBooleanProperty(); - ObservableValue g = val.map(aBoolean -> aBoolean ? - new LabelGraphic.IconGraphic("mdi2c-circle-slice-8") : new LabelGraphic.IconGraphic("mdi2p-power")); + ObservableValue g = val.map(aBoolean -> aBoolean + ? new LabelGraphic.IconGraphic("mdi2c-circle-slice-8") + : new LabelGraphic.IconGraphic("mdi2p-power")); var t = new StoreToggleComp( nameKey, g, @@ -68,17 +75,29 @@ public class StoreToggleComp extends SimpleComp { } public static StoreToggleComp childrenToggle( - String nameKey, boolean graphic, StoreSection section, Function initial, BiConsumer setter) { + String nameKey, + boolean graphic, + StoreSection section, + Function initial, + BiConsumer setter) { var val = new SimpleBooleanProperty(); - ObservableValue g = graphic ? val.map(aBoolean -> aBoolean ? - new LabelGraphic.IconGraphic("mdi2c-circle-slice-8") : new LabelGraphic.IconGraphic("mdi2c-circle-half-full")) : null; - var t = new StoreToggleComp(nameKey, g, section, - new SimpleBooleanProperty(initial.apply(section.getWrapper().getEntry().getStore().asNeeded())), v -> { - Platform.runLater(() -> { - setter.accept(section.getWrapper().getEntry().getStore().asNeeded(), v); - StoreViewState.get().toggleStoreListUpdate(); - }); - }); + ObservableValue g = graphic + ? val.map(aBoolean -> aBoolean + ? new LabelGraphic.IconGraphic("mdi2c-circle-slice-8") + : new LabelGraphic.IconGraphic("mdi2c-circle-half-full")) + : null; + var t = new StoreToggleComp( + nameKey, + g, + section, + new SimpleBooleanProperty( + initial.apply(section.getWrapper().getEntry().getStore().asNeeded())), + v -> { + Platform.runLater(() -> { + setter.accept(section.getWrapper().getEntry().getStore().asNeeded(), v); + StoreViewState.get().toggleStoreListUpdate(); + }); + }); t.tooltipKey("showAllChildren"); t.value.subscribe((newValue) -> { val.set(newValue); @@ -86,7 +105,12 @@ public class StoreToggleComp extends SimpleComp { return t; } - public StoreToggleComp(String nameKey, ObservableValue graphic, StoreSection section, boolean initial, Consumer onChange) { + public StoreToggleComp( + String nameKey, + ObservableValue graphic, + StoreSection section, + boolean initial, + Consumer onChange) { this.nameKey = nameKey; this.graphic = graphic; this.section = section; @@ -94,7 +118,12 @@ public class StoreToggleComp extends SimpleComp { this.onChange = onChange; } - public StoreToggleComp(String nameKey, ObservableValue graphic, StoreSection section, BooleanProperty initial, Consumer onChange) { + public StoreToggleComp( + String nameKey, + ObservableValue graphic, + StoreSection section, + BooleanProperty initial, + Consumer onChange) { this.nameKey = nameKey; this.graphic = graphic; this.section = section; diff --git a/app/src/main/java/io/xpipe/app/comp/base/ToggleSwitchComp.java b/app/src/main/java/io/xpipe/app/comp/base/ToggleSwitchComp.java index 94960c975..068de4aae 100644 --- a/app/src/main/java/io/xpipe/app/comp/base/ToggleSwitchComp.java +++ b/app/src/main/java/io/xpipe/app/comp/base/ToggleSwitchComp.java @@ -1,15 +1,17 @@ package io.xpipe.app.comp.base; -import atlantafx.base.controls.ToggleSwitch; import io.xpipe.app.fxcomps.SimpleComp; import io.xpipe.app.fxcomps.util.LabelGraphic; import io.xpipe.app.fxcomps.util.PlatformThread; + import javafx.beans.property.Property; import javafx.beans.value.ObservableValue; import javafx.css.PseudoClass; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.layout.Region; + +import atlantafx.base.controls.ToggleSwitch; import lombok.EqualsAndHashCode; import lombok.Value; @@ -44,8 +46,9 @@ public class ToggleSwitchComp extends SimpleComp { s.textProperty().bind(PlatformThread.sync(name)); } if (graphic != null) { - s.graphicProperty().bind(PlatformThread.sync(graphic.map(labelGraphic -> labelGraphic.createGraphicNode()))); - s.pseudoClassStateChanged(PseudoClass.getPseudoClass("has-graphic"),true); + s.graphicProperty() + .bind(PlatformThread.sync(graphic.map(labelGraphic -> labelGraphic.createGraphicNode()))); + s.pseudoClassStateChanged(PseudoClass.getPseudoClass("has-graphic"), true); } return s; } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreCreationMenu.java b/app/src/main/java/io/xpipe/app/comp/store/StoreCreationMenu.java index cbb597a5d..f5f0c40eb 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreCreationMenu.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreCreationMenu.java @@ -39,8 +39,7 @@ public class StoreCreationMenu { "addScript", "mdi2s-script-text-outline", DataStoreProvider.CreationCategory.SCRIPT, "script")); menu.getItems() - .add(category( - "addService", "mdi2c-cloud-braces", DataStoreProvider.CreationCategory.SERVICE, null)); + .add(category("addService", "mdi2c-cloud-braces", DataStoreProvider.CreationCategory.SERVICE, null)); menu.getItems() .add(category( diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java index 6cd55eba6..a2f4cc9f8 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryComp.java @@ -1,7 +1,5 @@ package io.xpipe.app.comp.store; -import atlantafx.base.layout.InputGroup; -import atlantafx.base.theme.Styles; import io.xpipe.app.comp.base.LoadingOverlayComp; import io.xpipe.app.core.*; import io.xpipe.app.ext.ActionProvider; @@ -22,6 +20,7 @@ import io.xpipe.app.storage.DataStorage; import io.xpipe.app.storage.DataStoreColor; import io.xpipe.app.update.XPipeDistributionType; import io.xpipe.app.util.*; + import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ObservableDoubleValue; @@ -34,6 +33,9 @@ import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; + +import atlantafx.base.layout.InputGroup; +import atlantafx.base.theme.Styles; import org.kordamp.ikonli.javafx.FontIcon; import java.nio.file.Files; @@ -207,9 +209,11 @@ public abstract class StoreEntryComp extends SimpleComp { protected Region createButtonBar() { var list = new DerivedObservableList<>(wrapper.getActionProviders(), false); var buttons = list.mapped(actionProvider -> { - var button = buildButton(actionProvider); - return button != null ? button.createRegion() : null; - }).filtered(region -> region != null).getList(); + var button = buildButton(actionProvider); + return button != null ? button.createRegion() : null; + }) + .filtered(region -> region != null) + .getList(); var ig = new InputGroup(); Runnable update = () -> { @@ -236,28 +240,31 @@ public abstract class StoreEntryComp extends SimpleComp { return null; } - var button = - new IconButtonComp(cs.getIcon(wrapper.getEntry().ref()), leaf != null ? () -> { - ThreadHelper.runFailableAsync(() -> { - wrapper.runAction(leaf.createAction(wrapper.getEntry().ref()), leaf.showBusy()); - }); - } : null); + var button = new IconButtonComp( + cs.getIcon(wrapper.getEntry().ref()), + leaf != null + ? () -> { + ThreadHelper.runFailableAsync(() -> { + wrapper.runAction( + leaf.createAction(wrapper.getEntry().ref()), leaf.showBusy()); + }); + } + : null); if (branch != null) { - button.apply(new ContextMenuAugment<>(mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY,keyEvent -> false,() -> { - var cm = ContextMenuHelper.create(); - branch.getChildren().forEach(childProvider -> { - var menu = buildMenuItemForAction(childProvider); - if (menu != null) { - cm.getItems().add(menu); - } - }); - return cm; - })); + button.apply(new ContextMenuAugment<>( + mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, keyEvent -> false, () -> { + var cm = ContextMenuHelper.create(); + branch.getChildren().forEach(childProvider -> { + var menu = buildMenuItemForAction(childProvider); + if (menu != null) { + cm.getItems().add(menu); + } + }); + return cm; + })); } - button.accessibleText( - cs.getName(wrapper.getEntry().ref()).getValue()); - button.apply(new TooltipAugment<>( - cs.getName(wrapper.getEntry().ref()), null)); + button.accessibleText(cs.getName(wrapper.getEntry().ref()).getValue()); + button.apply(new TooltipAugment<>(cs.getName(wrapper.getEntry().ref()), null)); return button; } @@ -284,7 +291,9 @@ public abstract class StoreEntryComp extends SimpleComp { continue; } - if (p.getLeafDataStoreCallSite() != null && p.getLeafDataStoreCallSite().isSystemAction() && !hasSep) { + if (p.getLeafDataStoreCallSite() != null + && p.getLeafDataStoreCallSite().isSystemAction() + && !hasSep) { if (contextMenu.getItems().size() > 0) { contextMenu.getItems().add(new SeparatorMenuItem()); } @@ -312,8 +321,8 @@ public abstract class StoreEntryComp extends SimpleComp { contextMenu.getItems().add(browse); var copyId = new MenuItem(AppI18n.get("copyId"), new FontIcon("mdi2c-content-copy")); - copyId.setOnAction( - event -> ClipboardHelper.copyText(wrapper.getEntry().getUuid().toString())); + copyId.setOnAction(event -> + ClipboardHelper.copyText(wrapper.getEntry().getUuid().toString())); contextMenu.getItems().add(copyId); } @@ -343,12 +352,16 @@ public abstract class StoreEntryComp extends SimpleComp { .getList() .forEach(storeCategoryWrapper -> { MenuItem m = new MenuItem(); - m.textProperty().setValue(" ".repeat(storeCategoryWrapper.getDepth()) + storeCategoryWrapper.getName().getValue()); + m.textProperty() + .setValue(" ".repeat(storeCategoryWrapper.getDepth()) + + storeCategoryWrapper.getName().getValue()); m.setOnAction(event -> { wrapper.moveTo(storeCategoryWrapper.getCategory()); event.consume(); }); - if (storeCategoryWrapper.getParent() == null || storeCategoryWrapper.equals(wrapper.getCategory().getValue())) { + if (storeCategoryWrapper.getParent() == null + || storeCategoryWrapper.equals( + wrapper.getCategory().getValue())) { m.setDisable(true); } @@ -386,10 +399,17 @@ public abstract class StoreEntryComp extends SimpleComp { section.get().getAllChildren().getList().forEach(other -> { var ow = other.getWrapper(); var op = ow.getEntry().getProvider(); - MenuItem m = new MenuItem(ow.getName().getValue(), - op != null ? PrettyImageHelper.ofFixedSizeSquare(op.getDisplayIconFileName(ow.getEntry().getStore()), - 16).createRegion() : null); - if (other.getWrapper().equals(wrapper) || ow.getEntry().getUuid().equals(wrapper.getEntry().getOrderBefore())) { + MenuItem m = new MenuItem( + ow.getName().getValue(), + op != null + ? PrettyImageHelper.ofFixedSizeSquare( + op.getDisplayIconFileName( + ow.getEntry().getStore()), + 16) + .createRegion() + : null); + if (other.getWrapper().equals(wrapper) + || ow.getEntry().getUuid().equals(wrapper.getEntry().getOrderBefore())) { m.setDisable(true); } m.setOnAction(event -> { @@ -436,9 +456,7 @@ public abstract class StoreEntryComp extends SimpleComp { : new MenuItem(null, new FontIcon(icon)); var proRequired = p.getProFeatureId() != null - && !LicenseProvider.get() - .getFeature(p.getProFeatureId()) - .isSupported(); + && !LicenseProvider.get().getFeature(p.getProFeatureId()).isSupported(); if (proRequired) { item.setDisable(true); item.textProperty().bind(Bindings.createStringBinding(() -> name.getValue() + " (Pro)", name)); @@ -448,7 +466,9 @@ public abstract class StoreEntryComp extends SimpleComp { Menu menu = item instanceof Menu m ? m : null; if (branch != null) { - var items = branch.getChildren().stream().map(c -> buildMenuItemForAction(c)).toList(); + var items = branch.getChildren().stream() + .map(c -> buildMenuItemForAction(c)) + .toList(); menu.getItems().addAll(items); return menu; } else if (leaf.canLinkTo()) { @@ -462,18 +482,16 @@ public abstract class StoreEntryComp extends SimpleComp { menu.getItems().add(run); var sc = new MenuItem(null, new FontIcon("mdi2c-code-greater-than")); - var url = "xpipe://action/" + p.getId() + "/" - + wrapper.getEntry().getUuid(); + var url = "xpipe://action/" + p.getId() + "/" + wrapper.getEntry().getUuid(); sc.textProperty().bind(AppI18n.observable("base.createShortcut")); sc.setOnAction(event -> { ThreadHelper.runFailableAsync(() -> { DesktopShortcuts.create( url, wrapper.nameProperty().getValue() + " (" - + p - .getLeafDataStoreCallSite() - .getName(wrapper.getEntry().ref()) - .getValue() + ")"); + + p.getLeafDataStoreCallSite() + .getName(wrapper.getEntry().ref()) + .getValue() + ")"); }); }); menu.getItems().add(sc); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java index ad7a40d9e..8fd934ac4 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListComp.java @@ -18,8 +18,14 @@ public class StoreEntryListComp extends SimpleComp { private Comp createList() { var content = new ListBoxViewComp<>( - StoreViewState.get().getCurrentTopLevelSection().getShownChildren().getList(), - StoreViewState.get().getCurrentTopLevelSection().getAllChildren().getList(), + StoreViewState.get() + .getCurrentTopLevelSection() + .getShownChildren() + .getList(), + StoreViewState.get() + .getCurrentTopLevelSection() + .getAllChildren() + .getList(), (StoreSection e) -> { var custom = StoreSection.customSection(e, true).hgrow(); return new HorizontalComp(List.of(Comp.hspacer(8), custom, Comp.hspacer(10))) @@ -50,16 +56,21 @@ public class StoreEntryListComp extends SimpleComp { var map = new LinkedHashMap, ObservableValue>(); map.put( createList(), - Bindings.not(Bindings.isEmpty( - StoreViewState.get().getCurrentTopLevelSection().getShownChildren().getList()))); + Bindings.not(Bindings.isEmpty(StoreViewState.get() + .getCurrentTopLevelSection() + .getShownChildren() + .getList()))); map.put(new StoreIntroComp(), showIntro); map.put( new StoreNotFoundComp(), Bindings.and( - Bindings.not(Bindings.isEmpty(StoreViewState.get().getAllEntries().getList())), - Bindings.isEmpty( - StoreViewState.get().getCurrentTopLevelSection().getShownChildren().getList()))); + Bindings.not(Bindings.isEmpty( + StoreViewState.get().getAllEntries().getList())), + Bindings.isEmpty(StoreViewState.get() + .getCurrentTopLevelSection() + .getShownChildren() + .getList()))); return new MultiContentComp(map).createRegion(); } } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListStatusComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListStatusComp.java index a1111478e..93f2655d4 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListStatusComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryListStatusComp.java @@ -10,6 +10,7 @@ import io.xpipe.app.fxcomps.impl.IconButtonComp; import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.util.ThreadHelper; import io.xpipe.core.process.OsType; + import javafx.beans.binding.Bindings; import javafx.beans.property.Property; import javafx.beans.property.SimpleObjectProperty; @@ -23,6 +24,7 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; import javafx.scene.text.TextAlignment; + import org.kordamp.ikonli.javafx.FontIcon; public class StoreEntryListStatusComp extends SimpleComp { @@ -55,17 +57,28 @@ public class StoreEntryListStatusComp extends SimpleComp { label.textProperty().bind(name); label.getStyleClass().add("name"); - var all = StoreViewState.get().getAllEntries().filtered( - storeEntryWrapper -> { - var rootCategory = storeEntryWrapper.getCategory().getValue().getRoot(); - var inRootCategory = StoreViewState.get().getActiveCategory().getValue().getRoot().equals(rootCategory); - // Sadly the all binding does not update when the individual visibility of entries changes - // But it is good enough. - var showProvider = !storeEntryWrapper.getEntry().getValidity().isUsable() || - storeEntryWrapper.getEntry().getProvider().shouldShow(storeEntryWrapper); - return inRootCategory && showProvider; - }, - StoreViewState.get().getActiveCategory()); + var all = StoreViewState.get() + .getAllEntries() + .filtered( + storeEntryWrapper -> { + var rootCategory = + storeEntryWrapper.getCategory().getValue().getRoot(); + var inRootCategory = StoreViewState.get() + .getActiveCategory() + .getValue() + .getRoot() + .equals(rootCategory); + // Sadly the all binding does not update when the individual visibility of entries changes + // But it is good enough. + var showProvider = + !storeEntryWrapper.getEntry().getValidity().isUsable() + || storeEntryWrapper + .getEntry() + .getProvider() + .shouldShow(storeEntryWrapper); + return inRootCategory && showProvider; + }, + StoreViewState.get().getActiveCategory()); var shownList = all.filtered( storeEntryWrapper -> { return storeEntryWrapper.matchesFilter( diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java index c548f5fdc..1519be859 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreEntryWrapper.java @@ -9,8 +9,10 @@ import io.xpipe.app.storage.DataStoreCategory; import io.xpipe.app.storage.DataStoreColor; import io.xpipe.app.storage.DataStoreEntry; import io.xpipe.app.util.ThreadHelper; + import javafx.beans.property.*; import javafx.collections.FXCollections; + import lombok.Getter; import java.time.Duration; @@ -26,7 +28,8 @@ public class StoreEntryWrapper { private final BooleanProperty disabled = new SimpleBooleanProperty(); private final BooleanProperty busy = new SimpleBooleanProperty(); private final Property validity = new SimpleObjectProperty<>(); - private final ListProperty actionProviders = new SimpleListProperty<>(FXCollections.observableArrayList()); + private final ListProperty actionProviders = + new SimpleListProperty<>(FXCollections.observableArrayList()); private final Property defaultActionProvider = new SimpleObjectProperty<>(); private final BooleanProperty deletable = new SimpleBooleanProperty(); private final BooleanProperty expanded = new SimpleBooleanProperty(); @@ -50,8 +53,8 @@ public class StoreEntryWrapper { .getApplicableClass() .isAssignableFrom(entry.getStore().getClass()); }) - .sorted(Comparator.comparing( - actionProvider -> actionProvider.getLeafDataStoreCallSite().isSystemAction())) + .sorted(Comparator.comparing(actionProvider -> + actionProvider.getLeafDataStoreCallSite().isSystemAction())) .forEach(dataStoreActionProvider -> { actionProviders.add(dataStoreActionProvider); }); @@ -67,7 +70,7 @@ public class StoreEntryWrapper { public void orderBefore(StoreEntryWrapper other) { ThreadHelper.runAsync(() -> { - DataStorage.get().orderBefore(getEntry(),other.getEntry()); + DataStorage.get().orderBefore(getEntry(), other.getEntry()); }); } @@ -155,10 +158,11 @@ public class StoreEntryWrapper { defaultActionProvider.setValue(null); } else { var defaultProvider = ActionProvider.ALL.stream() - .filter(e -> entry.getStore() != null && e.getDefaultDataStoreCallSite() != null + .filter(e -> entry.getStore() != null + && e.getDefaultDataStoreCallSite() != null && e.getDefaultDataStoreCallSite() - .getApplicableClass() - .isAssignableFrom(entry.getStore().getClass()) + .getApplicableClass() + .isAssignableFrom(entry.getStore().getClass()) && e.getDefaultDataStoreCallSite().isApplicable(entry.ref())) .findFirst() .orElse(null); @@ -167,11 +171,10 @@ public class StoreEntryWrapper { try { var newProviders = ActionProvider.ALL.stream() .filter(dataStoreActionProvider -> { - return showActionProvider(dataStoreActionProvider); + return showActionProvider(dataStoreActionProvider); }) - .sorted(Comparator.comparing( - actionProvider -> actionProvider.getLeafDataStoreCallSite() != null && - actionProvider.getLeafDataStoreCallSite().isSystemAction())) + .sorted(Comparator.comparing(actionProvider -> actionProvider.getLeafDataStoreCallSite() != null + && actionProvider.getLeafDataStoreCallSite().isSystemAction())) .toList(); if (!actionProviders.equals(newProviders)) { actionProviders.setAll(newProviders); @@ -186,14 +189,15 @@ public class StoreEntryWrapper { var leaf = p.getLeafDataStoreCallSite(); if (leaf != null) { return (entry.getValidity().isUsable() || (!leaf.requiresValidStore() && entry.getProvider() != null)) - && leaf.getApplicableClass().isAssignableFrom(entry.getStore().getClass()) - && leaf - .isApplicable(entry.ref()); + && leaf.getApplicableClass() + .isAssignableFrom(entry.getStore().getClass()) + && leaf.isApplicable(entry.ref()); } - var branch = p.getBranchDataStoreCallSite(); - if (branch != null && entry.getStore() != null && branch.getApplicableClass().isAssignableFrom(entry.getStore().getClass())) { + if (branch != null + && entry.getStore() != null + && branch.getApplicableClass().isAssignableFrom(entry.getStore().getClass())) { return branch.getChildren().stream().anyMatch(child -> { return showActionProvider(child); }); @@ -223,7 +227,7 @@ public class StoreEntryWrapper { entry.notifyUpdate(true, false); if (found != null) { var act = found.getDefaultDataStoreCallSite().createAction(entry.ref()); - runAction(act,found.getDefaultDataStoreCallSite().showBusy()); + runAction(act, found.getDefaultDataStoreCallSite().showBusy()); } else { entry.setExpanded(!entry.isExpanded()); } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java index 63ba318fb..53c10156e 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreIntroComp.java @@ -1,6 +1,5 @@ package io.xpipe.app.comp.store; -import atlantafx.base.theme.Styles; import io.xpipe.app.core.AppFont; import io.xpipe.app.core.AppI18n; import io.xpipe.app.fxcomps.SimpleComp; @@ -8,6 +7,7 @@ import io.xpipe.app.fxcomps.impl.PrettySvgComp; import io.xpipe.app.prefs.AppPrefs; import io.xpipe.app.storage.DataStorage; import io.xpipe.app.util.ScanAlert; + import javafx.beans.property.SimpleStringProperty; import javafx.geometry.Insets; import javafx.geometry.Pos; @@ -17,6 +17,8 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; + +import atlantafx.base.theme.Styles; import org.kordamp.ikonli.javafx.FontIcon; public class StoreIntroComp extends SimpleComp { @@ -58,7 +60,6 @@ public class StoreIntroComp extends SimpleComp { return v; } - private Region createImportIntro() { var title = new Label(); title.textProperty().bind(AppI18n.observable("importConnectionsTitle")); diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreLayoutComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreLayoutComp.java index 7ddbc96bc..85a43b6f0 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreLayoutComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreLayoutComp.java @@ -4,8 +4,8 @@ import io.xpipe.app.comp.base.SideSplitPaneComp; import io.xpipe.app.core.AppActionLinkDetector; import io.xpipe.app.core.AppLayoutModel; import io.xpipe.app.fxcomps.SimpleComp; - import io.xpipe.app.util.InputHelper; + import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javafx.scene.input.KeyCombination; @@ -24,10 +24,11 @@ public class StoreLayoutComp extends SimpleComp { struc.getLeft().setMinWidth(260); struc.getLeft().setMaxWidth(500); struc.get().getStyleClass().add("store-layout"); - InputHelper.onKeyCombination(struc.get(),new KeyCodeCombination(KeyCode.V, KeyCombination.SHORTCUT_DOWN), true, keyEvent -> { - AppActionLinkDetector.detectOnPaste(); - keyEvent.consume(); - }); + InputHelper.onKeyCombination( + struc.get(), new KeyCodeCombination(KeyCode.V, KeyCombination.SHORTCUT_DOWN), true, keyEvent -> { + AppActionLinkDetector.detectOnPaste(); + keyEvent.consume(); + }); return struc.get(); } } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreNotesComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreNotesComp.java index fe7949b20..f4453d6af 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreNotesComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreNotesComp.java @@ -1,6 +1,5 @@ package io.xpipe.app.comp.store; -import atlantafx.base.controls.Popover; import io.xpipe.app.comp.base.ButtonComp; import io.xpipe.app.comp.base.DialogComp; import io.xpipe.app.comp.base.MarkdownEditorComp; @@ -11,12 +10,15 @@ import io.xpipe.app.fxcomps.CompStructure; import io.xpipe.app.fxcomps.impl.IconButtonComp; import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.storage.DataStorage; + import javafx.application.Platform; import javafx.beans.property.Property; import javafx.beans.property.SimpleStringProperty; import javafx.event.ActionEvent; import javafx.scene.control.Button; +import atlantafx.base.controls.Popover; + import java.util.List; import java.util.concurrent.atomic.AtomicReference; @@ -24,7 +26,9 @@ public class StoreNotesComp extends Comp { private final StoreEntryWrapper wrapper; - public StoreNotesComp(StoreEntryWrapper wrapper) {this.wrapper = wrapper;} + public StoreNotesComp(StoreEntryWrapper wrapper) { + this.wrapper = wrapper; + } @Override public Structure createBase() { @@ -36,7 +40,8 @@ public class StoreNotesComp extends Comp { .styleClass("notes-button") .grow(false, true) .hide(BindingsHelper.map(n, s -> s.getCommited() == null && s.getCurrent() == null)) - .createStructure().get(); + .createStructure() + .get(); button.prefWidthProperty().bind(button.heightProperty()); var prop = new SimpleStringProperty(n.getValue().getCurrent()); @@ -73,12 +78,16 @@ public class StoreNotesComp extends Comp { private Popover createPopover(AtomicReference ref, Property prop) { var n = wrapper.getNotes(); - var md = new MarkdownEditorComp(prop, "notes-" + wrapper.getName().getValue()).prefWidth(600).prefHeight(600).createStructure(); + var md = new MarkdownEditorComp(prop, "notes-" + wrapper.getName().getValue()) + .prefWidth(600) + .prefHeight(600) + .createStructure(); var dialog = new DialogComp() { @Override protected void finish() { - n.setValue(new StoreNotes(n.getValue().getCurrent(), n.getValue().getCurrent())); + n.setValue( + new StoreNotes(n.getValue().getCurrent(), n.getValue().getCurrent())); ref.get().hide(); } @@ -90,8 +99,9 @@ public class StoreNotesComp extends Comp { @Override public Comp bottom() { return new ButtonComp(AppI18n.observable("delete"), () -> { - n.setValue(new StoreNotes(null, null)); - }).hide(BindingsHelper.map(n, v -> v.getCommited() == null)); + n.setValue(new StoreNotes(null, null)); + }) + .hide(BindingsHelper.map(n, v -> v.getCommited() == null)); } @Override @@ -114,7 +124,8 @@ public class StoreNotesComp extends Comp { popover.setTitle(wrapper.getName().getValue()); popover.showingProperty().addListener((observable, oldValue, newValue) -> { if (!newValue) { - n.setValue(new StoreNotes(n.getValue().getCommited(), n.getValue().getCommited())); + n.setValue( + new StoreNotes(n.getValue().getCommited(), n.getValue().getCommited())); DataStorage.get().saveAsync(); ref.set(null); } @@ -136,7 +147,6 @@ public class StoreNotesComp extends Comp { return popover; } - public record Structure(Popover popover, Button button) implements CompStructure