From a2628edceb6a725aa4c0ccd60b0e9d179b7d5cf6 Mon Sep 17 00:00:00 2001 From: Shuhari Date: Wed, 12 Nov 2025 15:28:03 +0800 Subject: [PATCH] fix: improve paste support for PIN code input fields - Add support for pasting multi-digit verification codes - Filter pasted content to alphanumeric characters only - Always start filling from the first field when pasting - Optimize performance by updating all fields at once - Support both numeric and alphanumeric codes (e.g., 123456, A1B2C3) Fixes the issue where pasting a 6-digit code like '123456' would only show the last digit '6' in the first field. Now all digits are correctly distributed across all input fields. This improvement benefits both SignInSMSView and SignIn2FAView since they share the same PinCodeTextField component. --- Xcodes/Frontend/SignIn/PinCodeTextView.swift | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Xcodes/Frontend/SignIn/PinCodeTextView.swift b/Xcodes/Frontend/SignIn/PinCodeTextView.swift index f0b1c2a0..6140cdd1 100644 --- a/Xcodes/Frontend/SignIn/PinCodeTextView.swift +++ b/Xcodes/Frontend/SignIn/PinCodeTextView.swift @@ -149,6 +149,34 @@ class PinCodeTextView: NSControl, NSTextFieldDelegate { let newFieldText = field.stringValue + // Handle pasting multiple characters (e.g., pasting "123456" from clipboard) + if newFieldText.count > 1 { + // Filter to alphanumeric characters only + let validCharacters = newFieldText.filter { $0.isLetter || $0.isNumber } + + // Always start from the first field and clear previous content + var newCode = Array(repeating: Character?.none, count: numberOfDigits) + for (offset, character) in validCharacters.enumerated() { + if offset < numberOfDigits { + newCode[offset] = character + } + } + + // Update all fields at once to avoid triggering didSet multiple times + code = newCode + + // Move focus to next empty field or the last field if all are filled + let nextEmptyIndex = code.firstIndex(where: { $0 == nil }) ?? numberOfDigits - 1 + if nextEmptyIndex < characterViews.count { + window?.makeFirstResponder(characterViews[nextEmptyIndex]) + } else { + resignFirstResponder() + } + + return + } + + // Handle single character input let lastCharacter: Character? if newFieldText.isEmpty { lastCharacter = nil