From 15959d2422b58c9764aaf260832fdc84c1c51f9b Mon Sep 17 00:00:00 2001 From: Davide Date: Sun, 3 Nov 2024 08:17:19 +0100 Subject: [PATCH] Resolve some focus issues (#802) - [x] tvOS: When profile selector appears, if it's closed without selecting any profile, it instantly reopens - [x] Set initial focus in OpenVPN credentials --- .../Views/Profile/ActiveProfileView.swift | 5 ---- .../AppUITV/Views/Profile/ProfileView.swift | 1 - .../Modules/OpenVPNView+Credentials.swift | 23 +++++++++++++++++++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/Passepartout/Library/Sources/AppUITV/Views/Profile/ActiveProfileView.swift b/Passepartout/Library/Sources/AppUITV/Views/Profile/ActiveProfileView.swift index a0fa388f..7569c2a5 100644 --- a/Passepartout/Library/Sources/AppUITV/Views/Profile/ActiveProfileView.swift +++ b/Passepartout/Library/Sources/AppUITV/Views/Profile/ActiveProfileView.swift @@ -31,8 +31,6 @@ import SwiftUI struct ActiveProfileView: View { let profile: Profile? - let firstProfileId: Profile.ID? - @ObservedObject var tunnel: ExtendedTunnel @@ -95,9 +93,6 @@ private extension ActiveProfileView { var switchProfileButton: some View { Button { - if let focus = tunnel.currentProfile?.id ?? firstProfileId { - focusedField = .profile(focus) - } isSwitching.toggle() } label: { Text(Strings.Global.select) diff --git a/Passepartout/Library/Sources/AppUITV/Views/Profile/ProfileView.swift b/Passepartout/Library/Sources/AppUITV/Views/Profile/ProfileView.swift index 3f19f7ef..ab124eae 100644 --- a/Passepartout/Library/Sources/AppUITV/Views/Profile/ProfileView.swift +++ b/Passepartout/Library/Sources/AppUITV/Views/Profile/ProfileView.swift @@ -131,7 +131,6 @@ private extension ProfileView { var activeView: some View { ActiveProfileView( profile: currentProfile, - firstProfileId: profileManager.headers.first?.id, tunnel: tunnel, isSwitching: $isSwitching, focusedField: $focusedField, diff --git a/Passepartout/Library/Sources/UILibrary/Views/Modules/OpenVPNView+Credentials.swift b/Passepartout/Library/Sources/UILibrary/Views/Modules/OpenVPNView+Credentials.swift index 359f79bd..d59919c3 100644 --- a/Passepartout/Library/Sources/UILibrary/Views/Modules/OpenVPNView+Credentials.swift +++ b/Passepartout/Library/Sources/UILibrary/Views/Modules/OpenVPNView+Credentials.swift @@ -29,6 +29,13 @@ import PassepartoutKit import SwiftUI public struct OpenVPNCredentialsView: View { + private enum Field: Hashable { + case username + + case password + + case otp + } @EnvironmentObject private var iapManager: IAPManager @@ -47,6 +54,9 @@ public struct OpenVPNCredentialsView: View { @State private var paywallReason: PaywallReason? + @FocusState + private var focusedField: Field? + public init( isInteractive: Binding, credentials: Binding, @@ -66,6 +76,15 @@ public struct OpenVPNCredentialsView: View { .onLoad { builder = credentials?.builder() ?? OpenVPN.Credentials.Builder() builder.otp = nil + if isAuthenticating { + switch builder.otpMethod { + case .none: + focusedField = .username + + default: + focusedField = .otp + } + } } .onChange(of: builder) { var copy = $0 @@ -137,8 +156,11 @@ private extension OpenVPNCredentialsView { if !isAuthenticating || builder.otpMethod == .none { ThemeTextField(Strings.Global.username, text: $builder.username, placeholder: Strings.Placeholders.username) .textContentType(.username) + .focused($focusedField, equals: .username) + ThemeSecureField(title: Strings.Global.password, text: $builder.password, placeholder: Strings.Placeholders.secret) .textContentType(.password) + .focused($focusedField, equals: .password) } if isEligibleForInteractiveLogin, isAuthenticating, builder.otpMethod != .none { ThemeSecureField( @@ -147,6 +169,7 @@ private extension OpenVPNCredentialsView { placeholder: Strings.Placeholders.secret ) .textContentType(.oneTimeCode) + .focused($focusedField, equals: .otp) } } .themeSection(footer: inputFooter)