remove: eliminate file management and LittleFS-based filesystem, implement savegame management for JSON config slots with wear-leveling

This commit is contained in:
2026-04-08 22:12:55 +02:00
parent 1da6d54d7a
commit 301298522b
17 changed files with 318 additions and 622 deletions

View File

@@ -1,96 +1,49 @@
import {Controller} from "./main";
import {FileInfo, FileList} from "./api";
const regex = /[^a-zA-Z0-9_.]/g;
function sanitize(str:string){
return str.replaceAll(regex, '_')
}
import {SaveInfo} from "./api";
export class FileView {
readonly fileListView: HTMLElement;
readonly controller: Controller;
readonly filefreesize: HTMLElement;
readonly filetotalsize: HTMLElement;
readonly fileusedsize: HTMLElement;
constructor(controller: Controller) {
(document.getElementById("fileview") as HTMLElement).innerHTML = require('./fileview.html') as string;
this.fileListView = document.getElementById("fileList") as HTMLElement
this.filefreesize = document.getElementById("filefreesize") as HTMLElement
this.filetotalsize = document.getElementById("filetotalsize") as HTMLElement
this.fileusedsize = document.getElementById("fileusedsize") as HTMLElement
let fileuploadfile = document.getElementById("fileuploadfile") as HTMLInputElement
let fileuploadname = document.getElementById("fileuploadname") as HTMLInputElement
let fileuploadbtn = document.getElementById("fileuploadbtn") as HTMLInputElement
fileuploadfile.onchange = () => {
const selectedFile = fileuploadfile.files?.[0];
if (selectedFile == null) {
//TODO error dialog here
return
}
fileuploadname.value = sanitize(selectedFile.name)
};
fileuploadname.onchange = () => {
let input = fileuploadname.value
let clean = sanitize(fileuploadname.value)
if (input != clean){
fileuploadname.value = clean
}
}
fileuploadbtn.onclick = () => {
const selectedFile = fileuploadfile.files?.[0];
if (selectedFile == null) {
//TODO error dialog here
return
}
controller.uploadFile(selectedFile, selectedFile.name)
}
this.fileListView = document.getElementById("fileList") as HTMLElement;
this.controller = controller;
}
setFileList(fileList: FileList, public_url: string) {
this.filetotalsize.innerText = Math.floor(fileList.total / 1024) + "kB"
this.fileusedsize.innerText = Math.ceil(fileList.used / 1024) + "kB"
this.filefreesize.innerText = Math.ceil((fileList.total - fileList.used) / 1024) + "kB"
setSaveList(saves: SaveInfo[], public_url: string) {
// Sort newest first (highest index = most recently written slot)
const sorted = saves.slice().sort((a, b) => b.idx - a.idx);
//fast clear
this.fileListView.textContent = ""
for (let i = 0; i < fileList.files.length; i++) {
let file = fileList.files[i]
new FileEntry(this.controller, i, file, this.fileListView, public_url);
this.fileListView.textContent = "";
for (let i = 0; i < sorted.length; i++) {
new SaveEntry(this.controller, i, sorted[i], this.fileListView, public_url);
}
}
}
class FileEntry {
class SaveEntry {
view: HTMLElement;
constructor(controller: Controller, fileid: number, fileinfo: FileInfo, parent: HTMLElement, public_url: string) {
this.view = document.createElement("div") as HTMLElement
parent.appendChild(this.view)
this.view.classList.add("fileentryouter")
constructor(controller: Controller, fileid: number, saveinfo: SaveInfo, parent: HTMLElement, public_url: string) {
this.view = document.createElement("div") as HTMLElement;
parent.appendChild(this.view);
this.view.classList.add("fileentryouter");
const template = require('./fileviewentry.html') as string;
this.view.innerHTML = template.replaceAll("${fileid}", String(fileid))
this.view.innerHTML = template.replaceAll("${fileid}", String(fileid));
let name = document.getElementById("file_" + fileid + "_name") as HTMLElement;
let size = document.getElementById("file_" + fileid + "_size") as HTMLElement;
let deleteBtn = document.getElementById("file_" + fileid + "_delete") as HTMLButtonElement;
deleteBtn.onclick = () => {
controller.deleteFile(fileinfo.filename);
}
controller.deleteSlot(saveinfo.idx);
};
let downloadBtn = document.getElementById("file_" + fileid + "_download") as HTMLAnchorElement;
downloadBtn.href = public_url + "/file?filename=" + fileinfo.filename
downloadBtn.download = fileinfo.filename
downloadBtn.href = public_url + "/get_config?saveidx=" + saveinfo.idx;
downloadBtn.download = "config_slot_" + saveinfo.idx + ".json";
name.innerText = fileinfo.filename;
size.innerText = fileinfo.size.toString()
name.innerText = "Slot " + saveinfo.idx;
size.innerText = saveinfo.len + " bytes";
}
}
}