import { sendToMain } from "../../renderer/sendToMain.js"; import { AbstractStateSubscriberWebComponent } from "../util/AbstractStateSubscriberWebComponent.js"; import { registerElement } from "../../renderer/registerElement.js"; import { registerShortcut, shortcutString } from "../../renderer/registerShortcut.js"; import type { IconWebComponent } from "../util/IconWebComponent.js"; import type { AeroflyFlightFormatterSunPosition } from "../../../core/formatter/AeroflyFlightFormatter.js"; export type TimeAndDateWebComponentState = { utcDate: string; // YYYY-MM-DD utcTime: string; // HH:mm }; export class TimeAndDateWebComponent extends AbstractStateSubscriberWebComponent { private isInitialized = false; private shortcut: (() => void) | undefined = undefined; private readonly shortcutKey = "n"; private elements!: { dateUtc: HTMLInputElement; timeUtc: HTMLInputElement; dateLocal: HTMLInputElement; timeLocal: HTMLInputElement; timeZoneLocal: HTMLElement; nowButton: HTMLButtonElement; sunPosition: IconWebComponent; }; private initialize() { this.setAttribute("aria-role", "region"); this.innerHTML = `\

 Time & date

# Date Time
UTC
Local (0)
`; this.elements = { dateUtc: this.querySelector("#date-utc") as HTMLInputElement, timeUtc: this.querySelector("#time-utc") as HTMLInputElement, dateLocal: this.querySelector("#date-local") as HTMLInputElement, timeLocal: this.querySelector("#time-local") as HTMLInputElement, timeZoneLocal: this.querySelector("#timezone-local") as HTMLElement, nowButton: this.querySelector("#synchronize-time") as HTMLButtonElement, sunPosition: this.querySelector("#sun-position") as IconWebComponent, }; } get state(): TimeAndDateWebComponentState { return { utcDate: this.elements.dateUtc.value, utcTime: this.elements.timeUtc.value, }; } get utcDate() { return new Date(this.elements.dateUtc.value + "T" + this.elements.timeUtc.value + "Z"); } connectedCallback() { if (!this.isInitialized) { this.initialize(); this.isInitialized = true; } [this.elements.dateUtc, this.elements.timeUtc].forEach((e) => e.addEventListener("input", this.setLocalFromUtc), ); [this.elements.dateLocal, this.elements.timeLocal].forEach((e) => e.addEventListener("input", this.setUtcFromLocal), ); this.elements.nowButton.addEventListener("click", this.setNow); this.subscribeToStateUpdates((state) => { this.elements.dateUtc.value = state.dateTime.utc.date; this.elements.timeUtc.value = state.dateTime.utc.time; this.elements.timeZoneLocal.dataset.value = state.dateTime.local.timeZoneOffset_h.toString(); this.elements.timeZoneLocal.textContent = (state.dateTime.local.timeZoneOffset_h >= 0 ? "+" : "") + state.dateTime.local.timeZoneOffset_h; this.elements.dateLocal.value = state.dateTime.local.date; this.elements.timeLocal.value = state.dateTime.local.time; // Sun Position this.elements.sunPosition.title = state.dateTime.local.sunPosition; this.elements.sunPosition.icon = this.convertSunPositionToIcon(state.dateTime.local.sunPosition); this.elements.sunPosition.classList.toggle("has-warning", state.dateTime.local.sunPosition === "Twilight"); this.elements.sunPosition.classList.toggle("has-info", state.dateTime.local.sunPosition === "Night"); this.checkWarning(); }); this.addEventListener("input", this.handleChange); this.shortcut = registerShortcut(this.shortcutKey, this.setNow); } convertSunPositionToIcon(sunPosition: AeroflyFlightFormatterSunPosition): string { switch (sunPosition) { case "Day": return "sun"; case "Twilight": return "sunset"; case "Night": return "moon"; } } disconnectedCallback(): void { super.disconnectedCallback(); [this.elements.dateUtc, this.elements.timeUtc].forEach((e) => e.removeEventListener("input", this.setLocalFromUtc), ); [this.elements.dateLocal, this.elements.timeLocal].forEach((e) => e.removeEventListener("input", this.setUtcFromLocal), ); this.elements.nowButton.removeEventListener("click", this.setNow); this.removeEventListener("input", this.handleChange); if (this.shortcut) { this.shortcut(); } } private checkWarning() { const now = new Date(); const hasWarning = this.utcDate > now; const warningClass = "input-warning"; this.elements.dateUtc.classList.toggle(warningClass, hasWarning); this.elements.timeUtc.classList.toggle(warningClass, hasWarning); this.elements.dateLocal.classList.toggle(warningClass, hasWarning); this.elements.timeLocal.classList.toggle(warningClass, hasWarning); } private handleChange = () => { this.checkWarning(); sendToMain("date-time:set", this.state); }; private setLocalFromUtc = () => { const d = this.utcDate; d.setUTCHours(d.getUTCHours() + Number(this.elements.timeZoneLocal.dataset.value ?? "0")); this.elements.timeLocal.value = this.pad(d.getUTCHours()) + ":" + this.pad(d.getUTCMinutes()); this.elements.dateLocal.value = d.getFullYear().toString() + "-" + this.pad(d.getUTCMonth() + 1) + "-" + this.pad(d.getUTCDate()); }; private setUtcFromLocal = () => { const d = new Date(this.elements.dateLocal.value + "T" + this.elements.timeLocal.value + "Z"); d.setUTCHours(d.getUTCHours() - Number(this.elements.timeZoneLocal.dataset.value ?? "0")); this.elements.timeUtc.value = this.pad(d.getUTCHours()) + ":" + this.pad(d.getUTCMinutes()); this.elements.dateUtc.value = d.getFullYear().toString() + "-" + this.pad(d.getUTCMonth() + 1) + "-" + this.pad(d.getUTCDate()); }; private setNow = () => { const now = new Date(); this.elements.dateUtc.value = now.getUTCFullYear().toString() + "-" + this.pad(now.getUTCMonth() + 1) + "-" + this.pad(now.getUTCDate()); this.elements.timeUtc.value = this.pad(now.getUTCHours()) + ":" + this.pad(now.getUTCMinutes()); this.setLocalFromUtc(); this.handleChange(); }; private pad(t: string | number) { return String(t).padStart(2, "0"); } static registerElement() { registerElement("startgeraet-time-and-date", TimeAndDateWebComponent); } }