Icon rework

This commit is contained in:
crschnick 2024-09-15 11:04:24 +00:00
parent 076084952e
commit 85e2e7ba2f
5 changed files with 113 additions and 9 deletions

View file

@ -0,0 +1,44 @@
package io.xpipe.app.resources;
import io.xpipe.app.ext.ContainerImageStore;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.store.DataStore;
import lombok.EqualsAndHashCode;
import lombok.Value;
import java.util.function.Predicate;
@Value
@EqualsAndHashCode(callSuper=true)
public class ContainerAutoSystemIcon extends SystemIcon {
Predicate<String> imageCheck;
public ContainerAutoSystemIcon(String iconName, String displayName, Predicate<String> imageCheck) {
super(iconName, displayName);
this.imageCheck = imageCheck;
}
@Override
public boolean isApplicable(ShellControl sc) throws Exception {
var source = sc.getSourceStore();
if (source.isEmpty()) {
return false;
}
return isApplicable(source.get());
}
@Override
public boolean isApplicable(DataStore store) {
if (!(store instanceof ContainerImageStore containerImageStore)) {
return false;
}
if (containerImageStore.getImageName() == null) {
return false;
}
return imageCheck.test(containerImageStore.getImageName());
}
}

View file

@ -7,11 +7,11 @@ import lombok.Value;
@Value
@EqualsAndHashCode(callSuper=true)
public class AutoSystemIcon extends SystemIcon {
public class ShellAutoSystemIcon extends SystemIcon {
FailableFunction<ShellControl, Boolean, Exception> applicable;
public AutoSystemIcon(String iconName, String displayName, FailableFunction<ShellControl, Boolean, Exception> applicable) {
public ShellAutoSystemIcon(String iconName, String displayName, FailableFunction<ShellControl, Boolean, Exception> applicable) {
super(iconName, displayName);
this.applicable = applicable;
}

View file

@ -1,6 +1,7 @@
package io.xpipe.app.resources;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.store.DataStore;
import lombok.Value;
import lombok.experimental.NonFinal;
@ -14,4 +15,8 @@ public class SystemIcon {
public boolean isApplicable(ShellControl sc) throws Exception {
return false;
}
public boolean isApplicable(DataStore store) {
return false;
}
}

View file

@ -2,6 +2,9 @@ package io.xpipe.app.resources;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.process.ShellStoreState;
import io.xpipe.core.store.DataStore;
import io.xpipe.core.store.StatefulDataStore;
import org.apache.commons.io.FilenameUtils;
import java.nio.file.Files;
@ -13,9 +16,25 @@ import java.util.Optional;
public class SystemIcons {
private static final List<AutoSystemIcon> AUTO_SYSTEM_ICONS = List.of(new AutoSystemIcon("opnsense", "OpnSense",sc -> {
return sc.getOriginalShellDialect() == ShellDialects.OPNSENSE;
}));
private static final List<SystemIcon> AUTO_SYSTEM_ICONS = List.of(
new SystemIcon("opnsense", "OpnSense") {
@Override
public boolean isApplicable(DataStore store) {
return store instanceof StatefulDataStore<?> statefulDataStore &&
statefulDataStore.getState() instanceof ShellStoreState shellStoreState &&
shellStoreState.getShellDialect() == ShellDialects.OPNSENSE;
}
},
new SystemIcon("pfsense", "PfSense") {
@Override
public boolean isApplicable(DataStore store) {
return store instanceof StatefulDataStore<?> statefulDataStore &&
statefulDataStore.getState() instanceof ShellStoreState shellStoreState &&
shellStoreState.getShellDialect() == ShellDialects.PFSENSE;
}
},
new ContainerAutoSystemIcon("file-browser", "File Browser", name -> name.contains("filebrowser"))
);
private static final List<SystemIcon> SYSTEM_ICONS = new ArrayList<>();
private static boolean loaded = false;
@ -69,7 +88,7 @@ public class SystemIcons {
}
public static Optional<SystemIcon> detectForSystem(ShellControl sc) throws Exception {
for (AutoSystemIcon autoSystemIcon : AUTO_SYSTEM_ICONS) {
for (var autoSystemIcon : AUTO_SYSTEM_ICONS) {
if (autoSystemIcon.isApplicable(sc)) {
return Optional.of(autoSystemIcon);
}
@ -77,6 +96,19 @@ public class SystemIcons {
return Optional.empty();
}
public static Optional<SystemIcon> detectForStore(DataStore store) {
if (store == null) {
return Optional.empty();
}
for (var autoSystemIcon : AUTO_SYSTEM_ICONS) {
if (autoSystemIcon.isApplicable(store)) {
return Optional.of(autoSystemIcon);
}
}
return Optional.empty();
}
public static List<SystemIcon> getSystemIcons() {
return SYSTEM_ICONS;
}

View file

@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import io.xpipe.app.ext.DataStoreProvider;
import io.xpipe.app.ext.DataStoreProviders;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.resources.SystemIcons;
import io.xpipe.app.util.FixedHierarchyStore;
import io.xpipe.core.store.*;
import io.xpipe.core.util.JacksonMapper;
@ -87,7 +88,8 @@ public class DataStoreEntry extends StorageElement {
boolean expanded,
DataColor color,
String notes,
Order explicitOrder, String icon
Order explicitOrder,
String icon
) {
super(directory, uuid, name, lastUsed, lastModified, color, expanded, dirty);
this.categoryUuid = categoryUuid;
@ -152,6 +154,7 @@ public class DataStoreEntry extends StorageElement {
var validity = storeFromNode == null
? Validity.LOAD_FAILED
: store.isComplete() ? Validity.COMPLETE : Validity.INCOMPLETE;
var icon = SystemIcons.detectForStore(store);
var entry = new DataStoreEntry(
null,
uuid,
@ -169,10 +172,21 @@ public class DataStoreEntry extends StorageElement {
null,
null,
null,
null);
icon.map(systemIcon -> systemIcon.getIconName()).orElse(null));
return entry;
}
private void refreshIcon() {
if (icon != null) {
return;
}
var icon = SystemIcons.detectForStore(store);
if (icon.isPresent()) {
setIcon(icon.get().getIconName());
}
}
public static Optional<DataStoreEntry> fromDirectory(Path dir) throws Exception {
ObjectMapper mapper = JacksonMapper.getDefault();
@ -204,8 +218,12 @@ public class DataStoreEntry extends StorageElement {
}
})
.orElse(null);
var iconNode = json.get("icon");
String icon = iconNode != null ? iconNode.asText() : null;
String icon = iconNode != null && !iconNode.isNull() ? iconNode.asText() : null;
if (icon != null && SystemIcons.getForId(icon).isEmpty()) {
icon = null;
}
var persistentState = stateJson.get("persistentState");
var lastUsed = Optional.ofNullable(stateJson.get("lastUsed"))
@ -261,6 +279,9 @@ public class DataStoreEntry extends StorageElement {
// Store loading is prone to errors.
JsonNode storeNode = DataStorageEncryption.readPossiblyEncryptedNode(mapper.readTree(storeFile.toFile()));
var store = JacksonMapper.getDefault().treeToValue(storeNode, DataStore.class);
if (icon == null) {
icon = SystemIcons.detectForStore(store).map(systemIcon -> systemIcon.getIconName()).orElse(null);
}
return Optional.of(new DataStoreEntry(
dir,
uuid,
@ -363,6 +384,7 @@ public class DataStoreEntry extends StorageElement {
this.storePersistentState = value;
this.storePersistentStateNode = JacksonMapper.getDefault().valueToTree(value);
if (changed) {
refreshIcon();
notifyUpdate(false, true);
}
}
@ -447,6 +469,7 @@ public class DataStoreEntry extends StorageElement {
validity = store == null ? Validity.LOAD_FAILED : store.isComplete() ? Validity.COMPLETE : Validity.INCOMPLETE;
storePersistentState = e.storePersistentState;
storePersistentStateNode = e.storePersistentStateNode;
icon = e.icon;
notifyUpdate(false, true);
}