This commit is contained in:
crschnick
2025-03-05 19:17:40 +00:00
parent f93558f692
commit a0ebda03c0
52 changed files with 421 additions and 292 deletions
@@ -112,7 +112,8 @@ public class AppBeaconServer {
executor.shutdown();
try {
executor.awaitTermination(30, TimeUnit.SECONDS);
} catch (InterruptedException ignored) {}
} catch (InterruptedException ignored) {
}
}
private void initAuthSecret() throws IOException {
@@ -2,15 +2,10 @@ package io.xpipe.app.beacon.impl;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStorageQuery;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.beacon.api.ConnectionQueryExchange;
import com.sun.net.httpserver.HttpExchange;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public class ConnectionQueryExchangeImpl extends ConnectionQueryExchange {
@Override
@@ -1,8 +1,5 @@
package io.xpipe.app.beacon.impl;
import atlantafx.base.layout.ModalBox;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.app.comp.base.ModalOverlay;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.window.AppDialog;
import io.xpipe.app.ext.ShellStore;
@@ -14,6 +11,8 @@ import io.xpipe.beacon.BeaconClientException;
import io.xpipe.beacon.BeaconServerException;
import io.xpipe.beacon.api.TerminalExternalLaunchExchange;
import com.sun.net.httpserver.HttpExchange;
import java.util.List;
public class TerminalExternalLaunchExchangeImpl extends TerminalExternalLaunchExchange {
@@ -26,13 +25,15 @@ public class TerminalExternalLaunchExchangeImpl extends TerminalExternalLaunchEx
}
if (found.size() > 1) {
throw new BeaconServerException("Multiple connections found: " + found.stream().map(DataStoreEntry::getName).toList());
throw new BeaconServerException("Multiple connections found: "
+ found.stream().map(DataStoreEntry::getName).toList());
}
var e = found.getFirst();
var isShell = e.getStore() instanceof ShellStore;
if (!isShell) {
throw new BeaconClientException("Connection " + DataStorage.get().getStorePath(e).toString() + " is not a shell connection");
throw new BeaconClientException(
"Connection " + DataStorage.get().getStorePath(e).toString() + " is not a shell connection");
}
if (!checkPermission()) {
@@ -12,7 +12,6 @@ import java.nio.file.Path;
import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Timer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
@@ -437,7 +436,8 @@ public class BrowserFileTransferOperation {
outputStream.write(buffer, 0, read);
transferred.addAndGet(read);
updateProgress(new BrowserTransferProgress(sourceFile.getName(), transferred.get(), total.get(), start));
updateProgress(
new BrowserTransferProgress(sourceFile.getName(), transferred.get(), total.get(), start));
}
} catch (Exception ex) {
exception.set(ex);
@@ -4,7 +4,6 @@ import io.xpipe.app.browser.BrowserAbstractSessionModel;
import io.xpipe.app.browser.BrowserFullSessionModel;
import io.xpipe.app.browser.BrowserSessionTab;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.base.AppMainWindowContentComp;
import io.xpipe.app.comp.base.ModalOverlay;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppLayoutModel;
@@ -3,14 +3,13 @@ package io.xpipe.app.comp.base;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.CompStructure;
import io.xpipe.app.comp.SimpleCompStructure;
import io.xpipe.app.util.PlatformThread;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import java.util.List;
@@ -4,8 +4,8 @@ import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.CompStructure;
import io.xpipe.app.comp.SimpleCompStructure;
import io.xpipe.app.util.PlatformThread;
import io.xpipe.core.process.OsType;
import javafx.application.Platform;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleStringProperty;
@@ -4,12 +4,11 @@ import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.CompStructure;
import io.xpipe.app.comp.SimpleCompStructure;
import io.xpipe.app.util.PlatformThread;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.HBox;
import java.util.List;
@@ -8,7 +8,6 @@ import javafx.beans.binding.Bindings;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
@@ -13,8 +13,8 @@ import io.xpipe.app.storage.DataStoreCategory;
import io.xpipe.app.util.ClipboardHelper;
import io.xpipe.app.util.ContextMenuHelper;
import io.xpipe.app.util.LabelGraphic;
import io.xpipe.core.process.OsType;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
@@ -197,7 +197,8 @@ public class StoreCreationComp extends DialogComp {
if (e.getStore().equals(newE.getStore())) {
e.setName(newE.getName());
} else {
var madeValid = !e.getValidity().isUsable() && newE.getValidity().isUsable();
var madeValid = !e.getValidity().isUsable()
&& newE.getValidity().isUsable();
DataStorage.get().updateEntry(e, newE);
if (madeValid) {
StoreViewState.get().toggleStoreListUpdate();
@@ -423,14 +424,12 @@ public class StoreCreationComp extends DialogComp {
public Comp<?> bottom() {
var disable = Bindings.createBooleanBinding(
() -> {
return provider.getValue() == null
|| provider.getValue().getHelpLink() == null;
return provider.getValue() == null || provider.getValue().getHelpLink() == null;
},
provider);
return new ButtonComp(
AppI18n.observable("docs"), () -> {
return new ButtonComp(AppI18n.observable("docs"), () -> {
Hyperlinks.open(provider.getValue().getHelpLink());
})
})
.hide(disable)
.styleClass("button-comp");
}
@@ -1,20 +1,21 @@
package io.xpipe.app.comp.store;
import io.xpipe.app.comp.SimpleComp;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
public class StoreEntryBatchSelectComp extends SimpleComp {
private final StoreSection section;
public StoreEntryBatchSelectComp(StoreSection section) {this.section = section;}
public StoreEntryBatchSelectComp(StoreSection section) {
this.section = section;
}
@Override
protected Region createSimple() {
@@ -28,11 +29,13 @@ public class StoreEntryBatchSelectComp extends SimpleComp {
}
});
StoreViewState.get().getBatchModeSelection().getList().addListener((ListChangeListener<? super StoreEntryWrapper>) c -> {
Platform.runLater(() -> {
update(cb);
});
});
StoreViewState.get().getBatchModeSelection().getList().addListener((ListChangeListener<
? super StoreEntryWrapper>)
c -> {
Platform.runLater(() -> {
update(cb);
});
});
section.getShownChildren().getList().addListener((ListChangeListener<? super StoreSection>) c -> {
if (cb.isSelected()) {
StoreViewState.get().selectBatchMode(section);
@@ -59,8 +62,12 @@ public class StoreEntryBatchSelectComp extends SimpleComp {
return;
}
var count = section.getShownChildren().getList().stream().filter(c -> StoreViewState.get().getBatchModeSelection().getList().contains(c.getWrapper())).count();
checkBox.setIndeterminate(count > 0 && count != section.getShownChildren().getList().size());
var count = section.getShownChildren().getList().stream()
.filter(c ->
StoreViewState.get().getBatchModeSelection().getList().contains(c.getWrapper()))
.count();
checkBox.setIndeterminate(
count > 0 && count != section.getShownChildren().getList().size());
return;
}
}
@@ -2,7 +2,6 @@ package io.xpipe.app.comp.store;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.SimpleComp;
import io.xpipe.app.comp.base.HorizontalComp;
import io.xpipe.app.comp.base.ListBoxViewComp;
import io.xpipe.app.comp.base.MultiContentComp;
import io.xpipe.app.comp.base.VerticalComp;
@@ -1,6 +1,5 @@
package io.xpipe.app.comp.store;
import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.SimpleComp;
import io.xpipe.app.comp.base.CountComp;
@@ -14,8 +13,6 @@ 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;
import javafx.beans.property.SimpleStringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
@@ -27,6 +24,7 @@ import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.text.TextAlignment;
import atlantafx.base.theme.Styles;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.function.Function;
@@ -131,15 +129,13 @@ public class StoreEntryListOverviewComp extends SimpleComp {
return menu;
}
private Comp<?> createBatchModeButton() {
var batchMode = StoreViewState.get().getBatchMode();
var b = new IconButtonComp("mdi2l-layers", () -> {
batchMode.setValue(!batchMode.getValue());
});
b.apply(struc -> {
struc
.get()
struc.get()
.opacityProperty()
.bind(Bindings.createDoubleBinding(
() -> {
@@ -1,16 +1,15 @@
package io.xpipe.app.comp.store;
import atlantafx.base.theme.Styles;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.SimpleComp;
import io.xpipe.app.comp.augment.ContextMenuAugment;
import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.AppFontSizes;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.ActionProvider;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.util.*;
import io.xpipe.core.store.DataStore;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
@@ -22,6 +21,8 @@ import javafx.scene.control.MenuItem;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.Region;
import atlantafx.base.theme.Styles;
import java.util.ArrayList;
import java.util.List;
@@ -30,9 +31,17 @@ public class StoreEntryListStatusBarComp extends SimpleComp {
@Override
protected Region createSimple() {
var checkbox = new StoreEntryBatchSelectComp(StoreViewState.get().getCurrentTopLevelSection());
var l = new LabelComp(Bindings.createStringBinding(() -> {
return AppI18n.get("connectionsSelected", StoreViewState.get().getEffectiveBatchModeSelection().getList().size());
}, StoreViewState.get().getEffectiveBatchModeSelection().getList(), AppI18n.activeLanguage()));
var l = new LabelComp(Bindings.createStringBinding(
() -> {
return AppI18n.get(
"connectionsSelected",
StoreViewState.get()
.getEffectiveBatchModeSelection()
.getList()
.size());
},
StoreViewState.get().getEffectiveBatchModeSelection().getList(),
AppI18n.activeLanguage()));
l.minWidth(Region.USE_PREF_SIZE);
l.apply(struc -> {
struc.get().setAlignment(Pos.CENTER);
@@ -47,7 +56,8 @@ public class StoreEntryListStatusBarComp extends SimpleComp {
struc.get().prefWidthProperty().bind(struc.get().heightProperty());
struc.get().maxWidthProperty().bind(struc.get().heightProperty());
});
var bar = new HorizontalComp(List.of(checkbox, Comp.hspacer(12), l, Comp.hspacer(20), actions, Comp.hspacer(), Comp.hspacer(20), close));
var bar = new HorizontalComp(List.of(
checkbox, Comp.hspacer(12), l, Comp.hspacer(20), actions, Comp.hspacer(), Comp.hspacer(20), close));
bar.apply(struc -> {
struc.get().setFillHeight(true);
struc.get().setAlignment(Pos.CENTER_LEFT);
@@ -61,12 +71,15 @@ public class StoreEntryListStatusBarComp extends SimpleComp {
private ObservableList<Comp<?>> createActions() {
var l = new DerivedObservableList<ActionProvider>(FXCollections.observableArrayList(), true);
StoreViewState.get().getEffectiveBatchModeSelection().getList().addListener((ListChangeListener<? super StoreEntryWrapper>) c -> {
l.setContent(getCompatibleActionProviders());
});
StoreViewState.get().getEffectiveBatchModeSelection().getList().addListener((ListChangeListener<
? super StoreEntryWrapper>)
c -> {
l.setContent(getCompatibleActionProviders());
});
return l.<Comp<?>>mapped(actionProvider -> {
return buildButton(actionProvider);
}).getList();
return buildButton(actionProvider);
})
.getList();
}
private List<ActionProvider> getCompatibleActionProviders() {
@@ -77,22 +90,25 @@ public class StoreEntryListStatusBarComp extends SimpleComp {
var all = new ArrayList<>(ActionProvider.ALL);
for (StoreEntryWrapper w : l) {
var actions = ActionProvider.ALL.stream().filter(actionProvider -> {
var s = actionProvider.getBatchDataStoreCallSite();
if (s == null) {
return false;
}
var actions = ActionProvider.ALL.stream()
.filter(actionProvider -> {
var s = actionProvider.getBatchDataStoreCallSite();
if (s == null) {
return false;
}
if (!s.getApplicableClass().isAssignableFrom(w.getStore().getValue().getClass())) {
return false;
}
if (!s.getApplicableClass()
.isAssignableFrom(w.getStore().getValue().getClass())) {
return false;
}
if (!s.isApplicable(w.getEntry().ref())) {
return false;
}
if (!s.isApplicable(w.getEntry().ref())) {
return false;
}
return true;
}).toList();
return true;
})
.toList();
all.removeIf(actionProvider -> !actions.contains(actionProvider));
}
return all;
@@ -100,40 +116,43 @@ public class StoreEntryListStatusBarComp extends SimpleComp {
@SuppressWarnings("unchecked")
private <T extends DataStore> Comp<?> buildButton(ActionProvider p) {
ActionProvider.BatchDataStoreCallSite<T> s = (ActionProvider.BatchDataStoreCallSite<T>) p.getBatchDataStoreCallSite();
ActionProvider.BatchDataStoreCallSite<T> s =
(ActionProvider.BatchDataStoreCallSite<T>) p.getBatchDataStoreCallSite();
if (s == null) {
return Comp.empty();
}
List<DataStoreEntryRef<T>> childrenRefs = StoreViewState.get().getEffectiveBatchModeSelection().getList().stream().map(
storeEntryWrapper -> storeEntryWrapper.getEntry().<T>ref()).toList();
List<DataStoreEntryRef<T>> childrenRefs =
StoreViewState.get().getEffectiveBatchModeSelection().getList().stream()
.map(storeEntryWrapper -> storeEntryWrapper.getEntry().<T>ref())
.toList();
var batchActions = s.getChildren(childrenRefs);
var button = new ButtonComp(s.getName(), new SimpleObjectProperty<>(new LabelGraphic.IconGraphic(s.getIcon())), () -> {
if (batchActions.size() > 0) {
return;
}
var button = new ButtonComp(
s.getName(), new SimpleObjectProperty<>(new LabelGraphic.IconGraphic(s.getIcon())), () -> {
if (batchActions.size() > 0) {
return;
}
runActions(s);
});
runActions(s);
});
if (batchActions.size() > 0) {
button.apply(new ContextMenuAugment<>(
mouseEvent -> mouseEvent.getButton() == MouseButton.PRIMARY, keyEvent -> false, () -> {
var cm = ContextMenuHelper.create();
s.getChildren(childrenRefs)
.forEach(childProvider -> {
var cm = ContextMenuHelper.create();
s.getChildren(childrenRefs).forEach(childProvider -> {
var menu = buildMenuItemForAction(childrenRefs, childProvider);
cm.getItems().add(menu);
});
return cm;
}));
return cm;
}));
}
return button;
}
@SuppressWarnings("unchecked")
private <T extends DataStore> MenuItem buildMenuItemForAction(List<DataStoreEntryRef<T>> batch, ActionProvider a) {
ActionProvider.BatchDataStoreCallSite<T> s = (ActionProvider.BatchDataStoreCallSite<T>) a.getBatchDataStoreCallSite();
ActionProvider.BatchDataStoreCallSite<T> s =
(ActionProvider.BatchDataStoreCallSite<T>) a.getBatchDataStoreCallSite();
var name = s.getName();
var icon = s.getIcon();
var children = s.getChildren(batch);
@@ -165,7 +184,8 @@ public class StoreEntryListStatusBarComp extends SimpleComp {
@SuppressWarnings("unchecked")
private <T extends DataStore> void runActions(ActionProvider.BatchDataStoreCallSite<?> s) {
ThreadHelper.runFailableAsync(() -> {
var l = new ArrayList<>( StoreViewState.get().getEffectiveBatchModeSelection().getList());
var l = new ArrayList<>(
StoreViewState.get().getEffectiveBatchModeSelection().getList());
var mapped = l.stream().map(w -> w.getEntry().<T>ref()).toList();
var action = ((ActionProvider.BatchDataStoreCallSite<T>) s).createAction(mapped);
if (action != null) {
@@ -108,7 +108,8 @@ public class StoreIconChoiceComp extends SimpleComp {
private void updateData(TableView<List<SystemIcon>> table, String filterString) {
var stream = icons.stream()
.filter(systemIcon -> AppImages.hasNormalImage("icons/" + systemIcon.getSource().getId() + "/" + systemIcon.getId() + "-40.png"))
.filter(systemIcon -> AppImages.hasNormalImage(
"icons/" + systemIcon.getSource().getId() + "/" + systemIcon.getId() + "-40.png"))
.sorted(Comparator.comparing(systemIcon -> systemIcon.getId()));
if (filterString != null && !filterString.isBlank() && filterString.length() >= 2) {
stream = stream.filter(icon -> containsString(icon.getId(), filterString));
@@ -14,9 +14,8 @@ import io.xpipe.app.util.PlatformThread;
import javafx.application.Platform;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import lombok.Getter;
import java.util.*;
@@ -47,20 +46,24 @@ public class StoreViewState {
@Getter
private final BooleanProperty batchMode = new SimpleBooleanProperty(true);
@Getter
private final DerivedObservableList<StoreEntryWrapper> batchModeSelection = new DerivedObservableList<>(FXCollections.observableArrayList(), true);
@Getter
private final DerivedObservableList<StoreEntryWrapper> effectiveBatchModeSelection = batchModeSelection.filtered(storeEntryWrapper -> {
if (!storeEntryWrapper.getValidity().getValue().isUsable()) {
return false;
}
if (storeEntryWrapper.getEntry().getProvider().getUsageCategory() == DataStoreUsageCategory.GROUP) {
return false;
}
@Getter
private final DerivedObservableList<StoreEntryWrapper> batchModeSelection =
new DerivedObservableList<>(FXCollections.observableArrayList(), true);
return true;
});
@Getter
private final DerivedObservableList<StoreEntryWrapper> effectiveBatchModeSelection =
batchModeSelection.filtered(storeEntryWrapper -> {
if (!storeEntryWrapper.getValidity().getValue().isUsable()) {
return false;
}
if (storeEntryWrapper.getEntry().getProvider().getUsageCategory() == DataStoreUsageCategory.GROUP) {
return false;
}
return true;
});
@Getter
private StoreSection currentTopLevelSection;
@@ -106,7 +109,9 @@ public class StoreViewState {
if (wrapper != null && !batchModeSelection.getList().contains(wrapper)) {
batchModeSelection.getList().add(wrapper);
}
if (wrapper == null || (wrapper.getValidity().getValue().isUsable() && wrapper.getEntry().getProvider().getUsageCategory() == DataStoreUsageCategory.GROUP)) {
if (wrapper == null
|| (wrapper.getValidity().getValue().isUsable()
&& wrapper.getEntry().getProvider().getUsageCategory() == DataStoreUsageCategory.GROUP)) {
section.getShownChildren().getList().forEach(c -> selectBatchMode(c));
}
}
@@ -116,7 +121,9 @@ public class StoreViewState {
if (wrapper != null) {
batchModeSelection.getList().remove(wrapper);
}
if (wrapper == null || (wrapper.getValidity().getValue().isUsable() && wrapper.getEntry().getProvider().getUsageCategory() == DataStoreUsageCategory.GROUP)) {
if (wrapper == null
|| (wrapper.getValidity().getValue().isUsable()
&& wrapper.getEntry().getProvider().getUsageCategory() == DataStoreUsageCategory.GROUP)) {
section.getShownChildren().getList().forEach(c -> unselectBatchMode(c));
}
}
@@ -124,7 +131,9 @@ public class StoreViewState {
public boolean isSectionSelected(StoreSection section) {
if (section.getWrapper() == null) {
var batchSet = new HashSet<>(batchModeSelection.getList());
var childSet = section.getShownChildren().getList().stream().map(s -> s.getWrapper()).toList();
var childSet = section.getShownChildren().getList().stream()
.map(s -> s.getWrapper())
.toList();
return batchSet.containsAll(childSet);
}
@@ -128,11 +128,11 @@ public class AppLayoutModel {
null)));
if (AppDistributionType.get() != AppDistributionType.WEBTOP) {
l.add(new Entry(
AppI18n.observable("webtop"),
new LabelGraphic.IconGraphic("mdi2d-desktop-mac"),
null,
() -> Hyperlinks.open(Hyperlinks.GITHUB_WEBTOP),
null));
AppI18n.observable("webtop"),
new LabelGraphic.IconGraphic("mdi2d-desktop-mac"),
null,
() -> Hyperlinks.open(Hyperlinks.GITHUB_WEBTOP),
null));
}
return l;
}
@@ -104,7 +104,9 @@ public class AppTheme {
}
Platform.getPreferences().addListener((MapChangeListener<? super String, ? super Object>) change -> {
TrackEvent.withTrace("Platform preference changed").tag("change", change.toString()).handle();
TrackEvent.withTrace("Platform preference changed")
.tag("change", change.toString())
.handle();
});
Platform.getPreferences().addListener((MapChangeListener<? super String, ? super Object>) change -> {
@@ -140,10 +142,10 @@ public class AppTheme {
private static void updateThemeToThemeName(Object oldName, Object newName) {
if (OsType.getLocal() == OsType.LINUX && newName != null) {
var toDark = (oldName == null || !oldName.toString().contains("-dark")) &&
newName.toString().contains("-dark");
var toLight = (oldName == null || oldName.toString().contains("-dark")) &&
!newName.toString().contains("-dark");
var toDark = (oldName == null || !oldName.toString().contains("-dark"))
&& newName.toString().contains("-dark");
var toLight = (oldName == null || oldName.toString().contains("-dark"))
&& !newName.toString().contains("-dark");
if (toDark) {
updateThemeToColorScheme(ColorScheme.DARK);
} else if (toLight) {
@@ -172,8 +174,7 @@ public class AppTheme {
AppPrefs.get().theme.setValue(Theme.getDefaultDarkTheme());
}
if (colorScheme != ColorScheme.DARK
&& AppPrefs.get().theme().getValue().isDark()) {
if (colorScheme != ColorScheme.DARK && AppPrefs.get().theme().getValue().isDark()) {
AppPrefs.get().theme.setValue(Theme.getDefaultLightTheme());
}
}
@@ -256,7 +256,8 @@ public abstract class OperationMode {
var exec = XPipeInstallation.createExternalAsyncLaunchCommand(
loc,
XPipeDaemonMode.GUI,
"\"-Dio.xpipe.app.acceptEula=true\" \"-Dio.xpipe.app.dataDir=" + dataDir + "\" \"-Dio.xpipe.app.restarted=true\"",
"\"-Dio.xpipe.app.acceptEula=true\" \"-Dio.xpipe.app.dataDir=" + dataDir
+ "\" \"-Dio.xpipe.app.restarted=true\"",
true);
LocalShell.getShell().executeSimpleCommand(exec);
}
@@ -208,9 +208,12 @@ public interface ActionProvider {
}
default Action createAction(List<DataStoreEntryRef<T>> stores) {
var individual = stores.stream().map(ref -> {
return createAction(ref);
}).filter(action -> action != null).toList();
var individual = stores.stream()
.map(ref -> {
return createAction(ref);
})
.filter(action -> action != null)
.toList();
return new Action() {
@Override
public void execute() throws Exception {
@@ -22,7 +22,6 @@ import javax.imageio.ImageIO;
public class SystemIconCache {
private static enum ImageColorScheme {
TRANSPARENT,
MIXED,
LIGHT,
@@ -68,14 +67,17 @@ public class SystemIconCache {
continue;
}
if (scheme != ImageColorScheme.DARK || icon.getColorSchemeData() != SystemIconSourceFile.ColorSchemeData.DEFAULT) {
if (scheme != ImageColorScheme.DARK
|| icon.getColorSchemeData() != SystemIconSourceFile.ColorSchemeData.DEFAULT) {
continue;
}
var hasExplicitDark = e.getValue().getIcons().stream().anyMatch(
systemIconSourceFile -> systemIconSourceFile.getSource().equals(icon.getSource()) &&
systemIconSourceFile.getName().equals(icon.getName()) &&
systemIconSourceFile.getColorSchemeData() == SystemIconSourceFile.ColorSchemeData.DARK);
var hasExplicitDark = e.getValue().getIcons().stream()
.anyMatch(systemIconSourceFile ->
systemIconSourceFile.getSource().equals(icon.getSource())
&& systemIconSourceFile.getName().equals(icon.getName())
&& systemIconSourceFile.getColorSchemeData()
== SystemIconSourceFile.ColorSchemeData.DARK);
if (hasExplicitDark) {
continue;
}
@@ -130,7 +132,8 @@ public class SystemIconCache {
}
}
private static ImageColorScheme rasterizeSizesInverted(Path path, Path dir, String name, boolean dark) throws IOException {
private static ImageColorScheme rasterizeSizesInverted(Path path, Path dir, String name, boolean dark)
throws IOException {
try {
ImageColorScheme c = null;
for (var size : sizes) {
@@ -172,8 +175,8 @@ public class SystemIconCache {
return image;
}
private static BufferedImage write(Path dir, String name, boolean dark, int px, BufferedImage image) throws IOException {
private static BufferedImage write(Path dir, String name, boolean dark, int px, BufferedImage image)
throws IOException {
var out = dir.resolve(name + "-" + px + (dark ? "-dark" : "") + ".png");
ImageIO.write(image, "png", out.toFile());
return image;
@@ -183,12 +186,12 @@ public class SystemIconCache {
var buffer = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int clr = image.getRGB(x, y);
int alpha = (clr >> 24) & 0xff;
int red = (clr & 0x00ff0000) >> 16;
int green = (clr & 0x0000ff00) >> 8;
int blue = clr & 0x000000ff;
buffer.setRGB(x, y, new Color(255- red, 255- green, 255- blue, alpha).getRGB());
int clr = image.getRGB(x, y);
int alpha = (clr >> 24) & 0xff;
int red = (clr & 0x00ff0000) >> 16;
int green = (clr & 0x0000ff00) >> 8;
int blue = clr & 0x000000ff;
buffer.setRGB(x, y, new Color(255 - red, 255 - green, 255 - blue, alpha).getRGB());
}
}
return buffer;
@@ -199,11 +202,11 @@ public class SystemIconCache {
var mean = 0.0;
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int clr = image.getRGB(x, y);
int alpha = (clr >> 24) & 0xff;
int red = (clr & 0x00ff0000) >> 16;
int green = (clr & 0x0000ff00) >> 8;
int blue = clr & 0x000000ff;
int clr = image.getRGB(x, y);
int alpha = (clr >> 24) & 0xff;
int red = (clr & 0x00ff0000) >> 16;
int green = (clr & 0x0000ff00) >> 8;
int blue = clr & 0x000000ff;
if (alpha < 200) {
continue;
@@ -35,11 +35,12 @@ public class SystemIconSourceData {
.filter(path -> Files.isRegularFile(path))
.filter(path -> path.toString().endsWith(".svg"))
.map(path -> {
var name = FilenameUtils.getBaseName(path.getFileName().toString());
var cleanedName = name.replaceFirst("-light$", "").replaceFirst("-dark$", "");
var cleanedPath = path.getParent().resolve(cleanedName + ".svg");
return cleanedPath;
}).toList();
var name = FilenameUtils.getBaseName(path.getFileName().toString());
var cleanedName = name.replaceFirst("-light$", "").replaceFirst("-dark$", "");
var cleanedPath = path.getParent().resolve(cleanedName + ".svg");
return cleanedPath;
})
.toList();
for (var file : flatFiles) {
var name = FilenameUtils.getBaseName(file.getFileName().toString());
var displayName = name.toLowerCase(Locale.ROOT);
@@ -51,33 +52,40 @@ public class SystemIconSourceData {
var hasLightModeVariant = Files.exists(lightModeFile);
if (hasBaseVariant && hasDarkModeVariant) {
sourceFiles.add(new SystemIconSourceFile(source, displayName, baseFile, SystemIconSourceFile.ColorSchemeData.DEFAULT));
sourceFiles.add(new SystemIconSourceFile(source, displayName, darkModeFile, SystemIconSourceFile.ColorSchemeData.DARK));
sourceFiles.add(new SystemIconSourceFile(
source, displayName, baseFile, SystemIconSourceFile.ColorSchemeData.DEFAULT));
sourceFiles.add(new SystemIconSourceFile(
source, displayName, darkModeFile, SystemIconSourceFile.ColorSchemeData.DARK));
continue;
}
if (hasBaseVariant && hasLightModeVariant) {
sourceFiles.add(new SystemIconSourceFile(source, displayName, baseFile, SystemIconSourceFile.ColorSchemeData.DARK));
sourceFiles.add(new SystemIconSourceFile(source, displayName, lightModeFile, SystemIconSourceFile.ColorSchemeData.DEFAULT));
sourceFiles.add(new SystemIconSourceFile(
source, displayName, baseFile, SystemIconSourceFile.ColorSchemeData.DARK));
sourceFiles.add(new SystemIconSourceFile(
source, displayName, lightModeFile, SystemIconSourceFile.ColorSchemeData.DEFAULT));
continue;
}
if (!hasBaseVariant) {
if (hasLightModeVariant) {
sourceFiles.add(new SystemIconSourceFile(source, displayName, lightModeFile, SystemIconSourceFile.ColorSchemeData.DEFAULT));
sourceFiles.add(new SystemIconSourceFile(
source, displayName, lightModeFile, SystemIconSourceFile.ColorSchemeData.DEFAULT));
if (hasDarkModeVariant) {
sourceFiles.add(new SystemIconSourceFile(source, displayName, darkModeFile, SystemIconSourceFile.ColorSchemeData.DARK));
sourceFiles.add(new SystemIconSourceFile(
source, displayName, darkModeFile, SystemIconSourceFile.ColorSchemeData.DARK));
}
} else {
if (hasDarkModeVariant) {
sourceFiles.add(
new SystemIconSourceFile(source, displayName, darkModeFile, SystemIconSourceFile.ColorSchemeData.DEFAULT));
sourceFiles.add(new SystemIconSourceFile(
source, displayName, darkModeFile, SystemIconSourceFile.ColorSchemeData.DEFAULT));
}
}
continue;
}
sourceFiles.add(new SystemIconSourceFile(source, displayName, baseFile, SystemIconSourceFile.ColorSchemeData.DEFAULT));
sourceFiles.add(new SystemIconSourceFile(
source, displayName, baseFile, SystemIconSourceFile.ColorSchemeData.DEFAULT));
}
} catch (Exception e) {
ErrorEvent.fromThrowable(e).handle();
@@ -32,10 +32,11 @@ public class AboutCategory extends AppPrefsCategory {
.grow(true, false),
null)
.addComp(
new TileButtonComp("documentation", "documentationDescription", "mdi2b-book-open-variant", e -> {
Hyperlinks.open(Hyperlinks.DOCS);
e.consume();
})
new TileButtonComp(
"documentation", "documentationDescription", "mdi2b-book-open-variant", e -> {
Hyperlinks.open(Hyperlinks.DOCS);
e.consume();
})
.grow(true, false),
null)
.addComp(
@@ -54,13 +55,13 @@ public class AboutCategory extends AppPrefsCategory {
null)
.addComp(
new TileButtonComp("thirdParty", "thirdPartyDescription", "mdi2o-open-source-initiative", e -> {
var comp = new ThirdPartyDependencyListComp()
.prefWidth(650)
.styleClass("open-source-notices");
var modal = ModalOverlay.of("openSourceNotices", comp);
modal.show();
})
.grow(true, false))
var comp = new ThirdPartyDependencyListComp()
.prefWidth(650)
.styleClass("open-source-notices");
var modal = ModalOverlay.of("openSourceNotices", comp);
modal.show();
})
.grow(true, false))
.addComp(
new TileButtonComp("eula", "eulaDescription", "mdi2c-card-text-outline", e -> {
Hyperlinks.open(Hyperlinks.DOCS_EULA);
@@ -29,8 +29,7 @@ public class ConnectionsCategory extends AppPrefsCategory {
.sub(new OptionsBuilder().pref(prefs.useLocalFallbackShell).addToggle(prefs.useLocalFallbackShell));
if (OsType.getLocal() == OsType.WINDOWS) {
options.addTitle("sshConfiguration")
.sub(new OptionsBuilder()
.addComp(prefs.getCustomComp("x11WslInstance")));
.sub(new OptionsBuilder().addComp(prefs.getCustomComp("x11WslInstance")));
}
return options.buildComp();
}
@@ -187,12 +187,36 @@ public interface ExternalEditorType extends PrefsChoiceValue {
ExternalEditorType PYCHARM = new GenericPathType("app.pycharm", "pycharm", false);
ExternalEditorType WEBSTORM = new GenericPathType("app.webstorm", "webstorm", false);
ExternalEditorType CLION = new GenericPathType("app.clion", "clion", false);
List<ExternalEditorType> WINDOWS_EDITORS =
List.of(CURSOR_WINDOWS, WINDSURF_WINDOWS, TRAE_WINDOWS, VSCODIUM_WINDOWS, VSCODE_INSIDERS_WINDOWS, VSCODE_WINDOWS, NOTEPADPLUSPLUS, NOTEPAD);
List<LinuxPathType> LINUX_EDITORS =
List.of(ExternalEditorType.WINDSURF_LINUX, VSCODIUM_LINUX, VSCODE_LINUX, ZED_LINUX, KATE, GEDIT, PLUMA, LEAFPAD, MOUSEPAD, GNOME);
List<ExternalEditorType> MACOS_EDITORS =
List.of(CURSOR_MACOS, WINDSURF_MACOS, TRAE_MACOS, BBEDIT, VSCODIUM_MACOS, VSCODE_MACOS, SUBLIME_MACOS, ZED_MACOS, TEXT_EDIT);
List<ExternalEditorType> WINDOWS_EDITORS = List.of(
CURSOR_WINDOWS,
WINDSURF_WINDOWS,
TRAE_WINDOWS,
VSCODIUM_WINDOWS,
VSCODE_INSIDERS_WINDOWS,
VSCODE_WINDOWS,
NOTEPADPLUSPLUS,
NOTEPAD);
List<LinuxPathType> LINUX_EDITORS = List.of(
ExternalEditorType.WINDSURF_LINUX,
VSCODIUM_LINUX,
VSCODE_LINUX,
ZED_LINUX,
KATE,
GEDIT,
PLUMA,
LEAFPAD,
MOUSEPAD,
GNOME);
List<ExternalEditorType> MACOS_EDITORS = List.of(
CURSOR_MACOS,
WINDSURF_MACOS,
TRAE_MACOS,
BBEDIT,
VSCODIUM_MACOS,
VSCODE_MACOS,
SUBLIME_MACOS,
ZED_MACOS,
TEXT_EDIT);
List<ExternalEditorType> CROSS_PLATFORM_EDITORS = List.of(FLEET, INTELLIJ, PYCHARM, WEBSTORM, CLION);
@SuppressWarnings("TrivialFunctionalExpressionUsage")
@@ -10,16 +10,15 @@ import io.xpipe.core.util.SecretValue;
import lombok.Value;
import org.apache.commons.io.FileUtils;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Supplier;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public interface ExternalRdpClientType extends PrefsChoiceValue {
@@ -126,7 +125,12 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
public void launch(LaunchConfiguration configuration) throws Exception {
var file = writeRdpConfigFile(configuration.getTitle(), configuration.getConfig());
var escapedPw = configuration.getPassword().getSecretValue().replaceAll("'", "\\\\'");
launch(configuration.getTitle(), CommandBuilder.of().addFile(file.toString()).add("/cert-ignore").add("/p:'" + escapedPw + "'"));
launch(
configuration.getTitle(),
CommandBuilder.of()
.addFile(file.toString())
.add("/cert-ignore")
.add("/p:'" + escapedPw + "'"));
}
@Override
@@ -293,7 +297,8 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
.add(ExternalApplicationHelper.replaceFileArgument(
format,
"FILE",
writeRdpConfigFile(configuration.getTitle(), configuration.getConfig()).toString())));
writeRdpConfigFile(configuration.getTitle(), configuration.getConfig())
.toString())));
}
@Override
@@ -307,9 +312,11 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
}
}
class RemminaRdpType extends ExternalApplicationType.PathApplication implements ExternalRdpClientType {
class RemminaRdpType extends ExternalApplicationType.PathApplication implements ExternalRdpClientType {
public RemminaRdpType() {super("app.remmina", "remmina", true);}
public RemminaRdpType() {
super("app.remmina", "remmina", true);
}
private List<String> toStrip() {
return List.of("auto connect", "password 51", "prompt for credentials", "smart sizing");
@@ -324,7 +331,9 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
var encrypted = encryptPassword(configuration.getPassword());
if (encrypted.isPresent()) {
var file = writeRemminaConfigFile(configuration, encrypted.get());
launch(configuration.getTitle(), CommandBuilder.of().add("-c").addFile(file.toString()));
launch(
configuration.getTitle(),
CommandBuilder.of().add("-c").addFile(file.toString()));
ThreadHelper.runFailableAsync(() -> {
ThreadHelper.sleep(5000);
FileUtils.deleteQuietly(file.toFile());
@@ -343,7 +352,8 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
}
try (var sc = LocalShell.getShell().start()) {
var prefSecretBase64 = sc.command("sed -n 's/^secret=//p' ~/.config/remmina/remmina.pref").readStdoutIfPossible();
var prefSecretBase64 = sc.command("sed -n 's/^secret=//p' ~/.config/remmina/remmina.pref")
.readStdoutIfPossible();
if (prefSecretBase64.isEmpty()) {
return Optional.empty();
}
@@ -367,7 +377,8 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
private Path writeRemminaConfigFile(LaunchConfiguration configuration, String password) throws Exception {
var name = OsType.getLocal().makeFileSystemCompatible(configuration.getTitle());
var file = LocalShell.getShell().getSystemTemporaryDirectory().join(name + ".remmina");
var string = """
var string =
"""
[remmina]
protocol=RDP
name=%s
@@ -375,11 +386,20 @@ public interface ExternalRdpClientType extends PrefsChoiceValue {
server=%s
password=%s
cert_ignore=1
""".formatted(configuration.getTitle(),
configuration.getConfig().get("username").orElseThrow().getValue(),
configuration.getConfig().get("full address").orElseThrow().getValue(),
password
);
"""
.formatted(
configuration.getTitle(),
configuration
.getConfig()
.get("username")
.orElseThrow()
.getValue(),
configuration
.getConfig()
.get("full address")
.orElseThrow()
.getValue(),
password);
Files.writeString(file.toLocalPath(), string);
return file.toLocalPath();
}
@@ -3,7 +3,6 @@ package io.xpipe.app.prefs;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.base.*;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.window.AppDialog;
import io.xpipe.app.storage.DataStorageSyncHandler;
import io.xpipe.app.util.Hyperlinks;
import io.xpipe.app.util.OptionsBuilder;
@@ -54,9 +54,10 @@ public class UpdateCheckComp extends SimpleComp {
}
if (updateReady.getValue()) {
var prefix = !AppDistributionType.get().getUpdateHandler().supportsDirectInstallation()
? AppI18n.get("updateReadyPortable")
: AppI18n.get("updateReady");
var prefix =
!AppDistributionType.get().getUpdateHandler().supportsDirectInstallation()
? AppI18n.get("updateReadyPortable")
: AppI18n.get("updateReady");
var version = "Version "
+ AppDistributionType.get()
.getUpdateHandler()
@@ -534,9 +534,11 @@ public abstract class DataStorage {
.merge(pair.getValue().getStore().asNeeded());
var mergedStoreChanged = pair.getKey().getStore() != merged;
var nameChanged = shouldUpdateChildrenStoreName(pair.getKey(), pair.getValue().get());
var nameChanged =
shouldUpdateChildrenStoreName(pair.getKey(), pair.getValue().get());
if (pair.getKey().getStorePersistentState() == null || pair.getValue().get().getStorePersistentState() == null) {
if (pair.getKey().getStorePersistentState() == null
|| pair.getValue().get().getStorePersistentState() == null) {
return !mergedStoreChanged && !nameChanged;
}
@@ -574,7 +576,9 @@ public abstract class DataStorage {
addStoreEntriesIfNotPresent(toAdd.stream().map(DataStoreEntryRef::get).toArray(DataStoreEntry[]::new));
toUpdate.forEach(pair -> {
if (shouldUpdateChildrenStoreName(pair.getKey(), pair.getValue().get())) {
pair.getKey().setName(getNameableStoreName(pair.getValue().get()).orElse(pair.getKey().getName()));
pair.getKey()
.setName(getNameableStoreName(pair.getValue().get())
.orElse(pair.getKey().getName()));
}
DataStore merged = ((FixedChildStore) pair.getKey().getStore())
@@ -1,8 +1,5 @@
package io.xpipe.app.storage;
import com.sun.net.httpserver.HttpExchange;
import io.xpipe.beacon.api.ConnectionQueryExchange;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
@@ -12,21 +9,22 @@ public class DataStorageQuery {
public static List<DataStoreEntry> queryUserInput(String connection) {
var found = query("**", "**" + connection + "*", "*");
if (found.size() > 1) {
var narrow = found.stream().filter(dataStoreEntry -> dataStoreEntry.getName().equalsIgnoreCase(connection)).toList();
var narrow = found.stream()
.filter(dataStoreEntry -> dataStoreEntry.getName().equalsIgnoreCase(connection))
.toList();
if (narrow.size() == 1) {
return narrow;
}
}
return found;
}
public static List<DataStoreEntry> query(String categoryFilter, String connectionFilter, String typeFilter) {
if (DataStorage.get() == null) {
return List.of();
}
var catMatcher = Pattern.compile(
toRegex("all connections/" + categoryFilter.toLowerCase()));
var catMatcher = Pattern.compile(toRegex("all connections/" + categoryFilter.toLowerCase()));
var conMatcher = Pattern.compile(toRegex(connectionFilter.toLowerCase()));
var typeMatcher = Pattern.compile(toRegex(typeFilter.toLowerCase()));
@@ -437,9 +437,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
@Override
protected CommandBuilder toCommand(TerminalLaunchConfiguration configuration) {
return CommandBuilder.of()
.add("-e")
.addFile(configuration.getScriptFile());
return CommandBuilder.of().add("-e").addFile(configuration.getScriptFile());
}
};
ExternalTerminalType UXTERM = new SimplePathType("app.uxterm", "uxterm", true) {
@@ -4,8 +4,6 @@ import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.ext.ShellStore;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.util.LocalShell;
import io.xpipe.app.util.SecretManager;
import io.xpipe.app.util.SecretQueryProgress;
import io.xpipe.beacon.BeaconClientException;
import io.xpipe.beacon.BeaconServerException;
import io.xpipe.core.process.*;
@@ -127,8 +125,8 @@ public class TerminalLauncherManager {
}
}
public static List<String> externalExchange(DataStoreEntryRef<ShellStore> ref, List<String> arguments) throws BeaconClientException, BeaconServerException {
public static List<String> externalExchange(DataStoreEntryRef<ShellStore> ref, List<String> arguments)
throws BeaconClientException, BeaconServerException {
var request = UUID.randomUUID();
ShellControl session;
try {
@@ -149,15 +147,20 @@ public class TerminalLauncherManager {
waitExchange(request);
var script = launchExchange(request);
try (var sc = LocalShell.getShell().start()) {
var runCommand = ProcessControlProvider.get().getEffectiveLocalDialect().getOpenScriptCommand(script.toString()).buildBaseParts(sc);
var cleaned = runCommand.stream().map(s -> {
if (s.startsWith("\"") && s.endsWith("\"")) {
s = s.substring(1, s.length() - 1);
} else if (s.startsWith("'") && s.endsWith("'")) {
s = s.substring(1, s.length() - 1);
}
return s;
}).toList();
var runCommand = ProcessControlProvider.get()
.getEffectiveLocalDialect()
.getOpenScriptCommand(script.toString())
.buildBaseParts(sc);
var cleaned = runCommand.stream()
.map(s -> {
if (s.startsWith("\"") && s.endsWith("\"")) {
s = s.substring(1, s.length() - 1);
} else if (s.startsWith("'") && s.endsWith("'")) {
s = s.substring(1, s.length() - 1);
}
return s;
})
.toList();
return cleaned;
} catch (Exception e) {
throw new BeaconServerException(e);
@@ -127,7 +127,16 @@ public class AppInstaller {
echo Starting XPipe ...
start "" "%s" "-Dio.xpipe.app.dataDir=%s"
""",
file, file, logFile, args, file, logFile, args, exec, exec, AppProperties.get().getDataDir());
file,
file,
logFile,
args,
file,
logFile,
args,
exec,
exec,
AppProperties.get().getDataDir());
}
private String getPowershellCommand(String file, String logFile, String exec, boolean systemWide) {
@@ -143,7 +152,17 @@ public class AppInstaller {
echo 'Starting XPipe ...'
& "%s" "-Dio.xpipe.app.dataDir=%s"
""",
file, file, logFile, property, runas, file, logFile, startProcessProperty, exec, exec, AppProperties.get().getDataDir());
file,
file,
logFile,
property,
runas,
file,
logFile,
startProcessProperty,
exec,
exec,
AppProperties.get().getDataDir());
}
}
@@ -106,8 +106,11 @@ public abstract class UpdateHandler {
event("Starting background updater thread");
var run = !AppProperties.get().isRestarted();
while (true) {
if (run && (AppPrefs.get().automaticallyUpdate().get()
|| AppPrefs.get().checkForSecurityUpdates().get())) {
if (run
&& (AppPrefs.get().automaticallyUpdate().get()
|| AppPrefs.get()
.checkForSecurityUpdates()
.get())) {
event("Performing background update");
refreshUpdateCheckSilent(
!checked,
@@ -4,7 +4,6 @@ import io.xpipe.app.core.check.AppSystemFontCheck;
import io.xpipe.app.core.window.ModifiedStage;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.core.process.CommandBuilder;
import io.xpipe.core.process.OsType;
import javafx.application.Platform;
@@ -174,7 +173,8 @@ public enum PlatformState {
return OptionalInt.empty();
}
var factor = LocalExec.readStdoutIfPossible("gsettings", "get", "org.gnome.desktop.interface", "scaling-factor");
var factor =
LocalExec.readStdoutIfPossible("gsettings", "get", "org.gnome.desktop.interface", "scaling-factor");
if (factor.isEmpty()) {
return OptionalInt.empty();
}
@@ -184,7 +184,8 @@ public enum PlatformState {
return OptionalInt.empty();
}
var textFactor = LocalExec.readStdoutIfPossible("gsettings", "get", "org.gnome.desktop.interface", "text-scaling-factor");
var textFactor = LocalExec.readStdoutIfPossible(
"gsettings", "get", "org.gnome.desktop.interface", "text-scaling-factor");
if (textFactor.isEmpty()) {
return OptionalInt.empty();
}
@@ -4,8 +4,8 @@ import io.xpipe.app.ext.ScanProvider;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.process.ShellTtyState;
import javafx.collections.ObservableList;
public interface ScanDialogAction {
@@ -53,7 +53,6 @@ public interface ScanDialogAction {
return action;
}
boolean scan(
ObservableList<ScanProvider.ScanOpportunity> all,
ObservableList<ScanProvider.ScanOpportunity> selected,
@@ -3,23 +3,20 @@ package io.xpipe.app.util;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.base.ListSelectorComp;
import io.xpipe.app.comp.base.LoadingOverlayComp;
import io.xpipe.app.comp.store.StoreChoiceComp;
import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.ScanProvider;
import io.xpipe.app.ext.ShellStore;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.storage.DataStoreEntryRef;
import javafx.application.Platform;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import lombok.Getter;
import java.util.ArrayList;
@@ -41,7 +38,11 @@ public class ScanDialogBase {
@Getter
private final BooleanProperty busy = new SimpleBooleanProperty();
public ScanDialogBase(boolean expand, Runnable closeAction, ScanDialogAction action, ObservableList<DataStoreEntryRef<ShellStore>> entries) {
public ScanDialogBase(
boolean expand,
Runnable closeAction,
ScanDialogAction action,
ObservableList<DataStoreEntryRef<ShellStore>> entries) {
this.expand = expand;
this.closeAction = closeAction;
this.action = action;
@@ -121,19 +122,18 @@ public class ScanDialogBase {
return n + suffix.getDescriptionSuffix().map(d -> " (" + d + ")").orElse("");
};
var r = new ListSelectorComp<>(
available,
nameFunc,
selected,
scanOperation -> scanOperation.isDisabled(),
() -> available.size() > 3)
available,
nameFunc,
selected,
scanOperation -> scanOperation.isDisabled(),
() -> available.size() > 3)
.createRegion();
stackPane.getChildren().add(r);
onUpdate();
entries.addListener((ListChangeListener<? super DataStoreEntryRef<ShellStore>>) c -> onUpdate());
var comp = LoadingOverlayComp.noProgress(Comp.of(() -> stackPane), busy)
.vgrow();
var comp = LoadingOverlayComp.noProgress(Comp.of(() -> stackPane), busy).vgrow();
return comp;
}
}
@@ -1,18 +1,13 @@
package io.xpipe.app.util;
import io.xpipe.app.comp.base.ModalOverlayContentComp;
import io.xpipe.app.comp.store.StoreChoiceComp;
import io.xpipe.app.comp.store.StoreViewState;
import io.xpipe.app.ext.ShellStore;
import io.xpipe.app.storage.DataStoreEntryRef;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import java.util.List;
@@ -25,12 +20,16 @@ class ScanMultiDialogComp extends ModalOverlayContentComp {
ScanMultiDialogComp(List<DataStoreEntryRef<ShellStore>> entries, ScanDialogAction action) {
ObservableList<DataStoreEntryRef<ShellStore>> list = FXCollections.observableArrayList(entries);
this.base = new ScanDialogBase(true, () -> {
var modal = getModalOverlay();
if (modal != null) {
modal.close();
}
}, action, list);
this.base = new ScanDialogBase(
true,
() -> {
var modal = getModalOverlay();
if (modal != null) {
modal.close();
}
},
action,
list);
}
void finish() {
@@ -55,7 +54,8 @@ class ScanMultiDialogComp extends ModalOverlayContentComp {
.prefHeight(680)
.apply(struc -> {
VBox.setVgrow(struc.get().getChildren().getFirst(), ALWAYS);
});;
});
;
return b.createRegion();
}
}
@@ -10,7 +10,6 @@ import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import static javafx.scene.layout.Priority.ALWAYS;
@@ -34,12 +33,16 @@ class ScanSingleDialogComp extends ModalOverlayContentComp {
list.clear();
}
});
this.base = new ScanDialogBase(true, () -> {
var modal = getModalOverlay();
if (initialStore != null && modal != null) {
modal.close();
}
}, action, list);
this.base = new ScanDialogBase(
true,
() -> {
var modal = getModalOverlay();
if (initialStore != null && modal != null) {
modal.close();
}
},
action,
list);
}
void finish() {
@@ -45,7 +45,8 @@ public class SecretManager {
}
public static synchronized void clearSecretProgress(UUID request) {
progress.removeIf(secretQueryProgress -> secretQueryProgress.getRequestId().equals(request));
progress.removeIf(
secretQueryProgress -> secretQueryProgress.getRequestId().equals(request));
}
public static boolean isSpecialPrompt(String prompt) {
@@ -5,7 +5,6 @@ import io.xpipe.app.core.AppProperties;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.core.process.CommandBuilder;
import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.util.XPipeInstallation;
@@ -1,6 +1,7 @@
package io.xpipe.beacon.api;
import io.xpipe.beacon.BeaconInterface;
import lombok.Builder;
import lombok.NonNull;
import lombok.Value;
@@ -10,7 +10,6 @@ import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.terminal.TerminalLauncher;
import io.xpipe.core.process.ShellTtyState;
import io.xpipe.core.process.SystemState;
import io.xpipe.core.store.DataStore;
import io.xpipe.ext.base.script.ScriptHierarchy;
import javafx.beans.property.SimpleStringProperty;
@@ -22,13 +22,21 @@ public class IdentityChoice {
ObjectProperty<IdentityValue> identity,
boolean requireUser) {
var i = new IdentityChoice(
gateway, identity, requireUser, requireUser, true, true, true, "identityChoice", "passwordAuthentication");
gateway,
identity,
requireUser,
requireUser,
true,
true,
true,
"identityChoice",
"passwordAuthentication");
return i.build();
}
public static OptionsBuilder container(ObjectProperty<IdentityValue> identity) {
var i = new IdentityChoice(
null, identity, true, false, false, false, false,"customUsername", "customUsernamePassword");
null, identity, true, false, false, false, false, "customUsername", "customUsernamePassword");
return i.build();
}
@@ -92,17 +100,18 @@ public class IdentityChoice {
} else {
var u = user.get();
var p = EncryptedValue.CurrentKey.of(pass.get());
EncryptedValue<SshIdentityStrategy> i = keyInput
? EncryptedValue.CurrentKey.of(identityStrategy.get())
: null;
EncryptedValue<SshIdentityStrategy> i =
keyInput ? EncryptedValue.CurrentKey.of(identityStrategy.get()) : null;
if (u == null && p == null && i == null) {
return null;
} else {
return IdentityValue.InPlace.builder().identityStore(LocalIdentityStore.builder()
.username(u)
.password(p)
.sshIdentity(i)
.build()).build();
return IdentityValue.InPlace.builder()
.identityStore(LocalIdentityStore.builder()
.username(u)
.password(p)
.sshIdentity(i)
.build())
.build();
}
}
},
@@ -45,7 +45,9 @@ public class LocalIdentityStoreProvider extends IdentityStoreProvider {
.name("keyAuthentication")
.description("keyAuthenticationDescription")
.longDescription("base:sshKey")
.sub(SshIdentityStrategyHelper.identity(new SimpleObjectProperty<>(), identity, null, false, true), identity)
.sub(
SshIdentityStrategyHelper.identity(new SimpleObjectProperty<>(), identity, null, false, true),
identity)
.bind(
() -> {
return LocalIdentityStore.builder()
@@ -194,7 +194,8 @@ public interface SshIdentityStrategy {
}
if ((parent.getOsType().equals(OsType.LINUX) || parent.getOsType().equals(OsType.MACOS))) {
parent.command(CommandBuilder.of().add("chmod", "400").addFile(resolved)).executeAndCheck();
parent.command(CommandBuilder.of().add("chmod", "400").addFile(resolved))
.executeAndCheck();
}
}
@@ -28,7 +28,8 @@ public class SshIdentityStrategyHelper {
p);
}
var forward = new SimpleBooleanProperty(p.getValue() != null && p.getValue().isForwardAgent());
var forward =
new SimpleBooleanProperty(p.getValue() != null && p.getValue().isForwardAgent());
return new OptionsBuilder()
.nameAndDescription("forwardAgent")
.addToggle(forward)
@@ -33,7 +33,8 @@ public class IncusContainerStore
StatefulDataStore<ContainerStoreState>,
StartableStore,
StoppableStore,
PauseableStore, NameableStore {
PauseableStore,
NameableStore {
DataStoreEntryRef<IncusInstallStore> install;
String containerName;
@@ -27,11 +27,12 @@ import java.util.OptionalInt;
@AllArgsConstructor
public class LxdContainerStore
implements ShellStore,
FixedChildStore,
StatefulDataStore<ContainerStoreState>,
StartableStore,
StoppableStore,
PauseableStore, NameableStore {
FixedChildStore,
StatefulDataStore<ContainerStoreState>,
StartableStore,
StoppableStore,
PauseableStore,
NameableStore {
DataStoreEntryRef<LxdCmdStore> cmd;
String containerName;
@@ -46,8 +46,9 @@ public class PodmanCmdStore
var l = view.container().listContainersAndStates();
return l.stream()
.map(s -> {
boolean running =
s.getStatus().startsWith("running") || s.getStatus().startsWith("up") || s.getStatus().startsWith("Up");
boolean running = s.getStatus().startsWith("running")
|| s.getStatus().startsWith("up")
|| s.getStatus().startsWith("Up");
var c = PodmanContainerStore.builder()
.cmd(getSelfEntry().ref())
.containerName(s.getName())
@@ -32,14 +32,15 @@ import java.util.regex.Pattern;
@Value
public class PodmanContainerStore
implements StartableStore,
StoppableStore,
ShellStore,
InternalCacheDataStore,
FixedChildStore,
StatefulDataStore<ContainerStoreState>,
FixedServiceCreatorStore,
SelfReferentialStore,
ContainerImageStore, NameableStore {
StoppableStore,
ShellStore,
InternalCacheDataStore,
FixedChildStore,
StatefulDataStore<ContainerStoreState>,
FixedServiceCreatorStore,
SelfReferentialStore,
ContainerImageStore,
NameableStore {
DataStoreEntryRef<PodmanCmdStore> cmd;
String containerName;