mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-08-11 03:51:05 +00:00
Rework
This commit is contained in:
+1
-1
@@ -51,7 +51,7 @@ dependencies {
|
||||
api("com.github.weisj:jsvg:1.7.0")
|
||||
api files("$rootDir/gradle/gradle_scripts/markdowngenerator-1.3.1.1.jar")
|
||||
api files("$rootDir/gradle/gradle_scripts/vernacular-1.16.jar")
|
||||
api 'org.bouncycastle:bcprov-jdk18on:1.79'
|
||||
api 'org.bouncycastle:bcprov-jdk18on:1.80'
|
||||
api 'info.picocli:picocli:4.7.6'
|
||||
api ('org.kohsuke:github-api:1.326') {
|
||||
exclude group: 'org.apache.commons', module: 'commons-lang3'
|
||||
|
||||
@@ -2,8 +2,9 @@ package io.xpipe.app.comp.store;
|
||||
|
||||
import io.xpipe.app.comp.SimpleComp;
|
||||
import io.xpipe.app.comp.base.*;
|
||||
import io.xpipe.app.resources.SystemIcon;
|
||||
import io.xpipe.app.icon.SystemIcon;
|
||||
|
||||
import io.xpipe.app.icon.SystemIconManager;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
@@ -14,24 +15,21 @@ import javafx.scene.layout.Region;
|
||||
|
||||
import atlantafx.base.theme.Tweaks;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.*;
|
||||
|
||||
import static atlantafx.base.theme.Styles.TEXT_SMALL;
|
||||
|
||||
public class StoreIconChoiceComp extends SimpleComp {
|
||||
|
||||
private final Property<SystemIcon> selected;
|
||||
private final List<SystemIcon> icons;
|
||||
private final Set<SystemIcon> icons;
|
||||
private final int columns;
|
||||
private final SimpleStringProperty filter;
|
||||
private final Runnable doubleClick;
|
||||
|
||||
public StoreIconChoiceComp(
|
||||
Property<SystemIcon> selected,
|
||||
List<SystemIcon> icons,
|
||||
Set<SystemIcon> icons,
|
||||
int columns,
|
||||
SimpleStringProperty filter,
|
||||
Runnable doubleClick) {
|
||||
@@ -73,9 +71,9 @@ public class StoreIconChoiceComp extends SimpleComp {
|
||||
|
||||
private void updateData(TableView<List<SystemIcon>> table, String filterString) {
|
||||
var displayedIcons = filterString == null || filterString.isBlank() || filterString.length() < 2
|
||||
? icons
|
||||
? icons.stream().sorted(Comparator.<SystemIcon, String>comparing(systemIcon -> systemIcon.getId())).toList()
|
||||
: icons.stream()
|
||||
.filter(icon -> containsString(icon.getDisplayName(), filterString))
|
||||
.filter(icon -> containsString(icon.getId(), filterString))
|
||||
.toList();
|
||||
|
||||
var data = partitionList(displayedIcons, columns);
|
||||
@@ -137,8 +135,8 @@ public class StoreIconChoiceComp extends SimpleComp {
|
||||
return;
|
||||
}
|
||||
|
||||
root.setText(icon.getDisplayName());
|
||||
image.set("app:system/" + icon.getIconName() + ".svg");
|
||||
root.setText(icon.getId());
|
||||
image.set(SystemIconManager.getIconFile(icon));
|
||||
setGraphic(root);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.xpipe.app.comp.store;
|
||||
|
||||
import io.xpipe.app.comp.base.*;
|
||||
import io.xpipe.app.resources.SystemIcon;
|
||||
import io.xpipe.app.resources.SystemIcons;
|
||||
import io.xpipe.app.icon.SystemIcon;
|
||||
import io.xpipe.app.icon.SystemIconManager;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.util.Hyperlinks;
|
||||
|
||||
@@ -41,7 +41,7 @@ public class StoreIconChoiceDialog {
|
||||
.grow(false, true);
|
||||
var modal = ModalOverlay.of(
|
||||
"chooseCustomIcon",
|
||||
new StoreIconChoiceComp(selected, SystemIcons.getSystemIcons(), 5, filterText, () -> {
|
||||
new StoreIconChoiceComp(selected, SystemIconManager.getIcons(), 5, filterText, () -> {
|
||||
finish();
|
||||
})
|
||||
.prefWidth(600));
|
||||
@@ -63,7 +63,7 @@ public class StoreIconChoiceDialog {
|
||||
}
|
||||
|
||||
private void finish() {
|
||||
entry.setIcon(selected.get() != null ? selected.getValue().getIconName() : null, true);
|
||||
entry.setIcon(selected.get() != null ? selected.getValue().getSource().getId() + "/" + selected.getValue().getId() : null, true);
|
||||
overlay.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.xpipe.app.core.window.AppMainWindow;
|
||||
import io.xpipe.app.ext.ActionProvider;
|
||||
import io.xpipe.app.ext.DataStoreProviders;
|
||||
import io.xpipe.app.ext.ProcessControlProvider;
|
||||
import io.xpipe.app.icon.SystemIconManager;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
@@ -93,9 +94,6 @@ public class BaseMode extends OperationMode {
|
||||
XPipeDistributionType.init();
|
||||
AppPrefs.setLocalDefaultsIfNeeded();
|
||||
},
|
||||
() -> {
|
||||
SystemIconManager.init();
|
||||
},
|
||||
() -> {
|
||||
shellLoaded.await();
|
||||
AppMainWindow.loadingText("loadingGit");
|
||||
@@ -135,8 +133,9 @@ public class BaseMode extends OperationMode {
|
||||
() -> {
|
||||
PlatformInit.init(true);
|
||||
AppImages.init();
|
||||
SystemIcons.init();
|
||||
imagesLoaded.countDown();
|
||||
SystemIconManager.loadSources();
|
||||
SystemIconManager.loadImages();
|
||||
},
|
||||
() -> {
|
||||
BrowserIconManager.loadIfNecessary();
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package io.xpipe.app.icon;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
public class SystemIcon {
|
||||
|
||||
SystemIconSource source;
|
||||
String id;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package io.xpipe.app.icon;
|
||||
|
||||
import com.github.weisj.jsvg.SVGDocument;
|
||||
import com.github.weisj.jsvg.attributes.ViewBox;
|
||||
import com.github.weisj.jsvg.parser.SVGLoader;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.*;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
public class SystemIconCache {
|
||||
|
||||
private static final Path DIRECTORY = AppProperties.get().getDataDir().resolve("cache").resolve("icons").resolve("raster");
|
||||
private static final int[] sizes = new int[]{16, 24, 40, 80};
|
||||
|
||||
public static Path getDirectory(SystemIconSource source) {
|
||||
var target = DIRECTORY.resolve(source.getId());
|
||||
return target;
|
||||
}
|
||||
|
||||
public static void buildCache(Map<SystemIconSource, SystemIconSourceData> all) {
|
||||
try {
|
||||
for (var e : all.entrySet()) {
|
||||
var target = DIRECTORY.resolve(e.getKey().getId());
|
||||
Files.createDirectories(target);
|
||||
|
||||
for (var icon : e.getValue().getIcons()) {
|
||||
if (refreshChecksum(icon.getFile(),target,icon.getName(), icon.isDark())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rasterizeSizes(icon.getFile(),target,icon.getName(), icon.isDark());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean refreshChecksum(Path source, Path dir, String name, boolean dark) throws Exception {
|
||||
var md5Name = name + (dark ? "-dark" : "") + ".md5";
|
||||
var bytes = Files.readAllBytes(source);
|
||||
var md = MessageDigest.getInstance("MD5");
|
||||
md.update(bytes);
|
||||
var digest = md.digest();
|
||||
var md5File = dir.resolve(md5Name);
|
||||
if (Files.exists(md5File) && Arrays.equals(Files.readAllBytes(md5File), digest)) {
|
||||
return true;
|
||||
} else {
|
||||
Files.write(md5File, digest);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean rasterizeSizes(Path path, Path dir, String name, boolean dark) throws IOException {
|
||||
try {
|
||||
for (var size : sizes) {
|
||||
rasterize(path, dir, name, dark, size);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
if (ex instanceof IOException) {
|
||||
throw ex;
|
||||
}
|
||||
|
||||
ErrorEvent.fromThrowable(ex).omit().expected().handle();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void rasterize(Path path, Path dir, String name, boolean dark, int px) throws IOException {
|
||||
SVGLoader loader = new SVGLoader();
|
||||
URL svgUrl = path.toUri().toURL();
|
||||
SVGDocument svgDocument = loader.load(svgUrl);
|
||||
if (svgDocument == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
BufferedImage image = new BufferedImage(px, px, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = image.createGraphics();
|
||||
svgDocument.render((Component) null, g, new ViewBox(0, 0, px, px));
|
||||
g.dispose();
|
||||
|
||||
var out = dir.resolve(name + "-" + px + (dark ? "-dark" : "") + ".png");
|
||||
ImageIO.write(image,"png", out.toFile());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package io.xpipe.app.icon;
|
||||
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.resources.AppImages;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
public class SystemIconManager {
|
||||
|
||||
private static final Path DIRECTORY = AppProperties.get().getDataDir().resolve("cache").resolve("icons").resolve("pool");
|
||||
|
||||
private static final List<SystemIconSource> SOURCES = java.util.List.of(
|
||||
new SystemIconSource.GitRepository("https://github.com/selfhst/icons", "selfhst"));
|
||||
|
||||
private static final Map<SystemIconSource, SystemIconSourceData> LOADED = new HashMap<>();
|
||||
private static final Set<SystemIcon> ICONS = new HashSet<>();
|
||||
|
||||
public static Set<SystemIcon> getIcons() {
|
||||
return ICONS;
|
||||
}
|
||||
|
||||
public static String getIconFile(SystemIcon icon) {
|
||||
return "icons/" + icon.getSource().getId() + "/" + icon.getId() + ".svg";
|
||||
}
|
||||
|
||||
public static void loadSources() throws Exception {
|
||||
Files.createDirectories(DIRECTORY);
|
||||
|
||||
LOADED.clear();
|
||||
for (var source : SOURCES) {
|
||||
LOADED.put(source,SystemIconSourceData.of(source));
|
||||
}
|
||||
|
||||
ICONS.clear();
|
||||
SystemIconCache.buildCache(LOADED);
|
||||
LOADED.forEach((source, systemIconSourceData) -> {
|
||||
systemIconSourceData.getIcons().forEach(systemIconSourceFile -> {
|
||||
var icon = new SystemIcon(source, systemIconSourceFile.getName());
|
||||
ICONS.add(icon);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static void loadImages() {
|
||||
try {
|
||||
for (var source : SOURCES) {
|
||||
AppImages.loadRasterImages(SystemIconCache.getDirectory(source), "icons/" + source.getId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
}
|
||||
}
|
||||
|
||||
public static void reload() throws Exception {
|
||||
Files.createDirectories(DIRECTORY);
|
||||
for (var source : SOURCES) {
|
||||
source.refresh();
|
||||
}
|
||||
loadSources();
|
||||
}
|
||||
|
||||
public static Path getPoolPath() {
|
||||
return AppProperties.get().getDataDir().resolve("cache").resolve("icons").resolve("pool");
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -1,7 +1,6 @@
|
||||
package io.xpipe.app.resources;
|
||||
package io.xpipe.app.icon;
|
||||
|
||||
import io.xpipe.app.ext.ProcessControlProvider;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.core.process.CommandBuilder;
|
||||
import lombok.Value;
|
||||
|
||||
@@ -17,7 +16,7 @@ public interface SystemIconSource {
|
||||
String id;
|
||||
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
public void refresh() throws Exception {
|
||||
try (var sc = ProcessControlProvider.get().createLocalProcessControl(true).start()) {
|
||||
var dir = SystemIconManager.getPoolPath().resolve(id);
|
||||
if (!Files.exists(dir)) {
|
||||
@@ -34,7 +33,7 @@ public interface SystemIconSource {
|
||||
}
|
||||
}
|
||||
|
||||
void init() throws Exception;
|
||||
void refresh() throws Exception;
|
||||
|
||||
String getId();
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package io.xpipe.app.icon;
|
||||
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import lombok.Value;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Value
|
||||
public class SystemIconSourceData {
|
||||
|
||||
Path directory;
|
||||
List<SystemIconSourceFile> icons;
|
||||
|
||||
public static SystemIconSourceData of(SystemIconSource source) throws IOException {
|
||||
var target = source.getPath();
|
||||
var list = new ArrayList<SystemIconSourceFile>();
|
||||
walkTree(source, target, list);
|
||||
return new SystemIconSourceData(target, list);
|
||||
}
|
||||
|
||||
private static void walkTree(SystemIconSource source, Path dir, List<SystemIconSourceFile> sourceFiles) {
|
||||
try {
|
||||
if (!Files.isDirectory(dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var files = Files.walk(dir, FileVisitOption.FOLLOW_LINKS).toList();
|
||||
for (var file : files) {
|
||||
if (file.getFileName().toString().endsWith(".svg")) {
|
||||
var name = FilenameUtils.getBaseName(file.getFileName().toString());
|
||||
var cleanedName = name.replaceFirst("-light$", "").replaceFirst("-dark$", "");
|
||||
if (name.endsWith("-light") || name.endsWith("-dark")) {
|
||||
var s = new SystemIconSourceFile(source, cleanedName, file, name.endsWith("-dark"));
|
||||
sourceFiles.add(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
var bothVariants = Files.exists(file.getParent().resolve(cleanedName + "-light.svg")) && Files.exists(
|
||||
file.getParent().resolve(cleanedName + "-dark.svg"));
|
||||
if (!bothVariants) {
|
||||
var s = new SystemIconSourceFile(source, cleanedName, file, name.endsWith("-dark"));
|
||||
sourceFiles.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorEvent.fromThrowable(e).handle();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package io.xpipe.app.icon;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
@Value
|
||||
public class SystemIconSourceFile {
|
||||
|
||||
SystemIconSource source;
|
||||
String name;
|
||||
Path file;
|
||||
boolean dark;
|
||||
}
|
||||
@@ -75,6 +75,24 @@ public class AppImages {
|
||||
TrackEvent.trace("Loaded images in " + module + ":" + dir + " in " + elapsed.toMillis() + " ms");
|
||||
}
|
||||
|
||||
|
||||
public static void loadRasterImages(Path directory, String prefix) throws IOException {
|
||||
Files.walkFileTree(directory, new SimpleFileVisitor<>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
var relativeFileName = FilenameUtils.separatorsToUnix(
|
||||
directory.relativize(file).toString());
|
||||
var key = prefix + "/" + relativeFileName;
|
||||
if (images.containsKey(key)) {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
images.put(key, loadImage(file));
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static String svgImage(String file) {
|
||||
if (file == null) {
|
||||
return "";
|
||||
@@ -95,6 +113,10 @@ public class AppImages {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (images.containsKey(file)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var key = file.contains(":") ? file : "app:" + file;
|
||||
return images.containsKey(key);
|
||||
}
|
||||
@@ -113,6 +135,10 @@ public class AppImages {
|
||||
return DEFAULT_IMAGE;
|
||||
}
|
||||
|
||||
if (images.containsKey(file)) {
|
||||
return images.get(file);
|
||||
}
|
||||
|
||||
var key = file.contains(":") ? file : "app:" + file;
|
||||
|
||||
if (images.containsKey(key)) {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package io.xpipe.app.resources;
|
||||
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.store.DataStore;
|
||||
|
||||
import lombok.Value;
|
||||
import lombok.experimental.NonFinal;
|
||||
|
||||
@Value
|
||||
public class SystemIcon {
|
||||
|
||||
SystemIconSource source;
|
||||
String iconName;
|
||||
String displayName;
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package io.xpipe.app.resources;
|
||||
|
||||
import com.github.weisj.jsvg.SVGDocument;
|
||||
import com.github.weisj.jsvg.geometry.size.FloatSize;
|
||||
import com.github.weisj.jsvg.parser.SVGLoader;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.file.*;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class SystemIconCache {
|
||||
|
||||
private static final Path DIRECTORY = AppProperties.get().getDataDir().resolve("cache").resolve("icons").resolve("raster");
|
||||
private static final int[] sizes = new int[]{16, 24, 40, 80};
|
||||
|
||||
public static void init() throws Exception {
|
||||
Files.createDirectories(DIRECTORY);
|
||||
walkTree(Path.of("C:\\Projects\\xpipe\\xpipex\\img\\selfhst"),"selfhst");
|
||||
}
|
||||
|
||||
public static void walkTree(Path dir, String source) throws Exception {
|
||||
var target = DIRECTORY.resolve(source);
|
||||
Files.createDirectories(target);
|
||||
|
||||
var files = Files.walk(dir, FileVisitOption.FOLLOW_LINKS).toList();
|
||||
for (var file : files) {
|
||||
if (file.getFileName().toString().endsWith(".svg")) {
|
||||
rasterize(file, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void rasterize(Path path, String source) throws Exception {
|
||||
var name = FilenameUtils.getBaseName(path.getFileName().toString());
|
||||
var dark = !name.endsWith("-light");
|
||||
var md5Name = name.replaceFirst("-light$", "") + (dark ? "-dark" : "");
|
||||
var bytes = Files.readAllBytes(path);
|
||||
var md = MessageDigest.getInstance("MD5");
|
||||
md.update(bytes);
|
||||
var digest = md.digest();
|
||||
var dir = DIRECTORY.resolve(source);
|
||||
var md5File = dir.resolve(md5Name);
|
||||
if (Files.exists(md5File) && Arrays.equals(Files.readAllBytes(md5File), digest)) {
|
||||
return;
|
||||
} else {
|
||||
Files.write(md5File, digest);
|
||||
}
|
||||
|
||||
for (var size : sizes) {
|
||||
rasterize(path, source, size);
|
||||
}
|
||||
}
|
||||
|
||||
private static void rasterize(Path path, String source, int px) throws IOException {
|
||||
var name = FilenameUtils.getBaseName(path.getFileName().toString());
|
||||
var dark = !name.endsWith("-light");
|
||||
var fixedName = name.replaceFirst("-light$", "");
|
||||
rasterize(path, source,fixedName, px, dark);
|
||||
}
|
||||
|
||||
private static void rasterize(Path path, String source, String name, int px, boolean dark) throws IOException {
|
||||
SVGLoader loader = new SVGLoader();
|
||||
URL svgUrl = path.toUri().toURL();
|
||||
SVGDocument svgDocument = loader.load(svgUrl);
|
||||
if (svgDocument == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
BufferedImage image = new BufferedImage(px, px, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = image.createGraphics();
|
||||
svgDocument.render(null, g);
|
||||
g.dispose();
|
||||
|
||||
var dir = DIRECTORY.resolve(source);
|
||||
Files.createDirectories(dir);
|
||||
var out = dir.resolve(name + "-" + px + (dark ? "-dark" : "") + ".png");
|
||||
ImageIO.write(image,"png", out.toFile());
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package io.xpipe.app.resources;
|
||||
|
||||
import com.github.weisj.jsvg.SVGDocument;
|
||||
import com.github.weisj.jsvg.geometry.size.FloatSize;
|
||||
import com.github.weisj.jsvg.parser.SVGLoader;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class SystemIconManager {
|
||||
|
||||
private static final Path DIRECTORY = AppProperties.get().getDataDir().resolve("cache").resolve("icons").resolve("pool");
|
||||
|
||||
private static final List<SystemIconSource> SOURCES = java.util.List.of(
|
||||
new SystemIconSource.GitRepository("https://github.com/selfhst/icons", "selfhst"));
|
||||
|
||||
public static void init() throws Exception {
|
||||
Files.createDirectories(DIRECTORY);
|
||||
for (var source : SOURCES) {
|
||||
source.init();
|
||||
SystemIconCache.walkTree(source.getPath(), source.getId());
|
||||
}
|
||||
}
|
||||
|
||||
public static Path getPoolPath() {
|
||||
return AppProperties.get().getDataDir().resolve("cache").resolve("icons").resolve("pool");
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package io.xpipe.app.resources;
|
||||
|
||||
import io.xpipe.core.process.*;
|
||||
import io.xpipe.core.store.DataStore;
|
||||
import io.xpipe.core.store.StatefulDataStore;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class SystemIcons {
|
||||
|
||||
private static final List<SystemIcon> SYSTEM_ICONS = new ArrayList<>();
|
||||
private static boolean loaded = false;
|
||||
|
||||
public static synchronized void init() {
|
||||
if (SYSTEM_ICONS.size() > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void load() {
|
||||
if (loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
AppImages.loadDirectory(AppResources.XPIPE_MODULE, "img/system", true, false);
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
public static Optional<SystemIcon> getForId(String id) {
|
||||
if (id == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
for (SystemIcon systemIcon : SYSTEM_ICONS) {
|
||||
if (systemIcon.getIconName().equals(id)) {
|
||||
return Optional.of(systemIcon);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static List<SystemIcon> getSystemIcons() {
|
||||
return SYSTEM_ICONS;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import io.xpipe.app.ext.DataStoreProvider;
|
||||
import io.xpipe.app.ext.DataStoreProviders;
|
||||
import io.xpipe.app.ext.UserScopeStore;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.resources.SystemIcons;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import io.xpipe.core.store.*;
|
||||
import io.xpipe.core.util.JacksonMapper;
|
||||
@@ -186,7 +185,7 @@ public class DataStoreEntry extends StorageElement {
|
||||
return getProvider().getDisplayIconFileName(getStore());
|
||||
}
|
||||
|
||||
return "app:system/" + icon + ".svg";
|
||||
return "icons/" + icon + ".svg";
|
||||
}
|
||||
|
||||
public static Optional<DataStoreEntry> fromDirectory(Path dir) throws Exception {
|
||||
|
||||
@@ -40,6 +40,7 @@ open module io.xpipe.app {
|
||||
exports io.xpipe.app.core.window;
|
||||
exports io.xpipe.app.resources;
|
||||
exports io.xpipe.app.comp;
|
||||
exports io.xpipe.app.icon;
|
||||
|
||||
requires com.sun.jna;
|
||||
requires com.sun.jna.platform;
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ buildscript {
|
||||
plugins {
|
||||
id("io.github.gradle-nexus.publish-plugin") version "2.0.0"
|
||||
id 'org.gradlex.extra-java-module-info' version '1.9' apply false
|
||||
id("com.diffplug.spotless") version "6.25.0" apply false
|
||||
id("com.diffplug.spotless") version "7.0.2" apply false
|
||||
}
|
||||
|
||||
allprojects { subproject ->
|
||||
|
||||
Vendored
+3
-3
@@ -1,9 +1,9 @@
|
||||
|
||||
plugins {
|
||||
id 'org.beryx.jlink' version '3.1.1'
|
||||
id "org.asciidoctor.jvm.convert" version "4.0.3"
|
||||
id 'org.jreleaser' version '1.15.0'
|
||||
id("com.netflix.nebula.ospackage") version "11.10.0"
|
||||
id "org.asciidoctor.jvm.convert" version "4.0.4"
|
||||
id 'org.jreleaser' version '1.16.0'
|
||||
id("com.netflix.nebula.ospackage") version "11.10.1"
|
||||
id 'org.gradle.crypto.checksum' version '1.4.0'
|
||||
id 'signing'
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
name=Bouncy Castle Crypto Package For Java
|
||||
version=1.79
|
||||
version=1.80
|
||||
license=MIT License
|
||||
link=https://github.com/bcgit/bc-java
|
||||
@@ -7,12 +7,10 @@ import io.xpipe.app.comp.store.StoreEntryWrapper;
|
||||
import io.xpipe.app.comp.store.StoreSection;
|
||||
import io.xpipe.app.comp.store.SystemStateComp;
|
||||
import io.xpipe.app.ext.*;
|
||||
import io.xpipe.app.resources.SystemIcons;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.terminal.TerminalLauncher;
|
||||
import io.xpipe.app.util.ShellStoreFormat;
|
||||
import io.xpipe.core.process.SystemState;
|
||||
import io.xpipe.ext.base.script.ScriptStore;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
Reference in New Issue
Block a user