commit
46795ed074
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New app!
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Tally
|
||||||
|
|
||||||
|
An app that lets you keep a tally - when events happen, etc.
|
||||||
|
|
||||||
|
Use the clock info to add to the tally. The app can be used to review/edit/delete tallies
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Navigate to the tally clock info, then swipe up/down to select one of the tallies to enter. Tap on it to add to the tally.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwInkgf/AAXAg4FD8EPAofwAowcDAqkD4AFW4fAAqYEBAtp3XTZStFXIsAh/gD4cPBAIFDwAFEbAkOAokMAokIApQAKA=="))
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
var storage = require("Storage");
|
||||||
|
function readTallies() {
|
||||||
|
var tallies = [];
|
||||||
|
var f = storage.open("tallies.csv", "r");
|
||||||
|
var line;
|
||||||
|
while ((line = f.readLine()) !== undefined) {
|
||||||
|
var parts = line.replace("\n", "").split(",");
|
||||||
|
tallies.push({ date: new Date(parts[0]), name: parts[1] });
|
||||||
|
}
|
||||||
|
return tallies;
|
||||||
|
}
|
||||||
|
function saveTallies(tallies) {
|
||||||
|
var f = storage.open("tallies.csv", "w");
|
||||||
|
for (var _i = 0, tallies_1 = tallies; _i < tallies_1.length; _i++) {
|
||||||
|
var tally = tallies_1[_i];
|
||||||
|
f.write([tally.date.toISOString(), tally.name].join(",") + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var dayEq = function (a, b) {
|
||||||
|
return a.getFullYear() === b.getFullYear()
|
||||||
|
&& a.getMonth() === b.getMonth()
|
||||||
|
&& a.getDate() === b.getDate();
|
||||||
|
};
|
||||||
|
function showTallies(tallies) {
|
||||||
|
var menu = {
|
||||||
|
"": { title: "Tallies" },
|
||||||
|
"< Back": function () { return load(); },
|
||||||
|
};
|
||||||
|
var today = new Date;
|
||||||
|
var day;
|
||||||
|
tallies.forEach(function (tally, i) {
|
||||||
|
var td = tally.date;
|
||||||
|
if (!dayEq(day !== null && day !== void 0 ? day : today, td)) {
|
||||||
|
var s = "".concat(td.getFullYear(), "-").concat(pad2(td.getMonth() + 1), "-").concat(pad2(td.getDate()));
|
||||||
|
menu[s] = function () { };
|
||||||
|
day = td;
|
||||||
|
}
|
||||||
|
menu["".concat(tfmt(tally), ": ").concat(tally.name)] = function () { return editTally(tallies, i); };
|
||||||
|
});
|
||||||
|
E.showMenu(menu);
|
||||||
|
}
|
||||||
|
function editTally(tallies, i) {
|
||||||
|
var tally = tallies[i];
|
||||||
|
var onback = function () {
|
||||||
|
saveTallies(tallies);
|
||||||
|
E.removeListener("kill", onback);
|
||||||
|
};
|
||||||
|
E.on("kill", onback);
|
||||||
|
var menu = {
|
||||||
|
"": { title: "Edit ".concat(tally.name) },
|
||||||
|
"< Back": function () {
|
||||||
|
onback();
|
||||||
|
showTallies(tallies);
|
||||||
|
},
|
||||||
|
"Name": {
|
||||||
|
value: tally.name,
|
||||||
|
onchange: function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
require("textinput")
|
||||||
|
.input({ text: tally.name })
|
||||||
|
.then(function (text) {
|
||||||
|
if (text) {
|
||||||
|
tally.name = text;
|
||||||
|
}
|
||||||
|
editTally(tallies, i);
|
||||||
|
});
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Time": {
|
||||||
|
value: tally.date.getTime(),
|
||||||
|
format: function (_tm) { return tfmt(tally); },
|
||||||
|
onchange: function (v) {
|
||||||
|
tally.date = new Date(v);
|
||||||
|
},
|
||||||
|
step: 60000,
|
||||||
|
},
|
||||||
|
"Delete": function () {
|
||||||
|
E.showPrompt("Delete \"".concat(tally.name, "\"?"), {
|
||||||
|
title: "Delete",
|
||||||
|
buttons: { Yes: true, No: false },
|
||||||
|
}).then(function (confirm) {
|
||||||
|
if (confirm) {
|
||||||
|
tallies.splice(i, 1);
|
||||||
|
saveTallies(tallies);
|
||||||
|
showTallies(tallies);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
editTally(tallies, i);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
E.showMenu(menu);
|
||||||
|
}
|
||||||
|
function tfmt(tally) {
|
||||||
|
var d = tally.date;
|
||||||
|
return "".concat(d.getHours(), ":").concat(pad2(d.getMinutes()));
|
||||||
|
}
|
||||||
|
var pad2 = function (s) { return ("0" + s.toFixed(0)).slice(-2); };
|
||||||
|
showTallies(readTallies());
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 296 B |
|
|
@ -0,0 +1,120 @@
|
||||||
|
const storage = require("Storage");
|
||||||
|
|
||||||
|
type Tally = {
|
||||||
|
date: Date,
|
||||||
|
name: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
function readTallies() {
|
||||||
|
const tallies: Tally[] = [];
|
||||||
|
const f = storage.open("tallies.csv", "r");
|
||||||
|
let line;
|
||||||
|
while ((line = f.readLine()) !== undefined) {
|
||||||
|
const parts = line.replace("\n", "").split(",");
|
||||||
|
tallies.push({ date: new Date(parts[0]), name: parts[1] });
|
||||||
|
}
|
||||||
|
return tallies;
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveTallies(tallies: Tally[]) {
|
||||||
|
const f = storage.open("tallies.csv", "w");
|
||||||
|
for(const tally of tallies){
|
||||||
|
f.write([tally.date.toISOString(), tally.name].join(",") + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dayEq = (a: Date, b: Date) =>
|
||||||
|
a.getFullYear() === b.getFullYear()
|
||||||
|
&& a.getMonth() === b.getMonth()
|
||||||
|
&& a.getDate() === b.getDate();
|
||||||
|
|
||||||
|
function showTallies(tallies: Tally[]) {
|
||||||
|
const menu: Menu = {
|
||||||
|
"": { title: "Tallies" },
|
||||||
|
"< Back": () => load(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const today = new Date;
|
||||||
|
let day: undefined | Date;
|
||||||
|
|
||||||
|
tallies.forEach((tally, i) => {
|
||||||
|
const td = tally.date;
|
||||||
|
if(!dayEq(day ?? today, td)){
|
||||||
|
const s = `${td.getFullYear()}-${pad2(td.getMonth() + 1)}-${pad2(td.getDate())}`;
|
||||||
|
menu[s] = () => {};
|
||||||
|
day = td;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu[`${tfmt(tally)}: ${tally.name}`] = () => editTally(tallies, i);
|
||||||
|
});
|
||||||
|
|
||||||
|
E.showMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
function editTally(tallies: Tally[], i: number) {
|
||||||
|
const tally = tallies[i]!;
|
||||||
|
|
||||||
|
const onback = () => {
|
||||||
|
saveTallies(tallies);
|
||||||
|
E.removeListener("kill", onback);
|
||||||
|
};
|
||||||
|
E.on("kill", onback);
|
||||||
|
|
||||||
|
const menu: Menu = {
|
||||||
|
"": { title: `Edit ${tally.name}` },
|
||||||
|
"< Back": () => {
|
||||||
|
onback();
|
||||||
|
showTallies(tallies)
|
||||||
|
},
|
||||||
|
"Name": {
|
||||||
|
value: tally.name,
|
||||||
|
onchange: () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
require("textinput")
|
||||||
|
.input({ text: tally.name })
|
||||||
|
.then(text => {
|
||||||
|
if (text) {
|
||||||
|
tally.name = text;
|
||||||
|
}
|
||||||
|
editTally(tallies, i);
|
||||||
|
});
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Time": {
|
||||||
|
value: tally.date.getTime(),
|
||||||
|
format: (_tm: number) => tfmt(tally),
|
||||||
|
onchange: (v: number) => {
|
||||||
|
tally.date = new Date(v);
|
||||||
|
},
|
||||||
|
step: 60000, // 1 min
|
||||||
|
},
|
||||||
|
"Delete": () => {
|
||||||
|
E.showPrompt(`Delete "${tally.name}"?`, {
|
||||||
|
title: "Delete",
|
||||||
|
buttons: { Yes: true, No: false },
|
||||||
|
}).then(confirm => {
|
||||||
|
if (confirm) {
|
||||||
|
tallies.splice(i, 1);
|
||||||
|
saveTallies(tallies);
|
||||||
|
showTallies(tallies);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// need to regrab ui, can't `m.draw()`
|
||||||
|
editTally(tallies, i);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
E.showMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tfmt(tally: Tally) {
|
||||||
|
const d = tally.date;
|
||||||
|
return `${d.getHours()}:${pad2(d.getMinutes())}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pad2 = (s: number) => ("0" + s.toFixed(0)).slice(-2);
|
||||||
|
|
||||||
|
showTallies(readTallies());
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
(function () {
|
||||||
|
var storage = require("Storage");
|
||||||
|
var tallyEntries = storage.readJSON("tallycfg.json", 1) || [];
|
||||||
|
var img = atob("GBiBAAAAAAAAAAAAAB//+D///DAADDAADDAYDDAYDDAZjDAZjDGZjDGZjDGZjDGZjDAADDAADD///B//+APAAAMAAAIAAAAAAAAAAA==");
|
||||||
|
return {
|
||||||
|
name: "Tally",
|
||||||
|
img: img,
|
||||||
|
items: tallyEntries.map(function (ent) { return ({
|
||||||
|
name: ent.name,
|
||||||
|
img: img,
|
||||||
|
get: function () {
|
||||||
|
return { text: this.name, img: img };
|
||||||
|
},
|
||||||
|
run: function () {
|
||||||
|
var f = storage.open("tallies.csv", "a");
|
||||||
|
f.write([
|
||||||
|
new Date().toISOString(),
|
||||||
|
this.name,
|
||||||
|
].join(",") + "\n");
|
||||||
|
},
|
||||||
|
show: function () { },
|
||||||
|
hide: function () { },
|
||||||
|
}); }),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
(function() {
|
||||||
|
const storage = require("Storage");
|
||||||
|
const tallyEntries = storage.readJSON("tallycfg.json", 1) as TallySettings || [];
|
||||||
|
|
||||||
|
// transparent
|
||||||
|
const img = atob("GBiBAAAAAAAAAAAAAB//+D///DAADDAADDAYDDAYDDAZjDAZjDGZjDGZjDGZjDGZjDAADDAADD///B//+APAAAMAAAIAAAAAAAAAAA==")
|
||||||
|
// non-transparent
|
||||||
|
//const img = atob("GBgBAAAAAAAAAAAAH//4P//8MAAMMAAMMBgMMBgMMBmMMBmMMZmMMZmMMZmMMZmMMAAMMAAMP//8H//4A4AAAwAAAgAAAAAAAAAA")
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "Tally",
|
||||||
|
img,
|
||||||
|
items: tallyEntries.map(ent => ({
|
||||||
|
name: ent.name,
|
||||||
|
img,
|
||||||
|
get: function() {
|
||||||
|
return { text: this.name, img };
|
||||||
|
},
|
||||||
|
run: function() {
|
||||||
|
const f = storage.open("tallies.csv", "a");
|
||||||
|
f.write([
|
||||||
|
new Date().toISOString(),
|
||||||
|
this.name,
|
||||||
|
].join(",") + "\n");
|
||||||
|
},
|
||||||
|
show: function(){},
|
||||||
|
hide: function(){},
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}) satisfies ClockInfoFunc
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 760 B |
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"id": "tally",
|
||||||
|
"name": "Tally Keeper",
|
||||||
|
"shortName": "Tally",
|
||||||
|
"version": "0.01",
|
||||||
|
"description": "Add to a tally from clock info",
|
||||||
|
"icon": "app.png",
|
||||||
|
"tags": "clkinfo",
|
||||||
|
"supports": ["BANGLEJS2"],
|
||||||
|
"readme": "README.md",
|
||||||
|
"storage": [
|
||||||
|
{ "name": "tally.settings.js", "url": "settings.js" },
|
||||||
|
{ "name": "tally.img", "url": "app-icon.js", "evaluate": true },
|
||||||
|
{ "name": "tally.clkinfo.js", "url": "clkinfo.js" },
|
||||||
|
{ "name": "tally.app.js", "url": "app.js" }
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
{ "name": "tallycfg.json" },
|
||||||
|
{ "name": "tallies.csv" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
(function (back) {
|
||||||
|
var storage = require("Storage");
|
||||||
|
var SETTINGS_FILE = "tallycfg.json";
|
||||||
|
var tallycfg = storage.readJSON(SETTINGS_FILE, 1) || [];
|
||||||
|
function saveSettings() {
|
||||||
|
storage.writeJSON(SETTINGS_FILE, tallycfg);
|
||||||
|
}
|
||||||
|
function showMainMenu() {
|
||||||
|
var menu = {
|
||||||
|
"": { "title": "Tally Configs" },
|
||||||
|
"< Back": back,
|
||||||
|
"Add New": function () { return showEditMenu(); },
|
||||||
|
};
|
||||||
|
tallycfg.forEach(function (tally, index) {
|
||||||
|
menu[tally.name] = function () { return showEditMenu(tally, index); };
|
||||||
|
});
|
||||||
|
E.showMenu(menu);
|
||||||
|
}
|
||||||
|
function showEditMenu(tally, index) {
|
||||||
|
var isNew = tally == null;
|
||||||
|
if (tally == null) {
|
||||||
|
tally = { name: "" };
|
||||||
|
index = tallycfg.length;
|
||||||
|
tallycfg.push(tally);
|
||||||
|
}
|
||||||
|
var menu = {
|
||||||
|
"": { "title": isNew ? "New Tally" : "Edit Tally" },
|
||||||
|
"< Back": function () {
|
||||||
|
saveSettings();
|
||||||
|
showMainMenu();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
menu[tally.name || "<set name>"] = function () {
|
||||||
|
require("textinput")
|
||||||
|
.input({ text: tally.name })
|
||||||
|
.then(function (text) {
|
||||||
|
tally.name = text;
|
||||||
|
showEditMenu(tally, index);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (!isNew) {
|
||||||
|
menu["Delete"] = function () {
|
||||||
|
tallycfg.splice(index, 1);
|
||||||
|
saveSettings();
|
||||||
|
showMainMenu();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
E.showMenu(menu);
|
||||||
|
}
|
||||||
|
showMainMenu();
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
type TallySettings = TallySetting[];
|
||||||
|
type TallySetting = { name: string };
|
||||||
|
|
||||||
|
(function(back) {
|
||||||
|
const storage = require("Storage");
|
||||||
|
const SETTINGS_FILE = "tallycfg.json";
|
||||||
|
|
||||||
|
const tallycfg = storage.readJSON(SETTINGS_FILE, 1) as TallySettings || [];
|
||||||
|
|
||||||
|
function saveSettings() {
|
||||||
|
storage.writeJSON(SETTINGS_FILE, tallycfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMainMenu() {
|
||||||
|
const menu: Menu = {
|
||||||
|
"": { "title": "Tally Configs" },
|
||||||
|
"< Back": back,
|
||||||
|
"Add New": () => showEditMenu(),
|
||||||
|
};
|
||||||
|
|
||||||
|
tallycfg.forEach((tally, index) => {
|
||||||
|
menu[tally.name] = () => showEditMenu(tally, index);
|
||||||
|
});
|
||||||
|
|
||||||
|
E.showMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showEditMenu(tally?: TallySetting, index?: number) {
|
||||||
|
const isNew = tally == null;
|
||||||
|
if (tally == null) {
|
||||||
|
tally = { name: "" };
|
||||||
|
index = tallycfg.length;
|
||||||
|
tallycfg.push(tally);
|
||||||
|
}
|
||||||
|
|
||||||
|
const menu: Menu = {
|
||||||
|
"": { "title": isNew ? "New Tally" : "Edit Tally" },
|
||||||
|
"< Back": () => {
|
||||||
|
saveSettings();
|
||||||
|
showMainMenu();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
menu[tally.name || "<set name>"] = () => {
|
||||||
|
require("textinput")
|
||||||
|
.input({ text: tally.name })
|
||||||
|
.then(text => {
|
||||||
|
tally.name = text;
|
||||||
|
|
||||||
|
showEditMenu(tally, index);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!isNew) {
|
||||||
|
menu["Delete"] = () => {
|
||||||
|
tallycfg.splice(index!, 1);
|
||||||
|
saveSettings();
|
||||||
|
showMainMenu();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
E.showMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
showMainMenu();
|
||||||
|
}) satisfies SettingsFunc;
|
||||||
|
|
@ -8,3 +8,4 @@ declare function require(moduleName: "Layout"): typeof Layout.Layout;
|
||||||
declare function require(moduleName: "power_usage"): PowerUsageModule;
|
declare function require(moduleName: "power_usage"): PowerUsageModule;
|
||||||
declare function require(moduleName: "exstats"): typeof ExStats;
|
declare function require(moduleName: "exstats"): typeof ExStats;
|
||||||
declare function require(moduleName: "time_utils"): typeof TimeUtils;
|
declare function require(moduleName: "time_utils"): typeof TimeUtils;
|
||||||
|
declare function require(moduleName: "textinput"): typeof TextInput;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
declare module TextInput {
|
||||||
|
function input(options: { text: string }): Promise<string>;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue