chore(android): drop the keyboard diagnostic, and the field only jumps if it must
The trace has served: it named the cause where two rounds of reasoning had missed it. Out with it, and out with the viewport measurement it proved worthless here - a value that is always zero reads as a mechanism, and the next person would trust it. adjustResize goes too. Measured to do nothing: Android ignores the mode for a fullscreen window, which FMX's is. Leaving it in the manifest would suggest it carries something. A field already near the top of the panel - the settings ones - stays where it is. It was visible as it was, and lifting it only moved under the eye what was already fine. The plan keeps what the measurement cost: on this screen, instrument first.
This commit is contained in:
@@ -63,21 +63,11 @@
|
|||||||
<%services%>
|
<%services%>
|
||||||
<!-- Our activity is a subclass of the built-in NativeActivity framework class.
|
<!-- Our activity is a subclass of the built-in NativeActivity framework class.
|
||||||
This will take care of integrating with our NDK code. -->
|
This will take care of integrating with our NDK code. -->
|
||||||
<!-- windowSoftInputMode : LA FENETRE SE RETRECIT QUAND LE CLAVIER MONTE.
|
|
||||||
Sans cela il RECOUVRE la page - le cadre garde sa hauteur, le
|
|
||||||
contenu ne deborde de rien, et le bas du formulaire devient
|
|
||||||
inatteignable : le champ mot de passe ne se voyait qu'en repliant
|
|
||||||
le clavier. Mesure a l'appui, clavier leve : innerHeight et
|
|
||||||
visualViewport.height restaient tous deux a 719, et la boite
|
|
||||||
defilante montrait 659 pour 659 de contenu. La page n'avait aucun
|
|
||||||
moyen d'apprendre que le clavier existait ; c'est la fenetre qui
|
|
||||||
devait le dire. -->
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.embarcadero.firemonkey.FMXNativeActivity"
|
android:name="com.embarcadero.firemonkey.FMXNativeActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="%activityLabel%"
|
android:label="%activityLabel%"
|
||||||
android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"
|
android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"
|
||||||
android:windowSoftInputMode="adjustResize"
|
|
||||||
android:launchMode="singleTask">
|
android:launchMode="singleTask">
|
||||||
<!-- Tell NativeActivity the name of our .so -->
|
<!-- Tell NativeActivity the name of our .so -->
|
||||||
<meta-data android:name="android.app.lib_name" android:value="%libNameValue%" />
|
<meta-data android:name="android.app.lib_name" android:value="%libNameValue%" />
|
||||||
|
|||||||
@@ -729,6 +729,37 @@ 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,
|
et il n'a toujours jamais tourné. Le provoquer : synchroniser depuis le poste,
|
||||||
puis enregistrer depuis le téléphone sans synchroniser d'abord.
|
puis enregistrer depuis le téléphone sans synchroniser d'abord.
|
||||||
|
|
||||||
|
### Le clavier : personne ne dit ce qu'il recouvre — 2026-08-21
|
||||||
|
|
||||||
|
Le bas du formulaire restait sous le clavier, sans moyen d'y accéder. **Trois
|
||||||
|
sources ont été interrogées sur ce qu'il recouvre, les trois répondent comme
|
||||||
|
s'il n'existait pas** :
|
||||||
|
|
||||||
|
- `visualViewport.height` — identique à `innerHeight`, clavier levé ;
|
||||||
|
- `innerHeight` — inchangé, la fenêtre reste en plein écran ;
|
||||||
|
- `android:windowSoftInputMode="adjustResize"` — sans effet : Android l'ignore
|
||||||
|
pour une fenêtre plein écran, ce qu'est celle de FMX. Retiré, pour ne pas
|
||||||
|
laisser croire qu'il porte quelque chose.
|
||||||
|
|
||||||
|
La mesure qui a tranché, clavier levé :
|
||||||
|
|
||||||
|
```
|
||||||
|
focus: inner 719 visual 719 | box client 659 scroll 659 | body=on-detail
|
||||||
|
```
|
||||||
|
|
||||||
|
`client` = ce que la boîte montre, `scroll` = ce qu'elle contient. Égaux :
|
||||||
|
aucun débordement, donc rien à faire défiler. Le clavier recouvrait le bas
|
||||||
|
d'une page qui se croyait en pleine hauteur.
|
||||||
|
|
||||||
|
**On a donc cessé de demander.** Le temps de la saisie, le panneau réserve 60 %
|
||||||
|
de hauteur sous son contenu — c'est du débordement, donc ça défile — et le champ
|
||||||
|
focalisé remonte en haut, mais **seulement s'il est dans le bas du panneau** :
|
||||||
|
un champ déjà visible ne doit pas sauter sous l'œil pour rien.
|
||||||
|
|
||||||
|
Deux corrections antérieures, posées par raisonnement sans instrument,
|
||||||
|
reposaient toutes deux sur une mesure qui vaut zéro ici. La leçon vaut d'être
|
||||||
|
écrite : sur cet écran, **instrumenter 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
|
||||||
|
|||||||
+23
-54
@@ -75,7 +75,7 @@
|
|||||||
.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;
|
overscroll-behavior: contain;
|
||||||
padding: 0 12px calc(16px + var(--kb, 0px)); }
|
padding: 0 12px 16px; }
|
||||||
/* DE LA PLACE SOUS LE CONTENU PENDANT QU'ON TAPE, et rien a mesurer.
|
/* DE LA PLACE SOUS LE CONTENU PENDANT QU'ON TAPE, et rien a mesurer.
|
||||||
Le clavier recouvre la page sans que rien ne le dise : ni la fenetre, qui
|
Le clavier recouvre la page sans que rien ne le dise : ni la fenetre, qui
|
||||||
reste en plein ecran, ni visualViewport, qui rapporte la meme hauteur
|
reste en plein ecran, ni visualViewport, qui rapporte la meme hauteur
|
||||||
@@ -684,66 +684,35 @@ 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 CLAVIER RECOUVRE LA PAGE, ET PERSONNE NE LE DIT.
|
||||||
//
|
//
|
||||||
// Le cadre est cloue a l'ecran entier (position:fixed, inset:0) et le moteur ne
|
// Le cadre est cloue a l'ecran entier et le moteur ne le redimensionne pas
|
||||||
// le redimensionne pas quand le clavier monte : la page garde sa hauteur, le
|
// quand le clavier monte. Trois sources ont ete interrogees sur ce qu'il
|
||||||
// clavier passe par-dessus, et le tiers du bas devient inatteignable. Rien ne
|
// recouvre - visualViewport, innerHeight, la fenetre elle-meme via
|
||||||
// depassait, donc rien ne defilait - le champ mot de passe du formulaire ne se
|
// windowSoftInputMode - et les trois repondent comme s'il n'existait pas :
|
||||||
// voyait qu'en repliant le clavier.
|
// clavier leve, la boite defilante montrait 659 pour 659 de contenu. Aucun
|
||||||
|
// debordement, donc rien a faire defiler, et le bas du formulaire restait
|
||||||
|
// sous le clavier definitivement.
|
||||||
//
|
//
|
||||||
// visualViewport donne la hauteur REELLEMENT visible. La reporter sur le corps
|
// On cesse donc de demander. Le temps de la saisie, le panneau reserve de la
|
||||||
// retrecit les vues, le panneau defilant retrouve du contenu en trop, et le
|
// place sous son contenu (body.typing, plus haut) - c'est du debordement, donc
|
||||||
// moteur peut de nouveau amener a l'ecran le champ qui prend le focus.
|
// ca defile - et le champ focalise remonte en haut, la ou aucun clavier ne
|
||||||
if (window.visualViewport) {
|
// peut l'atteindre quelle que soit sa hauteur.
|
||||||
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');
|
|
||||||
reportBox('keyboard');
|
|
||||||
};
|
|
||||||
vv.addEventListener('resize', measureKeyboard);
|
|
||||||
measureKeyboard();
|
|
||||||
} else {
|
|
||||||
window._noVisualViewport = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DIAGNOSTIC, temporaire. Deux corrections posees a l'aveugle n'ont rien
|
|
||||||
// change ; celle-ci dit ce que la page mesure vraiment, dans le journal plutot
|
|
||||||
// qu'en message fugace, pour qu'on puisse la lire apres coup.
|
|
||||||
function reportBox(why) {
|
|
||||||
// PM n'existe pas encore au chargement : cette fonction tourne aussi avant
|
|
||||||
// lui, et on ne va pas casser la page pour une trace.
|
|
||||||
// Les trois vues sont TOUTES dans le document - c'est un rail, rien n'est
|
|
||||||
// masque - donc la vue active se designe par son nom, pas par sa visibilite.
|
|
||||||
if (!window.PM || !PM.log) return;
|
|
||||||
var box = document.getElementById(view);
|
|
||||||
box = box && box.querySelector('.scroll');
|
|
||||||
var vh = window.visualViewport ? Math.round(window.visualViewport.height) : -1;
|
|
||||||
var sc = document.body.className || '(none)';
|
|
||||||
if (!box) { PM.log(why + ': no scroll box, body=' + sc); return; }
|
|
||||||
// clientHeight = ce que la boite montre, scrollHeight = ce qu'elle contient.
|
|
||||||
// Egaux, il n'y a rien a faire defiler, et c'est TOUT le probleme.
|
|
||||||
PM.log(why + ': inner ' + window.innerHeight + ' visual ' + vh
|
|
||||||
+ ' | box client ' + box.clientHeight + ' scroll ' + box.scrollHeight
|
|
||||||
+ ' | body=' + sc);
|
|
||||||
}
|
|
||||||
document.addEventListener('focusin', function (ev) {
|
document.addEventListener('focusin', function (ev) {
|
||||||
var el = ev.target;
|
var el = ev.target;
|
||||||
if (!el.classList || !el.classList.contains('field-in')) return;
|
if (!el.classList || !el.classList.contains('field-in')) return;
|
||||||
document.body.classList.add('typing');
|
document.body.classList.add('typing');
|
||||||
// Le champ remonte EN HAUT du panneau : la ou le clavier ne peut pas
|
// Differe d'un tour : la place reservee ci-dessus n'est pas encore prise en
|
||||||
// l'atteindre, quelle que soit sa hauteur. Differe d'un tour, sinon la place
|
// compte, et il n'y aurait nulle part ou remonter.
|
||||||
// reservee ci-dessus n'est pas encore prise en compte et il n'y a nulle part
|
|
||||||
// ou remonter.
|
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
var row = el.closest ? el.closest('.field, .in-wrap') : null;
|
var row = el.closest && el.closest('.field, .in-wrap');
|
||||||
if (row && row.scrollIntoView) row.scrollIntoView({ block: 'start' });
|
var box = el.closest && el.closest('.scroll');
|
||||||
reportBox('focus');
|
if (!row || !box || !row.scrollIntoView) return;
|
||||||
|
// NE BOUGER QUE SI C'EST UTILE. Un champ deja dans le haut du panneau -
|
||||||
|
// celui des reglages, par exemple - est visible tel quel, et le faire
|
||||||
|
// sauter quand meme ne fait que deplacer sous l'oeil ce qui allait bien.
|
||||||
|
var top = row.getBoundingClientRect().top - box.getBoundingClientRect().top;
|
||||||
|
if (top > box.clientHeight * 0.4) row.scrollIntoView({ block: 'start' });
|
||||||
}, 250);
|
}, 250);
|
||||||
});
|
});
|
||||||
document.addEventListener('focusout', function () {
|
document.addEventListener('focusout', function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user