feat(apk): bouton de copie du code 2FA sur chaque ligne de la liste

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-09-18 14:58:09 +01:00
parent 255d685e73
commit 0e32a51bf1
3 changed files with 17 additions and 0 deletions
+2
View File
@@ -131,6 +131,8 @@ begin
LObj.AddPair('initial', Initial(E.Display)); LObj.AddPair('initial', Initial(E.Display));
LObj.AddPair('hasUser', TJSONBool.Create(E.Username <> '')); LObj.AddPair('hasUser', TJSONBool.Create(E.Username <> ''));
LObj.AddPair('isNote', TJSONBool.Create(E.IsNote)); LObj.AddPair('isNote', TJSONBool.Create(E.IsNote));
// Un booleen, jamais le secret : le code se calcule chez Delphi a la copie.
LObj.AddPair('hasTotp', TJSONBool.Create(E.Totp <> ''));
LEntries.AddElement(LObj); LEntries.AddElement(LObj);
end; end;
+5
View File
@@ -919,6 +919,10 @@ function renderRows() {
+ (e.sub ? '<span>' + esc(e.sub) + '</span>' : '') + '</div>' + (e.sub ? '<span>' + esc(e.sub) + '</span>' : '') + '</div>'
+ (e.hasUser ? '<button class="btn ico-btn" data-copy="user">' + (e.hasUser ? '<button class="btn ico-btn" data-copy="user">'
+ ico('user', 'Copy username') + '</button>' : '') + ico('user', 'Copy username') + '</button>' : '')
// LE CODE 2FA A PORTEE DE POUCE, comme l'identifiant et le mot de
// passe : il fallait ouvrir l'entree pour le copier.
+ (e.hasTotp ? '<button class="btn ico-btn" data-copy="rtotp">'
+ ico('clock', 'Copy 2FA code') + '</button>' : '')
+ '<button class="btn ico-btn" data-copy="pwd">' + '<button class="btn ico-btn" data-copy="pwd">'
+ (e.isNote ? ico('note', 'Copy text') : ico('key', 'Copy password')) + (e.isNote ? ico('note', 'Copy text') : ico('key', 'Copy password'))
+ '</button></div>'; + '</button></div>';
@@ -1001,6 +1005,7 @@ var ICONS = {
dots: '<circle cx="12" cy="5" r="1.4"/><circle cx="12" cy="12" r="1.4"/>' dots: '<circle cx="12" cy="5" r="1.4"/><circle cx="12" cy="12" r="1.4"/>'
+ '<circle cx="12" cy="19" r="1.4"/>', + '<circle cx="12" cy="19" r="1.4"/>',
check: '<path d="M4 12.5l5.5 5.5L20 7"/>', check: '<path d="M4 12.5l5.5 5.5L20 7"/>',
clock: '<circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 2"/>',
dice: '<rect x="4" y="4" width="16" height="16" rx="3"/>' dice: '<rect x="4" y="4" width="16" height="16" rx="3"/>'
+ '<circle cx="9" cy="9" r="1.2"/><circle cx="15" cy="15" r="1.2"/>' + '<circle cx="9" cy="9" r="1.2"/><circle cx="15" cy="15" r="1.2"/>'
+ '<circle cx="15" cy="9" r="1.2"/><circle cx="9" cy="15" r="1.2"/>', + '<circle cx="15" cy="9" r="1.2"/><circle cx="9" cy="15" r="1.2"/>',
+10
View File
@@ -2032,6 +2032,16 @@ begin
begin begin
E := FVault.Entry(LIdx); E := FVault.Entry(LIdx);
if Param('f') = 'user' then CopyToClipboard(E.Username, 'Username') if Param('f') = 'user' then CopyToClipboard(E.Username, 'Username')
else if Param('f') = 'rtotp' then
begin
// Calcule a l'instant de la copie : un code se perime en 30 s.
var LLeft, LPeriod: Integer;
var LCode := TotpNow(E.Totp, LLeft, LPeriod);
if LCode <> '' then
CopyToClipboard(LCode, Format('2FA code (%d s left)', [LLeft]))
else
WebCall('PM.toast("Unreadable 2FA secret")');
end
else if E.IsNote then CopyToClipboard(E.Password, 'Content') else if E.IsNote then CopyToClipboard(E.Password, 'Content')
else CopyToClipboard(E.Password, 'Password'); else CopyToClipboard(E.Password, 'Password');
end; end;