add progress bar to data transfer
This commit is contained in:
Vendored
+63
-53
@@ -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,15 +8701,21 @@
|
||||
};
|
||||
// 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);
|
||||
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) => {
|
||||
@@ -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,16 +133,22 @@ 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);
|
||||
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);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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,7 +5,7 @@ const ENCRYPTION_ALG = "AES-GCM";
|
||||
|
||||
// random
|
||||
export function random(length: number): string {
|
||||
return cryptoRandomString({length})
|
||||
return cryptoRandomString({ length });
|
||||
}
|
||||
|
||||
// encrypt
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
+21
-12
@@ -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 = (
|
||||
@@ -128,10 +137,9 @@ 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>
|
||||
@@ -139,12 +147,13 @@ export function HomePage(
|
||||
|
||||
<hr></hr>
|
||||
|
||||
{NewItemEntry(coreViewModel, chatListViewModel.chatQuery, chatListViewModel.createChat)}
|
||||
{NewItemEntry(
|
||||
coreViewModel,
|
||||
chatListViewModel.chatQuery,
|
||||
chatListViewModel.createChat,
|
||||
)}
|
||||
|
||||
<span
|
||||
class="secondary"
|
||||
toggle:hidden={isChatPlaceholderHidden}
|
||||
>
|
||||
<span class="secondary" toggle:hidden={isChatPlaceholderHidden}>
|
||||
{coreViewModel.translations.homePage.noChatsPlaceholder}
|
||||
</span>
|
||||
|
||||
|
||||
+14
-13
@@ -181,10 +181,10 @@ const englishTranslations = {
|
||||
|
||||
///
|
||||
|
||||
filesSentCount: (count: number) => `Files sent: ${count}.`,
|
||||
allFilesSent: "Done.",
|
||||
|
||||
filesReceivedCount: (count: number) => `Files processed: ${count}.`,
|
||||
filesSentProgress: (progress: number, total: number) =>
|
||||
`Sent ${progress} of ${total} files`,
|
||||
filesReceivedProgress: (progress: number, total: number) =>
|
||||
`Received ${progress} of ${total} files`,
|
||||
|
||||
//
|
||||
|
||||
@@ -402,7 +402,8 @@ export const allTranslations: {
|
||||
saveButton: "Speichern",
|
||||
setButton: "OK",
|
||||
|
||||
filterOrCreateLabel: (type: string) => `${type} suchen oder erstellen`,
|
||||
filterOrCreateLabel: (type: string) =>
|
||||
`${type} suchen oder erstellen`,
|
||||
createLabel: (query: string) => `"${query}" erstellen`,
|
||||
|
||||
reloadAppButton: "Neu laden",
|
||||
@@ -550,10 +551,10 @@ export const allTranslations: {
|
||||
sendButton: "Senden",
|
||||
sendAgainButton: "Erneut senden",
|
||||
|
||||
filesSentCount: (count) => `Dateien gesendet: ${count}.`,
|
||||
allFilesSent: "Fertig.",
|
||||
|
||||
filesReceivedCount: (count) => `Dateien empfangen: ${count}.`,
|
||||
filesSentProgress: (progress: number, total: number) =>
|
||||
`${progress} von ${total} Dateien gesendet`,
|
||||
filesReceivedProgress: (progress: number, total: number) =>
|
||||
`${progress} von ${total} Dateien empfangen`,
|
||||
|
||||
exportKey: "Schlüssel",
|
||||
exportKeyConfirmation: "Schlüssel bestätigen",
|
||||
@@ -894,10 +895,10 @@ export const allTranslations: {
|
||||
sendButton: "Enviar",
|
||||
sendAgainButton: "Enviar otra vez",
|
||||
|
||||
filesSentCount: (count) => `Archivos enviados: ${count}.`,
|
||||
allFilesSent: "Hecho.",
|
||||
|
||||
filesReceivedCount: (count) => `Archivos recibidos: ${count}.`,
|
||||
filesSentProgress: (progress: number, total: number) =>
|
||||
`${progress} de ${total} enviados`,
|
||||
filesReceivedProgress: (progress: number, total: number) =>
|
||||
`${progress} de ${total} recibidos`,
|
||||
|
||||
exportKey: "Clave de encriptación",
|
||||
exportKeyConfirmation: "Confirmar clave",
|
||||
|
||||
@@ -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 =
|
||||
@@ -109,7 +107,12 @@ 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
|
||||
|
||||
@@ -57,14 +57,15 @@ export default class CoreViewModel {
|
||||
while (this.contexts.length > 0) {
|
||||
const currentContext: Context | undefined = this.context;
|
||||
if (!currentContext) break;
|
||||
const response = currentContext.handleContextClose(fromHistoryEvent);
|
||||
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
|
||||
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,
|
||||
|
||||
@@ -203,8 +203,8 @@ export default class BoardViewModel extends TaskContainingPageViewModel {
|
||||
};
|
||||
|
||||
resetPinchZoom = (): void => {
|
||||
this.pinchToZoomData.value = {x: 0, y: 0, zoom: 1};
|
||||
}
|
||||
this.pinchToZoomData.value = { x: 0, y: 0, zoom: 1 };
|
||||
};
|
||||
|
||||
// load
|
||||
preloadData = (): void => {
|
||||
@@ -316,9 +316,9 @@ export default class BoardViewModel extends TaskContainingPageViewModel {
|
||||
this.storeLastUsedView();
|
||||
});
|
||||
|
||||
this.searchViewModel.appliedQuery.subscribeSilent(()=> {
|
||||
this.searchViewModel.appliedQuery.subscribeSilent(() => {
|
||||
this.resetPinchZoom();
|
||||
})
|
||||
});
|
||||
|
||||
// handlers
|
||||
boardsAndTasksModel.taskHandlerManager.setHandler(
|
||||
|
||||
@@ -224,7 +224,7 @@ export default class CalendarPageViewModel extends TaskContainingPageViewModel {
|
||||
handleContextClose = (fromHistoryEvent: boolean): void | boolean => {
|
||||
if (!fromHistoryEvent) return;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
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 {
|
||||
|
||||
@@ -197,14 +197,14 @@ export default class MessagePageViewModel extends Context {
|
||||
};
|
||||
|
||||
// context
|
||||
handleContextClose = (fromHistoryEvent: boolean):boolean=> {
|
||||
handleContextClose = (fromHistoryEvent: boolean): boolean | void => {
|
||||
if (fromHistoryEvent) {
|
||||
if (this.replyViewSelectedMessage.value == undefined) return true;
|
||||
|
||||
this.resetReplyView();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
|
||||
@@ -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
|
||||
@@ -76,8 +76,7 @@ export default class SettingsPageViewModel extends Context {
|
||||
|
||||
randomizeKey = (): void => {
|
||||
this.encryptionKeyInput.value = random(24);
|
||||
this.setEncryptionKey();
|
||||
}
|
||||
};
|
||||
|
||||
applyColor = (): void => {
|
||||
this.chatViewModel.setColor(this.color.value);
|
||||
@@ -125,7 +124,7 @@ export default class SettingsPageViewModel extends Context {
|
||||
handleContextClose = (fromHistoryEvent: boolean): void | boolean => {
|
||||
if (!fromHistoryEvent) return;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
|
||||
@@ -170,7 +170,7 @@ export default class TaskPageViewModel extends ContextHost<string> {
|
||||
handleContextClose = (fromHistoryEvent: boolean): void | boolean => {
|
||||
if (!fromHistoryEvent) return;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user