Submit on OpenVPN fields (#805)
Submit on password or OTP depending on the selected method.
This commit is contained in:
parent
fff21c3250
commit
fbe2d84113
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in New Issue