Focus some text fields on appearance (#334)
Feature from iOS 15, use it on: - New profile name - New profile passphrase - Renamed profile name - Account username
This commit is contained in:
parent
6ede6f052a
commit
34f6738b69
|
@ -27,6 +27,14 @@ import PassepartoutLibrary
|
|||
import SwiftUI
|
||||
|
||||
struct AccountView: View {
|
||||
enum Field {
|
||||
case username
|
||||
|
||||
case password
|
||||
|
||||
case seed
|
||||
}
|
||||
|
||||
@ObservedObject private var providerManager: ProviderManager
|
||||
|
||||
private let providerName: ProviderName?
|
||||
|
@ -41,6 +49,8 @@ struct AccountView: View {
|
|||
|
||||
@State private var liveAccount = Profile.Account()
|
||||
|
||||
@FocusState private var focusedField: Field?
|
||||
|
||||
init(
|
||||
providerName: ProviderName?,
|
||||
vpnProtocol: VPNProtocolType,
|
||||
|
@ -71,6 +81,7 @@ struct AccountView: View {
|
|||
TextField(usernamePlaceholder ?? L10n.Account.Items.Username.placeholder, text: $liveAccount.username)
|
||||
.textContentType(.username)
|
||||
.keyboardType(.emailAddress)
|
||||
.focused($focusedField, equals: .username)
|
||||
.themeRawTextStyle()
|
||||
.withLeadingText(L10n.Account.Items.Username.caption)
|
||||
|
||||
|
@ -80,12 +91,14 @@ struct AccountView: View {
|
|||
EmptyView()
|
||||
} else {
|
||||
themeSecureField(L10n.Account.Items.Password.placeholder, text: $liveAccount.password)
|
||||
.focused($focusedField, equals: .password)
|
||||
.withLeadingText(L10n.Account.Items.Password.caption)
|
||||
}
|
||||
|
||||
// TODO: interactive, scan QR code
|
||||
case .totp:
|
||||
// TODO: interactive, scan QR code
|
||||
themeSecureField(L10n.Account.Items.Password.placeholder, text: $liveAccount.password, contentType: .oneTimeCode)
|
||||
.focused($focusedField, equals: .seed)
|
||||
.withLeadingText(L10n.Account.Items.Seed.caption)
|
||||
}
|
||||
} footer: {
|
||||
|
@ -111,6 +124,8 @@ struct AccountView: View {
|
|||
saveAnyway: saveAnyway,
|
||||
onSave: onSave
|
||||
)
|
||||
}.onAppear {
|
||||
focusedField = .username
|
||||
}.navigationTitle(L10n.Account.title)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ extension AddHostView {
|
|||
|
||||
@State private var isEnteringCredentials = false
|
||||
|
||||
@FocusState private var focusedField: AddProfileView.Field?
|
||||
|
||||
init(
|
||||
url: URL,
|
||||
deletingURLOnSuccess: Bool,
|
||||
|
@ -75,7 +77,11 @@ extension AddHostView {
|
|||
isPresented: $viewModel.isAskingOverwrite,
|
||||
actions: alertOverwriteActions,
|
||||
message: alertOverwriteMessage
|
||||
).onAppear(perform: requestResourcePermissions)
|
||||
).onChange(of: viewModel.requiresPassphrase) {
|
||||
if $0 {
|
||||
focusedField = .passphrase
|
||||
}
|
||||
}.onAppear(perform: requestResourcePermissions)
|
||||
.onDisappear(perform: dropResourcePermissions)
|
||||
.navigationTitle(L10n.AddProfile.Shared.title)
|
||||
.themeSecondaryView()
|
||||
|
@ -91,6 +97,7 @@ private extension AddHostView.NameView {
|
|||
var mainView: some View {
|
||||
AddProfileView.ProfileNameSection(
|
||||
profileName: $viewModel.profileName,
|
||||
focusedField: $focusedField,
|
||||
errorMessage: viewModel.errorMessage
|
||||
) {
|
||||
processProfile(replacingExisting: false)
|
||||
|
@ -118,7 +125,7 @@ private extension AddHostView.NameView {
|
|||
Section {
|
||||
SecureField(L10n.AddProfile.Host.Sections.Encryption.footer, text: $viewModel.encryptionPassphrase) {
|
||||
processProfile(replacingExisting: false)
|
||||
}
|
||||
}.focused($focusedField, equals: .passphrase)
|
||||
} header: {
|
||||
Text(L10n.Global.Strings.encryption)
|
||||
}
|
||||
|
|
|
@ -27,6 +27,12 @@ import PassepartoutLibrary
|
|||
import SwiftUI
|
||||
|
||||
enum AddProfileView {
|
||||
enum Field {
|
||||
case name
|
||||
|
||||
case passphrase
|
||||
}
|
||||
|
||||
struct Bindings {
|
||||
@Binding var isPresented: Bool
|
||||
}
|
||||
|
@ -34,6 +40,8 @@ enum AddProfileView {
|
|||
struct ProfileNameSection: View {
|
||||
@Binding var profileName: String
|
||||
|
||||
@FocusState.Binding var focusedField: Field?
|
||||
|
||||
let errorMessage: String?
|
||||
|
||||
let onCommit: () -> Void
|
||||
|
@ -41,11 +49,14 @@ enum AddProfileView {
|
|||
var body: some View {
|
||||
Section {
|
||||
TextField(L10n.Global.Placeholders.profileName, text: $profileName, onCommit: onCommit)
|
||||
.focused($focusedField, equals: .name)
|
||||
.themeValidProfileName()
|
||||
} header: {
|
||||
Text(L10n.Global.Strings.name)
|
||||
} footer: {
|
||||
themeErrorMessage(errorMessage)
|
||||
}.onAppear {
|
||||
focusedField = .name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ extension AddProviderView {
|
|||
|
||||
@State private var isEnteringCredentials = false
|
||||
|
||||
@FocusState private var focusedField: AddProfileView.Field?
|
||||
|
||||
init(
|
||||
profile: Binding<Profile>,
|
||||
providerMetadata: ProviderMetadata,
|
||||
|
@ -57,6 +59,7 @@ extension AddProviderView {
|
|||
List {
|
||||
AddProfileView.ProfileNameSection(
|
||||
profileName: $viewModel.profileName,
|
||||
focusedField: $focusedField,
|
||||
errorMessage: viewModel.errorMessage
|
||||
) {
|
||||
saveProfile(replacingExisting: false)
|
||||
|
|
|
@ -28,6 +28,10 @@ import SwiftUI
|
|||
|
||||
extension ProfileView {
|
||||
struct RenameView: View {
|
||||
enum Field {
|
||||
case name
|
||||
}
|
||||
|
||||
@Environment(\.presentationMode) private var presentationMode
|
||||
|
||||
@ObservedObject private var profileManager: ProfileManager
|
||||
|
@ -38,6 +42,8 @@ extension ProfileView {
|
|||
|
||||
@State private var isOverwritingExistingProfile = false
|
||||
|
||||
@FocusState private var focusedField: Field?
|
||||
|
||||
init(currentProfile: ObservableProfile) {
|
||||
profileManager = .shared
|
||||
self.currentProfile = currentProfile
|
||||
|
@ -48,6 +54,7 @@ extension ProfileView {
|
|||
Section {
|
||||
TextField(L10n.Global.Placeholders.profileName, text: $newName, onCommit: commitRenaming)
|
||||
.themeValidProfileName()
|
||||
.focused($focusedField, equals: .name)
|
||||
.onAppear(perform: loadCurrentName)
|
||||
} header: {
|
||||
Text(L10n.Profile.Alerts.Rename.title)
|
||||
|
@ -96,6 +103,7 @@ private extension ProfileView.RenameView {
|
|||
private extension ProfileView.RenameView {
|
||||
func loadCurrentName() {
|
||||
newName = currentProfile.value.header.name
|
||||
focusedField = .name
|
||||
}
|
||||
|
||||
func commitRenaming() {
|
||||
|
|
Loading…
Reference in New Issue