Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

Device configuration changes. For Pi details, see [archive/NOMADPI-DETAILS.md](archive/NOMADPI-DETAILS.md). For mini PC setup, see [MINIPC-SETUP.md](MINIPC-SETUP.md).

## 2026-11-06 - Google sign-in tap detected via Google's own click_listener (v0.149.1)

A test against production after v0.149.0 found the window-blur check misses some Google taps. The Google button now
also passes GIS `renderButton`'s documented `click_listener`, and the blur check stays as a backup. A tap seen by
both within 1.5 s counts once. Verified in Chromium against the live page: one `tap` event, popup opened, then
`stall` and the email hint.

## 2026-11-06 - Google/Apple sign-in: a fallback when it never comes back, and every step logged (v0.149.0)

Live 2026-11-05 a singer's Google and Apple taps on the make-it screen "did nothing" (likely a Safari private
Expand Down
2 changes: 1 addition & 1 deletion kj-controller/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "kj-controller"
version = "0.149.0"
version = "0.149.1"
description = "Web-based karaoke show management with mpv + VLC playback"
requires-python = ">=3.11"

Expand Down
13 changes: 11 additions & 2 deletions kj-controller/static-sing/make.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@ function googleButton({ el, social, holder, onToken, testPrefix, w }) {
callback: (resp) => onToken("google", resp && resp.credential) });
gid.renderButton(node, { type: "standard", theme: "filled_black", size: "large", shape: "pill",
text: "continue_with", logo_alignment: "center", locale: getLocale(),
width: Math.min(400, node.clientWidth || 320) });
width: Math.min(400, node.clientWidth || 320),
// Google's documented tap hook (the button is a cross-origin iframe).
click_listener: () => holder.onGoogleTap && holder.onGoogleTap() });
}).catch(() => { // blocked / offline: email still works
node.hidden = true;
w.report("google", "script_failed");
Expand Down Expand Up @@ -214,6 +216,10 @@ export function socialButtons({ el, social, holder, onToken, onError, report = (
report: (provider, event, detail) => { try { report(provider, event, detail || ""); } catch { /* best-effort */ } },
settle,
tapped: (provider) => {
// Google's click_listener and the window-blur fallback can both fire for one tap.
const now = Date.now();
if (holder.lastTap && holder.lastTap.provider === provider && now - holder.lastTap.at < 1500) return;
holder.lastTap = { provider, at: now };
w.report(provider, "tap");
clearTimeout(holder.stallTimer);
holder.stallTimer = setTimeout(() => {
Expand All @@ -233,7 +239,10 @@ export function socialButtons({ el, social, holder, onToken, onError, report = (
const google = social.google ? googleButton(opts) : null;
const apple = social.apple ? appleButton(opts) : null;
if (!google && !apple) return null;
if (google) hookGoogleTap(() => w.tapped("google"));
if (google) {
holder.onGoogleTap = () => w.tapped("google");
hookGoogleTap(() => w.tapped("google"));
}
if (apple && !window.__SING_SOCIAL_STUB) loadScript(APPLE_SRC).catch(() => {}); // so the tap opens the popup at once
return el("div", { class: "mk-socials" },
...(onApplePlatform() ? [apple, google] : [google, apple]), hint);
Expand Down
Loading