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

couple tweaks before app store resubmit #103

Merged
merged 3 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions iosapp/lib-ios/Sources/LibFilter/Filter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,9 @@ public func decideFlow(hostname: String?, url: String?, sourceId: String?) -> Bo
return false
} else if target.contains("media.fosu2-1.fna.whatsapp.net") {
return false
} else if sourceId?.contains(".com.apple.MobileSMS") == true {
if target.contains("amp-api-edge.apps.apple.com") {
return false
} else if target.contains("is1-ssl.mzstatic.com") {
return false
}
} else if sourceId?.contains(".com.apple.MobileSMS") == true,
target.contains("is1-ssl.mzstatic.com") {
return false
}
}
return true
Expand Down
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
12 changes: 11 additions & 1 deletion iosapp/lib-ios/Sources/LibIOS/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public struct AppReducer {
@Dependency(\.storage) var storage
@ObservationIgnored
@Dependency(\.date.now) var now
@ObservationIgnored
@Dependency(\.locale) var locale

// TODO: figure out why i can't use a root store enum
public enum AppState: Equatable {
Expand All @@ -42,6 +44,7 @@ public struct AppReducer {
case authorizationFailed(AuthFailureReason)
case authorizationSucceeded
case authorizationFailedTryAgainTapped
case authorizationFailedReviewRequirementsTapped
case installFailed(FilterInstallError)
case installFailedTryAgainTapped
case installSucceeded
Expand All @@ -64,7 +67,10 @@ public struct AppReducer {
let now = self.now
self.storage.set(now, forKey: .launchDateStorageKey)
await send(.setFirstLaunch(now))
await self.api.logEvent("dcd721aa", "first launch")
await self.api.logEvent(
"dcd721aa",
"first launch, region: `\(self.locale.region?.identifier ?? "(nil)")`"
)
}
}

Expand Down Expand Up @@ -106,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
5 changes: 3 additions & 2 deletions iosapp/lib-ios/Tests/LibFilterTests/FilterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ final class FilterTests: XCTestCase {
(host: "media0.giphy.com", url: nil, src: "com.widget", allow: false),
(host: "media.fosu2-1.fna.whatsapp.net", url: nil, src: "", allow: false),
// block these only from Messages app, they allow searching/viewing app store content
(host: "amp-api-edge.apps.apple.com", url: nil, src: ".com.apple.MobileSMS", allow: false),
(host: "amp-api-edge.apps.apple.com", url: nil, src: "com.widget", allow: true),
(host: "is1-ssl.mzstatic.com", url: nil, src: ".com.apple.MobileSMS", allow: false),
(host: "is1-ssl.mzstatic.com", url: nil, src: "com.widget", allow: true),
// these totally kill iMessage App store app, which is not preferred for some parents
// (host: "amp-api-edge.apps.apple.com", url: nil, src: ".com.apple.MobileSMS", allow: false),
// (host: "amp-api-edge.apps.apple.com", url: nil, src: "com.widget", allow: true),
]

for (host, url, src, expected) in cases {
Expand Down