diff --git a/Splits.xcodeproj/project.pbxproj b/Splits.xcodeproj/project.pbxproj index ba68ed2..bf9fb1a 100644 --- a/Splits.xcodeproj/project.pbxproj +++ b/Splits.xcodeproj/project.pbxproj @@ -335,13 +335,14 @@ DEVELOPMENT_TEAM = UQJ7U8R2CV; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSFaceIDUsageDescription = "We'll need authentication before we can show sensitive data"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UIRequiresFullScreen = NO; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeRight UIInterfaceOrientationLandscapeLeft"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; IPHONEOS_DEPLOYMENT_TARGET = 15.5; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -370,13 +371,14 @@ DEVELOPMENT_TEAM = UQJ7U8R2CV; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSFaceIDUsageDescription = "We'll need authentication before we can show sensitive data"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UIRequiresFullScreen = NO; INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeRight UIInterfaceOrientationLandscapeLeft"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; IPHONEOS_DEPLOYMENT_TARGET = 15.5; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/Splits/ChangeLogData.swift b/Splits/ChangeLogData.swift index a361571..c28c9af 100644 --- a/Splits/ChangeLogData.swift +++ b/Splits/ChangeLogData.swift @@ -12,6 +12,19 @@ import SwiftUI struct June2022: View { var body: some View { ScrollView { + //2022-06-11 + HStack { + VStack (alignment: .leading) { + Text("2022-06-11") + .font(.title2) + Text("Version Release Candidate 2 (LVSXT10a.2)\n") + .font(.footnote) + Text("\u{2022} Added biometrics to sign in along with option for username/password") + } + Spacer() + } + .padding(30) + //2022-06-10 HStack { VStack (alignment: .leading) { diff --git a/Splits/ContentView.swift b/Splits/ContentView.swift index 86290eb..bfd424b 100644 --- a/Splits/ContentView.swift +++ b/Splits/ContentView.swift @@ -21,7 +21,7 @@ struct ContentView: View { VStack { Spacer() VStack { - TextField("Enter distance here", text: $distance) + TextField("Enter distance", text: $distance) .padding() .keyboardType(.decimalPad) .textFieldStyle(.roundedBorder) @@ -39,7 +39,7 @@ struct ContentView: View { HStack { VStack { Text("Hours") - TextField("Enter hours here", text: $timeHours) + TextField("Enter hours", text: $timeHours) .keyboardType(.numberPad) .textFieldStyle(.roundedBorder) .focused($nameIsFocused) @@ -49,7 +49,7 @@ struct ContentView: View { .padding() VStack { Text("Minutes") - TextField("Enter minutes here", text: $timeMinutes) + TextField("Enter minutes", text: $timeMinutes) .keyboardType(.numberPad) .textFieldStyle(.roundedBorder) .focused($nameIsFocused) @@ -60,7 +60,7 @@ struct ContentView: View { .padding() VStack { Text("Seconds") - TextField("Enter seconds here", text: $timeSeconds) + TextField("Enter seconds", text: $timeSeconds) .keyboardType(.numberPad) .textFieldStyle(.roundedBorder) .focused($nameIsFocused) @@ -99,10 +99,10 @@ struct PaceResults: View { // but then my message would disappear to let you know // what to enter in that box - let multiplier = {selectedSystem == "mi" ? 1.609344 : 0.6213711922}() - let notSelectedSystem = {selectedSystem == "km" ? "mi" : "km"}() + let multiplier = (selectedSystem == "mi" ? 1.609344 : 0.6213711922) + let notSelectedSystem = (selectedSystem == "km" ? "mi" : "km") let convertedDistance = distanceDub * multiplier - let convertedDistanceString = {distance == "" ? "" : String(format: "%.2f", convertedDistance)}() + let convertedDistanceString = (distance == "" ? "" : String(format: "%.2f", convertedDistance)) let convertedSeconds:Double = (Double(timeSeconds) ?? 0) * (1.6666666666666666666666666) let timeSecondsInt:Int = Int(timeSeconds) ?? 0 @@ -164,9 +164,9 @@ struct PaceResults: View { // and the hours calculated in the previous section // and adds them together to get our total number of hours. let hoursFormatted:String = String(format: "%.0f", totalHours) - let paceFormatted:String = {pace >= 60 ? "\(paceHours):\(properTimeMS)" : "\(properTimeMS)"}() + let paceFormatted:String = (pace >= 60 ? "\(paceHours):\(properTimeMS)" : "\(properTimeMS)") - let paceFormattedOpposite:String = {paceOpposite >= 60 ? "\(paceHoursOpposite):\(properTimeMSOpposite)" : "\(properTimeMSOpposite)"}() + let paceFormattedOpposite:String = (paceOpposite >= 60 ? "\(paceHoursOpposite):\(properTimeMSOpposite)" : "\(properTimeMSOpposite)") let leadingZeros:String = String(format: "%02d:%02d", timeMinutesUnderSixty, timeSecondsUnderSixty) // this takes the minutes and the seconds and adds leading @@ -176,15 +176,18 @@ struct PaceResults: View { HStack { VStack { - Text("Distance: \(distance)\(selectedSystem)") - Text("Distance: \(convertedDistanceString)\(notSelectedSystem)") + Text("\(distance)\(selectedSystem)") + Text("\(convertedDistanceString)\(notSelectedSystem)") } - Text("Total time\n\(hoursFormatted):\(leadingZeros)") + .frame(minWidth: 100) + Text("\(hoursFormatted):\(leadingZeros)") .padding() + .frame(minWidth: 100) VStack(alignment: .trailing) { - Text("\(paceFormatted) per \(selectedSystem)") - Text("\(paceFormattedOpposite) per \(notSelectedSystem)") + Text("\(paceFormatted)/\(selectedSystem)") + Text("\(paceFormattedOpposite)/\(notSelectedSystem)") } + .frame(minWidth: 100) } } } diff --git a/Splits/DocsView.swift b/Splits/DocsView.swift index dbb6208..183935c 100644 --- a/Splits/DocsView.swift +++ b/Splits/DocsView.swift @@ -6,9 +6,10 @@ // import SwiftUI -// this file will not have comments. -// this code is considered simple enough to be -// human-readable without aid, as long as +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. @@ -23,7 +24,8 @@ struct DocsView: View { @State private var pass: String = "" @State private var user: String = "" - @FocusState private var focusedField: Field? + @State private var isUnlocked = false + @FocusState private var focusedField: Field? var body: some View { NavigationView { @@ -44,24 +46,38 @@ struct DocsView: View { } Section(header: Text("App Information")) { NavigationLink("Software License", destination: LicenseView()) - Text("Version: Release Candidate (1.0.0)") - Text("Release date: 2022-06-10") + Text("Version: Release Candidate 2 (1.0.0)") + Text("Release date: 2022-06-11") 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")) { - SecureField("Username", text: $user) - .keyboardType(.alphabet) - .textContentType(.username) - .submitLabel(.next) - .focused($focusedField, equals: .username) - SecureField("Password", text: $pass) - .keyboardType(.numbersAndPunctuation) - .textContentType(.password) - .submitLabel(.done) - .focused($focusedField, equals: .password) - if (pass == password && user == username) { + if (isUnlocked) { NavigationLink("Contacts", destination: SecretView()) + Button("Log out") { + pass = "" + user = "" + isUnlocked = false + } + } else { + if !isUnlocked { + Button("Log in with biometrics") { + authenticate() + } + } + SecureField("Username", text: $user) + .keyboardType(.alphabet) + .textContentType(.username) + .submitLabel(.next) + .focused($focusedField, equals: .username) + SecureField("Password", text: $pass) + .keyboardType(.numbersAndPunctuation) + .textContentType(.password) + .submitLabel(.done) + .focused($focusedField, equals: .password) + if checkPassword() { + NavigationLink("Contacts", destination: SecretView()) + } } } } @@ -74,8 +90,48 @@ struct DocsView: View { default: () } + if (pass == password && user == username) { + isUnlocked = true + } } } + func checkPassword() -> Bool { + if (pass == password && user == username) { + return true + } else { + return false + } + } + func checkIfUnlocked() { + if !isUnlocked { + authenticate() + } + } + 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 { diff --git a/Splits/FeaturesView.swift b/Splits/FeaturesView.swift index 2a03e49..130ce1e 100644 --- a/Splits/FeaturesView.swift +++ b/Splits/FeaturesView.swift @@ -11,6 +11,14 @@ struct NewFeatures: View { var body: some View { ScrollView { VStack(alignment: .leading) { + Text("\u{2022} Added TouchID and FaceID to sign in") + Text("Implemented in Version Release Candidate 2\n") + .font(.footnote) + .italic() + Text("\u{2022} Implemented a way to dismiss the keyboard") + Text("Implemented in Version Release Candidate\n") + .font(.footnote) + .italic() Text("\u{2022} Reformatted the Docs tabs and made the common things up at the top") Text("Implemented in Version Prerelease LVSXT10d.2\n") .font(.footnote) @@ -33,15 +41,11 @@ struct NewFeatures: View { struct InProgressFeatures: View { var body: some View { ScrollView { - Text("Features In Progress") - .font(.largeTitle) - .bold() - .padding(.top, 40) Text("Note: this does not include things I have to fix\n") .font(.footnote) .italic() VStack(alignment: .leading) { - Text("\u{2022} Working on a conversion between measurements for pace and distance\n") + Text("\u{2022} Adding a better-formatted Contacts tab on iPad\n") } .padding(30) } @@ -52,10 +56,6 @@ struct InProgressFeatures: View { struct DeprecatedFeatures: View { var body: some View { ScrollView { - Text("Deprecated Features") - .font(.largeTitle) - .bold() - .padding(.top, 40) VStack(alignment: .leading) { Text("\n\u{2022} Removed the picker wheel to enter total time (a truly horrible system)") Text("Stricken before recorded history\n") diff --git a/Splits/KnownIssues.swift b/Splits/KnownIssues.swift index 6915b47..5ee79af 100644 --- a/Splits/KnownIssues.swift +++ b/Splits/KnownIssues.swift @@ -13,7 +13,7 @@ struct RecentlyResolved: View { var body: some View { ScrollView { VStack(alignment: .leading) { - Text("\u{2022} Implemented an easy way to dismiss the keyboard in the main view of Calculator (it only took 2 1/2 months)") + Text("\u{2022} Implemented an easy way to dismiss the keyboard in the main view of Calculator (it only took 2 1/2 months)\n\u{2022} Opening the contacts tab no longer causes the app to crash (RC 2)") } .padding(30) } @@ -24,8 +24,11 @@ struct RecentlyResolved: View { struct HighPriority: View { var body: some View { ScrollView { - VStack(alignment: .leading) { - Text("Tapping on the Contacts tab after entering correct login details causes the app to crash") + VStack { + Image(systemName: "checkmark.shield.fill") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 70) } .padding(30) } @@ -36,9 +39,11 @@ struct HighPriority: View { struct MediumPriority: View { var body: some View { ScrollView { - VStack(alignment: .leading) { - Text("Wow. Such Empty.") - .italic() + VStack { + Image(systemName: "checkmark.shield.fill") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 70) } .padding(30) } diff --git a/Splits/LicenseView.swift b/Splits/LicenseView.swift index 05aeef8..c201d69 100644 --- a/Splits/LicenseView.swift +++ b/Splits/LicenseView.swift @@ -17,7 +17,6 @@ struct LicenseView: View { // setting fontSize to a value based on that where the whole // line can be viewed without scrolling horizontally // or with wrapped text, ruining the required formatting I have. - // As of 2022-06-08, I have not tested this on a phone. var body: some View { ScrollView { diff --git a/Splits/SecretView.swift b/Splits/SecretView.swift index 6878478..aa648d3 100644 --- a/Splits/SecretView.swift +++ b/Splits/SecretView.swift @@ -14,8 +14,8 @@ import SwiftUI struct SecretView: View { var body: some View { - VStack { - ScrollView { + ScrollView { + VStack { VStack { Image("jake.zimmerman.group") .resizable() @@ -101,9 +101,90 @@ Email: greenei@students.lakeviewspartans.org } .frame(minWidth: 350, minHeight: 175) .border(.primary) + VStack { + Image(systemName: "person.crop.circle.fill") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 75, height: 75) + Text("Pryor") + .font(.title2) + VStack (alignment: .leading) { + Text(""" +Name: Becky Pryor +Email: bpryor@lakeviewspartans.org +""") + HStack { + Text("Phone:") + Link("(269) 209-9906", destination: URL(string: "tel:2692099906")!) + } + } + } + .frame(minWidth: 350, minHeight: 175) + .border(.primary) + VStack { + Image(systemName: "person.crop.circle.fill") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 75, height: 75) + Text("Paige") + .font(.title2) + VStack (alignment: .leading) { + Text(""" +Name: Paige Ratliff +Email: ratliffp@students.lakeviewspartans.org +""") + HStack { + Text("Phone:") + Link("(269) 753-8569", destination: URL(string: "tel:2697538569")!) + } + } + } + .frame(minWidth: 350, minHeight: 175) + .border(.primary) + VStack { + Image(systemName: "person.crop.circle.fill") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 75, height: 75) + Text("Emma") + .font(.title2) + VStack (alignment: .leading) { + Text(""" +Name: Emma Kerschbaum +Email: kerschbaume@students.lakeviewspartans.org +""") + HStack { + Text("Phone:") + Link("(269) 419-7880", destination: URL(string: "tel:2694197880")!) + } + } + } + .frame(minWidth: 350, minHeight: 175) + .border(.primary) + VStack { + Image(systemName: "person.crop.circle.fill") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 75, height: 75) + Text("Alyssa") + .font(.title2) + VStack (alignment: .leading) { + Text(""" +Name: Alyssa Hinton +Email: hintona2@students.lakeviewspartans.org +""") + HStack { + Text("Phone:") + Link("(269) 589-7609", destination: URL(string: "tel:2695897609")!) + } + } + } + .frame(minWidth: 350, minHeight: 175) + .border(.primary) + } + .frame(maxWidth: .infinity) .navigationTitle("Contacts") } - .frame(minWidth: .infinity) } } diff --git a/qerberymjthnrgbefvdcs.playground/Contents.swift b/qerberymjthnrgbefvdcs.playground/Contents.swift new file mode 100644 index 0000000..80cb5ea --- /dev/null +++ b/qerberymjthnrgbefvdcs.playground/Contents.swift @@ -0,0 +1,6 @@ +import UIKit +var selectedSystem = "mi" + +let multiplier = (selectedSystem == "mi" ? 1.609344 : 0.6213711922) + +print(multiplier) diff --git a/qerberymjthnrgbefvdcs.playground/contents.xcplayground b/qerberymjthnrgbefvdcs.playground/contents.xcplayground new file mode 100644 index 0000000..cf026f2 --- /dev/null +++ b/qerberymjthnrgbefvdcs.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/qerberymjthnrgbefvdcs.playground/playground.xcworkspace/contents.xcworkspacedata b/qerberymjthnrgbefvdcs.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..ca3329e --- /dev/null +++ b/qerberymjthnrgbefvdcs.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/qerberymjthnrgbefvdcs.playground/timeline.xctimeline b/qerberymjthnrgbefvdcs.playground/timeline.xctimeline new file mode 100644 index 0000000..8510264 --- /dev/null +++ b/qerberymjthnrgbefvdcs.playground/timeline.xctimeline @@ -0,0 +1,11 @@ + + + + + + +