add storage quota display

This commit is contained in:
marlon-erler
2026-09-24 23:27:54 +02:00
parent a63488d62a
commit c5db5290ac
11 changed files with 500 additions and 326 deletions
+90 -8
View File
@@ -306,12 +306,13 @@
applyButton: "Apply", applyButton: "Apply",
backButton: "Back", backButton: "Back",
cancelButton: "Cancel", cancelButton: "Cancel",
confirmButton: "Confirm",
continueButton: "Continue",
closeButton: "Close", closeButton: "Close",
deleteButton: "Delete", deleteButton: "Delete",
exitButton: "Exit", exitButton: "Exit",
fullscreenButton: "Fullscreen", fullscreenButton: "Fullscreen",
continueButton: "Continue", refreshButton: "Refresh",
confirmButton: "Confirm",
saveButton: "Save", saveButton: "Save",
setButton: "Set", setButton: "Set",
filterOrCreateLabel: "Search or create", filterOrCreateLabel: "Search or create",
@@ -424,6 +425,8 @@
noItemSelected: "No item selected", noItemSelected: "No item selected",
notAFile: "(not a file)", notAFile: "(not a file)",
contentEmpty: "(empty)", contentEmpty: "(empty)",
usageLabel: "Usage",
usageVauleLabel: (used, max) => `${used} of ${max} MB`,
path: "Path", path: "Path",
content: "Content", content: "Content",
deleteItem: "Delete item", deleteItem: "Delete item",
@@ -551,12 +554,13 @@
applyButton: "Anwenden", applyButton: "Anwenden",
backButton: "Zur\xFCck", backButton: "Zur\xFCck",
cancelButton: "Abbrechen", cancelButton: "Abbrechen",
continueButton: "Weiter",
confirmButton: "Best\xE4tigen",
closeButton: "Schlie\xDFen", closeButton: "Schlie\xDFen",
deleteButton: "L\xF6schen", deleteButton: "L\xF6schen",
exitButton: "Schlie\xDFen", exitButton: "Schlie\xDFen",
fullscreenButton: "Vollbild", fullscreenButton: "Vollbild",
continueButton: "Weiter", refreshButton: "Aktualisieren",
confirmButton: "Best\xE4tigen",
saveButton: "Speichern", saveButton: "Speichern",
setButton: "OK", setButton: "OK",
filterOrCreateLabel: "Suchen oder erstellen", filterOrCreateLabel: "Suchen oder erstellen",
@@ -661,6 +665,8 @@
noItemSelected: "Kein Element ausgew\xE4hlt", noItemSelected: "Kein Element ausgew\xE4hlt",
notAFile: "(keine Datei)", notAFile: "(keine Datei)",
contentEmpty: "(leer)", contentEmpty: "(leer)",
usageLabel: "Speicher",
usageVauleLabel: (used, max) => `${used} von ${max} MB belegt`,
path: "Pfad", path: "Pfad",
content: "Inhalt", content: "Inhalt",
deleteItem: "Element l\xF6schen", deleteItem: "Element l\xF6schen",
@@ -776,12 +782,13 @@
applyButton: "Guardar", applyButton: "Guardar",
backButton: "Atr\xE1s", backButton: "Atr\xE1s",
cancelButton: "Cancelar", cancelButton: "Cancelar",
continueButton: "Continuar",
confirmButton: "Confirmar",
closeButton: "Cerrar", closeButton: "Cerrar",
deleteButton: "Borrar", deleteButton: "Borrar",
exitButton: "Salir", exitButton: "Salir",
fullscreenButton: "Pantalla completa", fullscreenButton: "Pantalla completa",
continueButton: "Continuar", refreshButton: "Actualizar",
confirmButton: "Confirmar",
saveButton: "Guardar", saveButton: "Guardar",
setButton: "OK", setButton: "OK",
filterOrCreateLabel: "Buscar o crear", filterOrCreateLabel: "Buscar o crear",
@@ -886,6 +893,8 @@
noItemSelected: "Ning\xFAn elemento seleccionado", noItemSelected: "Ning\xFAn elemento seleccionado",
notAFile: "(no es un archivo)", notAFile: "(no es un archivo)",
contentEmpty: "(vac\xEDo)", contentEmpty: "(vac\xEDo)",
usageLabel: "Almacenamiento",
usageVauleLabel: (used, max) => `${used} de ${max} MB en uso`,
path: "Ruta", path: "Ruta",
content: "Contenido", content: "Contenido",
deleteItem: "Eliminar elemento", deleteItem: "Eliminar elemento",
@@ -1121,6 +1130,9 @@
if (value != null) localStorage.setItem(`_${key}`, value); if (value != null) localStorage.setItem(`_${key}`, value);
return value; return value;
} }
function bytesToMB(bytes) {
return bytes / (1024 * 1024);
}
function stringify(data) { function stringify(data) {
return JSON.stringify(data, null, 4); return JSON.stringify(data, null, 4);
} }
@@ -1607,13 +1619,41 @@
if (object == null) return null; if (object == null) return null;
return object; return object;
}; };
// cleaning // cleaning & usage
this.removeJunk = () => { this.removeJunk = () => {
this.recurse([], (path) => { this.recurse([], (path) => {
if (path[0] == DATA_VERSION) return; if (path[0] == DATA_VERSION) return;
this.remove(path); this.remove(path);
}); });
}; };
this.determineCapacity = () => {
const KEY = "storage-capacity-check";
let chunk = "0";
for (let i = 0; i < 1024 * 256; i++) {
chunk += "0";
}
localStorage.setItem(KEY, "");
while (true) {
try {
const current = localStorage.getItem(KEY);
console.log(current);
localStorage.setItem(KEY, current + chunk);
} catch (e) {
const capacity = this.calculateUsage();
localStorage.removeItem(KEY);
return capacity;
}
}
};
this.calculateUsage = () => {
let data = JSON.stringify(localStorage);
const encoder = new TextEncoder();
const encoded = encoder.encode(data);
const bytes = encoded.byteLength;
const mb = bytesToMB(bytes);
const rounded = Math.round(mb * 100) / 100;
return rounded;
};
// tree // tree
this.initializeTree = () => { this.initializeTree = () => {
console.log("initializing tree"); console.log("initializing tree");
@@ -1721,6 +1761,8 @@
PATH_COMPONENT_SEPARATOR PATH_COMPONENT_SEPARATOR
); );
this.didMakeChanges = new State(false); this.didMakeChanges = new State(false);
this.occupiedSpaceMB = new State(0);
this.maximumSpaceMB = new State(0);
this.lastDeletedItemPath = new State(""); this.lastDeletedItemPath = new State("");
// methods // methods
this.getSelectedItemContent = () => { this.getSelectedItemContent = () => {
@@ -1742,10 +1784,16 @@
this.coreViewModel.storageModel.removeJunk(); this.coreViewModel.storageModel.removeJunk();
this.selectedPath.value = PATH_COMPONENT_SEPARATOR; this.selectedPath.value = PATH_COMPONENT_SEPARATOR;
}; };
this.calculateUsage = () => {
this.occupiedSpaceMB.value = this.coreViewModel.storageModel.calculateUsage();
this.maximumSpaceMB.value = this.coreViewModel.storageModel.determineCapacity();
console.log(this.occupiedSpaceMB.value, this.maximumSpaceMB.value);
};
// view // view
this.showStorageModal = () => { this.showStorageModal = () => {
this.coreViewModel.context = this; this.coreViewModel.context = this;
this.isShowingStorageModal.value = true; this.isShowingStorageModal.value = true;
this.calculateUsage();
}; };
// exit // exit
this.close = () => { this.close = () => {
@@ -7125,13 +7173,47 @@
)); ));
} }
// src/View/Components/usageBar.tsx
function UsageBar(label, valueLabel, value, maximum) {
const style = createProxyState([value, maximum], () => `width: ${100 * (value.value / maximum.value)}%`);
return /* @__PURE__ */ createElement(
"div",
{
class: "surface flex-column padding gap"
},
/* @__PURE__ */ createElement("b", null, label),
/* @__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/storageModal.tsx // src/View/Modals/storageModal.tsx
function StorageModal(coreViewModel2, storageViewModel2) { function StorageModal(coreViewModel2, storageViewModel2) {
const usageValueLabel = createProxyState([storageViewModel2.occupiedSpaceMB, storageViewModel2.maximumSpaceMB], () => coreViewModel2.translations.storage.usageVauleLabel(storageViewModel2.occupiedSpaceMB.value, storageViewModel2.maximumSpaceMB.value));
const detailView = createProxyState( const detailView = createProxyState(
[storageViewModel2.selectedPath], [storageViewModel2.selectedPath],
() => { () => {
if (storageViewModel2.selectedPath.value == PATH_COMPONENT_SEPARATOR) if (storageViewModel2.selectedPath.value == PATH_COMPONENT_SEPARATOR)
return /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.storage.noItemSelected), /* @__PURE__ */ createElement("hr", null), DangerousActionButton( return /* @__PURE__ */ createElement("div", { class: "flex-column gap" }, /* @__PURE__ */ createElement("span", { class: "secondary" }, coreViewModel2.translations.storage.noItemSelected), /* @__PURE__ */ createElement("hr", null), UsageBar(coreViewModel2.translations.storage.usageLabel, usageValueLabel, storageViewModel2.occupiedSpaceMB, storageViewModel2.maximumSpaceMB), /* @__PURE__ */ createElement("hr", null), DangerousActionButton(
coreViewModel2, coreViewModel2,
coreViewModel2.translations.storage.removeJunkButton, coreViewModel2.translations.storage.removeJunkButton,
"delete_forever", "delete_forever",
+4
View File
@@ -145,6 +145,10 @@ a {
color: var(--link); color: var(--link);
} }
.background-primary {
background: var(--primary);
}
/* text */ /* text */
.success { .success {
Vendored
+1 -1
View File
@@ -1,4 +1,4 @@
const VERSION = "2610 Beta 1" const VERSION = "2610 Beta 2"
function processUrl(event) { function processUrl(event) {
const url = event.request.url; const url = event.request.url;
+1 -1
View File
@@ -1 +1 @@
2610 Beta 1 2610 Beta 2
Binary file not shown.
+34 -3
View File
@@ -1,6 +1,5 @@
// cleanup: Phase A
import { localeCompare, parseValidObject, stringify } from "../Utility/utility"; import { bytesToMB, localeCompare, parseValidObject, stringify } from "../Utility/utility";
import { DATA_VERSION, ValidObject } from "../Utility/typeSafety"; import { DATA_VERSION, ValidObject } from "../Utility/typeSafety";
export const PATH_COMPONENT_SEPARATOR = "\\"; export const PATH_COMPONENT_SEPARATOR = "\\";
@@ -144,7 +143,7 @@ export default class StorageModel {
return object; return object;
}; };
// cleaning // cleaning & usage
readonly removeJunk = (): void => { readonly removeJunk = (): void => {
this.recurse([], (path: string[]) => { this.recurse([], (path: string[]) => {
if (path[0] == DATA_VERSION) return; if (path[0] == DATA_VERSION) return;
@@ -152,6 +151,38 @@ export default class StorageModel {
}); });
}; };
readonly determineCapacity = (): number => {
const KEY = "storage-capacity-check";
let chunk = "0";
for (let i = 0; i < 1024*256; i++) {
chunk += "0";
}
localStorage.setItem(KEY, "");
while (true) {
try {
const current = localStorage.getItem(KEY);
console.log(current);
localStorage.setItem(KEY, current + chunk);
} catch (e) {
const capacity = this.calculateUsage();
localStorage.removeItem(KEY);
return capacity;
}
}
}
readonly calculateUsage = (): number => {
let data = JSON.stringify(localStorage);
const encoder = new TextEncoder();
const encoded = encoder.encode(data);
const bytes = encoded.byteLength;
const mb = bytesToMB(bytes);
const rounded = Math.round(mb * 100)/100;
return rounded;
}
// tree // tree
readonly initializeTree = (): void => { readonly initializeTree = (): void => {
console.log("initializing tree"); console.log("initializing tree");
+4
View File
@@ -177,6 +177,10 @@ export function getLocalStorageItemAndClear(key: string): string | null {
return value; return value;
} }
export function bytesToMB(bytes: number): number {
return bytes / (1024*1024);
}
// string & parsing // string & parsing
export function stringify(data: any): string { export function stringify(data: any): string {
return JSON.stringify(data, null, 4); return JSON.stringify(data, null, 4);
+26
View File
@@ -0,0 +1,26 @@
import * as React from "../../react";
export function UsageBar(label: string, 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
class="surface flex-column padding gap"
>
<b>{label}</b>
<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>
);
}
+73 -65
View File
@@ -5,82 +5,90 @@ import * as React from "../../react";
import StorageViewModel from "../../ViewModel/Global/storageViewModel"; import StorageViewModel from "../../ViewModel/Global/storageViewModel";
import CoreViewModel from "../../ViewModel/Global/coreViewModel"; import CoreViewModel from "../../ViewModel/Global/coreViewModel";
import { PATH_COMPONENT_SEPARATOR } from "../../Model/Global/storageModel"; import { PATH_COMPONENT_SEPARATOR } from "../../Model/Global/storageModel";
import {UsageBar} from "../Components/usageBar";
export function StorageModal( export function StorageModal(
coreViewModel: CoreViewModel, coreViewModel: CoreViewModel,
storageViewModel: StorageViewModel, storageViewModel: StorageViewModel,
) { ) {
const usageValueLabel = React.createProxyState([storageViewModel.occupiedSpaceMB, storageViewModel.maximumSpaceMB], ()=>
coreViewModel.translations.storage.usageVauleLabel(storageViewModel.occupiedSpaceMB.value, storageViewModel.maximumSpaceMB.value));
const detailView = React.createProxyState( const detailView = React.createProxyState(
[storageViewModel.selectedPath], [storageViewModel.selectedPath],
() => { () => {
if (storageViewModel.selectedPath.value == PATH_COMPONENT_SEPARATOR) if (storageViewModel.selectedPath.value == PATH_COMPONENT_SEPARATOR)
return ( return (
<div> <div class="flex-column gap">
<span class="secondary"> <span class="secondary">
{coreViewModel.translations.storage.noItemSelected} {coreViewModel.translations.storage.noItemSelected}
</span> </span>
<hr></hr> <hr></hr>
{DangerousActionButton( {UsageBar(coreViewModel.translations.storage.usageLabel, usageValueLabel, storageViewModel.occupiedSpaceMB, storageViewModel.maximumSpaceMB)}
coreViewModel,
coreViewModel.translations.storage.removeJunkButton,
"delete_forever",
storageViewModel.removeJunk,
)}
</div>
);
return ( <hr></hr>
<div class="flex-column gap">
<div class="tile flex-no">
<div>
<b>{coreViewModel.translations.storage.path}</b>
<span
class="break-all"
subscribe:innerText={
storageViewModel.selectedPath
}
></span>
</div>
</div>
<div class="tile flex-no">
<div>
<b>{coreViewModel.translations.storage.content}</b>
<code
subscribe:innerText={
storageViewModel.selectedFileContent
}
></code>
</div>
</div>
{DangerousActionButton( {DangerousActionButton(
coreViewModel, coreViewModel,
coreViewModel.translations.storage.deleteItem, coreViewModel.translations.storage.removeJunkButton,
"delete_forever", "delete_forever",
storageViewModel.deleteSelectedItem, storageViewModel.removeJunk,
)} )}
</div> </div>
); );
},
return (
<div class="flex-column gap">
<div class="tile flex-no">
<div>
<b>{coreViewModel.translations.storage.path}</b>
<span
class="break-all"
subscribe:innerText={
storageViewModel.selectedPath
}
></span>
</div>
</div>
<div class="tile flex-no">
<div>
<b>{coreViewModel.translations.storage.content}</b>
<code
subscribe:innerText={
storageViewModel.selectedFileContent
}
></code>
</div>
</div>
{DangerousActionButton(
coreViewModel,
coreViewModel.translations.storage.deleteItem,
"delete_forever",
storageViewModel.deleteSelectedItem,
)}
</div>
);
},
); );
return ( return (
<div class="modal" toggle:open={storageViewModel.isShowingStorageModal}> <div class="modal" toggle:open={storageViewModel.isShowingStorageModal}>
<div> <div>
<main class="padding-0"> <main class="padding-0">
{SplitModal( {SplitModal(
coreViewModel, coreViewModel,
new React.State(DirectoryItemList(storageViewModel)), new React.State(DirectoryItemList(storageViewModel)),
detailView, detailView,
true, true,
)} )}
</main> </main>
<button on:click={storageViewModel.close}> <button on:click={storageViewModel.close}>
{coreViewModel.translations.general.closeButton} {coreViewModel.translations.general.closeButton}
<span class="icon">close</span> <span class="icon">close</span>
</button> </button>
</div> </div>
</div> </div>
); );
} }
+257 -248
View File
@@ -1,338 +1,341 @@
const englishTranslations = { const englishTranslations = {
updater: { updater: {
migrated: "Migrated", migrated: "Migrated",
}, },
general: { general: {
deleteItemButtonAudioLabel: "delete item", deleteItemButtonAudioLabel: "delete item",
searchButtonAudioLabel: "search", searchButtonAudioLabel: "search",
searchButtonClearAudioLabel: "clear search query", searchButtonClearAudioLabel: "clear search query",
abortButton: "Abort", abortButton: "Abort",
applyButton: "Apply", applyButton: "Apply",
backButton: "Back", backButton: "Back",
cancelButton: "Cancel", cancelButton: "Cancel",
closeButton: "Close", confirmButton: "Confirm",
deleteButton: "Delete", continueButton: "Continue",
exitButton: "Exit", closeButton: "Close",
fullscreenButton: "Fullscreen", deleteButton: "Delete",
exitButton: "Exit",
continueButton: "Continue", fullscreenButton: "Fullscreen",
confirmButton: "Confirm", refreshButton: "Refresh",
saveButton: "Save", saveButton: "Save",
setButton: "Set", setButton: "Set",
filterOrCreateLabel: "Search or create", filterOrCreateLabel: "Search or create",
createLabel: (query: string) => `Create "${query}"`, createLabel: (query: string) => `Create "${query}"`,
reloadAppButton: "Reload App", reloadAppButton: "Reload App",
fileVersionLabel: "Version", fileVersionLabel: "Version",
searchLabel: "Search", searchLabel: "Search",
searchSuggestionsLabel: "Recent searches", searchSuggestionsLabel: "Recent searches",
waitingLabel: "Waiting...", waitingLabel: "Waiting...",
restoreConnection: "Restore connection", restoreConnection: "Restore connection",
noPageSelected: "No page selected", noPageSelected: "No page selected",
}, },
regional: { regional: {
weekdays: { weekdays: {
full: [ full: [
"Sunday", "Sunday",
"Monday", "Monday",
"Tuesday", "Tuesday",
"Wednesday", "Wednesday",
"Thursday", "Thursday",
"Friday", "Friday",
"Saturday", "Saturday",
], ],
abbreviated: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], abbreviated: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
}, },
}, },
homePage: { homePage: {
appName: "Comms", appName: "Comms",
/// ///
overviewHeadline: "Overview", overviewHeadline: "Overview",
serverAddress: "Server address", serverAddress: "Server address",
serverAddressPlaceholder: "wss://192.168.0.69:3000", serverAddressPlaceholder: "wss://192.168.0.69:3000",
connectAudioLabel: "connect to server", connectAudioLabel: "connect to server",
disconnectAudioLabel: "disconnect from server", disconnectAudioLabel: "disconnect from server",
manageConnectionsAudioLabel: "manage connections", manageConnectionsAudioLabel: "manage connections",
yourNameLabel: "Your name", yourNameLabel: "Your name",
yourNamePlaceholder: "Jane Doe", yourNamePlaceholder: "Jane Doe",
setNameButtonAudioLabel: "set name", setNameButtonAudioLabel: "set name",
settingsButton: "Settings", settingsButton: "Settings",
manageStorageButton: "Manage storage", manageStorageButton: "Manage storage",
transferDataButton: "Transfer or export data", transferDataButton: "Transfer or export data",
updateButton: (version: string) => `Update to ${version}`, updateButton: (version: string) => `Update to ${version}`,
scrollToChatButton: "Chats", scrollToChatButton: "Chats",
/// ///
backToOverviewAudioLabel: "go back to overview", backToOverviewAudioLabel: "go back to overview",
chatsHeadline: "Chats", chatsHeadline: "Chats",
addChatAudioLabel: "name of new chat", addChatAudioLabel: "name of new chat",
addChatPlaceholder: "Add chat", addChatPlaceholder: "Add chat",
addChatButton: "Add chat", addChatButton: "Add chat",
}, },
settings: { settings: {
pages: { pages: {
appearance: "Appearance", appearance: "Appearance",
regional: "Language & Region", regional: "Language & Region",
info: "About Comms", info: "About Comms",
}, },
themes: { themes: {
dynamic: "Dynamic", dynamic: "Dynamic",
dark: "Dark", dark: "Dark",
light: "Light", light: "Light",
system: "Device theme", system: "Device theme",
}, },
version: "Version", version: "Version",
language: "Language", language: "Language",
firstDayOfWeekLabel: "First day of week", firstDayOfWeekLabel: "First day of week",
}, },
connectionModal: { connectionModal: {
connectionModalHeadline: "Manage Connections", connectionModalHeadline: "Manage Connections",
/// ///
connectButtonAudioLabel: "connect", connectButtonAudioLabel: "connect",
}, },
dataTransferModal: { dataTransferModal: {
transferDataHeadline: "Data Transfer", transferDataHeadline: "Data Transfer",
sendHeadline: "Transfer to other device", sendHeadline: "Transfer to other device",
receiveHeadline: "Transfer to This Device", receiveHeadline: "Transfer to This Device",
exportHeadline: "Export Data", exportHeadline: "Export Data",
importHeadline: "Import Data", importHeadline: "Import Data",
selectionDescription: "Select the data that you want to transfer.", selectionDescription: "Select the data that you want to transfer.",
exportSelectionDescription: "Select the data that you want to export.", exportSelectionDescription: "Select the data that you want to export.",
dataEntryDescription: "Enter this data on the other device.", dataEntryDescription: "Enter this data on the other device.",
dataEntryInputDescription: dataEntryInputDescription:
"Enter the data displayed on the other device.", "Enter the data displayed on the other device.",
/// ///
fromThisDeviceButton: "Send to other device", fromThisDeviceButton: "Send to other device",
toThisDeviceButton: "Send to this device", toThisDeviceButton: "Send to this device",
exportButton: "Export to file", exportButton: "Export to file",
importButton: "Import from file", importButton: "Import from file",
/// ///
generalHeadline: "General", generalHeadline: "General",
connectionData: "Connection Data", connectionData: "Connection Data",
settingsData: "Settings Data", settingsData: "Settings Data",
chatsHeadline: "Chats", chatsHeadline: "Chats",
/// ///
transferChannelHeadline: "Transfer Chanel", transferChannelHeadline: "Transfer Chanel",
transferKeyHeadline: "Transfer Encryption Key", transferKeyHeadline: "Transfer Encryption Key",
sendButton: "Send", sendButton: "Send",
sendAgainButton: "Send again", sendAgainButton: "Send again",
/// ///
filesSentCount: (count: number) => `Files sent: ${count}.`, filesSentCount: (count: number) => `Files sent: ${count}.`,
allFilesSent: "Done.", allFilesSent: "Done.",
filesReceivedCount: (count: number) => `Files processed: ${count}.`, filesReceivedCount: (count: number) => `Files processed: ${count}.`,
// //
exportKey: "Encryption key", exportKey: "Encryption key",
exportKeyConfirmation: "Confirm", exportKeyConfirmation: "Confirm",
downloadFileButton: "Download", downloadFileButton: "Download",
importFileButton: "Import", importFileButton: "Import",
decryptImportButton: "Decrypt", decryptImportButton: "Decrypt",
incorrectPassphraseError: "The encryption key is incorrect", incorrectPassphraseError: "The encryption key is incorrect",
}, },
storage: { storage: {
noItemSelected: "No item selected", noItemSelected: "No item selected",
notAFile: "(not a file)", notAFile: "(not a file)",
contentEmpty: "(empty)", contentEmpty: "(empty)",
path: "Path", usageLabel: "Usage",
content: "Content", usageVauleLabel: (used: number, max: number) => `${used} of ${max} MB`,
deleteItem: "Delete item", path: "Path",
content: "Content",
removeJunkButton: "Delete junk files", deleteItem: "Delete item",
removeJunkButton: "Delete junk files",
}, },
chatPage: { chatPage: {
closeChatAudioLabe: "close chat", closeChatAudioLabe: "close chat",
chatSettingsAudioLabel: "chat settings", chatSettingsAudioLabel: "chat settings",
pages: { pages: {
settings: "Settings", settings: "Settings",
messages: "Messages", messages: "Messages",
tasks: "Tasks", tasks: "Tasks",
calendar: "Calendar", calendar: "Calendar",
}, },
settings: { settings: {
settingsHeadline: "Settings", settingsHeadline: "Settings",
primaryChannelLabel: "Primary channel", primaryChannelLabel: "Primary channel",
setPrimaryChannelButtonAudioLabel: "set primary channel", setPrimaryChannelButtonAudioLabel: "set primary channel",
namespaceLabel: "Namespace", namespaceLabel: "Namespace",
namespacePlaceholder: "No namespace", namespacePlaceholder: "No namespace",
setNamespaceButtonAudioLabel: "set namespace", setNamespaceButtonAudioLabel: "set namespace",
newSecondaryChannelPlaceholder: "Add secondary channel", newSecondaryChannelPlaceholder: "Add secondary channel",
newSecondaryChannelAudioLabel: "name of new secondary channel", newSecondaryChannelAudioLabel: "name of new secondary channel",
addSecondaryChannelButtonAudioLabel: "add secondary channel", addSecondaryChannelButtonAudioLabel: "add secondary channel",
encryptionKeyLabel: "Encryption key", encryptionKeyLabel: "Encryption key",
setEncryptionKeyButtonAudioLabel: "set encryption key", setEncryptionKeyButtonAudioLabel: "set encryption key",
showEncryptionKey: "Show encryption key", showEncryptionKey: "Show encryption key",
deleteChatButton: "Delete entire chat", deleteChatButton: "Delete entire chat",
}, },
message: { message: {
messagesHeadline: "Messages", messagesHeadline: "Messages",
messageFilterHeadline: "Filter messages", messageFilterHeadline: "Filter messages",
messageFilterReactionsHadline: "Reactions", messageFilterReactionsHadline: "Reactions",
messageFilterAllReactionsButton: "Show all", messageFilterAllReactionsButton: "Show all",
/// ///
composerInputPlaceholder: "Type a message...", composerInputPlaceholder: "Type a message...",
sendMessageButtonAudioLabel: "send message", sendMessageButtonAudioLabel: "send message",
filterMessagesButtonAudioLabel: "filter messages", filterMessagesButtonAudioLabel: "filter messages",
/// ///
showMessageInfoButtonAudioLabel: "show message info", showMessageInfoButtonAudioLabel: "show message info",
messageInfoHeadline: "Message Info", messageInfoHeadline: "Message Info",
cancelReplyAudioLabel: "cancel reply", cancelReplyAudioLabel: "cancel reply",
sentBy: "Sent by", sentBy: "Sent by",
timeSent: "Time sent", timeSent: "Time sent",
channel: "Channel", channel: "Channel",
messageContent: "Message content", messageContent: "Message content",
copyMessageButton: "Copy message", copyMessageButton: "Copy message",
resendMessageButton: "Resend message", resendMessageButton: "Resend message",
decryptMessageButton: "Decrypt message", decryptMessageButton: "Decrypt message",
replyToMessageButton: "Reply to message", replyToMessageButton: "Reply to message",
deleteMessageButton: "Delete message", deleteMessageButton: "Delete message",
//
thumbsUpReaction: "Reaction: thumbs up",
checkReaction: "Reaction: check",
stopReaction: "Reaction: stop sign",
attentionReaction: "Reaction: exclamation mark",
doubleAttentionReaction: "Reaction: double exclamation mark",
questionReaction: "Reaction: question mark",
// //
thumbsUpReaction: "Reaction: thumbs up",
checkReaction: "Reaction: check",
stopReaction: "Reaction: stop sign",
attentionReaction: "Reaction: exclamation mark",
doubleAttentionReaction: "Reaction: double exclamation mark",
questionReaction: "Reaction: question mark",
//
replyPrefixLabel: "Replies: ", replyPrefixLabel: "Replies: ",
replyHeaderLabel: (message: string) => `Replies to "${message}"`, replyHeaderLabel: (message: string) => `Replies to "${message}"`,
}, },
task: { task: {
noBoardSelected: "No board selected", noBoardSelected: "No board selected",
boardNotFound: "Board not found", boardNotFound: "Board not found",
/// ///
closeBoardButtonAudioLabel: "close board", closeBoardButtonAudioLabel: "close board",
toggleBoardButtonAudioLabel: "toggle board list", toggleBoardButtonAudioLabel: "toggle board list",
showBoardSettingsButtonAudioLabel: "show board settigns", showBoardSettingsButtonAudioLabel: "show board settigns",
listViewButtonAudioLabel: "list view", listViewButtonAudioLabel: "list view",
kanbanViewButtonAudioLabel: "kanban view", kanbanViewButtonAudioLabel: "kanban view",
statusViewButtonAudioLabel: "status grid view", statusViewButtonAudioLabel: "status grid view",
filterTasksButtonAudioLabel: "filter tasks", filterTasksButtonAudioLabel: "filter tasks",
createTaskButtonAudioLabel: "create new task", createTaskButtonAudioLabel: "create new task",
/// ///
boardSettingsHeadline: "Board Settings", boardSettingsHeadline: "Board Settings",
boardNameInputLabel: "Board name", boardNameInputLabel: "Board name",
deleteBoardButton: "Delete board and all tasks", deleteBoardButton: "Delete board and all tasks",
/// ///
taskSettingsHeadline: "Edit Task", taskSettingsHeadline: "Edit Task",
taskNameLabel: "Title", taskNameLabel: "Title",
taskBoardLabel: "Board", taskBoardLabel: "Board",
taskCategoryLabel: "Category", taskCategoryLabel: "Category",
taskStatusLabel: "Status", taskStatusLabel: "Status",
taskPriorityLabel: "Priority", taskPriorityLabel: "Priority",
taskDescriptionLabel: "Description", taskDescriptionLabel: "Description",
taskDateLabel: "Date", taskDateLabel: "Date",
taskTimeLabel: "Time", taskTimeLabel: "Time",
deleteTaskButton: "Delete task", deleteTaskButton: "Delete task",
/// ///
filterTasksHeadline: "Filter Tasks", filterTasksHeadline: "Filter Tasks",
/// ///
renameCategoryInputPlaceholder: "Rename category", renameCategoryInputPlaceholder: "Rename category",
renameStatusInputPlaceholder: "Rename status", renameStatusInputPlaceholder: "Rename status",
}, },
calendar: { calendar: {
eventsBoard: "Events", eventsBoard: "Events",
/// ///
todayButtonAudioLabel: "go to today", todayButtonAudioLabel: "go to today",
previousMonthButtonAudioLabel: "previous month", previousMonthButtonAudioLabel: "previous month",
nextMonthButtonAudioLabel: "next month", nextMonthButtonAudioLabel: "next month",
yearInputAudioLabel: "year", yearInputAudioLabel: "year",
monthInputAudioLabel: "month", monthInputAudioLabel: "month",
yearInputPlaceholder: "2000", yearInputPlaceholder: "2000",
monthInputPlaceholder: "01", monthInputPlaceholder: "01",
/// ///
searchEventsHeadline: "Search Events", searchEventsHeadline: "Search Events",
/// ///
events: "Events", events: "Events",
noEvents: "No events", noEvents: "No events",
}, },
}, },
}; };
@@ -342,29 +345,29 @@ export const allTranslations: {
en: englishTranslations, en: englishTranslations,
de: { de: {
updater: { updater: {
migrated: "Migriert", migrated: "Migriert",
}, },
general: { general: {
deleteItemButtonAudioLabel: "element löschen", deleteItemButtonAudioLabel: "element löschen",
searchButtonAudioLabel: "suchen", searchButtonAudioLabel: "suchen",
searchButtonClearAudioLabel: "suche zurücksetzen", searchButtonClearAudioLabel: "suche zurücksetzen",
abortButton: "Abbrechen", abortButton: "Abbrechen",
applyButton: "Anwenden", applyButton: "Anwenden",
backButton: "Zurück", backButton: "Zurück",
cancelButton: "Abbrechen", cancelButton: "Abbrechen",
closeButton: "Schließen", continueButton: "Weiter",
deleteButton: "Löschen", confirmButton: "Bestätigen",
exitButton: "Schließen", closeButton: "Schließen",
fullscreenButton: "Vollbild", deleteButton: "Löschen",
exitButton: "Schließen",
fullscreenButton: "Vollbild",
refreshButton: "Aktualisieren",
saveButton: "Speichern",
setButton: "OK",
continueButton: "Weiter",
confirmButton: "Bestätigen",
saveButton: "Speichern",
setButton: "OK",
filterOrCreateLabel: "Suchen oder erstellen", filterOrCreateLabel: "Suchen oder erstellen",
createLabel: (query: string) => `"${query}" erstellen`, createLabel: (query: string) => `"${query}" erstellen`,
@@ -413,7 +416,7 @@ export const allTranslations: {
settingsButton: "Einstellungen", settingsButton: "Einstellungen",
manageStorageButton: "Daten verwalten", manageStorageButton: "Daten verwalten",
transferDataButton: "Daten übertragen", transferDataButton: "Daten übertragen",
updateButton: (version: string) => `Aktualisieren: ${version}`, updateButton: (version: string) => `Aktualisieren: ${version}`,
scrollToChatButton: "Chats", scrollToChatButton: "Chats",
@@ -502,6 +505,9 @@ export const allTranslations: {
notAFile: "(keine Datei)", notAFile: "(keine Datei)",
contentEmpty: "(leer)", contentEmpty: "(leer)",
usageLabel: "Speicher",
usageVauleLabel: (used: number, max: number) => `${used} von ${max} MB belegt`,
path: "Pfad", path: "Pfad",
content: "Inhalt", content: "Inhalt",
@@ -578,7 +584,7 @@ export const allTranslations: {
attentionReaction: "Reaktion: Ausrufezeichen", attentionReaction: "Reaktion: Ausrufezeichen",
doubleAttentionReaction: "Reaktion: doppeltes Ausrufezeichen", doubleAttentionReaction: "Reaktion: doppeltes Ausrufezeichen",
questionReaction: "Reaktion: Fragezeichen", questionReaction: "Reaktion: Fragezeichen",
replyPrefixLabel: "Antworten: ", replyPrefixLabel: "Antworten: ",
replyHeaderLabel: (message: string) => `Antworten an "${message}"`, replyHeaderLabel: (message: string) => `Antworten an "${message}"`,
}, },
@@ -662,13 +668,13 @@ export const allTranslations: {
applyButton: "Guardar", applyButton: "Guardar",
backButton: "Atrás", backButton: "Atrás",
cancelButton: "Cancelar", cancelButton: "Cancelar",
continueButton: "Continuar",
confirmButton: "Confirmar",
closeButton: "Cerrar", closeButton: "Cerrar",
deleteButton: "Borrar", deleteButton: "Borrar",
exitButton: "Salir", exitButton: "Salir",
fullscreenButton: "Pantalla completa", fullscreenButton: "Pantalla completa",
refreshButton: "Actualizar",
continueButton: "Continuar",
confirmButton: "Confirmar",
saveButton: "Guardar", saveButton: "Guardar",
setButton: "OK", setButton: "OK",
@@ -720,7 +726,7 @@ export const allTranslations: {
settingsButton: "Ajustes", settingsButton: "Ajustes",
manageStorageButton: "Gestionar almacenamiento", manageStorageButton: "Gestionar almacenamiento",
transferDataButton: "Enviar o exportar archivos", transferDataButton: "Enviar o exportar archivos",
updateButton: (version: string) => `Actualizar a ${version}`, updateButton: (version: string) => `Actualizar a ${version}`,
scrollToChatButton: "Chats", scrollToChatButton: "Chats",
@@ -808,6 +814,9 @@ export const allTranslations: {
notAFile: "(no es un archivo)", notAFile: "(no es un archivo)",
contentEmpty: "(vacío)", contentEmpty: "(vacío)",
usageLabel: "Almacenamiento",
usageVauleLabel: (used: number, max: number) => `${used} de ${max} MB en uso`,
path: "Ruta", path: "Ruta",
content: "Contenido", content: "Contenido",
+10
View File
@@ -13,6 +13,9 @@ export default class StorageViewModel extends Context {
); );
didMakeChanges: React.State<boolean> = new React.State(false); didMakeChanges: React.State<boolean> = new React.State(false);
occupiedSpaceMB: React.State<number> = new React.State(0);
maximumSpaceMB: React.State<number> = new React.State(0);
selectedFileName: React.State<string>; selectedFileName: React.State<string>;
selectedFileContent: React.State<string>; selectedFileContent: React.State<string>;
@@ -46,10 +49,17 @@ export default class StorageViewModel extends Context {
this.selectedPath.value = PATH_COMPONENT_SEPARATOR; this.selectedPath.value = PATH_COMPONENT_SEPARATOR;
}; };
calculateUsage = (): void => {
this.occupiedSpaceMB.value = this.coreViewModel.storageModel.calculateUsage();
this.maximumSpaceMB.value = this.coreViewModel.storageModel.determineCapacity();
console.log(this.occupiedSpaceMB.value, this.maximumSpaceMB.value);
}
// view // view
showStorageModal = (): void => { showStorageModal = (): void => {
this.coreViewModel.context = this; this.coreViewModel.context = this;
this.isShowingStorageModal.value = true; this.isShowingStorageModal.value = true;
this.calculateUsage();
}; };
// exit // exit