Add Voice Recording to ChatScene

The ChatScene layout has been adjusted to include a voice message
button. When pressed, a recording starts. To finish the recording, press
the button again. The recording will be saved as a pending attachment.

The next message sent will include the attachment. When a pending
attachment is present, a message can be sent without text.

When the chat is switched, the pending attachment is discarded. This
does not stop active recordings, however.

The ChatScene layout handles large stages better now by ditching
percentage-wise row and column scaling in favor of absolute values for
all cells except the message list and text area.
This commit is contained in:
2020-07-03 23:32:22 +02:00
parent 0abd5cf17c
commit 60d3e65574
2 changed files with 100 additions and 112 deletions

View File

@ -17,9 +17,7 @@ import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import envoy.client.data.Chat;
import envoy.client.data.LocalDB;
import envoy.client.data.Settings;
import envoy.client.data.*;
import envoy.client.event.MessageCreationEvent;
import envoy.client.net.Client;
import envoy.client.net.WriteProxy;
@ -29,10 +27,12 @@ import envoy.client.ui.listcell.ContactListCellFactory;
import envoy.client.ui.listcell.MessageControl;
import envoy.client.ui.listcell.MessageListCellFactory;
import envoy.data.*;
import envoy.data.Attachment.AttachmentType;
import envoy.event.EventBus;
import envoy.event.MessageStatusChange;
import envoy.event.UserStatusChange;
import envoy.event.contact.ContactOperation;
import envoy.exception.EnvoyException;
import envoy.util.EnvoyLog;
/**
@ -57,6 +57,9 @@ public final class ChatScene {
@FXML
private Button postButton;
@FXML
private Button voiceButton;
@FXML
private Button settingsButton;
@ -77,9 +80,11 @@ public final class ChatScene {
private WriteProxy writeProxy;
private SceneContext sceneContext;
private boolean postingPermanentlyDisabled = false;
private Chat currentChat;
private Chat currentChat;
private AudioRecorder recorder;
private boolean recording;
private Attachment pendingAttachment;
private boolean postingPermanentlyDisabled = false;
private static final Settings settings = Settings.getInstance();
private static final EventBus eventBus = EventBus.getInstance();
@ -171,6 +176,9 @@ public final class ChatScene {
contactLabel.setText(localDB.getUser().getName());
MessageControl.setUser(localDB.getUser());
if (!client.isOnline()) updateInfoLabel("You are offline", "infoLabel-info");
recorder = new AudioRecorder();
if (!recorder.isSupported()) voiceButton.setDisable(true);
}
/**
@ -201,6 +209,10 @@ public final class ChatScene {
logger.log(Level.WARNING, "Could not read current chat.", e);
}
// Discard the pending attachment
// TODO: stop running recording
pendingAttachment = null;
remainingChars.setVisible(true);
remainingChars
.setText(String.format("remaining chars: %d/%d", MAX_MESSAGE_LENGTH - messageTextArea.getText().length(), MAX_MESSAGE_LENGTH));
@ -230,6 +242,25 @@ public final class ChatScene {
sceneContext.<ContactSearchScene>getController().initializeData(sceneContext, localDB);
}
@FXML
private void voiceButtonClicked() {
new Thread(() -> {
try {
if (!recording) {
recording = true;
Platform.runLater(() -> voiceButton.setText("Recording..."));
recorder.start();
} else {
pendingAttachment = new Attachment(recorder.finish(), AttachmentType.VOICE);
recording = false;
Platform.runLater(() -> { voiceButton.setText("Record Voice Message"); checkPostConditions(false); });
}
} catch (EnvoyException e) {
e.printStackTrace();
}
}).start();
}
/**
* Checks the text length of the {@code messageTextArea}, adjusts the
* {@code remainingChars} label and checks whether to send the message
@ -252,11 +283,15 @@ public final class ChatScene {
*/
@FXML
private void checkPostConditions(KeyEvent e) {
checkPostConditions(settings.isEnterToSend() && e.getCode() == KeyCode.ENTER
|| !settings.isEnterToSend() && e.getCode() == KeyCode.ENTER && e.isControlDown());
}
private void checkPostConditions(boolean sendKeyPressed) {
if (!postingPermanentlyDisabled) {
if (!postButton.isDisabled() && (settings.isEnterToSend() && e.getCode() == KeyCode.ENTER
|| !settings.isEnterToSend() && e.getCode() == KeyCode.ENTER && e.isControlDown()))
if (!postButton.isDisabled() && sendKeyPressed)
postMessage();
postButton.setDisable(messageTextArea.getText().isBlank() || currentChat == null);
postButton.setDisable((messageTextArea.getText().isBlank() && pendingAttachment == null) || currentChat == null);
} else {
final var noMoreMessaging = "Go online to send messages";
if (!infoLabel.getText().equals(noMoreMessaging))
@ -311,12 +346,14 @@ public final class ChatScene {
return;
}
final var text = messageTextArea.getText().strip();
if (text.isBlank()) throw new IllegalArgumentException("A message without visible text can not be sent.");
try {
// Create and send message
final var message = new MessageBuilder(localDB.getUser().getID(), currentChat.getRecipient().getID(), localDB.getIDGenerator())
.setText(text)
.build();
var builder = new MessageBuilder(localDB.getUser().getID(), currentChat.getRecipient().getID(), localDB.getIDGenerator()).setText(text);
if (pendingAttachment != null) {
builder.setAttachment(pendingAttachment);
pendingAttachment = null;
}
var message = builder.build();
// Send message
writeProxy.writeMessage(message);