Skip to content

Commit

Permalink
iosapp: add more info to error states
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredh159 committed Oct 22, 2024
1 parent 7f01e74 commit 54cc1a9
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 29 deletions.
5 changes: 3 additions & 2 deletions iosapp/lib-ios/Sources/LibIOS/App+Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ public enum AuthFailureReason: Error, Equatable {
case passcodeRequired
/// The parent or guardian cancelled a request for authorization
case authorizationCanceled
/// A restriction prevents your app from using Family Controls on this device
/// likely an MDM supervised device, see https://developer.apple.com/forums/thread/746716
case restricted

public enum Unexpected: Equatable {
/// The method's arguments are invalid
case invalidArgument
/// The system failed to set up the Family Control famework
case unavailable
/// A restriction prevents your app from using Family Controls on this device
case restricted
}
}

Expand Down
5 changes: 5 additions & 0 deletions iosapp/lib-ios/Sources/LibIOS/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public struct AppReducer {
case authorizationFailed(AuthFailureReason)
case authorizationSucceeded
case authorizationFailedTryAgainTapped
case authorizationFailedReviewRequirementsTapped
case installFailed(FilterInstallError)
case installFailedTryAgainTapped
case installSucceeded
Expand Down Expand Up @@ -111,6 +112,10 @@ public struct AppReducer {
state.appState = .authorizationFailed(reason)
return .none

case .authorizationFailedReviewRequirementsTapped:
state.appState = .prereqs
return .none

case .authorizationFailedTryAgainTapped:
state.appState = .welcome
return .none
Expand Down
7 changes: 6 additions & 1 deletion iosapp/lib-ios/Sources/LibIOS/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ public struct ContentView: View {

case .authorizationFailed(let reason):
AuthFailed(reason: reason) {
self.store.send(.authorizationFailedTryAgainTapped)
switch reason {
case .invalidAccountType, .restricted:
self.store.send(.authorizationFailedReviewRequirementsTapped)
default:
self.store.send(.authorizationFailedTryAgainTapped)
}
}

case .prereqs:
Expand Down
2 changes: 1 addition & 1 deletion iosapp/lib-ios/Sources/LibIOS/SystemClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ extension SystemClient: DependencyKey {
case .authenticationMethodUnavailable:
return .failure(.passcodeRequired)
case .restricted:
return .failure(.unexpected(.restricted))
return .failure(.restricted)
case .unavailable:
return .failure(.unexpected(.unavailable))
case .invalidArgument:
Expand Down
51 changes: 37 additions & 14 deletions iosapp/lib-ios/Sources/LibIOS/Views/AuthFailed.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,44 @@ struct AuthFailed: View {
switch self.reason {
case .networkError:
Text(
"You must be connected to the internet in order to complete the parent/guardian authorization step."
"You must be connected to the internet in order to complete the authorization step."
)
case .authorizationConflict:
Text(
"Failed to authorize due to conflict. You might already have another app managing parental controls. Disable that app to continue using Gertrude."
)
case .invalidAccountType:
Text("Apple account error. Please confirm that:")
Text("Sorry, there was a problem with your **Apple Account.** Please ensure that:")
HStack {
VStack(alignment: .leading, spacing: 6) {
Text("The \(self.deviceType) user is logged into iCloud")
Text("The \(self.deviceType) user is signed in to iCloud")
Text("The \(self.deviceType) user is under 18")
Text("The \(self.deviceType) user is enrolled in an Apple Family")
Text("The \(self.deviceType) user is in an Apple Family")
}.font(.footnote)
Spacer()
}
.padding(8)
.background(.gray.opacity(0.1))
.multilineTextAlignment(.leading)
.cornerRadius(8)
case .unexpected, .other:
// TODO: log, contact support, etc.
Text("An unexpected error occurred, please try again.")
case .passcodeRequired:
Text(
"Failed to authorize. A passcode is required in order to enable parental controls."
)
Text("Failed to authorize. A passcode is required in order to enable parental controls.")
case .authorizationCanceled:
Text("Failed to authorize. The parent/guardian canceled the authorization.")
Text("Failed to authorize. The parent or guardian canceled the authorization.")
case .restricted:
VStack(spacing: 16) {
Text("A restriction is preventing Gertrude from using Family Controls.")
Text(
"Is this device is enrolled in **mobile device management (MDM)** by an organization or school? If so, try again on a device not managed by MDM."
)
.font(.footnote)
}
case .unexpected, .other:
VStack(spacing: 16) {
Text("An unexpected error occurred.")
Text("Please try again, or contact us for more help at https://gertrude.app/contact.")
.font(.footnote)
}
}
}
.multilineTextAlignment(.center)
Expand All @@ -47,7 +56,17 @@ struct AuthFailed: View {
self.onTryAgain()
} label: {
Spacer()
Text("Try again")
switch self.reason {
case .invalidAccountType, .restricted:
HStack {
Image(systemName: "arrow.left")
Text("Review requirements")
.padding(.trailing, 4)
}

default:
Text("Try again")
}
Spacer()
}
.padding(.vertical, 12)
Expand Down Expand Up @@ -89,8 +108,8 @@ struct AuthFailedPreview: View {
AuthFailedPreview(reason: .invalidAccountType)
}

#Preview("Unexpected/other") {
AuthFailedPreview(reason: .unexpected(.restricted))
#Preview("Restricted/MDM") {
AuthFailedPreview(reason: .restricted)
}

#Preview("Canceled") {
Expand All @@ -100,3 +119,7 @@ struct AuthFailedPreview: View {
#Preview("Need passcode") {
AuthFailedPreview(reason: .passcodeRequired)
}

#Preview("Unexpected") {
AuthFailedPreview(reason: .unexpected(.invalidArgument))
}
26 changes: 15 additions & 11 deletions iosapp/lib-ios/Sources/LibIOS/Views/PreReqs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,29 @@ struct PreReqs: View {

var requirements: [String] {
[
"The \(self.deviceType) user must be logged into iCloud",
"The \(self.deviceType) user must be under 18",
"The \(self.deviceType) user must be part of an Apple Family",
"The \(self.deviceType) user must be restricted from deleting apps",
"The \(self.deviceType) user must be **signed in to iCloud.**",
"The \(self.deviceType) user must be **under 18.**",
"The \(self.deviceType) user must be **part of an Apple Family.**",
"The \(self.deviceType) user must be **restricted from deleting apps.**",
"The \(self.deviceType) must **not be controlled** by a school or organization with **MDM.**",
]
}

var body: some View {
VStack(spacing: 20) {
VStack(spacing: 32) {
Text("In order to safely use Gertrude:")
.font(.system(size: 20, weight: .semibold))
.font(.system(size: 26, weight: .semibold))
.multilineTextAlignment(.center)

VStack(alignment: .leading) {
VStack(alignment: .leading, spacing: 12) {
ForEach(self.requirements, id: \.self) { requirement in
HStack {
HStack(alignment: .top) {
Image(systemName: "checkmark.circle")
.font(.system(size: 12, weight: .semibold))
.font(.system(size: 13, weight: .semibold))
.foregroundColor(.violet500)
Text(requirement)
.font(.footnote)
.padding(.top, 1)
Text(LocalizedStringKey(requirement))
.font(.system(size: 16))
}
}
}
Expand All @@ -38,6 +41,7 @@ struct PreReqs: View {
}
.padding(.top, 60)
.padding(.bottom, 36)
.padding(.horizontal, 24)
}
}

Expand Down

0 comments on commit 54cc1a9

Please sign in to comment.