diff --git a/android-client/PMA.Store.pas b/android-client/PMA.Store.pas index 837d88e..4d19337 100644 --- a/android-client/PMA.Store.pas +++ b/android-client/PMA.Store.pas @@ -151,6 +151,20 @@ procedure SaveLocalContainer(const AContainer: string); /// c'est le geste qui fait passer l'autorite au depot, et il est sans retour. procedure DropLocalContainer; +/// DES MODIFICATIONS ATTENDENT D'ETRE PUBLIEES. +/// +/// UN FICHIER A PART, ET NON UN CHAMP DU CACHE : ce drapeau ne porte aucun +/// secret - sa seule information est "oui" ou "non" -, il n'a donc rien a +/// faire dans un blob chiffre dont l'ecriture coute une derivation et dont la +/// signature est deja longue de neuf parametres. +/// +/// IL DOIT SURVIVRE A UN REDEMARRAGE. En memoire seulement, une application +/// tuee entre l'enregistrement hors ligne et la publication oubliait qu'elle +/// avait quelque chose a envoyer - et le rafraichissement suivant remplacait +/// le cache par la version du depot, effacant la modification sans un mot. +function HasPendingFlag: Boolean; +procedure SetPendingFlag(AOn: Boolean); + /// Chemin du fichier, pour le journal et les tests. function VaultPath: string; @@ -184,6 +198,7 @@ uses const VAULT_FILE = 'vault.bin'; LOCAL_FILE = 'vault-local.json'; + PENDING_FILE = 'pending.flag'; SETTINGS_FILE = 'settings.bin'; // Un alias par schema : la contrainte d'authentification est figee a la // creation de la cle et ne peut pas etre ajoutee apres coup. @@ -259,6 +274,27 @@ begin TFile.Delete(LocalContainerPath); end; +function PendingPath: string; +begin + Result := TPath.Combine(TPath.GetHomePath, PENDING_FILE); +end; + +function HasPendingFlag: Boolean; +begin + Result := TFile.Exists(PendingPath); +end; + +procedure SetPendingFlag(AOn: Boolean); +begin + try + if AOn then TFile.WriteAllText(PendingPath, '1') + else if TFile.Exists(PendingPath) then TFile.Delete(PendingPath); + except + // Un drapeau qu'on n'a pas pu ecrire ne doit pas faire echouer un + // enregistrement qui, lui, a reussi. + end; +end; + function VaultPath: string; begin // GetHomePath sur Android = /data/data//files, prive a l'app. diff --git a/mainApk.pas b/mainApk.pas index dcbff20..7dc3cc2 100644 --- a/mainApk.pas +++ b/mainApk.pas @@ -390,6 +390,9 @@ begin IFMXApplicationEventService, LEvents) then LEvents.SetApplicationEventHandler(HandleAppEvent); + // AVANT TOUT RAFRAICHISSEMENT : sans cela le premier tirage remplacerait le + // cache par la version du depot, et ce qui attend ici serait perdu. + FPending := HasPendingFlag; PushConfig; ShowUnlock; {$IFNDEF DEBUG} @@ -976,6 +979,7 @@ begin end; AdoptVault(LNew); FPending := not LPublished; + SetPendingFlag(FPending); WebCall(Format('PM.setPending(%s)', [LowerCase(BoolToStr(FPending, True))])); if LPublished then @@ -1141,6 +1145,7 @@ begin if LDone then begin FPending := False; + SetPendingFlag(False); AdoptVault(LMerged); Log('pending changes published, new sha ' + FETag); WebCall('PM.setPending(false)'); @@ -1930,6 +1935,8 @@ begin end; end; + WebCall(Format('PM.setPending(%s)', + [LowerCase(BoolToStr(FPending, True))])); try LSw := TStopwatch.StartNew; AdoptVault(LPlain); @@ -2286,6 +2293,18 @@ begin FETag := LRes.ETag; Log(' decrypted in ' + LSw.ElapsedMilliseconds.ToString + ' ms'); + // CE QUI ATTEND ICI NE SE FAIT PAS ECRASER. Le rafraichissement + // remplacait le cache par la version du depot : une modification faite + // hors connexion disparaissait alors sans un mot, et c'est exactement + // ce que l'enregistrement hors ligne promet d'eviter. + // + // On garde le drapeau : fondre ne publie pas. + if FPending and (FPlain <> '') then + begin + LPlain := MergeSnapshots(FPlain, LPlain); + Log(' merged with what is waiting here - still to publish'); + end; + // Ecrit APRES un dechiffrement reussi seulement, et avec son ETag : // les deux doivent rester coherents. try