@@ -33,6 +33,7 @@ public struct MFAEnrolmentView {
3333 @State private var isLoading = false
3434 @State private var errorMessage = " "
3535 @State private var displayName = " "
36+ @State private var showCopiedFeedback = false
3637
3738 @FocusState private var focus : FocusableField ?
3839
@@ -169,6 +170,20 @@ public struct MFAEnrolmentView {
169170 resetForm ( )
170171 authService. authView = . authPicker
171172 }
173+
174+ private func copyToClipboard( _ text: String ) {
175+ UIPasteboard . general. string = text
176+
177+
178+ // Show feedback
179+ showCopiedFeedback = true
180+
181+ // Quickly show it has been copied to the clipboard
182+ Task {
183+ try ? await Task . sleep ( nanoseconds: 500_000_000 )
184+ showCopiedFeedback = false
185+ }
186+ }
172187}
173188
174189extension MFAEnrolmentView : View {
@@ -502,14 +517,37 @@ extension MFAEnrolmentView: View {
502517 Text ( " Manual Entry Key: " )
503518 . font ( . headline)
504519
505- Text ( totpInfo. sharedSecretKey)
506- . font ( . system( . body, design: . monospaced) )
507- . padding ( )
508- . background ( Color . gray. opacity ( 0.1 ) )
509- . cornerRadius ( 8 )
510- . textSelection ( . enabled)
520+ VStack ( spacing: 8 ) {
521+ Button ( action: {
522+ copyToClipboard ( totpInfo. sharedSecretKey)
523+ } ) {
524+ HStack {
525+ Text ( totpInfo. sharedSecretKey)
526+ . font ( . system( . body, design: . monospaced) )
527+ . lineLimit ( 1 )
528+ . minimumScaleFactor ( 0.5 )
529+
530+ Spacer ( )
531+
532+ Image ( systemName: showCopiedFeedback ? " checkmark " : " doc.on.doc " )
533+ . foregroundColor ( showCopiedFeedback ? . green : . blue)
534+ }
535+ . padding ( )
536+ . background ( Color . gray. opacity ( 0.1 ) )
537+ . cornerRadius ( 8 )
538+ }
539+ . buttonStyle ( . plain)
511540 . accessibilityIdentifier ( " totp-secret-key " )
512541
542+ if showCopiedFeedback {
543+ Text ( " Copied to clipboard! " )
544+ . font ( . caption)
545+ . foregroundColor ( . green)
546+ . transition ( . opacity)
547+ }
548+ }
549+ . animation ( . easeInOut( duration: 0.2 ) , value: showCopiedFeedback)
550+
513551 TextField ( " Display Name (Optional) " , text: $displayName)
514552 . textFieldStyle ( . roundedBorder)
515553 . accessibilityIdentifier ( " display-name-field " )
0 commit comments