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

Subscribe to notifications on launch AB #416

Merged
merged 12 commits into from
Nov 30, 2018
46 changes: 25 additions & 21 deletions Stepic.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -4012,6 +4012,7 @@
62E9826D2C6AABDF608C2B57 /* ProfileDescriptionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98AFF3B8AC3CB8374445B /* ProfileDescriptionPresenter.swift */; };
62E982769C19C7852BCD59C4 /* TooltipStorageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98117E7E58E81E4BF6E24 /* TooltipStorageManager.swift */; };
62E9829488F863D10CF5544C /* UITableView+TableHeaderLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E98D9D45E6DA6099AF1C0B /* UITableView+TableHeaderLayout.swift */; };
62E982C316E409B90DC3AA21 /* SubscribeNotificationsOnLaunchSplitTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E988F198B6ED19738CB0B5 /* SubscribeNotificationsOnLaunchSplitTest.swift */; };
62E982CD54C2C86F14DF84EB /* ProfileHeaderInfoView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 62E98801330B94B34FA0D7B9 /* ProfileHeaderInfoView.xib */; };
62E982F7B4EDC6C94D1283FE /* ProgressesNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E982F6B023E2C827407B1B /* ProgressesNetworkService.swift */; };
62E983397736699787D8DD35 /* UIView+fromNib.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E982BB5246C2BBC5E88D06 /* UIView+fromNib.swift */; };
Expand Down Expand Up @@ -6044,6 +6045,7 @@
62E9888C0199CE31C6B4E91D /* ProfileViewController+StreakNotificationsControlView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ProfileViewController+StreakNotificationsControlView.swift"; sourceTree = "<group>"; };
62E988EACCEC4FB37B0567A7 /* VerticalCourseListFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerticalCourseListFlowLayout.swift; sourceTree = "<group>"; };
62E988EC03C89C26C42DE55E /* CourseListCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseListCollectionViewCell.swift; sourceTree = "<group>"; };
62E988F198B6ED19738CB0B5 /* SubscribeNotificationsOnLaunchSplitTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubscribeNotificationsOnLaunchSplitTest.swift; sourceTree = "<group>"; };
62E989338C0834107DD43B60 /* CourseReviewSummariesNetworkService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CourseReviewSummariesNetworkService.swift; sourceTree = "<group>"; };
62E989579A70D89D559F7520 /* CodeEditorSettingsPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodeEditorSettingsPresenter.swift; sourceTree = "<group>"; };
62E9897F76726E9D4EF78C1A /* StepsPagerRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StepsPagerRouter.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -7107,17 +7109,6 @@
name = Explore;
sourceTree = "<group>";
};
0853A3DE213D8F6100931F72 /* Split tests */ = {
isa = PBXGroup;
children = (
089877B4214061EC0065DFA2 /* Active Tests */,
0898779D214047640065DFA2 /* SplitTestGroupProtocol.swift */,
0898779F214047650065DFA2 /* SplitTestingService.swift */,
0898779E214047640065DFA2 /* SplitTestProtocol.swift */,
);
name = "Split tests";
sourceTree = "<group>";
};
085514E91CFB09170080CB88 /* WebViewHelpers */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -7514,14 +7505,6 @@
path = "Deep Links";
sourceTree = "<group>";
};
089877B4214061EC0065DFA2 /* Active Tests */ = {
isa = PBXGroup;
children = (
08421BCA21764FC400E8A81B /* ActiveSplitTestsContainer.swift */,
);
name = "Active Tests";
sourceTree = "<group>";
};
089F58871D22BD44000CD540 /* DiscussionCountView */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -7802,7 +7785,7 @@
62E986DB2768602666465180 /* AppDelegate.swift */,
08E43E95214C277600E3CB50 /* Transition Routers */,
2C89089E216F460F00083341 /* Services */,
0853A3DE213D8F6100931F72 /* Split tests */,
62E98F39D7A7B4486E71DF3E /* SplitTests */,
08484EDF211AF41A0006266F /* Stories */,
2CE664DE20F5204D0082F3FE /* Downloader */,
088E73E92060124B00D458E3 /* ApiRequestRetrier.swift */,
Expand Down Expand Up @@ -9055,6 +9038,15 @@
path = View;
sourceTree = "<group>";
};
2C37968421ABED9500BC7E62 /* ActiveTests */ = {
isa = PBXGroup;
children = (
08421BCA21764FC400E8A81B /* ActiveSplitTestsContainer.swift */,
62E988F198B6ED19738CB0B5 /* SubscribeNotificationsOnLaunchSplitTest.swift */,
);
path = ActiveTests;
sourceTree = "<group>";
};
2C3E42B92101DE34009D76DF /* KnowledgeGraph */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -10867,6 +10859,17 @@
path = Presenter;
sourceTree = "<group>";
};
62E98F39D7A7B4486E71DF3E /* SplitTests */ = {
isa = PBXGroup;
children = (
2C37968421ABED9500BC7E62 /* ActiveTests */,
0898779D214047640065DFA2 /* SplitTestGroupProtocol.swift */,
0898779F214047650065DFA2 /* SplitTestingService.swift */,
0898779E214047640065DFA2 /* SplitTestProtocol.swift */,
);
path = SplitTests;
sourceTree = "<group>";
};
62E98F6778240E9688E5282D /* StreakActivityView */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -12845,7 +12848,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "${SRCROOT}/lint.sh";
shellScript = "${SRCROOT}/lint.sh\n";
};
08983F251F3E4131008199B1 /* SwiftLint Script */ = {
isa = PBXShellScriptBuildPhase;
Expand Down Expand Up @@ -15035,6 +15038,7 @@
62E982769C19C7852BCD59C4 /* TooltipStorageManager.swift in Sources */,
62E985DD90444821A835C02F /* CourseListsCollectionSkeletonView.swift in Sources */,
62E98A53567525055BCCA089 /* AppDelegate.swift in Sources */,
62E982C316E409B90DC3AA21 /* SubscribeNotificationsOnLaunchSplitTest.swift in Sources */,
62E9874D1EAE49639F81C916 /* URL+AppendQueryParameters.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
3 changes: 3 additions & 0 deletions Stepic/Analytics/NotificationAlertsAnalytics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct NotificationAlertsAnalytics {
case streakAfterLogin
case streakAfterSubmission(shownCount: Int)
case personalDeadline
case abAppLaunch

var description: String {
switch self {
Expand All @@ -63,6 +64,8 @@ struct NotificationAlertsAnalytics {
return "streak after submission - \(shownCount)"
case .personalDeadline:
return "create personal deadline"
case .abAppLaunch:
return "ab subscribe on app launch"
}
}
}
Expand Down
25 changes: 21 additions & 4 deletions Stepic/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?

private let userNotificationsCenterDelegate = UserNotificationsCenterDelegate()
private let notificationsRegistrationService: NotificationsRegistrationServiceProtocol = NotificationsRegistrationService()
private let notificationsRegistrationService: NotificationsRegistrationServiceProtocol = NotificationsRegistrationService(
presenter: NotificationsRequestOnlySettingsAlertPresenter(),
analytics: .init(source: .abAppLaunch)
)
private let branchService = BranchService(deepLinkRoutingService: DeepLinkRoutingService())
private let splitTestingService = SplitTestingService(
analyticsService: AnalyticsUserProperties(),
storage: UserDefaults.standard
)
private var didShowOnboarding = true

deinit {
NotificationCenter.default.removeObserver(self)
Expand Down Expand Up @@ -85,6 +93,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
IQKeyboardManager.sharedManager().enableAutoToolbar = false

if !DefaultsContainer.launch.didLaunch {
self.didShowOnboarding = false
DefaultsContainer.launch.initStartVersion()
ActiveSplitTestsContainer.setActiveTestsGroups()
AnalyticsUserProperties.shared.setPushPermissionStatus(.notDetermined)
Expand All @@ -96,7 +105,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
self.checkForUpdates()
}

self.notificationsRegistrationService.renewDeviceToken()
let subscribeSplitTest = self.splitTestingService.fetchSplitTest(SubscribeNotificationsOnLaunchSplitTest.self)
let shouldParticipate = SubscribeNotificationsOnLaunchSplitTest.shouldParticipate
&& subscribeSplitTest.currentGroup.isParticipant
if shouldParticipate && self.didShowOnboarding {
self.notificationsRegistrationService.registerForRemoteNotifications()
} else {
self.notificationsRegistrationService.renewDeviceToken()
}

LocalNotificationsMigrator().migrateIfNeeded()
NotificationsService().handleLaunchOptions(launchOptions)
self.userNotificationsCenterDelegate.attachNotificationDelegate()
Expand Down Expand Up @@ -227,7 +244,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return true
}
if url.scheme == "vk\(StepicApplicationsInfo.SocialInfo.AppIds.vk)"
|| url.scheme == "fb\(StepicApplicationsInfo.SocialInfo.AppIds.facebook)" {
|| url.scheme == "fb\(StepicApplicationsInfo.SocialInfo.AppIds.facebook)" {
return true
}

Expand All @@ -249,7 +266,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
if branchService.canOpenWithBranch(url: url) {
branchService.openURL(app: app, open: url, options: options)
} else {
// Other actions
// Other actions
self.handleOpenedFromDeepLink(url)
}
}
Expand Down
28 changes: 25 additions & 3 deletions Stepic/AuthNavigationViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ final class AuthNavigationViewController: UINavigationController {
private let streaksAlertPresentationManager = StreaksAlertPresentationManager(source: .login)
private let notificationSuggestionManager = NotificationSuggestionManager()
private let userActivitiesAPI = UserActivitiesAPI()
private let splitTestingService: SplitTestingServiceProtocol = SplitTestingService(
analyticsService: AnalyticsUserProperties(),
storage: UserDefaults.standard
)

enum Controller {
case social
Expand Down Expand Up @@ -41,10 +45,28 @@ final class AuthNavigationViewController: UINavigationController {
return
}

if SubscribeNotificationsOnLaunchSplitTest.shouldParticipate {
let subscribeSplitTest = self.splitTestingService.fetchSplitTest(
SubscribeNotificationsOnLaunchSplitTest.self
)
if !subscribeSplitTest.currentGroup.isParticipant {
self.suggestStreakForUserWithId(userId)
}
} else {
self.suggestStreakForUserWithId(userId)
}
}

private func suggestStreakForUserWithId(_ userId: Int) {
ivan-magda marked this conversation as resolved.
Show resolved Hide resolved
self.userActivitiesAPI.retrieve(user: userId).done { userActivity in
if userActivity.didSolveThisWeek
&& self.notificationSuggestionManager.canShowAlert(context: .streak, after: .login) {
self.streaksAlertPresentationManager.suggestStreak(streak: userActivity.currentStreak)
let canShowAlert = self.notificationSuggestionManager.canShowAlert(
context: .streak,
after: .login
)
if canShowAlert && userActivity.didSolveThisWeek {
self.streaksAlertPresentationManager.suggestStreak(
streak: userActivity.currentStreak
)
}
}.catch { error in
print("\(#file) \(#function) \(error)")
Expand Down
6 changes: 5 additions & 1 deletion Stepic/BaseCardsStepsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ class BaseCardsStepsViewController: CardsStepsViewController {
analytics: .init(source: .courseSubscription)
),
course: course,
view: self
view: self,
splitTestingService: SplitTestingService(
analyticsService: AnalyticsUserProperties(),
storage: UserDefaults.standard
)
)
presenter?.refresh()
}
Expand Down
15 changes: 13 additions & 2 deletions Stepic/CardsStepsPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class BaseCardsStepsPresenter: CardsStepsPresenter, StepCardViewDelegate {
internal var lastViewedUpdater: LocalProgressLastViewedUpdater
internal var notificationSuggestionManager: NotificationSuggestionManager
internal var notificationsRegistrationService: NotificationsRegistrationServiceProtocol
var splitTestingService: SplitTestingServiceProtocol

// FIXME: incapsulate/remove this
var state: CardsStepsPresenterState = .loaded
Expand Down Expand Up @@ -118,7 +119,7 @@ class BaseCardsStepsPresenter: CardsStepsPresenter, StepCardViewDelegate {
return true
}

init(stepsAPI: StepsAPI, lessonsAPI: LessonsAPI, recommendationsAPI: RecommendationsAPI, unitsAPI: UnitsAPI, viewsAPI: ViewsAPI, ratingsAPI: AdaptiveRatingsAPI, ratingManager: AdaptiveRatingManager, statsManager: AdaptiveStatsManager, storageManager: AdaptiveStorageManager, lastViewedUpdater: LocalProgressLastViewedUpdater, notificationSuggestionManager: NotificationSuggestionManager, notificationsRegistrationService: NotificationsRegistrationServiceProtocol, course: Course?, view: CardsStepsView) {
init(stepsAPI: StepsAPI, lessonsAPI: LessonsAPI, recommendationsAPI: RecommendationsAPI, unitsAPI: UnitsAPI, viewsAPI: ViewsAPI, ratingsAPI: AdaptiveRatingsAPI, ratingManager: AdaptiveRatingManager, statsManager: AdaptiveStatsManager, storageManager: AdaptiveStorageManager, lastViewedUpdater: LocalProgressLastViewedUpdater, notificationSuggestionManager: NotificationSuggestionManager, notificationsRegistrationService: NotificationsRegistrationServiceProtocol, course: Course?, view: CardsStepsView, splitTestingService: SplitTestingServiceProtocol) {
self.stepsAPI = stepsAPI
self.lessonsAPI = lessonsAPI
self.recommendationsAPI = recommendationsAPI
Expand All @@ -131,6 +132,7 @@ class BaseCardsStepsPresenter: CardsStepsPresenter, StepCardViewDelegate {
self.lastViewedUpdater = lastViewedUpdater
self.notificationSuggestionManager = notificationSuggestionManager
self.notificationsRegistrationService = notificationsRegistrationService
self.splitTestingService = splitTestingService

self.course = course
self.view = view
Expand All @@ -152,7 +154,16 @@ class BaseCardsStepsPresenter: CardsStepsPresenter, StepCardViewDelegate {
}

func appearedAfterSubscription() {
self.notificationsRegistrationService.registerForRemoteNotifications()
if SubscribeNotificationsOnLaunchSplitTest.shouldParticipate {
let subscribeSplitTest = self.splitTestingService.fetchSplitTest(
SubscribeNotificationsOnLaunchSplitTest.self
)
if !subscribeSplitTest.currentGroup.isParticipant {
self.notificationsRegistrationService.registerForRemoteNotifications()
}
} else {
self.notificationsRegistrationService.registerForRemoteNotifications()
}
}

private func refreshTopCardForOnboarding(stepIndex: Int) {
Expand Down
17 changes: 15 additions & 2 deletions Stepic/NotificationsPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,17 @@ final class NotificationsPresenter {
// Store unread notifications count to pass it to analytics
private var badgeUnreadCount = 0

private let splitTestingService: SplitTestingServiceProtocol

init(
section: NotificationsSection,
notificationsAPI: NotificationsAPI,
usersAPI: UsersAPI,
notificationsStatusAPI: NotificationStatusesAPI,
notificationsRegistrationService: NotificationsRegistrationServiceProtocol,
notificationSuggestionManager: NotificationSuggestionManager,
view: NotificationsView
view: NotificationsView,
splitTestingService: SplitTestingServiceProtocol
) {
self.section = section
self.notificationsAPI = notificationsAPI
Expand All @@ -71,6 +74,7 @@ final class NotificationsPresenter {
self.notificationsRegistrationService = notificationsRegistrationService
self.notificationSuggestionManager = notificationSuggestionManager
self.view = view
self.splitTestingService = splitTestingService

self.notificationsRegistrationService.delegate = self

Expand Down Expand Up @@ -139,7 +143,16 @@ final class NotificationsPresenter {
}

func didAppear() {
self.notificationsRegistrationService.registerForRemoteNotifications()
if SubscribeNotificationsOnLaunchSplitTest.shouldParticipate {
let subscribeSplitTest = self.splitTestingService.fetchSplitTest(
SubscribeNotificationsOnLaunchSplitTest.self
)
if !subscribeSplitTest.currentGroup.isParticipant {
self.notificationsRegistrationService.registerForRemoteNotifications()
}
} else {
self.notificationsRegistrationService.registerForRemoteNotifications()
}
}

func refresh() {
Expand Down
6 changes: 5 additions & 1 deletion Stepic/NotificationsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,11 @@ class NotificationsViewController: UIViewController, NotificationsView {
analytics: .init(source: .notificationsTab)
),
notificationSuggestionManager: NotificationSuggestionManager(),
view: self
view: self,
splitTestingService: SplitTestingService(
analyticsService: AnalyticsUserProperties(),
storage: UserDefaults.standard
)
)

tableView.register(UINib(nibName: "NotificationsTableViewCell", bundle: nil), forCellReuseIdentifier: NotificationsTableViewCell.reuseId)
Expand Down
10 changes: 9 additions & 1 deletion Stepic/OnboardingViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,16 @@ class OnboardingViewController: UIViewController {
return DeviceInfo.current.orientation.interface.isLandscape
}

private let notificationsRegistrationService: NotificationsRegistrationServiceProtocol = NotificationsRegistrationService(
presenter: NotificationsRequestOnlySettingsAlertPresenter(),
analytics: .init(source: .abAppLaunch)
)

@IBAction func onCloseButtonClick(_ sender: Any) {
dismiss(animated: true) {
AnalyticsReporter.reportEvent(AnalyticsEvents.Onboarding.onboardingClosed, parameters: ["screen": self.currentPageIndex + 1])
AmplitudeAnalyticsEvents.Onboarding.closed(screen: self.currentPageIndex + 1).send()
self.notificationsRegistrationService.registerForRemoteNotifications()
}
}

Expand Down Expand Up @@ -194,7 +200,9 @@ class OnboardingViewController: UIViewController {
} else {
AnalyticsReporter.reportEvent(AnalyticsEvents.Onboarding.onboardingComplete, parameters: ["screen": currentPageIndex + 1])
AmplitudeAnalyticsEvents.Onboarding.completed.send()
dismiss(animated: true, completion: nil)
self.dismiss(animated: true, completion: {
self.notificationsRegistrationService.registerForRemoteNotifications()
})

if let authSource = authSource {
RoutingManager.auth.routeFrom(controller: authSource, success: nil, cancel: nil)
Expand Down
Loading