diff --git a/src/templates/chat.html b/src/templates/chat.html index f323017..af21582 100644 --- a/src/templates/chat.html +++ b/src/templates/chat.html @@ -148,20 +148,32 @@ if (diff > 150) { // Keyboard is likely open if (messagesWrapper) { - messagesWrapper.style.paddingBottom = '120px'; // More padding for mobile keyboard - // Auto-scroll when keyboard opens, with multiple attempts for reliability - userScrolled = false; // Reset scroll state when keyboard opens + messagesWrapper.style.paddingBottom = '140px'; // Even more padding for mobile keyboard + // Reset scroll state and aggressively scroll to bottom + userScrolled = false; + + // Multiple scroll attempts with increasing delays setTimeout(() => { - scrollToBottom(false); - }, 200); - // iOS often needs multiple scroll attempts + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 150; + }, 100); + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 150; + }, 250); + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 150; + }, 400); + + // iOS often needs even more attempts if (isIOS) { setTimeout(() => { - messagesWrapper.scrollTop = messagesWrapper.scrollHeight; - }, 400); - setTimeout(() => { - messagesWrapper.scrollTop = messagesWrapper.scrollHeight; + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 200; }, 600); + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 200; + }, 800); + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 200; + }, 1000); } } } else { @@ -170,9 +182,14 @@ // Scroll to bottom when keyboard closes too setTimeout(() => { if (!userScrolled) { - scrollToBottom(false); + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 100; } }, 200); + setTimeout(() => { + if (!userScrolled) { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 100; + } + }, 400); } } } @@ -199,9 +216,16 @@ setTimeout(() => { const messagesWrapper = document.getElementById('messagesWrapper'); if (messagesWrapper) { - messagesWrapper.scrollTop = messagesWrapper.scrollHeight; + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 200; } }, 800); + // Additional scroll attempt for stubborn mobile browsers + setTimeout(() => { + const messagesWrapper = document.getElementById('messagesWrapper'); + if (messagesWrapper) { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 250; + } + }, 1200); } }); @@ -230,11 +254,27 @@ if (messagesWrapper) { // On mobile, especially iOS, direct scrollTop assignment is more reliable if (isMobile) { - messagesWrapper.scrollTop = messagesWrapper.scrollHeight; - // Double-check scroll position after a short delay for mobile + // Force scroll to absolute bottom with extra padding + const targetScroll = messagesWrapper.scrollHeight + 100; + messagesWrapper.scrollTop = targetScroll; + + // Multiple aggressive scroll attempts for mobile reliability setTimeout(() => { - messagesWrapper.scrollTop = messagesWrapper.scrollHeight; - }, 100); + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 100; + }, 50); + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 100; + }, 150); + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 100; + }, 300); + + // Final iOS-specific attempt + if (isIOS) { + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 200; + }, 500); + } } else { if (smooth) { messagesWrapper.scrollTo({ @@ -334,11 +374,26 @@ // Only auto-scroll if user hasn't manually scrolled up if (!userScrolled) { - // Longer delay for mobile to ensure proper rendering - const delay = isMobile ? 200 : 50; - setTimeout(() => { - scrollToBottom(false); // Always instant scroll on mobile - }, delay); + // Multiple scroll attempts for mobile with extra padding + const messagesWrapper = document.getElementById('messagesWrapper'); + if (messagesWrapper) { + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 150; + }, 100); + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 150; + }, 250); + if (isMobile) { + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 200; + }, 400); + if (isIOS) { + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 200; + }, 600); + } + } + } } } } @@ -346,19 +401,28 @@ // Force scroll with mobile optimizations function forceScrollToBottom() { userScrolled = false; - const delay = isMobile ? 300 : 100; - setTimeout(() => { - scrollToBottom(false); - // iOS double-check + const messagesWrapper = document.getElementById('messagesWrapper'); + if (messagesWrapper) { + // Immediate aggressive scroll + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 150; + + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 150; + }, 100); + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 200; + }, 300); + + // Extra attempts for iOS if (isIOS) { setTimeout(() => { - const messagesWrapper = document.getElementById('messagesWrapper'); - if (messagesWrapper) { - messagesWrapper.scrollTop = messagesWrapper.scrollHeight; - } - }, 100); + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 250; + }, 500); + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 250; + }, 700); } - }, delay); + } } // Mobile-optimized mutation observer @@ -376,10 +440,20 @@ ); if (hasNewMessage && !userScrolled) { - const delay = isMobile ? 250 : 50; - setTimeout(() => { - scrollToBottom(false); // Instant scroll for reliability - }, delay); + const messagesWrapper = document.getElementById('messagesWrapper'); + if (messagesWrapper) { + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 150; + }, 100); + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 200; + }, 300); + if (isMobile) { + setTimeout(() => { + messagesWrapper.scrollTop = messagesWrapper.scrollHeight + 250; + }, 500); + } + } } } });