added timer-complete display

This commit is contained in:
Zlatko Đurić 2025-04-13 21:17:17 +02:00
parent 061637c481
commit 30e4a4a62a
12 changed files with 230 additions and 9 deletions

View File

@ -5,6 +5,23 @@
"time-remaining": "Verbliebend",
"resume": "Fortsetzen",
"pause": "Anhalten",
"delete": "Löschen"
"delete": "Löschen",
"resume-runner": "Timer fortsetzen",
"pause-runner": "Timer anhalten",
"status": {
"timers-are": "Timers sind",
"timers-paused": "pausiert",
"timers-active": "aktiv",
"add-timer": "Timer hinzufügen"
},
"timer": {
"complete": "Timer fertig",
"your-timer-is-complete": "Dein Timer \"{name}\" ist ausgelaufen"
},
"add-timer": {
"timer name": "Timer Name",
"duration": "Dauer",
"format-hint": "Nutze den Format n (nur Sekunden), mm:ss oder hh:mm:ss für Stunden/Minuten/Sekunden.hours/minutes/seconds."
}
}
}

View File

@ -5,6 +5,23 @@
"time-remaining": "Time remaining",
"resume": "Resume",
"pause": "Pause",
"delete": "Delete"
"delete": "Delete",
"resume-runner": "Resume timer",
"pause-runner": "Pause timer",
"status": {
"timers-are": "Timers are",
"timers-paused": "paused",
"timers-active": "active",
"add-timer": "Add timer"
},
"timer": {
"complete": "Timer complete",
"your-timer-is-complete": "Your timer \"{name}\" is complete"
},
"add-timer": {
"timer name": "Timer name",
"duration": "Duration",
"format-hint": "Use format n (for seconds), mm:ss or hh:mm:ss for hours/minutes/seconds."
}
}
}

View File

@ -5,6 +5,23 @@
"time-remaining": "Preostalo vrijeme",
"resume": "Nastavi",
"pause": "Zaustavi",
"delete": "Obriši"
"delete": "Obriši",
"resume-runner": "Nastavi timer",
"pause-runner": "Zaustavi timer",
"status": {
"timers-are": "Brojači su",
"timers-paused": "zaustavljeni",
"timers-active": "aktivni",
"add-timer": "Dodaj timer"
},
"timer": {
"complete": "Timer gotov",
"your-timer-is-complete": "Tvoj timer \"{name}\" je završen"
},
"add-timer": {
"timer name": "Ime timera",
"duration": "Trajanje",
"format-hint": "Koristi šprancu n za sekunde, mm:ss ili hh:mm:ss za sate/minute/sekunde."
}
}
}

38
src/add-timer-screen.js Normal file
View File

@ -0,0 +1,38 @@
import { logger } from './logger.js';
const templatePath = `modules/yet-another-timer/templates/add-timer.hbs`;
export class AddTimerScreen extends FormApplication {a
static get defaultOptions() {
const defaults = super.defaultOptions;
const overrides = {
height: "auto",
id: "yet-another-timer-add-timer",
template: templatePath,
title: game.i18n?.localize("YAT.status.add-timer") || "Add Timer",
};
return Object.assign({}, defaults, overrides);
}
getData() {
return {
};
}
activateListeners(html) {
logger.debug('Activating listeners...');
html.on('click', "[data-action]", this.#handleClick.bind(this));
logger.debug('Activated.');
}
#handleClick(event) {
logger.debug('**click**', event);
const el = $(event.currentTarget);
const action = el.data().action;
logger.debug('handle debug on ', action);
const data = $(el).parents('form');
logger.debug('Data:', data);
}
}

View File

@ -0,0 +1,27 @@
import { logger } from './logger.js';
const templatePath = `modules/yet-another-timer/templates/timer-complete.hbs`;
export class TimerCompleteScreen extends FormApplication {a
static get defaultOptions() {
const defaults = super.defaultOptions;
const overrides = {
height: "auto",
id: "yet-another-timer-add-timer",
template: templatePath,
title: game.i18n?.localize("YAT.timer.complete") || "Timer complete",
};
return Object.assign({}, defaults, overrides);
}
data = {};
setData(data) {
this.data = data;
}
getData() {
return this.data;
}
}

View File

