Files
CT/src/ViewModel/chatViewModel.ts
T

236 lines
6.9 KiB
TypeScript
Raw Normal View History

2024-07-20 04:17:10 +02:00
import * as React from "bloatless-react";
2024-07-21 21:41:19 +02:00
import ChatModel, { ChatMessage } from "../Model/chatModel";
2024-07-20 16:34:16 +02:00
import StorageModel, { storageKeys } from "../Model/storageModel";
2024-07-20 14:16:26 +02:00
import ChatListViewModel from "./chatListViewModel";
2024-07-21 01:12:35 +02:00
import ChatMessageViewModel from "../Model/chatMessageViewModel";
2024-07-20 18:10:42 +02:00
import { Color } from "./colors";
2024-07-20 21:04:41 +02:00
import SettingsViewModel from "./settingsViewModel";
2024-07-20 18:58:25 +02:00
import { localeCompare } from "../Model/Utility/utility";
2024-07-20 04:17:10 +02:00
export default class ChatViewModel {
2024-07-20 14:16:26 +02:00
chatModel: ChatModel;
2024-07-20 16:34:16 +02:00
storageModel: StorageModel;
2024-07-20 21:04:41 +02:00
settingsViewModel: SettingsViewModel;
2024-07-20 20:42:43 +02:00
chatListViewModel: ChatListViewModel;
2024-07-20 04:17:10 +02:00
2024-07-20 14:16:26 +02:00
// state
2024-07-20 16:49:01 +02:00
index: React.State<number> = new React.State(0);
2024-07-20 14:16:26 +02:00
primaryChannel: React.State<string> = new React.State("");
primaryChannelInput: React.State<string> = new React.State("");
2024-07-20 18:49:05 +02:00
secondaryChannels: React.ListState<string> = new React.ListState();
newSecondaryChannelInput: React.State<string> = new React.State("");
2024-07-20 19:18:19 +02:00
encryptionKeyInput: React.State<string> = new React.State("");
shouldShowEncryptionKey: React.State<boolean> = new React.State(false);
encryptionKeyInputType: React.State<"text" | "password"> =
React.createProxyState([this.shouldShowEncryptionKey], () =>
this.shouldShowEncryptionKey.value == true ? "text" : "password"
);
2024-07-20 18:10:42 +02:00
color: React.State<Color> = new React.State<Color>(Color.Standard);
2024-07-20 16:28:00 +02:00
selectedPage: React.State<ChatPageType> = new React.State<ChatPageType>(
ChatPageType.Messages
);
2024-07-21 13:13:41 +02:00
chatMessageViewModels: React.MapState<ChatMessageViewModel> =
new React.MapState();
2024-07-20 20:42:43 +02:00
composingMessage: React.State<string> = new React.State("");
2024-07-20 14:16:26 +02:00
// guards
cannotSetPrimaryChannel: React.State<boolean> = React.createProxyState(
[this.primaryChannel, this.primaryChannelInput],
() =>
this.primaryChannelInput.value == "" ||
this.primaryChannelInput.value == this.primaryChannel.value
);
2024-07-20 23:22:08 +02:00
cannotAddSecondaryChannel: React.State<boolean> = React.createProxyState(
[this.newSecondaryChannelInput],
2024-07-21 01:12:35 +02:00
() => this.newSecondaryChannelInput.value == ""
2024-07-20 23:22:08 +02:00
);
2024-07-20 19:18:19 +02:00
cannotSetEncryptionKey: React.State<boolean>;
2024-07-20 21:04:41 +02:00
cannotSendMessage: React.State<boolean>;
2024-07-20 14:16:26 +02:00
2024-07-20 16:49:01 +02:00
// sorting
updateIndex = (): void => {
2024-07-20 20:42:43 +02:00
this.index.value = this.chatModel.index;
2024-07-20 16:49:01 +02:00
};
2024-07-20 20:42:43 +02:00
// view
2024-07-20 16:34:16 +02:00
open = (): void => {
2024-07-20 14:16:26 +02:00
this.chatListViewModel.openChat(this);
2024-07-21 21:41:19 +02:00
this.loadMessages();
2024-07-20 16:28:00 +02:00
};
2024-07-20 14:16:26 +02:00
2024-07-20 16:34:16 +02:00
close = (): void => {
this.chatListViewModel.closeChat();
2024-07-20 16:28:00 +02:00
};
2024-07-21 01:12:35 +02:00
// add
addChatMessage = (chatMessage: ChatMessage): void => {
2024-07-21 01:53:25 +02:00
const chatMessageModel = new ChatMessageViewModel(
2024-07-21 13:13:41 +02:00
this,
2024-07-21 01:53:25 +02:00
chatMessage,
chatMessage.sender == this.settingsViewModel.username.value
);
2024-07-21 13:13:41 +02:00
const existingChatMessageViewModel: ChatMessageViewModel | undefined =
this.chatMessageViewModels.value.get(chatMessage.id);
if (existingChatMessageViewModel != undefined) {
existingChatMessageViewModel.body.value = chatMessage.body;
existingChatMessageViewModel.status.value = chatMessage.status;
2024-07-21 13:13:41 +02:00
} else {
this.chatMessageViewModels.set(chatMessage.id, chatMessageModel);
}
2024-07-21 01:12:35 +02:00
};
2024-07-20 20:42:43 +02:00
// settings
2024-07-20 17:30:36 +02:00
setPrimaryChannel = (): void => {
this.chatModel.setPrimaryChannel(this.primaryChannelInput.value);
this.primaryChannel.value = this.chatModel.info.primaryChannel;
this.chatListViewModel.updateIndices();
2024-07-20 18:49:05 +02:00
};
addSecondaryChannel = (): void => {
this.secondaryChannels.add(this.newSecondaryChannelInput.value);
this.newSecondaryChannelInput.value = "";
this.storeSecondaryChannels();
2024-07-21 21:41:19 +02:00
this.loadSecondaryChannels();
2024-07-20 18:49:05 +02:00
};
removeSecondaryChannel = (secondaryChannel: string): void => {
this.secondaryChannels.remove(secondaryChannel);
this.storeSecondaryChannels();
};
storeSecondaryChannels = (): void => {
this.chatModel.setSecondaryChannels([
...this.secondaryChannels.value.values(),
]);
2024-07-20 18:58:25 +02:00
};
2024-07-20 17:30:36 +02:00
2024-07-20 19:18:19 +02:00
setEncryptionKey = (): void => {
this.chatModel.setEncryptionKey(this.encryptionKeyInput.value);
// disable button
this.encryptionKeyInput.callSubscriptions();
};
2024-07-20 18:10:42 +02:00
setColor = (newColor: Color): void => {
this.color.value = newColor;
this.chatModel.setColor(newColor);
2024-07-20 18:49:05 +02:00
};
2024-07-20 18:10:42 +02:00
2024-07-20 20:48:13 +02:00
remove = (): void => {
this.close();
this.chatModel.delete();
2024-07-21 21:41:19 +02:00
this.chatListViewModel.loadChats();
2024-07-20 21:04:41 +02:00
};
2024-07-20 20:48:13 +02:00
2024-07-20 20:53:48 +02:00
// messaging
sendMessage = (): void => {
if (this.cannotSendMessage.value == true) return;
2024-07-21 13:13:41 +02:00
this.sendMessageFromBody(this.composingMessage.value);
2024-07-20 20:53:48 +02:00
this.composingMessage.value = "";
2024-07-20 21:04:41 +02:00
};
2024-07-20 20:53:48 +02:00
2024-07-21 13:13:41 +02:00
sendMessageFromBody = (body: string): void => {
this.chatModel.sendMessage(body);
};
decryptMessage = async (
messageViewModel: ChatMessageViewModel
): Promise<void> => {
const chatMessage: ChatMessage = messageViewModel.chatMessage;
await this.chatModel.decryptMessage(chatMessage);
this.chatModel.addMessage(chatMessage);
2024-07-21 13:13:41 +02:00
messageViewModel.loadData();
};
2024-07-21 21:41:19 +02:00
// load
loadPageSelection = (): void => {
2024-07-20 16:34:16 +02:00
const path: string[] = storageKeys.chatLastUsedPage(this.chatModel.id);
2024-07-21 21:41:19 +02:00
const lastUsedPage: string | null = this.storageModel.read(path);
2024-07-20 16:34:16 +02:00
if (lastUsedPage != null) {
this.selectedPage.value = lastUsedPage as any;
}
this.selectedPage.subscribeSilent((newPage) => {
2024-07-21 21:41:19 +02:00
this.storageModel.write(path, newPage);
2024-07-20 16:34:16 +02:00
});
};
2024-07-21 21:41:19 +02:00
loadSecondaryChannels = (): void => {
2024-07-20 18:58:25 +02:00
this.secondaryChannels.clear();
2024-07-20 19:18:19 +02:00
for (const secondaryChannel of this.chatModel.info.secondaryChannels.sort(
localeCompare
)) {
2024-07-20 18:58:25 +02:00
this.secondaryChannels.add(secondaryChannel);
}
};
2024-07-21 21:41:19 +02:00
loadMessages = (): void => {
for (const chatMessage of this.chatModel.messages) {
this.addChatMessage(chatMessage);
}
}
2024-07-20 14:16:26 +02:00
// init
2024-07-20 20:42:43 +02:00
constructor(
chatModel: ChatModel,
storageModel: StorageModel,
2024-07-20 21:04:41 +02:00
settingsViewModel: SettingsViewModel,
2024-07-20 20:42:43 +02:00
chatListViewModel: ChatListViewModel
) {
2024-07-21 01:12:35 +02:00
// models
2024-07-20 14:16:26 +02:00
this.chatModel = chatModel;
2024-07-20 20:42:43 +02:00
this.storageModel = storageModel;
2024-07-20 21:04:41 +02:00
this.settingsViewModel = settingsViewModel;
2024-07-20 14:16:26 +02:00
this.chatListViewModel = chatListViewModel;
2024-07-21 01:12:35 +02:00
// handlers
chatModel.setMessageHandler((chatMessage) => {
this.addChatMessage(chatMessage);
});
2024-07-21 21:41:19 +02:00
// load
2024-07-20 14:16:26 +02:00
this.primaryChannel.value = chatModel.info.primaryChannel;
this.primaryChannelInput.value = chatModel.info.primaryChannel;
2024-07-20 18:49:05 +02:00
2024-07-20 19:18:19 +02:00
this.encryptionKeyInput.value = chatModel.info.encryptionKey;
this.cannotSetEncryptionKey = React.createProxyState(
[this.encryptionKeyInput],
() => this.encryptionKeyInput.value == this.chatModel.info.encryptionKey
);
2024-07-21 01:12:35 +02:00
this.color.value = chatModel.color;
2024-07-21 21:41:19 +02:00
this.loadSecondaryChannels();
this.loadPageSelection();
2024-07-21 01:12:35 +02:00
this.updateIndex();
// guards
2024-07-20 21:04:41 +02:00
this.cannotSendMessage = React.createProxyState(
[this.settingsViewModel.username, this.composingMessage],
() =>
this.settingsViewModel.username.value == "" ||
this.composingMessage.value == ""
2024-07-20 21:04:41 +02:00
);
2024-07-20 14:16:26 +02:00
}
}
2024-07-20 16:28:00 +02:00
// types
export enum ChatPageType {
2024-07-20 16:34:16 +02:00
Settings = "settings",
Messages = "messages",
AllObjects = "all",
Kanban = "kanban",
Calendar = "calendar",
Progress = "progress",
2024-07-20 16:28:00 +02:00
}