From 1351da3d7c8e95f37072cc0cb7474dc6cebe3ebc Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Wed, 5 Jun 2024 21:26:37 +0200 Subject: [PATCH] Fix some small bugs (#915) The APIs that are not supported by every browser or may not always be allowed (Battery and Wake Lock) are requested in try catch blocks. The problem was that both of them actually yield promises. If the promises fail, then those exceptions would not be caught properly, because we forgot to await them. So especially for the wake lock you would sometimes see an error message when it gets hot reloaded. This should be fixed now. Additionally this changes the window title for when there are unsaved changes. Apparently when LiveSplit One is used as a PWA, then at least Chrome wants to always keep the app name in the title. If the title itself is changed, then it gets shown as `LiveSplit One - The new title`. By us putting an asterisk in the front of the title, the PWA then shows `LiveSplit One - *LiveSplit One`, which is pretty bad. I noticed that if the app name is also the prefix of the title, Chrome recognizes that and does not end up showing the app name twice. There also was a small bug in the event sink where the `togglePauseOrStart` event did not update the splits modified state. --- src/index.tsx | 4 +-- src/ui/LSOEventSink.ts | 1 + src/ui/LiveSplit.tsx | 8 +++++- src/util/FrameRate.ts | 55 ++++++++++++++++++++++++++++-------------- 4 files changed, 47 insertions(+), 21 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 854c80a..435c13a 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -49,9 +49,9 @@ try { generalSettings, } = await LiveSplit.loadStoredData(); - function requestWakeLock() { + async function requestWakeLock() { try { - (navigator as any)?.wakeLock?.request("screen"); + await (navigator as any)?.wakeLock?.request(); } catch { // It's fine if it fails. } diff --git a/src/ui/LSOEventSink.ts b/src/ui/LSOEventSink.ts index adb11aa..0e10296 100644 --- a/src/ui/LSOEventSink.ts +++ b/src/ui/LSOEventSink.ts @@ -80,6 +80,7 @@ export class LSOEventSink { this.currentPhaseChanged(); this.currentSplitChanged(); + this.splitsModifiedChanged(); } public pause(): void { diff --git a/src/ui/LiveSplit.tsx b/src/ui/LiveSplit.tsx index a95d2d2..bee2865 100644 --- a/src/ui/LiveSplit.tsx +++ b/src/ui/LiveSplit.tsx @@ -828,7 +828,13 @@ export class LiveSplit extends React.Component { } catch { // It's fine if this fails. } - document.title = "*LiveSplit One"; + + // It's important that any change is at the end of the title, + // because at least Chrome then recognizes that it's an extension of + // the PWA name. Otherwise it would show: + // LiveSplit One - Window Title + // which would repeat LiveSplit One. + document.title = "LiveSplit One ●"; } else { try { navigator?.clearAppBadge(); diff --git a/src/util/FrameRate.ts b/src/util/FrameRate.ts index 736ec9f..b27abf3 100644 --- a/src/util/FrameRate.ts +++ b/src/util/FrameRate.ts @@ -20,25 +20,30 @@ switch (navigator.platform) { export let batteryAwareFrameRate: FrameRate = batteryFrameRate; +let computePressure: FrameRate = FRAME_RATE_MATCH_SCREEN; + if ('PressureObserver' in window) { - try { - const observer = new (window as any).PressureObserver((records: any) => { - const state = records[0].state; - switch (state) { - case "serious": - batteryAwareFrameRate = FRAME_RATE_SERIOUS; - break; - case "critical": - batteryAwareFrameRate = FRAME_RATE_CRITICAL; - break; - default: - batteryAwareFrameRate = batteryFrameRate; - } - }); - observer.observe("cpu", { sampleInterval: 2_000 }); - } catch { - // The Compute Pressure API is not supported by the browser. - } + (async () => { + try { + const observer = new (window as any).PressureObserver((records: any) => { + const state = records[0].state; + switch (state) { + case "serious": + computePressure = FRAME_RATE_SERIOUS; + break; + case "critical": + computePressure = FRAME_RATE_CRITICAL; + break; + default: + computePressure = FRAME_RATE_MATCH_SCREEN; + } + updateBatteryAwareFrameRate(); + }); + await observer.observe("cpu", { sampleInterval: 2_000 }); + } catch { + // The Compute Pressure API is not supported by every browser. + } + })(); } (async () => { @@ -48,8 +53,22 @@ if ('PressureObserver' in window) { batteryFrameRate = batteryApi.charging === true ? FRAME_RATE_MATCH_SCREEN : FRAME_RATE_LOW_POWER; + updateBatteryAwareFrameRate(); }; } catch { // The battery API is not supported by every browser. } })(); + +function updateBatteryAwareFrameRate() { + // Choose the lower of the two frame rates. If one of them is a string, it + // is "Match Screen", which has the lowest priority. + + if (typeof batteryFrameRate === "string") { + batteryAwareFrameRate = computePressure; + } else if (typeof computePressure === "string") { + batteryAwareFrameRate = batteryFrameRate; + } else { + batteryAwareFrameRate = Math.min(batteryFrameRate, computePressure); + } +}