Skip to content

Commit

Permalink
Re-prompt for crash reporting (#3595)
Browse files Browse the repository at this point in the history
Task/Issue URL:
https://app.asana.com/0/1208592102886666/1208630312625695/f
Tech Design URL:
https://app.asana.com/0/1208592102886666/1208660326715650/f

**Description**:
- Introduce a feature flag for use with this project overall, currently
set to internal only
- Introduce a new UserDefaults value
(```crashCollectionShouldRevertOptedInStatusTrigger```) that can be used
to force the client to revert the existing
```crashCollectionOptInStatus``` to .unknown, only if the value is
currently .optedIn. This new trigger is implemented as an Int, so that
we can ensure the user’s Opt-In state will be reverted only once after
the feature is turned on. In the future if we need this functionality
again, we’d simply bump the garget value and the opt-in state would be
reset again.

See asana task for specific requirements, and the parent project for
more context if necessary.
  • Loading branch information
jdjackson authored Nov 20, 2024
1 parent 0511bf3 commit 20c6e11
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 1 deletion.
5 changes: 5 additions & 0 deletions Core/FeatureFlag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ public enum FeatureFlag: String {

/// https://app.asana.com/0/72649045549333/1208617860225199/f
case networkProtectionEnforceRoutes

/// https://app.asana.com/0/1208592102886666/1208613627589762/f
case crashReportOptInStatusResetting
}

extension FeatureFlag: FeatureFlagDescribing {
Expand Down Expand Up @@ -118,6 +121,8 @@ extension FeatureFlag: FeatureFlagDescribing {
return .remoteDevelopment(.subfeature(NetworkProtectionSubfeature.enforceRoutes))
case .adAttributionReporting:
return .remoteReleasable(.feature(.adAttributionReporting))
case .crashReportOptInStatusResetting:
return .internalOnly
}
}
}
Expand Down
1 change: 1 addition & 0 deletions DuckDuckGo/AppSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ protocol AppSettings: AnyObject, AppDebugSettings {
var autoconsentEnabled: Bool { get set }

var crashCollectionOptInStatus: CrashCollectionOptInStatus { get set }
var crashCollectionShouldRevertOptedInStatusTrigger: Int { get set }

var duckPlayerMode: DuckPlayerMode { get set }
var duckPlayerAskModeOverlayHidden: Bool { get set }
Expand Down
14 changes: 14 additions & 0 deletions DuckDuckGo/AppUserDefaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public class AppUserDefaults: AppSettings {
static let favoritesDisplayMode = "com.duckduckgo.ios.favoritesDisplayMode"

static let crashCollectionOptInStatus = "com.duckduckgo.ios.crashCollectionOptInStatus"
static let crashCollectionShouldRevertOptedInStatusTrigger = "com.duckduckgo.ios.crashCollectionShouldRevertOptedInStatusTrigger"

static let duckPlayerMode = "com.duckduckgo.ios.duckPlayerMode"
static let duckPlayerAskModeOverlayHidden = "com.duckduckgo.ios.duckPlayerAskModeOverlayHidden"
Expand Down Expand Up @@ -399,6 +400,19 @@ public class AppUserDefaults: AppSettings {
}
}

var crashCollectionShouldRevertOptedInStatusTrigger: Int {
get {
if let resetTrigger = userDefaults?.integer(forKey: Keys.crashCollectionShouldRevertOptedInStatusTrigger) {
return resetTrigger
} else {
return 0
}
}
set {
userDefaults?.setValue(newValue, forKey: Keys.crashCollectionShouldRevertOptedInStatusTrigger)
}
}

var duckPlayerMode: DuckPlayerMode {
get {
if let value = userDefaults?.string(forKey: Keys.duckPlayerMode),
Expand Down
20 changes: 19 additions & 1 deletion DuckDuckGo/CrashCollectionOnboarding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import Combine
import Foundation
import SwiftUI
import BrowserServicesKit

enum CrashCollectionOptInStatus: String {
case undetermined, optedIn, optedOut
Expand All @@ -35,16 +36,33 @@ final class CrashCollectionOnboardingViewController: UIHostingController<CrashCo
}

final class CrashCollectionOnboarding: NSObject {

private var featureFlagger: FeatureFlagger

init(appSettings: AppSettings) {
init(appSettings: AppSettings,
featureFlagger: FeatureFlagger = AppDependencyProvider.shared.featureFlagger) {
self.appSettings = appSettings
self.viewModel = CrashCollectionOnboardingViewModel(appSettings: appSettings)
self.featureFlagger = featureFlagger
super.init()
}

// If the user's crash report opt in status should be reset to unknown upon next release,
// increment this value by 1
private let crashCollectionShouldRevertOptedInStatusTriggerTargetValue: Int = 1

@MainActor
func presentOnboardingIfNeeded(for payloads: [Data], from viewController: UIViewController, sendReport: @escaping () -> Void) {
let isCurrentlyPresenting = viewController.presentedViewController != nil

if featureFlagger.isFeatureOn(.crashReportOptInStatusResetting) {
if appSettings.crashCollectionOptInStatus == .optedIn &&
appSettings.crashCollectionShouldRevertOptedInStatusTrigger < crashCollectionShouldRevertOptedInStatusTriggerTargetValue {
appSettings.crashCollectionOptInStatus = .undetermined
appSettings.crashCollectionShouldRevertOptedInStatusTrigger = crashCollectionShouldRevertOptedInStatusTriggerTargetValue
}
}

guard shouldPresentOnboarding, !isCurrentlyPresenting else {
if appSettings.crashCollectionOptInStatus == .optedIn {
sendReport()
Expand Down
2 changes: 2 additions & 0 deletions DuckDuckGoTests/AppSettingsMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ class AppSettingsMock: AppSettings {
var autoconsentEnabled = true

var crashCollectionOptInStatus: CrashCollectionOptInStatus = .undetermined

var crashCollectionShouldRevertOptedInStatusTrigger: Int = 0

var newTabPageSectionsEnabled: Bool = false

Expand Down

0 comments on commit 20c6e11

Please sign in to comment.