add progress bar to data transfer
This commit is contained in:
Vendored
+67
-57
@@ -436,9 +436,8 @@
|
||||
sendButton: "Send",
|
||||
sendAgainButton: "Send again",
|
||||
///
|
||||
filesSentCount: (count) => `Files sent: ${count}.`,
|
||||
allFilesSent: "Done.",
|
||||
filesReceivedCount: (count) => `Files processed: ${count}.`,
|
||||
filesSentProgress: (progress, total) => `Sent ${progress} of ${total} files`,
|
||||
filesReceivedProgress: (progress, total) => `Received ${progress} of ${total} files`,
|
||||
//
|
||||
exportKey: "Encryption key",
|
||||
exportKeyConfirmation: "Confirm",
|
||||
@@ -702,9 +701,8 @@
|
||||
transferKeyHeadline: "Schl\xFCssel",
|
||||
sendButton: "Senden",
|
||||
sendAgainButton: "Erneut senden",
|
||||
filesSentCount: (count) => `Dateien gesendet: ${count}.`,
|
||||
allFilesSent: "Fertig.",
|
||||
filesReceivedCount: (count) => `Dateien empfangen: ${count}.`,
|
||||
filesSentProgress: (progress, total) => `${progress} von ${total} Dateien gesendet`,
|
||||
filesReceivedProgress: (progress, total) => `${progress} von ${total} Dateien empfangen`,
|
||||
exportKey: "Schl\xFCssel",
|
||||
exportKeyConfirmation: "Schl\xFCssel best\xE4tigen",
|
||||
downloadFileButton: "Herunterladen",
|
||||
@@ -954,9 +952,8 @@
|
||||
transferKeyHeadline: "Clave de encriptaci\xF3n de transferencia",
|
||||
sendButton: "Enviar",
|
||||
sendAgainButton: "Enviar otra vez",
|
||||
filesSentCount: (count) => `Archivos enviados: ${count}.`,
|
||||
allFilesSent: "Hecho.",
|
||||
filesReceivedCount: (count) => `Archivos recibidos: ${count}.`,
|
||||
filesSentProgress: (progress, total) => `${progress} de ${total} enviados`,
|
||||
filesReceivedProgress: (progress, total) => `${progress} de ${total} recibidos`,
|
||||
exportKey: "Clave de encriptaci\xF3n",
|
||||
exportKeyConfirmation: "Confirmar clave",
|
||||
downloadFileButton: "Descargar",
|
||||
@@ -2290,27 +2287,13 @@
|
||||
this.receivingTransferChannel = new State("");
|
||||
this.receivingTransferKey = new State("");
|
||||
this.filePathsSent = new ListState();
|
||||
this.filesSentCount = createProxyState(
|
||||
[this.filePathsSent],
|
||||
() => this.filePathsSent.value.size
|
||||
);
|
||||
this.filesSentText = createProxyState(
|
||||
[this.filesSentCount],
|
||||
() => this.coreViewModel.translations.dataTransferModal.filesSentCount(
|
||||
this.filesSentCount.value
|
||||
)
|
||||
);
|
||||
this.fileTransferTotal = new State(0);
|
||||
this.fileTransferProgress = new State(0);
|
||||
this.filePathsReceived = new ListState();
|
||||
this.filesReceivedCount = createProxyState(
|
||||
[this.filePathsReceived],
|
||||
() => this.filePathsReceived.value.size
|
||||
);
|
||||
this.filesReceivedText = createProxyState(
|
||||
[this.filesReceivedCount],
|
||||
() => this.coreViewModel.translations.dataTransferModal.filesReceivedCount(
|
||||
this.filesReceivedCount.value
|
||||
)
|
||||
);
|
||||
this.exportKey = new State("");
|
||||
this.exportKeyConfirmation = new State("");
|
||||
this.importedFile = new State(void 0);
|
||||
@@ -2322,7 +2305,6 @@
|
||||
[this.selectedPaths],
|
||||
() => this.selectedPaths.value.size == 0
|
||||
);
|
||||
this.didNotFinishSending = new State(true);
|
||||
this.cannotPrepareToReceive = createProxyState(
|
||||
[this.receivingTransferChannel, this.receivingTransferKey],
|
||||
() => this.receivingTransferChannel.value == "" || this.receivingTransferKey.value == ""
|
||||
@@ -2346,6 +2328,7 @@
|
||||
// handlers
|
||||
this.handleReceivedFile = (path) => {
|
||||
this.filePathsReceived.add(path);
|
||||
this.fileTransferProgress.value = this.filePathsReceived.value.size;
|
||||
};
|
||||
// methods
|
||||
this.getOptions = () => {
|
||||
@@ -2454,7 +2437,6 @@
|
||||
};
|
||||
this.initiateTransfer = () => {
|
||||
this.presentedModal.value = 3 /* TransferDisplay */;
|
||||
this.didNotFinishSending.value = true;
|
||||
this.filePathsSent.clear();
|
||||
this.coreViewModel.fileTransferModel.sendFiles(
|
||||
this.selectedPaths.value.values(),
|
||||
@@ -2462,7 +2444,6 @@
|
||||
this.filePathsSent.add(path);
|
||||
}
|
||||
);
|
||||
this.didNotFinishSending.value = false;
|
||||
};
|
||||
this.showTransferDataInputModal = () => {
|
||||
this.presentedModal.value = 4 /* TransferDataInput */;
|
||||
@@ -2496,6 +2477,10 @@
|
||||
this.handleContextClose = () => {
|
||||
this.presentedModal.value = void 0;
|
||||
};
|
||||
this.coreViewModel.fileTransferModel.transferSizeHandlerManager.setHandler(
|
||||
"file-transfer-view-model",
|
||||
(count) => this.fileTransferTotal.value = count
|
||||
);
|
||||
this.coreViewModel.fileTransferModel.fileHandlerManager.setHandler(
|
||||
"file-transfer-view-model",
|
||||
this.handleReceivedFile
|
||||
@@ -4742,7 +4727,6 @@
|
||||
};
|
||||
this.randomizeKey = () => {
|
||||
this.encryptionKeyInput.value = random(24);
|
||||
this.setEncryptionKey();
|
||||
};
|
||||
this.applyColor = () => {
|
||||
this.chatViewModel.setColor(this.color.value);
|
||||
@@ -8165,6 +8149,21 @@
|
||||
return /* @__PURE__ */ createElement("span", { class: "ellipsis" }, string);
|
||||
};
|
||||
|
||||
// src/View/Components/progressBar.tsx
|
||||
function ProgressBar(valueLabel, value, maximum) {
|
||||
const style = createProxyState(
|
||||
[value, maximum],
|
||||
() => `width: ${100 * (value.value / maximum.value)}%`
|
||||
);
|
||||
return /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("div", { class: "width-100 surface-alt", style: "height: 18px" }, /* @__PURE__ */ createElement(
|
||||
"div",
|
||||
{
|
||||
class: "height-100 background-primary",
|
||||
"set:style": style
|
||||
}
|
||||
)), /* @__PURE__ */ createElement("span", { class: "secondary", "subscribe:innerText": valueLabel }));
|
||||
}
|
||||
|
||||
// src/View/Modals/dataTransferModal.tsx
|
||||
function DataTransferModalWrapper(coreViewModel2, connectionViewModel2, fileTransferViewModel2) {
|
||||
return /* @__PURE__ */ createElement("div", null, DirectionSelectionModal(
|
||||
@@ -8320,20 +8319,8 @@
|
||||
[fileTransferViewModel2.presentedModal],
|
||||
() => fileTransferViewModel2.presentedModal.value == 3 /* TransferDisplay */
|
||||
);
|
||||
return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isPresented }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.dataTransferModal.transferDataHeadline), /* @__PURE__ */ createElement(
|
||||
"p",
|
||||
{
|
||||
class: "secondary",
|
||||
"subscribe:innerText": fileTransferViewModel2.filesSentText
|
||||
}
|
||||
), /* @__PURE__ */ createElement(
|
||||
"p",
|
||||
{
|
||||
class: "secondary",
|
||||
"toggle:hidden": fileTransferViewModel2.didNotFinishSending
|
||||
},
|
||||
coreViewModel2.translations.dataTransferModal.allFilesSent
|
||||
), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "flex-column gap content-margin-bottom" }, /* @__PURE__ */ createElement("div", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "forum"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.dataTransferModal.transferChannelHeadline), /* @__PURE__ */ createElement(
|
||||
const progressLabel = createProxyState([fileTransferViewModel2.fileTransferProgress, fileTransferViewModel2.fileTransferTotal], () => coreViewModel2.translations.dataTransferModal.filesSentProgress(fileTransferViewModel2.fileTransferProgress.value, fileTransferViewModel2.fileTransferTotal.value));
|
||||
return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isPresented }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.dataTransferModal.transferDataHeadline), ProgressBar(progressLabel, fileTransferViewModel2.fileTransferProgress, fileTransferViewModel2.fileTransferTotal), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "flex-column gap content-margin-bottom" }, /* @__PURE__ */ createElement("div", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "forum"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.dataTransferModal.transferChannelHeadline), /* @__PURE__ */ createElement(
|
||||
"b",
|
||||
{
|
||||
"subscribe:innerText": fileTransferViewModel2.transferChannel
|
||||
@@ -8364,8 +8351,7 @@
|
||||
"button",
|
||||
{
|
||||
class: "flex",
|
||||
"on:click": fileTransferViewModel2.close,
|
||||
"toggle:disabled": fileTransferViewModel2.didNotFinishSending
|
||||
"on:click": fileTransferViewModel2.close
|
||||
},
|
||||
coreViewModel2.translations.general.closeButton,
|
||||
/* @__PURE__ */ createElement("span", { class: "icon" }, "close")
|
||||
@@ -8413,13 +8399,8 @@
|
||||
[fileTransferViewModel2.presentedModal],
|
||||
() => fileTransferViewModel2.presentedModal.value == 5 /* ReceptionDisplay */
|
||||
);
|
||||
return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isPresented }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.dataTransferModal.receiveHeadline), /* @__PURE__ */ createElement(
|
||||
"p",
|
||||
{
|
||||
class: "secondary",
|
||||
"subscribe:innerText": fileTransferViewModel2.filesReceivedText
|
||||
}
|
||||
), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement(
|
||||
const progressLabel = createProxyState([fileTransferViewModel2.fileTransferProgress, fileTransferViewModel2.fileTransferTotal], () => coreViewModel2.translations.dataTransferModal.filesReceivedProgress(fileTransferViewModel2.fileTransferProgress.value, fileTransferViewModel2.fileTransferTotal.value));
|
||||
return /* @__PURE__ */ createElement("div", { class: "modal", "toggle:open": isPresented }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("main", null, /* @__PURE__ */ createElement("h2", null, coreViewModel2.translations.dataTransferModal.receiveHeadline), ProgressBar(progressLabel, fileTransferViewModel2.fileTransferProgress, fileTransferViewModel2.fileTransferTotal), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement(
|
||||
"div",
|
||||
{
|
||||
class: "tile flex-column align-start",
|
||||
@@ -8641,6 +8622,7 @@
|
||||
this.direction = 0 /* Send */;
|
||||
// handler managers
|
||||
this.fileHandlerManager = new HandlerManager();
|
||||
this.transferSizeHandlerManager = new HandlerManager();
|
||||
this.readyToSendHandlerManager = new HandlerManager();
|
||||
// general
|
||||
this.generateTransferData = () => {
|
||||
@@ -8700,6 +8682,11 @@
|
||||
};
|
||||
this.handleDecryptedFile = (data) => {
|
||||
const parsed = parse(data);
|
||||
if (!parsed.type) return;
|
||||
if (parsed.type == "transfer-size" && typeof parsed.count == "number") {
|
||||
this.transferSizeHandlerManager.trigger(parsed.count);
|
||||
return;
|
||||
}
|
||||
const isFileData = checkMatchesObjectStructure(
|
||||
parsed,
|
||||
FileDataReference
|
||||
@@ -8714,16 +8701,22 @@
|
||||
};
|
||||
// sending
|
||||
this.sendFiles = (directoryPaths, fileCallback) => {
|
||||
const filesToSend = /* @__PURE__ */ new Set();
|
||||
for (const directoryPath of directoryPaths) {
|
||||
this.storageModel.recurse(directoryPath, (filePath) => {
|
||||
const stringifiedFileData = this.prepareFileForSending(filePath);
|
||||
this.sendFile(stringifiedFileData);
|
||||
const pathString = StorageModel.pathComponentsToString(
|
||||
...filePath
|
||||
);
|
||||
fileCallback(pathString);
|
||||
filesToSend.add([stringifiedFileData, filePath]);
|
||||
});
|
||||
}
|
||||
this.sendTransferSize(filesToSend.size);
|
||||
for (const file of filesToSend) {
|
||||
const [stringifiedFileData, filePath] = file;
|
||||
this.sendFile(stringifiedFileData);
|
||||
const pathString = StorageModel.pathComponentsToString(
|
||||
...filePath
|
||||
);
|
||||
fileCallback(pathString);
|
||||
}
|
||||
};
|
||||
this.generateBackup = async (directoryPaths, passphrase) => {
|
||||
const files = [];
|
||||
@@ -8739,10 +8732,26 @@
|
||||
const blob = new Blob([encrypted], { type: "text/plain" });
|
||||
return blob;
|
||||
};
|
||||
this.sendTransferSize = async (count) => {
|
||||
if (!this.transferData) return;
|
||||
const data = {
|
||||
type: "transfer-size",
|
||||
count
|
||||
};
|
||||
const encryptedData = await encryptString(
|
||||
stringify(data),
|
||||
this.transferData.key
|
||||
);
|
||||
this.connectionModel.sendPlainMessage(
|
||||
this.transferData.channel,
|
||||
encryptedData
|
||||
);
|
||||
};
|
||||
this.prepareFileForSending = (filePath) => {
|
||||
const fileContent = this.storageModel.read(filePath);
|
||||
if (fileContent == null) return "";
|
||||
const fileData = {
|
||||
type: "file-data",
|
||||
path: filePath,
|
||||
body: fileContent
|
||||
};
|
||||
@@ -8771,6 +8780,7 @@
|
||||
}
|
||||
};
|
||||
var FileDataReference = {
|
||||
type: "file-data",
|
||||
path: [""],
|
||||
body: ""
|
||||
};
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
const VERSION = "2610 Beta 21.12"
|
||||
const VERSION = "2610 Beta 21.13"
|
||||
|
||||
function processUrl(event) {
|
||||
const url = event.request.url;
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
2610 Beta 21.12
|
||||
2610 Beta 21.13
|
||||
|
||||
@@ -24,6 +24,7 @@ export default class FileTransferModel {
|
||||
|
||||
// handler managers
|
||||
readonly fileHandlerManager = new HandlerManager<string>();
|
||||
readonly transferSizeHandlerManager = new HandlerManager<number>();
|
||||
readonly readyToSendHandlerManager = new HandlerManager<boolean>();
|
||||
|
||||
// general
|
||||
@@ -105,6 +106,12 @@ export default class FileTransferModel {
|
||||
readonly handleDecryptedFile = (data: string): void => {
|
||||
const parsed: any = parse(data);
|
||||
|
||||
if (!parsed.type) return;
|
||||
if (parsed.type == "transfer-size" && typeof parsed.count == "number") {
|
||||
this.transferSizeHandlerManager.trigger(parsed.count);
|
||||
return;
|
||||
}
|
||||
|
||||
const isFileData: boolean = checkMatchesObjectStructure(
|
||||
parsed,
|
||||
FileDataReference,
|
||||
@@ -126,17 +133,23 @@ export default class FileTransferModel {
|
||||
directoryPaths: IteratorObject<string[]>,
|
||||
fileCallback: (path: string) => void,
|
||||
): void => {
|
||||
const filesToSend = new Set<[string, string[]]>();
|
||||
for (const directoryPath of directoryPaths) {
|
||||
this.storageModel.recurse(directoryPath, (filePath: string[]) => {
|
||||
const stringifiedFileData =
|
||||
this.prepareFileForSending(filePath);
|
||||
this.sendFile(stringifiedFileData);
|
||||
const pathString: string = StorageModel.pathComponentsToString(
|
||||
...filePath,
|
||||
);
|
||||
fileCallback(pathString);
|
||||
filesToSend.add([stringifiedFileData, filePath]);
|
||||
});
|
||||
}
|
||||
this.sendTransferSize(filesToSend.size);
|
||||
for (const file of filesToSend) {
|
||||
const [stringifiedFileData, filePath] = file;
|
||||
this.sendFile(stringifiedFileData);
|
||||
const pathString: string = StorageModel.pathComponentsToString(
|
||||
...filePath,
|
||||
);
|
||||
fileCallback(pathString);
|
||||
}
|
||||
};
|
||||
|
||||
readonly generateBackup = async (
|
||||
@@ -158,11 +171,30 @@ export default class FileTransferModel {
|
||||
return blob;
|
||||
};
|
||||
|
||||
readonly sendTransferSize = async (count: number): Promise<void> => {
|
||||
if (!this.transferData) return;
|
||||
|
||||
const data: TransferSize = {
|
||||
type: "transfer-size",
|
||||
count,
|
||||
};
|
||||
|
||||
const encryptedData: string = await encryptString(
|
||||
stringify(data),
|
||||
this.transferData.key,
|
||||
);
|
||||
this.connectionModel.sendPlainMessage(
|
||||
this.transferData.channel,
|
||||
encryptedData,
|
||||
);
|
||||
};
|
||||
|
||||
readonly prepareFileForSending = (filePath: string[]): string => {
|
||||
const fileContent: string | null = this.storageModel.read(filePath);
|
||||
if (fileContent == null) return "";
|
||||
|
||||
const fileData: FileData = {
|
||||
type: "file-data",
|
||||
path: filePath,
|
||||
body: fileContent,
|
||||
};
|
||||
@@ -200,11 +232,18 @@ export interface TransferData {
|
||||
}
|
||||
|
||||
export interface FileData {
|
||||
type: "file-data";
|
||||
path: string[];
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface TransferSize {
|
||||
type: "transfer-size";
|
||||
count: number;
|
||||
}
|
||||
|
||||
export const FileDataReference: FileData = {
|
||||
type: "file-data",
|
||||
path: [""],
|
||||
body: "",
|
||||
};
|
||||
|
||||
@@ -5,10 +5,10 @@ const ENCRYPTION_ALG = "AES-GCM";
|
||||
|
||||
// random
|
||||
export function random(length: number): string {
|
||||
return cryptoRandomString({length})
|
||||
return cryptoRandomString({ length });
|
||||
}
|
||||
|
||||
// encrypt
|
||||
// encrypt
|
||||
export async function encryptString(
|
||||
plaintext: string,
|
||||
passphrase: string,
|
||||
|
||||
@@ -140,11 +140,12 @@ export function SettingsPage(
|
||||
<div class="flex-row width-input">
|
||||
<button
|
||||
class="width-50"
|
||||
on:click={
|
||||
settingsPageViewModel.randomizeKey
|
||||
}
|
||||
on:click={settingsPageViewModel.randomizeKey}
|
||||
>
|
||||
{coreViewModel.translations.chatPage.settings.randomizeKey}
|
||||
{
|
||||
coreViewModel.translations.chatPage.settings
|
||||
.randomizeKey
|
||||
}
|
||||
<span class="icon">shuffle</span>
|
||||
</button>
|
||||
<button
|
||||
@@ -176,7 +177,7 @@ export function SettingsPage(
|
||||
coreViewModel.translations.chatPage.settings
|
||||
.showEncryptionKey
|
||||
}
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<hr></hr>
|
||||
|
||||
|
||||
@@ -65,10 +65,10 @@ export function TaskPage(
|
||||
class="no-outline"
|
||||
bind:value={taskPageViewModel.boardQuery}
|
||||
on:enter={taskPageViewModel.createBoard}
|
||||
placeholder={
|
||||
coreViewModel.translations.general
|
||||
.filterOrCreateLabel(coreViewModel.translations.chatPage.task.typeBoard)
|
||||
}
|
||||
placeholder={coreViewModel.translations.general.filterOrCreateLabel(
|
||||
coreViewModel.translations.chatPage.task
|
||||
.typeBoard,
|
||||
)}
|
||||
></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,8 +12,8 @@ export function BoardViewToggleButton(
|
||||
key: string,
|
||||
) {
|
||||
function select() {
|
||||
boardViewModel.selectedPage.value = page;
|
||||
boardViewModel.resetPinchZoom();
|
||||
boardViewModel.selectedPage.value = page;
|
||||
boardViewModel.resetPinchZoom();
|
||||
}
|
||||
|
||||
const isSelected = React.createProxyState(
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import * as React from "../../react";
|
||||
|
||||
export function ProgressBar(
|
||||
valueLabel: React.State<string>,
|
||||
value: React.State<number>,
|
||||
maximum: React.State<number>,
|
||||
) {
|
||||
const style = React.createProxyState(
|
||||
[value, maximum],
|
||||
() => `width: ${100 * (value.value / maximum.value)}%`,
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div class="width-100 surface-alt" style="height: 18px">
|
||||
<div
|
||||
class="height-100 background-primary"
|
||||
set:style={style}
|
||||
></div>
|
||||
</div>
|
||||
<span class="secondary" subscribe:innerText={valueLabel}></span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ViewController } from "../viewController";
|
||||
import { CommonKeys, getKeySymbol } from "../keystrokes";
|
||||
import { StringToTextSpan } from "../Components/textSpan";
|
||||
import { ProgressBar } from "../Components/progressBar";
|
||||
import * as React from "../../react";
|
||||
import FileTransferViewModel, {
|
||||
FileTransferModals,
|
||||
@@ -370,6 +371,18 @@ function TransferDisplayModal(
|
||||
FileTransferModals.TransferDisplay,
|
||||
);
|
||||
|
||||
const progressLabel = React.createProxyState(
|
||||
[
|
||||
fileTransferViewModel.fileTransferProgress,
|
||||
fileTransferViewModel.fileTransferTotal,
|
||||
],
|
||||
() =>
|
||||
coreViewModel.translations.dataTransferModal.filesSentProgress(
|
||||
fileTransferViewModel.fileTransferProgress.value,
|
||||
fileTransferViewModel.fileTransferTotal.value,
|
||||
),
|
||||
);
|
||||
|
||||
return (
|
||||
<div class="modal" toggle:open={isPresented}>
|
||||
<div>
|
||||
@@ -381,24 +394,11 @@ function TransferDisplayModal(
|
||||
}
|
||||
</h2>
|
||||
|
||||
<p
|
||||
class="secondary"
|
||||
subscribe:innerText={
|
||||
fileTransferViewModel.filesSentText
|
||||
}
|
||||
></p>
|
||||
|
||||
<p
|
||||
class="secondary"
|
||||
toggle:hidden={
|
||||
fileTransferViewModel.didNotFinishSending
|
||||
}
|
||||
>
|
||||
{
|
||||
coreViewModel.translations.dataTransferModal
|
||||
.allFilesSent
|
||||
}
|
||||
</p>
|
||||
{ProgressBar(
|
||||
progressLabel,
|
||||
fileTransferViewModel.fileTransferProgress,
|
||||
fileTransferViewModel.fileTransferTotal,
|
||||
)}
|
||||
|
||||
<hr></hr>
|
||||
|
||||
@@ -460,13 +460,7 @@ function TransferDisplayModal(
|
||||
}
|
||||
<span class="icon">restart_alt</span>
|
||||
</button>
|
||||
<button
|
||||
class="flex"
|
||||
on:click={fileTransferViewModel.close}
|
||||
toggle:disabled={
|
||||
fileTransferViewModel.didNotFinishSending
|
||||
}
|
||||
>
|
||||
<button class="flex" on:click={fileTransferViewModel.close}>
|
||||
{coreViewModel.translations.general.closeButton}
|
||||
<span class="icon">close</span>
|
||||
</button>
|
||||
@@ -588,6 +582,18 @@ function DataReceptionModal(
|
||||
FileTransferModals.ReceptionDisplay,
|
||||
);
|
||||
|
||||
const progressLabel = React.createProxyState(
|
||||
[
|
||||
fileTransferViewModel.fileTransferProgress,
|
||||
fileTransferViewModel.fileTransferTotal,
|
||||
],
|
||||
() =>
|
||||
coreViewModel.translations.dataTransferModal.filesReceivedProgress(
|
||||
fileTransferViewModel.fileTransferProgress.value,
|
||||
fileTransferViewModel.fileTransferTotal.value,
|
||||
),
|
||||
);
|
||||
|
||||
return (
|
||||
<div class="modal" toggle:open={isPresented}>
|
||||
<div>
|
||||
@@ -599,12 +605,11 @@ function DataReceptionModal(
|
||||
}
|
||||
</h2>
|
||||
|
||||
<p
|
||||
class="secondary"
|
||||
subscribe:innerText={
|
||||
fileTransferViewModel.filesReceivedText
|
||||
}
|
||||
></p>
|
||||
{ProgressBar(
|
||||
progressLabel,
|
||||
fileTransferViewModel.fileTransferProgress,
|
||||
fileTransferViewModel.fileTransferTotal,
|
||||
)}
|
||||
|
||||
<hr></hr>
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
@media (min-width: 640px) {
|
||||
#home-page > div {
|
||||
gap: var(--content-padding);
|
||||
gap: var(--content-padding);
|
||||
}
|
||||
|
||||
#home-page #overview-section {
|
||||
@@ -66,11 +66,11 @@
|
||||
|
||||
@media (min-width: 1000px) {
|
||||
#home-page > div {
|
||||
gap: var(--large-gap);
|
||||
gap: var(--large-gap);
|
||||
}
|
||||
|
||||
#home-page > h1 {
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 1rem;
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
+30
-21
@@ -1,5 +1,6 @@
|
||||
import "./homePage.css";
|
||||
import { StringToOption } from "./Components/option";
|
||||
import { NewItemEntry } from "./Components/newItemEntry";
|
||||
import { HomePageButton } from "./Components/homePageButton";
|
||||
import { ChatViewModelToChatEntry } from "./Components/chatEntry";
|
||||
import * as React from "../react";
|
||||
@@ -9,7 +10,6 @@ import FileTransferViewModel from "../ViewModel/Global/fileTransferViewModel";
|
||||
import CoreViewModel from "../ViewModel/Global/coreViewModel";
|
||||
import ConnectionViewModel from "../ViewModel/Global/connectionViewModel";
|
||||
import ChatListViewModel from "../ViewModel/Chat/chatListViewModel";
|
||||
import {NewItemEntry} from "./Components/newItemEntry";
|
||||
|
||||
export function HomePage(
|
||||
coreViewModel: CoreViewModel,
|
||||
@@ -19,9 +19,18 @@ export function HomePage(
|
||||
fileTransferViewModel: FileTransferViewModel,
|
||||
chatListViewModel: ChatListViewModel,
|
||||
) {
|
||||
const greeting = React.createProxyState([settingsViewModel.username], ()=>coreViewModel.translations.homePage.greeting(settingsViewModel.username.value));
|
||||
const greeting = React.createProxyState([settingsViewModel.username], () =>
|
||||
coreViewModel.translations.homePage.greeting(
|
||||
settingsViewModel.username.value,
|
||||
),
|
||||
);
|
||||
|
||||
const isChatPlaceholderHidden = React.createProxyState([chatListViewModel.chatMatches, chatListViewModel.chatQuery], ()=>chatListViewModel.chatMatches.value.size > 0 || chatListViewModel.chatQuery.value != "");
|
||||
const isChatPlaceholderHidden = React.createProxyState(
|
||||
[chatListViewModel.chatMatches, chatListViewModel.chatQuery],
|
||||
() =>
|
||||
chatListViewModel.chatMatches.value.size > 0 ||
|
||||
chatListViewModel.chatQuery.value != "",
|
||||
);
|
||||
|
||||
// sections
|
||||
const overviewSection = (
|
||||
@@ -119,8 +128,8 @@ export function HomePage(
|
||||
<span subscribe:innerText={coreViewModel.updateText}></span>
|
||||
<span class="icon">update</span>
|
||||
</button>
|
||||
|
||||
<hr class="mobile-only"></hr>
|
||||
|
||||
<hr class="mobile-only"></hr>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -128,25 +137,25 @@ export function HomePage(
|
||||
<div id="chat-section">
|
||||
<div class="flex-row width-input">
|
||||
<input
|
||||
placeholder={
|
||||
coreViewModel.translations.general
|
||||
.filterOrCreateLabel(coreViewModel.translations.homePage.typeChat)
|
||||
}
|
||||
placeholder={coreViewModel.translations.general.filterOrCreateLabel(
|
||||
coreViewModel.translations.homePage.typeChat,
|
||||
)}
|
||||
bind:value={chatListViewModel.chatQuery}
|
||||
on:enter={chatListViewModel.createChat}
|
||||
></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr></hr>
|
||||
<hr></hr>
|
||||
|
||||
{NewItemEntry(coreViewModel, chatListViewModel.chatQuery, chatListViewModel.createChat)}
|
||||
{NewItemEntry(
|
||||
coreViewModel,
|
||||
chatListViewModel.chatQuery,
|
||||
chatListViewModel.createChat,
|
||||
)}
|
||||
|
||||
<span
|
||||
class="secondary"
|
||||
toggle:hidden={isChatPlaceholderHidden}
|
||||
>
|
||||
{coreViewModel.translations.homePage.noChatsPlaceholder}
|
||||
</span>
|
||||
<span class="secondary" toggle:hidden={isChatPlaceholderHidden}>
|
||||
{coreViewModel.translations.homePage.noChatsPlaceholder}
|
||||
</span>
|
||||
|
||||
<div
|
||||
id="chat-grid"
|
||||
@@ -154,14 +163,14 @@ export function HomePage(
|
||||
chatListViewModel.chatMatches,
|
||||
ChatViewModelToChatEntry,
|
||||
]}
|
||||
></div>
|
||||
></div>
|
||||
</div>
|
||||
);
|
||||
|
||||
// final
|
||||
return (
|
||||
<article id="home-page">
|
||||
<h1 subscribe:innerText={greeting}></h1>
|
||||
<article id="home-page">
|
||||
<h1 subscribe:innerText={greeting}></h1>
|
||||
<div>
|
||||
{overviewSection}
|
||||
{chatSection}
|
||||
|
||||
+567
-566
File diff suppressed because it is too large
Load Diff
@@ -35,9 +35,7 @@ export default class ChatListViewModel {
|
||||
// methods
|
||||
createChat = (): void => {
|
||||
const chatModel: ChatModel =
|
||||
this.coreViewModel.chatListModel.createChat(
|
||||
this.chatQuery.value,
|
||||
);
|
||||
this.coreViewModel.chatListModel.createChat(this.chatQuery.value);
|
||||
this.chatQuery.value = "";
|
||||
|
||||
const chatViewModel: ChatViewModel =
|
||||
@@ -108,8 +106,13 @@ export default class ChatListViewModel {
|
||||
);
|
||||
|
||||
this.loadChats();
|
||||
|
||||
implementFilter(this.chatViewModels, this.chatMatches, this.chatQuery, chat => chat.chatModel.info.name)
|
||||
|
||||
implementFilter(
|
||||
this.chatViewModels,
|
||||
this.chatMatches,
|
||||
this.chatQuery,
|
||||
(chat) => chat.chatModel.info.name,
|
||||
);
|
||||
}
|
||||
|
||||
// utility
|
||||
|
||||
@@ -52,22 +52,23 @@ export default class CoreViewModel {
|
||||
)
|
||||
return;
|
||||
|
||||
let exitNext: boolean = false;
|
||||
let exitNext: boolean = false;
|
||||
|
||||
while (this.contexts.length > 0) {
|
||||
const currentContext: Context | undefined = this.context;
|
||||
if (!currentContext) break;
|
||||
const response = currentContext.handleContextClose(fromHistoryEvent);
|
||||
if (response == false) break;
|
||||
const response =
|
||||
currentContext.handleContextClose(fromHistoryEvent);
|
||||
if (response == false) break;
|
||||
this.contextStack.delete(currentContext.contextId);
|
||||
if (response == true) {
|
||||
exitNext = true;
|
||||
continue;
|
||||
} else if (exitNext == true) {
|
||||
break
|
||||
} else if (currentContext.contextId == contextId) {
|
||||
break;
|
||||
}
|
||||
if (response == true) {
|
||||
exitNext = true;
|
||||
continue;
|
||||
} else if (exitNext == true) {
|
||||
break;
|
||||
} else if (currentContext.contextId == contextId) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -206,7 +207,7 @@ export class Context {
|
||||
};
|
||||
|
||||
close = (): void => {};
|
||||
handleContextClose = (fromHistoryEvent: boolean): void|boolean=> {};
|
||||
handleContextClose = (fromHistoryEvent: boolean): void | boolean => {};
|
||||
|
||||
registerKeyStroke = (key: string, fn: () => void): void => {
|
||||
this.keystrokes.set(key, fn);
|
||||
|
||||
@@ -11,7 +11,7 @@ import ChatModel from "../../Model/Chat/chatModel";
|
||||
|
||||
export default class FileTransferViewModel extends Context {
|
||||
// state
|
||||
exitReception: () => void | undefined = undefined;
|
||||
exitReception: (() => void) | undefined = undefined;
|
||||
|
||||
presentedModal: React.State<FileTransferModals | undefined> =
|
||||
new React.State<any>(undefined);
|
||||
@@ -29,30 +29,14 @@ export default class FileTransferViewModel extends Context {
|
||||
receivingTransferKey: React.State<string> = new React.State("");
|
||||
|
||||
filePathsSent: React.ListState<string> = new React.ListState();
|
||||
filesSentCount: React.State<number> = React.createProxyState(
|
||||
[this.filePathsSent],
|
||||
() => this.filePathsSent.value.size,
|
||||
);
|
||||
filesSentText: React.State<string> = React.createProxyState(
|
||||
[this.filesSentCount],
|
||||
() =>
|
||||
this.coreViewModel.translations.dataTransferModal.filesSentCount(
|
||||
this.filesSentCount.value,
|
||||
),
|
||||
);
|
||||
|
||||
fileTransferTotal: React.State<number> = new React.State(0);
|
||||
fileTransferProgress: React.State<number> = new React.State(0);
|
||||
filePathsReceived: React.ListState<string> = new React.ListState();
|
||||
filesReceivedCount: React.State<number> = React.createProxyState(
|
||||
[this.filePathsReceived],
|
||||
() => this.filePathsReceived.value.size,
|
||||
);
|
||||
filesReceivedText: React.State<string> = React.createProxyState(
|
||||
[this.filesReceivedCount],
|
||||
() =>
|
||||
this.coreViewModel.translations.dataTransferModal.filesReceivedCount(
|
||||
this.filesReceivedCount.value,
|
||||
),
|
||||
);
|
||||
|
||||
exportKey: React.State<string> = new React.State("");
|
||||
exportKeyConfirmation: React.State<string> = new React.State("");
|
||||
@@ -69,7 +53,6 @@ export default class FileTransferViewModel extends Context {
|
||||
[this.selectedPaths],
|
||||
() => this.selectedPaths.value.size == 0,
|
||||
);
|
||||
didNotFinishSending: React.State<boolean> = new React.State(true);
|
||||
cannotPrepareToReceive: React.State<boolean> = React.createProxyState(
|
||||
[this.receivingTransferChannel, this.receivingTransferKey],
|
||||
() =>
|
||||
@@ -99,6 +82,7 @@ export default class FileTransferViewModel extends Context {
|
||||
// handlers
|
||||
handleReceivedFile = (path: string): void => {
|
||||
this.filePathsReceived.add(path);
|
||||
this.fileTransferProgress.value = this.filePathsReceived.value.size;
|
||||
};
|
||||
|
||||
// methods
|
||||
@@ -229,7 +213,6 @@ export default class FileTransferViewModel extends Context {
|
||||
|
||||
initiateTransfer = (): void => {
|
||||
this.presentedModal.value = FileTransferModals.TransferDisplay;
|
||||
this.didNotFinishSending.value = true;
|
||||
this.filePathsSent.clear();
|
||||
|
||||
this.coreViewModel.fileTransferModel.sendFiles(
|
||||
@@ -238,8 +221,6 @@ export default class FileTransferViewModel extends Context {
|
||||
this.filePathsSent.add(path);
|
||||
},
|
||||
);
|
||||
|
||||
this.didNotFinishSending.value = false;
|
||||
};
|
||||
|
||||
showTransferDataInputModal = (): void => {
|
||||
@@ -287,6 +268,11 @@ export default class FileTransferViewModel extends Context {
|
||||
constructor(public readonly coreViewModel: CoreViewModel) {
|
||||
super("file-transfer");
|
||||
|
||||
this.coreViewModel.fileTransferModel.transferSizeHandlerManager.setHandler(
|
||||
"file-transfer-view-model",
|
||||
(count) => (this.fileTransferTotal.value = count),
|
||||
);
|
||||
|
||||
this.coreViewModel.fileTransferModel.fileHandlerManager.setHandler(
|
||||
"file-transfer-view-model",
|
||||
this.handleReceivedFile,
|
||||
|
||||
@@ -21,7 +21,7 @@ export default class BoardViewModel extends TaskContainingPageViewModel {
|
||||
index: React.State<number> = new React.State(0);
|
||||
|
||||
selectedPage: React.State<BoardPageTypes> = new React.State<any>(
|
||||
BoardPageTypes.List,
|
||||
BoardPageTypes.List,
|
||||
);
|
||||
|
||||
isSelected: React.State<boolean>;
|
||||
@@ -31,339 +31,339 @@ export default class BoardViewModel extends TaskContainingPageViewModel {
|
||||
searchViewModel: SearchViewModel<TaskViewModel>;
|
||||
searchSuggestions = new React.ListState<string>();
|
||||
filteredTaskViewModels: React.ListState<TaskViewModel> =
|
||||
new React.ListState();
|
||||
new React.ListState();
|
||||
isFilterActive: React.State<boolean>;
|
||||
|
||||
pinchToZoomData: React.State<PinchToZoomData> = new React.State({
|
||||
zoom: 1,
|
||||
x: 0,
|
||||
y: 0,
|
||||
zoom: 1,
|
||||
x: 0,
|
||||
y: 0,
|
||||
});
|
||||
|
||||
// paths
|
||||
getBasePath = (): string[] => {
|
||||
return [
|
||||
...this.taskPageViewModel.getBoardViewPath(this.boardInfo.fileId),
|
||||
];
|
||||
return [
|
||||
...this.taskPageViewModel.getBoardViewPath(this.boardInfo.fileId),
|
||||
];
|
||||
};
|
||||
|
||||
getLastUsedBoardPath = (): string[] => {
|
||||
return [...this.getBasePath(), BoardViewModelSubPaths.LastUsedView];
|
||||
return [...this.getBasePath(), BoardViewModelSubPaths.LastUsedView];
|
||||
};
|
||||
|
||||
getPreviousSearchesPath = (): string[] => {
|
||||
return [...this.getBasePath(), BoardViewModelSubPaths.PreviousSearches];
|
||||
return [...this.getBasePath(), BoardViewModelSubPaths.PreviousSearches];
|
||||
};
|
||||
|
||||
getLastSearchPath = (): string[] => {
|
||||
return [...this.getBasePath(), BoardViewModelSubPaths.LastSearch];
|
||||
return [...this.getBasePath(), BoardViewModelSubPaths.LastSearch];
|
||||
};
|
||||
|
||||
// settings
|
||||
saveSettings = (): void => {
|
||||
const newBoardInfoFileContent: BoardInfoFileContent =
|
||||
BoardsAndTasksModel.createBoardInfoFileContent(
|
||||
this.boardInfo.fileId,
|
||||
this.name.value,
|
||||
this.color.value,
|
||||
);
|
||||
const newBoardInfoFileContent: BoardInfoFileContent =
|
||||
BoardsAndTasksModel.createBoardInfoFileContent(
|
||||
this.boardInfo.fileId,
|
||||
this.name.value,
|
||||
this.color.value,
|
||||
);
|
||||
|
||||
this.taskPageViewModel.updateBoard(newBoardInfoFileContent);
|
||||
this.taskPageViewModel.updateBoard(newBoardInfoFileContent);
|
||||
};
|
||||
|
||||
applyColor = (): void => {
|
||||
this.taskPageViewModel.chatViewModel.setDisplayedColor(
|
||||
this.color.value,
|
||||
);
|
||||
this.taskPageViewModel.chatViewModel.setDisplayedColor(
|
||||
this.color.value,
|
||||
);
|
||||
};
|
||||
|
||||
deleteBoard = (): void => {
|
||||
this.taskPageViewModel.deleteBoard(this.boardInfo);
|
||||
this.chatViewModel.taskBoardSuggestions.remove(this.boardInfo.fileId);
|
||||
this.close();
|
||||
this.taskPageViewModel.deleteBoard(this.boardInfo);
|
||||
this.chatViewModel.taskBoardSuggestions.remove(this.boardInfo.fileId);
|
||||
this.close();
|
||||
};
|
||||
|
||||
// methods
|
||||
createTask = (): void => {
|
||||
this.createTaskFromBoardId(this.boardInfo.fileId);
|
||||
this.createTaskFromBoardId(this.boardInfo.fileId);
|
||||
};
|
||||
|
||||
handleDropWithinBoard = (category?: string, status?: string): void => {
|
||||
const draggedObject: any = this.coreViewModel.draggedObject.value;
|
||||
if (draggedObject instanceof TaskViewModel == false) return;
|
||||
draggedObject.setCategoryAndStatus(category, status);
|
||||
const draggedObject: any = this.coreViewModel.draggedObject.value;
|
||||
if (draggedObject instanceof TaskViewModel == false) return;
|
||||
draggedObject.setCategoryAndStatus(category, status);
|
||||
};
|
||||
|
||||
handleDropBetweenBoards = (): void => {
|
||||
const draggedObject: any = this.coreViewModel.draggedObject.value;
|
||||
if (draggedObject instanceof TaskViewModel == false) return;
|
||||
draggedObject.setBoardId(this.boardInfo.fileId);
|
||||
const draggedObject: any = this.coreViewModel.draggedObject.value;
|
||||
if (draggedObject instanceof TaskViewModel == false) return;
|
||||
draggedObject.setBoardId(this.boardInfo.fileId);
|
||||
};
|
||||
|
||||
// storage
|
||||
storeLastUsedView = (): void => {
|
||||
const path: string[] = this.getLastUsedBoardPath();
|
||||
const lastUsedView: string = this.selectedPage.value;
|
||||
this.coreViewModel.storageModel.write(path, lastUsedView);
|
||||
const path: string[] = this.getLastUsedBoardPath();
|
||||
const lastUsedView: string = this.selectedPage.value;
|
||||
this.coreViewModel.storageModel.write(path, lastUsedView);
|
||||
};
|
||||
|
||||
restoreLastUsedView = (): void => {
|
||||
const path: string[] = this.getLastUsedBoardPath();
|
||||
const lastUsedView: string | null =
|
||||
this.coreViewModel.storageModel.read(path);
|
||||
if (lastUsedView == null) return;
|
||||
const path: string[] = this.getLastUsedBoardPath();
|
||||
const lastUsedView: string | null =
|
||||
this.coreViewModel.storageModel.read(path);
|
||||
if (lastUsedView == null) return;
|
||||
|
||||
this.selectedPage.value = lastUsedView as BoardPageTypes;
|
||||
this.selectedPage.value = lastUsedView as BoardPageTypes;
|
||||
};
|
||||
|
||||
handleNewSearch = (searchTerm: string): void => {
|
||||
const suggestionPath: string[] = [
|
||||
...this.getPreviousSearchesPath(),
|
||||
searchTerm,
|
||||
];
|
||||
this.coreViewModel.storageModel.write(suggestionPath, "");
|
||||
if (!this.searchSuggestions.value.has(searchTerm) && searchTerm != "") {
|
||||
this.searchSuggestions.add(searchTerm);
|
||||
}
|
||||
const suggestionPath: string[] = [
|
||||
...this.getPreviousSearchesPath(),
|
||||
searchTerm,
|
||||
];
|
||||
this.coreViewModel.storageModel.write(suggestionPath, "");
|
||||
if (!this.searchSuggestions.value.has(searchTerm) && searchTerm != "") {
|
||||
this.searchSuggestions.add(searchTerm);
|
||||
}
|
||||
|
||||
const lastSearchPath: string[] = this.getLastSearchPath();
|
||||
this.coreViewModel.storageModel.write(lastSearchPath, searchTerm);
|
||||
const lastSearchPath: string[] = this.getLastSearchPath();
|
||||
this.coreViewModel.storageModel.write(lastSearchPath, searchTerm);
|
||||
};
|
||||
|
||||
handleSearchRemoved = (searchTerm: string): void => {
|
||||
const suggestionPath: string[] = [
|
||||
...this.getPreviousSearchesPath(),
|
||||
searchTerm,
|
||||
];
|
||||
this.coreViewModel.storageModel.remove(suggestionPath);
|
||||
const suggestionPath: string[] = [
|
||||
...this.getPreviousSearchesPath(),
|
||||
searchTerm,
|
||||
];
|
||||
this.coreViewModel.storageModel.remove(suggestionPath);
|
||||
};
|
||||
|
||||
// view
|
||||
showTask = (taskFileContent: TaskFileContent): void => {
|
||||
if (taskFileContent.boardId != this.boardInfo.fileId) {
|
||||
// remove task that was moved to different board
|
||||
this.boardsAndTasksModel.deleteTaskReference(
|
||||
this.boardInfo.fileId,
|
||||
taskFileContent.fileId,
|
||||
);
|
||||
this.removeTaskFromView(taskFileContent);
|
||||
return;
|
||||
}
|
||||
if (taskFileContent.boardId != this.boardInfo.fileId) {
|
||||
// remove task that was moved to different board
|
||||
this.boardsAndTasksModel.deleteTaskReference(
|
||||
this.boardInfo.fileId,
|
||||
taskFileContent.fileId,
|
||||
);
|
||||
this.removeTaskFromView(taskFileContent);
|
||||
return;
|
||||
}
|
||||
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent,
|
||||
);
|
||||
this.taskViewModels.set(taskFileContent.fileId, taskViewModel);
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent,
|
||||
);
|
||||
this.taskViewModels.set(taskFileContent.fileId, taskViewModel);
|
||||
};
|
||||
|
||||
removeTaskFromView = (taskFileContent: TaskFileContent): void => {
|
||||
this.taskViewModels.remove(taskFileContent.fileId);
|
||||
this.updateIndex();
|
||||
this.taskViewModels.remove(taskFileContent.fileId);
|
||||
this.updateIndex();
|
||||
};
|
||||
|
||||
select = (): void => {
|
||||
this.taskPageViewModel.selectBoard(this);
|
||||
this.taskPageViewModel.selectBoard(this);
|
||||
};
|
||||
|
||||
close = (): void => {
|
||||
this.taskPageViewModel.closeBoard();
|
||||
this.taskPageViewModel.storeLastUsedBoard();
|
||||
this.taskViewModels.clear();
|
||||
this.taskPageViewModel.closeBoard();
|
||||
this.taskPageViewModel.storeLastUsedBoard();
|
||||
this.taskViewModels.clear();
|
||||
};
|
||||
|
||||
showSettings = (): void => {
|
||||
this.isPresentingSettingsModal.value = true;
|
||||
this.isPresentingSettingsModal.value = true;
|
||||
};
|
||||
|
||||
hideSettings = (): void => {
|
||||
this.saveSettings();
|
||||
this.isPresentingSettingsModal.value = false;
|
||||
this.saveSettings();
|
||||
this.isPresentingSettingsModal.value = false;
|
||||
};
|
||||
|
||||
showFilterModal = (): void => {
|
||||
this.isPresentingFilterModal.value = true;
|
||||
this.isPresentingFilterModal.value = true;
|
||||
};
|
||||
|
||||
hideFilterModal = (): void => {
|
||||
this.isPresentingFilterModal.value = false;
|
||||
this.isPresentingFilterModal.value = false;
|
||||
};
|
||||
|
||||
resetFilter = (): void => {
|
||||
this.searchViewModel.search("");
|
||||
this.searchViewModel.search("");
|
||||
};
|
||||
|
||||
updateIndex = (): void => {
|
||||
const index: number =
|
||||
this.taskPageViewModel.boardIndexManager.getIndex(this);
|
||||
this.index.value = index;
|
||||
const index: number =
|
||||
this.taskPageViewModel.boardIndexManager.getIndex(this);
|
||||
this.index.value = index;
|
||||
};
|
||||
|
||||
resetPinchZoom = (): void => {
|
||||
this.pinchToZoomData.value = {x: 0, y: 0, zoom: 1};
|
||||
}
|
||||
this.pinchToZoomData.value = { x: 0, y: 0, zoom: 1 };
|
||||
};
|
||||
|
||||
// load
|
||||
preloadData = (): void => {
|
||||
this.name.value = this.boardInfo.name;
|
||||
this.color.value = this.boardInfo.color;
|
||||
this.name.value = this.boardInfo.name;
|
||||
this.color.value = this.boardInfo.color;
|
||||
};
|
||||
|
||||
loadTasks = (): void => {
|
||||
const taskIds: string[] = this.boardsAndTasksModel.listTaskIds(
|
||||
this.boardInfo.fileId,
|
||||
);
|
||||
for (const taskId of taskIds) {
|
||||
if (this.taskViewModels.value.has(taskId)) continue;
|
||||
const taskIds: string[] = this.boardsAndTasksModel.listTaskIds(
|
||||
this.boardInfo.fileId,
|
||||
);
|
||||
for (const taskId of taskIds) {
|
||||
if (this.taskViewModels.value.has(taskId)) continue;
|
||||
|
||||
const taskFileContent: TaskFileContent | null =
|
||||
this.boardsAndTasksModel.getLatestTaskFileContent(taskId);
|
||||
if (taskFileContent == null) continue;
|
||||
const taskFileContent: TaskFileContent | null =
|
||||
this.boardsAndTasksModel.getLatestTaskFileContent(taskId);
|
||||
if (taskFileContent == null) continue;
|
||||
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent,
|
||||
);
|
||||
this.taskViewModels.set(taskFileContent.fileId, taskViewModel);
|
||||
}
|
||||
const taskViewModel: TaskViewModel = new TaskViewModel(
|
||||
this.coreViewModel,
|
||||
this.chatViewModel,
|
||||
this.boardsAndTasksModel,
|
||||
this,
|
||||
taskFileContent,
|
||||
);
|
||||
this.taskViewModels.set(taskFileContent.fileId, taskViewModel);
|
||||
}
|
||||
|
||||
this.updateTaskIndices();
|
||||
this.updateTaskIndices();
|
||||
};
|
||||
|
||||
loadSearchSuggestions = (): void => {
|
||||
const dirPath: string[] = this.getPreviousSearchesPath();
|
||||
const searches: string[] =
|
||||
this.coreViewModel.storageModel.list(dirPath);
|
||||
this.searchSuggestions.add(...searches.filter((x) => x != ""));
|
||||
const dirPath: string[] = this.getPreviousSearchesPath();
|
||||
const searches: string[] =
|
||||
this.coreViewModel.storageModel.list(dirPath);
|
||||
this.searchSuggestions.add(...searches.filter((x) => x != ""));
|
||||
};
|
||||
|
||||
restoreSearch = (): void => {
|
||||
const lastSearchPath: string[] = this.getLastSearchPath();
|
||||
const lastSearch: string | null =
|
||||
this.coreViewModel.storageModel.read(lastSearchPath);
|
||||
if (lastSearch != null) {
|
||||
this.searchViewModel.search(lastSearch);
|
||||
}
|
||||
const lastSearchPath: string[] = this.getLastSearchPath();
|
||||
const lastSearch: string | null =
|
||||
this.coreViewModel.storageModel.read(lastSearchPath);
|
||||
if (lastSearch != null) {
|
||||
this.searchViewModel.search(lastSearch);
|
||||
}
|
||||
};
|
||||
|
||||
loadData = (): void => {
|
||||
this.restoreLastUsedView();
|
||||
this.loadTasks();
|
||||
this.loadSearchSuggestions();
|
||||
this.restoreLastUsedView();
|
||||
this.loadTasks();
|
||||
this.loadSearchSuggestions();
|
||||
};
|
||||
|
||||
// exit
|
||||
handleContextClose = (fromHistoryEvent: boolean): void => {
|
||||
this.taskPageViewModel.handleBoardClosed(this);
|
||||
this.taskPageViewModel.handleBoardClosed(this);
|
||||
|
||||
if (!fromHistoryEvent) return;
|
||||
this.taskPageViewModel.storeLastUsedBoard();
|
||||
if (!fromHistoryEvent) return;
|
||||
this.taskPageViewModel.storeLastUsedBoard();
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public readonly coreViewModel: CoreViewModel,
|
||||
public readonly chatViewModel: ChatViewModel,
|
||||
public readonly boardsAndTasksModel: BoardsAndTasksModel,
|
||||
public readonly taskPageViewModel: TaskPageViewModel,
|
||||
public readonly boardInfo: BoardInfoFileContent,
|
||||
public readonly coreViewModel: CoreViewModel,
|
||||
public readonly chatViewModel: ChatViewModel,
|
||||
public readonly boardsAndTasksModel: BoardsAndTasksModel,
|
||||
public readonly taskPageViewModel: TaskPageViewModel,
|
||||
public readonly boardInfo: BoardInfoFileContent,
|
||||
) {
|
||||
super(coreViewModel, chatViewModel, boardsAndTasksModel, "board");
|
||||
super(coreViewModel, chatViewModel, boardsAndTasksModel, "board");
|
||||
|
||||
// load
|
||||
this.preloadData();
|
||||
|
||||
// search
|
||||
this.searchViewModel = new SearchViewModel(
|
||||
this.taskViewModels,
|
||||
this.filteredTaskViewModels,
|
||||
TaskViewModel.getStringsForFilter,
|
||||
this.searchSuggestions,
|
||||
);
|
||||
this.searchViewModel.appliedQuery.subscribeSilent((newQuery) => {
|
||||
this.handleNewSearch(newQuery);
|
||||
});
|
||||
this.restoreSearch();
|
||||
this.searchSuggestions.handleRemovals(this.handleSearchRemoved);
|
||||
// load
|
||||
this.preloadData();
|
||||
|
||||
this.isFilterActive = React.createProxyState(
|
||||
[this.searchViewModel.appliedQuery],
|
||||
() => this.searchViewModel.appliedQuery.value != "",
|
||||
);
|
||||
// search
|
||||
this.searchViewModel = new SearchViewModel(
|
||||
this.taskViewModels,
|
||||
this.filteredTaskViewModels,
|
||||
TaskViewModel.getStringsForFilter,
|
||||
this.searchSuggestions,
|
||||
);
|
||||
this.searchViewModel.appliedQuery.subscribeSilent((newQuery) => {
|
||||
this.handleNewSearch(newQuery);
|
||||
});
|
||||
this.restoreSearch();
|
||||
this.searchSuggestions.handleRemovals(this.handleSearchRemoved);
|
||||
|
||||
// subscriptions
|
||||
this.isSelected = React.createProxyState(
|
||||
[this.taskPageViewModel.selectedBoardId],
|
||||
() =>
|
||||
this.taskPageViewModel.selectedBoardId.value ==
|
||||
this.boardInfo.fileId,
|
||||
);
|
||||
this.isFilterActive = React.createProxyState(
|
||||
[this.searchViewModel.appliedQuery],
|
||||
() => this.searchViewModel.appliedQuery.value != "",
|
||||
);
|
||||
|
||||
this.color.subscribe(() => {
|
||||
if (this.isSelected.value == false) return;
|
||||
if (this.chatViewModel.selectedPage.value != ChatPageTypes.Tasks)
|
||||
return;
|
||||
this.applyColor();
|
||||
});
|
||||
// subscriptions
|
||||
this.isSelected = React.createProxyState(
|
||||
[this.taskPageViewModel.selectedBoardId],
|
||||
() =>
|
||||
this.taskPageViewModel.selectedBoardId.value ==
|
||||
this.boardInfo.fileId,
|
||||
);
|
||||
|
||||
this.selectedPage.subscribeSilent(() => {
|
||||
this.storeLastUsedView();
|
||||
});
|
||||
this.color.subscribe(() => {
|
||||
if (this.isSelected.value == false) return;
|
||||
if (this.chatViewModel.selectedPage.value != ChatPageTypes.Tasks)
|
||||
return;
|
||||
this.applyColor();
|
||||
});
|
||||
|
||||
this.searchViewModel.appliedQuery.subscribeSilent(()=> {
|
||||
this.resetPinchZoom();
|
||||
})
|
||||
this.selectedPage.subscribeSilent(() => {
|
||||
this.storeLastUsedView();
|
||||
});
|
||||
|
||||
// handlers
|
||||
boardsAndTasksModel.taskHandlerManager.setHandler(
|
||||
this.boardInfo.fileId,
|
||||
(taskFileContent: TaskFileContent) => {
|
||||
if (taskFileContent.boardId != this.boardInfo.fileId) return;
|
||||
this.showTask(taskFileContent);
|
||||
this.updateTaskIndices();
|
||||
},
|
||||
);
|
||||
this.searchViewModel.appliedQuery.subscribeSilent(() => {
|
||||
this.resetPinchZoom();
|
||||
});
|
||||
|
||||
// keystrokes
|
||||
this.registerKeyStroke(CommonKeys.Filter, this.showFilterModal);
|
||||
this.registerKeyStroke(CommonKeys.Reset, this.resetFilter); //
|
||||
this.registerKeyStroke(CommonKeys.CloseOrCancel, this.hideFilterModal);
|
||||
this.registerKeyStroke(CommonKeys.Settings, this.showSettings);
|
||||
this.registerKeyStroke(CommonKeys.Apply, this.hideSettings);
|
||||
this.registerKeyStroke(CommonKeys.Create, this.createTask);
|
||||
// handlers
|
||||
boardsAndTasksModel.taskHandlerManager.setHandler(
|
||||
this.boardInfo.fileId,
|
||||
(taskFileContent: TaskFileContent) => {
|
||||
if (taskFileContent.boardId != this.boardInfo.fileId) return;
|
||||
this.showTask(taskFileContent);
|
||||
this.updateTaskIndices();
|
||||
},
|
||||
);
|
||||
|
||||
this.registerKeyStroke(
|
||||
"j",
|
||||
() => (this.selectedPage.value = BoardPageTypes.List),
|
||||
);
|
||||
this.registerKeyStroke(
|
||||
"k",
|
||||
() => (this.selectedPage.value = BoardPageTypes.Kanban),
|
||||
);
|
||||
this.registerKeyStroke(
|
||||
"l",
|
||||
() => (this.selectedPage.value = BoardPageTypes.StatusGrid),
|
||||
);
|
||||
// keystrokes
|
||||
this.registerKeyStroke(CommonKeys.Filter, this.showFilterModal);
|
||||
this.registerKeyStroke(CommonKeys.Reset, this.resetFilter); //
|
||||
this.registerKeyStroke(CommonKeys.CloseOrCancel, this.hideFilterModal);
|
||||
this.registerKeyStroke(CommonKeys.Settings, this.showSettings);
|
||||
this.registerKeyStroke(CommonKeys.Apply, this.hideSettings);
|
||||
this.registerKeyStroke(CommonKeys.Create, this.createTask);
|
||||
|
||||
this.taskPageViewModel.registerContext(this.boardInfo.fileId, this);
|
||||
this.registerKeyStroke(
|
||||
"j",
|
||||
() => (this.selectedPage.value = BoardPageTypes.List),
|
||||
);
|
||||
this.registerKeyStroke(
|
||||
"k",
|
||||
() => (this.selectedPage.value = BoardPageTypes.Kanban),
|
||||
);
|
||||
this.registerKeyStroke(
|
||||
"l",
|
||||
() => (this.selectedPage.value = BoardPageTypes.StatusGrid),
|
||||
);
|
||||
|
||||
this.taskPageViewModel.registerContext(this.boardInfo.fileId, this);
|
||||
}
|
||||
}
|
||||
|
||||
export enum BoardViewModelSubPaths {
|
||||
LastUsedView = "last-used-view",
|
||||
PreviousSearches = "previous-searches",
|
||||
LastSearch = "last-search",
|
||||
PreviousSearches = "previous-searches",
|
||||
LastSearch = "last-search",
|
||||
}
|
||||
|
||||
// types
|
||||
export enum BoardPageTypes {
|
||||
List = "list",
|
||||
Kanban = "kanban",
|
||||
StatusGrid = "status-grid",
|
||||
Kanban = "kanban",
|
||||
StatusGrid = "status-grid",
|
||||
}
|
||||
|
||||
@@ -219,12 +219,12 @@ export default class CalendarPageViewModel extends TaskContainingPageViewModel {
|
||||
};
|
||||
|
||||
loadData = (): void => {};
|
||||
|
||||
|
||||
// context
|
||||
handleContextClose = (fromHistoryEvent: boolean): void | boolean => {
|
||||
if (!fromHistoryEvent) return;
|
||||
return true;
|
||||
}
|
||||
if (!fromHistoryEvent) return;
|
||||
return true;
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
|
||||
@@ -1,34 +1,33 @@
|
||||
import * as React from "../../react";
|
||||
|
||||
import StorageViewModel from "../Global/storageViewModel";
|
||||
import SettingsViewModel from "../Global/settingsViewModel";
|
||||
import FileTransferViewModel from "../Global/fileTransferViewModel";
|
||||
import CoreViewModel, { Context } from "../Global/coreViewModel";
|
||||
import ConnectionViewModel from "../Global/connectionViewModel";
|
||||
import * as React from "../../react";
|
||||
import { CommonKeys } from "../../View/keystrokes";
|
||||
|
||||
export default class HomeViewModel extends Context {
|
||||
constructor(
|
||||
public readonly coreViewModel: CoreViewModel,
|
||||
public readonly settingsViewModel: SettingsViewModel,
|
||||
public readonly fileTransferViewModel: FileTransferViewModel,
|
||||
public readonly storageViewModel: StorageViewModel,
|
||||
public readonly connectionViewModel: ConnectionViewModel,
|
||||
public readonly coreViewModel: CoreViewModel,
|
||||
public readonly settingsViewModel: SettingsViewModel,
|
||||
public readonly fileTransferViewModel: FileTransferViewModel,
|
||||
public readonly storageViewModel: StorageViewModel,
|
||||
public readonly connectionViewModel: ConnectionViewModel,
|
||||
) {
|
||||
super("home");
|
||||
super("home");
|
||||
|
||||
this.coreViewModel.context = this;
|
||||
this.coreViewModel.context = this;
|
||||
|
||||
this.registerKeyStroke(
|
||||
CommonKeys.Settings,
|
||||
this.settingsViewModel.showSettingsModal,
|
||||
);
|
||||
this.registerKeyStroke(
|
||||
"t",
|
||||
this.fileTransferViewModel.showDirectionSelectionModal,
|
||||
);
|
||||
this.registerKeyStroke("e", this.storageViewModel.showStorageModal);
|
||||
this.registerKeyStroke("x", this.connectionViewModel.disconnect);
|
||||
this.registerKeyStroke("c", this.connectionViewModel.connect);
|
||||
this.registerKeyStroke(
|
||||
CommonKeys.Settings,
|
||||
this.settingsViewModel.showSettingsModal,
|
||||
);
|
||||
this.registerKeyStroke(
|
||||
"t",
|
||||
this.fileTransferViewModel.showDirectionSelectionModal,
|
||||
);
|
||||
this.registerKeyStroke("e", this.storageViewModel.showStorageModal);
|
||||
this.registerKeyStroke("x", this.connectionViewModel.disconnect);
|
||||
this.registerKeyStroke("c", this.connectionViewModel.connect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,61 +197,61 @@ export default class MessagePageViewModel extends Context {
|
||||
};
|
||||
|
||||
// context
|
||||
handleContextClose = (fromHistoryEvent: boolean):boolean=> {
|
||||
if (fromHistoryEvent) {
|
||||
if (this.replyViewSelectedMessage.value == undefined) return true;
|
||||
handleContextClose = (fromHistoryEvent: boolean): boolean | void => {
|
||||
if (fromHistoryEvent) {
|
||||
if (this.replyViewSelectedMessage.value == undefined) return true;
|
||||
|
||||
this.resetReplyView();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this.resetReplyView();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
public readonly coreViewModel: CoreViewModel,
|
||||
public readonly chatViewModel: ChatViewModel,
|
||||
public readonly contactListViewModel: ContactListViewModel,
|
||||
public readonly coreViewModel: CoreViewModel,
|
||||
public readonly chatViewModel: ChatViewModel,
|
||||
public readonly contactListViewModel: ContactListViewModel,
|
||||
) {
|
||||
super("message-page");
|
||||
this.restoreFilter();
|
||||
super("message-page");
|
||||
this.restoreFilter();
|
||||
|
||||
// states
|
||||
this.cannotSendMessage = React.createProxyState(
|
||||
[
|
||||
this.chatViewModel.settingsViewModel.username,
|
||||
this.composingMessage,
|
||||
],
|
||||
() =>
|
||||
this.chatViewModel.settingsViewModel.username.value == "" ||
|
||||
this.composingMessage.value == "",
|
||||
);
|
||||
// states
|
||||
this.cannotSendMessage = React.createProxyState(
|
||||
[
|
||||
this.chatViewModel.settingsViewModel.username,
|
||||
this.composingMessage,
|
||||
],
|
||||
() =>
|
||||
this.chatViewModel.settingsViewModel.username.value == "" ||
|
||||
this.composingMessage.value == "",
|
||||
);
|
||||
|
||||
this.searchViewModel = new SearchViewModel(
|
||||
this.chatMessageViewModels,
|
||||
this.filteredMessageViewModels,
|
||||
(chatMessageViewModel) => [chatMessageViewModel.body.value],
|
||||
new React.ListState(),
|
||||
);
|
||||
this.searchViewModel = new SearchViewModel(
|
||||
this.chatMessageViewModels,
|
||||
this.filteredMessageViewModels,
|
||||
(chatMessageViewModel) => [chatMessageViewModel.body.value],
|
||||
new React.ListState(),
|
||||
);
|
||||
|
||||
this.isFilterActive = React.createProxyState(
|
||||
[this.searchViewModel.appliedQuery, this.reactionFilter],
|
||||
() =>
|
||||
this.searchViewModel.appliedQuery.value != "" ||
|
||||
this.reactionFilter.value != undefined,
|
||||
);
|
||||
this.isFilterActive = React.createProxyState(
|
||||
[this.searchViewModel.appliedQuery, this.reactionFilter],
|
||||
() =>
|
||||
this.searchViewModel.appliedQuery.value != "" ||
|
||||
this.reactionFilter.value != undefined,
|
||||
);
|
||||
|
||||
// keystrokes
|
||||
this.registerKeyStroke(CommonKeys.Filter, this.showFilterModal);
|
||||
this.registerKeyStroke(CommonKeys.CloseOrCancel, () => {
|
||||
if (this.isFilterModalOpen.value == true) {
|
||||
this.hideFilterModal();
|
||||
} else {
|
||||
this.replyingMessage.value = undefined;
|
||||
}
|
||||
});
|
||||
this.registerKeyStroke(CommonKeys.Reset, this.resetFilter);
|
||||
this.registerKeyStroke(CommonKeys.Create, this.setFocus);
|
||||
// keystrokes
|
||||
this.registerKeyStroke(CommonKeys.Filter, this.showFilterModal);
|
||||
this.registerKeyStroke(CommonKeys.CloseOrCancel, () => {
|
||||
if (this.isFilterModalOpen.value == true) {
|
||||
this.hideFilterModal();
|
||||
} else {
|
||||
this.replyingMessage.value = undefined;
|
||||
}
|
||||
});
|
||||
this.registerKeyStroke(CommonKeys.Reset, this.resetFilter);
|
||||
this.registerKeyStroke(CommonKeys.Create, this.setFocus);
|
||||
|
||||
this.chatViewModel.registerContext(ChatPageTypes.Messages, this);
|
||||
this.chatViewModel.registerContext(ChatPageTypes.Messages, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import CoreViewModel, { Context } from "../Global/coreViewModel";
|
||||
import ChatViewModel, { ChatPageTypes } from "../Chat/chatViewModel";
|
||||
import * as React from "../../react";
|
||||
import { Colors } from "../../colors";
|
||||
import {random} from "../../Model/Utility/crypto";
|
||||
import { random } from "../../Model/Utility/crypto";
|
||||
|
||||
export default class SettingsPageViewModel extends Context {
|
||||
// state
|
||||
@@ -75,9 +75,8 @@ export default class SettingsPageViewModel extends Context {
|
||||
};
|
||||
|
||||
randomizeKey = (): void => {
|
||||
this.encryptionKeyInput.value = random(24);
|
||||
this.setEncryptionKey();
|
||||
}
|
||||
this.encryptionKeyInput.value = random(24);
|
||||
};
|
||||
|
||||
applyColor = (): void => {
|
||||
this.chatViewModel.setColor(this.color.value);
|
||||
@@ -123,9 +122,9 @@ export default class SettingsPageViewModel extends Context {
|
||||
|
||||
// context
|
||||
handleContextClose = (fromHistoryEvent: boolean): void | boolean => {
|
||||
if (!fromHistoryEvent) return;
|
||||
return true;
|
||||
}
|
||||
if (!fromHistoryEvent) return;
|
||||
return true;
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
|
||||
@@ -165,12 +165,12 @@ export default class TaskPageViewModel extends ContextHost<string> {
|
||||
this.updateBoardIndices();
|
||||
this.openLastUsedBoard();
|
||||
};
|
||||
|
||||
|
||||
// context
|
||||
handleContextClose = (fromHistoryEvent: boolean): void | boolean => {
|
||||
if (!fromHistoryEvent) return;
|
||||
return true;
|
||||
}
|
||||
if (!fromHistoryEvent) return;
|
||||
return true;
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
|
||||
@@ -40,7 +40,7 @@ export default class SearchViewModel<T> {
|
||||
|
||||
clear = (): void => {
|
||||
this.searchInput.value = "";
|
||||
this.applySearch();
|
||||
this.applySearch();
|
||||
};
|
||||
|
||||
deleteSuggestion = (suggestion: string): void => {
|
||||
|
||||
+3
-3
@@ -29,8 +29,8 @@ main {
|
||||
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
|
||||
opacity: .3;
|
||||
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
#background-wrapper > div > div {
|
||||
@@ -143,6 +143,6 @@ body[theme="dark"] #background-wrapper #grass-2 {
|
||||
}
|
||||
|
||||
body[keystroke-active] [ctkeystroke]::after {
|
||||
opacity: .7;
|
||||
opacity: 0.7;
|
||||
transform: translateY(0px);
|
||||
}
|
||||
|
||||
+23
-23
@@ -85,32 +85,32 @@ chatListViewModel.selectedChat.subscribe(() => {
|
||||
|
||||
document.body.append(
|
||||
<div id="background-wrapper">
|
||||
<div>
|
||||
<div id="sky"></div>
|
||||
<div id="grass-1"></div>
|
||||
<div id="grass-2"></div>
|
||||
</div>
|
||||
<div>
|
||||
<div id="sky"></div>
|
||||
<div id="grass-1"></div>
|
||||
<div id="grass-2"></div>
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
document
|
||||
.querySelector("main")!
|
||||
.append(
|
||||
HomePage(
|
||||
coreViewModel,
|
||||
storageViewModel,
|
||||
settingsViewModel,
|
||||
connectionViewModel,
|
||||
fileTransferViewModel,
|
||||
chatListViewModel,
|
||||
),
|
||||
ChatPageWrapper(coreViewModel, chatListViewModel),
|
||||
OnboardingModalWrapper(coreViewModel, onboardingViewModel),
|
||||
ConnectionModal(coreViewModel, connectionViewModel),
|
||||
DataTransferModalWrapper(
|
||||
coreViewModel,
|
||||
connectionViewModel,
|
||||
fileTransferViewModel,
|
||||
),
|
||||
StorageModal(coreViewModel, storageViewModel),
|
||||
SettingsModal(coreViewModel, settingsViewModel),
|
||||
HomePage(
|
||||
coreViewModel,
|
||||
storageViewModel,
|
||||
settingsViewModel,
|
||||
connectionViewModel,
|
||||
fileTransferViewModel,
|
||||
chatListViewModel,
|
||||
),
|
||||
ChatPageWrapper(coreViewModel, chatListViewModel),
|
||||
OnboardingModalWrapper(coreViewModel, onboardingViewModel),
|
||||
ConnectionModal(coreViewModel, connectionViewModel),
|
||||
DataTransferModalWrapper(
|
||||
coreViewModel,
|
||||
connectionViewModel,
|
||||
fileTransferViewModel,
|
||||
),
|
||||
StorageModal(coreViewModel, storageViewModel),
|
||||
SettingsModal(coreViewModel, settingsViewModel),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user