cleanup, add button to resend messages

This commit is contained in:
marlon-erler
2024-07-10 15:08:06 +02:00
parent 62ce36e017
commit dd8e86688b
6 changed files with 76 additions and 28 deletions
+34 -11
View File
@@ -260,7 +260,7 @@
var IV_SIZE = 12; var IV_SIZE = 12;
var ENCRYPTION_ALG = "AES-GCM"; var ENCRYPTION_ALG = "AES-GCM";
async function encryptString(plaintext, passphrase) { async function encryptString(plaintext, passphrase) {
if (!window.crypto.subtle) return false; if (!window.crypto.subtle) return plaintext;
const iv = generateIV(); const iv = generateIV();
const key = await importKey(passphrase, "encrypt"); const key = await importKey(passphrase, "encrypt");
const encryptedArray = await encrypt(iv, key, plaintext); const encryptedArray = await encrypt(iv, key, plaintext);
@@ -360,6 +360,7 @@
newSecondaryChannelName; newSecondaryChannelName;
primaryChannelInput; primaryChannelInput;
cannotSendMessage; cannotSendMessage;
cannotResendMessage;
cannotAddSecondaryChannel; cannotAddSecondaryChannel;
cannotSetChannel; cannotSetChannel;
cannotUndoChannel; cannotUndoChannel;
@@ -392,6 +393,10 @@
], ],
() => this.primaryChannel.value == "" || this.composingMessage.value == "" || senderName.value == "" || this.isSubscribed.value == false || isConnected.value == false () => this.primaryChannel.value == "" || this.composingMessage.value == "" || senderName.value == "" || this.isSubscribed.value == false || isConnected.value == false
); );
this.cannotResendMessage = createProxyState(
[this.primaryChannel, this.isSubscribed, isConnected, senderName],
() => this.primaryChannel.value == "" || senderName.value == "" || this.isSubscribed.value == false || isConnected.value == false
);
this.cannotAddSecondaryChannel = createProxyState( this.cannotAddSecondaryChannel = createProxyState(
[this.newSecondaryChannelName], [this.newSecondaryChannelName],
() => this.newSecondaryChannelName.value == "" () => this.newSecondaryChannelName.value == ""
@@ -439,8 +444,16 @@
this.messages.add(chatMessage); this.messages.add(chatMessage);
}; };
// messages // messages
sendMessage = async () => { sendNewMessage = async () => {
if (this.cannotSendMessage.value == true) return; if (this.cannotSendMessage.value == true) return;
this.sendMessageText(this.composingMessage.value);
this.composingMessage.value = "";
};
resendMessage = (message) => {
if (this.cannotResendMessage.value == true) return;
this.sendMessageText(message.body);
};
sendMessageText = async (messageText) => {
const secondaryChannelNames = [ const secondaryChannelNames = [
...this.secondaryChannels.value.values() ...this.secondaryChannels.value.values()
]; ];
@@ -448,10 +461,7 @@
this.primaryChannel.value, this.primaryChannel.value,
...secondaryChannelNames ...secondaryChannelNames
]; ];
const encrypted = this.encryptionKey.value == "" ? this.composingMessage.value : await encryptString( const encrypted = this.encryptionKey.value == "" ? messageText : await encryptString(messageText, this.encryptionKey.value);
this.composingMessage.value,
this.encryptionKey.value
) || this.composingMessage.value;
const joinedChannelName = allChannelNames.join("/"); const joinedChannelName = allChannelNames.join("/");
const messageObject = { const messageObject = {
channel: joinedChannelName, channel: joinedChannelName,
@@ -461,7 +471,6 @@
}; };
const messageString = JSON.stringify(messageObject); const messageString = JSON.stringify(messageObject);
UDN.sendMessage(joinedChannelName, messageString); UDN.sendMessage(joinedChannelName, messageString);
this.composingMessage.value = "";
}; };
clearMessages = () => { clearMessages = () => {
this.messages.clear(); this.messages.clear();
@@ -775,6 +784,7 @@
noChatSelected: "No chat selected", noChatSelected: "No chat selected",
composerPlaceholder: "Type a message...", composerPlaceholder: "Type a message...",
sendMessage: "Send", sendMessage: "Send",
resendMessage: "Resend message",
decryptMessage: "Decrypt message", decryptMessage: "Decrypt message",
copyMessage: "Copy message", copyMessage: "Copy message",
deleteMessage: "Delete message" deleteMessage: "Delete message"
@@ -821,6 +831,7 @@
noChatSelected: "Selecciona un chat", noChatSelected: "Selecciona un chat",
composerPlaceholder: "Escribe un mensaje...", composerPlaceholder: "Escribe un mensaje...",
sendMessage: "Enviar", sendMessage: "Enviar",
resendMessage: "Enviar de nuevo",
decryptMessage: "Descifrar mensaje", decryptMessage: "Descifrar mensaje",
copyMessage: "Copiar mensaje", copyMessage: "Copiar mensaje",
deleteMessage: "Eliminar este mensaje" deleteMessage: "Eliminar este mensaje"
@@ -865,6 +876,7 @@
noChatSelected: "Kein Chat ausgew\xE4hlt", noChatSelected: "Kein Chat ausgew\xE4hlt",
composerPlaceholder: "Neue Nachricht...", composerPlaceholder: "Neue Nachricht...",
sendMessage: "Senden", sendMessage: "Senden",
resendMessage: "Erneut senden",
decryptMessage: "Nachricht entschl\xFCsseln", decryptMessage: "Nachricht entschl\xFCsseln",
copyMessage: "Nachricht kopieren", copyMessage: "Nachricht kopieren",
deleteMessage: "Nachricht l\xF6schen" deleteMessage: "Nachricht l\xF6schen"
@@ -981,13 +993,13 @@
style: "max-width: unset", style: "max-width: unset",
placeholder: translation.composerPlaceholder, placeholder: translation.composerPlaceholder,
"bind:value": chat.composingMessage, "bind:value": chat.composingMessage,
"on:enter": chat.sendMessage "on:enter": chat.sendNewMessage
} }
), /* @__PURE__ */ createElement( ), /* @__PURE__ */ createElement(
"button", "button",
{ {
class: "primary", class: "primary",
"on:click": chat.sendMessage, "on:click": chat.sendNewMessage,
"toggle:disabled": chat.cannotSendMessage "toggle:disabled": chat.cannotSendMessage
}, },
/* @__PURE__ */ createElement("span", { class: "icon" }, "send") /* @__PURE__ */ createElement("span", { class: "icon" }, "send")
@@ -997,6 +1009,9 @@
// src/Views/threadView.tsx // src/Views/threadView.tsx
function ThreadView(chat) { function ThreadView(chat) {
const messageConverter = (message) => { const messageConverter = (message) => {
function resendMessage() {
chat.resendMessage(message);
}
function copyMessage() { function copyMessage() {
navigator.clipboard.writeText(message.body); navigator.clipboard.writeText(message.body);
} }
@@ -1010,7 +1025,15 @@
[chat.messages], [chat.messages],
() => message.body () => message.body
); );
return /* @__PURE__ */ createElement("div", { class: "tile width-100 flex-no padding-0" }, /* @__PURE__ */ createElement("div", { class: "flex-column" }, /* @__PURE__ */ createElement("div", { class: "flex-row justify-apart align-center secondary" }, /* @__PURE__ */ createElement("span", { class: "padding-h ellipsis" }, /* @__PURE__ */ createElement("b", { class: "info" }, message.sender), " - ", message.channel), /* @__PURE__ */ createElement("span", { class: "flex-row" }, /* @__PURE__ */ createElement( return /* @__PURE__ */ createElement("div", { class: "tile width-100 flex-no padding-0" }, /* @__PURE__ */ createElement("div", { class: "flex-column" }, /* @__PURE__ */ createElement("div", { class: "flex-row justify-apart align-center secondary" }, /* @__PURE__ */ createElement("span", { class: "padding-h ellipsis" }, /* @__PURE__ */ createElement("b", { class: "info" }, message.sender)), /* @__PURE__ */ createElement("span", { class: "flex-row" }, /* @__PURE__ */ createElement(
"button",
{
"aria-label": translation.resendMessage,
"on:click": resendMessage,
"toggle:disabled": chat.cannotResendMessage
},
/* @__PURE__ */ createElement("span", { class: "icon" }, "replay")
), /* @__PURE__ */ createElement(
"button", "button",
{ {
"aria-label": translation.copyMessage, "aria-label": translation.copyMessage,
@@ -1024,7 +1047,7 @@
"on:click": decrypt2 "on:click": decrypt2
}, },
/* @__PURE__ */ createElement("span", { class: "icon" }, "key") /* @__PURE__ */ createElement("span", { class: "icon" }, "key")
), /* @__PURE__ */ createElement("button", { "aria-label": translation.deleteMessage, "on:click": remove }, /* @__PURE__ */ createElement("span", { class: "icon" }, "delete")))), /* @__PURE__ */ createElement("div", { class: "flex-column padding-h padding-bottom" }, /* @__PURE__ */ createElement("b", { class: "break-word", "subscribe:innerText": messageBody }), /* @__PURE__ */ createElement("span", { class: "secondary" }, new Date(message.isoDate).toLocaleString())))); ), /* @__PURE__ */ createElement("button", { "aria-label": translation.deleteMessage, "on:click": remove }, /* @__PURE__ */ createElement("span", { class: "icon" }, "delete")))), /* @__PURE__ */ createElement("div", { class: "flex-column padding-h padding-bottom" }, /* @__PURE__ */ createElement("b", { class: "break-word", "subscribe:innerText": messageBody }), /* @__PURE__ */ createElement("span", { class: "secondary" }, /* @__PURE__ */ createElement("b", null, new Date(message.isoDate).toLocaleString()), " - ", message.channel))));
}; };
const listElement = /* @__PURE__ */ createElement( const listElement = /* @__PURE__ */ createElement(
"div", "div",
+22 -9
View File
@@ -38,6 +38,7 @@ export class Chat {
primaryChannelInput: React.State<string>; primaryChannelInput: React.State<string>;
cannotSendMessage: React.State<boolean>; cannotSendMessage: React.State<boolean>;
cannotResendMessage: React.State<boolean>;
cannotAddSecondaryChannel: React.State<boolean>; cannotAddSecondaryChannel: React.State<boolean>;
cannotSetChannel: React.State<boolean>; cannotSetChannel: React.State<boolean>;
cannotUndoChannel: React.State<boolean>; cannotUndoChannel: React.State<boolean>;
@@ -84,6 +85,14 @@ export class Chat {
this.isSubscribed.value == false || this.isSubscribed.value == false ||
isConnected.value == false isConnected.value == false
); );
this.cannotResendMessage = React.createProxyState(
[this.primaryChannel, this.isSubscribed, isConnected, senderName],
() =>
this.primaryChannel.value == "" ||
senderName.value == "" ||
this.isSubscribed.value == false ||
isConnected.value == false
);
this.cannotAddSecondaryChannel = React.createProxyState( this.cannotAddSecondaryChannel = React.createProxyState(
[this.newSecondaryChannelName], [this.newSecondaryChannelName],
() => this.newSecondaryChannelName.value == "" () => this.newSecondaryChannelName.value == ""
@@ -141,9 +150,19 @@ export class Chat {
}; };
// messages // messages
sendMessage = async (): Promise<void> => { sendNewMessage = async (): Promise<void> => {
if (this.cannotSendMessage.value == true) return; if (this.cannotSendMessage.value == true) return;
this.sendMessageText(this.composingMessage.value);
this.composingMessage.value = "";
};
resendMessage = (message: ChatMessage) => {
if (this.cannotResendMessage.value == true) return;
this.sendMessageText(message.body);
};
sendMessageText = async (messageText: string): Promise<void> => {
// get channels // get channels
const secondaryChannelNames: string[] = [ const secondaryChannelNames: string[] = [
...this.secondaryChannels.value.values(), ...this.secondaryChannels.value.values(),
@@ -156,11 +175,8 @@ export class Chat {
// encrypt // encrypt
const encrypted = const encrypted =
this.encryptionKey.value == "" this.encryptionKey.value == ""
? this.composingMessage.value ? messageText
: (await encryptString( : await encryptString(messageText, this.encryptionKey.value);
this.composingMessage.value,
this.encryptionKey.value
)) || this.composingMessage.value;
// create object // create object
const joinedChannelName = allChannelNames.join("/"); const joinedChannelName = allChannelNames.join("/");
@@ -174,9 +190,6 @@ export class Chat {
// send // send
UDN.sendMessage(joinedChannelName, messageString); UDN.sendMessage(joinedChannelName, messageString);
// clear
this.composingMessage.value = "";
}; };
clearMessages = (): void => { clearMessages = (): void => {
+2 -2
View File
@@ -12,11 +12,11 @@ export function MessageComposer(chat: Chat) {
style="max-width: unset" style="max-width: unset"
placeholder={translation.composerPlaceholder} placeholder={translation.composerPlaceholder}
bind:value={chat.composingMessage} bind:value={chat.composingMessage}
on:enter={chat.sendMessage} on:enter={chat.sendNewMessage}
></input> ></input>
<button <button
class="primary" class="primary"
on:click={chat.sendMessage} on:click={chat.sendNewMessage}
toggle:disabled={chat.cannotSendMessage} toggle:disabled={chat.cannotSendMessage}
> >
<span class="icon">send</span> <span class="icon">send</span>
+13 -4
View File
@@ -6,6 +6,10 @@ import { translation } from "../translations";
export function ThreadView(chat: Chat) { export function ThreadView(chat: Chat) {
const messageConverter: React.ListItemConverter<ChatMessage> = (message) => { const messageConverter: React.ListItemConverter<ChatMessage> = (message) => {
function resendMessage() {
chat.resendMessage(message);
}
function copyMessage() { function copyMessage() {
navigator.clipboard.writeText(message.body); navigator.clipboard.writeText(message.body);
} }
@@ -28,9 +32,16 @@ export function ThreadView(chat: Chat) {
<div class="flex-column"> <div class="flex-column">
<div class="flex-row justify-apart align-center secondary"> <div class="flex-row justify-apart align-center secondary">
<span class="padding-h ellipsis"> <span class="padding-h ellipsis">
<b class="info">{message.sender}</b> - {message.channel} <b class="info">{message.sender}</b>
</span> </span>
<span class="flex-row"> <span class="flex-row">
<button
aria-label={translation.resendMessage}
on:click={resendMessage}
toggle:disabled={chat.cannotResendMessage}
>
<span class="icon">replay</span>
</button>
<button <button
aria-label={translation.copyMessage} aria-label={translation.copyMessage}
on:click={copyMessage} on:click={copyMessage}
@@ -50,9 +61,7 @@ export function ThreadView(chat: Chat) {
</div> </div>
<div class="flex-column padding-h padding-bottom"> <div class="flex-column padding-h padding-bottom">
<b class="break-word" subscribe:innerText={messageBody}></b> <b class="break-word" subscribe:innerText={messageBody}></b>
<span class="secondary"> <span class="secondary"><b>{new Date(message.isoDate).toLocaleString()}</b> - {message.channel}</span>
{new Date(message.isoDate).toLocaleString()}
</span>
</div> </div>
</div> </div>
</div> </div>
+2 -2
View File
@@ -5,8 +5,8 @@ const ENCRYPTION_ALG = "AES-GCM";
export async function encryptString( export async function encryptString(
plaintext: string, plaintext: string,
passphrase: string passphrase: string
): Promise<string | false> { ): Promise<string> {
if (!window.crypto.subtle) return false; if (!window.crypto.subtle) return plaintext;
const iv = generateIV(); const iv = generateIV();
const key = await importKey(passphrase, "encrypt"); const key = await importKey(passphrase, "encrypt");
+3
View File
@@ -55,6 +55,7 @@ const englishTranslations = {
composerPlaceholder: "Type a message...", composerPlaceholder: "Type a message...",
sendMessage: "Send", sendMessage: "Send",
resendMessage: "Resend message",
decryptMessage: "Decrypt message", decryptMessage: "Decrypt message",
copyMessage: "Copy message", copyMessage: "Copy message",
deleteMessage: "Delete message", deleteMessage: "Delete message",
@@ -119,6 +120,7 @@ const allTranslations: { [key: string]: typeof englishTranslations } = {
composerPlaceholder: "Escribe un mensaje...", composerPlaceholder: "Escribe un mensaje...",
sendMessage: "Enviar", sendMessage: "Enviar",
resendMessage: "Enviar de nuevo",
decryptMessage: "Descifrar mensaje", decryptMessage: "Descifrar mensaje",
copyMessage: "Copiar mensaje", copyMessage: "Copiar mensaje",
deleteMessage: "Eliminar este mensaje", deleteMessage: "Eliminar este mensaje",
@@ -180,6 +182,7 @@ const allTranslations: { [key: string]: typeof englishTranslations } = {
composerPlaceholder: "Neue Nachricht...", composerPlaceholder: "Neue Nachricht...",
sendMessage: "Senden", sendMessage: "Senden",
resendMessage: "Erneut senden",
decryptMessage: "Nachricht entschlüsseln", decryptMessage: "Nachricht entschlüsseln",
copyMessage: "Nachricht kopieren", copyMessage: "Nachricht kopieren",
deleteMessage: "Nachricht löschen", deleteMessage: "Nachricht löschen",