diff --git a/android/app/src/main/assets/public/main.js b/android/app/src/main/assets/public/main.js index a5d0ca32..6cf66b66 100644 --- a/android/app/src/main/assets/public/main.js +++ b/android/app/src/main/assets/public/main.js @@ -4206,6 +4206,55 @@ function handleChatInputKey(event) { let dmMessagePollInterval = null; let appWebSocket = null; let dmMessageLoadTimeout = null; +let appWsPingTimer = null; +let callStatesResyncTimer = null; + +//Keepalive app-WS: tekstowy "ping" co 20 s. Serwer zamyka połączenie po 75 s +//bezczynności (AppWsIdleTimeout) - bez tego half-open TCP po zabiciu aplikacji / +//zmianie sieci wisiał na serwerze godzinami, cleanup ActiveCalls nie biegł i +//wskaźniki rozmów pokazywały uczestników, którzy dawno wyszli. Ping utrzymuje +//też mapping NAT przy danych komórkowych, więc eventy (call_update!) nie giną. +function startAppWsPing() { + if (appWsPingTimer) clearInterval(appWsPingTimer); + appWsPingTimer = setInterval(() => { + if (appWebSocket && appWebSocket.readyState === WebSocket.OPEN) { + try { appWebSocket.send("ping"); } catch (e) {} + } + }, 20000); +} + +function stopAppWsPing() { + if (appWsPingTimer) { clearInterval(appWsPingTimer); appWsPingTimer = null; } +} + +//Pełna resynchronizacja wskaźników rozmów: zgubiony podczas przerwy w app-WS +//call_update NIGDY nie jest odtwarzany przez serwer, a seedCallStateFromList +//tylko dodaje wpisy - bez tego wskaźniki "znikały dopiero po ręcznym odświeżeniu". +//Dla każdego pokoju znanego jako aktywny (+ otwartego) pyta room/voice/state +//i koryguje mapę oraz UI. Uruchamiane: po (re)otwarciu WS, co 30 s, przy powrocie +//karty/aplikacji na wierzch. +async function resyncAllCallStates() { + if (!window.id || typeof fetchEncrypted !== "function" || typeof ensureActiveCallsMap !== "function") return; + let map = ensureActiveCallsMap(); + let keys = Object.keys(map); + let currentKey = window.currentDmId ? sanitizeId(window.currentDmId) : null; + if (currentKey && !keys.includes(currentKey)) keys.push(currentKey); + if (keys.length === 0) return; + + for (let key of keys) { + let roomType = window.currentDmId === key && window.currentRoomType ? window.currentRoomType + : (String(key).includes("_") ? "dms" : "groups"); + try { + let res = await fetchEncrypted("room/voice/state", JSON.stringify({ string1: roomType, string2: key })); + if (!res || !res.startsWith("[")) continue; + let participants = JSON.parse(res).map(u => String(u).split(";")[0]); + if (participants.length > 0) map[key] = participants; + else delete map[key]; + } catch (e) {} + } + //Po serii poprawek pełne przerysowanie wskaźników (listy + top-bary + details) + if (typeof updateVoicePresenceUI === "function") updateVoicePresenceUI(); +} function setupWebSocket() { if (appWebSocket && (appWebSocket.readyState === WebSocket.OPEN || appWebSocket.readyState === WebSocket.CONNECTING)) return; @@ -4228,6 +4277,17 @@ function setupWebSocket() { } finally { release(); } + + startAppWsPing(); + //Po każdym (re)połączeniu odtwarzamy stan wskaźników - eventy call_update + //z czasu rozłączenia są bezpowrotnie stracone + resyncAllCallStates(); + if (!callStatesResyncTimer) { + callStatesResyncTimer = setInterval(() => { + if (document.visibilityState !== "visible") return; + resyncAllCallStates(); + }, 30000); + } }; appWebSocket.onmessage = (event) => { @@ -4273,10 +4333,22 @@ function setupWebSocket() { }; appWebSocket.onclose = () => { + stopAppWsPing(); setTimeout(setupWebSocket, 5000); }; } +//Powrót karty/aplikacji na wierzch: mobilne WebView potrafią trzymać martwy +//socket odkryty bardzo długo (brak ramek = brak detekcji). Wymuszamy próbę +//połączenia i od razu resynchronizujemy wskaźniki rozmów. +document.addEventListener("visibilitychange", () => { + if (document.visibilityState !== "visible") return; + if (appWebSocket && appWebSocket.readyState !== WebSocket.OPEN && appWebSocket.readyState !== WebSocket.CONNECTING) { + setupWebSocket(); + } + resyncAllCallStates(); +}); + let currentContextMenuMsgId = null; let touchContextMenuFired = false; diff --git a/android/app/src/main/assets/public/screens.js b/android/app/src/main/assets/public/screens.js index 63c3484f..8366ba00 100644 --- a/android/app/src/main/assets/public/screens.js +++ b/android/app/src/main/assets/public/screens.js @@ -141,7 +141,7 @@ var invitesEntry = ` var chatScreen = `
-
+