// // DocsView.swift // Splits // // Created by Isaac Greene on 6/3/22. // import SwiftUI import LocalAuthentication // this file will have some comments. // Most of this code is considered simple enough // to be human-readable without aid, as long as // the reader has a basic understanding of // Swift and/or SwiftUI. /// The system username for the app /// - Note: This is not a secure way to do it /// or in any way good practice /// but this is mainly to test out `SecureField` let username = "admin" /// The system password associated with ``username`` /// /// I'm thinking about hashing them, but that would take work. /// /// It would be more secure though. /// - Note: Just as with `username` you should not define /// these unencrypted like they are right now. let password = "123" /// Holds the views and login for the Docs tab in-app /// /// Mostly just a long list of sections and calling views /// - Note: New views are best called in this `struct` struct DocsView: View { enum Field: Hashable { case username case password } @State private var pass: String = "" @State private var user: String = "" @State private var isUnlocked = false @FocusState private var focusedField: Field? var body: some View { NavigationView { List { NavigationLink("Help", destination: HelpView()) NavigationLink("Change Log", destination: ChangeLog()) Section(header: Text("Features")) { NavigationLink("New", destination: NewFeatures()) NavigationLink("In Progress", destination: InProgressFeatures()) NavigationLink("Deprecated", destination: DeprecatedFeatures()) } Section(header: Text("Known Issues")) { NavigationLink("Recently Resolved", destination: RecentlyResolved()) NavigationLink("High Priority", destination: HighPriority()) NavigationLink("Medium Priority", destination: MediumPriority()) NavigationLink("Low Priority", destination: LowPriority()) } Section(header: Text("App Information")) { NavigationLink("Software License", destination: LicenseView()) Text("Version: Release Candidate 4") Text("Release date: 2022-06-17") Text("Start date: 2022-03-25") Link("Built with SwiftUI \(Image(systemName: "swift"))", destination: URL(string: "https://developer.apple.com/xcode/swiftui")!) } Section(header: Text("Login")) { if (isUnlocked) { NavigationLink("Contacts", destination: SecretView()) Button("Log out") { pass = "" user = "" isUnlocked = false } } else { Button("Log in with biometrics") { authenticate() } SecureField("Username", text: $user) .keyboardType(.alphabet) .textContentType(.username) .submitLabel(.next) .focused($focusedField, equals: .username) .textContentType(.username) SecureField("Password", text: $pass) .keyboardType(.numbersAndPunctuation) .textContentType(.password) .submitLabel(.done) .focused($focusedField, equals: .password) .textContentType(.password) if checkPassword() { NavigationLink("Contacts", destination: SecretView()) } } } } .navigationTitle("Docs") } .onSubmit { switch focusedField { case .username: focusedField = .password default: () } if checkPassword() { isUnlocked = true } } } /// Compares the `user` SecureField and the `pass` SecureField against ``username`` and ``password`` /// /// - Note: come back to this /// /// /// - Returns: `true` if `user` equals `username` *and* `pass` equals `password`, `false` if one or both checks return false. func checkPassword() -> Bool { if (pass == password && user == username) { return true } else { return false } } /// Checks wether the user can use biometrics to sign in /// and (if true) prompts the user to sign with either FaceID or TouchID /// depending on the device. /// /// If the prompt was shown, and the user authenticated correctly /// `isUnlocked` is set to `true` /// /// - Note: `authenticate()` has to be called to show the sign-in sheet func authenticate() { let context = LAContext() var error: NSError? // check whether biometric authentication is possible if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { // it's possible, so go ahead and use it let reason = "We need authentication before we can show you sensitive data" context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, authenticationError in // authentication has now completed if success { isUnlocked = true } else { () } } } else { () } } // getting this to work came from // https://www.hackingwithswift.com/books/ios-swiftui/using-touch-id-and-face-id-with-swiftui // a truly epic website and it's helped me with // just about all of my code questions } struct DocsView_Previews: PreviewProvider { static var previews: some View { DocsView() } }