Submit on OpenVPN fields (#805)

Submit on password or OTP depending on the selected method.
This commit is contained in:
Davide 2024-11-03 11:27:12 +01:00 committed by GitHub
parent fff21c3250
commit fbe2d84113
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 46 additions and 20 deletions

View File

@ -29,5 +29,5 @@ public protocol InteractiveViewProviding {
associatedtype InteractiveContent: View associatedtype InteractiveContent: View
@MainActor @MainActor
func interactiveView(with editor: ProfileEditor) -> InteractiveContent func interactiveView(with editor: ProfileEditor, onSubmit: @escaping () -> Void) -> InteractiveContent
} }

View File

@ -27,13 +27,14 @@ import PassepartoutKit
import SwiftUI import SwiftUI
extension OpenVPNModule.Builder: InteractiveViewProviding { extension OpenVPNModule.Builder: InteractiveViewProviding {
public func interactiveView(with editor: ProfileEditor) -> some View { public func interactiveView(with editor: ProfileEditor, onSubmit: @escaping () -> Void) -> some View {
let draft = editor[self] let draft = editor[self]
return OpenVPNCredentialsView( return OpenVPNCredentialsView(
isInteractive: draft.isInteractive, isInteractive: draft.isInteractive,
credentials: draft.credentials, credentials: draft.credentials,
isAuthenticating: true isAuthenticating: true,
onSubmit: onSubmit
) )
} }
} }

View File

@ -46,7 +46,9 @@ public struct OpenVPNCredentialsView: View {
@Binding @Binding
private var credentials: OpenVPN.Credentials? private var credentials: OpenVPN.Credentials?
private var isAuthenticating = false private let isAuthenticating: Bool
private let onSubmit: (() -> Void)?
@State @State
private var builder = OpenVPN.Credentials.Builder() private var builder = OpenVPN.Credentials.Builder()
@ -60,11 +62,13 @@ public struct OpenVPNCredentialsView: View {
public init( public init(
isInteractive: Binding<Bool>, isInteractive: Binding<Bool>,
credentials: Binding<OpenVPN.Credentials?>, credentials: Binding<OpenVPN.Credentials?>,
isAuthenticating: Bool = false isAuthenticating: Bool = false,
onSubmit: (() -> Void)? = nil
) { ) {
_isInteractive = isInteractive _isInteractive = isInteractive
_credentials = credentials _credentials = credentials
self.isAuthenticating = isAuthenticating self.isAuthenticating = isAuthenticating
self.onSubmit = onSubmit
} }
public var body: some View { public var body: some View {
@ -154,22 +158,11 @@ private extension OpenVPNCredentialsView {
var inputSection: some View { var inputSection: some View {
Group { Group {
if !isAuthenticating || builder.otpMethod == .none { if !isAuthenticating || builder.otpMethod == .none {
ThemeTextField(Strings.Global.username, text: $builder.username, placeholder: Strings.Placeholders.username) usernameField
.textContentType(.username) passwordField
.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 { if isEligibleForInteractiveLogin, isAuthenticating, builder.otpMethod != .none {
ThemeSecureField( otpField
title: Strings.Unlocalized.otp,
text: $builder.otp ?? "",
placeholder: Strings.Placeholders.secret
)
.textContentType(.oneTimeCode)
.focused($focusedField, equals: .otp)
} }
} }
.themeSection(footer: inputFooter) .themeSection(footer: inputFooter)
@ -182,6 +175,38 @@ private extension OpenVPNCredentialsView {
} }
return nil return nil
} }
var usernameField: some View {
ThemeTextField(Strings.Global.username, text: $builder.username, placeholder: Strings.Placeholders.username)
.textContentType(.username)
.focused($focusedField, equals: .username)
}
var passwordField: some View {
ThemeSecureField(title: Strings.Global.password, text: $builder.password, placeholder: Strings.Placeholders.secret)
.textContentType(.password)
.focused($focusedField, equals: .password)
.onSubmit {
if builder.otpMethod == .none {
onSubmit?()
}
}
}
var otpField: some View {
ThemeSecureField(
title: Strings.Unlocalized.otp,
text: $builder.otp ?? "",
placeholder: Strings.Placeholders.secret
)
.textContentType(.oneTimeCode)
.focused($focusedField, equals: .otp)
.onSubmit {
if builder.otpMethod != .none {
onSubmit?()
}
}
}
} }
#Preview { #Preview {

View File

@ -163,7 +163,7 @@ private extension InteractiveCoordinator {
} }
func innerView(with provider: any InteractiveViewProviding) -> some View { func innerView(with provider: any InteractiveViewProviding) -> some View {
AnyView(provider.interactiveView(with: manager.editor)) AnyView(provider.interactiveView(with: manager.editor, onSubmit: confirm))
} }
func confirm() { func confirm() {