From 3c7f2da752c3a660a0e21bd4c42fe93a5e965996 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 10 Oct 2020 14:31:10 +0200 Subject: [PATCH 1/2] Add image caching --- .../envoy/client/ui/controller/ChatScene.java | 10 ++-- .../main/java/envoy/client/util/IconUtil.java | 46 +++++++++++++++---- client/src/main/resources/fxml/ChatScene.fxml | 2 +- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/client/src/main/java/envoy/client/ui/controller/ChatScene.java b/client/src/main/java/envoy/client/ui/controller/ChatScene.java index da4323e..c2b0ef1 100644 --- a/client/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -132,7 +132,6 @@ public final class ChatScene implements EventListener, Restorable { private Chat currentChat; private FilteredList chats; - private boolean recording; private Attachment pendingAttachment; private boolean postingPermanentlyDisabled; private boolean isCustomAttachmentImage; @@ -354,7 +353,8 @@ public final class ChatScene implements EventListener, Restorable { // Discard the pending attachment if (recorder.isRecording()) { recorder.cancel(); - recording = false; + voiceButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("microphone", DEFAULT_ICON_SIZE))); + voiceButton.setText(null); } pendingAttachment = null; updateAttachmentView(false); @@ -414,18 +414,16 @@ public final class ChatScene implements EventListener, Restorable { private void voiceButtonClicked() { new Thread(() -> { try { - if (!recording) { - recording = true; + if (!recorder.isRecording()) { Platform.runLater(() -> { voiceButton.setText("Recording"); voiceButton.setGraphic(new ImageView(IconUtil.loadIcon("microphone_recording", DEFAULT_ICON_SIZE))); }); recorder.start(); } else { - pendingAttachment = new Attachment(recorder.finish(), "Voice_recording_" + pendingAttachment = new Attachment(recorder.finish(), "Voice_recording_" + DateTimeFormatter.ofPattern("yyyy_MM_dd-HH_mm_ss").format(LocalDateTime.now()) + "." + AudioRecorder.FILE_FORMAT, AttachmentType.VOICE); - recording = false; Platform.runLater(() -> { voiceButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("microphone", DEFAULT_ICON_SIZE))); voiceButton.setText(null); diff --git a/client/src/main/java/envoy/client/util/IconUtil.java b/client/src/main/java/envoy/client/util/IconUtil.java index 42a8554..39dce33 100644 --- a/client/src/main/java/envoy/client/util/IconUtil.java +++ b/client/src/main/java/envoy/client/util/IconUtil.java @@ -21,8 +21,11 @@ import envoy.util.EnvoyLog; */ public final class IconUtil { - private IconUtil() {} + private static final HashMap cache = new HashMap<>(); + private static final HashMap awtCache = new HashMap<>(); + private IconUtil() {} + /** * Loads an image from the resource folder. * @@ -30,7 +33,14 @@ public final class IconUtil { * @return the loaded image * @since Envoy Client v0.1-beta */ - public static Image load(String path) { return new Image(IconUtil.class.getResource(path).toExternalForm()); } + public static Image load(String path) { + if (cache.containsKey(path)) return cache.get(path); + else { + final var image = new Image(IconUtil.class.getResource(path).toExternalForm()); + cache.put(path, image); + return image; + } + } /** * Loads an image from the resource folder and scales it to the given size. @@ -39,9 +49,21 @@ public final class IconUtil { * @param size the size to scale the icon to * @return the scaled image * @since Envoy Client v0.1-beta + * @apiNote There is an extraordinarily low chance that there is a size and name + * conflict. To achieve that however, you basically have to name your + * image intentionally like that. For normal human readable names or + * even automatically generated ones it will never occur. */ public static Image load(String path, int size) { - return new Image(IconUtil.class.getResource(path).toExternalForm(), size, size, true, true); + + // Minimizing the risk of size and name conflict + final var sizeSpecificString = path + size + "+a* "; + if (cache.containsKey(sizeSpecificString)) return cache.get(sizeSpecificString); + else { + final var image = new Image(IconUtil.class.getResource(path).toExternalForm(), size, size, true, true); + cache.put(sizeSpecificString, image); + return image; + } } /** @@ -138,13 +160,19 @@ public final class IconUtil { * @since Envoy Client v0.2-beta */ public static BufferedImage loadAWTCompatible(String path) { - BufferedImage image = null; - try { - image = ImageIO.read(IconUtil.class.getResource(path)); - } catch (final IOException e) { - EnvoyLog.getLogger(IconUtil.class).log(Level.WARNING, String.format("Could not load image at path %s: ", path), e); + if (awtCache.containsKey(path)) return awtCache.get(path); + else { + BufferedImage image = null; + try { + image = ImageIO.read(IconUtil.class.getResource(path)); + } catch (final IOException e) { + EnvoyLog.getLogger(IconUtil.class).log(Level.WARNING, String.format("Could not load image at path %s: ", path), e); + } + + // If an IOException occurs we don't assume it'll be fixed on the next call + awtCache.put(path, image); + return image; } - return image; } /** diff --git a/client/src/main/resources/fxml/ChatScene.fxml b/client/src/main/resources/fxml/ChatScene.fxml index ec6db63..d3fb6e9 100644 --- a/client/src/main/resources/fxml/ChatScene.fxml +++ b/client/src/main/resources/fxml/ChatScene.fxml @@ -175,7 +175,7 @@ - + -- 2.30.2 From cbc4d1f534ef59cf64c50f78c130dbbfb37dcd21 Mon Sep 17 00:00:00 2001 From: kske Date: Mon, 12 Oct 2020 15:04:08 +0200 Subject: [PATCH 2/2] Simplify image caching --- .../main/java/envoy/client/util/IconUtil.java | 44 +++++-------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/client/src/main/java/envoy/client/util/IconUtil.java b/client/src/main/java/envoy/client/util/IconUtil.java index 39dce33..3445b42 100644 --- a/client/src/main/java/envoy/client/util/IconUtil.java +++ b/client/src/main/java/envoy/client/util/IconUtil.java @@ -22,10 +22,11 @@ import envoy.util.EnvoyLog; public final class IconUtil { private static final HashMap cache = new HashMap<>(); + private static final HashMap scaledCache = new HashMap<>(); private static final HashMap awtCache = new HashMap<>(); private IconUtil() {} - + /** * Loads an image from the resource folder. * @@ -33,14 +34,7 @@ public final class IconUtil { * @return the loaded image * @since Envoy Client v0.1-beta */ - public static Image load(String path) { - if (cache.containsKey(path)) return cache.get(path); - else { - final var image = new Image(IconUtil.class.getResource(path).toExternalForm()); - cache.put(path, image); - return image; - } - } + public static Image load(String path) { return cache.computeIfAbsent(path, p -> new Image(IconUtil.class.getResource(p).toExternalForm())); } /** * Loads an image from the resource folder and scales it to the given size. @@ -49,26 +43,15 @@ public final class IconUtil { * @param size the size to scale the icon to * @return the scaled image * @since Envoy Client v0.1-beta - * @apiNote There is an extraordinarily low chance that there is a size and name - * conflict. To achieve that however, you basically have to name your - * image intentionally like that. For normal human readable names or - * even automatically generated ones it will never occur. */ public static Image load(String path, int size) { - - // Minimizing the risk of size and name conflict - final var sizeSpecificString = path + size + "+a* "; - if (cache.containsKey(sizeSpecificString)) return cache.get(sizeSpecificString); - else { - final var image = new Image(IconUtil.class.getResource(path).toExternalForm(), size, size, true, true); - cache.put(sizeSpecificString, image); - return image; - } + return scaledCache.computeIfAbsent(path + size, p -> new Image(IconUtil.class.getResource(path).toExternalForm(), size, size, true, true)); } /** * Loads a {@code .png} image from the sub-folder {@code /icons/} of the - * resource folder.
+ * resource folder. + *

* The suffix {@code .png} is automatically appended. * * @param name the image name without the .png suffix @@ -160,19 +143,14 @@ public final class IconUtil { * @since Envoy Client v0.2-beta */ public static BufferedImage loadAWTCompatible(String path) { - if (awtCache.containsKey(path)) return awtCache.get(path); - else { - BufferedImage image = null; + return awtCache.computeIfAbsent(path, p -> { try { - image = ImageIO.read(IconUtil.class.getResource(path)); - } catch (final IOException e) { + return ImageIO.read(IconUtil.class.getResource(path)); + } catch (IOException e) { EnvoyLog.getLogger(IconUtil.class).log(Level.WARNING, String.format("Could not load image at path %s: ", path), e); + return null; } - - // If an IOException occurs we don't assume it'll be fixed on the next call - awtCache.put(path, image); - return image; - } + }); } /** -- 2.30.2