chore(ops,docs): first-boot containers, image versions, design docs, android remote-input

- first-boot-containers + image-versions for fmcd/fedimint
- dual-ecash, meshroller-integration, and remaining-issues design docs
- Android remote-input two-finger scroll + external-open handling

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-06-17 19:22:02 -04:00
co-authored by Claude Opus 4.8
parent 87769cbfbf
commit 705e2436ba
8 changed files with 622 additions and 1 deletions
@@ -35,6 +35,13 @@ class InputWebSocket(
/** Player ID for arcade mode (0 = broadcast, 1 = P1, 2 = P2) */
var playerId: Int = 0
/**
* Invoked when the kiosk asks us to open a URL in the phone's default
* browser ({"t":"o","url":"…"}). "Open in external browser" apps can't be
* usefully opened on the kiosk, so the kiosk forwards them here.
*/
var onExternalOpen: ((String) -> Unit)? = null
private val _state = MutableStateFlow(ConnectionState.DISCONNECTED)
val state: StateFlow<ConnectionState> = _state
@@ -127,6 +134,20 @@ class InputWebSocket(
reconnectAttempt = 0
}
override fun onMessage(webSocket: WebSocket, text: String) {
// The only inbound message we act on is an external-open request
// forwarded from the kiosk: {"t":"o","url":"https://…"}.
try {
val obj = org.json.JSONObject(text)
if (obj.optString("t") == "o") {
val url = obj.optString("url")
if (url.startsWith("http://") || url.startsWith("https://")) {
onExternalOpen?.invoke(url)
}
}
} catch (_: Exception) {}
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
_state.value = ConnectionState.ERROR
scheduleReconnect()
@@ -63,6 +63,21 @@ fun RemoteInputScreen(onBack: () -> Unit) {
val ws = remember { InputWebSocket(scope) }
// When the kiosk forwards an "open in external browser" app, launch it in
// the phone's default browser.
DisposableEffect(ws) {
ws.onExternalOpen = { url ->
try {
val intent = android.content.Intent(
android.content.Intent.ACTION_VIEW,
android.net.Uri.parse(url),
).apply { addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK) }
context.startActivity(intent)
} catch (_: Exception) {}
}
onDispose { ws.onExternalOpen = null }
}
fun togglePlayer() {
playerId = when (playerId) { 0 -> 1; 1 -> 2; else -> 0 }
ws.playerId = playerId