Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 9 commits into from
Jul 16, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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 = "<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>"; };
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>"; };
Expand Down Expand Up @@ -195,6 +198,7 @@
children = (
7345AD042703D9470020AFB1 /* ContentView.swift */,
739FCC45270E467600C92042 /* BirthdayView.swift */,
641495062C3C90E100C9A613 /* VerificationView.swift */,
7345AD112703D9C30020AFB1 /* SignInView.swift */,
7345AD142703D9C30020AFB1 /* UserProfileImageView.swift */,
);
Expand Down Expand Up @@ -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 */,
Expand All @@ -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 */,
Expand Down Expand Up @@ -577,14 +583,15 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iOS/Preview Content\"";
DEVELOPMENT_TEAM = JA85M8JD4Z;
brnnmrls marked this conversation as resolved.
Show resolved Hide resolved
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = iOS/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.google.DaysUntilBirthday;
PRODUCT_BUNDLE_IDENTIFIER = "testing-com.google.DaysUntilBirthday";
brnnmrls marked this conversation as resolved.
Show resolved Hide resolved
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand All @@ -599,14 +606,15 @@
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;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.google.DaysUntilBirthday;
PRODUCT_BUNDLE_IDENTIFIER = "testing-com.google.DaysUntilBirthday";
brnnmrls marked this conversation as resolved.
Show resolved Hide resolved
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
brnnmrls marked this conversation as resolved.
Show resolved Hide resolved
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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
brnnmrls marked this conversation as resolved.
Show resolved Hide resolved
#endif

private var authenticator: GoogleSignInAuthenticator {
return GoogleSignInAuthenticator(authViewModel: self)
}
Expand All @@ -43,6 +50,9 @@ final class AuthenticationViewModel: ObservableObject {
} else {
self.state = .signedOut
}
#if os(iOS)
self.verificationState = .unverified
#endif
}

/// Signs the user in.
Expand All @@ -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)
}
Expand All @@ -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
}
Original file line number Diff line number Diff line change
@@ -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
brnnmrls marked this conversation as resolved.
Show resolved Hide resolved

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()
brnnmrls marked this conversation as resolved.
Show resolved Hide resolved
dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .short
return dateFormatter.string(from: date)
}
}
7 changes: 7 additions & 0 deletions Samples/Swift/DaysUntilBirthday/iOS/UserProfileView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading