feat(android): tell when the repository has moved, without adopting it

A probe every ten minutes compares the remote fingerprint to ours and lights
an indicator. It does not pull: adopting on its own while someone is reading
an entry would change it under their eyes. The user decides when.

The body is downloaded anyway - Gitea's contents API cannot answer without it
- but it is thrown away undecrypted: no derivation, no write, just a string
comparison. The cost is network, not time or battery.

It rides the idle timer rather than a second one. That timer already beats
every 15 seconds for auto-lock; counting its beats costs an integer, where
another timer costs an object, a lifecycle, and one more chance to forget it
on shutdown.

Two indicators, two colours, two gestures. Orange: things wait HERE and the
repository does not know. Blue: the repository holds things we do not have.
One dot for both would say "something is wrong" without saying what - and one
is resolved by publishing, the other by fetching.
This commit is contained in:
r-zakarya
2026-08-22 15:28:41 +01:00
parent 92ceb1e8c9
commit 4ae845bc13
3 changed files with 119 additions and 7 deletions
+17 -3
View File
@@ -106,12 +106,26 @@ prouve rien.
5. Touche **retour** pendant une sélection → elle s'annule **sans verrouiller**.
6. Sur le poste, synchroniser → les suppressions doivent y être répercutées.
### E. Pièces jointes
### E. Le dépôt a bougé — témoin bleu
1. Coffre ouvert sur le téléphone, **le laisser ouvert**.
2. Sur le poste, modifier une entrée et synchroniser.
3. Attendre — la vérification bat toutes les **dix minutes**. Le journal doit
dire `remote has moved - sync to bring it in`, et un **point bleu** paraître
sur *Sync* et sur le cadenas.
4. **Rien ne doit changer à l'écran de soi-même.** Si l'entrée qu'on regarde se
met à jour toute seule, c'est que le sondage adopte au lieu de signaler.
5. *Sync* → le point bleu s'éteint.
6. Les deux ensemble : provoquer A puis E sans synchroniser → **orange et bleu
côte à côte**. Ils demandent deux gestes différents ; les confondre dirait
« quelque chose ne va pas » sans dire quoi.
### F. Pièces jointes
1. Ligne *Attachment* → flèche de téléchargement → le fichier apparaît dans
*Téléchargements* sous son nom, accents et arabe compris.
### F. Code de déverrouillage
### G. Code de déverrouillage
1. Poser un code, ouvrir le coffre, fermer, rouvrir → il est demandé.
2. Code faux → *« Wrong unlock code »*, et **Open vault reste offert** (le
@@ -121,7 +135,7 @@ prouve rien.
4. Contre-épreuve : taper n'importe quoi dans le champ du code puis *Sync* →
le code **ne doit pas changer**.
### G. Empaquetage
### H. Empaquetage
1. `build-apk.ps1 -Release -Keystore ... -Alias ...` → la sortie doit afficher
`Signer #1 certificate DN: CN=R Zakarya`. Si elle affiche `CN=Android
+19 -4
View File
@@ -181,12 +181,21 @@
.btn.ico-btn:active { opacity: .45; }
/* Le point des modifications en attente. Sur le cadenas parce qu'il est
toujours a l'ecran de la liste, et qu'il parle deja de l'etat du coffre. */
.ico.pending, .btn.pending { position: relative; }
.ico.pending::after, .btn.pending::after {
content: ''; position: absolute; top: 6px; right: 6px;
/* DEUX TEMOINS, DEUX COULEURS, DEUX GESTES.
Orange : des choses attendent ICI et le depot les ignore.
Bleu : le depot porte des choses que nous n'avons pas.
Les confondre en un seul point dirait "quelque chose ne va pas" sans dire
quoi - or l'un se resout en publiant, l'autre en tirant. */
.ico.pending, .btn.pending, .ico.ahead, .btn.ahead { position: relative; }
.ico.pending::after, .btn.pending::after,
.ico.ahead::before, .btn.ahead::before {
content: ''; position: absolute; top: 6px;
width: 9px; height: 9px; border-radius: 50%;
background: #ffb44d; box-shadow: 0 0 0 2px var(--bg-top);
box-shadow: 0 0 0 2px var(--bg-top);
}
.ico.pending::after, .btn.pending::after { right: 6px; background: #ffb44d; }
/* Decale, pour que les deux se voient ensemble quand les deux sont vrais. */
.ico.ahead::before, .btn.ahead::before { right: 20px; background: #5ec8ff; }
@keyframes spin { to { transform: rotate(360deg); } }
/* L'ENREGISTREMENT DURE UNE A DEUX SECONDES, et le bouton doit le dire. Le
mot "Saving..." le disait ; une coche immobile ne dirait rien, et c'est
@@ -1477,6 +1486,12 @@ var PM = {
document.getElementById('lock').classList.toggle('pending', !!on);
document.getElementById('btnSync').classList.toggle('pending', !!on);
},
/// LE DEPOT A BOUGE. Signale, jamais adopte de soi-meme : tirer pendant que
/// quelqu'un lit une entree la ferait changer sous ses yeux.
setRemoteAhead: function (on) {
document.getElementById('lock').classList.toggle('ahead', !!on);
document.getElementById('btnSync').classList.toggle('ahead', !!on);
},
setBusy: function (on) {
if (on) document.getElementById('busy').firstChild.innerHTML =
ico('loader', 'Working') + '<span>Please wait...</span>';