Files
hermes-webui/static
nesquena-hermes 7ec7b9c942 fix(mobile): PWA reflow guard + avoid redundant same-session refresh (salvage of #3976)
Salvages PR #3976 by ksj5131513-ops, ported fresh onto current master and
re-applied on top of #4195's external-refresh gate (the original PR predated
#3916/#4195's rework of refreshActiveSessionIfExternallyUpdated).

Two parts:

1. Avoid an unconditional same-session force reload the moment streaming
   settles. _scheduleActiveSessionIdleReload previously called
   loadSession(force:true) on every idle reconcile, which on mobile PWA caused
   a visible end-of-turn flash and could briefly restore the pane with stale
   layout geometry. It now reconciles against server metadata first via
   refreshActiveSessionIfExternallyUpdated('idle-reconcile', {ignoreStreamJustFinished:true})
   — reloading ONLY when the message count actually changed — and falls back to
   the original forced reload only if the metadata probe itself fails.

   This COEXISTS with #4195: the poll-only external-session early-return
   (if((reason||'poll')==='poll' && !_isExternalSession(S.session)) return) is
   left untouched. The idle path uses a non-'poll' reason so it never trips that
   gate, and opts (read via arguments[1], same pattern as loadSession) only
   bypasses the post-stream cooldown, not the external gate. The function keeps
   its (reason) signature and now returns a status string
   ('skipped'/'unchanged'/'reloaded'/'failed') for callers that want it.

2. Mobile viewport reflow guard for PWA visualViewport changes. When the
   on-screen keyboard / browser chrome shows or hides, the phone layout can stay
   painted against stale geometry. _forceMobileViewportReflow() toggles a
   one-frame html.viewport-reflow class (cheap GPU-promotion transform) to force
   a repaint, then resyncs the workspace panel + sidebar aria. Wired to
   visualViewport resize/scroll (debounced) where available, falling back to the
   window resize handler otherwise. Adds safe-area-inset padding to topbar,
   messages-inner, and composer-wrap on phones. Uses overflow-x:clip (NOT hidden)
   on .layout per the #4856 lesson to avoid coercing overflow-y into a scroller.

Co-authored-by: ksj5131513-ops <ksj5131513-ops@users.noreply.github.com>
2026-06-28 09:02:10 +00:00
..
2026-05-25 00:14:38 +00:00