Rework start on init stores

This commit is contained in:
crschnick
2025-08-31 15:54:14 +00:00
parent 8fd873ac12
commit efcc4525d8
7 changed files with 143 additions and 67 deletions

View File

@@ -1,65 +0,0 @@
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.comp.augment.ContextMenuAugment;
import io.xpipe.app.platform.ContextMenuHelper;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableValue;
import javafx.css.Size;
import javafx.css.SizeUnits;
import javafx.scene.control.Button;
import javafx.scene.control.MenuItem;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.List;
public class DropdownComp extends Comp<CompStructure<Button>> {
private final List<Comp<?>> items;
public DropdownComp(List<Comp<?>> items) {
this.items = items;
}
@Override
public CompStructure<Button> createBase() {
var cm = ContextMenuHelper.create();
cm.getItems()
.setAll(items.stream()
.map(comp -> {
return new MenuItem(null, comp.createRegion());
})
.toList());
Button button = (Button) new ButtonComp(null, () -> {})
.apply(new ContextMenuAugment<>(e -> true, null, () -> {
return cm;
}))
.createRegion();
List<? extends ObservableValue<Boolean>> l = cm.getItems().stream()
.map(menuItem -> menuItem.getGraphic().visibleProperty())
.toList();
button.visibleProperty()
.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 -> {
graphic.setIconSize((int) new Size(c.getSize(), SizeUnits.PT).pixels());
});
button.setGraphic(graphic);
button.getStyleClass().add("dropdown-comp");
button.setAccessibleText("Dropdown actions");
return new SimpleCompStructure<>(button);
}
}

View File

