Commit Graph
3 Commits
Author SHA1 Message Date
lockbitchat 12e62db76f v6.8.2: the keyboard no longer pushes the chat off the screen on iOS
Reported from an iPhone, with a screenshot: tap the message box, the keyboard
comes up, and the whole app has slid off the top — header gone, only the bottom
edge of the composer left, black underneath it down to the keyboard.

That is the visual viewport being panned. WebKit shrinks it for the keyboard and
then moves it down inside the layout viewport (which it does not shrink) to
reveal the focused field. The shell had shrunk correctly, to the top --sb-vh of
the layout viewport; the window had simply moved off it. No CSS declines that
pan, and it is not a document scroll, so there is no scrollTop to put back.

So the shell is pinned to the visible rect: fixed to the layout viewport and
translated by visualViewport.offsetTop. The earlier objection to pinning is kept
where it was right — HEIGHT still moves on resize only, which is what stopped the
layout twitching under the finger, and the offset rides a transform rather than
`top`.

The first cut of this had a guard that silently disabled it: the pan was only
followed when window.innerHeight was much taller than the visual viewport, i.e.
"a keyboard is covering us". That assumes iOS never resizes the layout viewport,
which stopped being safe once WebKit started honouring interactive-widget. Only a
pinch-zoomed page switches the pan off now, by scale, and offsetTop is believed
whenever it is non-zero. The offset is also re-read across the keyboard's
animation on focusin/focusout: on iOS 26 the viewport is documented not to settle
back immediately on dismissal.

The message list stays at the newest message across a keyboard open or close,
instead of holding a scroll position from the taller layout and leaving the last
few messages under the composer.

Two smaller things on the same screen:

The QR code closes itself once the safety number appears. It was only dismissed
when both exchange flags cleared, and those stay set through verification, so a
one-time credential sat on top of the code the user was meant to be reading.

The disconnect button's label is hidden wherever the button becomes a 40px
square. Its own rule stopped at 560px while the square starts at 768px, so
between the two the word was still inside the box, pushing the icon off centre.

?vvdebug=1 paints the viewport numbers over the app — visible rect height,
offset, scale, what the shell resolved to. A phone cannot be put on a debugger
and none of those numbers show up in a screenshot of the result; this one is how
the guard above was caught. Off unless named in the URL.

Claude-Session: https://claude.ai/code/session_01R63J7dexujFQCJpDAeKxr9
2026-09-12 01:25:45 -04:00
lockbitchat 113bb107d3 feat(groups): audio and video calls in group chats; release v6.6.6
CodeQL Analysis / Analyze CodeQL (push) Canceled after 0s
Deploy Application / deploy (push) Canceled after 0s
Mirror to Codeberg / mirror (push) Canceled after 0s
Mirror to PrivacyGuides / mirror (push) Canceled after 0s
A group call is N-1 ordinary 1:1 calls, one to each other member, each riding
the pairwise session that member already has — a transport a human already
authenticated by comparing the safety code. No mixer, no SFU, no point at which
two people's media meets anywhere but on a device.

Call control is separate from call media, because the two reach different sets
of people. Who opened a call, who joined and who left travels as group frames
signed with the sender's group identity key, so it reaches members currently
reachable only through a relay — and a relaying member can drop one but cannot
write one. Media flows only where a direct link exists, so a member without one
shows as connecting rather than being omitted. Frames carry a per-sender
sequence checked before the action, so a captured leave cannot end a later call,
and simultaneous calls converge on the lower random call id.

One capture is shared across every leg rather than one getUserMedia per member,
and legs answer without prompting: the flag permitting that is set only locally,
only while this user is in the call, and cleared when they leave.

UI: a gallery that sizes itself from the space it has, a spotlight view, an
active-speaker indicator read from the waveform, and the call surface in the
same visual language as the 1:1 one.

Also in this commit, the v6.5.0 language-suggestion work that had not been
pushed yet; its notes are in the changelog. And two fixes: the safety-code input
asks for digits rather than text, and starting a new chat from inside a group no
longer creates it behind the group where it cannot be seen — which had made it
impossible to connect to anyone new, or to add anyone to a group, while a group
was open.

Claude-Session: https://claude.ai/code/session_01XSxAkET3hQTkYDQfbjCQwZ
2026-09-01 01:04:11 -04:00
lockbitchat 6a98e2eb00 fix(mobile): make the chat layout responsive on phones; release v5.9.2
CodeQL Analysis / Analyze CodeQL (push) Canceled after 0s
Deploy Application / deploy (push) Canceled after 0s
Mirror to Codeberg / mirror (push) Canceled after 0s
Mirror to PrivacyGuides / mirror (push) Canceled after 0s
The chat did not lay out correctly on phones, iPhone worst of all: the header
would not stay at the top, and the layout shifted as you scrolled or opened the
keyboard.

The root cause was a floor, not a position. The app shell and column both carry
.minimal-bg, which sets min-height:100vh — and min-height always beats height. On
iOS 100vh is the URL-bar-retracted *large* viewport, so with the bar showing the
shell was held some 60-100px taller than the visible area. That surplus made the
document scrollable, and a scrolling document is how the header rode off the top.
It also left the visual-viewport tracking inert: forcing --sb-vh to 700px left the
shell at 844px. With the floor removed it follows to 700px and the document does
not scroll.

Also: the app shell is now sized from visualViewport rather than pinned, the
message list is the only scroller and can actually shrink, safe-area padding
applies (viewport-fit=cover) and collapses under the keyboard, and the
online/offline toast no longer sits on top of the header.

Adds ?preview=chat, which renders the chat layout with canned content and no
connection — presentational only, no peer manager, keys, or network.

Verified in an emulated iPhone viewport at rest and with the keyboard open:
header pinned at 0-64, composer flush to the keyboard line, document unscrollable.
2026-08-09 13:21:44 -04:00