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:
Davide De Rosa 2023-07-23 13:28:47 +02:00 committed by GitHub
parent 6ede6f052a
commit 34f6738b69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 47 additions and 3 deletions

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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
}
}
}

View File

@ -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)

View File

@ -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() {