mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-25 09:00:26 +00:00
Rework icon loading
This commit is contained in:
parent
b093295c67
commit
c7c7321aff
17 changed files with 83 additions and 77 deletions
|
@ -84,7 +84,7 @@ public class BrowserNavBar extends Comp<BrowserNavBar.Structure> {
|
|||
var graphic = Bindings.createStringBinding(
|
||||
() -> {
|
||||
return model.getCurrentDirectory() != null
|
||||
? FileIconManager.getFileIcon(model.getCurrentDirectory(), false)
|
||||
? FileIconManager.getFileIcon(model.getCurrentDirectory())
|
||||
: null;
|
||||
},
|
||||
model.getCurrentPath());
|
||||
|
|
|
@ -65,11 +65,11 @@ public class BrowserEntry {
|
|||
if (fileType != null) {
|
||||
return fileType.getIcon();
|
||||
} else if (directoryType != null) {
|
||||
return directoryType.getIcon(rawFileEntry, false);
|
||||
return directoryType.getIcon(rawFileEntry);
|
||||
} else {
|
||||
return rawFileEntry != null && rawFileEntry.resolved().getKind() == FileKind.DIRECTORY
|
||||
? "default_folder.svg"
|
||||
: "default_file.svg";
|
||||
? "browser/default_folder.svg"
|
||||
: "browser/default_file.svg";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ public class BrowserQuickAccessContextMenu extends ContextMenu {
|
|||
// Use original name, not the link target
|
||||
browserEntry.getRawFileEntry().getName(),
|
||||
PrettyImageHelper.ofFixedSize(
|
||||
FileIconManager.getFileIcon(browserEntry.getRawFileEntry(), false), 24, 24)
|
||||
FileIconManager.getFileIcon(browserEntry.getRawFileEntry()), 24, 24)
|
||||
.createRegion());
|
||||
createMenu();
|
||||
addInputListeners();
|
||||
|
|
|
@ -42,8 +42,8 @@ public abstract class BrowserIconDirectoryType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getIcon(FileEntry entry, boolean open) {
|
||||
return open ? "default_root_folder_opened.svg" : "default_root_folder.svg";
|
||||
public String getIcon(FileEntry entry) {
|
||||
return "browser/default_root_folder.svg";
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -60,16 +60,12 @@ public abstract class BrowserIconDirectoryType {
|
|||
})
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
var closedIcon = split[2].trim();
|
||||
var openIcon = split[3].trim();
|
||||
|
||||
var lightClosedIcon = split.length > 4 ? split[4].trim() : closedIcon;
|
||||
var lightOpenIcon = split.length > 4 ? split[5].trim() : openIcon;
|
||||
var closedIcon = "browser/" + split[2].trim();
|
||||
var lightClosedIcon = split.length > 4 ? "browser/" + split[4].trim() : closedIcon;
|
||||
|
||||
ALL.add(new Simple(
|
||||
id,
|
||||
new IconVariant(lightClosedIcon, closedIcon),
|
||||
new IconVariant(lightOpenIcon, openIcon),
|
||||
filter));
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +80,7 @@ public abstract class BrowserIconDirectoryType {
|
|||
|
||||
public abstract boolean matches(FileEntry entry);
|
||||
|
||||
public abstract String getIcon(FileEntry entry, boolean open);
|
||||
public abstract String getIcon(FileEntry entry);
|
||||
|
||||
public static class Simple extends BrowserIconDirectoryType {
|
||||
|
||||
|
@ -92,13 +88,11 @@ public abstract class BrowserIconDirectoryType {
|
|||
private final String id;
|
||||
|
||||
private final IconVariant closed;
|
||||
private final IconVariant open;
|
||||
private final Set<String> names;
|
||||
|
||||
public Simple(String id, IconVariant closed, IconVariant open, Set<String> names) {
|
||||
public Simple(String id, IconVariant closed, Set<String> names) {
|
||||
this.id = id;
|
||||
this.closed = closed;
|
||||
this.open = open;
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
|
@ -113,8 +107,8 @@ public abstract class BrowserIconDirectoryType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getIcon(FileEntry entry, boolean open) {
|
||||
return open ? this.open.getIcon() : this.closed.getIcon();
|
||||
public String getIcon(FileEntry entry) {
|
||||
return this.closed.getIcon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,8 +47,8 @@ public abstract class BrowserIconFileType {
|
|||
return "." + r;
|
||||
})
|
||||
.collect(Collectors.toSet());
|
||||
var darkIcon = split[2].trim();
|
||||
var lightIcon = split.length > 3 ? split[3].trim() : darkIcon;
|
||||
var darkIcon = "browser/" + split[2].trim();
|
||||
var lightIcon = (split.length > 3 ? "browser/" + split[3].trim() : darkIcon);
|
||||
ALL.add(new BrowserIconFileType.Simple(id, lightIcon, darkIcon, filter));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,11 @@ import io.xpipe.core.store.FileEntry;
|
|||
public class BrowserIcons {
|
||||
|
||||
public static Comp<?> createDefaultFileIcon() {
|
||||
return PrettyImageHelper.ofFixedSizeSquare("default_file.svg", 24);
|
||||
return PrettyImageHelper.ofFixedSizeSquare("browser/default_file.svg", 24);
|
||||
}
|
||||
|
||||
public static Comp<?> createDefaultDirectoryIcon() {
|
||||
return PrettyImageHelper.ofFixedSizeSquare("default_folder.svg", 24);
|
||||
return PrettyImageHelper.ofFixedSizeSquare("browser/default_folder.svg", 24);
|
||||
}
|
||||
|
||||
public static Comp<?> createIcon(BrowserIconFileType type) {
|
||||
|
@ -19,6 +19,6 @@ public class BrowserIcons {
|
|||
}
|
||||
|
||||
public static Comp<?> createIcon(FileEntry entry) {
|
||||
return PrettyImageHelper.ofFixedSizeSquare(FileIconManager.getFileIcon(entry, false), 24);
|
||||
return PrettyImageHelper.ofFixedSizeSquare(FileIconManager.getFileIcon(entry), 24);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package io.xpipe.app.browser.icon;
|
||||
|
||||
import io.xpipe.app.resources.AppImages;
|
||||
import io.xpipe.app.resources.AppResources;
|
||||
import io.xpipe.core.store.FileEntry;
|
||||
import io.xpipe.core.store.FileKind;
|
||||
|
||||
|
@ -13,12 +11,11 @@ public class FileIconManager {
|
|||
if (!loaded) {
|
||||
BrowserIconFileType.loadDefinitions();
|
||||
BrowserIconDirectoryType.loadDefinitions();
|
||||
AppImages.loadDirectory(AppResources.XPIPE_MODULE, "img/browser", true, false);
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized String getFileIcon(FileEntry entry, boolean open) {
|
||||
public static synchronized String getFileIcon(FileEntry entry) {
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -33,13 +30,13 @@ public class FileIconManager {
|
|||
} else {
|
||||
for (var f : BrowserIconDirectoryType.getAll()) {
|
||||
if (f.matches(r)) {
|
||||
return f.getIcon(r, open);
|
||||
return f.getIcon(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return r.getKind() == FileKind.DIRECTORY
|
||||
? (open ? "default_folder_opened.svg" : "default_folder.svg")
|
||||
: "default_file.svg";
|
||||
return "browser/" + (r.getKind() == FileKind.DIRECTORY
|
||||
? "default_folder.svg"
|
||||
: "default_file.svg");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,15 +9,15 @@ import io.xpipe.app.storage.DataStorage;
|
|||
import io.xpipe.app.storage.DataStoreCategory;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
|
||||
import javafx.beans.property.*;
|
||||
import javafx.collections.FXCollections;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
public class StoreEntryWrapper {
|
||||
|
@ -40,7 +40,8 @@ public class StoreEntryWrapper {
|
|||
private final Property<StoreCategoryWrapper> category = new SimpleObjectProperty<>();
|
||||
private final Property<String> summary = new SimpleObjectProperty<>();
|
||||
private final Property<StoreNotes> notes;
|
||||
private final Property<String> icon = new SimpleObjectProperty<>();
|
||||
private final Property<String> customIcon = new SimpleObjectProperty<>();
|
||||
private final Property<String> iconFile = new SimpleObjectProperty<>();
|
||||
|
||||
public StoreEntryWrapper(DataStoreEntry entry) {
|
||||
this.entry = entry;
|
||||
|
@ -138,7 +139,8 @@ public class StoreEntryWrapper {
|
|||
}
|
||||
color.setValue(entry.getColor());
|
||||
notes.setValue(new StoreNotes(entry.getNotes(), entry.getNotes()));
|
||||
icon.setValue(entry.getIcon());
|
||||
customIcon.setValue(entry.getIcon());
|
||||
iconFile.setValue(getEffectiveIconFile());
|
||||
|
||||
busy.setValue(entry.getBusyCounter().get() != 0);
|
||||
deletable.setValue(entry.getConfiguration().isDeletable()
|
||||
|
@ -192,6 +194,20 @@ public class StoreEntryWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
private String getEffectiveIconFile() {
|
||||
if (disabledProperty().get()) {
|
||||
return "disabled_icon.png";
|
||||
}
|
||||
|
||||
if (getCustomIcon().getValue() == null) {
|
||||
return getEntry()
|
||||
.getProvider()
|
||||
.getDisplayIconFileName(getEntry().getStore());
|
||||
}
|
||||
|
||||
return "app:system/" + getCustomIcon().getValue() + ".svg";
|
||||
}
|
||||
|
||||
private boolean showActionProvider(ActionProvider p) {
|
||||
var leaf = p.getLeafDataStoreCallSite();
|
||||
if (leaf != null) {
|
||||
|
|
|
@ -137,7 +137,7 @@ public class StoreIconChoiceComp extends SimpleComp {
|
|||
}
|
||||
|
||||
root.setText(icon.getDisplayName());
|
||||
image.set(icon.getIconName() + ".svg");
|
||||
image.set("app:system/" + icon.getIconName() + ".svg");
|
||||
setGraphic(root);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import java.util.List;
|
|||
public class StoreIconChoiceDialogComp extends SimpleComp {
|
||||
|
||||
public static void show(DataStoreEntry entry) {
|
||||
SystemIcons.load();
|
||||
var window = AppWindowHelper.sideWindow(
|
||||
AppI18n.get("chooseCustomIcon"), stage -> new StoreIconChoiceDialogComp(entry, stage), false, null);
|
||||
window.initModality(Modality.APPLICATION_MODAL);
|
||||
|
|
|
@ -3,15 +3,12 @@ package io.xpipe.app.comp.store;
|
|||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.impl.PrettyImageHelper;
|
||||
import io.xpipe.app.fxcomps.impl.TooltipAugment;
|
||||
import io.xpipe.app.resources.SystemIcons;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.StackPane;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.kordamp.ikonli.javafx.FontIcon;
|
||||
|
||||
|
@ -24,12 +21,7 @@ public class StoreIconComp extends SimpleComp {
|
|||
|
||||
@Override
|
||||
protected Region createSimple() {
|
||||
var icon = Bindings.createStringBinding(
|
||||
() -> {
|
||||
return getImage();
|
||||
},
|
||||
wrapper.getIcon());
|
||||
var imageComp = PrettyImageHelper.ofFixedSize(icon, w, h);
|
||||
var imageComp = PrettyImageHelper.ofFixedSize(wrapper.getIconFile(), w, h);
|
||||
var storeIcon = imageComp.createRegion();
|
||||
if (wrapper.getValidity().getValue().isUsable()) {
|
||||
new TooltipAugment<>(wrapper.getEntry().getProvider().displayName(), null).augment(storeIcon);
|
||||
|
@ -67,19 +59,4 @@ public class StoreIconComp extends SimpleComp {
|
|||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private String getImage() {
|
||||
if (wrapper.disabledProperty().get()) {
|
||||
return "disabled_icon.png";
|
||||
}
|
||||
|
||||
if (wrapper.getIcon().getValue() == null) {
|
||||
return wrapper.getEntry()
|
||||
.getProvider()
|
||||
.getDisplayIconFileName(wrapper.getEntry().getStore());
|
||||
}
|
||||
|
||||
SystemIcons.load();
|
||||
return "app:system/" + wrapper.getIcon().getValue() + ".svg";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
package io.xpipe.app.core.check;
|
||||
|
||||
import io.xpipe.app.comp.base.MarkdownComp;
|
||||
import io.xpipe.app.core.*;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.core.AppState;
|
||||
import io.xpipe.app.core.AppStyle;
|
||||
import io.xpipe.app.core.mode.OperationMode;
|
||||
import io.xpipe.app.core.window.AppWindowHelper;
|
||||
import io.xpipe.app.resources.AppImages;
|
||||
import io.xpipe.app.resources.AppResources;
|
||||
import io.xpipe.app.util.PlatformState;
|
||||
import io.xpipe.app.util.WindowsRegistry;
|
||||
import io.xpipe.core.process.OsType;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonBar;
|
||||
import javafx.scene.control.ButtonType;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.nio.file.Files;
|
||||
|
@ -44,7 +44,6 @@ public class AppAvCheck {
|
|||
|
||||
PlatformState.initPlatformOrThrow();
|
||||
AppStyle.init();
|
||||
AppImages.init();
|
||||
|
||||
var a = AppWindowHelper.showBlockingAlert(alert -> {
|
||||
alert.setTitle(AppI18n.get("antivirusNoticeTitle"));
|
||||
|
|
|
@ -4,6 +4,7 @@ import io.xpipe.app.browser.file.LocalFileSystem;
|
|||
import io.xpipe.app.browser.icon.FileIconManager;
|
||||
import io.xpipe.app.core.App;
|
||||
import io.xpipe.app.core.AppGreetings;
|
||||
import io.xpipe.app.core.AppLayoutModel;
|
||||
import io.xpipe.app.core.check.AppPtbCheck;
|
||||
import io.xpipe.app.core.window.AppMainWindow;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
|
@ -12,7 +13,6 @@ import io.xpipe.app.issue.TrackEvent;
|
|||
import io.xpipe.app.update.UpdateChangelogAlert;
|
||||
import io.xpipe.app.util.NativeBridge;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class GuiMode extends PlatformMode {
|
||||
|
@ -39,6 +39,7 @@ public class GuiMode extends PlatformMode {
|
|||
AppGreetings.showIfNeeded();
|
||||
AppPtbCheck.check();
|
||||
NativeBridge.init();
|
||||
AppLayoutModel.init();
|
||||
|
||||
TrackEvent.info("Waiting for window setup completion ...");
|
||||
PlatformThread.runLaterIfNeededBlocking(() -> {
|
||||
|
|
|
@ -9,7 +9,6 @@ import io.xpipe.app.resources.AppImages;
|
|||
import io.xpipe.app.update.UpdateAvailableAlert;
|
||||
import io.xpipe.app.util.PlatformState;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
|
||||
import javafx.application.Application;
|
||||
|
||||
public abstract class PlatformMode extends OperationMode {
|
||||
|
@ -30,11 +29,13 @@ public abstract class PlatformMode extends OperationMode {
|
|||
PlatformState.initPlatformOrThrow();
|
||||
// Check if we can load system fonts or fail
|
||||
AppFontLoadingCheck.check();
|
||||
// Can be loaded async
|
||||
var imageThread = ThreadHelper.runFailableAsync(() -> {
|
||||
AppImages.init();
|
||||
});
|
||||
AppFont.init();
|
||||
AppTheme.init();
|
||||
AppStyle.init();
|
||||
AppImages.init();
|
||||
AppLayoutModel.init();
|
||||
TrackEvent.info("Finished essential component initialization before platform");
|
||||
|
||||
TrackEvent.info("Launching application ...");
|
||||
|
@ -57,6 +58,7 @@ public abstract class PlatformMode extends OperationMode {
|
|||
}
|
||||
|
||||
StoreViewState.init();
|
||||
imageThread.join();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -216,7 +216,6 @@ public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
|
|||
selected.getValue().getStore());
|
||||
}
|
||||
|
||||
SystemIcons.load();
|
||||
return "app:system/"
|
||||
+ selected.getValue().get().getIcon() + ".svg";
|
||||
},
|
||||
|
|
|
@ -3,10 +3,8 @@ package io.xpipe.app.resources;
|
|||
import io.xpipe.app.core.AppExtensionManager;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.WritableImage;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
@ -16,6 +14,8 @@ import java.nio.file.Files;
|
|||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -37,6 +37,7 @@ public class AppImages {
|
|||
}
|
||||
|
||||
public static void loadDirectory(String module, String dir, boolean loadImages, boolean loadSvgs) {
|
||||
var start = Instant.now();
|
||||
AppResources.with(module, dir, basePath -> {
|
||||
if (!Files.exists(basePath)) {
|
||||
return;
|
||||
|
@ -49,12 +50,17 @@ public class AppImages {
|
|||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
var relativeFileName = FilenameUtils.separatorsToUnix(
|
||||
basePath.relativize(file).toString());
|
||||
var key = defaultPrefix + relativeFileName;
|
||||
if (images.containsKey(key) || svgImages.containsKey(key)) {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
try {
|
||||
if (FilenameUtils.getExtension(file.toString()).equals("svg") && loadSvgs) {
|
||||
var s = Files.readString(file);
|
||||
svgImages.put(defaultPrefix + relativeFileName, s);
|
||||
svgImages.put(key, s);
|
||||
} else if (loadImages) {
|
||||
images.put(defaultPrefix + relativeFileName, loadImage(file));
|
||||
images.put(key, loadImage(file));
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ErrorEvent.fromThrowable(ex).omitted(true).build().handle();
|
||||
|
@ -63,6 +69,8 @@ public class AppImages {
|
|||
}
|
||||
});
|
||||
});
|
||||
var elapsed = Duration.between(start, Instant.now());
|
||||
TrackEvent.trace("Loaded images in " + module + ":" + dir + " in " + elapsed.toMillis() + " ms");
|
||||
}
|
||||
|
||||
public static String svgImage(String file) {
|
||||
|
|
|
@ -172,6 +172,20 @@ public class DataStoreEntry extends StorageElement {
|
|||
return entry;
|
||||
}
|
||||
|
||||
|
||||
public String getEffectiveIconFile() {
|
||||
if (getValidity() == Validity.LOAD_FAILED) {
|
||||
return "disabled_icon.png";
|
||||
}
|
||||
|
||||
if (icon == null) {
|
||||
return getProvider()
|
||||
.getDisplayIconFileName(getStore());
|
||||
}
|
||||
|
||||
return "app:system/" + icon + ".svg";
|
||||
}
|
||||
|
||||
void refreshIcon() {
|
||||
if (icon != null && SystemIcons.getForId(icon).isEmpty()) {
|
||||
icon = null;
|
||||
|
|
Loading…
Reference in a new issue