add MessageInfoModal

This commit is contained in:
marlon-erler
2024-07-21 13:13:41 +02:00
parent a0932c2198
commit ca8f1d3348
10 changed files with 409 additions and 78 deletions
+32 -9
View File
@@ -422,24 +422,44 @@ body[showing-chat] #chat-page-wrapper {
width: 100%; width: 100%;
max-width: var(--max-content-width); max-width: var(--max-content-width);
} }
.message-bubble > div { .message-bubble .main {
display: flex; display: flex;
flex-direction: column; flex-direction: row;
background-color: var(--surface); background-color: var(--surface);
padding: var(--control-padding);
width: 100%; width: 100%;
max-width: var(--max-input-width); max-width: var(--max-input-width);
overflow: hidden;
} }
.message-bubble .timestamp, .message-bubble .main .text-container {
.message-bubble .sender-name { display: flex;
flex-direction: column;
overflow: hidden;
width: 100%;
flex: 1;
}
.message-bubble .main .button-container {
display: flex;
align-items: start;
}
.message-bubble .main button {
justify-content: center;
padding: 0px;
width: var(--control-height);
--surface: transparent;
}
.message-bubble .main .text-container {
padding: var(--control-padding);
}
.message-bubble .main .timestamp,
.message-bubble .main .sender-name {
font-size: 0.8rem; font-size: 0.8rem;
opacity: 0.6; opacity: 0.6;
} }
.message-bubble .sender-name { .message-bubble .main .sender-name {
font-weight: bold; font-weight: bold;
} }
.message-bubble .body { .message-bubble .main .body {
word-break: break-all; word-break: break-word;
} }
.message-bubble[sentbyuser] { .message-bubble[sentbyuser] {
justify-content: flex-end; justify-content: flex-end;
@@ -447,7 +467,10 @@ body[showing-chat] #chat-page-wrapper {
.message-bubble[sentbyuser] { .message-bubble[sentbyuser] {
align-items: flex-end; align-items: flex-end;
} }
.message-bubble[sentbyuser] span { .message-bubble[sentbyuser] .main {
flex-direction: row-reverse;
}
.message-bubble[sentbyuser] .main span {
text-align: right; text-align: right;
} }
+153 -36
View File
@@ -125,6 +125,49 @@
return json; return json;
} }
}; };
var MapState = class extends State {
additionHandlers = /* @__PURE__ */ new Set();
removalHandlers = /* @__PURE__ */ new Map();
// init
constructor(initialItems) {
super(new Map(initialItems));
}
// list
set(key, item) {
this.remove(key);
this.value.set(key, item);
this.additionHandlers.forEach((handler) => handler(item));
this.callSubscriptions();
}
remove(key) {
const item = this.value.get(key);
if (!item) return;
this.value.delete(key);
this.callSubscriptions();
if (!this.removalHandlers.has(item)) return;
this.removalHandlers.get(item).forEach((handler) => handler(item));
this.removalHandlers.delete(item);
}
clear() {
[...this.value.keys()].forEach((key) => this.remove(key));
}
// handlers
handleAddition(handler) {
this.additionHandlers.add(handler);
[...this.value.values()].forEach(handler);
}
handleRemoval(item, handler) {
if (!this.removalHandlers.has(item))
this.removalHandlers.set(item, /* @__PURE__ */ new Set());
this.removalHandlers.get(item).add(handler);
}
// stringification
toString() {
const array = [...this.value.entries()];
const json = JSON.stringify(array);
return json;
}
};
function createProxyState(statesToSubscibe, fn) { function createProxyState(statesToSubscibe, fn) {
const proxyState = new State(fn()); const proxyState = new State(fn());
statesToSubscibe.forEach( statesToSubscibe.forEach(
@@ -223,6 +266,7 @@
} }
} }
} }
break;
} }
default: default:
element.setAttribute(attributename, value); element.setAttribute(attributename, value);
@@ -604,7 +648,6 @@
const chatMessage = _ChatModel.parseMessage(body); const chatMessage = _ChatModel.parseMessage(body);
if (chatMessage == null) return; if (chatMessage == null) return;
await this.decryptMessage(chatMessage); await this.decryptMessage(chatMessage);
this.addMessage(chatMessage);
}; };
decryptMessage = async (chatMessage) => { decryptMessage = async (chatMessage) => {
const decryptedBody = await decryptString( const decryptedBody = await decryptString(
@@ -612,6 +655,7 @@
this.info.encryptionKey this.info.encryptionKey
); );
chatMessage.body = decryptedBody; chatMessage.body = decryptedBody;
this.addMessage(chatMessage);
}; };
setMessageHandler = (handler) => { setMessageHandler = (handler) => {
this.chatMessageHandler = handler; this.chatMessageHandler = handler;
@@ -744,20 +788,37 @@
// src/Model/chatMessageViewModel.ts // src/Model/chatMessageViewModel.ts
var ChatMessageViewModel = class { var ChatMessageViewModel = class {
chatModel; chatViewModel;
// data // data
chatMessage;
channel; channel;
sender; sender;
dateSent; dateSent;
body = new State(""); body = new State("");
sentByUser; sentByUser;
constructor(chatModel, chatMessage, sentByUser) { // methods
this.chatModel = chatModel; copyMessage = () => {
this.channel = chatMessage.channel; navigator.clipboard.writeText(this.body.value);
this.sender = chatMessage.sender; };
this.dateSent = new Date(chatMessage.dateSent).toLocaleString(); resendMessage = () => {
this.body.value = chatMessage.body; this.chatViewModel.sendMessageFromBody(this.body.value);
};
decryptMessage = () => {
this.chatViewModel.decryptMessage(this);
};
// load
loadData = () => {
this.channel = this.chatMessage.channel;
this.sender = this.chatMessage.sender;
this.dateSent = new Date(this.chatMessage.dateSent).toLocaleString();
this.body.value = this.chatMessage.body;
};
// init
constructor(chatViewModel, chatMessage, sentByUser) {
this.chatViewModel = chatViewModel;
this.chatMessage = chatMessage;
this.sentByUser = sentByUser; this.sentByUser = sentByUser;
this.loadData();
} }
}; };
@@ -783,7 +844,7 @@
selectedPage = new State( selectedPage = new State(
"messages" /* Messages */ "messages" /* Messages */
); );
chatMessageViewModels = new ListState(); chatMessageViewModels = new MapState();
composingMessage = new State(""); composingMessage = new State("");
// guards // guards
cannotSetPrimaryChannel = createProxyState( cannotSetPrimaryChannel = createProxyState(
@@ -810,11 +871,16 @@
// add // add
addChatMessage = (chatMessage) => { addChatMessage = (chatMessage) => {
const chatMessageModel = new ChatMessageViewModel( const chatMessageModel = new ChatMessageViewModel(
this.chatModel, this,
chatMessage, chatMessage,
chatMessage.sender == this.settingsViewModel.username.value chatMessage.sender == this.settingsViewModel.username.value
); );
this.chatMessageViewModels.add(chatMessageModel); const existingChatMessageViewModel = this.chatMessageViewModels.value.get(chatMessage.id);
if (existingChatMessageViewModel != void 0) {
existingChatMessageViewModel.body.value = chatMessage.body;
} else {
this.chatMessageViewModels.set(chatMessage.id, chatMessageModel);
}
}; };
// settings // settings
setPrimaryChannel = () => { setPrimaryChannel = () => {
@@ -852,9 +918,16 @@
}; };
// messaging // messaging
sendMessage = () => { sendMessage = () => {
this.chatModel.sendMessage(this.composingMessage.value); this.sendMessageFromBody(this.composingMessage.value);
this.composingMessage.value = ""; this.composingMessage.value = "";
}; };
sendMessageFromBody = (body) => {
this.chatModel.sendMessage(body);
};
decryptMessage = async (messageViewModel) => {
await this.chatModel.decryptMessage(messageViewModel.chatMessage);
messageViewModel.loadData();
};
// restore // restore
restorePageSelection = () => { restorePageSelection = () => {
const path = storageKeys.chatLastUsedPage(this.chatModel.id); const path = storageKeys.chatLastUsedPage(this.chatModel.id);
@@ -991,31 +1064,10 @@
); );
} }
// src/View/Components/chatMessage.tsx
function ChatMessage(chatMessageViewModel) {
return /* @__PURE__ */ createElement(
"div",
{
class: "message-bubble",
"toggle:sentbyuser": chatMessageViewModel.sentByUser
},
/* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", { class: "sender-name ellipsis" }, chatMessageViewModel.sender), /* @__PURE__ */ createElement(
"span",
{
class: "body",
"subscribe:innerText": chatMessageViewModel.body
}
), /* @__PURE__ */ createElement("span", { class: "timestamp ellipsis" }, chatMessageViewModel.dateSent))
);
}
var ChatMessageViewModelToView = (chatMessageViewModel) => {
return ChatMessage(chatMessageViewModel);
};
// src/View/translations.ts // src/View/translations.ts
var englishTranslations = { var englishTranslations = {
general: { general: {
closeButtonAudioLabel: "Close", closeButton: "Close",
deleteItemButtonAudioLabel: "delete item", deleteItemButtonAudioLabel: "delete item",
setButton: "Set" setButton: "Set"
}, },
@@ -1089,7 +1141,17 @@
}, },
message: { message: {
composerInputPlaceholder: "Type a message...", composerInputPlaceholder: "Type a message...",
sendMessageButtonAudioLabel: "send message" sendMessageButtonAudioLabel: "send message",
showMessageInfoButtonAudioLabel: "show message info",
messageInfoHeadline: "Message Info",
sentBy: "Sent by",
timeSent: "Time sent",
channel: "Channel",
messageContent: "Message content",
copyMessageButton: "Copy message",
resendMessageButton: "Resend message",
decryptMessageButton: "Decrypt message",
deleteMessageButton: "Delete message"
} }
} }
}; };
@@ -1099,6 +1161,61 @@
var language = navigator.language.substring(0, 2); var language = navigator.language.substring(0, 2);
var translations = allTranslations[language] || allTranslations.en; var translations = allTranslations[language] || allTranslations.en;
// src/View/Components/chatMessageInfoModal.tsx
function ChatMessageInfoModal(chatMessageViewModel, isOpen) {
function closeModal() {
isOpen.value = false;
}
return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isOpen }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, translations.chatPage.message.messageInfoHeadline), /* @__PURE__ */ createElement("div", { class: "flex-column gap" }, /* @__PURE__ */ createElement("div", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "account_circle"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translations.chatPage.message.sentBy), /* @__PURE__ */ createElement("b", { class: "break-word" }, chatMessageViewModel.sender))), /* @__PURE__ */ createElement("div", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "schedule"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translations.chatPage.message.timeSent), /* @__PURE__ */ createElement("b", { class: "break-word" }, chatMessageViewModel.dateSent))), /* @__PURE__ */ createElement("div", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "forum"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translations.chatPage.message.channel), /* @__PURE__ */ createElement("b", { class: "break-word" }, chatMessageViewModel.channel))), /* @__PURE__ */ createElement("div", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "description"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translations.chatPage.message.messageContent), /* @__PURE__ */ createElement(
"b",
{
class: "break-word",
"subscribe:innerText": chatMessageViewModel.body
}
)))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "flex-column gap" }, /* @__PURE__ */ createElement("button", { "on:click": chatMessageViewModel.copyMessage }, translations.chatPage.message.copyMessageButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "content_copy")), /* @__PURE__ */ createElement("button", { "on:click": chatMessageViewModel.resendMessage }, translations.chatPage.message.resendMessageButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "redo")), /* @__PURE__ */ createElement("button", { "on:click": chatMessageViewModel.decryptMessage }, translations.chatPage.message.decryptMessageButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "key")))), /* @__PURE__ */ createElement(
"button",
{
"on:click": closeModal,
"aria-label": translations.general.closeButton
},
translations.general.closeButton,
/* @__PURE__ */ createElement("span", { class: "icon" }, "close")
)));
}
// src/View/Components/chatMessage.tsx
function ChatMessage(chatMessageViewModel) {
const isInfoModalOpen = new State(false);
function openModal() {
isInfoModalOpen.value = true;
}
return /* @__PURE__ */ createElement(
"div",
{
class: "message-bubble",
"toggle:sentbyuser": chatMessageViewModel.sentByUser
},
/* @__PURE__ */ createElement("div", { class: "main" }, /* @__PURE__ */ createElement("div", { class: "text-container" }, /* @__PURE__ */ createElement("span", { class: "sender-name ellipsis" }, chatMessageViewModel.sender), /* @__PURE__ */ createElement(
"span",
{
class: "body",
"subscribe:innerText": chatMessageViewModel.body
}
), /* @__PURE__ */ createElement("span", { class: "timestamp ellipsis" }, chatMessageViewModel.dateSent)), /* @__PURE__ */ createElement("div", { class: "button-container" }, /* @__PURE__ */ createElement(
"button",
{
"on:click": openModal,
"aria-label": translations.chatPage.message.showMessageInfoButtonAudioLabel
},
/* @__PURE__ */ createElement("span", { class: "icon" }, "info")
))),
ChatMessageInfoModal(chatMessageViewModel, isInfoModalOpen)
);
}
var ChatMessageViewModelToView = (chatMessageViewModel) => {
return ChatMessage(chatMessageViewModel);
};
// src/View/ChatPages/messagePage.tsx // src/View/ChatPages/messagePage.tsx
function MessagePage(chatViewModel) { function MessagePage(chatViewModel) {
const messageContainer = /* @__PURE__ */ createElement( const messageContainer = /* @__PURE__ */ createElement(
@@ -1369,7 +1486,7 @@
previousAddressConverter previousAddressConverter
] ]
} }
)), /* @__PURE__ */ createElement("button", { "on:click": connectionViewModel2.hideConnectionModal }, translations.general.closeButtonAudioLabel, /* @__PURE__ */ createElement("span", { class: "icon" }, "close"))) )), /* @__PURE__ */ createElement("button", { "on:click": connectionViewModel2.hideConnectionModal }, translations.general.closeButton, /* @__PURE__ */ createElement("span", { class: "icon" }, "close")))
); );
} }
+28 -7
View File
@@ -4,27 +4,48 @@ import * as React from "bloatless-react";
import { ChatMessage, ChatModel } from "./chatModel"; import { ChatMessage, ChatModel } from "./chatModel";
import ChatViewModel from "../ViewModel/chatViewModel";
export default class ChatMessageViewModel { export default class ChatMessageViewModel {
chatModel: ChatModel; chatViewModel: ChatViewModel;
// data // data
chatMessage: ChatMessage;
channel: string; channel: string;
sender: string; sender: string;
dateSent: string; dateSent: string;
body: React.State<string> = new React.State(""); body: React.State<string> = new React.State("");
sentByUser: boolean; sentByUser: boolean;
// methods
copyMessage = (): void => {
navigator.clipboard.writeText(this.body.value);
};
resendMessage = (): void => {
this.chatViewModel.sendMessageFromBody(this.body.value);
};
decryptMessage = (): void => {
this.chatViewModel.decryptMessage(this);
};
// load
loadData = (): void => {
this.channel = this.chatMessage.channel;
this.sender = this.chatMessage.sender;
this.dateSent = new Date(this.chatMessage.dateSent).toLocaleString();
this.body.value = this.chatMessage.body;
};
// init
constructor( constructor(
chatModel: ChatModel, chatViewModel: ChatViewModel,
chatMessage: ChatMessage, chatMessage: ChatMessage,
sentByUser: boolean sentByUser: boolean
) { ) {
this.chatModel = chatModel; this.chatViewModel = chatViewModel;
this.channel = chatMessage.channel; this.chatMessage = chatMessage;
this.sender = chatMessage.sender;
this.dateSent = new Date(chatMessage.dateSent).toLocaleString();
this.body.value = chatMessage.body;
this.sentByUser = sentByUser; this.sentByUser = sentByUser;
this.loadData();
} }
} }
+1 -1
View File
@@ -196,7 +196,6 @@ export class ChatModel {
if (chatMessage == null) return; if (chatMessage == null) return;
await this.decryptMessage(chatMessage); await this.decryptMessage(chatMessage);
this.addMessage(chatMessage);
}; };
decryptMessage = async (chatMessage: ChatMessage): Promise<void> => { decryptMessage = async (chatMessage: ChatMessage): Promise<void> => {
@@ -205,6 +204,7 @@ export class ChatModel {
this.info.encryptionKey this.info.encryptionKey
); );
chatMessage.body = decryptedBody; chatMessage.body = decryptedBody;
this.addMessage(chatMessage);
}; };
setMessageHandler = (handler: (chatMessage: ChatMessage) => void): void => { setMessageHandler = (handler: (chatMessage: ChatMessage) => void): void => {
+41 -10
View File
@@ -30,7 +30,6 @@
} }
@media (max-width: 700px) { @media (max-width: 700px) {
#message-page #composer div { #message-page #composer div {
width: 100%; width: 100%;
max-width: unset; max-width: unset;
@@ -79,29 +78,57 @@
max-width: var(--max-content-width); max-width: var(--max-content-width);
} }
.message-bubble > div { .message-bubble .main {
display: flex; display: flex;
flex-direction: column; flex-direction: row;
background-color: var(--surface); background-color: var(--surface);
padding: var(--control-padding);
width: 100%; width: 100%;
max-width: var(--max-input-width); max-width: var(--max-input-width);
overflow: hidden;
} }
.message-bubble .timestamp, .message-bubble .main .text-container {
.message-bubble .sender-name { display: flex;
flex-direction: column;
overflow: hidden;
width: 100%;
flex: 1;
}
.message-bubble .main .button-container {
display: flex;
align-items: start;
}
.message-bubble .main button {
justify-content: center;
padding: 0px;
width: var(--control-height);
--surface: transparent;
}
.message-bubble .main .text-container {
padding: var(--control-padding);
}
.message-bubble .main .timestamp,
.message-bubble .main .sender-name {
font-size: 0.8rem; font-size: 0.8rem;
opacity: 0.6; opacity: 0.6;
} }
.message-bubble .sender-name { .message-bubble .main .sender-name {
font-weight: bold; font-weight: bold;
} }
.message-bubble .body { .message-bubble .main .body {
word-break: break-all; word-break: break-word;
} }
.message-bubble[sentbyuser] { .message-bubble[sentbyuser] {
@@ -112,6 +139,10 @@
align-items: flex-end; align-items: flex-end;
} }
.message-bubble[sentbyuser] span { .message-bubble[sentbyuser] .main {
flex-direction: row-reverse;
}
.message-bubble[sentbyuser] .main span {
text-align: right; text-align: right;
} }
+28 -3
View File
@@ -1,21 +1,46 @@
import * as React from "bloatless-react"; import * as React from "bloatless-react";
import { ChatMessageInfoModal } from "./chatMessageInfoModal";
import ChatMessageViewModel from "../../Model/chatMessageViewModel"; import ChatMessageViewModel from "../../Model/chatMessageViewModel";
import { translations } from "../translations";
export function ChatMessage(chatMessageViewModel: ChatMessageViewModel) { export function ChatMessage(chatMessageViewModel: ChatMessageViewModel) {
const isInfoModalOpen = new React.State(false);
function openModal() {
isInfoModalOpen.value = true;
}
return ( return (
<div <div
class="message-bubble" class="message-bubble"
toggle:sentbyuser={chatMessageViewModel.sentByUser} toggle:sentbyuser={chatMessageViewModel.sentByUser}
> >
<div> <div class="main">
<span class="sender-name ellipsis">{chatMessageViewModel.sender}</span> <div class="text-container">
<span class="sender-name ellipsis">
{chatMessageViewModel.sender}
</span>
<span <span
class="body" class="body"
subscribe:innerText={chatMessageViewModel.body} subscribe:innerText={chatMessageViewModel.body}
></span> ></span>
<span class="timestamp ellipsis">{chatMessageViewModel.dateSent}</span> <span class="timestamp ellipsis">
{chatMessageViewModel.dateSent}
</span>
</div> </div>
<div class="button-container">
<button
on:click={openModal}
aria-label={
translations.chatPage.message.showMessageInfoButtonAudioLabel
}
>
<span class="icon">info</span>
</button>
</div>
</div>
{ChatMessageInfoModal(chatMessageViewModel, isInfoModalOpen)}
</div> </div>
); );
} }
@@ -0,0 +1,84 @@
import * as React from "bloatless-react";
import ChatMessageViewModel from "../../Model/chatMessageViewModel";
import { translations } from "../translations";
export function ChatMessageInfoModal(
chatMessageViewModel: ChatMessageViewModel,
isOpen: React.State<boolean>
) {
function closeModal() {
isOpen.value = false;
}
return (
<div class="modal" toggle:open={isOpen}>
<div>
<main>
<h2>{translations.chatPage.message.messageInfoHeadline}</h2>
<div class="flex-column gap">
<div class="tile">
<span class="icon">account_circle</span>
<div>
<span>{translations.chatPage.message.sentBy}</span>
<b class="break-word">{chatMessageViewModel.sender}</b>
</div>
</div>
<div class="tile">
<span class="icon">schedule</span>
<div>
<span>{translations.chatPage.message.timeSent}</span>
<b class="break-word">{chatMessageViewModel.dateSent}</b>
</div>
</div>
<div class="tile">
<span class="icon">forum</span>
<div>
<span>{translations.chatPage.message.channel}</span>
<b class="break-word">{chatMessageViewModel.channel}</b>
</div>
</div>
<div class="tile">
<span class="icon">description</span>
<div>
<span>{translations.chatPage.message.messageContent}</span>
<b
class="break-word"
subscribe:innerText={chatMessageViewModel.body}
></b>
</div>
</div>
</div>
<hr></hr>
<div class="flex-column gap">
<button on:click={chatMessageViewModel.copyMessage}>
{translations.chatPage.message.copyMessageButton}
<span class="icon">content_copy</span>
</button>
<button on:click={chatMessageViewModel.resendMessage}>
{translations.chatPage.message.resendMessageButton}
<span class="icon">redo</span>
</button>
<button on:click={chatMessageViewModel.decryptMessage}>
{translations.chatPage.message.decryptMessageButton}
<span class="icon">key</span>
</button>
</div>
</main>
<button
on:click={closeModal}
aria-label={translations.general.closeButton}
>
{translations.general.closeButton}
<span class="icon">close</span>
</button>
</div>
</div>
);
}
+1 -1
View File
@@ -53,7 +53,7 @@ export function ConnectionModal(connectionViewModel: ConnectionViewModel) {
></div> ></div>
</main> </main>
<button on:click={connectionViewModel.hideConnectionModal}> <button on:click={connectionViewModel.hideConnectionModal}>
{translations.general.closeButtonAudioLabel} {translations.general.closeButton}
<span class="icon">close</span> <span class="icon">close</span>
</button> </button>
</div> </div>
+14 -1
View File
@@ -1,6 +1,6 @@
const englishTranslations = { const englishTranslations = {
general: { general: {
closeButtonAudioLabel: "Close", closeButton: "Close",
deleteItemButtonAudioLabel: "delete item", deleteItemButtonAudioLabel: "delete item",
setButton: "Set", setButton: "Set",
@@ -102,6 +102,19 @@ const englishTranslations = {
message: { message: {
composerInputPlaceholder: "Type a message...", composerInputPlaceholder: "Type a message...",
sendMessageButtonAudioLabel: "send message", sendMessageButtonAudioLabel: "send message",
showMessageInfoButtonAudioLabel: "show message info",
messageInfoHeadline: "Message Info",
sentBy: "Sent by",
timeSent: "Time sent",
channel: "Channel",
messageContent: "Message content",
copyMessageButton: "Copy message",
resendMessageButton: "Resend message",
decryptMessageButton: "Decrypt message",
deleteMessageButton: "Delete message",
} }
}, },
}; };
+23 -6
View File
@@ -6,7 +6,6 @@ import StorageModel, { storageKeys } from "../Model/storageModel";
import ChatListViewModel from "./chatListViewModel"; import ChatListViewModel from "./chatListViewModel";
import ChatMessageViewModel from "../Model/chatMessageViewModel"; import ChatMessageViewModel from "../Model/chatMessageViewModel";
import { Color } from "./colors"; import { Color } from "./colors";
import SettingsModel from "../Model/settingsModel";
import SettingsViewModel from "./settingsViewModel"; import SettingsViewModel from "./settingsViewModel";
import { localeCompare } from "../Model/Utility/utility"; import { localeCompare } from "../Model/Utility/utility";
@@ -38,8 +37,8 @@ export default class ChatViewModel {
ChatPageType.Messages ChatPageType.Messages
); );
chatMessageViewModels: React.ListState<ChatMessageViewModel> = chatMessageViewModels: React.MapState<ChatMessageViewModel> =
new React.ListState(); new React.MapState();
composingMessage: React.State<string> = new React.State(""); composingMessage: React.State<string> = new React.State("");
// guards // guards
@@ -73,11 +72,18 @@ export default class ChatViewModel {
// add // add
addChatMessage = (chatMessage: ChatMessage): void => { addChatMessage = (chatMessage: ChatMessage): void => {
const chatMessageModel = new ChatMessageViewModel( const chatMessageModel = new ChatMessageViewModel(
this.chatModel, this,
chatMessage, chatMessage,
chatMessage.sender == this.settingsViewModel.username.value chatMessage.sender == this.settingsViewModel.username.value
); );
this.chatMessageViewModels.add(chatMessageModel);
const existingChatMessageViewModel: ChatMessageViewModel | undefined =
this.chatMessageViewModels.value.get(chatMessage.id);
if (existingChatMessageViewModel != undefined) {
existingChatMessageViewModel.body.value = chatMessage.body;
} else {
this.chatMessageViewModels.set(chatMessage.id, chatMessageModel);
}
}; };
// settings // settings
@@ -125,10 +131,21 @@ export default class ChatViewModel {
// messaging // messaging
sendMessage = (): void => { sendMessage = (): void => {
this.chatModel.sendMessage(this.composingMessage.value); this.sendMessageFromBody(this.composingMessage.value);
this.composingMessage.value = ""; this.composingMessage.value = "";
}; };
sendMessageFromBody = (body: string): void => {
this.chatModel.sendMessage(body);
};
decryptMessage = async (
messageViewModel: ChatMessageViewModel
): Promise<void> => {
await this.chatModel.decryptMessage(messageViewModel.chatMessage);
messageViewModel.loadData();
};
// restore // restore
restorePageSelection = (): void => { restorePageSelection = (): void => {
const path: string[] = storageKeys.chatLastUsedPage(this.chatModel.id); const path: string[] = storageKeys.chatLastUsedPage(this.chatModel.id);