+
+
+
No Active Chat
+
Select a peer from the sidebar or compose a new message below
-
No Active Chat
-
Select a Peer to start chatting!
-
-
+
+
+
+
+
+
+
+
![]()
+
+
+
Image Attachment
+
{{ formatBytes(newMessageImage.size) }}
+
+
+
+
+
+
Voice Note
+
{{ formatBytes(newMessageAudio.audio_blob.size) }}
+
+
+
+
+
+
+
+
+
{{ file.name }}
+
{{ formatBytes(file.size) }}
+
+
+
+
+
+
+
+
+
+
+ Recording: {{ audioAttachmentRecordingDuration }}
+
+
+
@@ -429,6 +505,7 @@ export default {
newMessageFiles: [],
isSendingMessage: false,
autoScrollOnNewMessage: true,
+ composeAddress: "",
isRecordingAudioAttachment: false,
audioAttachmentMicrophoneRecorder: null,
@@ -437,6 +514,7 @@ export default {
audioAttachmentRecordingDuration: null,
audioAttachmentRecordingTimer: null,
lxmfMessageAudioAttachmentCache: {},
+ expandedMessageInfo: null,
lxmfAudioModeToCodec2ModeMap: {
// https://github.com/markqvist/LXMF/blob/master/LXMF/LXMF.py#L21
0x01: "450PWB", // AM_CODEC2_450PWB
@@ -455,12 +533,16 @@ export default {
beforeUnmount() {
// stop listening for websocket messages
WebSocketConnection.off("message", this.onWebsocketMessage);
+ GlobalEmitter.off("compose-new-message", this.onComposeNewMessageEvent);
},
mounted() {
// listen for websocket messages
WebSocketConnection.on("message", this.onWebsocketMessage);
+ // listen for compose new message event
+ GlobalEmitter.on("compose-new-message", this.onComposeNewMessageEvent);
+
},
methods: {
close() {
@@ -597,6 +679,37 @@ export default {
openLXMFAddress() {
GlobalEmitter.emit("compose-new-message");
},
+ onComposeNewMessageEvent(destinationHash) {
+ if(!this.selectedPeer && !destinationHash){
+ this.$nextTick(() => {
+ const composeInput = document.getElementById("compose-input");
+ if(composeInput){
+ composeInput.focus();
+ }
+ });
+ }
+ },
+ async onComposeSubmit() {
+ if(!this.composeAddress || this.composeAddress.trim() === ""){
+ return;
+ }
+ let destinationHash = this.composeAddress.trim();
+ this.composeAddress = "";
+ await this.handleComposeAddress(destinationHash);
+ },
+ onComposeEnterPressed() {
+ this.onComposeSubmit();
+ },
+ async handleComposeAddress(destinationHash) {
+ if(destinationHash.startsWith("lxmf@")){
+ destinationHash = destinationHash.replace("lxmf@", "");
+ }
+ if(destinationHash.length !== 32){
+ DialogUtils.alert("Invalid Address");
+ return;
+ }
+ GlobalEmitter.emit("compose-new-message", destinationHash);
+ },
onLxmfMessageReceived(lxmfMessage) {
// add inbound message to ui
@@ -1464,89 +1577,64 @@ export default {
this.$emit("reload-conversations");
},
- showSentMessageInfo: function(lxmfMessage) {
-
- // basic info
- const info = [
- `Created: ${Utils.convertUnixMillisToLocalDateTimeString(lxmfMessage.timestamp * 1000)}`,
- `Method: ${lxmfMessage.method ?? "unknown"}`,
- ];
-
- // add audio attachment size
- if(lxmfMessage.fields?.audio?.audio_bytes){
- const audioBytesLength = atob(lxmfMessage.fields?.audio?.audio_bytes).length;
- info.push(`Audio Attachment: ${this.formatBytes(audioBytesLength)}`);
+ toggleSentMessageInfo: function(messageHash) {
+ if(this.expandedMessageInfo === messageHash){
+ this.expandedMessageInfo = null;
+ } else {
+ this.expandedMessageInfo = messageHash;
}
-
- // add image attachment size
- if(lxmfMessage.fields?.image?.image_bytes){
- const imageBytesLength = atob(lxmfMessage.fields?.image?.image_bytes).length;
- info.push(`Image Attachment: ${this.formatBytes(imageBytesLength)}`);
- }
-
- // add file attachments size
- if(lxmfMessage.fields?.file_attachments){
- var filesLength = 0;
- for(const fileAttachment of lxmfMessage.fields?.file_attachments){
- const fileBytesLength = atob(fileAttachment.file_bytes).length;
- filesLength += fileBytesLength;
- }
- info.push(`File Attachments: ${this.formatBytes(filesLength)}`);
- }
-
- // show message info
- DialogUtils.alert(info.join("\n"));
-
},
- showReceivedMessageInfo: function(lxmfMessage) {
+ toggleReceivedMessageInfo: function(messageHash) {
+ if(this.expandedMessageInfo === messageHash){
+ this.expandedMessageInfo = null;
+ } else {
+ this.expandedMessageInfo = messageHash;
+ }
+ },
+ getMessageInfoLines: function(lxmfMessage, isOutbound) {
+ const lines = [];
- // basic info
- const info = [
- `Sent: ${Utils.convertUnixMillisToLocalDateTimeString(lxmfMessage.timestamp * 1000)}`,
- `Received: ${Utils.convertDateTimeToLocalDateTimeString(new Date(lxmfMessage.created_at))}`,
- `Method: ${lxmfMessage.method ?? "unknown"}`,
- ];
+ if(isOutbound){
+ lines.push(`Created: ${Utils.convertUnixMillisToLocalDateTimeString(lxmfMessage.timestamp * 1000)}`);
+ } else {
+ lines.push(`Sent: ${Utils.convertUnixMillisToLocalDateTimeString(lxmfMessage.timestamp * 1000)}`);
+ lines.push(`Received: ${Utils.convertDateTimeToLocalDateTimeString(new Date(lxmfMessage.created_at))}`);
+ }
+
+ lines.push(`Method: ${lxmfMessage.method ?? "unknown"}`);
- // add audio attachment size
if(lxmfMessage.fields?.audio?.audio_bytes){
const audioBytesLength = atob(lxmfMessage.fields?.audio?.audio_bytes).length;
- info.push(`Audio Attachment: ${this.formatBytes(audioBytesLength)}`);
+ lines.push(`Audio Attachment: ${this.formatBytes(audioBytesLength)}`);
}
- // add image attachment size
if(lxmfMessage.fields?.image?.image_bytes){
const imageBytesLength = atob(lxmfMessage.fields?.image?.image_bytes).length;
- info.push(`Image Attachment: ${this.formatBytes(imageBytesLength)}`);
+ lines.push(`Image Attachment: ${this.formatBytes(imageBytesLength)}`);
}
- // add file attachments size
if(lxmfMessage.fields?.file_attachments){
var filesLength = 0;
for(const fileAttachment of lxmfMessage.fields?.file_attachments){
const fileBytesLength = atob(fileAttachment.file_bytes).length;
filesLength += fileBytesLength;
}
- info.push(`File Attachments: ${this.formatBytes(filesLength)}`);
+ lines.push(`File Attachments: ${this.formatBytes(filesLength)}`);
}
- // add signal quality if available
- if(lxmfMessage.quality != null){
- info.push(`Signal Quality: ${lxmfMessage.quality}%`);
+ if(!isOutbound){
+ if(lxmfMessage.quality != null){
+ lines.push(`Signal Quality: ${lxmfMessage.quality}%`);
+ }
+ if(lxmfMessage.rssi != null){
+ lines.push(`RSSI: ${lxmfMessage.rssi}dBm`);
+ }
+ if(lxmfMessage.snr != null){
+ lines.push(`SNR: ${lxmfMessage.snr}dB`);
+ }
}
- // add rssi if available
- if(lxmfMessage.rssi != null){
- info.push(`RSSI: ${lxmfMessage.rssi}dBm`);
- }
-
- // add snr if available
- if(lxmfMessage.snr != null){
- info.push(`SNR: ${lxmfMessage.snr}dB`);
- }
-
- // show message info
- DialogUtils.alert(info.join("\n"));
-
+ return lines;
},
},
computed: {
@@ -1621,7 +1709,7 @@ export default {
diff --git a/src/frontend/components/messages/MessagesPage.vue b/src/frontend/components/messages/MessagesPage.vue
index dce2019..55144b4 100644
--- a/src/frontend/components/messages/MessagesPage.vue
+++ b/src/frontend/components/messages/MessagesPage.vue
@@ -103,37 +103,36 @@ export default {
},
methods: {
async onComposeNewMessage(destinationHash) {
-
- // ask for destination address if not provided
if(destinationHash == null){
- destinationHash = await DialogUtils.prompt("Enter LXMF Address");
- if(!destinationHash){
+ if(this.selectedPeer){
return;
}
+ this.$nextTick(() => {
+ const composeInput = document.getElementById("compose-input");
+ if(composeInput){
+ composeInput.focus();
+ }
+ });
+ return;
}
- // if user provided an address with an "lxmf@" prefix, lets remove that to get the raw destination hash
if(destinationHash.startsWith("lxmf@")){
destinationHash = destinationHash.replace("lxmf@", "");
}
- // fetch updated announce as we might be composing new message before we loaded the announces list
await this.getLxmfDeliveryAnnounce(destinationHash);
- // attempt to find existing peer so we can show their name
const existingPeer = this.peers[destinationHash];
if(existingPeer){
this.onPeerClick(existingPeer);
return;
}
- // simple attempt to prevent garbage input
if(destinationHash.length !== 32){
DialogUtils.alert("Invalid Address");
return;
}
- // we didn't find an existing peer, so just use an unknown name
this.onPeerClick({
display_name: "Unknown Peer",
destination_hash: destinationHash,
diff --git a/src/frontend/components/messages/MessagesSidebar.vue b/src/frontend/components/messages/MessagesSidebar.vue
index 36d2842..1b7d5a8 100644
--- a/src/frontend/components/messages/MessagesSidebar.vue
+++ b/src/frontend/components/messages/MessagesSidebar.vue
@@ -44,12 +44,12 @@