From 775b2c1c7f4d968ac6eaf039fab18dfeee14aff5 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Sat, 24 Jan 2026 09:55:49 -0500 Subject: [PATCH] Update conversations.php --- conversations.php | 86 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/conversations.php b/conversations.php index 15412bf..87751d6 100644 --- a/conversations.php +++ b/conversations.php @@ -940,6 +940,9 @@ // Track whether the user is actively scrolling/reading to avoid forcing scroll-to-bottom this._userScrolling = false; this._userScrollTimer = null; + // Suspend periodic refresh while media playback or recording is active + this._suspendAutoRefresh = false; + this._pendingReloadAfterMedia = false; // Removed: automatic "Nuevos mensajes" indicator — we always reload full conversation now // this._lastRenderMessageCount = 0; @@ -1535,9 +1538,17 @@ }, 30000); // Actualizar mensajes del chat activo cada 10 segundos - // Use full reload (initial=true) — always fetch the full conversation and scroll to bottom + // Use full reload (initial=true) — always fetch the full conversation and scroll to bottom, + // but suspend while media playback or recording is active (to avoid interrupting) setInterval(() => { if (this.currentUserId) { + try { + if (typeof this.isMediaActive === 'function' && this.isMediaActive()) { + console.debug('Periodic load skipped: media active or recording in progress; scheduling reload after media ends'); + this._pendingReloadAfterMedia = true; + return; + } + } catch (e) { console.warn('isMediaActive check failed', e); } // full reload forces scroll-to-bottom this.loadMessages(this.currentUserId, true).catch(err => console.warn('Periodic loadMessages failed', err)); } @@ -2023,6 +2034,30 @@ }); chatContainer._infiniteScrollAdded = true; } + + // Media playback listeners: suspend auto-refresh while media is playing and resume when it stops + if (!chatContainer._mediaListenersAdded) { + const onMediaPlay = (ev) => { + try { + this._suspendAutoRefresh = true; + console.debug('Media play detected, suspending periodic reload'); + } catch (e) { /* ignore */ } + }; + const onMediaEnd = async (ev) => { + try { + this._suspendAutoRefresh = false; + console.debug('Media paused/ended, resuming periodic reload'); + if (this._pendingReloadAfterMedia && this.currentUserId) { + this._pendingReloadAfterMedia = false; + await this.loadMessages(this.currentUserId, true); + } + } catch (e) { console.warn('media end handler failed', e); } + }; + chatContainer.addEventListener('play', onMediaPlay, true); + chatContainer.addEventListener('pause', onMediaEnd, true); + chatContainer.addEventListener('ended', onMediaEnd, true); + chatContainer._mediaListenersAdded = true; + } } // Cargar respuestas rápidas y plantillas await this.loadQuickReplies(); @@ -2588,6 +2623,26 @@ return !(hasContent || hasMedia || nonText); } + // Helper: detect active media playback or recording to avoid interrupting with reloads + isMediaActive() { + // Recording in progress -> active + if (this._mediaRecorder && this._mediaRecorder.state === 'recording') return true; + // Explicit suspend flag + if (this._suspendAutoRefresh) return true; + try { + const container = document.getElementById('chat-conversations'); + if (!container) return false; + const mediaEls = container.querySelectorAll('audio,video'); + for (const el of mediaEls) { + if (!el.paused && !el.ended) return true; + if (el.readyState > 2 && !el.paused) return true; + } + } catch (e) { + console.warn('isMediaActive: failed to inspect media elements', e); + } + return false; + } + // Initialize recording handlers (so mic works before openConversation) and helper to manage recording state initRecordingHandlers() { if (this._recordingHandlersInitialized) return; @@ -2598,6 +2653,8 @@ this.startRecording = async function() { try { + // Suspend periodic reload while recording + this._suspendAutoRefresh = true; const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); this._mediaRecorder = new MediaRecorder(stream); const chunks = []; @@ -2628,6 +2685,15 @@ } catch(e) { /* ignore */ } // Clear recorder reference to indicate stopped this._mediaRecorder = null; + + // Resume auto-refresh and trigger a reload if one was pending + try { + this._suspendAutoRefresh = false; + if (this._pendingReloadAfterMedia && this.currentUserId) { + this._pendingReloadAfterMedia = false; + await this.loadMessages(this.currentUserId, true); + } + } catch (e) { console.warn('Failed to resume reload after recording', e); } }; this._mediaRecorder.start(); @@ -2667,6 +2733,15 @@ const ind = document.getElementById('recording-indicator'); if (ind) ind.style.display = 'none'; const micEl = document.getElementById('mic-btn'); if (micEl) micEl.classList.remove('recording'); if (this._updateSendMicVisibility) this._updateSendMicVisibility(); + + // Ensure we resume periodic reloads and trigger pending reload + try { + this._suspendAutoRefresh = false; + if (this._pendingReloadAfterMedia && this.currentUserId) { + this._pendingReloadAfterMedia = false; + this.loadMessages(this.currentUserId, true).catch(e => console.warn('Reload after stopRecording failed', e)); + } + } catch (e) { console.warn('stopRecording resume failed', e); } }; this.cancelRecording = function() { @@ -2688,6 +2763,15 @@ // hide delete button if present const delBtn = document.getElementById('delete-file-btn'); if (delBtn) delBtn.style.display = 'none'; if (this._updateSendMicVisibility) this._updateSendMicVisibility(); + + // Resume auto-refresh if it was suspended and trigger pending reload + try { + this._suspendAutoRefresh = false; + if (this._pendingReloadAfterMedia && this.currentUserId) { + this._pendingReloadAfterMedia = false; + this.loadMessages(this.currentUserId, true).catch(e => console.warn('Reload after cancelRecording failed', e)); + } + } catch (e) { console.warn('cancelRecording resume failed', e); } }; return true;