Merge pull request #178 from informatik-ag-ngl/f/more_icons
Added multiple (recording) icons and change them on recording. Updated and simplified IconUtil API. Dismissed rethrowing of image loading error.
@@ -25,7 +25,7 @@ import envoy.util.SerializationUtils;
 | 
				
			|||||||
public class Settings {
 | 
					public class Settings {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Actual settings accessible by the rest of the application
 | 
						// Actual settings accessible by the rest of the application
 | 
				
			||||||
	private Map<String, SettingsItem<?>>	items;
 | 
						private Map<String, SettingsItem<?>> items;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Settings are stored in this file.
 | 
						 * Settings are stored in this file.
 | 
				
			||||||
@@ -93,6 +93,15 @@ public class Settings {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void setCurrentTheme(String themeName) { ((SettingsItem<String>) items.get("currentTheme")).set(themeName); }
 | 
						public void setCurrentTheme(String themeName) { ((SettingsItem<String>) items.get("currentTheme")).set(themeName); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @return true if the currently used theme is one of the default themes
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public boolean isUsingDefaultTheme() {
 | 
				
			||||||
 | 
							final var theme = getCurrentTheme();
 | 
				
			||||||
 | 
							return theme.equals("dark") || theme.equals("light");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @return {@code true}, if pressing the {@code Enter} key suffices to send a
 | 
						 * @return {@code true}, if pressing the {@code Enter} key suffices to send a
 | 
				
			||||||
	 *         message. Otherwise it has to be pressed in conjunction with the
 | 
						 *         message. Otherwise it has to be pressed in conjunction with the
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,8 +11,6 @@ import javafx.scene.layout.Background;
 | 
				
			|||||||
import javafx.scene.layout.ColumnConstraints;
 | 
					import javafx.scene.layout.ColumnConstraints;
 | 
				
			||||||
import javafx.scene.layout.GridPane;
 | 
					import javafx.scene.layout.GridPane;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.Settings;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This class offers a text field that is automatically equipped with a clear
 | 
					 * This class offers a text field that is automatically equipped with a clear
 | 
				
			||||||
 * button.
 | 
					 * button.
 | 
				
			||||||
@@ -49,10 +47,7 @@ public class ClearableTextField extends GridPane {
 | 
				
			|||||||
	public ClearableTextField(String text, int size) {
 | 
						public ClearableTextField(String text, int size) {
 | 
				
			||||||
		// initializing the textField and the button
 | 
							// initializing the textField and the button
 | 
				
			||||||
		textField	= new TextField(text);
 | 
							textField	= new TextField(text);
 | 
				
			||||||
		clearButton	= new Button("",
 | 
							clearButton	= new Button("", new ImageView(IconUtil.loadIconThemeSensitive("clear_button", size)));
 | 
				
			||||||
				new ImageView(IconUtil.load(
 | 
					 | 
				
			||||||
						Settings.getInstance().getCurrentTheme().equals("dark") ? "/icons/clear_button_white.png" : "/icons/clear_button_black.png",
 | 
					 | 
				
			||||||
						size)));
 | 
					 | 
				
			||||||
		clearButton.setOnAction(e -> textField.clear());
 | 
							clearButton.setOnAction(e -> textField.clear());
 | 
				
			||||||
		clearButton.setFocusTraversable(false);
 | 
							clearButton.setFocusTraversable(false);
 | 
				
			||||||
		clearButton.getStyleClass().clear();
 | 
							clearButton.getStyleClass().clear();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,9 +2,13 @@ package envoy.client.ui;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import java.util.EnumMap;
 | 
					import java.util.EnumMap;
 | 
				
			||||||
import java.util.EnumSet;
 | 
					import java.util.EnumSet;
 | 
				
			||||||
 | 
					import java.util.logging.Level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.scene.image.Image;
 | 
					import javafx.scene.image.Image;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import envoy.client.data.Settings;
 | 
				
			||||||
 | 
					import envoy.util.EnvoyLog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Provides static utility methods for loading icons from the resource
 | 
					 * Provides static utility methods for loading icons from the resource
 | 
				
			||||||
 * folder.
 | 
					 * folder.
 | 
				
			||||||
@@ -21,37 +25,115 @@ public class IconUtil {
 | 
				
			|||||||
	private IconUtil() {}
 | 
						private IconUtil() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Loads an icon from the resource folder.
 | 
						 * Loads an image from the resource folder.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @param path the path to the icon inside the resource folder
 | 
						 * @param path the path to the icon inside the resource folder
 | 
				
			||||||
	 * @return the icon
 | 
						 * @return the loaded image
 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
						 * @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) {
 | 
				
			||||||
 | 
							Image image = null;
 | 
				
			||||||
	/**
 | 
							try {
 | 
				
			||||||
	 * Loads an icon from the resource folder and scales it to a given size.
 | 
								image = new Image(IconUtil.class.getResource(path).toExternalForm());
 | 
				
			||||||
	 *
 | 
							} catch (final NullPointerException e) {
 | 
				
			||||||
	 * @param path the path to the icon inside the resource folder
 | 
								EnvoyLog.getLogger(IconUtil.class).log(Level.WARNING, String.format("Could not load image at path %s: ", path), e);
 | 
				
			||||||
	 * @param size the size to scale the icon to
 | 
							}
 | 
				
			||||||
	 * @return the scaled icon
 | 
							return image;
 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public static Image load(String path, int size) {
 | 
					 | 
				
			||||||
		return new Image(IconUtil.class.getResource(path).toExternalForm(), size, size, true, true);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
 | 
						 * Loads an image from the resource folder and scales it to the given size.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * Loads icons specified by an enum. The images have to be named like the
 | 
						 * @param path the path to the icon inside the resource folder
 | 
				
			||||||
 | 
						 * @param size the size to scale the icon to
 | 
				
			||||||
 | 
						 * @return the scaled image
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static Image load(String path, int size) {
 | 
				
			||||||
 | 
							Image image = null;
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								image = new Image(IconUtil.class.getResource(path).toExternalForm(), size, size, true, true);
 | 
				
			||||||
 | 
							} catch (final NullPointerException e) {
 | 
				
			||||||
 | 
								EnvoyLog.getLogger(IconUtil.class).log(Level.WARNING, String.format("Could not load image at path %s: ", path), e);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return image;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Loads a {@code .png} image from the sub-folder {@code /icons/} of the
 | 
				
			||||||
 | 
						 * resource folder.<br>
 | 
				
			||||||
 | 
						 * The suffix {@code .png} is automatically appended.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param name the image name without the .png suffix
 | 
				
			||||||
 | 
						 * @return the loaded image
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 | 
						 * @apiNote let's load a sample image {@code /icons/abc.png}.<br>
 | 
				
			||||||
 | 
						 *          To do that, we only have to call {@code IconUtil.loadIcon("abc")}
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static Image loadIcon(String name) { return load("/icons/" + name + ".png"); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Loads a {@code .png} image from the sub-folder {@code /icons/} of the
 | 
				
			||||||
 | 
						 * resource folder and scales it to the given size.<br>
 | 
				
			||||||
 | 
						 * The suffix {@code .png} is automatically appended.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param name the image name without the .png suffix
 | 
				
			||||||
 | 
						 * @param size the size of the image to scale to
 | 
				
			||||||
 | 
						 * @return the loaded image
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 | 
						 * @apiNote let's load a sample image {@code /icons/abc.png} in size 16.<br>
 | 
				
			||||||
 | 
						 *          To do that, we only have to call
 | 
				
			||||||
 | 
						 *          {@code IconUtil.loadIcon("abc", 16)}
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static Image loadIcon(String name, int size) { return load("/icons/" + name + ".png", size); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Loads a {@code .png} image whose design depends on the currently active theme
 | 
				
			||||||
 | 
						 * from the sub-folder {@code /icons/dark/} or {@code /icons/light/} of the
 | 
				
			||||||
 | 
						 * resource folder.
 | 
				
			||||||
 | 
						 * <p>
 | 
				
			||||||
 | 
						 * The suffix {@code .png} is automatically appended.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param name the image name without the "black" or "white" suffix and without
 | 
				
			||||||
 | 
						 *             the .png suffix
 | 
				
			||||||
 | 
						 * @return the loaded image
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 | 
						 * @apiNote let's take two sample images {@code /icons/dark/abc.png} and
 | 
				
			||||||
 | 
						 *          {@code /icons/light/abc.png}, and load one of them.<br>
 | 
				
			||||||
 | 
						 *          To do that theme sensitive, we only have to call
 | 
				
			||||||
 | 
						 *          {@code IconUtil.loadIconThemeSensitive("abc")}
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static Image loadIconThemeSensitive(String name) { return loadIcon(themeSpecificSubFolder() + name); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Loads a {@code .png} image whose design depends on the currently active theme
 | 
				
			||||||
 | 
						 * from the sub-folder {@code /icons/dark/} or {@code /icons/light/} of the
 | 
				
			||||||
 | 
						 * resource folder and scales it to the given size.
 | 
				
			||||||
 | 
						 * <p>
 | 
				
			||||||
 | 
						 * The suffix {@code .png} is automatically appended.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param name the image name without the .png suffix
 | 
				
			||||||
 | 
						 * @param size the size of the image to scale to
 | 
				
			||||||
 | 
						 * @return the loaded image
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 | 
						 * @apiNote let's take two sample images {@code /icons/dark/abc.png} and
 | 
				
			||||||
 | 
						 *          {@code /icons/light/abc.png}, and load one of them in size 16.<br>
 | 
				
			||||||
 | 
						 *          To do that theme sensitive, we only have to call
 | 
				
			||||||
 | 
						 *          {@code IconUtil.loadIconThemeSensitive("abc", 16)}
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static Image loadIconThemeSensitive(String name, int size) { return loadIcon(themeSpecificSubFolder() + name, size); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Loads images specified by an enum. The images have to be named like the
 | 
				
			||||||
	 * lowercase enum constants with {@code .png} extension and be located inside a
 | 
						 * lowercase enum constants with {@code .png} extension and be located inside a
 | 
				
			||||||
	 * folder with the lowercase name of the enum, which must be contained inside
 | 
						 * folder with the lowercase name of the enum, which must be contained inside
 | 
				
			||||||
	 * the {@code /icons} folder.
 | 
						 * the {@code /icons/} folder.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @param <T>       the enum that specifies the icons to load
 | 
						 * @param <T>       the enum that specifies the images to load
 | 
				
			||||||
	 * @param enumClass the class of the enum
 | 
						 * @param enumClass the class of the enum
 | 
				
			||||||
	 * @param size      the size to scale the icons to
 | 
						 * @param size      the size to scale the images to
 | 
				
			||||||
	 * @return a map containing the loaded icons with the corresponding enum
 | 
						 * @return a map containing the loaded images with the corresponding enum
 | 
				
			||||||
	 *         constants as keys
 | 
						 *         constants as keys
 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
@@ -62,4 +144,17 @@ public class IconUtil {
 | 
				
			|||||||
			icons.put(e, load(path + e.toString().toLowerCase() + ".png", size));
 | 
								icons.put(e, load(path + e.toString().toLowerCase() + ".png", size));
 | 
				
			||||||
		return icons;
 | 
							return icons;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * This method should be called if the display of an image depends upon the
 | 
				
			||||||
 | 
						 * currently active theme.<br>
 | 
				
			||||||
 | 
						 * In case of a default theme, the string returned will be
 | 
				
			||||||
 | 
						 * ({@code dark/} or {@code light/}), otherwise it will be empty.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @return the theme specific folder
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static String themeSpecificSubFolder() {
 | 
				
			||||||
 | 
							return Settings.getInstance().isUsingDefaultTheme() ? Settings.getInstance().getCurrentTheme() + "/" : "";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -102,7 +102,7 @@ public final class Startup extends Application {
 | 
				
			|||||||
		messageStatusCache	= new Cache<>();
 | 
							messageStatusCache	= new Cache<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		stage.setTitle("Envoy");
 | 
							stage.setTitle("Envoy");
 | 
				
			||||||
		stage.getIcons().add(IconUtil.load("/icons/envoy_logo.png"));
 | 
							stage.getIcons().add(IconUtil.loadIcon("envoy_logo"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		final var sceneContext = new SceneContext(stage);
 | 
							final var sceneContext = new SceneContext(stage);
 | 
				
			||||||
		sceneContext.load(SceneInfo.LOGIN_SCENE);
 | 
							sceneContext.load(SceneInfo.LOGIN_SCENE);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -110,7 +110,8 @@ public final class ChatScene implements Restorable {
 | 
				
			|||||||
		messageList.setCellFactory(MessageListCellFactory::new);
 | 
							messageList.setCellFactory(MessageListCellFactory::new);
 | 
				
			||||||
		userList.setCellFactory(ContactListCellFactory::new);
 | 
							userList.setCellFactory(ContactListCellFactory::new);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		settingsButton.setGraphic(new ImageView(IconUtil.load("/icons/settings.png", 16)));
 | 
							settingsButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("settings", 16)));
 | 
				
			||||||
 | 
							voiceButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("microphone", 20)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Listen to received messages
 | 
							// Listen to received messages
 | 
				
			||||||
		eventBus.register(MessageCreationEvent.class, e -> {
 | 
							eventBus.register(MessageCreationEvent.class, e -> {
 | 
				
			||||||
@@ -222,9 +223,9 @@ public final class ChatScene implements Restorable {
 | 
				
			|||||||
			if (recorder.isRecording()) {
 | 
								if (recorder.isRecording()) {
 | 
				
			||||||
				recorder.cancel();
 | 
									recorder.cancel();
 | 
				
			||||||
				recording = false;
 | 
									recording = false;
 | 
				
			||||||
				voiceButton.setText("Record Voice Message");
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			pendingAttachment = null;
 | 
								pendingAttachment = null;
 | 
				
			||||||
 | 
								attachmentView.setVisible(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			remainingChars.setVisible(true);
 | 
								remainingChars.setVisible(true);
 | 
				
			||||||
			remainingChars
 | 
								remainingChars
 | 
				
			||||||
@@ -262,16 +263,19 @@ public final class ChatScene implements Restorable {
 | 
				
			|||||||
			try {
 | 
								try {
 | 
				
			||||||
				if (!recording) {
 | 
									if (!recording) {
 | 
				
			||||||
					recording = true;
 | 
										recording = true;
 | 
				
			||||||
					Platform.runLater(() -> voiceButton.setText("Recording..."));
 | 
										Platform.runLater(() -> {
 | 
				
			||||||
 | 
											voiceButton.setText("Recording");
 | 
				
			||||||
 | 
											voiceButton.setGraphic(new ImageView(IconUtil.loadIcon("microphone_recording", 24)));
 | 
				
			||||||
 | 
										});
 | 
				
			||||||
					recorder.start();
 | 
										recorder.start();
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					pendingAttachment	= new Attachment(recorder.finish(), AttachmentType.VOICE);
 | 
										pendingAttachment	= new Attachment(recorder.finish(), AttachmentType.VOICE);
 | 
				
			||||||
					recording			= false;
 | 
										recording			= false;
 | 
				
			||||||
					Platform.runLater(() -> {
 | 
										Platform.runLater(() -> {
 | 
				
			||||||
						voiceButton.setText("Record Voice Message");
 | 
											voiceButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("microphone", 20)));
 | 
				
			||||||
 | 
											voiceButton.setText(null);
 | 
				
			||||||
						checkPostConditions(false);
 | 
											checkPostConditions(false);
 | 
				
			||||||
						attachmentView.setImage(IconUtil.load(settings.getCurrentTheme().equals("dark") ? "/icons/attachment_present_white.png"
 | 
											attachmentView.setImage(IconUtil.loadIconThemeSensitive("attachment_present", 20));
 | 
				
			||||||
								: "/icons/attachment_present_black.png", 20));
 | 
					 | 
				
			||||||
						attachmentView.setVisible(true);
 | 
											attachmentView.setVisible(true);
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -311,7 +315,7 @@ public final class ChatScene implements Restorable {
 | 
				
			|||||||
	private void checkPostConditions(boolean sendKeyPressed) {
 | 
						private void checkPostConditions(boolean sendKeyPressed) {
 | 
				
			||||||
		if (!postingPermanentlyDisabled) {
 | 
							if (!postingPermanentlyDisabled) {
 | 
				
			||||||
			if (!postButton.isDisabled() && sendKeyPressed) postMessage();
 | 
								if (!postButton.isDisabled() && sendKeyPressed) postMessage();
 | 
				
			||||||
			postButton.setDisable((messageTextArea.getText().isBlank() && pendingAttachment == null) || currentChat == null);
 | 
								postButton.setDisable(messageTextArea.getText().isBlank() && pendingAttachment == null || currentChat == null);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			final var noMoreMessaging = "Go online to send messages";
 | 
								final var noMoreMessaging = "Go online to send messages";
 | 
				
			||||||
			if (!infoLabel.getText().equals(noMoreMessaging))
 | 
								if (!infoLabel.getText().equals(noMoreMessaging))
 | 
				
			||||||
@@ -373,6 +377,7 @@ public final class ChatScene implements Restorable {
 | 
				
			|||||||
			if (pendingAttachment != null) {
 | 
								if (pendingAttachment != null) {
 | 
				
			||||||
				builder.setAttachment(pendingAttachment);
 | 
									builder.setAttachment(pendingAttachment);
 | 
				
			||||||
				pendingAttachment = null;
 | 
									pendingAttachment = null;
 | 
				
			||||||
 | 
									attachmentView.setVisible(false);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			final var message = builder.build();
 | 
								final var message = builder.build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -117,7 +117,7 @@
 | 
				
			|||||||
			</GridPane.margin>
 | 
								</GridPane.margin>
 | 
				
			||||||
			<buttons>
 | 
								<buttons>
 | 
				
			||||||
				<Button fx:id="voiceButton" disable="true"
 | 
									<Button fx:id="voiceButton" disable="true"
 | 
				
			||||||
					onAction="#voiceButtonClicked" text="_Record Voice Message">
 | 
										onAction="#voiceButtonClicked">
 | 
				
			||||||
					<padding>
 | 
										<padding>
 | 
				
			||||||
						<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
 | 
											<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
 | 
				
			||||||
					</padding>
 | 
										</padding>
 | 
				
			||||||
 
 | 
				
			|||||||
| 
		 Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB  | 
| 
		 Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB  | 
| 
		 Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB  | 
| 
		 Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/icons/dark/microphone.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 21 KiB  | 
| 
		 Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB  | 
| 
		 Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB  | 
| 
		 Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB  | 
| 
		 Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/icons/light/forward.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 25 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/icons/light/microphone.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 18 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/icons/light/settings.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.4 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/icons/microphone_recording.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 20 KiB  |