Personal presentation timer

This commit is contained in:
Ian Gulliver
2020-06-27 21:48:27 +00:00
parent 3a015ecfd8
commit 31509efd16
4 changed files with 78 additions and 2 deletions

View File

@@ -65,6 +65,7 @@ type client struct {
Name string `json:"name"` Name string `json:"name"`
Admin bool `json:"admin"` Admin bool `json:"admin"`
Active bool `json:"active"` Active bool `json:"active"`
ActiveStart int64 `json:"active_start"`
clientId string clientId string
room *room room *room
@@ -84,6 +85,7 @@ type adminEvent struct {
type standardEvent struct { type standardEvent struct {
Active bool `json:"active"` Active bool `json:"active"`
ActiveStart int64 `json:"active_start"`
TimerStart int64 `json:"timer_start"` TimerStart int64 `json:"timer_start"`
AdminSecret string `json:"admin_secret"` AdminSecret string `json:"admin_secret"`
} }
@@ -223,6 +225,11 @@ func active(w http.ResponseWriter, r *http.Request) {
} }
c.Active = req.Active c.Active = req.Active
if c.Active {
c.ActiveStart = time.Now().Unix()
} else {
c.ActiveStart = 0
}
c.update() c.update()
rm.sendAdminEvent(&adminEvent{ rm.sendAdminEvent(&adminEvent{
Client: c, Client: c,
@@ -467,6 +474,7 @@ func (c *client) update() {
e := &event{ e := &event{
StandardEvent: &standardEvent{ StandardEvent: &standardEvent{
Active: c.Active, Active: c.Active,
ActiveStart: c.ActiveStart,
TimerStart: c.room.timerStart.Unix(), TimerStart: c.room.timerStart.Unix(),
}, },
} }

View File

@@ -79,9 +79,13 @@ tfoot tr {
} }
.action { .action {
color: var(--highlight-color);
cursor: pointer; cursor: pointer;
margin-left: 10px; margin-left: 10px;
color: var(--highlight-color); }
.users tbody tr td:nth-child(2) {
text-align: right;
} }
.github { .github {

View File

@@ -104,18 +104,22 @@ function renderControls(roomId, clientId, adminSecret, prnt, es) {
} }
function renderTimers(roomId, adminSecret, prnt, es) { function renderTimers(roomId, adminSecret, prnt, es) {
let overallStart = null; let overallStart = null;
let meStart = null;
es.addEventListener("message", (e) => { es.addEventListener("message", (e) => {
const event = JSON.parse(e.data); const event = JSON.parse(e.data);
if (!event.standard_event) { if (!event.standard_event) {
return; return;
} }
overallStart = parseInt(event.standard_event.timer_start || "0", 10) || null; overallStart = parseInt(event.standard_event.timer_start || "0", 10) || null;
meStart = parseInt(event.standard_event.active_start || "0", 10) || null;
}); });
const width = 10; const width = 10;
const clockDiv = create(prnt, "div", "Clock: ".padStart(width, "\u00a0")); const clockDiv = create(prnt, "div", "Clock: ".padStart(width, "\u00a0"));
const clock = create(clockDiv, "span"); const clock = create(clockDiv, "span");
const overallDiv = create(prnt, "div", "Overall: ".padStart(width, "\u00a0")); const overallDiv = create(prnt, "div", "Overall: ".padStart(width, "\u00a0"));
const overall = create(overallDiv, "span"); const overall = create(overallDiv, "span");
const meDiv = create(prnt, "div", "Me: ".padStart(width, "\u00a0"));
const me = create(meDiv, "span");
if (adminSecret) { if (adminSecret) {
const reset = create(overallDiv, "span", "↺", ["action"]); const reset = create(overallDiv, "span", "↺", ["action"]);
reset.addEventListener("click", () => { reset.addEventListener("click", () => {
@@ -142,6 +146,13 @@ function renderTimers(roomId, adminSecret, prnt, es) {
else { else {
overall.innerText = ""; overall.innerText = "";
} }
if (meStart) {
const d = Math.trunc(now.getTime() / 1000 - meStart);
me.innerText = `${Math.trunc(d / 3600).toString().padStart(2, "0")}h${Math.trunc(d % 3600 / 60).toString().padStart(2, "0")}m${Math.trunc(d % 60).toString().padStart(2, "0")}s`;
}
else {
me.innerText = "";
}
}, 250); }, 250);
} }
function renderAdmin(roomId, adminSecret, prnt, es) { function renderAdmin(roomId, adminSecret, prnt, es) {
@@ -149,10 +160,15 @@ function renderAdmin(roomId, adminSecret, prnt, es) {
const head = create(table, "thead"); const head = create(table, "thead");
const head1 = create(head, "tr"); const head1 = create(head, "tr");
create(head1, "th", "Name"); create(head1, "th", "Name");
create(head1, "th", "Active Time");
create(head1, "th", "👑"); create(head1, "th", "👑");
create(head1, "th", "👆"); create(head1, "th", "👆");
const body = create(table, "tbody"); const body = create(table, "tbody");
const rows = new Map(); const rows = new Map();
es.addEventListener("open", () => {
rows.clear();
body.innerHTML = "";
});
es.addEventListener("message", (e) => { es.addEventListener("message", (e) => {
const event = JSON.parse(e.data); const event = JSON.parse(e.data);
if (!event.admin_event) { if (!event.admin_event) {
@@ -169,6 +185,7 @@ function renderAdmin(roomId, adminSecret, prnt, es) {
} }
row = document.createElement("tr"); row = document.createElement("tr");
row.dataset.name = client.name; row.dataset.name = client.name;
row.dataset.activeStart = client.active_start;
let before = null; let before = null;
for (const iter of body.children) { for (const iter of body.children) {
const iterRow = iter; const iterRow = iter;
@@ -179,6 +196,7 @@ function renderAdmin(roomId, adminSecret, prnt, es) {
} }
body.insertBefore(row, before); body.insertBefore(row, before);
create(row, "td", client.name); create(row, "td", client.name);
create(row, "td");
const adminCell = create(row, "td", "👑", client.admin ? ["admin", "enable"] : ["admin"]); const adminCell = create(row, "td", "👑", client.admin ? ["admin", "enable"] : ["admin"]);
adminCell.addEventListener("click", () => { adminCell.addEventListener("click", () => {
if (!client.admin) { if (!client.admin) {
@@ -194,6 +212,17 @@ function renderAdmin(roomId, adminSecret, prnt, es) {
}); });
rows.set(client.public_client_id, row); rows.set(client.public_client_id, row);
}); });
setInterval(() => {
const now = new Date();
for (const row of rows.values()) {
const cell = row.children[1];
const as = parseInt(row.dataset.activeStart || "0", 10) || null;
if (as) {
const d = Math.trunc(now.getTime() / 1000 - as);
cell.innerText = `${Math.trunc(d / 3600).toString().padStart(2, "0")}h${Math.trunc(d % 3600 / 60).toString().padStart(2, "0")}m${Math.trunc(d % 60).toString().padStart(2, "0")}s`;
}
}
}, 250);
} }
function active(roomId, adminSecret, publicClientId, val) { function active(roomId, adminSecret, publicClientId, val) {
const req = { const req = {

View File

@@ -47,6 +47,7 @@ interface Event {
interface StandardEvent { interface StandardEvent {
timer_start?: string; timer_start?: string;
active?: boolean; active?: boolean;
active_start?: string;
admin_secret?: string; admin_secret?: string;
} }
@@ -60,6 +61,7 @@ interface Client {
name: string; name: string;
admin: boolean; admin: boolean;
active: boolean; active: boolean;
active_start: string;
} }
function main() { function main() {
@@ -191,7 +193,8 @@ function renderControls(roomId: string, clientId: string, adminSecret: string |
} }
function renderTimers(roomId: string, adminSecret: string | null, prnt: HTMLElement, es: EventSource) { function renderTimers(roomId: string, adminSecret: string | null, prnt: HTMLElement, es: EventSource) {
let overallStart: number | null = null; let overallStart: number | null = null;
let meStart: number | null = null;
es.addEventListener("message", (e) => { es.addEventListener("message", (e) => {
const event = JSON.parse(e.data) as Event; const event = JSON.parse(e.data) as Event;
@@ -201,6 +204,7 @@ function renderTimers(roomId: string, adminSecret: string | null, prnt: HTMLElem
} }
overallStart = parseInt(event.standard_event.timer_start || "0", 10) || null; overallStart = parseInt(event.standard_event.timer_start || "0", 10) || null;
meStart = parseInt(event.standard_event.active_start || "0", 10) || null;
}); });
const width = 10; const width = 10;
@@ -211,6 +215,9 @@ function renderTimers(roomId: string, adminSecret: string | null, prnt: HTMLElem
const overallDiv = create(prnt, "div", "Overall: ".padStart(width, "\u00a0")); const overallDiv = create(prnt, "div", "Overall: ".padStart(width, "\u00a0"));
const overall = create(overallDiv, "span"); const overall = create(overallDiv, "span");
const meDiv = create(prnt, "div", "Me: ".padStart(width, "\u00a0"));
const me = create(meDiv, "span");
if (adminSecret) { if (adminSecret) {
const reset = create(overallDiv, "span", "↺", ["action"]); const reset = create(overallDiv, "span", "↺", ["action"]);
reset.addEventListener("click", () => { reset.addEventListener("click", () => {
@@ -239,6 +246,13 @@ function renderTimers(roomId: string, adminSecret: string | null, prnt: HTMLElem
} else { } else {
overall.innerText = ""; overall.innerText = "";
} }
if (meStart) {
const d = Math.trunc(now.getTime() / 1000 - meStart);
me.innerText = `${Math.trunc(d / 3600).toString().padStart(2, "0")}h${Math.trunc(d % 3600 / 60).toString().padStart(2, "0")}m${Math.trunc(d % 60).toString().padStart(2, "0")}s`;
} else {
me.innerText = "";
}
}, 250); }, 250);
} }
@@ -247,6 +261,7 @@ function renderAdmin(roomId: string, adminSecret: string, prnt: HTMLElement, es:
const head = create(table, "thead"); const head = create(table, "thead");
const head1 = create(head, "tr"); const head1 = create(head, "tr");
create(head1, "th", "Name"); create(head1, "th", "Name");
create(head1, "th", "Active Time");
create(head1, "th", "👑"); create(head1, "th", "👑");
create(head1, "th", "👆"); create(head1, "th", "👆");
@@ -254,6 +269,11 @@ function renderAdmin(roomId: string, adminSecret: string, prnt: HTMLElement, es:
const rows: Map<string, HTMLTableRowElement> = new Map(); const rows: Map<string, HTMLTableRowElement> = new Map();
es.addEventListener("open", () => {
rows.clear();
body.innerHTML = "";
});
es.addEventListener("message", (e) => { es.addEventListener("message", (e) => {
const event = JSON.parse(e.data) as Event; const event = JSON.parse(e.data) as Event;
@@ -275,6 +295,7 @@ function renderAdmin(roomId: string, adminSecret: string, prnt: HTMLElement, es:
row = document.createElement("tr") as HTMLTableRowElement; row = document.createElement("tr") as HTMLTableRowElement;
row.dataset.name = client.name; row.dataset.name = client.name;
row.dataset.activeStart = client.active_start;
let before = null; let before = null;
for (const iter of body.children) { for (const iter of body.children) {
@@ -287,6 +308,7 @@ function renderAdmin(roomId: string, adminSecret: string, prnt: HTMLElement, es:
body.insertBefore(row, before); body.insertBefore(row, before);
create(row, "td", client.name); create(row, "td", client.name);
create(row, "td");
const adminCell = create(row, "td", "👑", client.admin ? ["admin", "enable"] : ["admin"]) as HTMLTableCellElement; const adminCell = create(row, "td", "👑", client.admin ? ["admin", "enable"] : ["admin"]) as HTMLTableCellElement;
adminCell.addEventListener("click", () => { adminCell.addEventListener("click", () => {
@@ -305,6 +327,19 @@ function renderAdmin(roomId: string, adminSecret: string, prnt: HTMLElement, es:
rows.set(client.public_client_id, row); rows.set(client.public_client_id, row);
}); });
setInterval(() => {
const now = new Date();
for (const row of rows.values()) {
const cell = row.children[1] as HTMLTableCellElement;
const as = parseInt(row.dataset.activeStart || "0", 10) || null;
if (as) {
const d = Math.trunc(now.getTime() / 1000 - as);
cell.innerText = `${Math.trunc(d / 3600).toString().padStart(2, "0")}h${Math.trunc(d % 3600 / 60).toString().padStart(2, "0")}m${Math.trunc(d % 60).toString().padStart(2, "0")}s`;
}
}
}, 250);
} }
function active(roomId: string, adminSecret: string, publicClientId: string, val: boolean) { function active(roomId: string, adminSecret: string, publicClientId: string, val: boolean) {