fix(android): the keyboard no longer buries the bottom of a form

The frame is nailed to the whole screen, so when the keyboard rises the
content overflows nothing and the bottom third becomes unreachable: the
form's password field could only be seen by folding the keyboard away.

Reserving below the scroll area exactly the height the keyboard covers
gives the panel something to scroll. The measure answers correctly whether
or not the engine actually resizes the window - if it does, innerHeight
shrinks too, the reserve is zero, and the natural overflow already does the
work. No need to know which case applies.

A first attempt shrank the body to the visible height; it changed nothing
observable, and it depended on which of three over-constrained box
properties the engine drops. This does not.

The plan records where a save's time actually goes: 46 ms of crypto, 2745 ms
of PUT for 267 Ko. That is the floor for a monolithic container.
This commit is contained in:
r-zakarya
2026-08-21 15:16:12 +01:00
parent bb222e1903
commit bde22d2288
2 changed files with 53 additions and 1 deletions
+21
View File
@@ -708,6 +708,27 @@ save: published, new sha e14eabcf...
48 ms là où le journal disait 4395. Ce qui reste dans l'attente est le GET et 48 ms là où le journal disait 4395. Ce qui reste dans l'attente est le GET et
le PUT vers le dépôt — plus rien de calculatoire. le PUT vers le dépôt — plus rien de calculatoire.
### Ce que coûte réellement un enregistrement — mesuré 2026-08-21
```
save: publishing against the snapshot in hand
save: decrypt+patch in 23 ms
save: re-encrypt in 23 ms
save: PUT 267700 chars in 2745 ms
```
Le calcul pèse 46 ms. **Tout le reste est le conteneur qui monte** : 267 Ko à
chaque écriture, dont l'essentiel est une pièce jointe de 116 Ko. C'est le
plancher de ce format — le conteneur est monolithique, il n'y a pas de
« publier seulement l'entrée modifiée ».
Le tirage préalable, lui, a disparu : il coûtait 3,2 s et ne servait qu'à
s'assurer de modifier la dernière version publiée, ce que le sha prouve
gratuitement. **Conséquence : le chemin 409 est devenu porteur.** C'est lui,
désormais, qui garantit qu'un enregistrement n'écrase pas un autre appareil,
et il n'a toujours jamais tourné. Le provoquer : synchroniser depuis le poste,
puis enregistrer depuis le téléphone sans synchroniser d'abord.
### Ce qui devient facultatif ### Ce qui devient facultatif
Sans dépôt configuré, *Sync* n'a rien à faire : les réglages du serveur Sans dépôt configuré, *Sync* n'a rien à faire : les réglages du serveur
+32 -1
View File
@@ -67,9 +67,15 @@
body.on-detail #list { transform: translateX(-22%); } body.on-detail #list { transform: translateX(-22%); }
body.on-detail #detail { transform: translateX(0); } body.on-detail #detail { transform: translateX(0); }
/* LE CLAVIER RECOUVRE LA PAGE, IL NE LA RETRECIT PAS. Le cadre est cloue a
l'ecran entier, donc quand le clavier monte le contenu ne deborde de rien
et le tiers du bas devient inatteignable : le champ mot de passe du
formulaire ne se voyait qu'en repliant le clavier. Reserver dessous la
hauteur qu'il occupe rend au panneau de quoi defiler. */
.scroll { flex: 1; overflow-y: auto; overflow-x: hidden; .scroll { flex: 1; overflow-y: auto; overflow-x: hidden;
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
overscroll-behavior: contain; padding: 0 12px 16px; } overscroll-behavior: contain;
padding: 0 12px calc(16px + var(--kb, 0px)); }
/* --- barre de recherche ------------------------------------------------ */ /* --- barre de recherche ------------------------------------------------ */
.top { padding: 10px 12px 6px; display: flex; gap: 8px; } .top { padding: 10px 12px 6px; display: flex; gap: 8px; }
@@ -669,6 +675,31 @@ addEventListener('scroll', function (ev) {
if (box && box.scrollLeft && box.id !== 'folders') box.scrollLeft = 0; if (box && box.scrollLeft && box.id !== 'folders') box.scrollLeft = 0;
}, true); }, true);
// LE CLAVIER RECOUVRE LA PAGE, IL NE LA RETRECIT PAS.
//
// Le cadre est cloue a l'ecran entier (position:fixed, inset:0) et le moteur ne
// le redimensionne pas quand le clavier monte : la page garde sa hauteur, le
// clavier passe par-dessus, et le tiers du bas devient inatteignable. Rien ne
// depassait, donc rien ne defilait - le champ mot de passe du formulaire ne se
// voyait qu'en repliant le clavier.
//
// visualViewport donne la hauteur REELLEMENT visible. La reporter sur le corps
// retrecit les vues, le panneau defilant retrouve du contenu en trop, et le
// moteur peut de nouveau amener a l'ecran le champ qui prend le focus.
if (window.visualViewport) {
var vv = window.visualViewport;
// Ce que le clavier RECOUVRE, en pixels. Zero quand il est replie - et zero
// aussi si le moteur retrecit reellement la fenetre, auquel cas le panneau
// deborde tout seul et n'a besoin de rien. La meme mesure repond donc juste
// dans les deux cas, sans qu'on ait a savoir lequel s'applique.
var measureKeyboard = function () {
var hidden = Math.max(0, Math.round(window.innerHeight - vv.height));
document.documentElement.style.setProperty('--kb', hidden + 'px');
};
vv.addEventListener('resize', measureKeyboard);
measureKeyboard();
}
// AUCUN CHAMP D'UNE VUE AU REPOS NE GARDE LE FOCUS. // AUCUN CHAMP D'UNE VUE AU REPOS NE GARDE LE FOCUS.
// //
// Meme origine que le glissement ci-dessus. La touche de validation du clavier // Meme origine que le glissement ci-dessus. La touche de validation du clavier