@@ -1,5 +1,7 @@
package io.xpipe.app.core;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.core.JacksonMapper;
@@ -45,8 +47,12 @@ public class AppCache {
}
}
@SuppressWarnings("unchecked")
public static <T> T getNonNull(String key, Class<?> type, Supplier<T> notPresent) {
return getNonNull(key, TypeFactory.defaultInstance().constructType(type), notPresent);
}
@SuppressWarnings("unchecked")
public static <T> T getNonNull(String key, JavaType type, Supplier<T> notPresent) {
var path = getPath(key);
if (Files.exists(path)) {
try {
@@ -58,7 +64,7 @@ public class AppCache {
}
var r = (T) JacksonMapper.getDefault().treeToValue(tree, type);
if (r == null || !type.isAssignableFrom(r.getClass())) {
if (r == null) {
FileUtils.deleteQuietly(path.toFile());
return notPresent.get();
} else {
@@ -75,6 +81,7 @@ public class AppCache {
return notPresent.get();
}
public static boolean getBoolean(String key, boolean notPresent) {
var path = getPath(key);
if (Files.exists(path)) {

View File

@@ -15,6 +15,7 @@ import io.xpipe.app.core.window.AppMainWindow;
import io.xpipe.app.core.window.AppWindowTitle;
import io.xpipe.app.ext.DataStoreProviders;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.ext.StartOnInitStore;
import io.xpipe.app.hub.comp.StoreViewState;
import io.xpipe.app.icon.SystemIconManager;
import io.xpipe.app.issue.TrackEvent;
@@ -162,6 +163,7 @@ public class BaseMode extends OperationMode {
ActionProvider.initProviders();
DataStoreProviders.init();
StartOnInitStore.init();
AppConfigurationDialog.showIfNeeded();
AppGnomeScaleDialog.showIfNeeded();

View File

@@ -0,0 +1,65 @@
package io.xpipe.app.ext;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.type.TypeFactory;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.icon.SystemIconSource;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.app.util.ThreadHelper;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public interface StartOnInitStore extends SelfReferentialStore, DataStore {
static void init() {
ThreadHelper.runFailableAsync(() -> {
var enabled = getEnabledStores();
for (DataStoreEntry e : DataStorage.get().getStoreEntries()) {
if (e.getStore() instanceof StartOnInitStore i && e.getValidity().isUsable() && enabled.contains(i.getSelfEntry().ref())) {
i.startOnInit();
}
}
});
}
static Set<DataStoreEntryRef<?>> getEnabledStores() {
synchronized (StartOnInitStore.class) {
var type = TypeFactory.defaultInstance().constructType(new TypeReference<Set<DataStoreEntryRef<?>>>() {});
Set<DataStoreEntryRef<?>> cached = AppCache.getNonNull("startOnInitStores", type, () -> Set.of());
return cached;
}
}
static void setEnabledStores(Set<DataStoreEntryRef<?>> stores) {
synchronized (StartOnInitStore.class) {
AppCache.update("startOnInitStores", stores);
}
}
default boolean isEnabled() {
return getEnabledStores().contains(getSelfEntry().ref());
}
default void enable() {
synchronized (StartOnInitStore.class) {
var enabled = new HashSet<>(getEnabledStores());
enabled.add(getSelfEntry().ref());
setEnabledStores(enabled);
}
}
default void disable() {
synchronized (StartOnInitStore.class) {
var enabled = new HashSet<>(getEnabledStores());
enabled.remove(getSelfEntry().ref());
setEnabledStores(enabled);
}
}
void startOnInit() throws Exception;
}

View File

@@ -0,0 +1,64 @@
package io.xpipe.app.hub.action.impl;
import io.xpipe.app.browser.BrowserFullSessionModel;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppLayoutModel;
import io.xpipe.app.ext.StartOnInitStore;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.hub.action.HubLeafProvider;
import io.xpipe.app.hub.action.StoreAction;
import io.xpipe.app.hub.action.StoreActionCategory;
import io.xpipe.app.platform.LabelGraphic;
import io.xpipe.app.storage.DataStoreEntryRef;
import io.xpipe.core.FilePath;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import lombok.experimental.SuperBuilder;
import lombok.extern.jackson.Jacksonized;
public class StartOnInitHubLeafProvider implements HubLeafProvider<StartOnInitStore> {
@Override
public Action createAction(DataStoreEntryRef<StartOnInitStore> ref) {
return Action.builder().ref(ref).build();
}
@Override
public StoreActionCategory getCategory() {
return StoreActionCategory.CUSTOM;
}
@Override
public ObservableValue<String> getName(DataStoreEntryRef<StartOnInitStore> store) {
return AppI18n.observable(store.getStore().isEnabled() ? "disableStartOnInit" : "enableStartOnInit");
}
@Override
public LabelGraphic getIcon(DataStoreEntryRef<StartOnInitStore> store) {
return new LabelGraphic.IconGraphic(store.getStore().isEnabled() ? "mdi2t-toggle-switch-off-outline" : "mdi2t-toggle-switch-outline");
}
@Override
public Class<StartOnInitStore> getApplicableClass() {
return StartOnInitStore.class;
}
@Override
public String getId() {
return "toggleStartOnInit";
}
@Jacksonized
@SuperBuilder
public static class Action extends StoreAction<StartOnInitStore> {
@Override
public void executeImpl() throws Exception {
if (ref.getStore().isEnabled()) {
ref.getStore().disable();
} else {
ref.getStore().enable();
}
}
}
}

View File

@@ -148,6 +148,7 @@ open module io.xpipe.app {
OpenDirectoryMenuProvider,
OpenDirectoryInNewTabMenuProvider,
ScanHubLeafProvider,
StartOnInitHubLeafProvider,
BrowseHubLeafProvider,
RefreshActionProvider,
ToggleActionProvider,

View File

@@ -1629,3 +1629,5 @@ enableTerminalStartupBell=Enable terminal startup bell
enableTerminalStartupBellDescription=Play a beep/bell command in a newly terminal session. If your terminal emulator supports bells, this can be used to make identifying newly launched terminal instances easier.
rdpSmartSizing=Enable smart sizing
rdpSmartSizingDescription=When enabled, mstsc will scale down the desktop size if the window is too small to display it in its full resolution. The aspect ratio of the desktop is preserved when scaled down.
disableStartOnInit=Disable automatic startup
enableStartOnInit=Enable automatic startup