diff --git a/android-client/web/app.html b/android-client/web/app.html index e4c632b..afe8fbe 100644 --- a/android-client/web/app.html +++ b/android-client/web/app.html @@ -270,6 +270,10 @@ /* --- deverrouillage ----------------------------------------------------- */ .status { color: var(--muted); margin: 22px 4px 14px; min-height: 20px; } + /* UN REFUS N'EST PAS UN ETAT. "Master password: 8 characters at least" se + lisait du meme gris que "Vault on this device" - on ne voyait pas que + l'application venait de refuser quelque chose. */ + .status.err { color: #ff9d9d; } .stack { display: flex; flex-direction: column; gap: 8px; } /* L'espace de 8 px vit A L'INTERIEUR de chaque pile. Deux piles voisines se touchaient donc, et "Create vault" collait a "Download vault" alors que @@ -304,8 +308,12 @@ .in-wrap { position: relative; } /* Le champ laisse la place a la croix, sinon le texte passe dessous. */ .in-wrap .field-in { padding-right: 44px; } + /* ANCREE EN BAS, PAS EN HAUT. Le champ porte un margin-top de 8 px, que les + piles annulent : caler la croix a `top: 8px` la laissait donc 8 px trop bas + des que le margin disparaissait. Le bord INFERIEUR, lui, est celui que le + champ touche dans les deux cas - le margin est au-dessus. */ .in-x { - position: absolute; right: 0; top: 8px; width: 44px; height: 46px; + position: absolute; right: 0; bottom: 0; width: 44px; height: 46px; display: flex; align-items: center; justify-content: center; color: var(--muted); font-size: 22px; } @@ -1601,8 +1609,12 @@ var PM = { document.body.classList.remove('on-list', 'on-detail', 'searching'); view = 'unlock'; }, - setStatus: function (text) { - document.getElementById('status').textContent = text; + setStatus: function (text, err) { + var s = document.getElementById('status'); + s.textContent = text; + // classList.toggle avec un second argument : la classe suit le drapeau, + // sans qu'un message neutre ait a penser a l'enlever. + s.classList.toggle('err', !!err); }, /// Etat des deux actions : ouvrir n'a de sens qu'avec un coffre local /// lisible, et synchroniser s'appelle autrement quand il n'y en a pas. diff --git a/mainApk.pas b/mainApk.pas index ca00a3b..92df680 100644 --- a/mainApk.pas +++ b/mainApk.pas @@ -351,6 +351,7 @@ type function HandleAppEvent(AAppEvent: TApplicationEvent; AContext: TObject): Boolean; procedure Log(const AMsg: string); procedure Status(const AMsg: string); + procedure StatusErr(const AMsg: string); procedure SetBusy(ABusy: Boolean); public constructor Create(AOwner: TComponent); override; @@ -1252,14 +1253,14 @@ begin if FBusy then Exit; if not HasLocalContainer then begin - Status('No local vault to reconcile'); + StatusErr('No local vault to reconcile'); Exit; end; // LES DEUX SONT REQUIS ICI, ET NULLE PART AILLEURS : c'est le seul moment ou // le conteneur local et l'instantane du depot se rencontrent. if FVaultPwd = '' then begin - Status('Open the vault first'); + StatusErr('Open the vault first'); Exit; end; // CE QUI EST DANS LES REGLAGES FAIT FOI quand le coffre n'en porte pas encore. @@ -1269,7 +1270,7 @@ begin if FSyncPwd = '' then FSyncPwd := FPwd; if FSyncPwd = '' then begin - Status('Set the sync password in Settings'); + StatusErr('Set the sync password in Settings'); Exit; end; SetBusy(True); @@ -1851,7 +1852,7 @@ begin if FBusy then Exit; if AUser = '' then begin - Status('Pick a username'); + StatusErr('Pick a username'); Exit; end; // Huit caracteres, comme le poste. Ce mot de passe est la SEULE chose qui @@ -1859,14 +1860,14 @@ begin // tentatives, et le fichier est un fichier. if Length(APwd) < 8 then begin - Status('Master password: 8 characters at least'); + StatusErr('Master password: 8 characters at least'); Exit; end; // Un coffre existant ne se remplace pas par accident : ce serait perdre tout // ce qu'il contient, sans retour possible. if HasLocalContainer or HasVault then begin - Status('This device already holds a vault'); + StatusErr('This device already holds a vault'); Exit; end; @@ -1920,7 +1921,7 @@ begin begin SetBusy(False); Log('Register failed: ' + E.ClassName + ' - ' + E.Message); - Status('Could not create the vault - see log'); + StatusErr('Could not create the vault - see log'); end); end; end).Start; @@ -1937,7 +1938,7 @@ begin if FBusy then Exit; if not HasLocalContainer then begin - Status('No vault on this device'); + StatusErr('No vault on this device'); Exit; end; if APwd = '' then @@ -2157,7 +2158,7 @@ begin begin Log('Vault did not open under this unlock code'); ShowUnlock; - Status('Wrong unlock code'); + StatusErr('Wrong unlock code'); WebCall('PM.focusPin()'); Exit; end; @@ -2172,13 +2173,13 @@ begin // une panne. if LastStoreKeyInvalidated then begin - Status('Device protection changed - download the vault again'); + StatusErr('Device protection changed - download the vault again'); WebCall('PM.toast("This phone''s screen lock was removed or reset, so ' + 'Android destroyed the key that sealed the local copy. ' + 'Nothing is lost - the vault is in the repository.")'); end else - Status('Local vault unreadable - see log'); + StatusErr('Local vault unreadable - see log'); end; end; @@ -2196,7 +2197,7 @@ begin // detruit le cache alors qu'il le protegeait. if VaultNeedsPin and (FPin = '') then begin - Status('Unlock code required'); + StatusErr('Unlock code required'); WebCall('PM.focusPin()'); Exit; end; @@ -2266,7 +2267,7 @@ begin if LPwd = '' then LPwd := FSyncPwd; if LPwd = '' then begin - Status('Sync password required'); + StatusErr('Sync password required'); Exit; end; WebCall('PM.clearLog()'); @@ -2296,7 +2297,7 @@ begin begin if VaultNeedsPin and (FPin = '') then begin - Status('Unlock code required'); + StatusErr('Unlock code required'); WebCall('PM.focusPin()'); Exit; end; @@ -2483,7 +2484,7 @@ begin Log(' failed: ' + LRes.Error); if not ASilent then TThread.Queue(nil, procedure - begin Status('Network failure'); end); + begin StatusErr('Network failure'); end); Exit; end; end; @@ -3016,6 +3017,16 @@ begin WebCall('PM.setStatus(' + JsArg(AMsg) + ')'); end; +/// Le meme endroit, mais en rouge : ce qui suit est un REFUS, pas un etat. +/// +/// Deux procedures plutot qu'un drapeau devine du texte : trier des messages +/// sur leur contenu est exactement ce qui a deja detruit un cache dans ce +/// projet. C'est l'appelant qui sait s'il refuse. +procedure TForm8.StatusErr(const AMsg: string); +begin + WebCall('PM.setStatus(' + JsArg(AMsg) + ', true)'); +end; + procedure TForm8.SetBusy(ABusy: Boolean); var LCanOpen: Boolean;