Compare commits

...
2 Commits
Author SHA1 Message Date
GGBandClaude Sonnet 5 aac37265a3 Stop BACK from bypassing the JS menu popup
BACK's isFullscreen()/navigate-away logic ran entirely on the Android
side, with no idea whether the website's Menu popup was open - so
pressing Back while the popup was showing jumped straight to the room
list (or reloaded) instead of closing it, since Android can't observe
JS-side modal state.

BACK now just relays a real Escape keypress into the page whenever
we're on a page this app controls (room list or in-room), and lets
the website's own keydown handler - which already knows about the
popup, cinema mode, and (now) fullscreen state - decide what Escape
should do. Removed the now-dead isFullscreen()/fullscreenView-reading
code path (fullscreenView itself stays: WebChromeClient still needs
onShowCustomView/onHideCustomView for HTML5 fullscreen to render).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHgWjmEJXsJEi1EVAoTp4K
2026-09-17 21:06:20 +02:00
GGBandClaude Sonnet 5 ba422bf089 Fix DPAD/Menu key remaps leaking into login and other non-room pages
isRoomList() only matched the exact "/tv" room-list path, so the
"!isRoomList()" checks gating DPAD center/up/down/left/right and Menu
treated every OTHER page - including /login - as if it were inside a
room. Result: DPAD OK typed a literal space into focused text fields,
DPAD up/down typed 'p'/'n', and Menu typed 'x'.

Replaced with isInRoom() (path starts with "/tv/"), so these remaps
only apply on an actual room page. Also stopped BACK from reloading to
the room list from unrelated pages like /login, which discarded
whatever the user had typed and, since /tv requires auth, just bounced
straight back to /login anyway.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHgWjmEJXsJEi1EVAoTp4K
2026-09-17 20:28:47 +02:00
@@ -30,15 +30,18 @@ import android.webkit.WebViewClient
* deshalb als Alias fuer die 'ContextMenu'-Taste, ausschliesslich fuer
* diesen App-Anwendungsfall.
*
* DPAD Center/Up/Down (und die entsprechenden Medientasten) werden NUR
* innerhalb eines Raums remapped (Space/P/N - siehe Design-Spec). Auf der
* Raumliste (/tv) haben sie dort keine Bedeutung: die Raumliste hat ihr
* eigenes Tastaturschema (ArrowUp/ArrowDown/Enter, siehe tv-rooms.js auf
* der Website) und muss die echten, unveraenderten Tasten bekommen, sonst
* bewegt sich der Fokus zwischen den Raum-Kacheln nie (genau der Fehler,
* der beim ersten Hardware-Test auftrat: die Raumliste laed, aber keine
* Taste tut etwas, weil DPAD_DOWN/CENTER als 'n'/Space statt als
* ArrowDown/Enter ankamen).
* DPAD Center/Up/Down/Left/Right, Menu und die entsprechenden Medientasten
* werden NUR innerhalb eines Raums (Pfad "/tv/<id>") remapped - siehe
* isInRoom(). Auf jeder anderen Seite (Raumliste "/tv", Login, Signup, ...)
* muessen sie unveraendert durchgereicht werden, sonst zerschiesst die
* Remapping-Logik dort Texteingaben. Zwei konkrete Bugs kamen genau daher,
* dass frueher statt isInRoom() die Umkehrung von isRoomList() geprueft
* wurde (also "ueberall ausser der Raumliste"), was auch Login/Signup
* einschloss: auf der Raumliste bewegte sich der Fokus zwischen den
* Raum-Kacheln nicht (DPAD_DOWN/CENTER kamen als 'n'/Space statt als
* ArrowDown/Enter an), und auf der Login-Seite tippte DPAD OK ein
* Leerzeichen in das fokussierte Textfeld statt das Formular zu bestaetigen
* (DPAD_CENTER kam als Space-Taste an statt als echtes Enter).
*/
class MainActivity : Activity() {
@@ -88,8 +91,8 @@ class MainActivity : Activity() {
super.onDestroy()
}
private fun isFullscreen() = fullscreenView != null
private fun isRoomList() = currentPath == "/tv"
private fun isInRoom() = currentPath.startsWith("/tv/")
private fun sendKey(keyCode: Int, shift: Boolean = false) {
val metaState = if (shift) KeyEvent.META_SHIFT_ON else 0
@@ -115,11 +118,12 @@ class MainActivity : Activity() {
* Tastendrucks abgefangen wird (sonst haengt Chromiums interner
* Tastenstatus fest, weil ein Keydown ohne passendes Keyup ankaeme). */
private fun shouldIntercept(keyCode: Int): Boolean = when (keyCode) {
KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT,
KeyEvent.KEYCODE_MENU -> true
KeyEvent.KEYCODE_BACK -> true
KeyEvent.KEYCODE_MENU -> isRoomList() || isInRoom()
KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT,
KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE,
KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN,
KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_MEDIA_NEXT -> !isRoomList()
KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_MEDIA_NEXT -> isInRoom()
else -> false
}
@@ -134,11 +138,16 @@ class MainActivity : Activity() {
KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS -> sendKey(KeyEvent.KEYCODE_P)
KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT -> sendKey(KeyEvent.KEYCODE_N)
KeyEvent.KEYCODE_MENU -> sendKey(KeyEvent.KEYCODE_X)
KeyEvent.KEYCODE_BACK -> when {
isRoomList() -> { /* verschluckt, keine weitere Aktion */ }
isFullscreen() -> sendKey(KeyEvent.KEYCODE_ESCAPE)
else -> webView.loadUrl(BuildConfig.WEBSITE_URL)
}
/* BACK entscheidet NICHT mehr selbst zwischen "Popup schliessen",
"Vollbild verlassen" und "zur Raumliste zurueck" - das kann nur
JS wissen (siehe room.js/tv-rooms.js keydown-Handler), weil nur
dort bekannt ist, ob z. B. das Menue-Popup gerade offen ist. Ein
fixer Fall genau darauf beruhte der Bug, dass BACK bei offenem
Popup direkt zur Raumliste sprang, statt das Popup zu schliessen.
Auf Login/Signup/sonstigen Seiten (weder Raumliste noch Raum)
bleibt BACK bewusst wirkungslos - sonst gehen unfertig
ausgefuellte Formulare verloren. */
KeyEvent.KEYCODE_BACK -> if (isRoomList() || isInRoom()) sendKey(KeyEvent.KEYCODE_ESCAPE)
}
return true
}