From 91be1db3937d0de045a8ed4bbf66a3d7c2f1daa4 Mon Sep 17 00:00:00 2001 From: delvh Date: Mon, 27 Jul 2020 12:00:49 +0200 Subject: [PATCH 1/3] Added ability to save attachments --- .../client/data/audio/AudioRecorder.java | 9 ++++-- .../envoy/client/ui/controller/ChatScene.java | 11 +++++-- .../client/ui/listcell/MessageControl.java | 28 +++++++++++++++-- .../src/main/java/envoy/data/Attachment.java | 26 ++++++++++------ .../main/java/envoy/server/data/Message.java | 31 ++++++++++++++----- 5 files changed, 81 insertions(+), 24 deletions(-) diff --git a/client/src/main/java/envoy/client/data/audio/AudioRecorder.java b/client/src/main/java/envoy/client/data/audio/AudioRecorder.java index 85dafae..251041a 100644 --- a/client/src/main/java/envoy/client/data/audio/AudioRecorder.java +++ b/client/src/main/java/envoy/client/data/audio/AudioRecorder.java @@ -27,6 +27,11 @@ public final class AudioRecorder { */ public static final AudioFormat DEFAULT_AUDIO_FORMAT = new AudioFormat(16000, 16, 1, true, false); + /** + * The format in which audio files will be saved. + */ + public static final String FILE_FORMAT = "wav"; + private final AudioFormat format; private final DataLine.Info info; @@ -78,7 +83,7 @@ public final class AudioRecorder { line.start(); // Prepare temp file - tempFile = Files.createTempFile("recording", "wav"); + tempFile = Files.createTempFile("recording", FILE_FORMAT); // Start the recording final var ais = new AudioInputStream(line); @@ -117,6 +122,6 @@ public final class AudioRecorder { line.close(); try { Files.deleteIfExists(tempFile); - } catch (IOException e) {} + } catch (final IOException e) {} } } 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 f9ba2d7..a708dd0 100644 --- a/client/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -8,6 +8,8 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Random; import java.util.logging.Level; import java.util.logging.Logger; @@ -240,9 +242,10 @@ public final class ChatScene implements Restorable { this.client = client; this.writeProxy = writeProxy; + MessageControl.setUser(localDB.getUser()); + MessageControl.setSceneContext(sceneContext); chatList.setItems(FXCollections.observableList(localDB.getChats())); contactLabel.setText(localDB.getUser().getName()); - MessageControl.setUser(localDB.getUser()); if (!client.isOnline()) updateInfoLabel("You are offline", "infoLabel-info"); recorder = new AudioRecorder(); @@ -334,7 +337,9 @@ public final class ChatScene implements Restorable { }); recorder.start(); } else { - pendingAttachment = new Attachment(recorder.finish(), AttachmentType.VOICE); + 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))); @@ -385,7 +390,7 @@ public final class ChatScene implements Restorable { // Create the pending attachment try { final var fileBytes = Files.readAllBytes(file.toPath()); - pendingAttachment = new Attachment(fileBytes, type); + pendingAttachment = new Attachment(fileBytes, file.getName(), type); checkPostConditions(false); // Setting the preview image as image of the attachmentView if (type == AttachmentType.PICTURE) diff --git a/client/src/main/java/envoy/client/ui/listcell/MessageControl.java b/client/src/main/java/envoy/client/ui/listcell/MessageControl.java index a6ecae5..795cd42 100644 --- a/client/src/main/java/envoy/client/ui/listcell/MessageControl.java +++ b/client/src/main/java/envoy/client/ui/listcell/MessageControl.java @@ -2,7 +2,7 @@ package envoy.client.ui.listcell; import java.awt.Toolkit; import java.awt.datatransfer.StringSelection; -import java.io.ByteArrayInputStream; +import java.io.*; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Map; @@ -16,9 +16,11 @@ import javafx.scene.control.MenuItem; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.VBox; +import javafx.stage.FileChooser; import envoy.client.ui.AudioControl; import envoy.client.ui.IconUtil; +import envoy.client.ui.SceneContext; import envoy.data.Message; import envoy.data.Message.MessageStatus; import envoy.data.User; @@ -38,6 +40,8 @@ public class MessageControl extends Label { private static User client; + private static SceneContext sceneContext; + private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss") .withZone(ZoneId.systemDefault()); private static final Map statusImages = IconUtil.loadByEnum(MessageStatus.class, 16); @@ -116,11 +120,31 @@ public class MessageControl extends Label { private void loadMessageInfoScene(Message message) { logger.log(Level.FINEST, "message info scene was requested for " + message); } - private void saveAttachment(Message message) { logger.log(Level.FINEST, "attachment saving was requested for " + message); } + private void saveAttachment(Message message) { + // Show save file dialog + final var fileChooser = new FileChooser(); + fileChooser.setInitialFileName(message.getAttachment().getName()); + + final File file = fileChooser.showSaveDialog(sceneContext.getStage()); + + // A file was selected + if (file != null) try (FileOutputStream fos = new FileOutputStream(file)) { + fos.write(message.getAttachment().getData()); + logger.log(Level.FINE, "Attachment of " + message + " was saved."); + } catch (final IOException e) { + logger.log(Level.WARNING, "Could not save attachment of " + message + ": ", e); + } + } /** * @param client the user who has logged in * @since Envoy Client v0.1-beta */ public static void setUser(User client) { MessageControl.client = client; } + + /** + * @param sceneContext the scene context storing the stage used in Envoy + * @since Envoy Client v0.1-beta + */ + public static void setSceneContext(SceneContext sceneContext) { MessageControl.sceneContext = sceneContext; } } diff --git a/common/src/main/java/envoy/data/Attachment.java b/common/src/main/java/envoy/data/Attachment.java index 177441b..67fca01 100644 --- a/common/src/main/java/envoy/data/Attachment.java +++ b/common/src/main/java/envoy/data/Attachment.java @@ -18,29 +18,28 @@ public class Attachment implements Serializable { /** * Defines the type of the attachment. - * + * * @since Envoy Common v0.1-beta */ public enum AttachmentType { /** * This attachment type denotes a picture. - * + * * @since Envoy Common v0.1-beta */ PICTURE, - /** * This attachment type denotes a video. - * + * * @since Envoy Common v0.1-beta */ VIDEO, - + /** * This attachment type denotes a voice message. - * + * * @since Envoy Common v0.1-beta */ VOICE, @@ -55,19 +54,22 @@ public class Attachment implements Serializable { private final byte[] data; private final AttachmentType type; + private final String name; - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L; /** * Constructs an attachment. - * + * * @param data the data of the attachment + * @param name the name of the attachment * @param type the type of the attachment * @since Envoy Common v0.1-beta */ - public Attachment(byte[] data, AttachmentType type) { + public Attachment(byte[] data, String name, AttachmentType type) { this.data = data; this.type = type; + this.name = name; } /** @@ -81,4 +83,10 @@ public class Attachment implements Serializable { * @since Envoy Common v0.1-beta */ public AttachmentType getType() { return type; } + + /** + * @return the name + * @since Envoy Common v0.2-beta + */ + public String getName() { return name; } } diff --git a/server/src/main/java/envoy/server/data/Message.java b/server/src/main/java/envoy/server/data/Message.java index fc564a2..ead0fde 100755 --- a/server/src/main/java/envoy/server/data/Message.java +++ b/server/src/main/java/envoy/server/data/Message.java @@ -47,7 +47,7 @@ public class Message { /** * Named query retrieving pending messages for a user (parameter {@code :user}) * which was last seen after a specific date (parameter {@code :lastSeen}). - * + * * @since Envoy Server Standalone v0.1-beta */ public static final String getPending = "Message.getPending"; @@ -76,6 +76,7 @@ public class Message { protected envoy.data.Message.MessageStatus status; protected AttachmentType attachmentType; protected byte[] attachment; + protected String attachmentName; protected boolean forwarded; /** @@ -93,7 +94,7 @@ public class Message { * @since Envoy Server Standalone v0.1-alpha */ public Message(envoy.data.Message message) { - PersistenceManager persistenceManager = PersistenceManager.getInstance(); + final var persistenceManager = PersistenceManager.getInstance(); id = message.getID(); status = message.getStatus(); text = message.getText(); @@ -104,8 +105,10 @@ public class Message { recipient = persistenceManager.getContactByID(message.getRecipientID()); forwarded = message.isForwarded(); if (message.hasAttachment()) { - attachment = message.getAttachment().getData(); - attachmentType = message.getAttachment().getType(); + final var messageAttachment = message.getAttachment(); + attachment = messageAttachment.getData(); + attachmentName = messageAttachment.getName(); + attachmentType = messageAttachment.getType(); } } @@ -123,20 +126,20 @@ public class Message { * @since Envoy Server Standalone v0.1-beta */ MessageBuilder prepareBuilder() { - var builder = new MessageBuilder(sender.getID(), recipient.getID(), id).setText(text) + final var builder = new MessageBuilder(sender.getID(), recipient.getID(), id).setText(text) .setCreationDate(creationDate) .setReceivedDate(receivedDate) .setReadDate(readDate) .setStatus(status) .setForwarded(forwarded); - if (attachment != null) builder.setAttachment(new Attachment(attachment, attachmentType)); + if (attachment != null) builder.setAttachment(new Attachment(attachment, attachmentName, attachmentType)); return builder; } /** * Sets the message status to {@link MessageStatus#RECEIVED} and sets the * current time stamp as the received date. - * + * * @since Envoy Server Standalone v0.1-beta */ public void received() { @@ -147,7 +150,7 @@ public class Message { /** * Sets the message status to {@link MessageStatus#READ} and sets the * current time stamp as the read date. - * + * * @since Envoy Server Standalone v0.1-beta */ public void read() { @@ -282,6 +285,18 @@ public class Message { */ public void setAttachmentType(AttachmentType attachmentType) { this.attachmentType = attachmentType; } + /** + * @return the attachmentName + * @since Envoy Server v0.2-beta + */ + public String getAttachmentName() { return attachmentName; } + + /** + * @param attachmentName the attachmentName to set + * @since Envoy Server v0.2-beta + */ + public void setAttachmentName(String attachmentName) { this.attachmentName = attachmentName; } + /** * @return whether this message is a forwarded message * @since Envoy Server Standalone v0.1-alpha From 01f63d6a1be3991a057dc1ba88b23e72fdbe4fed Mon Sep 17 00:00:00 2001 From: delvh Date: Mon, 27 Jul 2020 22:52:43 +0200 Subject: [PATCH 2/3] Added customizable download path and ability to save without FileChooser --- .../main/java/envoy/client/data/Settings.java | 35 ++++++++++ .../client/ui/controller/SettingsScene.java | 6 +- .../client/ui/listcell/MessageControl.java | 19 ++++-- .../ui/settings/DownloadSettingsPane.java | 66 +++++++++++++++++++ .../ui/settings/GeneralSettingsPane.java | 3 - .../client/ui/settings/SettingsPane.java | 6 +- 6 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 client/src/main/java/envoy/client/ui/settings/DownloadSettingsPane.java diff --git a/client/src/main/java/envoy/client/data/Settings.java b/client/src/main/java/envoy/client/data/Settings.java index d511553..07bb354 100644 --- a/client/src/main/java/envoy/client/data/Settings.java +++ b/client/src/main/java/envoy/client/data/Settings.java @@ -77,6 +77,10 @@ public class Settings { items.putIfAbsent("enterToSend", new SettingsItem<>(true, "Enter to send", "Sends a message by pressing the enter key.")); items.putIfAbsent("hideOnClose", new SettingsItem<>(true, "Hide on close", "Hides the chat window when it is closed.")); items.putIfAbsent("currentTheme", new SettingsItem<>("dark", "Current Theme Name", "The name of the currently selected theme.")); + items.putIfAbsent("downloadLocation", + new SettingsItem<>(new File(System.getProperty("user.home") + "/Downloads/"), "Download location", + "The location where files will be saved to")); + items.putIfAbsent("autoSaveDownloads", new SettingsItem<>(false, "Save without asking?", "Should downloads be saved without asking?")); } /** @@ -120,6 +124,37 @@ public class Settings { */ public void setEnterToSend(boolean enterToSend) { ((SettingsItem) items.get("enterToSend")).set(enterToSend); } + /** + * @return whether Envoy will prompt a dialogue before saving an + * {@link envoy.data.Attachment} + * @since Envoy Client v0.2-beta + */ + public Boolean isDownloadSavedWithoutAsking() { return (Boolean) items.get("autoSaveDownloads").get(); } + + /** + * Sets whether Envoy will prompt a dialogue before saving an + * {@link envoy.data.Attachment}. + * + * @param autosaveDownload whether a download should be saved without asking + * before + * @since Envoy Client v0.2-beta + */ + public void setDownloadSavedWithoutAsking(boolean autosaveDownload) { ((SettingsItem) items.get("autoSaveDownloads")).set(autosaveDownload); } + + /** + * @return the path where downloads should be saved + * @since Envoy Client v0.2-beta + */ + public File getDownloadLocation() { return (File) items.get("downloadLocation").get(); } + + /** + * Sets the path where downloads should be saved. + * + * @param downloadLocation the path to set + * @since Envoy Client v0.2-beta + */ + public void setDownloadLocation(File downloadLocation) { ((SettingsItem) items.get("downloadLocation")).set(downloadLocation); } + /** * @return the current on close mode. * @since Envoy Client v0.3-alpha diff --git a/client/src/main/java/envoy/client/ui/controller/SettingsScene.java b/client/src/main/java/envoy/client/ui/controller/SettingsScene.java index b7cc49d..f3358a9 100644 --- a/client/src/main/java/envoy/client/ui/controller/SettingsScene.java +++ b/client/src/main/java/envoy/client/ui/controller/SettingsScene.java @@ -4,6 +4,7 @@ import javafx.fxml.FXML; import javafx.scene.control.*; import envoy.client.ui.SceneContext; +import envoy.client.ui.settings.DownloadSettingsPane; import envoy.client.ui.settings.GeneralSettingsPane; import envoy.client.ui.settings.SettingsPane; @@ -29,7 +30,10 @@ public class SettingsScene { * @param sceneContext enables the user to return to the chat scene * @since Envoy Client v0.1-beta */ - public void initializeData(SceneContext sceneContext) { this.sceneContext = sceneContext; } + public void initializeData(SceneContext sceneContext) { + this.sceneContext = sceneContext; + settingsList.getItems().add(new DownloadSettingsPane(sceneContext)); + } @FXML private void initialize() { diff --git a/client/src/main/java/envoy/client/ui/listcell/MessageControl.java b/client/src/main/java/envoy/client/ui/listcell/MessageControl.java index 795cd42..0c0d91b 100644 --- a/client/src/main/java/envoy/client/ui/listcell/MessageControl.java +++ b/client/src/main/java/envoy/client/ui/listcell/MessageControl.java @@ -18,6 +18,7 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.VBox; import javafx.stage.FileChooser; +import envoy.client.data.Settings; import envoy.client.ui.AudioControl; import envoy.client.ui.IconUtil; import envoy.client.ui.SceneContext; @@ -45,6 +46,7 @@ public class MessageControl extends Label { private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss") .withZone(ZoneId.systemDefault()); private static final Map statusImages = IconUtil.loadByEnum(MessageStatus.class, 16); + private static final Settings settings = Settings.getInstance(); private static final Logger logger = EnvoyLog.getLogger(MessageControl.class); /** @@ -121,16 +123,21 @@ public class MessageControl extends Label { private void loadMessageInfoScene(Message message) { logger.log(Level.FINEST, "message info scene was requested for " + message); } private void saveAttachment(Message message) { - // Show save file dialog - final var fileChooser = new FileChooser(); - fileChooser.setInitialFileName(message.getAttachment().getName()); - - final File file = fileChooser.showSaveDialog(sceneContext.getStage()); + File file; + final var fileName = message.getAttachment().getName(); + final var downloadLocation = settings.getDownloadLocation(); + // Show save file dialog, if the user did not opt-out + if (!settings.isDownloadSavedWithoutAsking()) { + final var fileChooser = new FileChooser(); + fileChooser.setInitialFileName(fileName); + fileChooser.setInitialDirectory(downloadLocation); + file = fileChooser.showSaveDialog(sceneContext.getStage()); + } else file = new File(downloadLocation + (downloadLocation.getName().endsWith("/") ? "" : "/") + fileName); // A file was selected if (file != null) try (FileOutputStream fos = new FileOutputStream(file)) { fos.write(message.getAttachment().getData()); - logger.log(Level.FINE, "Attachment of " + message + " was saved."); + logger.log(Level.FINE, "Attachment of message was saved at " + file.getAbsolutePath()); } catch (final IOException e) { logger.log(Level.WARNING, "Could not save attachment of " + message + ": ", e); } diff --git a/client/src/main/java/envoy/client/ui/settings/DownloadSettingsPane.java b/client/src/main/java/envoy/client/ui/settings/DownloadSettingsPane.java new file mode 100644 index 0000000..c97cdd4 --- /dev/null +++ b/client/src/main/java/envoy/client/ui/settings/DownloadSettingsPane.java @@ -0,0 +1,66 @@ +package envoy.client.ui.settings; + +import javafx.geometry.Insets; +import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.stage.DirectoryChooser; + +import envoy.client.ui.SceneContext; + +/** + * Displays options for downloading {@link envoy.data.Attachment}s. + *

+ * Project: envoy-client
+ * File: DownloadSettingsPane.java
+ * Created: 27.07.2020
+ * + * @author Leon Hofmeister + * @since Envoy Client v0.2-beta + */ +public class DownloadSettingsPane extends SettingsPane { + + /** + * Constructs a new {@code DownloadSettingsPane} + * + * @param sceneContext the {@code SceneContext} used to block input to the + * {@link javafx.stage.Stage} used in Envoy + * @since Envoy Client v0.2-beta + */ + public DownloadSettingsPane(SceneContext sceneContext) { + super("Download"); + final var vbox = new VBox(15); + vbox.setPadding(new Insets(15)); + // checkbox to disable asking + final var checkBox = new CheckBox(settings.getItems().get("autoSaveDownloads").getUserFriendlyName()); + checkBox.setSelected(settings.isDownloadSavedWithoutAsking()); + checkBox.setOnAction(e -> settings.setDownloadSavedWithoutAsking(checkBox.isSelected())); + vbox.getChildren().add(checkBox); + + // Displaying the default path to save to + vbox.getChildren().add(new Label(settings.getItems().get("downloadLocation").getDescription() + ":")); + final var hbox = new HBox(20); + final var currentPath = new Label(settings.getDownloadLocation().getAbsolutePath()); + hbox.getChildren().add(currentPath); + + // Setting the default path + final var button = new Button("Select"); + button.setOnAction(e -> { + final var directoryChooser = new DirectoryChooser(); + directoryChooser.setTitle("Select the directory where attachments should be saved to"); + directoryChooser.setInitialDirectory(settings.getDownloadLocation()); + final var selectedDirectory = directoryChooser.showDialog(sceneContext.getStage()); + + if (selectedDirectory != null) { + currentPath.setText(selectedDirectory.getAbsolutePath()); + settings.setDownloadLocation(selectedDirectory); + } + }); + hbox.getChildren().add(button); + vbox.getChildren().add(hbox); + getChildren().add(vbox); + } + +} diff --git a/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java b/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java index c82cb18..af46fbb 100644 --- a/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java +++ b/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java @@ -5,7 +5,6 @@ import java.util.List; import javafx.scene.control.ComboBox; import javafx.scene.layout.VBox; -import envoy.client.data.Settings; import envoy.client.data.SettingsItem; import envoy.client.event.ThemeChangeEvent; import envoy.data.User.UserStatus; @@ -21,8 +20,6 @@ import envoy.event.EventBus; */ public class GeneralSettingsPane extends SettingsPane { - private static final Settings settings = Settings.getInstance(); - /** * @since Envoy Client v0.1-beta */ diff --git a/client/src/main/java/envoy/client/ui/settings/SettingsPane.java b/client/src/main/java/envoy/client/ui/settings/SettingsPane.java index 7c84221..49f8abd 100644 --- a/client/src/main/java/envoy/client/ui/settings/SettingsPane.java +++ b/client/src/main/java/envoy/client/ui/settings/SettingsPane.java @@ -2,11 +2,13 @@ package envoy.client.ui.settings; import javafx.scene.layout.Pane; +import envoy.client.data.Settings; + /** * Project: envoy-client
* File: SettingsPane.java
* Created: 18.04.2020
- * + * * @author Kai S. K. Engelbart * @since Envoy Client v0.1-beta */ @@ -14,6 +16,8 @@ public abstract class SettingsPane extends Pane { protected String title; + protected static final Settings settings = Settings.getInstance(); + protected SettingsPane(String title) { this.title = title; } /** From 45e18fdef1f1a3a316b84dbbdb58e4488e75eac3 Mon Sep 17 00:00:00 2001 From: delvh Date: Tue, 28 Jul 2020 08:53:10 +0200 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: CyB3RC0nN0R --- .../src/main/java/envoy/client/ui/listcell/MessageControl.java | 2 +- .../java/envoy/client/ui/settings/DownloadSettingsPane.java | 3 +-- common/src/main/java/envoy/data/Attachment.java | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/client/src/main/java/envoy/client/ui/listcell/MessageControl.java b/client/src/main/java/envoy/client/ui/listcell/MessageControl.java index 0c0d91b..eec8612 100644 --- a/client/src/main/java/envoy/client/ui/listcell/MessageControl.java +++ b/client/src/main/java/envoy/client/ui/listcell/MessageControl.java @@ -132,7 +132,7 @@ public class MessageControl extends Label { fileChooser.setInitialFileName(fileName); fileChooser.setInitialDirectory(downloadLocation); file = fileChooser.showSaveDialog(sceneContext.getStage()); - } else file = new File(downloadLocation + (downloadLocation.getName().endsWith("/") ? "" : "/") + fileName); + } else file = new File(downloadLocation, fileName); // A file was selected if (file != null) try (FileOutputStream fos = new FileOutputStream(file)) { diff --git a/client/src/main/java/envoy/client/ui/settings/DownloadSettingsPane.java b/client/src/main/java/envoy/client/ui/settings/DownloadSettingsPane.java index c97cdd4..bdc1352 100644 --- a/client/src/main/java/envoy/client/ui/settings/DownloadSettingsPane.java +++ b/client/src/main/java/envoy/client/ui/settings/DownloadSettingsPane.java @@ -23,7 +23,7 @@ import envoy.client.ui.SceneContext; public class DownloadSettingsPane extends SettingsPane { /** - * Constructs a new {@code DownloadSettingsPane} + * Constructs a new {@code DownloadSettingsPane}. * * @param sceneContext the {@code SceneContext} used to block input to the * {@link javafx.stage.Stage} used in Envoy @@ -62,5 +62,4 @@ public class DownloadSettingsPane extends SettingsPane { vbox.getChildren().add(hbox); getChildren().add(vbox); } - } diff --git a/common/src/main/java/envoy/data/Attachment.java b/common/src/main/java/envoy/data/Attachment.java index 67fca01..e231a76 100644 --- a/common/src/main/java/envoy/data/Attachment.java +++ b/common/src/main/java/envoy/data/Attachment.java @@ -68,8 +68,8 @@ public class Attachment implements Serializable { */ public Attachment(byte[] data, String name, AttachmentType type) { this.data = data; - this.type = type; this.name = name; + this.type = type; } /**