Просмотр исходного кода

[VwG] Add verification flow example to DaysUntilBirthday Sample App. (#452)

Brianna Morales 1 год назад
Родитель
Сommit
6ce9b8d2db

+ 13 - 1
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 = "<group>"; };
+		641495142C405E1400C9A613 /* VerificationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerificationView.swift; sourceTree = "<group>"; };
+		641495162C405E3600C9A613 /* VerificationLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerificationLoader.swift; sourceTree = "<group>"; };
 		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 = "<group>"; };
 		7345AD042703D9470020AFB1 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@@ -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;
 		};

+ 14 - 1
Samples/Swift/DaysUntilBirthday/DaysUntilBirthdayForPod.xcodeproj/project.pbxproj

@@ -3,11 +3,14 @@
 	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 */; };
+		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 */; };
@@ -45,6 +48,9 @@
 		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 = "<group>"; };
 		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 = "<group>"; };
 		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 = "<group>"; };
+		641495062C3C90E100C9A613 /* VerificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationView.swift; sourceTree = "<group>"; };
+		641495092C3E094B00C9A613 /* VerifiedAgeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifiedAgeViewModel.swift; sourceTree = "<group>"; };
+		6414950B2C3E0C7A00C9A613 /* VerificationLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerificationLoader.swift; sourceTree = "<group>"; };
 		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 = "<group>"; };
 		7345AD042703D9470020AFB1 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@@ -195,6 +201,7 @@
 			children = (
 				7345AD042703D9470020AFB1 /* ContentView.swift */,
 				739FCC45270E467600C92042 /* BirthdayView.swift */,
+				641495062C3C90E100C9A613 /* VerificationView.swift */,
 				7345AD112703D9C30020AFB1 /* SignInView.swift */,
 				7345AD142703D9C30020AFB1 /* UserProfileImageView.swift */,
 			);
@@ -214,6 +221,7 @@
 			children = (
 				7345AD162703D9C30020AFB1 /* AuthenticationViewModel.swift */,
 				736F49BB270E102C00580053 /* BirthdayViewModel.swift */,
+				641495092C3E094B00C9A613 /* VerifiedAgeViewModel.swift */,
 			);
 			path = ViewModels;
 			sourceTree = "<group>";
@@ -222,6 +230,7 @@
 			isa = PBXGroup;
 			children = (
 				7345AD172703D9C30020AFB1 /* GoogleSignInAuthenticator.swift */,
+				6414950B2C3E0C7A00C9A613 /* VerificationLoader.swift */,
 				736F49B9270E05E200580053 /* BirthdayLoader.swift */,
 				7345AD192703D9C30020AFB1 /* UserProfileImageLoader.swift */,
 			);
@@ -413,12 +422,15 @@
 			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 */,
+				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 */,
@@ -432,6 +444,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 */,

+ 58 - 0
Samples/Swift/DaysUntilBirthday/Shared/Services/VerificationLoader.swift

@@ -0,0 +1,58 @@
+/*
+ * 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 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 verifyUserAgeOver18() {
+    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 else {
+        self.verifiedAgeViewModel.verificationState = .unverified
+        print("Error! \(String(describing: error))")
+        return
+      }
+      self.verifiedAgeViewModel.verificationState = .verified(verifyResult)
+    }
+  }
+}
+
+#endif

+ 53 - 0
Samples/Swift/DaysUntilBirthday/Shared/ViewModels/VerifiedAgeViewModel.swift

@@ -0,0 +1,53 @@
+/*
+ * 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)
+
+/// 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 lazy var loader: VerificationLoader = {
+    return VerificationLoader(verifiedViewAgeModel: self)
+  }()
+
+  /// Creates an instance of this view model.
+  init() {
+    self.verificationState = .unverified
+  }
+
+  /// Verifies the user's age is over 18.
+  func verifyUserAgeOver18() {
+    loader.verifyUserAgeOver18()
+  }
+}
+
+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

+ 62 - 0
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 verifiedAgeViewModel: VerifiedAgeViewModel
+
+  var body: some View {
+    switch verifiedAgeViewModel.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)
+  }
+}

+ 13 - 0
Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift

@@ -19,6 +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
@@ -50,6 +53,16 @@ struct UserProfileView: View {
               return
             }
           })
+#if os(iOS)
+          NavigationLink(NSLocalizedString("Verify My Age", comment: "Verify Age"),
+                         destination: VerificationView(verifiedAgeViewModel: verifiedAgeViewModel)
+          .onAppear {
+            verifiedAgeViewModel.verifyUserAgeOver18()
+          }
+          .onDisappear {
+            verifiedAgeViewModel.verificationState = .unverified
+          })
+#endif
           Spacer()
         }
         .toolbar {