Skip to content

Commit

Permalink
Prevent New Tab Page Intro Message to initialize before it's availabl…
Browse files Browse the repository at this point in the history
…e in public release
  • Loading branch information
dus7 committed Aug 2, 2024
1 parent a7314c6 commit a5a3440
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 29 deletions.
13 changes: 10 additions & 3 deletions DuckDuckGo/NewTabPageIntroMessageSetup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,21 @@ import Core
struct NewTabPageIntroMessageSetup {
let appSettings: AppSettings
let statistics: StatisticsStore
let newTabPageManager: NewTabPageManaging

init(appSettings: AppSettings = AppDependencyProvider.shared.appSettings, statistics: StatisticsStore = StatisticsUserDefaults()) {
init(appSettings: AppSettings = AppDependencyProvider.shared.appSettings,
statistics: StatisticsStore = StatisticsUserDefaults(),
newTabPageManager: NewTabPageManaging = NewTabPageManager()) {
self.appSettings = appSettings
self.statistics = statistics
self.newTabPageManager = newTabPageManager
}

func perform() {
guard appSettings.newTabPageIntroMessageEnabled == nil else { return }
func perform(ignoringPublicAvailabilityCheck ignorePublicCheck: Bool = false) {
let isPublicOrBypassed = ignorePublicCheck || newTabPageManager.isAvailableInPublicRelease
let isNotSetUp = appSettings.newTabPageIntroMessageEnabled == nil

guard isPublicOrBypassed && isNotSetUp else { return }

// For new users we **don't** want intro message
appSettings.newTabPageIntroMessageEnabled = statistics.installDate != nil
Expand Down
14 changes: 14 additions & 0 deletions DuckDuckGo/NewTabPageManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@

import Foundation
import BrowserServicesKit
import Core

protocol NewTabPageManaging: AnyObject {
var isNewTabPageSectionsEnabled: Bool { get }
var isAvailableInPublicRelease: Bool { get }
}

protocol NewTabPageDebugging: NewTabPageManaging {
Expand All @@ -47,6 +49,15 @@ final class NewTabPageManager: NewTabPageManaging, NewTabPageDebugging {
isLocalFlagEnabled && isFeatureFlagEnabled
}

var isAvailableInPublicRelease: Bool {
switch FeatureFlag.newTabPageSections.source {
case .disabled, .internalOnly, .remoteDevelopment:
return false
case .remoteReleasable:
return true
}
}

// MARK: - NewTabPageDebugging

var isLocalFlagEnabled: Bool {
Expand All @@ -55,6 +66,9 @@ final class NewTabPageManager: NewTabPageManaging, NewTabPageDebugging {
}
set {
appDefaults.newTabPageSectionsEnabled = newValue
if newValue {
NewTabPageIntroMessageSetup().perform(ignoringPublicAvailabilityCheck: true)
}
}
}

Expand Down
62 changes: 41 additions & 21 deletions DuckDuckGo/NewTabPageSectionsDebugView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ struct NewTabPageSectionsDebugView: View {

@State private var isFeatureEnabled: Bool
@State private var introMessageCount: Int

@State private var isIntroMessageInitialized: Bool

private var localFlagEnabled: Binding<Bool> {
Binding {
newTabPageDebugging.isLocalFlagEnabled
} set: {
newTabPageDebugging.isLocalFlagEnabled = $0
isFeatureEnabled = newTabPageDebugging.isNewTabPageSectionsEnabled
isIntroMessageInitialized = appSettings.newTabPageIntroMessageEnabled != nil
}
}

Expand All @@ -41,6 +43,7 @@ struct NewTabPageSectionsDebugView: View {
appSettings.newTabPageIntroMessageEnabled ?? false
} set: {
appSettings.newTabPageIntroMessageEnabled = $0
isIntroMessageInitialized = appSettings.newTabPageIntroMessageEnabled != nil
}
}

Expand All @@ -60,13 +63,25 @@ struct NewTabPageSectionsDebugView: View {

appSettings = AppDependencyProvider.shared.appSettings
introMessageCount = appSettings.newTabPageIntroMessageSeenCount
isIntroMessageInitialized = appSettings.newTabPageIntroMessageEnabled != nil
}

var body: some View {
List {
Section {
Toggle(isOn: localFlagEnabled,
label: {
Text(verbatim: "Local setting enabled")
})
} header: {
Text(verbatim: "Feature settings")
} footer: {
Text(verbatim: "Requires internal user flag set to have an effect.\n\nEnabling the local flag will cause existing-user behavior for feature Intro Message.")
}

Section {
HStack {
Text("New tab page sections enabled")
Text(verbatim: "New tab page sections enabled")
Spacer()
if isFeatureEnabled {
Image(systemName: "checkmark")
Expand All @@ -76,11 +91,11 @@ struct NewTabPageSectionsDebugView: View {
.foregroundColor(Color.red40)
}
}
}

Section {

HStack {
Text("Feature flag enabled")
VStack {
Text(verbatim: "Feature flag enabled")
}
Spacer()
if newTabPageDebugging.isFeatureFlagEnabled {
Image(systemName: "checkmark")
Expand All @@ -92,33 +107,38 @@ struct NewTabPageSectionsDebugView: View {
.foregroundColor(Color.red40)
}
}
} footer: {
Text("Requires internal user")
}

Section {
Toggle(isOn: localFlagEnabled,
label: {
Text("Local setting enabled")
})
}


Section {
HStack {
Text(verbatim: "Intro message initialized")
Spacer()
Text(verbatim: isIntroMessageInitialized.description.localizedCapitalized)
.frame(alignment: .trailing)
.foregroundStyle(.secondary)
}

Toggle(isOn: introMessageEnabled) {
Text("Intro message")
Text(verbatim: "Intro message")
}

HStack {
Text("Message seen count")
.frame(maxWidth: .infinity, alignment: .leading)
Text("\(introMessageCount)")
Text(verbatim: "Message seen count")
Spacer()
Text(verbatim: "\(introMessageCount)")
.frame(alignment: .trailing)
.foregroundStyle(.secondary)
}
Button("Reset message seen count", action: {
introMessageCountBinding.wrappedValue = 0
})

Button("Reset intro message setting", action: {
appSettings.newTabPageIntroMessageEnabled = nil
isIntroMessageInitialized = false
})
} header: {
Text("Other Settings")
Text(verbatim: "Intro message")
}
}
.applyInsetGroupedListStyle()
Expand Down
42 changes: 37 additions & 5 deletions DuckDuckGoTests/NewTabPageIntroMessageSetupTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ import XCTest

final class NewTabPageIntroMessageSetupTests: XCTestCase {

let appSettings = AppSettingsMock()
let statistics = MockStatisticsStore()
private let appSettings = AppSettingsMock()
private let statistics = MockStatisticsStore()
private let ntpManagerMock = NewTabPageManagerMock()

func testEnablesFeatureForExistingUser() {
let sut = NewTabPageIntroMessageSetup(appSettings: appSettings, statistics: statistics)
let sut = createSUT()
statistics.installDate = Date()

sut.perform()
Expand All @@ -35,7 +36,7 @@ final class NewTabPageIntroMessageSetupTests: XCTestCase {
}

func testDisablesFeatureForNewUser() {
let sut = NewTabPageIntroMessageSetup(appSettings: appSettings, statistics: statistics)
let sut = createSUT()
statistics.installDate = nil

sut.perform()
Expand All @@ -44,12 +45,43 @@ final class NewTabPageIntroMessageSetupTests: XCTestCase {
}

func testDoesNothingIfSetAlready() {
let sut = NewTabPageIntroMessageSetup(appSettings: appSettings, statistics: statistics)
let sut = createSUT()
statistics.installDate = nil
appSettings.newTabPageIntroMessageEnabled = true

sut.perform()

XCTAssertEqual(appSettings.newTabPageIntroMessageEnabled, true)
}

func testDoesNothingIfNotPubliclyReleased() {
let sut = createSUT()
statistics.installDate = nil
ntpManagerMock.isAvailableInPublicRelease = false
appSettings.newTabPageIntroMessageEnabled = nil

sut.perform()

XCTAssertNil(appSettings.newTabPageIntroMessageEnabled)
}

func testPerformsSetupWhenPublicReleaseBypassed() {
let sut = createSUT()
statistics.installDate = nil
ntpManagerMock.isAvailableInPublicRelease = false
appSettings.newTabPageIntroMessageEnabled = nil

sut.perform(ignoringPublicAvailabilityCheck: true)

XCTAssertNotNil(appSettings.newTabPageIntroMessageEnabled)
}

private func createSUT() -> NewTabPageIntroMessageSetup {
NewTabPageIntroMessageSetup(appSettings: appSettings, statistics: statistics, newTabPageManager: ntpManagerMock)
}
}

private final class NewTabPageManagerMock: NewTabPageManaging {
var isNewTabPageSectionsEnabled: Bool = true
var isAvailableInPublicRelease: Bool = true
}

0 comments on commit a5a3440

Please sign in to comment.