docs: formulaire d'edition, scan QR 2FA, synchro et reseau, Copy / Fill

CLAUDE.md : interrupteur Copy / Fill de la recherche rapide et pourquoi le
tray copie seulement ; QR lu mais pas de 2FA ; nom par defaut data.json,
messages de commit neutres, 8 s / 3 essais sur le reseau.
README Android : edition de l'entree entiere en un commit, oeil, icone depuis
la galerie, scan 2FA ; verification a l'ouverture, depot vide = creation ; les
pieges 'view' qui defocalisait les champs et 'toast' qui etait un <div>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-09-28 18:42:12 +01:00
parent 8d3e20b702
commit 247771bfec
2 changed files with 111 additions and 2 deletions
+75
View File
@@ -341,6 +341,81 @@ reste.
(code, empreinte) **dans le service** avant de proposer quoi que ce soit : le
coffre ne vit que dans l'app, ouverte ou non.
## Modifier une entrée — 2026-09-25 à 09-28
**Un formulaire pour toute l'entrée**, ouvert par le crayon de l'en-tête. Le
crayon par ligne a disparu : chaque validation était un enregistrement complet,
donc un commit de plus dans le dépôt.
- **Un seul envoi, seulement ce qui a changé** : `setfields?f0=&v0=&f1=&v1=…`
→ `SaveEntryFields`, plusieurs `PatchEntryField` dans **un** `CommitChange`.
Le filtre des noms est celui de `SaveEntryField` (ce qui traverse le pont se
traite comme une entrée extérieure).
- **La page ne connaît pas le schéma** : elle rend une ligne par champ que
Delphi a marqué modifiable (`e` porte son nom, dans `DetailToJson`). Le champ
`folder` est une liste (`folderSelect`, avec *+ new folder*), pas un champ
libre — une faute de frappe rangerait l'entrée dans un dossier invisible.
- **Mot de passe et secret 2FA naissent masqués** (création et édition), avec
un œil (`data-eye`) pour les révéler.
- **Icône** en tête du formulaire, trois boutons : *From site* (recherche
automatique), *Image…* (sélecteur de photos d'Android via
`TTakePhotoFromLibraryAction`, réduite à 128 px, provenance **custom** — le
poste ne la remplacera jamais par une recherche), *Remove*. Une action
d'icône passe par un enregistrement : le formulaire est rouvert ensuite avec
ce qui y était tapé (`editAgain`). Manifeste : `READ_MEDIA_IMAGES`, et
`READ_EXTERNAL_STORAGE` bornée à `maxSdkVersion="32"`.
- **Scanner le QR 2FA** d'un site : bouton QR du champ 2FA →
`scanqr?for=totp` → même caméra que le scan des réglages (`FScanTotp`). Le
lien `otpauth://` part à la page (`PM.totpFromQr`), qui n'en garde que le
secret ; le journal ne note que le fait. Un autre QR fait dire au bandeau
« pas un code 2FA » et le scan continue.
- **Pas de menu ⋮ ni de crayon sur une entrée en création** : l'écran de
détail est réutilisé, et côté Delphi ces commandes visent la **dernière
entrée ouverte** — *Delete* depuis la création en aurait supprimé une autre.
### Piège : `view` nomme l'écran, pas ce qu'on y fait
Un gardien `focusin` défocalise tout ce qui prend le focus hors de l'écran
courant en comparant `view` à l'**identifiant de l'écran**. Le formulaire vit
dans l'écran `detail` ; poser `view = 'edit'` le faisait donc défocaliser
**chaque champ à l'instant où il prenait le focus** — clavier ouvert, pas de
curseur, rien ne rentrait. Trouvé en inspectant la page en direct par le
protocole DevTools (APK debug, `adb forward … localabstract:webview_devtools_remote_…`) :
le champ était atteignable et focalisé, ce qui éliminait le DOM et le CSS.
`view` reste `detail`, un drapeau `editing` dit qu'on modifie, et la flèche
comme la touche retour referment le formulaire avant de quitter l'entrée.
### Piège : `toast` était un `<div>`
Le navigateur expose chaque `id` comme variable globale : `toast` désignait
l'élément `<div id="toast">`, et **sept appels `toast('…')` de la page levaient
« toast is not a function »** — le message ne s'affichait pas et le reste du
gestionnaire ne s'exécutait pas (dont « Tap again to delete »). Une vraie
`function toast(text)` globale l'emporte sur l'id.
## Synchro : ce qui a changé — 2026-09-25 à 09-26
- **L'ouverture ne tire plus l'instantané.** Elle ouvre depuis le cache, puis
`ProbeRemote` pose une requête conditionnelle : si le dépôt a bougé, le
témoin **bleu** du bouton Sync s'allume et l'utilisateur tire quand il veut.
Le journal dit les trois cas : `unchanged`, `it moved`, `no answer (HTTP 0)`
— ce dernier n'est pas « rien n'a changé ».
- **Dépôt vide = création.** Un 404 à la lecture pendant une publication était
traité comme un échec : rien ne partait jamais vers un dépôt neuf. Sans `sha`,
l'API des contenus crée le fichier.
- **Réseau : 8 s pour se connecter, 30 s pour répondre, trois essais**, et
`Connection: close`. Mesuré : `api.github.com` rend plusieurs adresses,
`140.82.121.6` répond en 0,22 s et `140.82.121.5` n'est joignable depuis ce
réseau **ni par l'application ni par un navigateur**. Un navigateur passe à
la suivante aussitôt ; l'application attendait son délai entier. Le poste
applique la même règle.
- **Pas de clavier de recherche pendant une synchro** : synchroniser coffre
fermé ouvre d'abord le coffre, et ce chemin dépliait le clavier.
- **Messages de commit neutres** : `update from phone` partout (le téléphone
écrivait `new entry from phone`, `icon fetched…`, `entries deleted…`). Le
détail reste dans le journal local.
- **Nom par défaut `data.json`** au lieu de `vault-sync.json` — voir CLAUDE.md.
## Saisie : ce qui a résisté
- **`user-select: none` du `body`** était hérité par les champs : le curseur ne