Add Ability to Delete Messages Locally #70
@ -74,7 +74,7 @@ public class Chat implements Serializable {
|
|||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj) return true;
|
if (this == obj) return true;
|
||||||
if (!(obj instanceof Chat)) return false;
|
if (!(obj instanceof Chat)) return false;
|
||||||
final Chat other = (Chat) obj;
|
final var other = (Chat) obj;
|
||||||
return Objects.equals(recipient, other.recipient);
|
return Objects.equals(recipient, other.recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ public class Chat implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void read(WriteProxy writeProxy) {
|
public void read(WriteProxy writeProxy) {
|
||||||
for (int i = messages.size() - 1; i >= 0; --i) {
|
for (int i = messages.size() - 1; i >= 0; --i) {
|
||||||
final Message m = messages.get(i);
|
final var m = messages.get(i);
|
||||||
if (m.getSenderID() == recipient.getID()) if (m.getStatus() == MessageStatus.READ) break;
|
if (m.getSenderID() == recipient.getID()) if (m.getStatus() == MessageStatus.READ) break;
|
||||||
else {
|
else {
|
||||||
m.setStatus(MessageStatus.READ);
|
m.setStatus(MessageStatus.READ);
|
||||||
@ -121,6 +121,15 @@ public class Chat implements Serializable {
|
|||||||
messages.add(0, message);
|
messages.add(0, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the message with the given ID.
|
||||||
|
*
|
||||||
|
* @param messageID the ID of the message to remove
|
||||||
|
* @return whether the message has been found and removed
|
||||||
|
* @since Envoy Client v0.3-beta
|
||||||
|
*/
|
||||||
|
public boolean remove(long messageID) { return messages.removeIf(m -> m.getID() == messageID); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increments the amount of unread messages.
|
* Increments the amount of unread messages.
|
||||||
*
|
*
|
||||||
|
@ -7,6 +7,7 @@ import java.time.Instant;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.*;
|
import javafx.collections.*;
|
||||||
|
|
||||||
import envoy.client.event.*;
|
import envoy.client.event.*;
|
||||||
@ -273,6 +274,24 @@ public final class LocalDB implements EventListener {
|
|||||||
cacheMap.clear();
|
cacheMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the message with the given ID, if present.
|
||||||
|
*
|
||||||
|
* @param message the event that was
|
||||||
|
* @since Envoy Client v0.3-beta
|
||||||
|
*/
|
||||||
|
@Event
|
||||||
|
private void onMessageDeletion(MessageDeletion message) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
|
||||||
|
// We suppose that messages have unique IDs, hence the search can be stopped
|
||||||
|
// once a message was removed
|
||||||
|
final var messageID = message.get();
|
||||||
|
for (final var chat : chats)
|
||||||
|
if (chat.remove(messageID)) break;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a {@code Map<String, User>} of all users stored locally with their
|
* @return a {@code Map<String, User>} of all users stored locally with their
|
||||||
* user names as keys
|
* user names as keys
|
||||||
|
20
client/src/main/java/envoy/client/event/MessageDeletion.java
Normal file
20
client/src/main/java/envoy/client/event/MessageDeletion.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package envoy.client.event;
|
||||||
|
|
||||||
|
import envoy.event.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conveys the deletion of a message.
|
||||||
|
*
|
||||||
|
* @author Leon Hofmeister
|
||||||
|
* @since Envoy Common v0.3-beta
|
||||||
|
*/
|
||||||
|
public class MessageDeletion extends Event<Long> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param messageID the ID of the deleted message
|
||||||
|
* @since Envoy Common v0.3-beta
|
||||||
|
*/
|
||||||
|
public MessageDeletion(long messageID) { super(messageID); }
|
||||||
|
}
|
@ -1,8 +1,6 @@
|
|||||||
package envoy.client.ui.control;
|
package envoy.client.ui.control;
|
||||||
|
|
||||||
import java.awt.Toolkit;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.awt.datatransfer.StringSelection;
|
|
||||||
import java.io.*;
|
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -12,11 +10,10 @@ import javafx.geometry.*;
|
|||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.image.*;
|
import javafx.scene.image.*;
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import javafx.stage.FileChooser;
|
|
||||||
|
|
||||||
import envoy.client.data.*;
|
import envoy.client.data.*;
|
||||||
import envoy.client.ui.*;
|
import envoy.client.net.Client;
|
||||||
import envoy.client.util.IconUtil;
|
import envoy.client.util.*;
|
||||||
import envoy.data.*;
|
import envoy.data.*;
|
||||||
import envoy.data.Message.MessageStatus;
|
import envoy.data.Message.MessageStatus;
|
||||||
import envoy.util.EnvoyLog;
|
import envoy.util.EnvoyLog;
|
||||||
@ -32,13 +29,13 @@ public final class MessageControl extends Label {
|
|||||||
|
|
||||||
private final boolean ownMessage;
|
private final boolean ownMessage;
|
||||||
|
|
||||||
private final LocalDB localDB = Context.getInstance().getLocalDB();
|
private final LocalDB localDB = context.getLocalDB();
|
||||||
private final SceneContext sceneContext = Context.getInstance().getSceneContext();
|
private final Client client = context.getClient();
|
||||||
|
|
||||||
|
private static final Context context = Context.getInstance();
|
||||||
private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")
|
private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")
|
||||||
.withZone(ZoneId.systemDefault());
|
.withZone(ZoneId.systemDefault());
|
||||||
private static final Map<MessageStatus, Image> statusImages = IconUtil.loadByEnum(MessageStatus.class, 16);
|
private static final Map<MessageStatus, Image> statusImages = IconUtil.loadByEnum(MessageStatus.class, 16);
|
||||||
private static final Settings settings = Settings.getInstance();
|
|
||||||
private static final Logger logger = EnvoyLog.getLogger(MessageControl.class);
|
private static final Logger logger = EnvoyLog.getLogger(MessageControl.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,6 +44,8 @@ public final class MessageControl extends Label {
|
|||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
*/
|
*/
|
||||||
public MessageControl(Message message) {
|
public MessageControl(Message message) {
|
||||||
|
ownMessage = message.getSenderID() == localDB.getUser().getID();
|
||||||
|
|
||||||
// Creating the underlying VBox and the dateLabel
|
// Creating the underlying VBox and the dateLabel
|
||||||
final var hbox = new HBox();
|
final var hbox = new HBox();
|
||||||
if (message.getSenderID() != localDB.getUser().getID() && message instanceof GroupMessage) {
|
if (message.getSenderID() != localDB.getUser().getID() && message instanceof GroupMessage) {
|
||||||
@ -67,18 +66,42 @@ public final class MessageControl extends Label {
|
|||||||
final var vbox = new VBox(hbox);
|
final var vbox = new VBox(hbox);
|
||||||
|
|
||||||
// Creating the actions for the MenuItems
|
// Creating the actions for the MenuItems
|
||||||
final var contextMenu = new ContextMenu();
|
final var contextMenu = new ContextMenu();
|
||||||
final var copyMenuItem = new MenuItem("Copy");
|
final var items = contextMenu.getItems();
|
||||||
final var deleteMenuItem = new MenuItem("Delete");
|
|
||||||
final var forwardMenuItem = new MenuItem("Forward");
|
// Copy message action
|
||||||
final var quoteMenuItem = new MenuItem("Quote");
|
if (!message.getText().isEmpty()) {
|
||||||
final var infoMenuItem = new MenuItem("Info");
|
final var copyMenuItem = new MenuItem("Copy Text");
|
||||||
copyMenuItem.setOnAction(e -> copyMessage(message));
|
copyMenuItem.setOnAction(e -> MessageUtil.copyMessageText(message));
|
||||||
deleteMenuItem.setOnAction(e -> deleteMessage(message));
|
items.add(copyMenuItem);
|
||||||
forwardMenuItem.setOnAction(e -> forwardMessage(message));
|
}
|
||||||
quoteMenuItem.setOnAction(e -> quoteMessage(message));
|
|
||||||
|
// Delete message - if own message - action
|
||||||
|
if (ownMessage && client.isOnline()) {
|
||||||
|
final var deleteMenuItem = new MenuItem("Delete locally");
|
||||||
|
deleteMenuItem.setOnAction(e -> MessageUtil.deleteMessage(message));
|
||||||
|
items.add(deleteMenuItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// As long as these types of messages are not implemented and no caches are
|
||||||
|
// defined for them, we only want them to appear when being online
|
||||||
|
if (client.isOnline()) {
|
||||||
|
|
||||||
|
// Forward menu item
|
||||||
|
final var forwardMenuItem = new MenuItem("Forward");
|
||||||
|
forwardMenuItem.setOnAction(e -> MessageUtil.forwardMessage(message));
|
||||||
|
items.add(forwardMenuItem);
|
||||||
|
|
||||||
|
// Quote menu item
|
||||||
|
final var quoteMenuItem = new MenuItem("Quote");
|
||||||
|
quoteMenuItem.setOnAction(e -> MessageUtil.quoteMessage(message));
|
||||||
|
items.add(quoteMenuItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info actions
|
||||||
|
final var infoMenuItem = new MenuItem("Info");
|
||||||
infoMenuItem.setOnAction(e -> loadMessageInfoScene(message));
|
infoMenuItem.setOnAction(e -> loadMessageInfoScene(message));
|
||||||
contextMenu.getItems().addAll(copyMenuItem, deleteMenuItem, forwardMenuItem, quoteMenuItem, infoMenuItem);
|
items.add(infoMenuItem);
|
||||||
|
|
||||||
// Handling message attachment display
|
// Handling message attachment display
|
||||||
// TODO: Add missing attachment types
|
// TODO: Add missing attachment types
|
||||||
@ -97,8 +120,8 @@ public final class MessageControl extends Label {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
final var saveAttachment = new MenuItem("Save attachment");
|
final var saveAttachment = new MenuItem("Save attachment");
|
||||||
saveAttachment.setOnAction(e -> saveAttachment(message));
|
saveAttachment.setOnAction(e -> MessageUtil.saveAttachment(message));
|
||||||
contextMenu.getItems().add(saveAttachment);
|
items.add(saveAttachment);
|
||||||
}
|
}
|
||||||
// Creating the textLabel
|
// Creating the textLabel
|
||||||
final var textLabel = new Label(message.getText());
|
final var textLabel = new Label(message.getText());
|
||||||
@ -116,12 +139,8 @@ public final class MessageControl extends Label {
|
|||||||
hBoxBottom.getChildren().add(statusIcon);
|
hBoxBottom.getChildren().add(statusIcon);
|
||||||
hBoxBottom.setAlignment(Pos.BOTTOM_RIGHT);
|
hBoxBottom.setAlignment(Pos.BOTTOM_RIGHT);
|
||||||
getStyleClass().add("own-message");
|
getStyleClass().add("own-message");
|
||||||
ownMessage = true;
|
|
||||||
hbox.setAlignment(Pos.CENTER_RIGHT);
|
hbox.setAlignment(Pos.CENTER_RIGHT);
|
||||||
} else {
|
} else getStyleClass().add("received-message");
|
||||||
getStyleClass().add("received-message");
|
|
||||||
ownMessage = false;
|
|
||||||
}
|
|
||||||
vbox.getChildren().add(hBoxBottom);
|
vbox.getChildren().add(hBoxBottom);
|
||||||
// Adjusting height and weight of the cell to the corresponding ListView
|
// Adjusting height and weight of the cell to the corresponding ListView
|
||||||
paddingProperty().setValue(new Insets(5, 20, 5, 20));
|
paddingProperty().setValue(new Insets(5, 20, 5, 20));
|
||||||
@ -129,41 +148,8 @@ public final class MessageControl extends Label {
|
|||||||
setGraphic(vbox);
|
setGraphic(vbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context Menu actions
|
|
||||||
|
|
||||||
private void copyMessage(Message message) {
|
|
||||||
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(message.getText()), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteMessage(Message message) { logger.log(Level.FINEST, "message deletion was requested for " + message); }
|
|
||||||
|
|
||||||
private void forwardMessage(Message message) { logger.log(Level.FINEST, "message forwarding was requested for " + message); }
|
|
||||||
|
|
||||||
private void quoteMessage(Message message) { logger.log(Level.FINEST, "message quotation was requested for " + message); }
|
|
||||||
|
|
||||||
private void loadMessageInfoScene(Message message) { logger.log(Level.FINEST, "message info scene was requested for " + message); }
|
private void loadMessageInfoScene(Message message) { logger.log(Level.FINEST, "message info scene was requested for " + message); }
|
||||||
|
|
||||||
private void saveAttachment(Message message) {
|
|
||||||
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, 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 at " + file.getAbsolutePath());
|
|
||||||
} catch (final IOException e) {
|
|
||||||
logger.log(Level.WARNING, "Could not save attachment of " + message + ": ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return whether the message stored by this {@code MessageControl} has been
|
* @return whether the message stored by this {@code MessageControl} has been
|
||||||
* sent by this user of Envoy
|
* sent by this user of Envoy
|
||||||
|
@ -82,6 +82,7 @@ public class TextInputContextMenu extends ContextMenu {
|
|||||||
copyMI.disableProperty().bind(control.selectedTextProperty().isEmpty());
|
copyMI.disableProperty().bind(control.selectedTextProperty().isEmpty());
|
||||||
deleteMI.disableProperty().bind(control.selectedTextProperty().isEmpty());
|
deleteMI.disableProperty().bind(control.selectedTextProperty().isEmpty());
|
||||||
clearMI.disableProperty().bind(control.textProperty().isEmpty());
|
clearMI.disableProperty().bind(control.textProperty().isEmpty());
|
||||||
|
selectAllMI.disableProperty().bind(control.textProperty().isEmpty());
|
||||||
setOnShowing(e -> pasteMI.setDisable(!Clipboard.getSystemClipboard().hasString()));
|
setOnShowing(e -> pasteMI.setDisable(!Clipboard.getSystemClipboard().hasString()));
|
||||||
|
|
||||||
selectAllMI.getProperties().put("refreshMenu", Boolean.TRUE);
|
selectAllMI.getProperties().put("refreshMenu", Boolean.TRUE);
|
||||||
|
@ -223,8 +223,8 @@ public final class ChatScene implements EventListener, Restorable {
|
|||||||
// The sender of the message is the recipient of the chat
|
// The sender of the message is the recipient of the chat
|
||||||
// Exceptions: this user is the sender (sync) or group message (group is
|
// Exceptions: this user is the sender (sync) or group message (group is
|
||||||
// recipient)
|
// recipient)
|
||||||
final boolean ownMessage = message.getSenderID() == localDB.getUser().getID();
|
final var ownMessage = message.getSenderID() == localDB.getUser().getID();
|
||||||
delvh marked this conversation as resolved
|
|||||||
final var recipientID = message instanceof GroupMessage || ownMessage ? message.getRecipientID() : message.getSenderID();
|
final var recipientID = message instanceof GroupMessage || ownMessage ? message.getRecipientID() : message.getSenderID();
|
||||||
|
|
||||||
localDB.getChat(recipientID).ifPresent(chat -> {
|
localDB.getChat(recipientID).ifPresent(chat -> {
|
||||||
chat.insert(message);
|
chat.insert(message);
|
||||||
@ -336,6 +336,24 @@ public final class ChatScene implements EventListener, Restorable {
|
|||||||
.setNumberOfArguments(0)
|
.setNumberOfArguments(0)
|
||||||
.setDescription("Opens the settings screen")
|
.setDescription("Opens the settings screen")
|
||||||
.build("settings");
|
.build("settings");
|
||||||
|
|
||||||
|
// Copy text of selection initialization
|
||||||
|
builder.setAction(text -> {
|
||||||
|
final var selectedMessage = messageList.getSelectionModel().getSelectedItem();
|
||||||
|
if (selectedMessage != null) MessageUtil.copyMessageText(selectedMessage);
|
||||||
|
}).setNumberOfArguments(0).setDescription("Copies the text of the currently selected message").build("cp-s");
|
||||||
|
|
||||||
|
// Delete selection initialization
|
||||||
|
builder.setAction(text -> {
|
||||||
|
final var selectedMessage = messageList.getSelectionModel().getSelectedItem();
|
||||||
|
if (selectedMessage != null) MessageUtil.deleteMessage(selectedMessage);
|
||||||
|
}).setNumberOfArguments(0).setDescription("Deletes the currently selected message").build("del-s");
|
||||||
|
|
||||||
|
// Save attachment of selection initialization
|
||||||
|
builder.setAction(text -> {
|
||||||
|
final var selectedMessage = messageList.getSelectionModel().getSelectedItem();
|
||||||
|
if (selectedMessage != null && selectedMessage.hasAttachment()) MessageUtil.saveAttachment(selectedMessage);
|
||||||
|
}).setNumberOfArguments(0).setDescription("Copies the text of the currently selected message").build("save-a-s");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -387,7 +405,7 @@ public final class ChatScene implements EventListener, Restorable {
|
|||||||
if (currentChat != null) {
|
if (currentChat != null) {
|
||||||
topBarContactLabel.setText(currentChat.getRecipient().getName());
|
topBarContactLabel.setText(currentChat.getRecipient().getName());
|
||||||
if (currentChat.getRecipient() instanceof User) {
|
if (currentChat.getRecipient() instanceof User) {
|
||||||
final String status = ((User) currentChat.getRecipient()).getStatus().toString();
|
final var status = ((User) currentChat.getRecipient()).getStatus().toString();
|
||||||
topBarStatusLabel.setText(status);
|
topBarStatusLabel.setText(status);
|
||||||
topBarStatusLabel.getStyleClass().add(status.toLowerCase());
|
topBarStatusLabel.getStyleClass().add(status.toLowerCase());
|
||||||
recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43));
|
recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43));
|
||||||
@ -395,7 +413,7 @@ public final class ChatScene implements EventListener, Restorable {
|
|||||||
topBarStatusLabel.setText(currentChat.getRecipient().getContacts().size() + " members");
|
topBarStatusLabel.setText(currentChat.getRecipient().getContacts().size() + " members");
|
||||||
recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("group_icon", 43));
|
recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("group_icon", 43));
|
||||||
}
|
}
|
||||||
final Rectangle clip = new Rectangle();
|
final var clip = new Rectangle();
|
||||||
clip.setWidth(43);
|
clip.setWidth(43);
|
||||||
clip.setHeight(43);
|
clip.setHeight(43);
|
||||||
clip.setArcHeight(43);
|
clip.setArcHeight(43);
|
||||||
@ -753,6 +771,13 @@ public final class ChatScene implements EventListener, Restorable {
|
|||||||
pendingAttachment = messageAttachment;
|
pendingAttachment = messageAttachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the current message selection.
|
||||||
|
*
|
||||||
|
* @since Envoy Client v0.3-beta
|
||||||
|
*/
|
||||||
|
public void clearMessageSelection() { messageList.getSelectionModel().clearSelection(); }
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void searchContacts() {
|
private void searchContacts() {
|
||||||
chats.setPredicate(contactSearch.getText().isBlank() ? c -> true
|
chats.setPredicate(contactSearch.getText().isBlank() ? c -> true
|
||||||
|
105
client/src/main/java/envoy/client/util/MessageUtil.java
Normal file
105
client/src/main/java/envoy/client/util/MessageUtil.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package envoy.client.util;
|
||||||
|
|
||||||
|
import java.awt.Toolkit;
|
||||||
|
import java.awt.datatransfer.StringSelection;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.logging.*;
|
||||||
|
|
||||||
|
import javafx.stage.FileChooser;
|
||||||
|
|
||||||
|
import envoy.client.data.*;
|
||||||
|
import envoy.client.event.MessageDeletion;
|
||||||
|
import envoy.client.ui.controller.ChatScene;
|
||||||
|
import envoy.data.Message;
|
||||||
|
import envoy.util.EnvoyLog;
|
||||||
|
|
||||||
|
import dev.kske.eventbus.EventBus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains methods that are commonly used for {@link Message}s.
|
||||||
|
*
|
||||||
|
* @author Leon Hofmeister
|
||||||
|
* @since Envoy Client v0.3-beta
|
||||||
|
*/
|
||||||
|
public class MessageUtil {
|
||||||
|
|
||||||
|
private MessageUtil() {}
|
||||||
|
|
||||||
|
private static Logger logger = EnvoyLog.getLogger(MessageUtil.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the text of the given message to the System Clipboard.
|
||||||
|
*
|
||||||
|
* @param message the message whose text to copy
|
||||||
|
* @since Envoy Client v0.3-beta
|
||||||
|
*/
|
||||||
|
public static void copyMessageText(Message message) {
|
||||||
|
logger.log(Level.FINEST, "A copy of message text \"" + message.getText() + "\" was requested");
|
||||||
|
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(message.getText()), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the given message.
|
||||||
|
*
|
||||||
|
* @param message the message to delete
|
||||||
|
* @since Envoy Client v0.3-beta
|
||||||
|
*/
|
||||||
|
public static void deleteMessage(Message message) {
|
||||||
|
final var messageDeletionEvent = new MessageDeletion(message.getID());
|
||||||
|
final var controller = Context.getInstance().getSceneContext().getController();
|
||||||
|
if (controller instanceof ChatScene) ((ChatScene) controller).clearMessageSelection();
|
||||||
|
|
||||||
|
// Removing the message locally
|
||||||
|
EventBus.getInstance().dispatch(messageDeletionEvent);
|
||||||
|
|
||||||
|
logger.log(Level.FINEST, "message deletion was requested for " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forwards the given message.
|
||||||
|
* Currently not implemented.
|
||||||
|
*
|
||||||
|
* @param message the message to forward
|
||||||
|
* @since Envoy Client v0.3-beta
|
||||||
|
*/
|
||||||
|
public static void forwardMessage(Message message) { logger.log(Level.FINEST, "Message forwarding was requested for " + message); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quotes the given message.
|
||||||
|
* Currently not implemented.
|
||||||
|
*
|
||||||
|
* @param message the message to quote
|
||||||
|
* @since Envoy Client v0.3-beta
|
||||||
|
*/
|
||||||
|
public static void quoteMessage(Message message) { logger.log(Level.FINEST, "Message quotation was requested for " + message); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the attachment of a message, if present.
|
||||||
|
*
|
||||||
|
* @param message the message whose attachment to save
|
||||||
|
* @throws IllegalStateException if no attachment is present in the message
|
||||||
|
* @since Envoy Client v0.3-beta
|
||||||
|
*/
|
||||||
|
public static void saveAttachment(Message message) {
|
||||||
|
if (!message.hasAttachment()) throw new IllegalArgumentException("Cannot save a non-existing attachment");
|
||||||
|
File file;
|
||||||
|
final var fileName = message.getAttachment().getName();
|
||||||
|
final var downloadLocation = Settings.getInstance().getDownloadLocation();
|
||||||
|
|
||||||
|
// Show save file dialog, if the user did not opt-out
|
||||||
|
if (!Settings.getInstance().isDownloadSavedWithoutAsking()) {
|
||||||
|
final var fileChooser = new FileChooser();
|
||||||
|
fileChooser.setInitialFileName(fileName);
|
||||||
|
fileChooser.setInitialDirectory(downloadLocation);
|
||||||
|
file = fileChooser.showSaveDialog(Context.getInstance().getSceneContext().getStage());
|
||||||
|
} else file = new File(downloadLocation, fileName);
|
||||||
|
|
||||||
|
// A file was selected
|
||||||
|
if (file != null) try (var fos = new FileOutputStream(file)) {
|
||||||
|
fos.write(message.getAttachment().getData());
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,8 @@ import envoy.data.User.UserStatus;
|
|||||||
import envoy.server.net.ConnectionManager;
|
import envoy.server.net.ConnectionManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Contains operations used for persistence.
|
||||||
|
*
|
||||||
* @author Leon Hofmeister
|
* @author Leon Hofmeister
|
||||||
* @author Maximilian Käfer
|
* @author Maximilian Käfer
|
||||||
* @since Envoy Server Standalone v0.1-alpha
|
* @since Envoy Server Standalone v0.1-alpha
|
||||||
|
Reference in New Issue
Block a user
I thought we don't declare primitives as
var
?We don't?
Well, we have to decide quick since I reactived
use var instad of field
in my formatter, and this was the result of it.Should I deactivate it?
You can deactivate it, however I will publish a new version of the formatter soon.
So, I don't have to change it?
It's up to you. With the new formatter, it will get changed anyway sooner or later.