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:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user