Skip to content

Commit

Permalink
Handle image icons properly with hashSum checking etc.
Browse files Browse the repository at this point in the history
  • Loading branch information
ToxicStoxm committed Feb 18, 2025
1 parent ac2eae4 commit dd4d803
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 32 deletions.
9 changes: 7 additions & 2 deletions src/main/java/com/toxicstoxm/LEDSuite/tools/YamlTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.toxicstoxm.LEDSuite.communication.packet_management.DeserializationException;
import com.toxicstoxm.LEDSuite.communication.packet_management.packets.errors.ErrorCode;
import com.toxicstoxm.LEDSuite.ui.HashSumCallable;
import com.toxicstoxm.YAJL.Logger;
import com.toxicstoxm.YAJSI.api.yaml.ConfigurationSection;
import io.github.jwharm.javagi.base.GErrorException;
Expand All @@ -12,6 +13,7 @@
import org.jetbrains.annotations.NotNull;

import java.util.Base64;
import java.util.Objects;

/**
* A utility class providing methods for interacting with YAML configuration sections.
Expand Down Expand Up @@ -147,13 +149,16 @@ public static long getLongIfAvailable(String key, long defaultValue, @NotNull Co
* @param iconIsName true if {@code iconString} should be treated as name, otherwise {@code false}
* @return the constructed {@link Image} or a 'broken image' if something went wrong or the name/base64 was invalid.
*/
public static Image constructIcon(String iconString, boolean iconIsName) {
public static Image constructIcon(String iconString, boolean iconIsName, String iconHash, HashSumCallable newIcon) {
Image finalImage = Image.fromIconName("");
if (iconIsName) {
finalImage = Image.fromIconName(iconString);
} else {
byte[] decodedBytes = Base64.getDecoder().decode(iconString);
try {
if (Objects.equals(newIcon.getHashSum(), iconHash)) return null;

byte[] decodedBytes = Base64.getDecoder().decode(iconString);

finalImage = Image.fromPaintable(Texture.fromBytes(Bytes.static_(decodedBytes)));
} catch (GErrorException e) {
logger.warn("Failed to decode icon from base64! Error message: '{}'!", e.getMessage());
Expand Down
54 changes: 34 additions & 20 deletions src/main/java/com/toxicstoxm/LEDSuite/ui/AnimationRow.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.toxicstoxm.LEDSuite.communication.packet_management.packets.requests.MenuRequestPacket;
import com.toxicstoxm.LEDSuite.time.CooldownManager;
import com.toxicstoxm.LEDSuite.tools.YamlTools;
import com.toxicstoxm.LEDSuite.ui.animation_menu.AnimationMenuReference;
import com.toxicstoxm.LEDSuite.ui.dialogs.alert_dialogs.ErrorData;
import com.toxicstoxm.YAJL.Logger;
import io.github.jwharm.javagi.gtk.annotations.GtkChild;
import io.github.jwharm.javagi.gtk.annotations.GtkTemplate;
Expand All @@ -18,6 +20,10 @@
import org.jetbrains.annotations.NotNull;

import java.lang.foreign.MemorySegment;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.atomic.AtomicReference;

/**
* Represents a row in the sidebar of the application, displaying information about a single animation.
Expand Down Expand Up @@ -66,19 +72,7 @@ public AnimationRow(MemorySegment address) {
@GtkChild(name = "animation_icon")
public Image animationIcon;

/**
* Sets the animation icons paintable or icon name depending on the provided icons structure.
*
* @param icon the new icon to use
*/
public final void setIcon(@NotNull Image icon) {
ImageType storageType = icon.getStorageType();
if (storageType == ImageType.EMPTY || storageType == ImageType.ICON_NAME) {
animationIcon.setFromIconName(icon.getIconName());
} else {
animationIcon.setFromPaintable(icon.getPaintable());
}
}
private String iconHash = "";

/**
* The {@link Label} widget used to display the animation's label.
Expand Down Expand Up @@ -121,7 +115,7 @@ public final void setAnimationLabel(String animationLabel) {
// Instantiate and configure the AnimationRow with the provided data.
AnimationRow row = GObject.newInstance(AnimationRow.class, "action-name", "app." + animationRowData.animationID());
row.animationID = animationRowData.animationID();
row.setIcon(animationRowData.icon());
row.update(null, animationRowData.iconString(), animationRowData.iconIsName(), null);
row.setLastAccessed(animationRowData.lastAccessed());
row.setAnimationLabel(animationRowData.label().strip());
row.animationRowLabel.setWrap(true); // Allow label to wrap if it's too long
Expand All @@ -138,18 +132,38 @@ public final void setAnimationLabel(String animationLabel) {
* This method can be called to refresh the row's display.
*
* @param label The new label to display.
* @param iconName The new icon name to display.
* @param iconString The new icon string.
* @param lastAccessed The last time this animation was accessed
*/
public void update(String label, String iconName, Long lastAccessed) {
animationRowLabel.setLabel(label);
animationIcon.setFromIconName(iconName);
setLastAccessed(lastAccessed);
public void update(String label, String iconString, boolean isName, Long lastAccessed) {
if (label != null) animationRowLabel.setLabel(label);
AtomicReference<String> newIconHash = new AtomicReference<>("");
Image newIcon = YamlTools.constructIcon(iconString, isName, iconHash, () -> {
try {
newIconHash.set(new String(MessageDigest.getInstance("md5").digest(iconString.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8));
} catch (NoSuchAlgorithmException e) {
LEDSuiteApplication.handleError(ErrorData.builder()
.logger(logger)
.message(logger.format("Failed to get hashSum algorithm 'md5' for computing icon hashSum within {}(ID:{})", getClass().getSimpleName(), getAnimationID()))
.heading("Error while receiving status update")
.build());
}
return newIconHash.get();
});
if (newIcon != null) {
if (isName) {
animationIcon.setFromIconName(newIcon.getIconName());
} else {
animationIcon.setFromPaintable(newIcon.getPaintable());
}
iconHash = newIconHash.get();
}
if (lastAccessed != null) setLastAccessed(lastAccessed);

// If the row is part of a menu, update the menu as well.
if (animationMenuReference != null) {
animationMenuReference.updateLabel(label);
animationMenuReference.updateIconName(iconName);
animationMenuReference.updateIcon(newIcon);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.toxicstoxm.LEDSuite.time.Action;
import lombok.Builder;
import org.gnome.gtk.Application;
import org.gnome.gtk.Image;
import org.jetbrains.annotations.NotNull;

/**
Expand All @@ -17,7 +16,8 @@
* @since 1.0.0
*
* @param app The main {@link Application} instance for the GTK application. This is used to associate the row with the application.
* @param icon The GTK name or base64 encoded image file of the icon to represent the animation.
* @param iconString The GTK name or base64 encoded image file of the icon to represent the animation.
* @param iconIsName If the above param is base64 or an icon name.
* @param label The name or description of the animation. This text is displayed on the animation row.
* @param animationID The unique identifier for the animation. This could be the animation's ID or the filename associated with it.
* @param action The action associated with this animation, typically used to handle interactions like button clicks. This is typically a unique action name used to trigger specific behavior.
Expand All @@ -26,7 +26,8 @@
@Builder
public record AnimationRowData(
@NotNull Application app,
Image icon,
String iconString,
boolean iconIsName,
String label,
String animationID,
Action action,
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/toxicstoxm/LEDSuite/ui/HashSumCallable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.toxicstoxm.LEDSuite.ui;

@FunctionalInterface
public interface HashSumCallable {
String getHashSum();
}
6 changes: 3 additions & 3 deletions src/main/java/com/toxicstoxm/LEDSuite/ui/LEDSuiteWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.toxicstoxm.LEDSuite.formatting.StringFormatter;
import com.toxicstoxm.LEDSuite.gettext.Translations;
import com.toxicstoxm.LEDSuite.task_scheduler.LEDSuiteRunnable;
import com.toxicstoxm.LEDSuite.tools.YamlTools;
import com.toxicstoxm.LEDSuite.ui.animation_menu.AnimationMenu;
import com.toxicstoxm.LEDSuite.ui.dialogs.alert_dialogs.FileCollisionDialog;
import com.toxicstoxm.LEDSuite.ui.dialogs.alert_dialogs.OverwriteConfirmationDialog;
Expand Down Expand Up @@ -316,7 +315,7 @@ public void updateAnimations(@NotNull Collection<StatusReplyPacket.Animation> up

// Update the animation row with new data
GLib.idleAddOnce(() -> {
animationRow.update(updatedAnimation.label(), updatedAnimation.iconString(), updatedAnimation.lastAccessed());
animationRow.update(updatedAnimation.label(), updatedAnimation.iconString(), updatedAnimation.iconIsName(), updatedAnimation.lastAccessed());
logger.verbose("Updated animation: {}", newAnimationName);
});

Expand All @@ -333,7 +332,8 @@ public void updateAnimations(@NotNull Collection<StatusReplyPacket.Animation> up
var newAnimationRow = AnimationRow.create(
AnimationRowData.builder()
.app(getApplication())
.icon(YamlTools.constructIcon(updatedAnimation.iconString(), updatedAnimation.iconIsName()))
.iconString(updatedAnimation.iconString())
.iconIsName(updatedAnimation.iconIsName())
.label(updatedAnimation.label())
.animationID(updatedAnimation.id())
.cooldown(500L)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,15 @@ public void updateLabel(String label) {
}

@Override
public void updateIconName(String iconName) {
public void updateIcon(Image icon) {
GLib.idleAddOnce(() -> {
if (iconName != null) {
animationMenuImage.setFromIconName(iconName);
if (icon != null) {
ImageType storageType = icon.getStorageType();
if (storageType == ImageType.EMPTY || storageType == ImageType.ICON_NAME) {
animationMenuImage.setFromIconName(icon.getIconName());
} else {
animationMenuImage.setFromPaintable(icon.getPaintable());
}
}
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.toxicstoxm.LEDSuite.ui.animation_menu;

import org.gnome.gtk.Image;

/**
* Add interface to hold reference to an {@link AnimationMenu}'s update methods.
* @since 1.0.0
*/
public interface AnimationMenuReference {
void updateLabel(String label);
void updateIconName(String iconName);
void updateIcon(Image iconName);
}

0 comments on commit dd4d803

Please sign in to comment.