docs(android): the plan catches up with the HTML interface

Section 3 bis asked whether Delphi controls were needed at all and said to decide before investing further in the interface. It is decided, so it now records the answer and the two traps buried in the bridge - the iframe, and the page having to stay ASCII - rather than leaving them to be re-discovered.

Section 1 ter described Skia as the fix for Arabic; it is gone, and what survives of that episode is the packaging constraint, which still governs the build.

The table in section 0 claimed template, icons, attachments, timestamps and folders were unread. They are read now; it says which parts, and what is genuinely still missing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-08-17 10:53:02 +01:00
parent 77809b09c8
commit b3fbaf44bd
+73 -48
View File
@@ -1,6 +1,6 @@
# Client Android — ce qu'il reste à faire # Client Android — ce qu'il reste à faire
État au 2026-08-15. Le client lit l'instantané et l'affiche ; il n'écrit rien. État au 2026-08-17. Le client lit l'instantané et l'affiche ; il n'écrit rien.
Ce document liste le reste, dans l'ordre où je le ferais. Ce document liste le reste, dans l'ordre où je le ferais.
Voir [README.md](README.md) pour l'architecture et les décisions déjà prises. Voir [README.md](README.md) pour l'architecture et les décisions déjà prises.
@@ -18,18 +18,21 @@ manques côté téléphone ne demandent **aucun** changement côté serveur.
| `folder`, `tags`, `kind` | oui | oui | | `folder`, `tags`, `kind` | oui | oui |
| `totp_secret` | oui | oui | | `totp_secret` | oui | oui |
| `custom_fields` (`label`/`value`/`is_secret`) | oui | oui | | `custom_fields` (`label`/`value`/`is_secret`) | oui | oui |
| `template` (carte, clé SSH, serveur…) | oui | **non** | | `template` (carte, clé SSH, serveur…) | oui | oui — ligne *Type* |
| `icon_b64`, `icon_custom` | oui | **non** | | `icon_b64` | oui | oui — pastille de la liste |
| `attachments` (avec `content_b64`) | oui | **non** | | `icon_custom` | oui | non — la provenance ne change rien à l'affichage |
| `created_at`, `updated_at` | oui | **non** | | `attachments` — nom, type, taille | oui | oui — nommées, pas ouvrables |
| `folders` (liste, couleur, icône) | oui | **non** | | `attachments` — `content_b64` | oui | **non** — c'est l'enregistrement qui manque |
| `updated_at` | oui | oui |
| `created_at` | oui | **non** |
| `folders` (liste, couleur, icône) | oui | oui — le nom seulement |
| `avatar_b64`, `username` (compte) | oui | **non** | | `avatar_b64`, `username` (compte) | oui | **non** |
| `tombstones` | oui | **non** | | `tombstones` | oui | **non** — n'aura de sens qu'avec l'écriture |
| `favorite`, `pinned` | **non** — device-local par conception | — | | `favorite`, `pinned` | **non** — device-local par conception | — |
| corbeille | **non** — voyage dans les sauvegardes, pas la sync | — | | corbeille | **non** — voyage dans les sauvegardes, pas la sync | — |
Autrement dit : dossiers, icônes, pièces jointes et horodatages sont déjà là, Ce qui manque encore ne demande donc **rien** au poste Windows : c'est de la
il ne manque que la lecture. Seules les favoris/épinglés et la corbeille lecture côté téléphone. Seules les favoris/épinglés et la corbeille
demanderaient une décision côté Windows — et pour les deux, la décision demanderaient une décision côté Windows — et pour les deux, la décision
actuelle est délibérée. actuelle est délibérée.
@@ -145,22 +148,27 @@ confort, ce qui est le mauvais sens pour un gestionnaire de mots de passe.
</details> </details>
## 1 ter. Écritures complexes — Skia (2026-08-15) ## 1 ter. ~~Écritures complexes — Skia~~ — DEVENU INUTILE le 2026-08-17
Un nom de pièce jointe en arabe s'affichait en désordre. Ce n'était pas un Un nom de pièce jointe en arabe s'affichait en désordre : le moteur de texte
réglage manqué : le moteur de texte d'origine de FMX ne met pas en forme les d'origine de FMX ne met pas en forme les écritures complexes — pas de
écritures complexes — pas de réordonnancement bidirectionnel, pas de liaison réordonnancement bidirectionnel, pas de liaison des lettres. `GlobalUseSkia`
des lettres. Séparer la taille du nom limitait les dégâts sans les supprimer. réglait cela, au prix de `libsk4d.so` (25 Mo) et d'un **APK passé de 13 à 22 Mo**.
`GlobalUseSkia := True` avant `Application.Initialize` remplace le moteur de **Retiré**, avec le style vendu, quand l'interface est passée au moteur du
rendu ; Skia embarque HarfBuzz et fait ce travail. Le prix est `libsk4d.so`, système (§3 bis) : Skia ne servait qu'aux libellés FMX, et il n'en reste aucun.
25 Mo (8,9 Mo compressés), et un **APK qui passe de 13 à 22 Mo**. Le moteur fait sa propre mise en forme — vérifié sur l'appareil, le même nom
arabe se lit correctement. L'APK **retombe à 12,7 Mo**.
Conséquence sur la fabrication : `Deploy` reconstruit `library\lib` avant Ce qui reste vrai de cet épisode, et qui gouverne encore la fabrication :
`aapt`, donc la bibliothèque posée à la main disparaît. D'où `Deploy` reconstruit `library\lib` avant `aapt`, donc tout ce qu'on y pose à la
main disparaît — aujourd'hui nos icônes, hier Skia. D'où
[repack-apk.ps1](repack-apk.ps1), qui refait *aapt → zipalign → signature* sur [repack-apk.ps1](repack-apk.ps1), qui refait *aapt → zipalign → signature* sur
le dossier déjà prêt. Une entrée `DeployFile` en bonne et due forme a été le dossier déjà prêt. Une entrée `DeployFile` en bonne et due forme a été
tentée d'abord : MSBuild l'ignore, comme il ignore toutes les autres ici. tentée d'abord : MSBuild l'ignore, comme il ignore toutes les autres ici.
[build-apk.ps1](build-apk.ps1) enchaîne les quatre étapes, y compris la
régénération de `web.res` — l'oublier embarque la page d'avant l'édition, et le
symptôme se lit alors comme un bug applicatif.
## 2. Durcissement — petit, à faire avant tout usage réel ## 2. Durcissement — petit, à faire avant tout usage réel
@@ -222,49 +230,66 @@ Rangé par ce que ça apporte réellement sur un téléphone.
À surveiller : quelques PDF suffiraient à peser plusieurs Mo, retéléchargés À surveiller : quelques PDF suffiraient à peser plusieurs Mo, retéléchargés
entièrement à chaque instantané nouveau. entièrement à chaque instantané nouveau.
2. ~~**Filtre dossier**~~ — **fait**, liste déroulante à côté de la recherche, 2. ~~**Filtre dossier**~~ — **fait**, une rangée de pastilles avec leur compte,
alimentée par le tableau `folders`, et le choix survit à un rafraîchissement alimentée par le tableau `folders`. Le filtrage se fait dans la page, donc
de fond. **Pas de filtre d'étiquette** : la recherche texte couvre déjà les sans aller-retour, et le choix survit à un rafraîchissement de fond. **Pas de filtre d'étiquette** : la recherche texte couvre déjà les
étiquettes, en taper le nom suffit. étiquettes, en taper le nom suffit.
3. ~~**Icônes**~~ (`icon_b64`) — **fait**, décodées une fois par coffre et non à 3. ~~**Icônes**~~ (`icon_b64`) — **fait**. Elles descendent telles quelles dans
chaque frappe (la liste est reconstruite à chaque caractère). Une icône SVG la page, en URI `data:` : le moteur décode, y compris le SVG, que FMX ne
n'est pas chargeable par FMX : l'entrée retombe sur ses initiales. savait pas charger. Sans icône, l'entrée retombe sur son initiale.
4. ~~**`template`**~~ — **fait**, affiché comme *Type* dans le détail. Adapter 4. ~~**`template`**~~ — **fait**, affiché comme *Type* dans le détail. Adapter
en plus les intitulés d'une carte bancaire reste à voir. en plus les intitulés d'une carte bancaire reste à voir.
5. ~~**Tri par nom**~~ — **fait** dans `TVault.Search`. L'ordre de l'instantané 5. ~~**Tri par nom**~~ — **fait** dans `TVault.Search`. L'ordre de l'instantané
est celui de la base, donc arbitraire à l'œil. est celui de la base, donc arbitraire à l'œil.
6. **`TListView` à la place de `TListBox`** le jour où la reconstruction à 6. **Liste virtuelle** le jour où la reconstruction à chaque frappe se voit. Le
chaque frappe se voit. Marqué `ponytail:` dans le code, pas avant. `innerHTML` complet est refait à chaque caractère ; sur quelques centaines
d'entrées c'est imperceptible. Marqué `ponytail:` dans la page, pas avant.
--- ---
## 3 bis. Deux questions ouvertes sur l'interface ## 3 bis. ~~Faudrait-il des composants Delphi du tout ?~~ — TRANCHÉ le 2026-08-17
**Le thème n'est pas encore celui de la recherche globale.** Le bleu et la **Non. Il n'en reste aucun.** Les trois écrans sont une page HTML rendue par le
pilule ont été repris, pas le reste : espacements, élévation, densité. À moteur du système ([web/app.html](web/app.html), servie par
reprendre capture en main plutôt qu'au jugé. [PMA.WebUI.pas](PMA.WebUI.pas)). Une sonde a décidé plutôt qu'un débat : la même
liste peinte par le moteur, en quarante lignes de CSS, rendait mieux que ce qui
avait coûté la journée à peindre à la main — et mettait l'arabe en forme seule.
**Et faudrait-il des composants Delphi du tout ?** Le poste Windows n'affiche Ce que la migration a réglé, et qui revenait à chaque écran : un gabarit absent
pas de contrôles natifs : il sert `js/app.js` et `css/style.css` dans un du style chargé, un ordre d'alignement laissé au hasard, un `HitTest` qui avale
WebView2. Le même montage est possible ici — `TWebBrowser` encapsule le WebView un appui, une vue native qui se peint par-dessus tout. Le dernier à partir a été
d'Android — et il réglerait d'un coup ce qui a coûté le plus cher aujourd'hui : l'écran de déverrouillage, pour une raison précise : dans un `TEdit` Android le
plus de gabarits de style à contourner, plus d'ordre d'empilement à deviner, curseur ne se place pas où on le touche, donc un jeton long est incorrigible.
une seule feuille de style pour les deux clients.
Ce que ça demanderait, honnêtement : **Le pont n'ouvre aucun port.** `evaluateJavascript` descend les données,
une navigation `cmd://` interceptée remonte les actions. Deux pièges y sont
enterrés, à ne pas re-découvrir :
- Un **pont** vers le Keystore, la biométrie et le presse-papiers, comme le - FMX répond **toujours** au moteur qu'il n'a pas pris la navigation en charge.
`cmd://` du poste. Ces trois-là resteront en Delphi de toute façon. Sur un schéma inconnu, le moteur essaie donc de la charger et remplace la page
- Une **disposition mobile** dans le frontend, qui est écrit pour un écran par son écran d'erreur. D'où l'**iframe jetable**, où l'échec reste confiné.
large. C'est le vrai coût, et il est dans `js/`, pas ici. - Le chargement de la page ne transporte pas l'encodage
- Trancher où vit le HTML : servi par un serveur local comme sur le poste, ou (`loadDataWithBaseURL` reçoit `nil`), et `Navigate` refuse une URL `data:`.
chargé depuis les ressources de l'application. **`app.html` doit donc rester en ASCII pur** ; les données, elles, passent par
une chaîne JNI et n'ont pas ce problème.
La crypto, elle, ne changerait pas de camp : `WebCrypto` fait déjà tout ce que **Les secrets ne traversent pas le pont.** La liste reçoit noms, sites et
`PMA.Crypto` fait, et c'est le poste qui écrit le format. identifiants — ce qui est déjà à l'écran. Copier depuis une ligne envoie un
**rang**, et Delphi relit le coffre chez lui. Seule l'entrée ouverte a ses
valeurs dans le tas JS, effacées par `PM.wipe` au verrouillage.
À décider avant d'investir davantage dans l'interface actuelle — chaque Reste en Delphi, et y restera : Keystore, biométrie, presse-papiers sensible,
correction d'affichage faite aujourd'hui serait perdue. `FLAG_SECURE`, réseau, déchiffrement.
**Ce que `js/` n'a pas donné.** Le CSS du poste est réutilisable presque tel
quel et c'est lui qui porte l'apparence ; `app.js` non — 12 000 lignes qui
supposent la session, le CSRF et l'API complète. La page du téléphone est
autonome.
**Le thème n'est pas encore exactement celui de la recherche globale.** Le
dégradé, les blocs translucides et les arrondis sont repris ; espacements,
élévation et densité restent au jugé. C'est maintenant du CSS, donc peu coûteux
à reprendre capture en main.
## 4. Le chemin d'écriture — le gros morceau ## 4. Le chemin d'écriture — le gros morceau