Rework icon handling

This commit is contained in:
crschnick 2024-09-20 12:14:52 +00:00
parent 6eb70ea7e5
commit 40af958800
740 changed files with 69 additions and 457 deletions

View file

@ -25,7 +25,7 @@ components from it when it is run in a development environment.
Note that in case the current master branch is ahead of the latest release, it might happen that there are some incompatibilities when loading data from your local XPipe installation. Note that in case the current master branch is ahead of the latest release, it might happen that there are some incompatibilities when loading data from your local XPipe installation.
You should therefore always check out the matching version tag for your local repository and local XPipe installation. You should therefore always check out the matching version tag for your local repository and local XPipe installation.
You can find the available version tags at https://github.com/xpipe-io/xpipe/tags. You can find the available version tags at https://github.com/xpipe-io/xpipe/tags.
So for example if you currently have XPipe `10.0` installed, you should run `git reset --hard 10.0` first to properly compile against it. So for example if you currently have XPipe `11.3` installed, you should run `git reset --hard 11.3` first to properly compile against it.
You need to have JDK for Java 21 installed to compile the project. You need to have JDK for Java 21 installed to compile the project.
If you are on Linux or macOS, you can easily accomplish that by running If you are on Linux or macOS, you can easily accomplish that by running
@ -74,7 +74,7 @@ Especially when starting out, it might be a good idea to start with easy tasks f
### Interacting via the HTTP API ### Interacting via the HTTP API
You can create clients they communicate with the XPipe daemon via its HTTP API. You can create clients that communicate with the XPipe daemon via its HTTP API.
To get started, see the [OpenAPI spec](/openapi.yaml). To get started, see the [OpenAPI spec](/openapi.yaml).
### Implementing support for a new editor ### Implementing support for a new editor
@ -98,6 +98,10 @@ All actions that you can perform for certain connections in the connection overv
You can add custom script definitions [here](https://github.com/xpipe-io/xpipe/tree/master/ext/base/src/main/java/io/xpipe/ext/base/script/PredefinedScriptStore.java) and [here](https://github.com/xpipe-io/xpipe/tree/master/ext/base/src/main/resources/io/xpipe/ext/base/resources/scripts). You can add custom script definitions [here](https://github.com/xpipe-io/xpipe/tree/master/ext/base/src/main/java/io/xpipe/ext/base/script/PredefinedScriptStore.java) and [here](https://github.com/xpipe-io/xpipe/tree/master/ext/base/src/main/resources/io/xpipe/ext/base/resources/scripts).
### Adding more system icons for system autodetection
You can register new system types [here](https://github.com/xpipe-io/xpipe/blob/master/app/src/main/java/io/xpipe/app/resources/SystemIcons.java) and add the respective icons [here](https://github.com/xpipe-io/xpipe/tree/master/app/src/main/resources/io/xpipe/app/resources/img/system).
### Adding more file icons for specific types ### Adding more file icons for specific types
You can register file types [here](https://github.com/xpipe-io/xpipe/blob/master/app/src/main/resources/io/xpipe/app/resources/file_list.txt) and add the respective icons [here](https://github.com/xpipe-io/xpipe/tree/master/app/src/main/resources/io/xpipe/app/resources/img/browser). You can register file types [here](https://github.com/xpipe-io/xpipe/blob/master/app/src/main/resources/io/xpipe/app/resources/file_list.txt) and add the respective icons [here](https://github.com/xpipe-io/xpipe/tree/master/app/src/main/resources/io/xpipe/app/resources/img/browser).
@ -108,6 +112,6 @@ The existing file list and icons are taken from the [vscode-icons](https://githu
if you want to work on something that was not listed here, you can still do so of course. You can reach out on the [Discord server](https://discord.gg/8y89vS8cRb) to discuss any development plans and get you started. if you want to work on something that was not listed here, you can still do so of course. You can reach out on the [Discord server](https://discord.gg/8y89vS8cRb) to discuss any development plans and get you started.
### Translations ### Adding translations
See the [translation guide](/lang) for details. See the [translation guide](/lang) for details.

View file

@ -631,6 +631,10 @@ public final class BrowserFileListComp extends SimpleComp {
() -> getTableRow().getItem(), fileList.getFileSystemModel()) () -> getTableRow().getItem(), fileList.getFileSystemModel())
.hide(Bindings.createBooleanBinding( .hide(Bindings.createBooleanBinding(
() -> { () -> {
if (getTableRow() == null) {
return true;
}
var item = getTableRow().getItem(); var item = getTableRow().getItem();
var notDir = item.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY; var notDir = item.getRawFileEntry().resolved().getKind() != FileKind.DIRECTORY;
var isParentLink = item.getRawFileEntry() var isParentLink = item.getRawFileEntry()

View file

@ -142,7 +142,7 @@ public class BrowserQuickAccessContextMenu extends ContextMenu {
this.menu = new Menu( this.menu = new Menu(
// Use original name, not the link target // Use original name, not the link target
browserEntry.getRawFileEntry().getName(), browserEntry.getRawFileEntry().getName(),
PrettyImageHelper.ofFixedRasterized( PrettyImageHelper.ofFixedSize(
FileIconManager.getFileIcon(browserEntry.getRawFileEntry(), false), 24, 24) FileIconManager.getFileIcon(browserEntry.getRawFileEntry(), false), 24, 24)
.createRegion()); .createRegion());
createMenu(); createMenu();

View file

@ -72,7 +72,7 @@ public class StoreEntryListOverviewComp extends SimpleComp {
// But it is good enough. // But it is good enough.
var showProvider = true; var showProvider = true;
try { try {
showProvider = storeEntryWrapper.getEntry().getProvider().shouldShow(storeEntryWrapper); showProvider = storeEntryWrapper.getEntry().getProvider() == null || storeEntryWrapper.getEntry().getProvider().shouldShow(storeEntryWrapper);
} catch (Exception ignored) {} } catch (Exception ignored) {}
return inRootCategory && showProvider; return inRootCategory && showProvider;
}, },

View file

@ -26,7 +26,7 @@ public class StoreIconChoiceDialogComp extends SimpleComp {
public static void show(DataStoreEntry entry) { public static void show(DataStoreEntry entry) {
SystemIcons.load(); SystemIcons.load();
var window = AppWindowHelper.sideWindow(AppI18n.get("chooseCustomIcon"), stage -> new StoreIconChoiceDialogComp(entry,stage),true,null); var window = AppWindowHelper.sideWindow(AppI18n.get("chooseCustomIcon"), stage -> new StoreIconChoiceDialogComp(entry,stage),false,null);
window.initModality(Modality.APPLICATION_MODAL); window.initModality(Modality.APPLICATION_MODAL);
window.show(); window.show();
} }

View file

@ -10,6 +10,8 @@ import io.xpipe.app.util.LicenseProvider;
import javafx.application.Application; import javafx.application.Application;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ObservableDoubleValue;
import javafx.stage.Stage; import javafx.stage.Stage;
import lombok.Getter; import lombok.Getter;
@ -63,4 +65,12 @@ public class App extends Application {
stage.requestFocus(); stage.requestFocus();
}); });
} }
public ObservableDoubleValue displayScale() {
if (getStage() == null) {
return new SimpleDoubleProperty(1.0);
}
return getStage().outputScaleXProperty();
}
} }

View file

@ -1,55 +1,68 @@
package io.xpipe.app.fxcomps.impl; package io.xpipe.app.fxcomps.impl;
import io.xpipe.app.core.App;
import io.xpipe.app.resources.AppImages; import io.xpipe.app.resources.AppImages;
import io.xpipe.app.fxcomps.Comp; import io.xpipe.app.fxcomps.Comp;
import io.xpipe.app.fxcomps.util.BindingsHelper; import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.core.store.FileNames; import io.xpipe.core.store.FileNames;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import java.util.List;
import java.util.Optional; import java.util.Optional;
public class PrettyImageHelper { public class PrettyImageHelper {
private static Optional<String> rasterizedImageIfExists(String img, int width, int height) { private static Optional<String> rasterizedImageIfExists(String img, int height) {
if (img != null && img.endsWith(".svg")) { if (img != null && img.endsWith(".svg")) {
var base = FileNames.getBaseName(img); var base = FileNames.getBaseName(img);
var renderedName = base + "-" + height + ".png"; var renderedName = base + "-" + height + ".png";
if (AppImages.hasNormalImage(base + "-" + height + ".png")) { if (AppImages.hasNormalImage(renderedName)) {
return Optional.of(renderedName); return Optional.of(renderedName);
} }
} }
if (img != null && img.endsWith(".png")) {
if (AppImages.hasNormalImage(img)) {
return Optional.of(img);
}
}
return Optional.empty(); return Optional.empty();
} }
private static ObservableValue<String> rasterizedImageIfExistsScaled(String img, int height) {
return Bindings.createStringBinding(() -> {
if (img == null) {
return null;
}
if (!img.endsWith(".svg")) {
return rasterizedImageIfExists(img, height).orElse(null);
}
var sizes = List.of(16, 24, 40, 80);
var mult = Math.round(App.getApp().displayScale().get() * height);
var base = FileNames.getBaseName(img);
var available = sizes.stream()
.filter(integer -> AppImages.hasNormalImage(base + "-" + integer + ".png"))
.toList();
var closest = available.stream()
.filter(integer -> integer >= mult)
.findFirst()
.orElse(available.size() > 0 ? available.getLast() : 0);
return rasterizedImageIfExists(img, closest).orElse(null);
}, App.getApp().displayScale());
}
public static Comp<?> ofFixedSizeSquare(String img, int size) { public static Comp<?> ofFixedSizeSquare(String img, int size) {
return ofFixedSize(img, size, size); return ofFixedSize(img, size, size);
} }
public static Comp<?> ofFixedRasterized(String img, int w, int h) {
if (img == null) {
return new PrettyImageComp(new SimpleStringProperty(null), w, h);
}
var rasterized = rasterizedImageIfExists(img, w, h);
return new PrettyImageComp(new SimpleStringProperty(rasterized.orElse(null)), w, h);
}
public static Comp<?> ofFixedSize(String img, int w, int h) { public static Comp<?> ofFixedSize(String img, int w, int h) {
if (img == null) { return ofFixedSize(new SimpleStringProperty(img), w,h);
return new PrettyImageComp(new SimpleStringProperty(null), w, h);
}
var rasterized = rasterizedImageIfExists(img, w, h);
if (rasterized.isPresent()) {
return new PrettyImageComp(new SimpleStringProperty(rasterized.get()), w, h);
} else {
return img.endsWith(".svg")
? new PrettySvgComp(new SimpleStringProperty(img), w, h)
: new PrettyImageComp(new SimpleStringProperty(img), w, h);
}
} }
public static Comp<?> ofFixedSize(ObservableValue<String> img, int w, int h) { public static Comp<?> ofFixedSize(ObservableValue<String> img, int w, int h) {
@ -57,8 +70,8 @@ public class PrettyImageHelper {
return new PrettyImageComp(new SimpleStringProperty(null), w, h); return new PrettyImageComp(new SimpleStringProperty(null), w, h);
} }
var binding = BindingsHelper.map(img, s -> { var binding = BindingsHelper.flatMap(img, s -> {
return rasterizedImageIfExists(s, w, h).orElse(s); return rasterizedImageIfExistsScaled(s, h);
}); });
return new PrettyImageComp(binding, w, h); return new PrettyImageComp(binding, w, h);
} }

View file

@ -18,7 +18,7 @@ import java.util.Optional;
public class SystemIcons { public class SystemIcons {
private static final List<SystemIcon> AUTO_SYSTEM_ICONS = List.of( private static final List<SystemIcon> AUTO_SYSTEM_ICONS = List.of(
new SystemIcon("opnsense", "OpnSense") { new SystemIcon("opnsense", "opnsense") {
@Override @Override
public boolean isApplicable(DataStore store) { public boolean isApplicable(DataStore store) {
return store instanceof StatefulDataStore<?> statefulDataStore && return store instanceof StatefulDataStore<?> statefulDataStore &&
@ -26,7 +26,7 @@ public class SystemIcons {
shellStoreState.getShellDialect() == ShellDialects.OPNSENSE; shellStoreState.getShellDialect() == ShellDialects.OPNSENSE;
} }
}, },
new SystemIcon("pfsense", "PfSense") { new SystemIcon("pfsense", "pfsense") {
@Override @Override
public boolean isApplicable(DataStore store) { public boolean isApplicable(DataStore store) {
return store instanceof StatefulDataStore<?> statefulDataStore && return store instanceof StatefulDataStore<?> statefulDataStore &&
@ -34,8 +34,8 @@ public class SystemIcons {
shellStoreState.getShellDialect() == ShellDialects.PFSENSE; shellStoreState.getShellDialect() == ShellDialects.PFSENSE;
} }
}, },
new ContainerAutoSystemIcon("file-browser", "File Browser", name -> name.contains("filebrowser")), new ContainerAutoSystemIcon("file-browser", "file browser", name -> name.contains("filebrowser")),
new FileAutoSystemIcon("syncthing", "Syncthing", OsType.LINUX, "~/.local/state/syncthing") new FileAutoSystemIcon("syncthing", "syncthing", OsType.LINUX, "~/.local/state/syncthing")
); );
private static final List<SystemIcon> SYSTEM_ICONS = new ArrayList<>(); private static final List<SystemIcon> SYSTEM_ICONS = new ArrayList<>();
@ -52,10 +52,10 @@ public class SystemIcons {
var all = stream.toList(); var all = stream.toList();
for (Path file : all) { for (Path file : all) {
var name = FilenameUtils.getBaseName(file.getFileName().toString()); var name = FilenameUtils.getBaseName(file.getFileName().toString());
if (name.contains("-dark") || name.contains("-40")) { if (name.contains("-dark") || name.contains("-16") || name.contains("-24")) {
continue; continue;
} }
var base = name.replaceAll("-24", ""); var base = name.replaceAll("-40", "");
if (AUTO_SYSTEM_ICONS.stream().anyMatch(autoSystemIcon -> autoSystemIcon.getIconName().equals(base))) { if (AUTO_SYSTEM_ICONS.stream().anyMatch(autoSystemIcon -> autoSystemIcon.getIconName().equals(base))) {
continue; continue;
} }

View file

@ -84,7 +84,7 @@ public enum PlatformState {
// fails // fails
} catch (HeadlessException h) { } catch (HeadlessException h) {
var msg = (OsType.getLocal().equals(OsType.LINUX) var msg = (OsType.getLocal().equals(OsType.LINUX)
? "No X11 DISPLAY variable was set or no headful library support was found." ? "No DISPLAY variable was set or no headful library support was found."
: "The application does not have desktop access, but this program performed an operation which requires it.") : "The application does not have desktop access, but this program performed an operation which requires it.")
+ "\n\n" + "\n\n"
+ "Please note that XPipe is a desktop application that should be run on your local workstation." + "Please note that XPipe is a desktop application that should be run on your local workstation."

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 998 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 902 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 740 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 902 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 808 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 843 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 789 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Some files were not shown because too many files have changed in this diff Show more