From 6e3cf95debcd575b593bcf41f29768e46616c9c9 Mon Sep 17 00:00:00 2001 From: sravan Date: Sat, 18 Jul 2026 08:32:23 +0530 Subject: [PATCH] fix(mobile): mode-adaptive smooth keyboard + force-latest-scroll + bottom-anchored file input - Keyboard: auto-detect resize mode. resize:none -> lift full keyboard height at willShow so the CSS transition slides the composer up WITH the keyboard (smooth, no iOS resize lag). resize:native -> residual only. Config set to resize:none for the smooth path (needs build); web stays correct on the current resize:native build meanwhile. - #7: force scroll-to-bottom at 0/120/320/600ms on open so a chat always opens on the newest message. - File picker: anchor the file to a fixed bottom spot (was display:none -> iOS dropped the menu mid-screen); now it comes up as a bottom sheet even as the composer moves. Build marker -> 2026-07-18-batch106. Co-Authored-By: Claude Opus 4.8 --- mobile/capacitor.config.json | 2 +- server/public/home.html | 48 ++++++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/mobile/capacitor.config.json b/mobile/capacitor.config.json index cb11352..afd4b3d 100644 --- a/mobile/capacitor.config.json +++ b/mobile/capacitor.config.json @@ -17,7 +17,7 @@ "offsetForKeyboardInsetBug": false }, "Keyboard": { - "resize": "native" + "resize": "none" }, "SplashScreen": { "launchShowDuration": 900, diff --git a/server/public/home.html b/server/public/home.html index 91c24b9..c8e3a62 100644 --- a/server/public/home.html +++ b/server/public/home.html @@ -1072,7 +1072,7 @@ /* Composer clears the home indicator; with keyboard resize:none we raise it by --kb (the reported keyboard height, set by the Keyboard listener) so it sits on the keyboard. No home indicator while the keyboard is up, so --sab collapses to 0. */ - body.chat-open .content .panel{bottom:calc(var(--sab) + var(--kb));transition:bottom .18s ease;} + body.chat-open .content .panel{bottom:calc(var(--sab) + var(--kb));transition:bottom .25s cubic-bezier(.17,.59,.4,1);} body.kb-open{--sab:0px;} /* Native-style push/pop: the conversation slides in from the right when opened and slides back out when you go back, so navigation has a clear direction (like Teams/WhatsApp). */ @@ -1112,7 +1112,7 @@ - // juggling here — we only tag so CSS can make small native-only tweaks if needed. (function(){ try{ var C=window.Capacitor; if(!C||!C.isNativePlatform||!C.isNativePlatform()) return; var p=(C.getPlatform&&C.getPlatform())||''; var r=document.documentElement; r.classList.add('native-app'); if(p) r.classList.add('native-'+p); - // Keyboard — DEVICE-INDEPENDENT & self-adjusting. resize:native already shrinks the WebView by the - // keyboard height, so the composer only needs the RESIDUAL lift = (layout viewport height - visible - // viewport height) — the sliver still under the keyboard's prediction/accessory bar. Read live from - // the VisualViewport API so the composer follows the keyboard smoothly. No per-device constants. - if(window.visualViewport){ - var vv=window.visualViewport; - var applyKb=function(){ - var kb=Math.max(0, Math.round(document.documentElement.clientHeight - vv.height - vv.offsetTop)); - r.style.setProperty('--kb', kb+'px'); - document.body.classList.toggle('kb-open', kb>4); - var b=document.getElementById('msgs'); if(b) b.scrollTop=b.scrollHeight; - }; - vv.addEventListener('resize', applyKb); vv.addEventListener('scroll', applyKb); + // Keyboard — DEVICE-INDEPENDENT & mode-adaptive (works whether the WebView is resize:native or + // resize:none). We lift the composer so it sits on the keyboard: + // • resize:none → the WebView doesn't move, so lift by the FULL keyboard height (reported at + // keyboardWillShow, before any animation) → the CSS transition slides it up WITH the keyboard. + // • resize:native→ the WebView already shrank by the keyboard height, so lift only the RESIDUAL + // (clientHeight − visualViewport.height). Detected once by checking if clientHeight shrank. + // No per-device constants — the keyboard height comes from the plugin / VisualViewport. + function setKb(px){ px=Math.max(0,Math.round(px)); r.style.setProperty('--kb',px+'px'); var b=document.getElementById('msgs'); if(b) b.scrollTop=b.scrollHeight; } + var kbMode=null; var KB=C.Plugins&&C.Plugins.Keyboard; + if(KB && KB.addListener){ + KB.addListener('keyboardWillShow', function(info){ + document.body.classList.add('kb-open'); + var raw=(info&&info.keyboardHeight)||0; var kbFull = raw>window.innerHeight ? raw/(window.devicePixelRatio||1) : raw; // normalize px→pt + var baseH=document.documentElement.clientHeight; + if(kbMode==='none') setKb(kbFull); // known non-resizing WebView → lift immediately (smooth) + setTimeout(function(){ + var nowH=document.documentElement.clientHeight; + if(!kbMode) kbMode=(baseH-nowH>20)?'native':'none'; + if(kbMode==='native'){ var vv=window.visualViewport; setKb(vv?Math.max(0, nowH - vv.height - vv.offsetTop):0); } + else setKb(kbFull); + }, 60); + }); + KB.addListener('keyboardWillHide', function(){ r.style.setProperty('--kb','0px'); document.body.classList.remove('kb-open'); }); } + // Live-track while the keyboard is up (covers rotation + resize:native's late resize) without doubling. + if(window.visualViewport){ window.visualViewport.addEventListener('resize', function(){ if(kbMode==='native' && document.body.classList.contains('kb-open')){ var vv=window.visualViewport; setKb(Math.max(0, document.documentElement.clientHeight - vv.height - vv.offsetTop)); } }); } }catch(_){} })();
Biz Connect
Loading…
@@ -1890,7 +1902,7 @@ function convoShellHTML(it){ + '' + '' + '' - + '' + + '' + '' + '' + '' @@ -2818,6 +2830,10 @@ async function openConvo(kind,id){ if(el){ const sep=document.createElement('div'); sep.className='new-sep'; sep.innerHTML='New messages'; el.parentNode.insertBefore(sep, el); el.scrollIntoView({block:'start'}); el.parentNode.scrollTop-=40; const jl=document.getElementById('jumpLatest'); if(jl) jl.style.display='grid'; } } const inp=document.getElementById('msgInput'); if(inp && !isMobileUA()) inp.focus(); // #2: on phones, opening a chat should NOT pop the keyboard (user taps the box to type) + // #7: guarantee the newest message is in view on open — force the scroll to the bottom a few times as + // late content (avatars, images, day separators) settles, unless we deliberately stopped at a "New + // messages" divider. This is the safety net over renderThread()'s own pin. + [0,120,320,600].forEach((d)=>setTimeout(()=>{ if(selected&&selected.kind===kind&&selected.id===id){ const b=document.getElementById('msgs'); if(b && !b.querySelector('.new-sep')) b.scrollTop=b.scrollHeight; } }, d)); } // ---------- @mentions (group chat) ---------- let mentionItems=[], mentionIdx=0, mentionStart=-1;