diff --git a/src/Model/chatModel.ts b/src/Model/chatModel.ts index 2cf82cd7..c11620eb 100644 --- a/src/Model/chatModel.ts +++ b/src/Model/chatModel.ts @@ -3,46 +3,42 @@ import * as React from "bloatless-react"; import { UDN, isConnected } from "./model"; import { decryptString, encryptString } from "../cryptUtility"; +import { Message } from "udn-frontend"; import { senderName } from "./viewModel"; import { storageKeys } from "../utility"; // TYPES // message -export interface Message { +export interface ChatMessage { channel: string; sender: string; body: string; isoDate: string; } -export class Message { - constructor( - public channel: string, - public sender: string, - public body: string, - public isoDate: string - ) {} -} - // chat export class Chat { id: string; - primaryChannel: React.State; + isSubscribed = new React.State(false); + currentChannel = new React.State(""); + + primaryChannelInput: React.State; secondaryChannels: React.ListState; encryptionKey: React.State; - messages: React.ListState; + messages: React.ListState; composingMessage: React.State; - cannotSendMessage: React.State; - newSecondaryChannelName: React.State; + + cannotSendMessage: React.State; cannotAddSecondaryChannel: React.State; + cannotSetChannel: React.State; // init constructor(id: string = React.UUID()) { - this.primaryChannel = React.restoreState( + this.primaryChannelInput = React.restoreState( storageKeys.primaryChannel(id), "" ); @@ -60,16 +56,48 @@ export class Chat { this.newSecondaryChannelName = new React.State(""); this.cannotSendMessage = React.createProxyState( - [this.primaryChannel, this.composingMessage, isConnected], + [ + this.primaryChannelInput, + this.composingMessage, + this.isSubscribed, + isConnected, + ], () => - this.primaryChannel.value == "" || + this.primaryChannelInput.value == "" || this.composingMessage.value == "" || + this.isSubscribed.value == false || isConnected.value == false ); this.cannotAddSecondaryChannel = React.createProxyState( [this.newSecondaryChannelName], () => this.newSecondaryChannelName.value == "" ); + this.cannotSetChannel = React.createProxyState( + [this.primaryChannelInput, this.currentChannel], + () => + this.primaryChannelInput.value == "" || + this.primaryChannelInput.value == this.currentChannel.value + ); + } + + // handlers + onmessage(data: Message): void { + if (data.messageChannel && data.messageChannel != this.currentChannel.value) + return; + + if (data.subscribed != undefined) this.handleSubscription(data.subscribed); + + if (!data.messageBody) return; + const { sender, body, channel, isoDate } = JSON.parse(data.messageBody); + this.handleMessage({ sender, body, channel, isoDate }); + } + + handleSubscription(isSubscribed: boolean): void { + this.isSubscribed.value = isSubscribed; + } + + handleMessage(chatMessage: ChatMessage): void { + this.messages.add(chatMessage); } // messages @@ -81,7 +109,7 @@ export class Chat { ...this.secondaryChannels.value.values(), ].map((channel) => channel); const allChannelNames: string[] = [ - this.primaryChannel.value, + this.primaryChannelInput.value, ...secondaryChannelNames, ]; @@ -95,12 +123,12 @@ export class Chat { // create object const joinedChannelName = allChannelNames.join("/"); - const messageObject = new Message( - joinedChannelName, - senderName.value, - encrypted, - new Date().toISOString() - ); + const messageObject: ChatMessage = { + channel: joinedChannelName, + sender: senderName.value, + body: encrypted, + isoDate: new Date().toISOString(), + }; const messageString = JSON.stringify(messageObject); // send @@ -114,17 +142,21 @@ export class Chat { this.messages.clear(); } - deleteMessage(message: Message): void { + deleteMessage(message: ChatMessage): void { this.messages.remove(message); } - async decryptReceivedMessage(message: Message): Promise { + async decryptReceivedMessage(message: ChatMessage): Promise { message.body = await decryptString(message.body, this.encryptionKey.value); this.messages.callSubscriptions(); } // channel - setChannel(): void {} + setChannel(): void { + if (this.cannotSetChannel.value == true) return; + this.currentChannel.value = this.primaryChannelInput.value; + UDN.subscribe(this.currentChannel.value); + } addSecondaryChannel(): void { if (this.cannotAddSecondaryChannel.value == true) return; @@ -146,7 +178,7 @@ export const chats = new React.ListState(chatArray); // METHODS export function createChatWithName(name: string): void { const newChat = new Chat(); - newChat.primaryChannel.value = name; + newChat.primaryChannelInput.value = name; chatIds.add(newChat.id); } diff --git a/src/Model/model.ts b/src/Model/model.ts index 34525a6f..e9a8a504 100644 --- a/src/Model/model.ts +++ b/src/Model/model.ts @@ -1,17 +1,8 @@ import * as React from "bloatless-react"; -import { - arrayToUint8, - decrypt, - encrypt, - generateIV, - importKey, - uInt8ToArray, -} from "../cryptUtility"; - import UDNFrontend from "udn-frontend"; +import { chats } from "./chatModel"; import { serverAddress } from "./viewModel"; -import { translation } from "../translations"; export const UDN = new UDNFrontend(); @@ -52,7 +43,9 @@ UDN.onconnect = () => { UDN.onmessage = (data) => { - + chats.value.forEach((chat) => { + chat.onmessage(data); + }) }; UDN.ondisconnect = () => { diff --git a/src/Model/viewModel.ts b/src/Model/viewModel.ts index 085771b9..66b5287c 100644 --- a/src/Model/viewModel.ts +++ b/src/Model/viewModel.ts @@ -1,5 +1,6 @@ import * as React from "bloatless-react"; +import { Chat } from "./chatModel"; import { translation } from "../translations"; // connection @@ -16,6 +17,4 @@ export const isEncryptionUnavailable = window.crypto.subtle == undefined; export const senderName = React.restoreState("sender-name", ""); // chat -export const newChatPrimaryChannelName = new React.State(""); -export const newChatSecondaryChannelName = new React.State(""); -export const newChatSecondaryChannelNames = new React.ListState(); \ No newline at end of file +export const selectedChat = new React.State(undefined);