@ -1,5 +1,7 @@
import { logger } from "./logger.js";
import { getTimers } from "./timer.repository.js";
import { getStatus, pauseTimer, resumeTimer, deleteTimer, flipTimers, subscribe } from './timer.loop.js';
import { TimerError } from "./error.js";
const templatePath = `modules/yet-another-timer/templates/timer.hbs`;
@ -39,13 +41,20 @@ export class TimerScreen extends FormApplication {
getData() {
return {
timers: getTimers(),
config: {
isPaused: getStatus()
}
};
}
activateListeners(html) {
logger.debug('Activating listeners...');
html.on('click', "[data-action]", this.#handleClick);
html.on('click', "[data-action]", this.#handleClick.bind(this));
logger.debug('Activated.');
// also make sure we're always active
subscribe(() => {
this.render();
});
}
#handleClick(event) {
@ -55,6 +64,28 @@ export class TimerScreen extends FormApplication {
const timerName = el.parents('[data-timer-name]')?.data()?.timerName;
console.log(el);
logger.debug('timerName and action', timerName, action);
switch(action) {
case 'flip-timers':
flipTimers();
break;
case 'pause':
pauseTimer(timerName);
break;
case 'resume':
resumeTimer(timerName);
break;
case 'delete':
deleteTimer(timerName);
break;
case 'add-timer':
showAddAction()
break;
default:
logger.error(`Unknown timer action: ${action}`);
throw new TimerError(`Unknown timer action: ${action}`);
}
this.render();
}
}

View File

@ -1,7 +1,7 @@
import { logger } from './logger.js';
import { startTimers, stopTimers, resumeTimer } from './timer.loop.js';
import { createTimer } from './timer.repository.js';
import { TimerScreen } from "./render.js";
import { TimerScreen } from "./timer-screen.js";
let isPaused = true;

View File

@ -1,14 +1,28 @@
import { logger } from "./logger.js";
import { TimerError } from "./error.js";
import { getActiveTimers, getTimer } from "./timer.repository.js";
import { logTimer } from "./render.js";
import { getActiveTimers, getTimer, deleteTimer as repoDeleteTimer } from "./timer.repository.js";
import { logTimer } from "./timer-screen.js";
import { TimerCompleteScreen } from "./timer-complete-screen.js";
const INTERVAL_MS = 1000; // main loop interval
const state = {
timerInterval: null,
subscribers: [],
};
export function getStatus() {
return state.timerInterval === null;
}
export function flipTimers() {
if (getStatus()) {
startTimers();
} else {
stopTimers();
}
}
export function startTimers() {
if (state.timerInterval !== null) {
throw new TimerError('Loop already running');
@ -16,6 +30,11 @@ export function startTimers() {
logger.debug(`Starting main timer loop`);
state.timerInterval = setInterval(() => runLoop(), INTERVAL_MS);
ping();
}
export function subscribe(cb) {
state.subscribers.push(cb);
}
export function stopTimers() {
@ -23,10 +42,10 @@ export function stopTimers() {
throw new TimerError('Loop not running.');
}
logger.debug('Stopping main timer loop.');
clearInterval(state.timerInterval);
state.timerInterval = null;
logger.debug('Stopping main timer loop.');
ping();
}
export function pauseTimer(timerName = '') {
@ -36,6 +55,7 @@ export function pauseTimer(timerName = '') {
} else {
logger.info(`Pausing timer ${timerName}.`);
timer.isPaused = true;
ping();
}
}
@ -46,9 +66,14 @@ export function resumeTimer(timerName = '') {
} else {
logger.info(`Resuming timer ${timerName}.`);
timer.isPaused = false;
ping();
}
}
export function deleteTimer(timerName) {
repoDeleteTimer(timerName);
}
function runLoop() {
logger.debug(`Running loop...`);
const timers = getActiveTimers();
@ -58,6 +83,15 @@ function runLoop() {
advance(timer, INTERVAL_MS);
logTimer(timer);
}
if (timers.length > 0) {
ping();
}
}
function ping() {
for (const sub of state.subscribers) {
sub();
}
}
function advance(timer, interval_ms) {
@ -76,4 +110,8 @@ function advance(timer, interval_ms) {
function completeTimer(timer) {
logger.log(`Timer ${timer.name} completed.`);
timer.isPaused = true;
// ping? close something?
const timerComplete = new TimerCompleteScreen();
timerComplete.setData({ name: timer.name });
timerComplete.render(true);
}

View File

@ -49,6 +49,14 @@ export function getTimer(timerName = '') {
return timerMap.get(timerName);
}
export function deleteTimer(timerName = '') {
if (timerMap.has(timerName)) {
timerMap.delete(timerName);
} else {
throw new TimerError(`Trying to delete non-existent timer ${timerName}.`);
}
}
/**
* Create a new timer.
* @param {TimeString} [durationString='01:00'] - the timer duration

10
templates/add-timer.hbs Normal file
View File

@ -0,0 +1,10 @@
<h3>{{ localize "YAT.status.add-timer" }}</h3>
<form>
<label>{{ localize "YAT.add-timer.timer name" }} <input name="timer-name"></label>
<label>{{ localize "YAT.add-timer.duration" }} <input name="timer-duration"></label>
<span class="hint">{{ localize "YAT.add-timer.format-hint" }}</span>
<label>{{ localize "YAT.start-now" }} <input type="checkbox" name="timer-start-now"></label>
<button class="button" data-action="add-timer">{{ localize "YAT.status.add-timer" }}</button>
</form>

View File

@ -0,0 +1 @@
<h2>{{ localize "YAT.timer.your-timer-is-complete" name=name }}!</h2>

View File

@ -1,5 +1,22 @@
<h2>{{localize "YAT.title" }}</h2> <!-- TODO: how to localize -->
<section id="yet-another-timer-config">
<p>{{ localize "YAT.status.timers-are" }} {{#if config.isPaused }}{{ localize "YAT.status.timers-paused" }}{{else}}{{ localize "YAT.status.timers-active"}}{{/if}}.</p>
<button class="button pause-button" data-action="flip-timers">
{{#if config.isPaused}}
{{ localize "YAT.resume-runner" }}
{{else}}
{{ localize "YAT.pause-runner" }}
{{/if}}
</button>
<button class="button resume-button" data-action="add-timer">
{{ localize "YAT.add-timer" }}
</button>
</section>
<hr>
<section id="yet-another-timer timers">
{{#each timers }}
<section class="timer-card {{#if isPaused}}{{ localize "YAT.paused" }}{{/if}}" data-timer-name="{{name}}">