From 73ee9c847b69addc4006f58da6c596209156775c Mon Sep 17 00:00:00 2001 From: brianna Date: Mon, 8 Jul 2024 16:31:44 -0700 Subject: [PATCH 1/9] Add verification flow to sample app. --- .../project.pbxproj | 14 ++++- .../Services/GoogleSignInAuthenticator.swift | 26 ++++++++ .../ViewModels/AuthenticationViewModel.swift | 32 ++++++++++ .../Shared/Views/VerificationView.swift | 62 +++++++++++++++++++ .../iOS/UserProfileView.swift | 7 +++ 5 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 Samples/Swift/DaysUntilBirthday/Shared/Views/VerificationView.swift diff --git a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj index 87f26e0c..8388274d 100644 --- a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj +++ b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj @@ -3,11 +3,13 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 4C6A2BA2321434ACBD2AF201 /* Pods_DaysUntilBirthdayForPod__macOS_.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 926A15D393D684C68E09FB0F /* Pods_DaysUntilBirthdayForPod__macOS_.framework */; }; + 641495072C3C90E100C9A613 /* VerificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 641495062C3C90E100C9A613 /* VerificationView.swift */; }; + 641495082C3C90E100C9A613 /* VerificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 641495062C3C90E100C9A613 /* VerificationView.swift */; }; 7345AD032703D9470020AFB1 /* DaysUntilBirthday.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7345AD022703D9470020AFB1 /* DaysUntilBirthday.swift */; }; 7345AD052703D9470020AFB1 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7345AD042703D9470020AFB1 /* ContentView.swift */; }; 7345AD072703D9480020AFB1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7345AD062703D9480020AFB1 /* Assets.xcassets */; }; @@ -45,6 +47,7 @@ 1A129363EBB5DF1F41FAAB14 /* Pods-DaysUntilBirthdayForPod(macOS).release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DaysUntilBirthdayForPod(macOS).release.xcconfig"; path = "Target Support Files/Pods-DaysUntilBirthdayForPod(macOS)/Pods-DaysUntilBirthdayForPod(macOS).release.xcconfig"; sourceTree = ""; }; 29BEB027A694593FA0450863 /* Pods-DaysUntilBirthdayForPod(iOS).debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DaysUntilBirthdayForPod(iOS).debug.xcconfig"; path = "Target Support Files/Pods-DaysUntilBirthdayForPod(iOS)/Pods-DaysUntilBirthdayForPod(iOS).debug.xcconfig"; sourceTree = ""; }; 5CF615341A61D92D89389D44 /* Pods-DaysUntilBirthdayForPod (macOS).release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DaysUntilBirthdayForPod (macOS).release.xcconfig"; path = "Target Support Files/Pods-DaysUntilBirthdayForPod (macOS)/Pods-DaysUntilBirthdayForPod (macOS).release.xcconfig"; sourceTree = ""; }; + 641495062C3C90E100C9A613 /* VerificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationView.swift; sourceTree = ""; }; 7345ACFF2703D9470020AFB1 /* DaysUntilBirthdayForPod (iOS).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DaysUntilBirthdayForPod (iOS).app"; sourceTree = BUILT_PRODUCTS_DIR; }; 7345AD022703D9470020AFB1 /* DaysUntilBirthday.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaysUntilBirthday.swift; sourceTree = ""; }; 7345AD042703D9470020AFB1 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -195,6 +198,7 @@ children = ( 7345AD042703D9470020AFB1 /* ContentView.swift */, 739FCC45270E467600C92042 /* BirthdayView.swift */, + 641495062C3C90E100C9A613 /* VerificationView.swift */, 7345AD112703D9C30020AFB1 /* SignInView.swift */, 7345AD142703D9C30020AFB1 /* UserProfileImageView.swift */, ); @@ -413,6 +417,7 @@ buildActionMask = 2147483647; files = ( 739FCC48270E659A00C92042 /* Birthday.swift in Sources */, + 641495072C3C90E100C9A613 /* VerificationView.swift in Sources */, 739FCC46270E467600C92042 /* BirthdayView.swift in Sources */, 7345AD1B2703D9C30020AFB1 /* SignInView.swift in Sources */, 7345AD212703D9C30020AFB1 /* GoogleSignInAuthenticator.swift in Sources */, @@ -432,6 +437,7 @@ buildActionMask = 2147483647; files = ( 73DB41912805FBFD0028B8D3 /* SignInView.swift in Sources */, + 641495082C3C90E100C9A613 /* VerificationView.swift in Sources */, 73DB418B2805FBC40028B8D3 /* BirthdayLoader.swift in Sources */, 73DB418D2805FBD00028B8D3 /* AuthenticationViewModel.swift in Sources */, 73DB418F2805FBF50028B8D3 /* ContentView.swift in Sources */, @@ -577,6 +583,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"iOS/Preview Content\""; + DEVELOPMENT_TEAM = JA85M8JD4Z; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -584,7 +591,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.google.DaysUntilBirthday; + PRODUCT_BUNDLE_IDENTIFIER = "testing-com.google.DaysUntilBirthday"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -599,6 +606,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"iOS/Preview Content\""; + DEVELOPMENT_TEAM = JA85M8JD4Z; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -606,7 +614,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.google.DaysUntilBirthday; + PRODUCT_BUNDLE_IDENTIFIER = "testing-com.google.DaysUntilBirthday"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift index deacb35b..21478dc7 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift @@ -27,6 +27,32 @@ final class GoogleSignInAuthenticator: ObservableObject { self.authViewModel = authViewModel } +#if os(iOS) + /// Verifies the user's age based upon the selected account. + /// - note: Successful calls to this will set the `authViewModel`'s `verificationState` property. + func verifyAccountDetails() { + let accountDetails: [GIDVerifiableAccountDetail] = [ + GIDVerifiableAccountDetail(accountDetailType:.ageOver18) + ] + + guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { + print("There is no root view controller!") + return + } + + let verifyAccountDetail = GIDVerifyAccountDetail() + verifyAccountDetail.verifyAccountDetails(accountDetails, presenting: rootViewController) { + verifyResult, error in + guard let verifyResult = verifyResult else { + self.authViewModel.verificationState = .unverified + print("Error! \(String(describing: error))") + return + } + self.authViewModel.verificationState = .verified(verifyResult) + } + } +#endif + /// Signs in the user based upon the selected account.' /// - note: Successful calls to this will set the `authViewModel`'s `state` property. func signIn() { diff --git a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift index 3ad14289..bf275eb6 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift @@ -22,6 +22,13 @@ final class AuthenticationViewModel: ObservableObject { /// The user's log in status. /// - note: This will publish updates when its value changes. @Published var state: State + +#if os(iOS) + /// The user's account verification status. + /// - note: This will publish updates when its value changes. + @Published var verificationState: VerificationState +#endif + private var authenticator: GoogleSignInAuthenticator { return GoogleSignInAuthenticator(authViewModel: self) } @@ -43,6 +50,9 @@ final class AuthenticationViewModel: ObservableObject { } else { self.state = .signedOut } +#if os(iOS) + self.verificationState = .unverified +#endif } /// Signs the user in. @@ -60,6 +70,18 @@ final class AuthenticationViewModel: ObservableObject { authenticator.disconnect() } +#if os(iOS) + /// Verifies the user. + func verifyAccountDetails() { + switch self.verificationState { + case .unverified: + authenticator.verifyAccountDetails() + case .verified: + return + } + } +#endif + var hasBirthdayReadScope: Bool { return authorizedScopes.contains(BirthdayLoader.birthdayReadScope) } @@ -80,4 +102,14 @@ extension AuthenticationViewModel { /// The user is logged out. case signedOut } + +#if os(iOS) + /// An enumeration representing verified status. + enum VerificationState { + /// The user's account is verified and is the associated value of this case. + case verified(GIDVerifiedAccountDetailResult) + /// The user's account is not verified. + case unverified + } +#endif } diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Views/VerificationView.swift b/Samples/Swift/DaysUntilBirthday/Shared/Views/VerificationView.swift new file mode 100644 index 00000000..93048122 --- /dev/null +++ b/Samples/Swift/DaysUntilBirthday/Shared/Views/VerificationView.swift @@ -0,0 +1,62 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import SwiftUI +import GoogleSignIn + +struct VerificationView: View { + @ObservedObject var authViewModel: AuthenticationViewModel + + var body: some View { + switch authViewModel.verificationState { + case .verified(let result): + VStack(alignment:.leading) { + Text("List of result object properties:") + .font(.headline) + + HStack(alignment: .top) { + Text("Access Token:") + Text(result.accessTokenString ?? "Not available") + } + HStack(alignment: .top) { + Text("Refresh Token:") + Text(result.refreshTokenString ?? "Not available") + } + HStack { + Text("Expiration:") + if let expirationDate = result.expirationDate { + Text(formatDateWithDateFormatter(expirationDate)) + } else { + Text("Not available") + } + } + Spacer() + } + .navigationTitle("Verified Account!") + case .unverified: + ProgressView() + .navigationTitle(NSLocalizedString("Unverified account", + comment: "Unverified account label")) + } + } + + func formatDateWithDateFormatter(_ date: Date) -> String { + let dateFormatter = DateFormatter() + dateFormatter.dateStyle = .medium + dateFormatter.timeStyle = .short + return dateFormatter.string(from: date) + } +} diff --git a/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift b/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift index 93366f47..256b02ac 100644 --- a/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift +++ b/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift @@ -50,6 +50,13 @@ struct UserProfileView: View { return } }) +#if os(iOS) + NavigationLink(NSLocalizedString("Verify My Age", comment: "Verify Age"), + destination: VerificationView(authViewModel: authViewModel) + .onAppear { + authViewModel.verifyAccountDetails() + }) +#endif Spacer() } .toolbar { From 367437d5d0c724f7e148186b2d400ec6f6d2e653 Mon Sep 17 00:00:00 2001 From: brianna Date: Tue, 9 Jul 2024 17:10:57 -0700 Subject: [PATCH 2/9] Fix indentation and remove development_team from project.pbxproj. --- .../DaysUntilBirthdayForPod.xcodeproj/project.pbxproj | 4 ---- .../Shared/Services/GoogleSignInAuthenticator.swift | 10 +++++----- .../Shared/Views/VerificationView.swift | 8 ++++---- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj index 8388274d..7eafc9da 100644 --- a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj +++ b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj @@ -583,7 +583,6 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"iOS/Preview Content\""; - DEVELOPMENT_TEAM = JA85M8JD4Z; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -591,7 +590,6 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = "testing-com.google.DaysUntilBirthday"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -606,7 +604,6 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"iOS/Preview Content\""; - DEVELOPMENT_TEAM = JA85M8JD4Z; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = iOS/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -614,7 +611,6 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = "testing-com.google.DaysUntilBirthday"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift index 21478dc7..6facce87 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift @@ -43,11 +43,11 @@ final class GoogleSignInAuthenticator: ObservableObject { let verifyAccountDetail = GIDVerifyAccountDetail() verifyAccountDetail.verifyAccountDetails(accountDetails, presenting: rootViewController) { verifyResult, error in - guard let verifyResult = verifyResult else { - self.authViewModel.verificationState = .unverified - print("Error! \(String(describing: error))") - return - } + guard let verifyResult = verifyResult else { + self.authViewModel.verificationState = .unverified + print("Error! \(String(describing: error))") + return + } self.authViewModel.verificationState = .verified(verifyResult) } } diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Views/VerificationView.swift b/Samples/Swift/DaysUntilBirthday/Shared/Views/VerificationView.swift index 93048122..af1b8965 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Views/VerificationView.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Views/VerificationView.swift @@ -54,9 +54,9 @@ struct VerificationView: View { } func formatDateWithDateFormatter(_ date: Date) -> String { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .short - return dateFormatter.string(from: date) + let dateFormatter = DateFormatter() + dateFormatter.dateStyle = .medium + dateFormatter.timeStyle = .short + return dateFormatter.string(from: date) } } From edcf98547ce52ab968592abe36bdc79be2dbc27c Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 10 Jul 2024 12:32:20 -0700 Subject: [PATCH 3/9] Create `VerifiedAgeViewModel` to load and hold verification state. --- .../project.pbxproj | 8 +++ .../Services/GoogleSignInAuthenticator.swift | 26 --------- .../Shared/Services/VerificationLoader.swift | 57 +++++++++++++++++++ .../ViewModels/AuthenticationViewModel.swift | 31 ---------- .../ViewModels/VerifiedAgeViewModel.swift | 57 +++++++++++++++++++ .../Shared/Views/VerificationView.swift | 4 +- .../iOS/UserProfileView.swift | 6 +- 7 files changed, 128 insertions(+), 61 deletions(-) create mode 100644 Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift create mode 100644 Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift diff --git a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj index 7eafc9da..1fecb2e5 100644 --- a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj +++ b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj @@ -10,6 +10,8 @@ 4C6A2BA2321434ACBD2AF201 /* Pods_DaysUntilBirthdayForPod__macOS_.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 926A15D393D684C68E09FB0F /* Pods_DaysUntilBirthdayForPod__macOS_.framework */; }; 641495072C3C90E100C9A613 /* VerificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 641495062C3C90E100C9A613 /* VerificationView.swift */; }; 641495082C3C90E100C9A613 /* VerificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 641495062C3C90E100C9A613 /* VerificationView.swift */; }; + 6414950A2C3E094B00C9A613 /* VerifiedAgeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 641495092C3E094B00C9A613 /* VerifiedAgeViewModel.swift */; }; + 6414950C2C3E0C7A00C9A613 /* VerificationLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6414950B2C3E0C7A00C9A613 /* VerificationLoader.swift */; }; 7345AD032703D9470020AFB1 /* DaysUntilBirthday.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7345AD022703D9470020AFB1 /* DaysUntilBirthday.swift */; }; 7345AD052703D9470020AFB1 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7345AD042703D9470020AFB1 /* ContentView.swift */; }; 7345AD072703D9480020AFB1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7345AD062703D9480020AFB1 /* Assets.xcassets */; }; @@ -48,6 +50,8 @@ 29BEB027A694593FA0450863 /* Pods-DaysUntilBirthdayForPod(iOS).debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DaysUntilBirthdayForPod(iOS).debug.xcconfig"; path = "Target Support Files/Pods-DaysUntilBirthdayForPod(iOS)/Pods-DaysUntilBirthdayForPod(iOS).debug.xcconfig"; sourceTree = ""; }; 5CF615341A61D92D89389D44 /* Pods-DaysUntilBirthdayForPod (macOS).release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DaysUntilBirthdayForPod (macOS).release.xcconfig"; path = "Target Support Files/Pods-DaysUntilBirthdayForPod (macOS)/Pods-DaysUntilBirthdayForPod (macOS).release.xcconfig"; sourceTree = ""; }; 641495062C3C90E100C9A613 /* VerificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationView.swift; sourceTree = ""; }; + 641495092C3E094B00C9A613 /* VerifiedAgeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifiedAgeViewModel.swift; sourceTree = ""; }; + 6414950B2C3E0C7A00C9A613 /* VerificationLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationLoader.swift; sourceTree = ""; }; 7345ACFF2703D9470020AFB1 /* DaysUntilBirthdayForPod (iOS).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DaysUntilBirthdayForPod (iOS).app"; sourceTree = BUILT_PRODUCTS_DIR; }; 7345AD022703D9470020AFB1 /* DaysUntilBirthday.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaysUntilBirthday.swift; sourceTree = ""; }; 7345AD042703D9470020AFB1 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -218,6 +222,7 @@ children = ( 7345AD162703D9C30020AFB1 /* AuthenticationViewModel.swift */, 736F49BB270E102C00580053 /* BirthdayViewModel.swift */, + 641495092C3E094B00C9A613 /* VerifiedAgeViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -226,6 +231,7 @@ isa = PBXGroup; children = ( 7345AD172703D9C30020AFB1 /* GoogleSignInAuthenticator.swift */, + 6414950B2C3E0C7A00C9A613 /* VerificationLoader.swift */, 736F49B9270E05E200580053 /* BirthdayLoader.swift */, 7345AD192703D9C30020AFB1 /* UserProfileImageLoader.swift */, ); @@ -421,9 +427,11 @@ 739FCC46270E467600C92042 /* BirthdayView.swift in Sources */, 7345AD1B2703D9C30020AFB1 /* SignInView.swift in Sources */, 7345AD212703D9C30020AFB1 /* GoogleSignInAuthenticator.swift in Sources */, + 6414950A2C3E094B00C9A613 /* VerifiedAgeViewModel.swift in Sources */, 7345AD232703D9C30020AFB1 /* UserProfileImageLoader.swift in Sources */, 7345AD1E2703D9C30020AFB1 /* UserProfileImageView.swift in Sources */, 736F49BC270E102C00580053 /* BirthdayViewModel.swift in Sources */, + 6414950C2C3E0C7A00C9A613 /* VerificationLoader.swift in Sources */, 736F49BA270E05E200580053 /* BirthdayLoader.swift in Sources */, 7345AD242703D9C30020AFB1 /* UserProfileView.swift in Sources */, 7345AD202703D9C30020AFB1 /* AuthenticationViewModel.swift in Sources */, diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift index 6facce87..deacb35b 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/GoogleSignInAuthenticator.swift @@ -27,32 +27,6 @@ final class GoogleSignInAuthenticator: ObservableObject { self.authViewModel = authViewModel } -#if os(iOS) - /// Verifies the user's age based upon the selected account. - /// - note: Successful calls to this will set the `authViewModel`'s `verificationState` property. - func verifyAccountDetails() { - let accountDetails: [GIDVerifiableAccountDetail] = [ - GIDVerifiableAccountDetail(accountDetailType:.ageOver18) - ] - - guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { - print("There is no root view controller!") - return - } - - let verifyAccountDetail = GIDVerifyAccountDetail() - verifyAccountDetail.verifyAccountDetails(accountDetails, presenting: rootViewController) { - verifyResult, error in - guard let verifyResult = verifyResult else { - self.authViewModel.verificationState = .unverified - print("Error! \(String(describing: error))") - return - } - self.authViewModel.verificationState = .verified(verifyResult) - } - } -#endif - /// Signs in the user based upon the selected account.' /// - note: Successful calls to this will set the `authViewModel`'s `state` property. func signIn() { diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift new file mode 100644 index 00000000..edd9bf13 --- /dev/null +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift @@ -0,0 +1,57 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation +import GoogleSignIn + +#if os(iOS) + +/// An observable class for verifying via Google. +final class VerificationLoader: ObservableObject { + private var verifiedAgeViewModel: VerifiedAgeViewModel + + /// Creates an instance of this loader. + /// - parameter verifiedAgeViewModel: The view model to use to set verification status on. + init(verifiedViewAgeModel: VerifiedAgeViewModel) { + self.verifiedAgeViewModel = verifiedViewAgeModel + } + + /// Verifies the user's age based upon the selected account. + /// - note: Successful calls to this will set the `verifiedAgeViewModel`'s `verificationState` property. + func verifyAccountDetails() { + let accountDetails: [GIDVerifiableAccountDetail] = [ + GIDVerifiableAccountDetail(accountDetailType:.ageOver18) + ] + + guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { + print("There is no root view controller!") + return + } + + let verifyAccountDetail = GIDVerifyAccountDetail() + verifyAccountDetail.verifyAccountDetails(accountDetails, presenting: rootViewController) { + verifyResult, error in + guard let verifyResult = verifyResult else { + self.verifiedAgeViewModel.verificationState = .unverified + print("Error! \(String(describing: error))") + return + } + self.verifiedAgeViewModel.verificationState = .verified(verifyResult) + } + } +} + +#endif diff --git a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift index bf275eb6..6217e03f 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift @@ -23,12 +23,6 @@ final class AuthenticationViewModel: ObservableObject { /// - note: This will publish updates when its value changes. @Published var state: State -#if os(iOS) - /// The user's account verification status. - /// - note: This will publish updates when its value changes. - @Published var verificationState: VerificationState -#endif - private var authenticator: GoogleSignInAuthenticator { return GoogleSignInAuthenticator(authViewModel: self) } @@ -50,9 +44,6 @@ final class AuthenticationViewModel: ObservableObject { } else { self.state = .signedOut } -#if os(iOS) - self.verificationState = .unverified -#endif } /// Signs the user in. @@ -70,18 +61,6 @@ final class AuthenticationViewModel: ObservableObject { authenticator.disconnect() } -#if os(iOS) - /// Verifies the user. - func verifyAccountDetails() { - switch self.verificationState { - case .unverified: - authenticator.verifyAccountDetails() - case .verified: - return - } - } -#endif - var hasBirthdayReadScope: Bool { return authorizedScopes.contains(BirthdayLoader.birthdayReadScope) } @@ -102,14 +81,4 @@ extension AuthenticationViewModel { /// The user is logged out. case signedOut } - -#if os(iOS) - /// An enumeration representing verified status. - enum VerificationState { - /// The user's account is verified and is the associated value of this case. - case verified(GIDVerifiedAccountDetailResult) - /// The user's account is not verified. - case unverified - } -#endif } diff --git a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift new file mode 100644 index 00000000..13fd7025 --- /dev/null +++ b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift @@ -0,0 +1,57 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import SwiftUI +import GoogleSignIn + +#if os(iOS) + +final class VerifiedAgeViewModel: ObservableObject { + /// The user's account verification status. + /// - note: This will publish updates when its value changes. + @Published var verificationState: VerificationState + + private var loader: VerificationLoader { + return VerificationLoader(verifiedViewAgeModel: self) + } + + /// Creates an instance of this view model. + init() { + self.verificationState = .unverified + } + + /// Verifies the user. + func verifyAccountDetails() { + switch self.verificationState { + case .unverified: + loader.verifyAccountDetails() + case .verified: + return + } + } +} + +extension VerifiedAgeViewModel { + /// An enumeration representing verified status. + enum VerificationState { + /// The user's account is verified and is the associated value of this case. + case verified(GIDVerifiedAccountDetailResult) + /// The user's account is not verified. + case unverified + } +} + +#endif diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Views/VerificationView.swift b/Samples/Swift/DaysUntilBirthday/Shared/Views/VerificationView.swift index af1b8965..a7849f29 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Views/VerificationView.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Views/VerificationView.swift @@ -18,10 +18,10 @@ import SwiftUI import GoogleSignIn struct VerificationView: View { - @ObservedObject var authViewModel: AuthenticationViewModel + @ObservedObject var verifiedAgeViewModel: VerifiedAgeViewModel var body: some View { - switch authViewModel.verificationState { + switch verifiedAgeViewModel.verificationState { case .verified(let result): VStack(alignment:.leading) { Text("List of result object properties:") diff --git a/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift b/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift index 256b02ac..27749980 100644 --- a/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift +++ b/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift @@ -19,6 +19,8 @@ import GoogleSignIn struct UserProfileView: View { @EnvironmentObject var authViewModel: AuthenticationViewModel + + @StateObject var verifiedAgeViewModel = VerifiedAgeViewModel() @StateObject var birthdayViewModel = BirthdayViewModel() private var user: GIDGoogleUser? { return GIDSignIn.sharedInstance.currentUser @@ -52,9 +54,9 @@ struct UserProfileView: View { }) #if os(iOS) NavigationLink(NSLocalizedString("Verify My Age", comment: "Verify Age"), - destination: VerificationView(authViewModel: authViewModel) + destination: VerificationView(verifiedAgeViewModel: verifiedAgeViewModel) .onAppear { - authViewModel.verifyAccountDetails() + verifiedAgeViewModel.verifyAccountDetails() }) #endif Spacer() From b8696c1f96face534201899b9a9918ad394a4e40 Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 10 Jul 2024 12:36:00 -0700 Subject: [PATCH 4/9] Add back in PRODUCT_BUNDLE_IDENTIFIER. --- .../DaysUntilBirthdayForPod.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj index 1fecb2e5..47a5b203 100644 --- a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj +++ b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj @@ -598,6 +598,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = com.google.DaysUntilBirthday; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -619,6 +620,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + PRODUCT_BUNDLE_IDENTIFIER = com.google.DaysUntilBirthday; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; From b27c7033cd3443a429c4edadfd1548e2895881cd Mon Sep 17 00:00:00 2001 From: brianna Date: Wed, 10 Jul 2024 12:41:24 -0700 Subject: [PATCH 5/9] Revert spacing in AuthenticationViewModel --- .../Shared/ViewModels/AuthenticationViewModel.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift index 6217e03f..3ad14289 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/AuthenticationViewModel.swift @@ -22,7 +22,6 @@ final class AuthenticationViewModel: ObservableObject { /// The user's log in status. /// - note: This will publish updates when its value changes. @Published var state: State - private var authenticator: GoogleSignInAuthenticator { return GoogleSignInAuthenticator(authViewModel: self) } From dd53e54548f6ad46c21c16b93a8f7ce5dedd82d1 Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 11 Jul 2024 11:44:14 -0700 Subject: [PATCH 6/9] Fix swift integration test by adding Verify Flow files to DaysUntilBirthday.xcodeproj. --- .../DaysUntilBirthday.xcodeproj/project.pbxproj | 14 +++++++++++++- .../project.pbxproj | 1 - .../DaysUntilBirthday/iOS/UserProfileView.swift | 3 ++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthday.xcodeproj/project.pbxproj b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthday.xcodeproj/project.pbxproj index 4c12414e..abc5605b 100644 --- a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthday.xcodeproj/project.pbxproj +++ b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthday.xcodeproj/project.pbxproj @@ -3,10 +3,13 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ + 641495132C405D0200C9A613 /* VerifiedAgeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 641495122C405D0200C9A613 /* VerifiedAgeViewModel.swift */; }; + 641495152C405E1400C9A613 /* VerificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 641495142C405E1400C9A613 /* VerificationView.swift */; }; + 641495172C405E3600C9A613 /* VerificationLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 641495162C405E3600C9A613 /* VerificationLoader.swift */; }; 7345AD032703D9470020AFB1 /* DaysUntilBirthday.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7345AD022703D9470020AFB1 /* DaysUntilBirthday.swift */; }; 7345AD052703D9470020AFB1 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7345AD042703D9470020AFB1 /* ContentView.swift */; }; 7345AD072703D9480020AFB1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7345AD062703D9480020AFB1 /* Assets.xcassets */; }; @@ -53,6 +56,9 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 641495122C405D0200C9A613 /* VerifiedAgeViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerifiedAgeViewModel.swift; sourceTree = ""; }; + 641495142C405E1400C9A613 /* VerificationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerificationView.swift; sourceTree = ""; }; + 641495162C405E3600C9A613 /* VerificationLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerificationLoader.swift; sourceTree = ""; }; 7345ACFF2703D9470020AFB1 /* DaysUntilBirthday (iOS).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DaysUntilBirthday (iOS).app"; sourceTree = BUILT_PRODUCTS_DIR; }; 7345AD022703D9470020AFB1 /* DaysUntilBirthday.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaysUntilBirthday.swift; sourceTree = ""; }; 7345AD042703D9470020AFB1 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -204,6 +210,7 @@ 7345AD042703D9470020AFB1 /* ContentView.swift */, 739FCC45270E467600C92042 /* BirthdayView.swift */, 7345AD112703D9C30020AFB1 /* SignInView.swift */, + 641495142C405E1400C9A613 /* VerificationView.swift */, 7345AD142703D9C30020AFB1 /* UserProfileImageView.swift */, ); path = Views; @@ -221,6 +228,7 @@ isa = PBXGroup; children = ( 7345AD162703D9C30020AFB1 /* AuthenticationViewModel.swift */, + 641495122C405D0200C9A613 /* VerifiedAgeViewModel.swift */, 736F49BB270E102C00580053 /* BirthdayViewModel.swift */, ); path = ViewModels; @@ -231,6 +239,7 @@ children = ( 7345AD172703D9C30020AFB1 /* GoogleSignInAuthenticator.swift */, 736F49B9270E05E200580053 /* BirthdayLoader.swift */, + 641495162C405E3600C9A613 /* VerificationLoader.swift */, 7345AD192703D9C30020AFB1 /* UserProfileImageLoader.swift */, ); path = Services; @@ -383,9 +392,12 @@ 736F49BC270E102C00580053 /* BirthdayViewModel.swift in Sources */, 736F49BA270E05E200580053 /* BirthdayLoader.swift in Sources */, 7345AD242703D9C30020AFB1 /* UserProfileView.swift in Sources */, + 641495172C405E3600C9A613 /* VerificationLoader.swift in Sources */, 7345AD202703D9C30020AFB1 /* AuthenticationViewModel.swift in Sources */, + 641495132C405D0200C9A613 /* VerifiedAgeViewModel.swift in Sources */, 7345AD052703D9470020AFB1 /* ContentView.swift in Sources */, 7345AD032703D9470020AFB1 /* DaysUntilBirthday.swift in Sources */, + 641495152C405E1400C9A613 /* VerificationView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj index 47a5b203..341e870b 100644 --- a/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj +++ b/Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj @@ -9,7 +9,6 @@ /* Begin PBXBuildFile section */ 4C6A2BA2321434ACBD2AF201 /* Pods_DaysUntilBirthdayForPod__macOS_.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 926A15D393D684C68E09FB0F /* Pods_DaysUntilBirthdayForPod__macOS_.framework */; }; 641495072C3C90E100C9A613 /* VerificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 641495062C3C90E100C9A613 /* VerificationView.swift */; }; - 641495082C3C90E100C9A613 /* VerificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 641495062C3C90E100C9A613 /* VerificationView.swift */; }; 6414950A2C3E094B00C9A613 /* VerifiedAgeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 641495092C3E094B00C9A613 /* VerifiedAgeViewModel.swift */; }; 6414950C2C3E0C7A00C9A613 /* VerificationLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6414950B2C3E0C7A00C9A613 /* VerificationLoader.swift */; }; 7345AD032703D9470020AFB1 /* DaysUntilBirthday.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7345AD022703D9470020AFB1 /* DaysUntilBirthday.swift */; }; diff --git a/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift b/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift index 27749980..32b30893 100644 --- a/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift +++ b/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift @@ -19,8 +19,9 @@ import GoogleSignIn struct UserProfileView: View { @EnvironmentObject var authViewModel: AuthenticationViewModel - +#if os(iOS) @StateObject var verifiedAgeViewModel = VerifiedAgeViewModel() +#endif @StateObject var birthdayViewModel = BirthdayViewModel() private var user: GIDGoogleUser? { return GIDSignIn.sharedInstance.currentUser From d70d8a77acca4530f98d89b55a68a50b0d23a6da Mon Sep 17 00:00:00 2001 From: brianna Date: Thu, 11 Jul 2024 14:47:56 -0700 Subject: [PATCH 7/9] Fix doc comments and make a loader when necessary using `lazy var`. --- .../Shared/Services/VerificationLoader.swift | 7 ++++--- .../Shared/ViewModels/VerifiedAgeViewModel.swift | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift index edd9bf13..f80b1a5e 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift @@ -30,10 +30,11 @@ final class VerificationLoader: ObservableObject { } /// Verifies the user's age based upon the selected account. - /// - note: Successful calls to this will set the `verifiedAgeViewModel`'s `verificationState` property. + /// - note: Successful calls to this method will set the `verificationState` property of the + /// `verifiedAgeViewModel` instance passed to the initializer. func verifyAccountDetails() { let accountDetails: [GIDVerifiableAccountDetail] = [ - GIDVerifiableAccountDetail(accountDetailType:.ageOver18) + GIDVerifiableAccountDetail(accountDetailType: .ageOver18) ] guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else { @@ -44,7 +45,7 @@ final class VerificationLoader: ObservableObject { let verifyAccountDetail = GIDVerifyAccountDetail() verifyAccountDetail.verifyAccountDetails(accountDetails, presenting: rootViewController) { verifyResult, error in - guard let verifyResult = verifyResult else { + guard let verifyResult else { self.verifiedAgeViewModel.verificationState = .unverified print("Error! \(String(describing: error))") return diff --git a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift index 13fd7025..dacd71c8 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift @@ -19,14 +19,15 @@ import GoogleSignIn #if os(iOS) +/// A class conforming to `ObservableObject` used to represent a user's verification status. final class VerifiedAgeViewModel: ObservableObject { /// The user's account verification status. /// - note: This will publish updates when its value changes. @Published var verificationState: VerificationState - private var loader: VerificationLoader { + private lazy var loader: VerificationLoader = { return VerificationLoader(verifiedViewAgeModel: self) - } + }() /// Creates an instance of this view model. init() { From 2b8047f2d915ab5c9d382723e0f3a33034291438 Mon Sep 17 00:00:00 2001 From: brianna Date: Fri, 12 Jul 2024 17:55:59 -0700 Subject: [PATCH 8/9] Request knowledge of user's verified age on button click each time and update method names. --- .../Shared/Services/VerificationLoader.swift | 2 +- .../Shared/ViewModels/VerifiedAgeViewModel.swift | 11 +++-------- .../Swift/DaysUntilBirthday/iOS/UserProfileView.swift | 5 ++++- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift index f80b1a5e..5e11a743 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift @@ -32,7 +32,7 @@ final class VerificationLoader: ObservableObject { /// Verifies the user's age based upon the selected account. /// - note: Successful calls to this method will set the `verificationState` property of the /// `verifiedAgeViewModel` instance passed to the initializer. - func verifyAccountDetails() { + func verifyUserAge() { let accountDetails: [GIDVerifiableAccountDetail] = [ GIDVerifiableAccountDetail(accountDetailType: .ageOver18) ] diff --git a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift index dacd71c8..1696fd43 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift @@ -34,14 +34,9 @@ final class VerifiedAgeViewModel: ObservableObject { self.verificationState = .unverified } - /// Verifies the user. - func verifyAccountDetails() { - switch self.verificationState { - case .unverified: - loader.verifyAccountDetails() - case .verified: - return - } + /// Verifies the user's age over 18. + func verifyUserAge() { + loader.verifyUserAge() } } diff --git a/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift b/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift index 32b30893..0bcad5b6 100644 --- a/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift +++ b/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift @@ -57,7 +57,10 @@ struct UserProfileView: View { NavigationLink(NSLocalizedString("Verify My Age", comment: "Verify Age"), destination: VerificationView(verifiedAgeViewModel: verifiedAgeViewModel) .onAppear { - verifiedAgeViewModel.verifyAccountDetails() + verifiedAgeViewModel.verifyUserAge() + } + .onDisappear { + verifiedAgeViewModel.verificationState = .unverified }) #endif Spacer() From aef9ff79668024f8a107c8204f205bb9c4601b72 Mon Sep 17 00:00:00 2001 From: brianna Date: Tue, 16 Jul 2024 15:03:08 -0700 Subject: [PATCH 9/9] Update method names + doc comments to indicate we verify the user's age is over 18. --- .../Shared/Services/VerificationLoader.swift | 4 ++-- .../Shared/ViewModels/VerifiedAgeViewModel.swift | 6 +++--- Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift b/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift index 5e11a743..410330b8 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift @@ -29,10 +29,10 @@ final class VerificationLoader: ObservableObject { self.verifiedAgeViewModel = verifiedViewAgeModel } - /// Verifies the user's age based upon the selected account. + /// Verifies the user's age is over 18 based upon the selected account. /// - note: Successful calls to this method will set the `verificationState` property of the /// `verifiedAgeViewModel` instance passed to the initializer. - func verifyUserAge() { + func verifyUserAgeOver18() { let accountDetails: [GIDVerifiableAccountDetail] = [ GIDVerifiableAccountDetail(accountDetailType: .ageOver18) ] diff --git a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift index 1696fd43..44315446 100644 --- a/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift +++ b/Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift @@ -34,9 +34,9 @@ final class VerifiedAgeViewModel: ObservableObject { self.verificationState = .unverified } - /// Verifies the user's age over 18. - func verifyUserAge() { - loader.verifyUserAge() + /// Verifies the user's age is over 18. + func verifyUserAgeOver18() { + loader.verifyUserAgeOver18() } } diff --git a/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift b/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift index 0bcad5b6..a82534ed 100644 --- a/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift +++ b/Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift @@ -57,7 +57,7 @@ struct UserProfileView: View { NavigationLink(NSLocalizedString("Verify My Age", comment: "Verify Age"), destination: VerificationView(verifiedAgeViewModel: verifiedAgeViewModel) .onAppear { - verifiedAgeViewModel.verifyUserAge() + verifiedAgeViewModel.verifyUserAgeOver18() } .onDisappear { verifiedAgeViewModel.verificationState = .unverified