From fa5f08dd7465619a00ced3d0a39d9bc319a09f00 Mon Sep 17 00:00:00 2001 From: crschnick Date: Fri, 24 Jan 2025 19:31:05 +0000 Subject: [PATCH] Rework --- app/build.gradle | 2 +- .../app/comp/store/StoreIconChoiceComp.java | 20 ++-- .../app/comp/store/StoreIconChoiceDialog.java | 8 +- .../java/io/xpipe/app/core/mode/BaseMode.java | 7 +- .../java/io/xpipe/app/icon/SystemIcon.java | 10 ++ .../io/xpipe/app/icon/SystemIconCache.java | 95 +++++++++++++++++++ .../io/xpipe/app/icon/SystemIconManager.java | 68 +++++++++++++ .../{resources => icon}/SystemIconSource.java | 7 +- .../xpipe/app/icon/SystemIconSourceData.java | 56 +++++++++++ .../xpipe/app/icon/SystemIconSourceFile.java | 14 +++ .../io/xpipe/app/resources/AppImages.java | 26 +++++ .../io/xpipe/app/resources/SystemIcon.java | 15 --- .../xpipe/app/resources/SystemIconCache.java | 90 ------------------ .../app/resources/SystemIconManager.java | 39 -------- .../io/xpipe/app/resources/SystemIcons.java | 52 ---------- .../io/xpipe/app/storage/DataStoreEntry.java | 3 +- app/src/main/java/module-info.java | 1 + build.gradle | 2 +- dist/build.gradle | 6 +- dist/licenses/bc-java.properties | 2 +- .../ext/base/store/ShellStoreProvider.java | 2 - gradle/wrapper/gradle-wrapper.properties | 2 +- 22 files changed, 297 insertions(+), 230 deletions(-) create mode 100644 app/src/main/java/io/xpipe/app/icon/SystemIcon.java create mode 100644 app/src/main/java/io/xpipe/app/icon/SystemIconCache.java create mode 100644 app/src/main/java/io/xpipe/app/icon/SystemIconManager.java rename app/src/main/java/io/xpipe/app/{resources => icon}/SystemIconSource.java (87%) create mode 100644 app/src/main/java/io/xpipe/app/icon/SystemIconSourceData.java create mode 100644 app/src/main/java/io/xpipe/app/icon/SystemIconSourceFile.java delete mode 100644 app/src/main/java/io/xpipe/app/resources/SystemIcon.java delete mode 100644 app/src/main/java/io/xpipe/app/resources/SystemIconCache.java delete mode 100644 app/src/main/java/io/xpipe/app/resources/SystemIconManager.java delete mode 100644 app/src/main/java/io/xpipe/app/resources/SystemIcons.java diff --git a/app/build.gradle b/app/build.gradle index 7ba6d5f92..53240db58 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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' diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreIconChoiceComp.java b/app/src/main/java/io/xpipe/app/comp/store/StoreIconChoiceComp.java index be9b53cc3..6a6ee98ec 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreIconChoiceComp.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreIconChoiceComp.java @@ -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 selected; - private final List icons; + private final Set icons; private final int columns; private final SimpleStringProperty filter; private final Runnable doubleClick; public StoreIconChoiceComp( Property selected, - List icons, + Set icons, int columns, SimpleStringProperty filter, Runnable doubleClick) { @@ -73,9 +71,9 @@ public class StoreIconChoiceComp extends SimpleComp { private void updateData(TableView> table, String filterString) { var displayedIcons = filterString == null || filterString.isBlank() || filterString.length() < 2 - ? icons + ? icons.stream().sorted(Comparator.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); } } diff --git a/app/src/main/java/io/xpipe/app/comp/store/StoreIconChoiceDialog.java b/app/src/main/java/io/xpipe/app/comp/store/StoreIconChoiceDialog.java index c971afa22..e0eda1b3c 100644 --- a/app/src/main/java/io/xpipe/app/comp/store/StoreIconChoiceDialog.java +++ b/app/src/main/java/io/xpipe/app/comp/store/StoreIconChoiceDialog.java @@ -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(); } } diff --git a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java index bd6a7de3e..50bbbe9ce 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/BaseMode.java @@ -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(); diff --git a/app/src/main/java/io/xpipe/app/icon/SystemIcon.java b/app/src/main/java/io/xpipe/app/icon/SystemIcon.java new file mode 100644 index 000000000..30097dbc7 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/icon/SystemIcon.java @@ -0,0 +1,10 @@ +package io.xpipe.app.icon; + +import lombok.Value; + +@Value +public class SystemIcon { + + SystemIconSource source; + String id; +} diff --git a/app/src/main/java/io/xpipe/app/icon/SystemIconCache.java b/app/src/main/java/io/xpipe/app/icon/SystemIconCache.java new file mode 100644 index 000000000..d5ab71d3b --- /dev/null +++ b/app/src/main/java/io/xpipe/app/icon/SystemIconCache.java @@ -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 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()); + } +} diff --git a/app/src/main/java/io/xpipe/app/icon/SystemIconManager.java b/app/src/main/java/io/xpipe/app/icon/SystemIconManager.java new file mode 100644 index 000000000..6c1792672 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/icon/SystemIconManager.java @@ -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 SOURCES = java.util.List.of( + new SystemIconSource.GitRepository("https://github.com/selfhst/icons", "selfhst")); + + private static final Map LOADED = new HashMap<>(); + private static final Set ICONS = new HashSet<>(); + + public static Set 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"); + } +} diff --git a/app/src/main/java/io/xpipe/app/resources/SystemIconSource.java b/app/src/main/java/io/xpipe/app/icon/SystemIconSource.java similarity index 87% rename from app/src/main/java/io/xpipe/app/resources/SystemIconSource.java rename to app/src/main/java/io/xpipe/app/icon/SystemIconSource.java index 44ee801a0..f9da21e08 100644 --- a/app/src/main/java/io/xpipe/app/resources/SystemIconSource.java +++ b/app/src/main/java/io/xpipe/app/icon/SystemIconSource.java @@ -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(); diff --git a/app/src/main/java/io/xpipe/app/icon/SystemIconSourceData.java b/app/src/main/java/io/xpipe/app/icon/SystemIconSourceData.java new file mode 100644 index 000000000..78626507d --- /dev/null +++ b/app/src/main/java/io/xpipe/app/icon/SystemIconSourceData.java @@ -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 icons; + + public static SystemIconSourceData of(SystemIconSource source) throws IOException { + var target = source.getPath(); + var list = new ArrayList(); + walkTree(source, target, list); + return new SystemIconSourceData(target, list); + } + + private static void walkTree(SystemIconSource source, Path dir, List 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(); + } + } +} diff --git a/app/src/main/java/io/xpipe/app/icon/SystemIconSourceFile.java b/app/src/main/java/io/xpipe/app/icon/SystemIconSourceFile.java new file mode 100644 index 000000000..65f97deba --- /dev/null +++ b/app/src/main/java/io/xpipe/app/icon/SystemIconSourceFile.java @@ -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; +} diff --git a/app/src/main/java/io/xpipe/app/resources/AppImages.java b/app/src/main/java/io/xpipe/app/resources/AppImages.java index ae13d2156..8cc43a7e7 100644 --- a/app/src/main/java/io/xpipe/app/resources/AppImages.java +++ b/app/src/main/java/io/xpipe/app/resources/AppImages.java @@ -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)) { diff --git a/app/src/main/java/io/xpipe/app/resources/SystemIcon.java b/app/src/main/java/io/xpipe/app/resources/SystemIcon.java deleted file mode 100644 index 11aba24c5..000000000 --- a/app/src/main/java/io/xpipe/app/resources/SystemIcon.java +++ /dev/null @@ -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; -} diff --git a/app/src/main/java/io/xpipe/app/resources/SystemIconCache.java b/app/src/main/java/io/xpipe/app/resources/SystemIconCache.java deleted file mode 100644 index 47d003bf3..000000000 --- a/app/src/main/java/io/xpipe/app/resources/SystemIconCache.java +++ /dev/null @@ -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()); - } -} diff --git a/app/src/main/java/io/xpipe/app/resources/SystemIconManager.java b/app/src/main/java/io/xpipe/app/resources/SystemIconManager.java deleted file mode 100644 index 74ec055d3..000000000 --- a/app/src/main/java/io/xpipe/app/resources/SystemIconManager.java +++ /dev/null @@ -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 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"); - } -} diff --git a/app/src/main/java/io/xpipe/app/resources/SystemIcons.java b/app/src/main/java/io/xpipe/app/resources/SystemIcons.java deleted file mode 100644 index 5e5e5e153..000000000 --- a/app/src/main/java/io/xpipe/app/resources/SystemIcons.java +++ /dev/null @@ -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 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 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 getSystemIcons() { - return SYSTEM_ICONS; - } -} diff --git a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java index e2482a0d1..715585bb1 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStoreEntry.java @@ -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 fromDirectory(Path dir) throws Exception { diff --git a/app/src/main/java/module-info.java b/app/src/main/java/module-info.java index f272d68be..b0fcc1496 100644 --- a/app/src/main/java/module-info.java +++ b/app/src/main/java/module-info.java @@ -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; diff --git a/build.gradle b/build.gradle index fffbf500d..d490e570a 100644 --- a/build.gradle +++ b/build.gradle @@ -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 -> diff --git a/dist/build.gradle b/dist/build.gradle index f513f7824..0ce173912 100644 --- a/dist/build.gradle +++ b/dist/build.gradle @@ -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' } diff --git a/dist/licenses/bc-java.properties b/dist/licenses/bc-java.properties index 018570997..d08e93e26 100644 --- a/dist/licenses/bc-java.properties +++ b/dist/licenses/bc-java.properties @@ -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 \ No newline at end of file diff --git a/ext/base/src/main/java/io/xpipe/ext/base/store/ShellStoreProvider.java b/ext/base/src/main/java/io/xpipe/ext/base/store/ShellStoreProvider.java index 1283e3f94..452ea507d 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/store/ShellStoreProvider.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/store/ShellStoreProvider.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; diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e0fd02028..d9fbee2e1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -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