correct type issues

This commit is contained in:
marlon-erler
2026-09-09 00:04:27 +02:00
parent 4631730f02
commit 839e887d85
24 changed files with 511 additions and 437 deletions
+56 -18
View File
@@ -605,9 +605,9 @@
exportHeadline: "Daten exportieren", exportHeadline: "Daten exportieren",
importHeadline: "Daten importieren", importHeadline: "Daten importieren",
selectionDescription: "W\xE4hle die Daten aus, die du \xFCbertragen m\xF6chtest.", selectionDescription: "W\xE4hle die Daten aus, die du \xFCbertragen m\xF6chtest.",
exportSelectionDescription: "W\xE4hle die Daten aus, die du exportieren m\xF6chtest.",
dataEntryDescription: "Gib diese Informationen auf dem anderen Ger\xE4t ein.", dataEntryDescription: "Gib diese Informationen auf dem anderen Ger\xE4t ein.",
dataEntryInputDescription: "Gib die auf dem anderen Ger\xE4t angezeigten Informationen ein.", dataEntryInputDescription: "Gib die auf dem anderen Ger\xE4t angezeigten Informationen ein.",
notConnectedError: "Du bist mit keinem Server verbunden.",
fromThisDeviceButton: "An anderes Ger\xE4t senden", fromThisDeviceButton: "An anderes Ger\xE4t senden",
toThisDeviceButton: "An dieses Ger\xE4t senden", toThisDeviceButton: "An dieses Ger\xE4t senden",
exportButton: "Als Datei exportieren", exportButton: "Als Datei exportieren",
@@ -622,7 +622,13 @@
sendAgainButton: "Erneut senden", sendAgainButton: "Erneut senden",
filesSentCount: (count) => `Dateien gesendet: ${count}.`, filesSentCount: (count) => `Dateien gesendet: ${count}.`,
allFilesSent: "Fertig.", allFilesSent: "Fertig.",
filesReceivedCount: (count) => `Dateien empfangen: ${count}.` filesReceivedCount: (count) => `Dateien empfangen: ${count}.`,
exportKey: "Schl\xFCssel",
exportKeyConfirmation: "Schl\xFCssel best\xE4tigen",
downloadFileButton: "Herunterladen",
importFileButton: "Importieren",
decryptImportButton: "Entschl\xFCsseln",
incorrectPassphraseError: "Der Schl\xFCssel ist nicht korrekt"
}, },
storage: { storage: {
noItemSelected: "Kein Element ausgew\xE4hlt", noItemSelected: "Kein Element ausgew\xE4hlt",
@@ -814,9 +820,9 @@
exportHeadline: "Exportar archivo", exportHeadline: "Exportar archivo",
importHeadline: "Importar archivo", importHeadline: "Importar archivo",
selectionDescription: "Selecciona los datos que quieres transferir.", selectionDescription: "Selecciona los datos que quieres transferir.",
exportSelectionDescription: "Selecciona los datos que quieres exportar.",
dataEntryDescription: "Introduce estos datos en el otro dispositivo.", dataEntryDescription: "Introduce estos datos en el otro dispositivo.",
dataEntryInputDescription: "Introduce los datos mostrados en el otro dispositivo.", dataEntryInputDescription: "Introduce los datos mostrados en el otro dispositivo.",
notConnectedError: "No est\xE1s conectado a ning\xFAn servidor.",
fromThisDeviceButton: "Enviar a otro dispositivo", fromThisDeviceButton: "Enviar a otro dispositivo",
toThisDeviceButton: "Enviar a este dispositivo", toThisDeviceButton: "Enviar a este dispositivo",
exportButton: "Exportar archivo", exportButton: "Exportar archivo",
@@ -826,12 +832,18 @@
settingsData: "Datos de Configuraci\xF3n", settingsData: "Datos de Configuraci\xF3n",
chatsHeadline: "Chats", chatsHeadline: "Chats",
transferChannelHeadline: "Canal de Transferencia", transferChannelHeadline: "Canal de Transferencia",
transferKeyHeadline: "Clave de Encriptaci\xF3n de Transferencia", transferKeyHeadline: "Clave de encriptaci\xF3n de transferencia",
sendButton: "Enviar", sendButton: "Enviar",
sendAgainButton: "Enviar otra vez", sendAgainButton: "Enviar otra vez",
filesSentCount: (count) => `Archivos enviados: ${count}.`, filesSentCount: (count) => `Archivos enviados: ${count}.`,
allFilesSent: "Hecho.", allFilesSent: "Hecho.",
filesReceivedCount: (count) => `Archivos recibidos: ${count}.` filesReceivedCount: (count) => `Archivos recibidos: ${count}.`,
exportKey: "Clave de encriptaci\xF3n",
exportKeyConfirmation: "Confirmar clave",
downloadFileButton: "Descargar",
importFileButton: "Importar",
decryptImportButton: "Descifrar",
incorrectPassphraseError: "La clave no es correcta"
}, },
storage: { storage: {
noItemSelected: "Ning\xFAn elemento seleccionado", noItemSelected: "Ning\xFAn elemento seleccionado",
@@ -1162,6 +1174,8 @@
const point = (e, direction, i) => e.touches[i][direction == "x" ? "clientX" : "clientY"]; const point = (e, direction, i) => e.touches[i][direction == "x" ? "clientX" : "clientY"];
const midpoint = (e, direction) => (point(e, direction, 0) + point(e, direction, 1)) / 2; const midpoint = (e, direction) => (point(e, direction, 0) + point(e, direction, 1)) / 2;
function apply(factor, _offset) { function apply(factor, _offset) {
const el = element();
if (!el) return;
if (factor < MIN) return apply(MIN, _offset); if (factor < MIN) return apply(MIN, _offset);
if (factor > MAX) return apply(5, _offset); if (factor > MAX) return apply(5, _offset);
let x, y; let x, y;
@@ -1170,7 +1184,7 @@
x = currentX; x = currentX;
y = currentY; y = currentY;
} }
element().style.transform = `scale(${factor.toString()}) translate(${x}px, ${y}px)`; el.style.transform = `scale(${factor.toString()}) translate(${x}px, ${y}px)`;
currentX = x; currentX = x;
currentY = y; currentY = y;
currentZoom = factor; currentZoom = factor;
@@ -1194,8 +1208,10 @@
}); });
canvas.addEventListener("touchstart", (event) => { canvas.addEventListener("touchstart", (event) => {
document.activeElement.blur(); document.activeElement.blur();
if (lastElement != void 0 && lastElement != element()) reset(); const el = element();
lastElement = element(); if (!el) return;
if (lastElement != void 0 && lastElement != el) reset();
lastElement = el;
initialZoom = currentZoom; initialZoom = currentZoom;
initialX = currentX; initialX = currentX;
initialY = currentY; initialY = currentY;
@@ -1241,7 +1257,7 @@
this.connectionModel = connectionModel2; this.connectionModel = connectionModel2;
this.chatListModel = chatListModel2; this.chatListModel = chatListModel2;
this.fileTransferModel = fileTransferModel2; this.fileTransferModel = fileTransferModel2;
this.BUILD = "Build 26.09.06.A"; this.BUILD = "Build 26.09.09.A";
// CONTEXT // CONTEXT
this.contextStack = /* @__PURE__ */ new Map(); this.contextStack = /* @__PURE__ */ new Map();
this.closeContext = (contextId, fromHistoryEvent = false) => { this.closeContext = (contextId, fromHistoryEvent = false) => {
@@ -1249,6 +1265,7 @@
return; return;
while (this.contexts.length > 0) { while (this.contexts.length > 0) {
const currentContext = this.context; const currentContext = this.context;
if (!currentContext) return;
currentContext.handleContextClose(fromHistoryEvent); currentContext.handleContextClose(fromHistoryEvent);
this.contextStack.delete(currentContext.contextId); this.contextStack.delete(currentContext.contextId);
if (currentContext.contextId == contextId) break; if (currentContext.contextId == contextId) break;
@@ -1260,7 +1277,7 @@
const contexts = this.contexts; const contexts = this.contexts;
while (contexts.length > 0) { while (contexts.length > 0) {
const currentContext = contexts.pop(); const currentContext = contexts.pop();
if (!currentContext) contexts; if (!currentContext) return;
const isHandled = currentContext.handleKeystroke(e); const isHandled = currentContext.handleKeystroke(e);
if (isHandled == true) break; if (isHandled == true) break;
} }
@@ -1287,6 +1304,7 @@
this.translations = allTranslations[settingsModel2.language] || allTranslations.en; this.translations = allTranslations[settingsModel2.language] || allTranslations.en;
document.body.addEventListener("keydown", this.handleKeyDown); document.body.addEventListener("keydown", this.handleKeyDown);
window.onpopstate = () => { window.onpopstate = () => {
if (!this.context) return;
this.closeContext(this.context.contextId, true); this.closeContext(this.context.contextId, true);
}; };
this.startChron(); this.startChron();
@@ -1337,8 +1355,9 @@
} }
}; };
var ContextHost = class extends Context { var ContextHost = class extends Context {
constructor() { constructor(contextDebugDescription, coreViewModel2) {
super(...arguments); super(contextDebugDescription);
this.coreViewModel = coreViewModel2;
this.contexts = /* @__PURE__ */ new Map(); this.contexts = /* @__PURE__ */ new Map();
this.currentContext = new State(void 0); this.currentContext = new State(void 0);
this.registerContext = (key, context) => { this.registerContext = (key, context) => {
@@ -1354,8 +1373,10 @@
}; };
this.updateContexts = () => { this.updateContexts = () => {
if (this.isOpen == false) return; if (this.isOpen == false) return;
const selection = this.contextSelection;
if (!selection) return;
const selectedContext = this.contexts.get( const selectedContext = this.contexts.get(
this.contextSelection selection
); );
if (!selectedContext) return; if (!selectedContext) return;
if (selectedContext != this.currentContext.value) { if (selectedContext != this.currentContext.value) {
@@ -1657,6 +1678,11 @@
var SettingsModel = class _SettingsModel { var SettingsModel = class _SettingsModel {
// init // init
constructor(storageModel2) { constructor(storageModel2) {
// data
this.username = "";
this.firstDayOfWeek = "";
this.language = "";
this.theme = "";
// storage // storage
this.storeSetting = (pathName, value) => { this.storeSetting = (pathName, value) => {
const path = StorageModel.getPath( const path = StorageModel.getPath(
@@ -1943,6 +1969,7 @@
const input = document.getElementById("file-transfer-input"); const input = document.getElementById("file-transfer-input");
if (!input) return; if (!input) return;
if (!(input instanceof HTMLInputElement)) return; if (!(input instanceof HTMLInputElement)) return;
if (!input.files) return;
const file = input.files[0]; const file = input.files[0];
this.importedFile.value = file; this.importedFile.value = file;
}; };
@@ -1953,6 +1980,7 @@
reader.readAsText(file, "utf8"); reader.readAsText(file, "utf8");
reader.onload = () => { reader.onload = () => {
const result = reader.result; const result = reader.result;
if (!result) return;
this.importedFileString.value = result.toString(); this.importedFileString.value = result.toString();
this.showImportDecryptDataModal(); this.showImportDecryptDataModal();
}; };
@@ -3183,7 +3211,7 @@
var TaskPageViewModel = class extends ContextHost { var TaskPageViewModel = class extends ContextHost {
// init // init
constructor(coreViewModel2, chatViewModel, boardsAndTasksModel) { constructor(coreViewModel2, chatViewModel, boardsAndTasksModel) {
super("task-page"); super("task-page", coreViewModel2);
this.coreViewModel = coreViewModel2; this.coreViewModel = coreViewModel2;
this.chatViewModel = chatViewModel; this.chatViewModel = chatViewModel;
this.boardsAndTasksModel = boardsAndTasksModel; this.boardsAndTasksModel = boardsAndTasksModel;
@@ -3508,6 +3536,8 @@
var ChatModel = class _ChatModel { var ChatModel = class _ChatModel {
// init // init
constructor(storageModel2, connectionModel2, settingsModel2, chatListModel2, chatId) { constructor(storageModel2, connectionModel2, settingsModel2, chatListModel2, chatId) {
/* load function called in constructor */
this.color = "standard" /* Standard */;
// handler managers // handler managers
this.chatMessageHandlerManager = new HandlerManager(); this.chatMessageHandlerManager = new HandlerManager();
this.reactionHandlerManager = new HandlerManager(); this.reactionHandlerManager = new HandlerManager();
@@ -3622,7 +3652,7 @@
}; };
this.sendMessage = async (body, inlineReplyId, fileContent) => { this.sendMessage = async (body, inlineReplyId, fileContent) => {
const nameAndChannel = this.getNameAndChannel(); const nameAndChannel = this.getNameAndChannel();
if (nameAndChannel == false) return; if (nameAndChannel == false) return false;
const [senderName, combinedChannel] = nameAndChannel; const [senderName, combinedChannel] = nameAndChannel;
const chatMessage = await _ChatModel.createChatMessage( const chatMessage = await _ChatModel.createChatMessage(
combinedChannel, combinedChannel,
@@ -3648,10 +3678,10 @@
chatMessage.body = decryptedBody; chatMessage.body = decryptedBody;
chatMessage.stringifiedFile = decryptedFile; chatMessage.stringifiedFile = decryptedFile;
}; };
this.sendReaction = async (messageId, content, isDeleting) => { this.sendReaction = async (messageId, content, isDeleting = false) => {
const nameAndChannel = this.getNameAndChannel(); const nameAndChannel = this.getNameAndChannel();
if (nameAndChannel == false) return; if (nameAndChannel == false) return;
const [senderName, combinedChannel] = nameAndChannel; const [senderName] = nameAndChannel;
const reaction = _ChatModel.createMessageReaction( const reaction = _ChatModel.createMessageReaction(
messageId, messageId,
senderName, senderName,
@@ -3860,6 +3890,9 @@
constructor(coreViewModel2, messagePageViewModel, chatMessage, sentByUser) { constructor(coreViewModel2, messagePageViewModel, chatMessage, sentByUser) {
this.coreViewModel = coreViewModel2; this.coreViewModel = coreViewModel2;
this.messagePageViewModel = messagePageViewModel; this.messagePageViewModel = messagePageViewModel;
this.channel = "";
this.sender = "";
this.dateSent = "";
this.body = new State(""); this.body = new State("");
this.inlineReply = void 0; this.inlineReply = void 0;
this.status = new State( this.status = new State(
@@ -4314,7 +4347,7 @@
var ChatViewModel6 = class extends ContextHost { var ChatViewModel6 = class extends ContextHost {
// init // init
constructor(coreViewModel2, chatModel, settingsViewModel2, notificationViewModel, connectionViewModel2, chatListViewModel2) { constructor(coreViewModel2, chatModel, settingsViewModel2, notificationViewModel, connectionViewModel2, chatListViewModel2) {
super("chat"); super("chat", coreViewModel2);
this.coreViewModel = coreViewModel2; this.coreViewModel = coreViewModel2;
this.chatModel = chatModel; this.chatModel = chatModel;
this.settingsViewModel = settingsViewModel2; this.settingsViewModel = settingsViewModel2;
@@ -4498,6 +4531,7 @@
].find( ].find(
(chat2) => chat2.chatModel.unwrappedPrimaryChannel == notification.chat (chat2) => chat2.chatModel.unwrappedPrimaryChannel == notification.chat
); );
if (!chat) return;
chat.open(); chat.open();
chat.openPage("messages" /* Messages */); chat.openPage("messages" /* Messages */);
}; };
@@ -4508,6 +4542,7 @@
return this.stopLoop(); return this.stopLoop();
} }
const notification = this.messagesInMarquee.shift(); const notification = this.messagesInMarquee.shift();
if (!notification) return;
this.seenMessageIds.delete(notification.messageId); this.seenMessageIds.delete(notification.messageId);
this.marquee.value = notification; this.marquee.value = notification;
}; };
@@ -6573,6 +6608,7 @@
// src/View/Modals/splitModal.tsx // src/View/Modals/splitModal.tsx
function SplitModal(coreViewModel2, leftView, rightView, extendedStyle = false, navigationState) { function SplitModal(coreViewModel2, leftView, rightView, extendedStyle = false, navigationState) {
function closePage() { function closePage() {
if (!navigationState) return;
navigationState.value = void 0; navigationState.value = void 0;
} }
const hasPageOpen = new State(false); const hasPageOpen = new State(false);
@@ -7531,6 +7567,7 @@
return transferData; return transferData;
}; };
this.prepareToSend = () => { this.prepareToSend = () => {
if (!this.transferData) return;
this.direction = 0 /* Send */; this.direction = 0 /* Send */;
this.connectionModel.addChannel(this.transferData.channel); this.connectionModel.addChannel(this.transferData.channel);
}; };
@@ -7627,6 +7664,7 @@
return stringify(fileData); return stringify(fileData);
}; };
this.sendFile = async (stringifiedFileData) => { this.sendFile = async (stringifiedFileData) => {
if (!this.transferData) return;
const encryptedFileData = await encryptString( const encryptedFileData = await encryptString(
stringifiedFileData, stringifiedFileData,
this.transferData.key this.transferData.key
Binary file not shown.
+5 -5
View File
@@ -34,8 +34,8 @@ export default class ChatModel {
// data // data
readonly id: string; readonly id: string;
info: ChatInfo; info: ChatInfo; /* load function called in constructor */
color: Colors; color: Colors = Colors.Standard;
get unwrappedPrimaryChannel(): string { get unwrappedPrimaryChannel(): string {
return this.info.namespace + this.info.primaryChannel; return this.info.namespace + this.info.primaryChannel;
@@ -196,7 +196,7 @@ export default class ChatModel {
fileContent?: FileContent<string>, fileContent?: FileContent<string>,
): Promise<boolean> => { ): Promise<boolean> => {
const nameAndChannel = this.getNameAndChannel(); const nameAndChannel = this.getNameAndChannel();
if (nameAndChannel == false) return; if (nameAndChannel == false) return false;
const [senderName, combinedChannel] = nameAndChannel; const [senderName, combinedChannel] = nameAndChannel;
const chatMessage: ChatMessage = await ChatModel.createChatMessage( const chatMessage: ChatMessage = await ChatModel.createChatMessage(
@@ -231,11 +231,11 @@ export default class ChatModel {
readonly sendReaction = async ( readonly sendReaction = async (
messageId: string, messageId: string,
content: ReactionSymbols, content: ReactionSymbols,
isDeleting?: boolean, isDeleting: boolean = false,
): Promise<void> => { ): Promise<void> => {
const nameAndChannel = this.getNameAndChannel(); const nameAndChannel = this.getNameAndChannel();
if (nameAndChannel == false) return; if (nameAndChannel == false) return;
const [senderName, combinedChannel] = nameAndChannel; const [senderName] = nameAndChannel;
const reaction = ChatModel.createMessageReaction( const reaction = ChatModel.createMessageReaction(
messageId, messageId,
+4 -1
View File
@@ -37,6 +37,7 @@ export default class FileTransferModel {
}; };
readonly prepareToSend = (): void => { readonly prepareToSend = (): void => {
if (!this.transferData) return;
this.direction = TransferDirections.Send; this.direction = TransferDirections.Send;
this.connectionModel.addChannel(this.transferData.channel); this.connectionModel.addChannel(this.transferData.channel);
}; };
@@ -156,7 +157,7 @@ export default class FileTransferModel {
}; };
readonly prepareFileForSending = (filePath: string[]): string => { readonly prepareFileForSending = (filePath: string[]): string => {
const fileContent: string | undefined = const fileContent: string | null =
this.storageModel.read(filePath); this.storageModel.read(filePath);
if (fileContent == null) return ""; if (fileContent == null) return "";
@@ -168,6 +169,8 @@ export default class FileTransferModel {
}; };
readonly sendFile = async (stringifiedFileData: string): Promise<void> => { readonly sendFile = async (stringifiedFileData: string): Promise<void> => {
if (!this.transferData) return;
const encryptedFileData: string = await encryptString( const encryptedFileData: string = await encryptString(
stringifiedFileData, stringifiedFileData,
this.transferData.key, this.transferData.key,
+5 -5
View File
@@ -6,10 +6,10 @@ export default class SettingsModel {
readonly storageModel: StorageModel; readonly storageModel: StorageModel;
// data // data
username: string; username: string = "";
firstDayOfWeek: string; firstDayOfWeek: string = "";
language: string; language: string = "";
theme: string; theme: string = "";
// storage // storage
private readonly storeSetting = ( private readonly storeSetting = (
@@ -46,7 +46,7 @@ export default class SettingsModel {
// load // load
private readonly readSetting = ( private readonly readSetting = (
pathName: keyof typeof filePaths.settingsModel, pathName: keyof typeof filePaths.settingsModel,
): string => { ): string|null=> {
const path = StorageModel.getPath( const path = StorageModel.getPath(
StorageModelSubPaths.SettingsModel, StorageModelSubPaths.SettingsModel,
filePaths.settingsModel[pathName], filePaths.settingsModel[pathName],
Binary file not shown.
+9 -5
View File
@@ -313,7 +313,7 @@ export function implementPinchZoom(canvas: HTMLElement) {
const MIN = 0.25; const MIN = 0.25;
const MAX = 5; const MAX = 5;
const element = (): HTMLElement => canvas.querySelector(".zoom"); const element = (): HTMLElement|null=> canvas.querySelector(".zoom");
const distance = (e: TouchEvent) => const distance = (e: TouchEvent) =>
Math.hypot( Math.hypot(
e.touches[0].pageX - e.touches[1].pageX, e.touches[0].pageX - e.touches[1].pageX,
@@ -325,6 +325,8 @@ export function implementPinchZoom(canvas: HTMLElement) {
(point(e, direction, 0) + point(e, direction, 1)) / 2; (point(e, direction, 0) + point(e, direction, 1)) / 2;
function apply(factor: number, _offset?: [number, number]) { function apply(factor: number, _offset?: [number, number]) {
const el = element();
if (!el) return;
if (factor < MIN) return apply(MIN, _offset); if (factor < MIN) return apply(MIN, _offset);
if (factor > MAX) return apply(5, _offset); if (factor > MAX) return apply(5, _offset);
@@ -334,7 +336,7 @@ export function implementPinchZoom(canvas: HTMLElement) {
x = currentX x = currentX
y = currentY y = currentY
} }
element().style.transform = `scale(${factor.toString()}) translate(${x}px, ${y}px)`; el.style.transform = `scale(${factor.toString()}) translate(${x}px, ${y}px)`;
currentX = x; currentX = x;
currentY = y; currentY = y;
currentZoom = factor; currentZoom = factor;
@@ -356,15 +358,17 @@ export function implementPinchZoom(canvas: HTMLElement) {
} }
apply(currentZoom - event.deltaY * 0.01); apply(currentZoom - event.deltaY * 0.01);
}); });
canvas.addEventListener("scroll", (event: MouseEvent) => { canvas.addEventListener("scroll", (event: Event) => {
event.preventDefault(); event.preventDefault();
}); });
canvas.addEventListener("touchstart", (event: TouchEvent) => { canvas.addEventListener("touchstart", (event: TouchEvent) => {
(document.activeElement as HTMLElement).blur(); (document.activeElement as HTMLElement).blur();
if (lastElement != undefined && lastElement != element()) reset(); const el = element();
lastElement = element(); if (!el) return;
if (lastElement != undefined && lastElement != el) reset();
lastElement = el;
initialZoom = currentZoom; initialZoom = currentZoom;
initialX = currentX; initialX = currentX;
+1 -1
View File
@@ -169,7 +169,7 @@ function SettingsAppearancePane(
<h2>{coreViewModel.translations.settings.pages.appearance}</h2> <h2>{coreViewModel.translations.settings.pages.appearance}</h2>
<hr></hr> <hr></hr>
{OptionButtonList( {OptionButtonList(
new React.ListState<[string, ThemeSettings]>([ new React.ListState<[string, string]>([
[ [
coreViewModel.translations.settings.themes.dark, coreViewModel.translations.settings.themes.dark,
ThemeSettings.Dark, ThemeSettings.Dark,
+1
View File
@@ -10,6 +10,7 @@ export function SplitModal<T>(
navigationState?: React.State<T | undefined>, navigationState?: React.State<T | undefined>,
) { ) {
function closePage() { function closePage() {
if (!navigationState) return;
navigationState.value = undefined; navigationState.value = undefined;
} }
+19 -5
View File
@@ -435,13 +435,13 @@ export const allTranslations: {
importHeadline: "Daten importieren", importHeadline: "Daten importieren",
selectionDescription: selectionDescription:
"Wähle die Daten aus, die du übertragen möchtest.", "Wähle die Daten aus, die du übertragen möchtest.",
exportSelectionDescription:
"Wähle die Daten aus, die du exportieren möchtest.",
dataEntryDescription: dataEntryDescription:
"Gib diese Informationen auf dem anderen Gerät ein.", "Gib diese Informationen auf dem anderen Gerät ein.",
dataEntryInputDescription: dataEntryInputDescription:
"Gib die auf dem anderen Gerät angezeigten Informationen ein.", "Gib die auf dem anderen Gerät angezeigten Informationen ein.",
notConnectedError: "Du bist mit keinem Server verbunden.",
fromThisDeviceButton: "An anderes Gerät senden", fromThisDeviceButton: "An anderes Gerät senden",
toThisDeviceButton: "An dieses Gerät senden", toThisDeviceButton: "An dieses Gerät senden",
exportButton: "Als Datei exportieren", exportButton: "Als Datei exportieren",
@@ -464,6 +464,13 @@ export const allTranslations: {
allFilesSent: "Fertig.", allFilesSent: "Fertig.",
filesReceivedCount: (count) => `Dateien empfangen: ${count}.`, filesReceivedCount: (count) => `Dateien empfangen: ${count}.`,
exportKey: "Schlüssel",
exportKeyConfirmation: "Schlüssel bestätigen",
downloadFileButton: "Herunterladen",
importFileButton: "Importieren",
decryptImportButton: "Entschlüsseln",
incorrectPassphraseError: "Der Schlüssel ist nicht korrekt"
}, },
storage: { storage: {
@@ -722,13 +729,13 @@ export const allTranslations: {
importHeadline: "Importar archivo", importHeadline: "Importar archivo",
selectionDescription: selectionDescription:
"Selecciona los datos que quieres transferir.", "Selecciona los datos que quieres transferir.",
exportSelectionDescription:
"Selecciona los datos que quieres exportar.",
dataEntryDescription: dataEntryDescription:
"Introduce estos datos en el otro dispositivo.", "Introduce estos datos en el otro dispositivo.",
dataEntryInputDescription: dataEntryInputDescription:
"Introduce los datos mostrados en el otro dispositivo.", "Introduce los datos mostrados en el otro dispositivo.",
notConnectedError: "No estás conectado a ningún servidor.",
fromThisDeviceButton: "Enviar a otro dispositivo", fromThisDeviceButton: "Enviar a otro dispositivo",
toThisDeviceButton: "Enviar a este dispositivo", toThisDeviceButton: "Enviar a este dispositivo",
exportButton: "Exportar archivo", exportButton: "Exportar archivo",
@@ -742,7 +749,7 @@ export const allTranslations: {
chatsHeadline: "Chats", chatsHeadline: "Chats",
transferChannelHeadline: "Canal de Transferencia", transferChannelHeadline: "Canal de Transferencia",
transferKeyHeadline: "Clave de Encriptación de Transferencia", transferKeyHeadline: "Clave de encriptación de transferencia",
sendButton: "Enviar", sendButton: "Enviar",
sendAgainButton: "Enviar otra vez", sendAgainButton: "Enviar otra vez",
@@ -751,6 +758,13 @@ export const allTranslations: {
allFilesSent: "Hecho.", allFilesSent: "Hecho.",
filesReceivedCount: (count) => `Archivos recibidos: ${count}.`, filesReceivedCount: (count) => `Archivos recibidos: ${count}.`,
exportKey: "Clave de encriptación",
exportKeyConfirmation: "Confirmar clave",
downloadFileButton: "Descargar",
importFileButton: "Importar",
decryptImportButton: "Descifrar",
incorrectPassphraseError: "La clave no es correcta"
}, },
storage: { storage: {
+3 -3
View File
@@ -7,9 +7,9 @@ class Tracker<T> {
class TrackerMap<T> { class TrackerMap<T> {
trackers = new Map<string, Tracker<T>>(); trackers = new Map<string, Tracker<T>>();
private register = (key: string): Tracker<T> => { private register = (key: string): Tracker<T>=> {
if (this.trackers.has(key)) { if (this.trackers.has(key)) {
return this.trackers.get(key); return this.trackers.get(key)!;
} }
const tracker = new Tracker<T>(); const tracker = new Tracker<T>();
this.trackers.set(key, tracker); this.trackers.set(key, tracker);
@@ -19,7 +19,7 @@ class TrackerMap<T> {
setState = ( setState = (
key: string, key: string,
stateBuilder: () => React.State<T>, stateBuilder: () => React.State<T>,
): React.State<T | undefined> | undefined => { ): React.State<T> | undefined => {
const tracker: Tracker<T> = this.register(key); const tracker: Tracker<T> = this.register(key);
if (tracker.state != undefined) { if (tracker.state != undefined) {
+3 -3
View File
@@ -11,9 +11,9 @@ import {
export default class ChatMessageViewModel { export default class ChatMessageViewModel {
// data // data
chatMessage: ChatMessage; chatMessage: ChatMessage;
channel: string; channel: string = "";
sender: string; sender: string = "";
dateSent: string; dateSent: string = "";
body: React.State<string> = new React.State(""); body: React.State<string> = new React.State("");
inlineReply: ChatMessageViewModel | undefined = undefined; inlineReply: ChatMessageViewModel | undefined = undefined;
status: React.State<ChatMessageStatuses | any> = new React.State<any>( status: React.State<ChatMessageStatuses | any> = new React.State<any>(
+2 -2
View File
@@ -143,14 +143,14 @@ export default class ChatViewModel extends ContextHost<ChatPageTypes> {
// init // init
constructor( constructor(
public readonly coreViewModel: CoreViewModel, readonly coreViewModel: CoreViewModel,
public readonly chatModel: ChatModel, public readonly chatModel: ChatModel,
public readonly settingsViewModel: SettingsViewModel, public readonly settingsViewModel: SettingsViewModel,
public readonly notificationViewModel: NotificationViewModel, public readonly notificationViewModel: NotificationViewModel,
public readonly connectionViewModel: ConnectionViewModel, public readonly connectionViewModel: ConnectionViewModel,
public readonly chatListViewModel: ChatListViewModel, public readonly chatListViewModel: ChatListViewModel,
) { ) {
super("chat"); super("chat", coreViewModel);
// page viewModels // page viewModels
this.calendarViewModel = new CalendarPageViewModel( this.calendarViewModel = new CalendarPageViewModel(
Binary file not shown.
+12 -5
View File
@@ -9,7 +9,7 @@ import ConnectionModel from "../../Model/Global/connectionModel";
import ChatListModel from "../../Model/Chat/chatListModel"; import ChatListModel from "../../Model/Chat/chatListModel";
export default class CoreViewModel { export default class CoreViewModel {
readonly BUILD = "Build 26.09.06.A"; readonly BUILD = "Build 26.09.09.A";
translations: Translations; translations: Translations;
@@ -40,7 +40,8 @@ export default class CoreViewModel {
return; return;
while (this.contexts.length > 0) { while (this.contexts.length > 0) {
const currentContext: Context = this.context; const currentContext: Context|undefined= this.context;
if (!currentContext) return;
currentContext.handleContextClose(fromHistoryEvent); currentContext.handleContextClose(fromHistoryEvent);
this.contextStack.delete(currentContext.contextId); this.contextStack.delete(currentContext.contextId);
if (currentContext.contextId == contextId) break; if (currentContext.contextId == contextId) break;
@@ -53,7 +54,7 @@ export default class CoreViewModel {
const contexts: Context[] = this.contexts; const contexts: Context[] = this.contexts;
while (contexts.length > 0) { while (contexts.length > 0) {
const currentContext: Context | undefined = contexts.pop(); const currentContext: Context | undefined = contexts.pop();
if (!currentContext) contexts; if (!currentContext) return;
const isHandled: boolean = currentContext.handleKeystroke(e); const isHandled: boolean = currentContext.handleKeystroke(e);
if (isHandled == true) break; if (isHandled == true) break;
} }
@@ -102,6 +103,7 @@ export default class CoreViewModel {
document.body.addEventListener("keydown", this.handleKeyDown); document.body.addEventListener("keydown", this.handleKeyDown);
window.onpopstate = () => { window.onpopstate = () => {
if (!this.context) return;
this.closeContext(this.context.contextId, true); this.closeContext(this.context.contextId, true);
}; };
@@ -142,7 +144,6 @@ export class Context {
} }
export class ContextHost<T> extends Context { export class ContextHost<T> extends Context {
coreViewModel: CoreViewModel;
contexts = new Map<T, Context>(); contexts = new Map<T, Context>();
currentContext = new React.State<Context | undefined>(undefined); currentContext = new React.State<Context | undefined>(undefined);
@@ -169,8 +170,10 @@ export class ContextHost<T> extends Context {
updateContexts = (): void => { updateContexts = (): void => {
if (this.isOpen == false) return; if (this.isOpen == false) return;
const selection = this.contextSelection;
if (!selection) return;
const selectedContext: Context | undefined = this.contexts.get( const selectedContext: Context | undefined = this.contexts.get(
this.contextSelection, selection
); );
if (!selectedContext) return; if (!selectedContext) return;
if (selectedContext != this.currentContext.value) { if (selectedContext != this.currentContext.value) {
@@ -180,4 +183,8 @@ export class ContextHost<T> extends Context {
this.coreViewModel.context = selectedContext; this.coreViewModel.context = selectedContext;
this.currentContext.value = selectedContext; this.currentContext.value = selectedContext;
}; };
constructor(contextDebugDescription: string, public coreViewModel: CoreViewModel) {
super(contextDebugDescription);
}
} }
@@ -54,7 +54,7 @@ export default class FileTransferViewModel extends Context {
exportKey: React.State<string> = new React.State(""); exportKey: React.State<string> = new React.State("");
exportKeyConfirmation: React.State<string> = new React.State(""); exportKeyConfirmation: React.State<string> = new React.State("");
importedFile: React.State<File | undefined> = new React.State(undefined); importedFile: React.State<File | undefined> = new React.State<File | undefined>(undefined);
importedFileString: React.State<string> = new React.State(""); importedFileString: React.State<string> = new React.State("");
importKey: React.State<string> = new React.State(""); importKey: React.State<string> = new React.State("");
isImportKeyCorrect: React.State<boolean> = new React.State(true); isImportKeyCorrect: React.State<boolean> = new React.State(true);
@@ -158,6 +158,7 @@ export default class FileTransferViewModel extends Context {
if (!input) return; if (!input) return;
if (!(input instanceof HTMLInputElement)) return; if (!(input instanceof HTMLInputElement)) return;
if (!input.files) return;
const file = input.files[0]; const file = input.files[0];
this.importedFile.value = file; this.importedFile.value = file;
}; };
@@ -170,6 +171,7 @@ export default class FileTransferViewModel extends Context {
reader.readAsText(file, "utf8"); reader.readAsText(file, "utf8");
reader.onload = () => { reader.onload = () => {
const result = reader.result; const result = reader.result;
if (!result) return;
this.importedFileString.value = result.toString(); this.importedFileString.value = result.toString();
this.showImportDecryptDataModal(); this.showImportDecryptDataModal();
}; };
@@ -35,7 +35,7 @@ export default class NotificationViewModel {
}; };
openNotification = () => { openNotification = () => {
const notification: Notification = this.marquee.value; const notification: Notification|undefined = this.marquee.value;
if (notification == undefined) return; if (notification == undefined) return;
const chat = [ const chat = [
@@ -44,6 +44,7 @@ export default class NotificationViewModel {
(chat) => (chat) =>
chat.chatModel.unwrappedPrimaryChannel == notification.chat, chat.chatModel.unwrappedPrimaryChannel == notification.chat,
); );
if (!chat) return;
chat.open(); chat.open();
chat.openPage(ChatPageTypes.Messages); chat.openPage(ChatPageTypes.Messages);
}; };
@@ -55,7 +56,8 @@ export default class NotificationViewModel {
return this.stopLoop(); return this.stopLoop();
} }
const notification: Notification = this.messagesInMarquee.shift(); const notification: Notification|undefined = this.messagesInMarquee.shift();
if (!notification) return;
this.seenMessageIds.delete(notification.messageId); this.seenMessageIds.delete(notification.messageId);
this.marquee.value = notification; this.marquee.value = notification;
}; };
+3 -3
View File
@@ -9,14 +9,14 @@ export default class SettingsViewModel extends Context {
usernameInput: React.State<string> = new React.State(""); usernameInput: React.State<string> = new React.State("");
isShowingSettingsModal: React.State<boolean> = new React.State(false); isShowingSettingsModal: React.State<boolean> = new React.State(false);
selectedModalPage: React.State<SettingsModalPages | undefined> = selectedModalPage: React.State<SettingsModalPages | undefined> =
new React.State(undefined); new React.State<SettingsModalPages | undefined>(undefined);
requiresReload = new React.State<boolean>(false); requiresReload = new React.State<boolean>(false);
firstDayOfWeek: React.State<string> = new React.State("0"); firstDayOfWeek: React.State<string> = new React.State("0");
language: React.State<Languages | string> = new React.State( language: React.State<Languages | string> = new React.State<Languages | string>(
Languages.English, Languages.English,
); );
theme: React.State<ThemeSettings | string> = new React.State( theme: React.State<ThemeSettings | string> = new React.State<ThemeSettings | string>(
ThemeSettings.System, ThemeSettings.System,
); );
+1 -1
View File
@@ -23,7 +23,7 @@ export default class StorageViewModel extends Context {
const path: string[] = StorageModel.stringToPathComponents( const path: string[] = StorageModel.stringToPathComponents(
this.selectedPath.value, this.selectedPath.value,
); );
const content: string | undefined = const content: string | null =
this.coreViewModel.storageModel.read(path); this.coreViewModel.storageModel.read(path);
return ( return (
(content ?? this.coreViewModel.translations.storage.notAFile) || (content ?? this.coreViewModel.translations.storage.notAFile) ||
+1 -1
View File
@@ -68,7 +68,7 @@ export default class MessagePageViewModel extends Context {
); );
}; };
setReply = (chatMessageViewModel: ChatMessageViewModel): void => { setReply = (chatMessageViewModel: ChatMessageViewModel|undefined): void => {
this.replyingMessage.value = chatMessageViewModel; this.replyingMessage.value = chatMessageViewModel;
this.setFocus(); this.setFocus();
}; };
+2 -2
View File
@@ -167,11 +167,11 @@ export default class TaskPageViewModel extends ContextHost<string> {
// init // init
constructor( constructor(
public readonly coreViewModel: CoreViewModel, readonly coreViewModel: CoreViewModel,
public readonly chatViewModel: ChatViewModel, public readonly chatViewModel: ChatViewModel,
public readonly boardsAndTasksModel: BoardsAndTasksModel, public readonly boardsAndTasksModel: BoardsAndTasksModel,
) { ) {
super("task-page"); super("task-page", coreViewModel);
this.loadData(); // needed for board options in calendar this.loadData(); // needed for board options in calendar
-1
View File
@@ -16,7 +16,6 @@ import { SettingsModal } from "./View/Modals/settingsModal";
import { DataTransferModalWrapper } from "./View/Modals/dataTransferModal"; import { DataTransferModalWrapper } from "./View/Modals/dataTransferModal";
import { ConnectionModal } from "./View/Modals/connectionModal"; import { ConnectionModal } from "./View/Modals/connectionModal";
import v1Upgrader from "./Upgrader/v1"; import v1Upgrader from "./Upgrader/v1";
import * as Utility from "./Model/Utility/utility";
import StorageModel from "./Model/Global/storageModel"; import StorageModel from "./Model/Global/storageModel";
import SettingsModel from "./Model/Global/settingsModel"; import SettingsModel from "./Model/Global/settingsModel";
import FileTransferModel from "./Model/Global/fileTransferModel"; import FileTransferModel from "./Model/Global/fileTransferModel";
+2
View File
@@ -0,0 +1,2 @@
declare module "*.css" {
}
+4 -2
View File
@@ -3,8 +3,10 @@
"noImplicitAny": false, "noImplicitAny": false,
"jsx": "react", "jsx": "react",
"jsxFactory": "React.createElement", "jsxFactory": "React.createElement",
"moduleResolution": "node", "module": "nodenext",
"moduleResolution": "nodenext",
"esModuleInterop": true, "esModuleInterop": true,
"target": "es2020" "target": "es2020"
} },
"include":["./**/*"]
} }