add chat list section
This commit is contained in:
Vendored
+271
-206
@@ -364,6 +364,7 @@
|
|||||||
cannotSetChannel;
|
cannotSetChannel;
|
||||||
// init
|
// init
|
||||||
constructor(id = UUID()) {
|
constructor(id = UUID()) {
|
||||||
|
this.id = id;
|
||||||
this.primaryChannelInput = restoreState(
|
this.primaryChannelInput = restoreState(
|
||||||
storageKeys.primaryChannel(id),
|
storageKeys.primaryChannel(id),
|
||||||
""
|
""
|
||||||
@@ -380,12 +381,12 @@
|
|||||||
this.newSecondaryChannelName = new State("");
|
this.newSecondaryChannelName = new State("");
|
||||||
this.cannotSendMessage = createProxyState(
|
this.cannotSendMessage = createProxyState(
|
||||||
[
|
[
|
||||||
this.primaryChannelInput,
|
this.currentChannel,
|
||||||
this.composingMessage,
|
this.composingMessage,
|
||||||
this.isSubscribed,
|
this.isSubscribed,
|
||||||
isConnected
|
isConnected
|
||||||
],
|
],
|
||||||
() => this.primaryChannelInput.value == "" || this.composingMessage.value == "" || this.isSubscribed.value == false || isConnected.value == false
|
() => this.currentChannel.value == "" || this.composingMessage.value == "" || this.isSubscribed.value == false || isConnected.value == false
|
||||||
);
|
);
|
||||||
this.cannotAddSecondaryChannel = createProxyState(
|
this.cannotAddSecondaryChannel = createProxyState(
|
||||||
[this.newSecondaryChannelName],
|
[this.newSecondaryChannelName],
|
||||||
@@ -418,7 +419,7 @@
|
|||||||
...this.secondaryChannels.value.values()
|
...this.secondaryChannels.value.values()
|
||||||
].map((channel) => channel);
|
].map((channel) => channel);
|
||||||
const allChannelNames = [
|
const allChannelNames = [
|
||||||
this.primaryChannelInput.value,
|
this.currentChannel.value,
|
||||||
...secondaryChannelNames
|
...secondaryChannelNames
|
||||||
];
|
];
|
||||||
const encrypted = await encryptString(
|
const encrypted = await encryptString(
|
||||||
@@ -463,206 +464,20 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
var chatIds = restoreListState("chat-ids");
|
var chatIds = restoreListState("chat-ids");
|
||||||
var chatArray = [...chatIds.value.values()].map((id) => new Chat(id));
|
var chats = new ListState();
|
||||||
var chats = new ListState(chatArray);
|
chatIds.value.forEach((id) => chats.add(new Chat(id)));
|
||||||
|
function createChatWithName(name) {
|
||||||
// node_modules/udn-frontend/index.ts
|
const newChat = new Chat();
|
||||||
var UDNFrontend = class {
|
newChat.currentChannel.value = name;
|
||||||
ws;
|
chatIds.add(newChat.id);
|
||||||
// HANDLERS
|
chats.add(newChat);
|
||||||
connectionHandler = () => {
|
|
||||||
};
|
|
||||||
disconnectionHandler = () => {
|
|
||||||
};
|
|
||||||
messageHandler = (data) => {
|
|
||||||
};
|
|
||||||
mailboxHandler = (mailboxId2) => {
|
|
||||||
};
|
|
||||||
mailboxConnectionHandler = (mailboxId2) => {
|
|
||||||
};
|
|
||||||
mailboxDeleteHandler = (mailboxId2) => {
|
|
||||||
};
|
|
||||||
// INIT
|
|
||||||
set onconnect(handler) {
|
|
||||||
this.connectionHandler = handler;
|
|
||||||
}
|
|
||||||
set ondisconnect(handler) {
|
|
||||||
this.disconnectionHandler = handler;
|
|
||||||
}
|
|
||||||
set onmessage(handler) {
|
|
||||||
this.messageHandler = handler;
|
|
||||||
}
|
|
||||||
set onmailboxcreate(handler) {
|
|
||||||
this.mailboxHandler = handler;
|
|
||||||
}
|
|
||||||
set onmailboxconnect(handler) {
|
|
||||||
this.mailboxConnectionHandler = handler;
|
|
||||||
}
|
|
||||||
set onmailboxdelete(handler) {
|
|
||||||
this.mailboxDeleteHandler = handler;
|
|
||||||
}
|
|
||||||
// UTILITY METHODS
|
|
||||||
send(messageObject) {
|
|
||||||
if (this.ws == void 0) return false;
|
|
||||||
const messageString = JSON.stringify(messageObject);
|
|
||||||
this.ws.send(messageString);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// PUBLIC METHODS
|
|
||||||
// connection
|
|
||||||
connect(address) {
|
|
||||||
try {
|
|
||||||
this.disconnect();
|
|
||||||
this.ws = new WebSocket(address);
|
|
||||||
this.ws.addEventListener("open", this.connectionHandler);
|
|
||||||
this.ws.addEventListener("close", this.disconnectionHandler);
|
|
||||||
this.ws.addEventListener("message", (message) => {
|
|
||||||
const dataString = message.data.toString();
|
|
||||||
const data = JSON.parse(dataString);
|
|
||||||
if (data.assignedMailboxId) {
|
|
||||||
return this.mailboxHandler(data.assignedMailboxId);
|
|
||||||
} else if (data.connectedMailboxId) {
|
|
||||||
return this.mailboxConnectionHandler(data.connectedMailboxId);
|
|
||||||
} else if (data.deletedMailbox) {
|
|
||||||
return this.mailboxDeleteHandler(data.deletedMailbox);
|
|
||||||
} else {
|
|
||||||
this.messageHandler(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
disconnect() {
|
|
||||||
this.ws?.close();
|
|
||||||
}
|
|
||||||
// message
|
|
||||||
sendMessage(channel, body) {
|
|
||||||
const messageObject = {
|
|
||||||
messageChannel: channel,
|
|
||||||
messageBody: body
|
|
||||||
};
|
|
||||||
return this.send(messageObject);
|
|
||||||
}
|
|
||||||
// subscription
|
|
||||||
subscribe(channel) {
|
|
||||||
const messageObject = {
|
|
||||||
subscribeChannel: channel
|
|
||||||
};
|
|
||||||
return this.send(messageObject);
|
|
||||||
}
|
|
||||||
unsubscribe(channel) {
|
|
||||||
const messageObject = {
|
|
||||||
unsubscribeChannel: channel
|
|
||||||
};
|
|
||||||
return this.send(messageObject);
|
|
||||||
}
|
|
||||||
// mailbox
|
|
||||||
requestMailbox() {
|
|
||||||
const messageObject = {
|
|
||||||
requestingMailboxSetup: true
|
|
||||||
};
|
|
||||||
return this.send(messageObject);
|
|
||||||
}
|
|
||||||
connectMailbox(mailboxId2) {
|
|
||||||
const messageObject = {
|
|
||||||
requestedMailbox: mailboxId2
|
|
||||||
};
|
|
||||||
return this.send(messageObject);
|
|
||||||
}
|
|
||||||
deleteMailbox(mailboxId2) {
|
|
||||||
const messageObject = {
|
|
||||||
deletingMailbox: mailboxId2
|
|
||||||
};
|
|
||||||
return this.send(messageObject);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// src/Model/model.ts
|
|
||||||
var UDN = new UDNFrontend();
|
|
||||||
var isConnected = new State(false);
|
|
||||||
var serverAddressInput = restoreState("socket-address", "");
|
|
||||||
var didRequestConnection = restoreState(
|
|
||||||
"did-request-connection",
|
|
||||||
false
|
|
||||||
);
|
|
||||||
var currentAddress = restoreState("current-address", "");
|
|
||||||
var cannotDisonnect = createProxyState(
|
|
||||||
[isConnected],
|
|
||||||
() => isConnected.value == false
|
|
||||||
);
|
|
||||||
var cannotConnect = createProxyState(
|
|
||||||
[serverAddressInput, currentAddress, isConnected],
|
|
||||||
() => serverAddressInput.value == "" || currentAddress.value == serverAddressInput.value && isConnected.value == true
|
|
||||||
);
|
|
||||||
var cannotResetAddress = createProxyState(
|
|
||||||
[serverAddressInput, currentAddress],
|
|
||||||
() => serverAddressInput.value == currentAddress.value
|
|
||||||
);
|
|
||||||
function connect() {
|
|
||||||
if (cannotConnect.value == true) return;
|
|
||||||
currentAddress.value = serverAddressInput.value;
|
|
||||||
isConnected.value = false;
|
|
||||||
didRequestConnection.value = true;
|
|
||||||
UDN.connect(serverAddressInput.value);
|
|
||||||
}
|
}
|
||||||
function disconnect() {
|
function removeChat(chat) {
|
||||||
didRequestConnection.value = false;
|
Object.values(storageKeys).forEach((cb) => {
|
||||||
if (cannotDisonnect.value == true) return;
|
localStorage.removeItem(cb(chat.id));
|
||||||
UDN.disconnect();
|
|
||||||
}
|
|
||||||
function resetAddressInput() {
|
|
||||||
serverAddressInput.value = currentAddress.value;
|
|
||||||
}
|
|
||||||
UDN.onconnect = () => {
|
|
||||||
isConnected.value = true;
|
|
||||||
};
|
|
||||||
UDN.onmessage = (data) => {
|
|
||||||
chats.value.forEach((chat) => {
|
|
||||||
chat.onmessage(data);
|
|
||||||
});
|
});
|
||||||
};
|
chats.remove(chat);
|
||||||
UDN.ondisconnect = () => {
|
chatIds.remove(chat.id);
|
||||||
isConnected.value = false;
|
|
||||||
};
|
|
||||||
var mailboxId = restoreState("mailbox-id", "");
|
|
||||||
var isMailboxActive = new State(false);
|
|
||||||
var cannotDeleteMailbox = createProxyState(
|
|
||||||
[mailboxId, isMailboxActive],
|
|
||||||
() => mailboxId.value == "" || isMailboxActive.value == false
|
|
||||||
);
|
|
||||||
var cannotRequestMailbox = createProxyState(
|
|
||||||
[isConnected, isMailboxActive],
|
|
||||||
() => isConnected.value == false || isMailboxActive.value == true
|
|
||||||
);
|
|
||||||
function requestMailbox() {
|
|
||||||
if (cannotRequestMailbox.value == true) return;
|
|
||||||
UDN.requestMailbox();
|
|
||||||
}
|
|
||||||
function deleteMailbox() {
|
|
||||||
if (cannotDeleteMailbox.value == true) return;
|
|
||||||
UDN.deleteMailbox(mailboxId.value);
|
|
||||||
}
|
|
||||||
UDN.onmailboxcreate = (id) => {
|
|
||||||
mailboxId.value = id;
|
|
||||||
UDN.connectMailbox(id);
|
|
||||||
};
|
|
||||||
UDN.onmailboxconnect = () => {
|
|
||||||
isMailboxActive.value = true;
|
|
||||||
};
|
|
||||||
UDN.onmailboxdelete = () => {
|
|
||||||
isMailboxActive.value = false;
|
|
||||||
mailboxId.value = "";
|
|
||||||
};
|
|
||||||
var isEncryptionUnavailable = window.crypto.subtle == void 0;
|
|
||||||
var senderName = restoreState("sender-name", "");
|
|
||||||
var selectedChat = new State(void 0);
|
|
||||||
function closeChat() {
|
|
||||||
selectedChat.value = void 0;
|
|
||||||
document.getElementById("settings-tab")?.scrollIntoView();
|
|
||||||
}
|
|
||||||
if (serverAddressInput.value != "" && didRequestConnection.value == true) {
|
|
||||||
connect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/translations.ts
|
// src/translations.ts
|
||||||
@@ -673,13 +488,17 @@
|
|||||||
// overview
|
// overview
|
||||||
overview: "Overview",
|
overview: "Overview",
|
||||||
connection: "Connection",
|
connection: "Connection",
|
||||||
communication: "Communication",
|
chats: "Chats",
|
||||||
encryption: "Encryption",
|
|
||||||
serverAddress: "Server Address",
|
serverAddress: "Server Address",
|
||||||
serverAddressPlaceholder: "wss://192.168.0.69:3000",
|
serverAddressPlaceholder: "wss://192.168.0.69:3000",
|
||||||
connectToServer: "Connect",
|
connectToServer: "Connect",
|
||||||
disconnect: "Disonnect",
|
disconnect: "Disonnect",
|
||||||
resetAddress: "Reset address",
|
resetAddress: "Reset address",
|
||||||
|
newChatPrimaryChannel: "Primary channel",
|
||||||
|
newChatNamePlaceholder: "my-channel",
|
||||||
|
addChat: "Add",
|
||||||
|
removeChat: "Remove chat",
|
||||||
|
// messages
|
||||||
noChatSelected: "No chat selected",
|
noChatSelected: "No chat selected",
|
||||||
primaryChannel: "Primary channel",
|
primaryChannel: "Primary channel",
|
||||||
leaveChannel: "Leave",
|
leaveChannel: "Leave",
|
||||||
@@ -857,7 +676,7 @@
|
|||||||
function clearMessageHistory() {
|
function clearMessageHistory() {
|
||||||
chat.clearMessages();
|
chat.clearMessages();
|
||||||
}
|
}
|
||||||
return /* @__PURE__ */ createElement("article", { id: "message-tab" }, /* @__PURE__ */ createElement("header", { class: "padding-0" }, /* @__PURE__ */ createElement("span", { class: "flex-row align-center" }, /* @__PURE__ */ createElement("button", { "aria-label": translation.back, "on:click": closeChat }, /* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_back")), /* @__PURE__ */ createElement("span", { "subscribe:innerText": chat.currentChannel })), /* @__PURE__ */ createElement("span", null, /* @__PURE__ */ createElement(
|
return /* @__PURE__ */ createElement("article", { id: "message-tab" }, /* @__PURE__ */ createElement("header", { class: "padding-0" }, /* @__PURE__ */ createElement("span", { class: "flex-row align-center" }, /* @__PURE__ */ createElement("button", { "aria-label": translation.back, "on:click": closeChatView }, /* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_back")), /* @__PURE__ */ createElement("span", { "subscribe:innerText": chat.currentChannel })), /* @__PURE__ */ createElement("span", null, /* @__PURE__ */ createElement(
|
||||||
"button",
|
"button",
|
||||||
{
|
{
|
||||||
"aria-label": translation.clearHistory,
|
"aria-label": translation.clearHistory,
|
||||||
@@ -869,9 +688,44 @@
|
|||||||
return /* @__PURE__ */ createElement("div", { "children:set": messageTabContent });
|
return /* @__PURE__ */ createElement("div", { "children:set": messageTabContent });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// src/Views/chatListSection.tsx
|
||||||
|
var chatConverter = (chat) => {
|
||||||
|
function remove() {
|
||||||
|
removeChat(chat);
|
||||||
|
}
|
||||||
|
return /* @__PURE__ */ createElement("div", { class: "tile padding-0" }, /* @__PURE__ */ createElement("div", { class: "flex-row width-100 justify-apart align-center" }, /* @__PURE__ */ createElement("span", { class: "padding-h ellipsis", "subscribe:innerText": chat.currentChannel }), /* @__PURE__ */ createElement(
|
||||||
|
"button",
|
||||||
|
{
|
||||||
|
class: "danger",
|
||||||
|
"aria-label": translation.removeChat,
|
||||||
|
"on:click": remove
|
||||||
|
},
|
||||||
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "delete")
|
||||||
|
)));
|
||||||
|
};
|
||||||
|
function ChatListSection() {
|
||||||
|
return /* @__PURE__ */ createElement("div", { class: "flex-column" }, /* @__PURE__ */ createElement("h2", null, translation.chats), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "forum"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.newChatPrimaryChannel), /* @__PURE__ */ createElement(
|
||||||
|
"input",
|
||||||
|
{
|
||||||
|
"bind:value": newChatName,
|
||||||
|
placeholder: translation.newChatNamePlaceholder,
|
||||||
|
"on:enter": createChat
|
||||||
|
}
|
||||||
|
))), /* @__PURE__ */ createElement("div", { class: "flex-row justify-end" }, /* @__PURE__ */ createElement(
|
||||||
|
"button",
|
||||||
|
{
|
||||||
|
class: "primary width-50",
|
||||||
|
"toggle:disabled": cannotCreateChat,
|
||||||
|
"on:click": createChat
|
||||||
|
},
|
||||||
|
translation.addChat,
|
||||||
|
/* @__PURE__ */ createElement("span", { class: "icon" }, "add")
|
||||||
|
)), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "flex-column gap", "children:append": [chats, chatConverter] }));
|
||||||
|
}
|
||||||
|
|
||||||
// src/Views/connectionSection.tsx
|
// src/Views/connectionSection.tsx
|
||||||
function ConnectionSection() {
|
function ConnectionSection() {
|
||||||
return /* @__PURE__ */ createElement("div", { class: "flex-column" }, /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "cell_tower"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.serverAddress), /* @__PURE__ */ createElement(
|
return /* @__PURE__ */ createElement("div", { class: "flex-column" }, /* @__PURE__ */ createElement("h2", null, translation.connection), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "cell_tower"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.serverAddress), /* @__PURE__ */ createElement(
|
||||||
"input",
|
"input",
|
||||||
{
|
{
|
||||||
"bind:value": serverAddressInput,
|
"bind:value": serverAddressInput,
|
||||||
@@ -927,10 +781,221 @@
|
|||||||
|
|
||||||
// src/Tabs/settingsTab.tsx
|
// src/Tabs/settingsTab.tsx
|
||||||
function SettingsTab() {
|
function SettingsTab() {
|
||||||
return /* @__PURE__ */ createElement("article", { id: "settings-tab", "toggle:connected": isConnected }, /* @__PURE__ */ createElement("header", null, translation.overview), /* @__PURE__ */ createElement("div", null, ConnectionSection()));
|
return /* @__PURE__ */ createElement("article", { id: "settings-tab", "toggle:connected": isConnected }, /* @__PURE__ */ createElement("header", null, translation.overview), /* @__PURE__ */ createElement("div", { class: "flex-column large-gap" }, ConnectionSection(), ChatListSection()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// node_modules/udn-frontend/index.ts
|
||||||
|
var UDNFrontend = class {
|
||||||
|
ws;
|
||||||
|
// HANDLERS
|
||||||
|
connectionHandler = () => {
|
||||||
|
};
|
||||||
|
disconnectionHandler = () => {
|
||||||
|
};
|
||||||
|
messageHandler = (data) => {
|
||||||
|
};
|
||||||
|
mailboxHandler = (mailboxId2) => {
|
||||||
|
};
|
||||||
|
mailboxConnectionHandler = (mailboxId2) => {
|
||||||
|
};
|
||||||
|
mailboxDeleteHandler = (mailboxId2) => {
|
||||||
|
};
|
||||||
|
// INIT
|
||||||
|
set onconnect(handler) {
|
||||||
|
this.connectionHandler = handler;
|
||||||
|
}
|
||||||
|
set ondisconnect(handler) {
|
||||||
|
this.disconnectionHandler = handler;
|
||||||
|
}
|
||||||
|
set onmessage(handler) {
|
||||||
|
this.messageHandler = handler;
|
||||||
|
}
|
||||||
|
set onmailboxcreate(handler) {
|
||||||
|
this.mailboxHandler = handler;
|
||||||
|
}
|
||||||
|
set onmailboxconnect(handler) {
|
||||||
|
this.mailboxConnectionHandler = handler;
|
||||||
|
}
|
||||||
|
set onmailboxdelete(handler) {
|
||||||
|
this.mailboxDeleteHandler = handler;
|
||||||
|
}
|
||||||
|
// UTILITY METHODS
|
||||||
|
send(messageObject) {
|
||||||
|
if (this.ws == void 0) return false;
|
||||||
|
const messageString = JSON.stringify(messageObject);
|
||||||
|
this.ws.send(messageString);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// PUBLIC METHODS
|
||||||
|
// connection
|
||||||
|
connect(address) {
|
||||||
|
try {
|
||||||
|
this.disconnect();
|
||||||
|
this.ws = new WebSocket(address);
|
||||||
|
this.ws.addEventListener("open", this.connectionHandler);
|
||||||
|
this.ws.addEventListener("close", this.disconnectionHandler);
|
||||||
|
this.ws.addEventListener("message", (message) => {
|
||||||
|
const dataString = message.data.toString();
|
||||||
|
const data = JSON.parse(dataString);
|
||||||
|
if (data.assignedMailboxId) {
|
||||||
|
return this.mailboxHandler(data.assignedMailboxId);
|
||||||
|
} else if (data.connectedMailboxId) {
|
||||||
|
return this.mailboxConnectionHandler(data.connectedMailboxId);
|
||||||
|
} else if (data.deletedMailbox) {
|
||||||
|
return this.mailboxDeleteHandler(data.deletedMailbox);
|
||||||
|
} else {
|
||||||
|
this.messageHandler(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disconnect() {
|
||||||
|
this.ws?.close();
|
||||||
|
}
|
||||||
|
// message
|
||||||
|
sendMessage(channel, body) {
|
||||||
|
const messageObject = {
|
||||||
|
messageChannel: channel,
|
||||||
|
messageBody: body
|
||||||
|
};
|
||||||
|
return this.send(messageObject);
|
||||||
|
}
|
||||||
|
// subscription
|
||||||
|
subscribe(channel) {
|
||||||
|
const messageObject = {
|
||||||
|
subscribeChannel: channel
|
||||||
|
};
|
||||||
|
return this.send(messageObject);
|
||||||
|
}
|
||||||
|
unsubscribe(channel) {
|
||||||
|
const messageObject = {
|
||||||
|
unsubscribeChannel: channel
|
||||||
|
};
|
||||||
|
return this.send(messageObject);
|
||||||
|
}
|
||||||
|
// mailbox
|
||||||
|
requestMailbox() {
|
||||||
|
const messageObject = {
|
||||||
|
requestingMailboxSetup: true
|
||||||
|
};
|
||||||
|
return this.send(messageObject);
|
||||||
|
}
|
||||||
|
connectMailbox(mailboxId2) {
|
||||||
|
const messageObject = {
|
||||||
|
requestedMailbox: mailboxId2
|
||||||
|
};
|
||||||
|
return this.send(messageObject);
|
||||||
|
}
|
||||||
|
deleteMailbox(mailboxId2) {
|
||||||
|
const messageObject = {
|
||||||
|
deletingMailbox: mailboxId2
|
||||||
|
};
|
||||||
|
return this.send(messageObject);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// src/index.tsx
|
// src/index.tsx
|
||||||
|
var UDN = new UDNFrontend();
|
||||||
|
var isConnected = new State(false);
|
||||||
|
var serverAddressInput = restoreState("socket-address", "");
|
||||||
|
var didRequestConnection = restoreState(
|
||||||
|
"did-request-connection",
|
||||||
|
false
|
||||||
|
);
|
||||||
|
var currentAddress = restoreState("current-address", "");
|
||||||
|
var cannotDisonnect = createProxyState(
|
||||||
|
[isConnected],
|
||||||
|
() => isConnected.value == false
|
||||||
|
);
|
||||||
|
var cannotConnect = createProxyState(
|
||||||
|
[serverAddressInput, currentAddress, isConnected],
|
||||||
|
() => serverAddressInput.value == "" || currentAddress.value == serverAddressInput.value && isConnected.value == true
|
||||||
|
);
|
||||||
|
var cannotResetAddress = createProxyState(
|
||||||
|
[serverAddressInput, currentAddress],
|
||||||
|
() => serverAddressInput.value == currentAddress.value
|
||||||
|
);
|
||||||
|
function connect() {
|
||||||
|
if (cannotConnect.value == true) return;
|
||||||
|
currentAddress.value = serverAddressInput.value;
|
||||||
|
isConnected.value = false;
|
||||||
|
didRequestConnection.value = true;
|
||||||
|
UDN.connect(serverAddressInput.value);
|
||||||
|
}
|
||||||
|
function disconnect() {
|
||||||
|
didRequestConnection.value = false;
|
||||||
|
if (cannotDisonnect.value == true) return;
|
||||||
|
UDN.disconnect();
|
||||||
|
}
|
||||||
|
function resetAddressInput() {
|
||||||
|
serverAddressInput.value = currentAddress.value;
|
||||||
|
}
|
||||||
|
UDN.onconnect = () => {
|
||||||
|
isConnected.value = true;
|
||||||
|
};
|
||||||
|
UDN.onmessage = (data) => {
|
||||||
|
chats.value.forEach((chat) => {
|
||||||
|
chat.onmessage(data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
UDN.ondisconnect = () => {
|
||||||
|
isConnected.value = false;
|
||||||
|
};
|
||||||
|
var mailboxId = restoreState("mailbox-id", "");
|
||||||
|
var isMailboxActive = new State(false);
|
||||||
|
var cannotDeleteMailbox = createProxyState(
|
||||||
|
[mailboxId, isMailboxActive],
|
||||||
|
() => mailboxId.value == "" || isMailboxActive.value == false
|
||||||
|
);
|
||||||
|
var cannotRequestMailbox = createProxyState(
|
||||||
|
[isConnected, isMailboxActive],
|
||||||
|
() => isConnected.value == false || isMailboxActive.value == true
|
||||||
|
);
|
||||||
|
function requestMailbox() {
|
||||||
|
if (cannotRequestMailbox.value == true) return;
|
||||||
|
UDN.requestMailbox();
|
||||||
|
}
|
||||||
|
function deleteMailbox() {
|
||||||
|
if (cannotDeleteMailbox.value == true) return;
|
||||||
|
UDN.deleteMailbox(mailboxId.value);
|
||||||
|
}
|
||||||
|
function updateMailbox() {
|
||||||
|
deleteMailbox();
|
||||||
|
updateMailbox();
|
||||||
|
}
|
||||||
|
UDN.onmailboxcreate = (id) => {
|
||||||
|
mailboxId.value = id;
|
||||||
|
UDN.connectMailbox(id);
|
||||||
|
};
|
||||||
|
UDN.onmailboxconnect = () => {
|
||||||
|
isMailboxActive.value = true;
|
||||||
|
};
|
||||||
|
UDN.onmailboxdelete = () => {
|
||||||
|
isMailboxActive.value = false;
|
||||||
|
mailboxId.value = "";
|
||||||
|
};
|
||||||
|
var isEncryptionUnavailable = window.crypto.subtle == void 0;
|
||||||
|
var senderName = restoreState("sender-name", "");
|
||||||
|
var selectedChat = new State(void 0);
|
||||||
|
var newChatName = new State("");
|
||||||
|
var cannotCreateChat = createProxyState(
|
||||||
|
[newChatName],
|
||||||
|
() => newChatName.value == ""
|
||||||
|
);
|
||||||
|
function createChat() {
|
||||||
|
if (cannotCreateChat.value == true) return;
|
||||||
|
createChatWithName(newChatName.value);
|
||||||
|
newChatName.value = "";
|
||||||
|
}
|
||||||
|
function closeChatView() {
|
||||||
|
selectedChat.value = void 0;
|
||||||
|
document.getElementById("settings-tab")?.scrollIntoView();
|
||||||
|
}
|
||||||
|
if (serverAddressInput.value != "" && didRequestConnection.value == true) {
|
||||||
|
connect();
|
||||||
|
}
|
||||||
document.querySelector("main").append(SettingsTab(), MessageTab());
|
document.querySelector("main").append(SettingsTab(), MessageTab());
|
||||||
document.querySelector("main").classList.add("split");
|
document.querySelector("main").classList.add("split");
|
||||||
})();
|
})();
|
||||||
|
|||||||
Vendored
+5
@@ -214,6 +214,7 @@ SIZES
|
|||||||
--gap-between-tiles: 4px;
|
--gap-between-tiles: 4px;
|
||||||
--gap-in-tab-links: 1rem;
|
--gap-in-tab-links: 1rem;
|
||||||
--gap-in-controls: 1.2rem;
|
--gap-in-controls: 1.2rem;
|
||||||
|
--large-gap: 2rem;
|
||||||
|
|
||||||
/* margin */
|
/* margin */
|
||||||
--label-top-padding: 0.25rem;
|
--label-top-padding: 0.25rem;
|
||||||
@@ -448,6 +449,10 @@ label.inline,
|
|||||||
gap: var(--gap-between-tiles) !important;
|
gap: var(--gap-between-tiles) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.large-gap {
|
||||||
|
gap: var(--large-gap) !important;
|
||||||
|
}
|
||||||
|
|
||||||
header,
|
header,
|
||||||
button {
|
button {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
+14
-7
@@ -1,6 +1,6 @@
|
|||||||
import * as React from "bloatless-react";
|
import * as React from "bloatless-react";
|
||||||
|
|
||||||
import { UDN, isConnected, senderName } from "./model";
|
import { UDN, isConnected, senderName } from "../Model/model";
|
||||||
import { decryptString, encryptString } from "../cryptUtility";
|
import { decryptString, encryptString } from "../cryptUtility";
|
||||||
|
|
||||||
import { Message } from "udn-frontend";
|
import { Message } from "udn-frontend";
|
||||||
@@ -37,6 +37,9 @@ export class Chat {
|
|||||||
|
|
||||||
// init
|
// init
|
||||||
constructor(id: string = React.UUID()) {
|
constructor(id: string = React.UUID()) {
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
|
// channels
|
||||||
this.primaryChannelInput = React.restoreState(
|
this.primaryChannelInput = React.restoreState(
|
||||||
storageKeys.primaryChannel(id),
|
storageKeys.primaryChannel(id),
|
||||||
""
|
""
|
||||||
@@ -45,6 +48,7 @@ export class Chat {
|
|||||||
storageKeys.secondaryChannels(id)
|
storageKeys.secondaryChannels(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// messaging
|
||||||
this.encryptionKey = React.restoreState(storageKeys.encyptionKey(id), "");
|
this.encryptionKey = React.restoreState(storageKeys.encyptionKey(id), "");
|
||||||
this.messages = React.restoreListState(storageKeys.messages(id));
|
this.messages = React.restoreListState(storageKeys.messages(id));
|
||||||
|
|
||||||
@@ -54,15 +58,16 @@ export class Chat {
|
|||||||
);
|
);
|
||||||
this.newSecondaryChannelName = new React.State("");
|
this.newSecondaryChannelName = new React.State("");
|
||||||
|
|
||||||
|
// guards
|
||||||
this.cannotSendMessage = React.createProxyState(
|
this.cannotSendMessage = React.createProxyState(
|
||||||
[
|
[
|
||||||
this.primaryChannelInput,
|
this.currentChannel,
|
||||||
this.composingMessage,
|
this.composingMessage,
|
||||||
this.isSubscribed,
|
this.isSubscribed,
|
||||||
isConnected,
|
isConnected,
|
||||||
],
|
],
|
||||||
() =>
|
() =>
|
||||||
this.primaryChannelInput.value == "" ||
|
this.currentChannel.value == "" ||
|
||||||
this.composingMessage.value == "" ||
|
this.composingMessage.value == "" ||
|
||||||
this.isSubscribed.value == false ||
|
this.isSubscribed.value == false ||
|
||||||
isConnected.value == false
|
isConnected.value == false
|
||||||
@@ -108,7 +113,7 @@ export class Chat {
|
|||||||
...this.secondaryChannels.value.values(),
|
...this.secondaryChannels.value.values(),
|
||||||
].map((channel) => channel);
|
].map((channel) => channel);
|
||||||
const allChannelNames: string[] = [
|
const allChannelNames: string[] = [
|
||||||
this.primaryChannelInput.value,
|
this.currentChannel.value,
|
||||||
...secondaryChannelNames,
|
...secondaryChannelNames,
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -171,14 +176,16 @@ export class Chat {
|
|||||||
|
|
||||||
// INIT
|
// INIT
|
||||||
const chatIds = React.restoreListState<string>("chat-ids");
|
const chatIds = React.restoreListState<string>("chat-ids");
|
||||||
const chatArray = [...chatIds.value.values()].map((id) => new Chat(id));
|
export const chats = new React.ListState<Chat>();
|
||||||
export const chats = new React.ListState<Chat>(chatArray);
|
|
||||||
|
chatIds.value.forEach((id) => chats.add(new Chat(id)));
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
export function createChatWithName(name: string): void {
|
export function createChatWithName(name: string): void {
|
||||||
const newChat = new Chat();
|
const newChat = new Chat();
|
||||||
newChat.primaryChannelInput.value = name;
|
newChat.currentChannel.value = name;
|
||||||
chatIds.add(newChat.id);
|
chatIds.add(newChat.id);
|
||||||
|
chats.add(newChat);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeChat(chat: Chat): void {
|
export function removeChat(chat: Chat): void {
|
||||||
|
|||||||
+20
-3
@@ -1,13 +1,12 @@
|
|||||||
import * as React from "bloatless-react";
|
import * as React from "bloatless-react";
|
||||||
|
|
||||||
import { Chat, chats } from "./chatModel";
|
import { Chat, chats, createChatWithName } from "./chatModel";
|
||||||
|
|
||||||
import UDNFrontend from "udn-frontend";
|
import UDNFrontend from "udn-frontend";
|
||||||
|
|
||||||
export const UDN = new UDNFrontend();
|
export const UDN = new UDNFrontend();
|
||||||
|
|
||||||
// CONNECTION
|
// CONNECTION
|
||||||
// state
|
|
||||||
export const isConnected = new React.State(false);
|
export const isConnected = new React.State(false);
|
||||||
|
|
||||||
export const serverAddressInput = React.restoreState("socket-address", "");
|
export const serverAddressInput = React.restoreState("socket-address", "");
|
||||||
@@ -95,6 +94,11 @@ export function deleteMailbox(): void {
|
|||||||
UDN.deleteMailbox(mailboxId.value);
|
UDN.deleteMailbox(mailboxId.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function updateMailbox(): void {
|
||||||
|
deleteMailbox();
|
||||||
|
updateMailbox();
|
||||||
|
}
|
||||||
|
|
||||||
UDN.onmailboxcreate = (id) => {
|
UDN.onmailboxcreate = (id) => {
|
||||||
mailboxId.value = id;
|
mailboxId.value = id;
|
||||||
UDN.connectMailbox(id);
|
UDN.connectMailbox(id);
|
||||||
@@ -114,8 +118,21 @@ export const isEncryptionUnavailable = window.crypto.subtle == undefined;
|
|||||||
export const senderName = React.restoreState("sender-name", "");
|
export const senderName = React.restoreState("sender-name", "");
|
||||||
|
|
||||||
export const selectedChat = new React.State<Chat | undefined>(undefined);
|
export const selectedChat = new React.State<Chat | undefined>(undefined);
|
||||||
|
export const newChatName = new React.State("");
|
||||||
|
|
||||||
export function closeChat() {
|
export const cannotCreateChat = React.createProxyState(
|
||||||
|
[newChatName],
|
||||||
|
() => newChatName.value == ""
|
||||||
|
);
|
||||||
|
|
||||||
|
export function createChat() {
|
||||||
|
if (cannotCreateChat.value == true) return;
|
||||||
|
|
||||||
|
createChatWithName(newChatName.value);
|
||||||
|
newChatName.value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeChatView() {
|
||||||
selectedChat.value = undefined;
|
selectedChat.value = undefined;
|
||||||
document.getElementById("settings-tab")?.scrollIntoView();
|
document.getElementById("settings-tab")?.scrollIntoView();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as React from "bloatless-react";
|
import * as React from "bloatless-react";
|
||||||
|
|
||||||
import { closeChat, selectedChat } from "../Model/model";
|
import { closeChatView, selectedChat } from "../Model/model";
|
||||||
|
|
||||||
import { MessageComposer } from "../Views/messageComposer";
|
import { MessageComposer } from "../Views/messageComposer";
|
||||||
import { ThreadView } from "../Views/threadView";
|
import { ThreadView } from "../Views/threadView";
|
||||||
@@ -25,7 +25,7 @@ export function MessageTab() {
|
|||||||
<article id="message-tab">
|
<article id="message-tab">
|
||||||
<header class="padding-0">
|
<header class="padding-0">
|
||||||
<span class="flex-row align-center">
|
<span class="flex-row align-center">
|
||||||
<button aria-label={translation.back} on:click={closeChat}>
|
<button aria-label={translation.back} on:click={closeChatView}>
|
||||||
<span class="icon">arrow_back</span>
|
<span class="icon">arrow_back</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import * as React from "bloatless-react";
|
import * as React from "bloatless-react";
|
||||||
|
|
||||||
|
import { ChatListSection } from "../Views/chatListSection";
|
||||||
import { ConnectionSection } from "../Views/connectionSection";
|
import { ConnectionSection } from "../Views/connectionSection";
|
||||||
import { isConnected } from "../Model/model";
|
import { isConnected } from "../Model/model";
|
||||||
import { translation } from "../translations";
|
import { translation } from "../translations";
|
||||||
@@ -8,7 +9,10 @@ export function SettingsTab() {
|
|||||||
return (
|
return (
|
||||||
<article id="settings-tab" toggle:connected={isConnected}>
|
<article id="settings-tab" toggle:connected={isConnected}>
|
||||||
<header>{translation.overview}</header>
|
<header>{translation.overview}</header>
|
||||||
<div>{ConnectionSection()}</div>
|
<div class="flex-column large-gap">
|
||||||
|
{ConnectionSection()}
|
||||||
|
{ChatListSection()}
|
||||||
|
</div>
|
||||||
</article>
|
</article>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import * as React from "bloatless-react";
|
||||||
|
|
||||||
|
import { Chat, chats, removeChat } from "../Model/chatModel";
|
||||||
|
import { cannotCreateChat, createChat, newChatName } from "../Model/model";
|
||||||
|
|
||||||
|
import { translation } from "../translations";
|
||||||
|
|
||||||
|
const chatConverter: React.ListItemConverter<Chat> = (chat) => {
|
||||||
|
function remove() {
|
||||||
|
removeChat(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="tile padding-0">
|
||||||
|
<div class="flex-row width-100 justify-apart align-center">
|
||||||
|
<span class="padding-h ellipsis" subscribe:innerText={chat.currentChannel}></span>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="danger"
|
||||||
|
aria-label={translation.removeChat}
|
||||||
|
on:click={remove}
|
||||||
|
>
|
||||||
|
<span class="icon">delete</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export function ChatListSection() {
|
||||||
|
return (
|
||||||
|
<div class="flex-column">
|
||||||
|
<h2>{translation.chats}</h2>
|
||||||
|
|
||||||
|
<label class="tile">
|
||||||
|
<span class="icon">forum</span>
|
||||||
|
<div>
|
||||||
|
<span>{translation.newChatPrimaryChannel}</span>
|
||||||
|
<input
|
||||||
|
bind:value={newChatName}
|
||||||
|
placeholder={translation.newChatNamePlaceholder}
|
||||||
|
on:enter={createChat}
|
||||||
|
></input>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<div class="flex-row justify-end">
|
||||||
|
<button
|
||||||
|
class="primary width-50"
|
||||||
|
toggle:disabled={cannotCreateChat}
|
||||||
|
on:click={createChat}
|
||||||
|
>
|
||||||
|
{translation.addChat}
|
||||||
|
<span class="icon">add</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr></hr>
|
||||||
|
|
||||||
|
<div class="flex-column gap" children:append={[chats, chatConverter]}></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -19,6 +19,8 @@ import { translation } from "../translations";
|
|||||||
export function ConnectionSection() {
|
export function ConnectionSection() {
|
||||||
return (
|
return (
|
||||||
<div class="flex-column">
|
<div class="flex-column">
|
||||||
|
<h2>{translation.connection}</h2>
|
||||||
|
|
||||||
<label class="tile">
|
<label class="tile">
|
||||||
<span class="icon">cell_tower</span>
|
<span class="icon">cell_tower</span>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
+7
-2
@@ -7,8 +7,7 @@ const englishTranslations = {
|
|||||||
overview: "Overview",
|
overview: "Overview",
|
||||||
|
|
||||||
connection: "Connection",
|
connection: "Connection",
|
||||||
communication: "Communication",
|
chats: "Chats",
|
||||||
encryption: "Encryption",
|
|
||||||
|
|
||||||
serverAddress: "Server Address",
|
serverAddress: "Server Address",
|
||||||
serverAddressPlaceholder: "wss://192.168.0.69:3000",
|
serverAddressPlaceholder: "wss://192.168.0.69:3000",
|
||||||
@@ -17,6 +16,12 @@ const englishTranslations = {
|
|||||||
disconnect: "Disonnect",
|
disconnect: "Disonnect",
|
||||||
resetAddress: "Reset address",
|
resetAddress: "Reset address",
|
||||||
|
|
||||||
|
newChatPrimaryChannel: "Primary channel",
|
||||||
|
newChatNamePlaceholder: "my-channel",
|
||||||
|
addChat: "Add",
|
||||||
|
removeChat: "Remove chat",
|
||||||
|
|
||||||
|
// messages
|
||||||
noChatSelected: "No chat selected",
|
noChatSelected: "No chat selected",
|
||||||
|
|
||||||
primaryChannel: "Primary channel",
|
primaryChannel: "Primary channel",
|
||||||
|
|||||||
Reference in New Issue
Block a user