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
+36 -2
View File
@@ -513,7 +513,10 @@ faire semblant couterait plus que de l'admettre.
**Le reste du travail Android est dans **Le reste du travail Android est dans
[android-client/README.md](android-client/README.md)**, tenu a jour le [android-client/README.md](android-client/README.md)**, tenu a jour le
2026-09-17 : les trois facons d'ouvrir le coffre (verrouillage d'ecran, code 2026-09-28 — dont le formulaire d'edition de l'entree entiere, le scan du QR
2FA, la verification a l'ouverture au lieu du retelechargement, et deux pieges
de la page (`view` qui defocalisait les champs, `toast` qui etait un `<div>`) ;
et avant cela, le 2026-09-17 : les trois facons d'ouvrir le coffre (verrouillage d'ecran, code
d'application, mot de passe), la copie de secours `vault-recover.bin` qui d'application, mot de passe), la copie de secours `vault-recover.bin` qui
survit au schema retire, le scanner de QR (`ThirdParty/ZXing`), le define survit au schema retire, le scanner de QR (`ThirdParty/ZXing`), le define
`AllowCreateLocal` — creer un coffre sur le telephone est reserve au debogage — `AllowCreateLocal` — creer un coffre sur le telephone est reserve au debogage —
@@ -794,7 +797,10 @@ bureau virtuel** en mémoire (GDI, octets bruts, jamais sur disque) et le décod
par ZXing.Delphi — le même que l'APK, `android-client\ThirdParty\ZXing` dans le par ZXing.Delphi — le même que l'APK, `android-client\ThirdParty\ZXing` dans le
chemin de recherche du `.dproj`. Pas de sélection de zone : le décodeur trouve chemin de recherche du `.dproj`. Pas de sélection de zone : le décodeur trouve
le QR où qu'il soit. **Seul un `otpauth://` repart vers la page** le QR où qu'il soit. **Seul un `otpauth://` repart vers la page**
(`Bridge.onScreenQr`), le reste de l'écran ne quitte pas l'exe. Format `BGR32` (`Bridge.onScreenQr(texte, trouvé)`), le reste de l'écran ne quitte pas l'exe.
Le second argument dit qu'**un QR a été lu** même s'il n'est pas un code 2FA :
« This QR code is not a 2FA code » plutôt que « aucun QR » (cas vu : un QR
**dynamique** de générateur en ligne encode un lien de suivi, pas le texte). Format `BGR32`
et non `BGRA32` : l'octet alpha d'une capture GDI vaut 0, lu comme transparent et non `BGRA32` : l'octet alpha d'une capture GDI vaut 0, lu comme transparent
→ image blanche. → image blanche.
@@ -1163,6 +1169,25 @@ QR que l'application Android scanne elle-meme.
- Telephone : `https://github.com/O/R` <-> URL d'API, comme pour Gitea. Le QR - Telephone : `https://github.com/O/R` <-> URL d'API, comme pour Gitea. Le QR
du PC porte aussi la forme courte `github.com/O/R`. du PC porte aussi la forme courte `github.com/O/R`.
### Ce que le depot laisse voir, et le reseau (2026-09-26)
- **Nom par defaut `data.json`** (`SYNC_DEFAULT_FILE`, JS et page du
telephone ; `SyncDefaultFile` dans le QR). `vault-sync.json` annoncait un
coffre a qui parcourt la liste des depots. Les configurations existantes
gardent leur nom : c'est l'URL complete qui est enregistree. **Le QR ne
raccourcit que le nom par defaut courant** — un autre nom voyage en URL
complete, sinon le telephone rallongerait vers `data.json` et les deux
appareils ne liraient pas le meme fichier.
- **Messages de commit neutres** : `update from desktop` / `update from phone`.
Le poste ecrivait `sync from <utilisateur du coffre>`, le telephone decrivait
ce qu'il faisait. Le detail reste dans le journal local.
- **8 s pour se connecter, 30 s pour repondre, trois essais sur status 0**
(poste et telephone). Mesure : `api.github.com` rend plusieurs adresses ;
`140.82.121.5` n'est joignable depuis ce reseau ni par l'application ni par un
navigateur, `140.82.121.6` repond en 0,22 s. Un navigateur passe a la
suivante aussitot ; nous attendions le delai entier. Un 404 ou un 409 sont
des reponses et ne relancent rien.
### Idee gardee : « Reinitialiser l'historique » du depot de synchro ### Idee gardee : « Reinitialiser l'historique » du depot de synchro
**Rien n'est fait, et le code actuel reste tel quel** (decide le 2026-09-17). **Rien n'est fait, et le code actuel reste tel quel** (decide le 2026-09-17).
@@ -1484,6 +1509,15 @@ après chaque `DELETE /attachments/{id}`. Un petit vault sain ne paie rien.
→ retombe sur pwd). → retombe sur pwd).
Fix clipboard : `MinimizeToTray(AClearClipboard=False)` via `keepclip=1` Fix clipboard : `MinimizeToTray(AClearClipboard=False)` via `keepclip=1`
pour ne pas effacer le pwd juste copié quand on re-minimise. pour ne pas effacer le pwd juste copié quand on re-minimise.
**Boutons par ligne** (2026-09-18) : utilisateur, mot de passe ou note, 2FA —
seulement ceux qui existent. Une **note est toujours copiée**, même en Fill :
tapée, chacun de ses retours à la ligne partirait comme un Entrée.
**Interrupteur Copy / Fill** (2026-09-28, `qsFills()`) : visible seulement
quand une fenêtre cible existe (Ctrl+Shift+Q, bouton Search de la barrette).
Depuis le tray, pas de cible — cliquer le tray donne le premier plan à la
barre des tâches — donc copie seule ; suivre « la dernière fenêtre active »
a été écarté : les frappes partiraient au mauvais endroit si l'utilisateur a
changé d'application entre-temps. Choix retenu en pref DPAPI `qsCopy`.
- **Custom fields combobox éditable** : les champs avec `options` (card - **Custom fields combobox éditable** : les champs avec `options` (card
brand, expiry…) rendent un `<input>` + menu custom `.so-combo` (flèche = brand, expiry…) rendent un `<input>` + menu custom `.so-combo` (flèche =
toutes les options, input = frappe libre). PAS un `<datalist>` natif toutes les options, input = frappe libre). PAS un `<datalist>` natif
+75
View File
@@ -341,6 +341,81 @@ reste.
(code, empreinte) **dans le service** avant de proposer quoi que ce soit : le (code, empreinte) **dans le service** avant de proposer quoi que ce soit : le
coffre ne vit que dans l'app, ouverte ou non. 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é ## Saisie : ce qui a résisté
- **`user-select: none` du `body`** était hérité par les champs : le curseur ne - **`user-select: none` du `body`** était hérité par les champs : le curseur ne