Add click-to-copy animation on TOTP code display

- Click anywhere on the code area copies to clipboard
- Visual feedback: green flash + checkmark for 400ms
- Hand cursor on code frame, label, and timer
- Copy button still works as before

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chrome-storm-c442
2026-02-23 11:10:41 -05:00
parent bf39fd7b67
commit b8c61e4719
2 changed files with 30 additions and 7 deletions

View File

@@ -36,27 +36,32 @@ class TOTPTab(ctk.CTkFrame):
)
self.server_label.pack(fill="x", padx=15, pady=(0, 10))
# Code display frame
code_frame = ctk.CTkFrame(self, fg_color="#1e1e2e", corner_radius=12)
code_frame.pack(fill="x", padx=15, pady=(0, 10))
# Code display frame — clickable
self.code_frame = ctk.CTkFrame(self, fg_color="#1e1e2e", corner_radius=12, cursor="hand2")
self.code_frame.pack(fill="x", padx=15, pady=(0, 10))
self.code_label = ctk.CTkLabel(
code_frame, text="------",
self.code_frame, text="------",
font=ctk.CTkFont(family="Consolas", size=42, weight="bold"),
text_color="#22c55e"
text_color="#22c55e", cursor="hand2"
)
self.code_label.pack(pady=(20, 5))
self.timer_label = ctk.CTkLabel(
code_frame, text="",
self.code_frame, text="",
font=ctk.CTkFont(size=12), text_color="#9ca3af"
)
self.timer_label.pack(pady=(0, 5))
self.progress_bar = ctk.CTkProgressBar(code_frame, width=300, height=6)
self.progress_bar = ctk.CTkProgressBar(self.code_frame, width=300, height=6)
self.progress_bar.pack(pady=(0, 15))
self.progress_bar.set(1.0)
# Click anywhere on the code frame → copy
self.code_frame.bind("<Button-1>", lambda e: self._copy_code())
self.code_label.bind("<Button-1>", lambda e: self._copy_code())
self.timer_label.bind("<Button-1>", lambda e: self._copy_code())
# Copy button
self.copy_btn = ctk.CTkButton(
self, text=t("totp_copy"), width=200, height=40,
@@ -205,12 +210,30 @@ class TOTPTab(ctk.CTkFrame):
if code_text and code_text != "------" and code_text != "ERROR":
self.clipboard_clear()
self.clipboard_append(code_text)
self._animate_copy()
self.status_label.configure(text=t("totp_copied"), text_color="#22c55e")
self.after(2000, lambda: self.status_label.configure(text=""))
else:
self.status_label.configure(text=t("totp_no_code"), text_color="#ef4444")
self.after(2000, lambda: self.status_label.configure(text=""))
def _animate_copy(self):
"""Flash the code frame and briefly show 'Copied' feedback."""
# Save original state
orig_fg = self.code_frame.cget("fg_color")
orig_text = self.code_label.cget("text")
orig_color = self.code_label.cget("text_color")
# Flash: green background + "Copied!" text
self.code_frame.configure(fg_color="#164e36")
self.code_label.configure(text="", text_color="#4ade80")
def restore():
self.code_frame.configure(fg_color=orig_fg)
self.code_label.configure(text=orig_text, text_color=orig_color)
self.after(400, restore)
def _toggle_secret(self):
self._secret_visible = not self._secret_visible
self.secret_entry.configure(show="" if self._secret_visible else "*")