diff --git a/android-client/PMA.SyncClient.pas b/android-client/PMA.SyncClient.pas index 14b3838..8d33281 100644 --- a/android-client/PMA.SyncClient.pas +++ b/android-client/PMA.SyncClient.pas @@ -395,7 +395,11 @@ begin inherited Create; FBaseUrl := ABaseUrl.Trim; FToken := AToken.Trim; - FTimeoutMs := 15000; + // 15 s ne suffisaient pas a GitHub depuis un telephone en mobile ou en + // Wi-Fi charge : un simple 404 a ete mesure a 16,3 s, donc la requete + // s'abandonnait juste avant la reponse et la synchro rendait "HTTP 0" une + // fois sur deux. Le delai ne coute rien quand le reseau repond vite. + FTimeoutMs := 40000; end; function TSyncClient.Fetch(const AKnownETag: string): TSyncResult; diff --git a/android-client/web/app.html b/android-client/web/app.html index 25705a0..2185452 100644 --- a/android-client/web/app.html +++ b/android-client/web/app.html @@ -1113,6 +1113,7 @@ function renderDetail(d) { } document.getElementById('fields').addEventListener('click', function (ev) { + // Meme raison que dans la liste : le dessin recoit l'appui, le bouton porte // l'intention. Tout ce qui suit lit et ecrit sur le bouton. var t = ev.target.closest('button') || ev.target; @@ -1315,6 +1316,17 @@ addEventListener('keydown', function (ev) { // defile. Une entree qu'on cree et une entree qu'on consulte occupent la meme // place a l'ecran, et c'est exactement ce que cette vue veut dire. var newKind = 'login'; +// LE CLAVIER NE MONTE PAS TOUT SEUL. Le champ prend bien le focus - mesure +// faite : l'appui arrive et focusin part -, mais la vue web est posee dans une +// activite FMX, et le systeme n'ouvre le clavier que si on le lui demande. +// C'est deja ce que fait la recherche ; les champs du formulaire passent par +// la meme porte. +document.addEventListener('focusin', function (ev) { + var el = ev.target; + if (!el.classList || !el.classList.contains('field-in')) return; + if (el.tagName === 'SELECT') return; // il ouvre sa propre liste + send('kbd'); +}, true); /// Le dossier a la creation. Le meme choix que dans l'editeur, et pour la /// meme raison : une entree rangee des le depart evite d'avoir a la deplacer. @@ -1527,6 +1539,8 @@ function openEditEntry() { // L'ICONE ET LE NOM EN TETE : on voit ce qu'on modifie, et surtout ce que // les trois boutons d'en dessous vont remplacer. var d = lastDetail; + // Pas de crayon pendant qu'on modifie : il n'a plus rien a ouvrir. + document.getElementById('pencil').hidden = true; var av = document.getElementById('dav'); av.hidden = false; av.className = 'av' + (d.icon ? ' has-img' : ''); @@ -1568,7 +1582,6 @@ function openEditEntry() { }); document.getElementById('eSave').addEventListener('click', saveEditEntry); view = 'edit'; - send('state?view=edit'); if (editAgain) { var ins = document.querySelectorAll('#fields [data-ef]'), i, f; for (i = 0; i < ins.length; i++) { @@ -2211,9 +2224,12 @@ var PM = { ico('loader', 'Working') + 'Please wait...'; document.body.classList.toggle('is-busy', !!on); }, - back: function () { if (view === 'detail') goList(); }, - // Touche retour du telephone pendant une modification : on revient a - // l'entree, pas a la liste. + // Touche retour du telephone : le formulaire d'abord, la liste ensuite. + // Delphi ne connait que 'detail' - la page seule sait qu'elle edite. + back: function () { + if (view === 'edit') { renderDetail(lastDetail); return; } + if (view === 'detail') goList(); + }, cancelEdit: function () { renderDetail(lastDetail); }, /// La touche retour annule la selection avant de verrouiller le coffre. /// Sans cela, un geste d'annulation fermait le coffre - le contraire de ce diff --git a/mainApk.pas b/mainApk.pas index 911391b..62f224c 100644 --- a/mainApk.pas +++ b/mainApk.pas @@ -507,7 +507,10 @@ begin // le filet. FDeadline := TTimer.Create(Self); FDeadline.Enabled := False; - FDeadline.Interval := 25000; + // Plus long que le delai du client HTTP (40 s) : ce garde-fou est la pour + // le cas ou la requete ne rend jamais la main, pas pour couper une reponse + // lente que le client attend encore - c'est ce qu'il faisait a 25 s. + FDeadline.Interval := 50000; FDeadline.OnTimer := OnDeadline; FTotpTimer := TTimer.Create(Self); @@ -2987,6 +2990,30 @@ begin begin // Le serveur repond pareil dans les deux cas, par conception. Log(' 404: no snapshot OR invalid token'); + // DEPOT VIDE ET DES CHANGEMENTS QUI ATTENDENT ICI : on publie. + // + // Le telephone verifiait d'abord le mot de passe de synchro en + // telechargeant l'instantane - et s'arretait la quand il n'y en + // avait pas encore, en repetant 404 a chaque essai. Rien ne + // partait jamais, alors que c'est exactement le premier envoi : + // le poste fait de meme sur un depot neuf. + // + // Le mot de passe tape devient celui du depot, faute d'un + // instantane contre lequel l'eprouver - c'est ce que veut dire + // "premiere publication". + if (FPlain <> '') and FPending then + begin + TThread.Queue(nil, + procedure + begin + FSyncPwd := APwd; + FPwdUserSet := False; + FPwdShown := APwd; + Log(' empty repository - publishing what waits here'); + PublishPending; + end); + Exit; + end; if not ASilent then begin // TRANCHER L'AMBIGUITE : fichier absent, depot ou utilisateur