1
0
Fork 0

rep: more layout/design tweaks

master
Rob Pilling 2023-05-21 15:13:18 +01:00
parent a783ee6435
commit ef26eae665
1 changed files with 194 additions and 121 deletions

View File

@ -18,59 +18,44 @@ const reps: Rep[] = [
// 3 min static recovery
// 1 X 4 mins to finish
{dur:1/60, label:"1st-sec"},
{dur:3/60, label:"1st-sec"},
{dur:5/60, label:"5-sec"},
{dur:4, label:"jog"},
{dur:4, label:"recovery"},
// {dur:4, label:"jog"},
// {dur:4, label:"recovery"},
{dur:2, label:"jog"},
{dur:2, label:"recovery"},
{dur:2, label:"jog"},
{dur:2, label:"recovery"},
// {dur:2, label:"jog"},
// {dur:2, label:"recovery"},
// {dur:2, label:"jog"},
// {dur:2, label:"recovery"},
{dur:1, label:"jog"},
{dur:1, label:"recovery"},
{dur:1, label:"jog"},
{dur:1, label:"recovery"},
{dur:1, label:"jog"},
{dur:1, label:"recovery"},
{dur:1, label:"jog"},
{dur:1, label:"recovery"},
// {dur:1, label:"jog"},
// {dur:1, label:"recovery"},
// {dur:1, label:"jog"},
// {dur:1, label:"recovery"},
// {dur:1, label:"jog"},
// {dur:1, label:"recovery"},
// {dur:1, label:"jog"},
// {dur:1, label:"recovery"},
{dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
{dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
{dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
{dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
{dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
{dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
{dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
{dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
// {dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
// {dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
// {dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
// {dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
// {dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
// {dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
// {dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
// {dur:0.5, label:"jog"}, {dur:0.5, label:"recovery"},
{dur:3, label:"static recovery"},
{dur:4, label:"finish"},
// {dur:3, label:"static recovery"},
// {dur:4, label:"finish"},
];
const fontSzMain = 64;
const fontSzRep = 20;
const fontSzRepDesc = 12;
// FIXME: `Layout_` name
const repLayout = (id: string): (Layout_.Hierarchy & {type:"txt"})[] => [
{
id: `${id}_name`,
type: "txt",
font: `Vector:${fontSzRep}`,
label: "Name PH",
//pad: 4,
fillx: 1,
}, {
id: `${id}_dur`,
type: "txt",
font: `Vector:${fontSzRep}`,
label: "DURATION",
halign: Layout_.Align.Right,
}
];
// FIXME: `Layout_` name, e.g. Layout_.Align.Right
// top: show current rep: name & duration
// middle: show time left on current rep
@ -80,53 +65,159 @@ const layout = new Layout({
type: "v",
c: [
{
id: "cur_time",
type: "txt",
id: "duration",
lazyBuster: 1,
type: "custom",
font: `Vector:${fontSzMain}` as FontNameWithScaleFactor, // modified in draw
label: "MM:SS", // TODO: empty strings
fillx: 1,
filly: 1,
render: (l: Layout_.RenderedHierarchy) => {
let lbl;
g.clearRect(l.x, l.y, l.x+l.w, l.y+l.h);
if(state){
const elapsed = getElapsed(state);
const i = currentRepIndex(elapsed);
if(i == null){
// FIXME: dodgy end-of-rep handling
lbl = msToHM(elapsed);
}else{
const thisDur = repDuration(reps[i]!);
const remaining = thisDur - elapsed;
lbl = msToHM(remaining);
const fract = elapsed / thisDur;
g.setColor("#00f")
.fillRect(
l.x,
l.y,
l.x + fract * l.w,
l.y+l.h
);
}
}else{
lbl = "RDY";
}
g.setColor(l.col || g.theme.fg)
.setFont(l.font!)
.setFontAlign(0, 0)
.drawString(
lbl,
l.x+(l.w>>1),
l.y+(l.h>>1)
);
},
},
{
type: "txt",
font: `Vector:${fontSzRepDesc}`,
label: "Activity / Duration",
},
{
id: `cur_name`,
type: "txt",
font: `Vector:${fontSzRep}`,
label: "",
//pad: 4,
fillx: 1,
},
{
type: "txt",
font: `Vector:${fontSzRepDesc}`,
label: "Next / Duration",
},
{
id: `next_name`,
type: "txt",
font: `Vector:${fontSzRep}`,
label: "",
//pad: 4,
fillx: 1,
},
{
type: "h",
c: repLayout("cur"),
filly: 1,
c: [
{
id: "prev",
type: "btn",
label: "<",
fillx: 1,
cb: () => onPrev(),
},
{
type: "h",
c: repLayout("next"),
filly: 1,
},
{
type: "h",
c: [{
id: "play",
type: "btn",
label: "Play", // TODO: change
fillx: 1,
cb: () => {
console.log("cb()");
cb: () => onToggle(),
},
filly: 1,
}]
{
id: "next",
type: "btn",
label: ">",
fillx: 1,
cb: () => onNext(),
}
]
}
]
}, {lazy: true});
let index = 0;
let begin: number | undefined = Date.now(); // TODO: start null
let drawTimeout: number | undefined;
let paused = false;
let positioned = false;
const onToggle = () => {
if(!state){
state = {
begin: Date.now(),
accumulated: 0,
};
play(true, state);
}else{
play(paused, state);
}
const pad2 = (s: number) => ('0' + s.toFixed(0)).slice(-2);
drawRep();
};
const onPrev = () => {
};
const onNext = () => {
};
const play = (p: boolean, state: State) => {
if(p){
layout["play"]!.label = "Pause";
state.begin = Date.now();
drawInterval = setInterval(drawRep, 1000);
}else{
layout["play"]!.label = "Play";
const diff = Date.now() - state.begin;
state.accumulated += diff;
clearInterval(drawInterval!);
}
paused = !p;
}
type State = { begin: number, accumulated: number };
let state: State | undefined;
//let drawTimeout: number | undefined;
let paused = false; // TODO: ditch this, used drawInterval
let drawInterval: IntervalId | undefined;
const currentRepIndex = (elapsedMs: number) => {
let total = 0;
let ent;
for(let i = 0; ent = reps[i]; i++){
total += ent.dur * 60 * 1000;
if(elapsedMs < total)
total += repDuration(ent);
if(elapsedMs <= total)
return i;
}
return null;
@ -135,44 +226,38 @@ const currentRepIndex = (elapsedMs: number) => {
const repToLabel = (i: number, id: string) => {
const rep = reps[i];
if(rep){
layout[`${id}_name`]!.label = `${i+1}: ${rep.label}`;
layout[`${id}_name`]!.label = `${i+1}: ${rep.label} / ${rep.dur.toFixed(0)}m`;
// FIXME: display time, i.e. hh:mm
layout[`${id}_dur`]!.label = `${rep.dur.toFixed(0)}m`;
//layout[`${id}_dur`]!.label = ``;
}else{
emptyLabel(id);
}
};
const emptyLabel = (id: string) => {
layout[`${id}_name`]!.label = "<none>";
layout[`${id}_dur`]!.label = `0m`;
layout[`${id}_name`]!.label = "<none> / 0m";
};
const pad2 = (s: number) => ('0' + s.toFixed(0)).slice(-2);
const repDuration = (rep: Rep) => rep.dur * 60 * 1000;
const getElapsed = (state: State) =>
Date.now() - state.begin + state.accumulated;
const msToHM = (ms: number) => {
const sec = Math.round(ms / 1000);
const min = Math.round(sec / 60);
return min.toFixed(0) + ":" + pad2(sec % 60);
};
const drawRep = () => {
if(paused || !begin){ // TODO: separate case for paused
layout.clear();
layout["cur_time"]!.label = "Ready";
if(!positioned){
positioned = true;
layout.update(); // position
}
layout.render(layout["play"]);
layout.render(layout["cur_time"]);
return;
}
(layout["duration"] as any).lazyBuster ^= 1;
if(state){
// TODO: layout.clear(layout.next_name); layout.render(layout.next_name)
const now = Date.now();
const elapsed = now - begin;
const sec = Math.round(elapsed / 1000);
const min = Math.round(sec / 60);
const timeStr = min.toFixed(0) + ":" + pad2(sec % 60);
layout["cur_time"]!.label = timeStr;
const elapsed = getElapsed(state);
const i = currentRepIndex(elapsed);
if(i !== null){
repToLabel(i, "cur");
@ -181,36 +266,24 @@ const drawRep = () => {
emptyLabel("cur");
emptyLabel("next");
}
if(!positioned){
positioned = true;
layout.update(); // position
}
layout.render();
/*
g.reset()
.clearRect(Bangle.appRect)
.setFontAlign(0, 0)
.setFont("Vector", 55)
.drawString(timeStr, x, y)
.setFont("Vector", 33)
.drawString(current ? current.label + " for " + current.dur : "<done>", x, y+48);
// TODO: figure out next rep change time? or every 5s, then countdown from 10-->0
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
drawRep();
}, 1000 - (Date.now() % 1000));
*/
};
g.clear();
var drawInterval = setInterval(drawRep, 1000);
drawRep();
// TODO: swipe handlers
//Bangle.setUI
// TODO: widgets