Dateien nach "/" hochladen
commit
4a996f58a0
Binary file not shown.
|
After Width: | Height: | Size: 8.0 KiB |
|
|
@ -0,0 +1,349 @@
|
|||
var gui = require('gui');
|
||||
var fs = require('fs');
|
||||
|
||||
var rh = 14;
|
||||
var sp = 4;
|
||||
var y = sp;
|
||||
|
||||
|
||||
let projectData = [
|
||||
{
|
||||
name: "Current",
|
||||
entries: [
|
||||
{
|
||||
date: 1704067200000,
|
||||
subject: '(Savings) Initial Deposit',
|
||||
amount: -500,
|
||||
targetAccount: "Savings"
|
||||
},
|
||||
{
|
||||
date: 1704067200000,
|
||||
subject: 'Salary',
|
||||
amount: 2182.15
|
||||
},
|
||||
{
|
||||
date: 1704153600000,
|
||||
subject: 'Rent',
|
||||
amount: -800
|
||||
},
|
||||
{
|
||||
date: 1704240000000,
|
||||
subject: 'Groceries',
|
||||
amount: -24.19
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Savings",
|
||||
entries: [
|
||||
{
|
||||
date: 1704067200000,
|
||||
subject: 'Initial Deposit',
|
||||
amount: 500
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
function getAccounts(data) {
|
||||
const resultData = [];
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
resultData.push(data[i].name);
|
||||
}
|
||||
return resultData
|
||||
}
|
||||
|
||||
function toListViewEntries(entries, visibleCols) {
|
||||
let cols = visibleCols;
|
||||
return entries.map(e => {
|
||||
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();
|
||||
|
|
@ -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": []
|
||||
}
|
||||
]
|
||||
Loading…
Reference in New Issue