From 4a996f58a04d7397e64e09b83b7deaab1c23f667 Mon Sep 17 00:00:00 2001 From: macniel Date: Fri, 1 May 2026 17:03:30 +0200 Subject: [PATCH] Dateien nach "/" hochladen --- Screenshot From 2026-05-01 16-59-52.png | Bin 0 -> 8146 bytes index.js | 349 ++++++++++++++++++++++++ project.json | 47 ++++ 3 files changed, 396 insertions(+) create mode 100644 Screenshot From 2026-05-01 16-59-52.png create mode 100644 index.js create mode 100644 project.json diff --git a/Screenshot From 2026-05-01 16-59-52.png b/Screenshot From 2026-05-01 16-59-52.png new file mode 100644 index 0000000000000000000000000000000000000000..c20bdbf7256b05ef225ef423298a7f7a702b7957 GIT binary patch literal 8146 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 { + const amount = parseFloat(e.amount); + const subject = ("" + e.subject).substr(0, cols - 20).padEnd(cols - 20, ' '); + const sum = ((amount >= 0 ? "+" : "") + amount.toFixed(2)).substr(0, 10).padStart(10, ' '); + const d = new Date(e.date); + const date = d.getDay().toString().padStart(2, '0') + "-" + (d.getMonth() + 1).toString().padStart(2, '0') + "-" + d.getFullYear(); + let s = (date.substr(0, 10)) + " " + subject + " " + sum; + return s; + }); +} + +function getSummation(entries) { + return entries.reduce((sum, e) => sum + parseFloat(e.amount), 0); +} + +function toDateByComponents(s) { + const parts = s.split("-"); + if (parts.length !== 3) return null; + const day = parseInt(parts[0]); + const month = parseInt(parts[1]) - 1; + const year = parseInt(parts[2]); + if (isNaN(day) || isNaN(month) || isNaN(year)) return null; + return new Date(year, month, day).getTime(); +} + +function subWindow(data) { + let gadgets = []; + let removable = false; + + const innerData = { + date: Date.now(), + subject: '', + amount: 0, + targetAccount: null + } + + if (data) { + innerData.date = data.date; + innerData.subject = data.subject; + innerData.amount = data.amount; + innerData.targetAccount = data.targetAccount; + removable = true; + } + + let d = new Date(innerData.date); + let formattedDate = d.getDay() + "-" + (d.getMonth() + 1) + "-" + d.getFullYear(); + + gadgets.push({ + kind: 'string', id: 1, label: 'Subject:', + left: sp + 80, top: y, width: 400 - sp - 80 - sp, height: rh, + value: innerData.subject + }); + gadgets.push({ + kind: 'string', id: 2, label: 'Amount:', + left: sp + 80, top: sp + rh + sp, width: 100, height: rh, + value: innerData.amount.toFixed(2) + }); + gadgets.push({ + kind: 'string', id: 3, label: 'Date:', + left: sp + 80, top: sp + rh + sp + rh + sp, width: 150, height: rh, + value: formattedDate + }); + gadgets.push({ kind: 'checkbox', id: 6, label: "Account:", left: sp + 80, top: sp + rh + sp + rh + sp + rh + sp + 2, width: rh, height: rh, value: 0 }); + + const accounts = getAccounts(projectData); + + gadgets.push({ kind: 'cycle', id: 7, left: sp + 160 + rh + sp, top: sp + rh + sp + rh + sp + rh + sp, width: 120, height: rh, items: accounts, value: 0 }); + + gadgets.push({ kind: 'button', id: 4, left: sp + 80, top: sp + rh + sp + rh + sp + rh + sp + rh + sp, width: 80, label: "Save", height: rh }); + gadgets.push({ kind: 'button', id: 5, left: sp + 80 + sp + 80, top: sp + rh + sp + rh + sp + rh + sp + rh + sp, width: 80, label: "Remove", height: rh }); + + let win = gui.createWindow({ + title: 'Entry Details', + width: 400, + height: sp + rh + sp + rh + sp + rh + sp + rh + sp + rh + sp, + left: 30, + top: 30, + gadgets: gadgets + }); + + if (innerData.targetAccount) { + gui.set(win, 6, 1); + let i = -1; + for (i = 0; i < accounts.length; i++) { + if (accounts[i] === innerData.targetAccount) { + break; + } + } + gui.set(win, 7, i); + gui.setDisabled(win, 7, false); + } else { + gui.setDisabled(win, 7, true); + } + + gui.setDisabled(win, 5, !removable); + + while (true) { + var evt = gui.waitEvent(win); + if (!evt) continue; + + if (evt.type === 'close') { + gui.closeWindow(win); + return null; + } + if (evt.type === 'gadgetup') { + if (evt.id === 6) { + gui.setDisabled(win, 7, !gui.get(win, 6)); + } + if (evt.id === 4) { + innerData.subject = gui.get(win, 1); + innerData.amount = parseFloat(gui.get(win, 2)); + innerData.date = toDateByComponents(gui.get(win, 3)); + + if (gui.get(win, 6)) { + const targetAccountIndex = gui.get(win, 7); + if (targetAccountIndex !== null && targetAccountIndex !== undefined) { + innerData.targetAccount = data[targetAccountIndex].name; + } + } + + gui.closeWindow(win); + return innerData; + } + if (evt.id === 5) { + gui.closeWindow(win); + return -1; + } + } + } +} + +function mainWindow() { + + let gadgets = []; + + const cycleId = 1; + const listViewId = 2; + const balanceId = 3; + const addButtonId = 4; + + cols = 56; + + gadgets.push({ + kind: 'cycle', id: cycleId, + left: sp, top: y, width: 120, height: rh, border: false, + items: getAccounts(projectData), value: 0 + }); + + gadgets.push({ kind: 'button', id: addButtonId, left: 500 - 80 - sp, top: y, width: 80, label: "+Transfer", height: rh }); + + gadgets.push({ + kind: 'listview', id: listViewId, left: sp, top: y + rh + sp, width: 500 - sp - sp, height: 186, + flex: true, + items: toListViewEntries(projectData[0].entries, cols), value: 0 + }); + + gadgets.push({ + kind: 'text', id: balanceId, label: 'Balance:', + left: 100, top: y + rh + sp + 186, width: 400 - sp, height: rh, + value: getSummation(projectData[0].entries).toFixed(2) + }); + + + + var win = gui.createWindow({ + title: 'Budget', + width: 500, + height: 14 + 4 + 4 + 200 + 4, + left: 20, + top: 15, + gadgets: gadgets + }); + + /* Set up menu bar */ + gui.setMenu(win, [ + { + title: 'Project', + items: [ + { label: 'New...', id: 101, key: 'N' }, + { label: 'Open...', id: 102, key: 'O' }, + { label: 'Save...', id: 103, key: 'S' }, + { label: '---' }, + { label: 'Quit', id: 199, key: 'Q' } + ] + }, + ]); + + let currentAccountIndex = 0; + + function updateView() { + gui.set(win, listViewId, toListViewEntries(projectData[currentAccountIndex].entries, cols)); + gui.set(win, balanceId, getSummation(projectData[currentAccountIndex].entries).toFixed(2)); + } + + function doNew() { + projectData = [ + { + name: "Current", + entries: [] + } + ]; + + + + currentAccountIndex = 0; + gui.set(win, cycleId, getAccounts(projectData)); + gui.set(win, cycleId, 0); + updateView(); + } + + function doOpen() { + var r = gui.fileRequest({ title: 'Open File', pattern: '#?.json' }); + if (r) { + projectData = JSON.parse(fs.readFileSync(r.file)); + } + } + + function doSave() { + var r = gui.fileRequest({ title: 'Save File', pattern: '#?.json', save: true }); + if (r) { + fs.writeFileSync(r.file, JSON.stringify(projectData)); + } + } + + while (true) { + var evt = gui.waitEvent(win); + if (!evt) continue; + + if (evt.type === 'close') break; + + if (evt.type === 'menu') { + if (evt.id === 101) doNew(); + else if (evt.id === 102) doOpen(); + else if (evt.id === 103) doSave(); + else if (evt.id === 199) break; + } + + if (evt.type === 'gadgetup') { + + if (evt.id === cycleId) { + currentAccountIndex = evt.code; + updateView(); + } + + if (evt.id === listViewId) { + const entry = subWindow(projectData[currentAccountIndex].entries[evt.code]); + if (entry != null) { + if (entry === -1) { + projectData[currentAccountIndex].entries.splice(evt.code, 1); + } else { + projectData[currentAccountIndex].entries[evt.code] = entry; + } + if (entry.targetAccount) { + const targetAccount = projectData.find(d => d.name === entry.targetAccount); + if (targetAccount) { + targetAccount.entries.push({ + date: entry.date, + subject: "(" + projectData[currentAccountIndex].name + ")" + entry.subject, + amount: -entry.amount + }); + } + } + updateView(); + } + } + if (evt.id === addButtonId) { + const entry = subWindow(); + if (entry != null) { + projectData[currentAccountIndex].entries.push(entry); + + if (entry.targetAccount) { + const targetAccount = projectData.find(d => d.name === entry.targetAccount); + if (targetAccount) { + targetAccount.entries.push({ + date: entry.date, + subject: "(" + projectData[currentAccountIndex].name + ")" + entry.subject, + amount: -entry.amount + }); + } + } + updateView(); + } + } + } + }; + + + gui.closeWindow(win); +} + +mainWindow(); \ No newline at end of file diff --git a/project.json b/project.json new file mode 100644 index 0000000..6f5956f --- /dev/null +++ b/project.json @@ -0,0 +1,47 @@ +[ + { + "name": "Current", + "entries": [ + { + "date": 1704067200000, + "subject": "(Savings) Initial Deposit", + "targetAccount": "Savings", + "amount": -500 + }, + { + "date": 1704067200000, + "subject": "Salary", + "amount": 2182.15000000000009 + }, + { + "date": 1704153600000, + "subject": "Rent", + "amount": -800 + }, + { + "date": 1704240000000, + "subject": "Groceries", + "amount": -24.19 + }, + { + "date": 1704240000000, + "subject": "Toiletries", + "amount": -12.95 + } + ] + }, + { + "name": "Savings", + "entries": [ + { + "date": 1704067200000, + "subject": "Initial Deposit", + "amount": 500 + } + ] + }, + { + "name": "Portfolio", + "entries": [] + } +] \ No newline at end of file