diff --git a/android-client/web/app.html b/android-client/web/app.html
index f76b4b9..170c608 100644
--- a/android-client/web/app.html
+++ b/android-client/web/app.html
@@ -285,8 +285,15 @@ function drain() {
f.src = 'cmd://' + queue.shift();
document.body.appendChild(f);
setTimeout(function () {
- f.parentNode.removeChild(f);
- drain();
+ // LE try/finally EST L'INTERET DE CE BLOC. Sans lui, une exception au
+ // retrait de l'iframe laisse "sending" a vrai pour toujours : plus une
+ // seule commande ne repart, et l'interface devient muette sans rien
+ // signaler. Le meme piege existait cote Delphi sur l'indicateur d'occupation.
+ try {
+ if (f.parentNode) f.parentNode.removeChild(f);
+ } finally {
+ drain();
+ }
}, 60);
}
@@ -496,7 +503,9 @@ var PM = {
setActions: function (canOpen, syncLabel, busy) {
var o = document.getElementById('btnOpen'), s = document.getElementById('btnSync');
o.hidden = !canOpen;
- s.innerHTML = '↻ ' + syncLabel;
+ // textContent et non innerHTML : l'intitule vient de Delphi, et une valeur
+ // interpretee comme du balisage n'a pas de raison de l'etre.
+ s.textContent = '\u21BB ' + syncLabel;
o.disabled = busy; s.disabled = busy;
o.style.opacity = busy ? .4 : 1;
s.style.opacity = busy ? .4 : 1;
diff --git a/mainApk.pas b/mainApk.pas
index 8bbbfa2..b08ebc6 100644
--- a/mainApk.pas
+++ b/mainApk.pas
@@ -119,6 +119,14 @@ type
FClipTimer: TTimer;
FCopied: string;
+ /// ECHEANCE SUR UNE OPERATION RESEAU. Sans elle, un appel qui ne rend
+ /// jamais la main laisse l'interface morte et muette : les deux actions
+ /// restent desactivees, aucun message n'apparait, et rien n'y ramene -
+ /// c'est arrive avec le serveur local arrete. Les delais de THTTPClient
+ /// sont censes couvrir ce cas ; celui-ci couvre le jour ou ils ne le font
+ /// pas, quelle qu'en soit la raison.
+ FDeadline: TTimer;
+
// --- verrouillage sur inactivite
FIdleTimer: TTimer;
FLastActivity: TDateTime;
@@ -161,6 +169,7 @@ type
procedure PushConfig;
procedure OpenEntry(AVaultIndex: Integer);
procedure OnClipTimer(Sender: TObject);
+ procedure OnDeadline(Sender: TObject);
procedure OnHardwareBack(Sender: TObject; var Key: Word;
var KeyChar: WideChar; Shift: TShiftState);
@@ -228,6 +237,14 @@ begin
FClipTimer.Interval := CLIPBOARD_CLEAR_SECONDS * 1000;
FClipTimer.OnTimer := OnClipTimer;
+ // Plus long que les delais de THTTPClient (15 s), pour que le message precis
+ // du client reseau arrive le premier quand il fonctionne. Celui-ci n'est que
+ // le filet.
+ FDeadline := TTimer.Create(Self);
+ FDeadline.Enabled := False;
+ FDeadline.Interval := 25000;
+ FDeadline.OnTimer := OnDeadline;
+
FTotpTimer := TTimer.Create(Self);
FTotpTimer.Enabled := False;
FTotpTimer.Interval := 1000;
@@ -1022,11 +1039,35 @@ begin
end;
procedure TForm8.SetBusy(ABusy: Boolean);
+var
+ LCanOpen: Boolean;
+ LLabel: string;
begin
FBusy := ABusy;
- WebCall(Format('PM.setActions(%s, "Sync", %s)',
- [LowerCase(BoolToStr(HasVault and not FVaultUnreadable, True)),
+ FDeadline.Enabled := False; // reposee a zero, pas prolongee
+ FDeadline.Enabled := ABusy;
+ LCanOpen := HasVault and not FVaultUnreadable;
+ // L'intitule suit l'etat du cache et non un mot fixe : sans coffre local,
+ // l'action n'est pas une synchronisation mais un premier telechargement, et
+ // le reprendre en dur ici effacait cette distinction a chaque passage.
+ if LCanOpen then LLabel := 'Sync' else LLabel := 'Download vault';
+ WebCall(Format('PM.setActions(%s, %s, %s)',
+ [LowerCase(BoolToStr(LCanOpen, True)), JsArg(LLabel),
LowerCase(BoolToStr(ABusy, True))]));
end;
+/// L'operation reseau n'a pas rendu la main dans le delai. On rend l'interface
+/// a l'utilisateur et on le dit. Le thread, lui, est ABANDONNE : il mourra
+/// quand sa socket finira par echouer, et s'il aboutit malgre tout, son
+/// resultat s'affichera - il n'y a rien a annuler.
+procedure TForm8.OnDeadline(Sender: TObject);
+begin
+ FDeadline.Enabled := False;
+ if not FBusy then Exit;
+ Log(' no reply after ' + (FDeadline.Interval div 1000).ToString +
+ ' s - request abandoned');
+ Status('No reply from the server');
+ SetBusy(False);
+end;
+
end.