Skip to content
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
16 changes: 16 additions & 0 deletions Stepic.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,10 @@
2C295A6A222D8BAB008878B6 /* EnrollmentsAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8CB0E21FB48F39008CB1AC /* EnrollmentsAPI.swift */; };
2C2972052147F5FD001502BD /* CourseTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08A9F71D1FC38C9E00640F1F /* CourseTag.swift */; };
2C2C4D91246B485400CF759D /* UIModalPresentationStyle+Fallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2C4D90246B485400CF759D /* UIModalPresentationStyle+Fallback.swift */; };
2C2E44CF24FE331F006B7303 /* CourseListCardStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2E44CE24FE331F006B7303 /* CourseListCardStyle.swift */; };
2C2E44D124FE3FBF006B7303 /* SmallCourseWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2E44D024FE3FBF006B7303 /* SmallCourseWidgetView.swift */; };
2C2E44D324FE474F006B7303 /* CourseListGridSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2E44D224FE474F006B7303 /* CourseListGridSize.swift */; };
2C2E44D524FE5FEA006B7303 /* VisitedCoursesCleaner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2E44D424FE5FEA006B7303 /* VisitedCoursesCleaner.swift */; };
2C2EA36B212D5FEF002116C9 /* StepikResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2EA36A212D5FEF002116C9 /* StepikResult.swift */; };
2C2F0BE72186EEB8007DCA0A /* StreakNotificationsRequestAlertDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2F0BE62186EEB8007DCA0A /* StreakNotificationsRequestAlertDataSource.swift */; };
2C2F0BE92186EF87007DCA0A /* CommonNotificationsRequestAlertDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2F0BE82186EF87007DCA0A /* CommonNotificationsRequestAlertDataSource.swift */; };
Expand Down Expand Up @@ -1847,6 +1851,10 @@
2C284DBA247444DF00669736 /* CoursePaymentsNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoursePaymentsNetworkService.swift; sourceTree = "<group>"; };
2C284DBD2474986600669736 /* IAPProductIDs.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = IAPProductIDs.plist; sourceTree = "<group>"; };
2C2C4D90246B485400CF759D /* UIModalPresentationStyle+Fallback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIModalPresentationStyle+Fallback.swift"; sourceTree = "<group>"; };
2C2E44CE24FE331F006B7303 /* CourseListCardStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseListCardStyle.swift; sourceTree = "<group>"; };
2C2E44D024FE3FBF006B7303 /* SmallCourseWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmallCourseWidgetView.swift; sourceTree = "<group>"; };
2C2E44D224FE474F006B7303 /* CourseListGridSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseListGridSize.swift; sourceTree = "<group>"; };
2C2E44D424FE5FEA006B7303 /* VisitedCoursesCleaner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisitedCoursesCleaner.swift; sourceTree = "<group>"; };
2C2EA36A212D5FEF002116C9 /* StepikResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StepikResult.swift; sourceTree = "<group>"; };
2C2EBAB92382E3EB00AB1B83 /* Model_lesson_can_edit.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model_lesson_can_edit.xcdatamodel; sourceTree = "<group>"; };
2C2F0BE62186EEB8007DCA0A /* StreakNotificationsRequestAlertDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreakNotificationsRequestAlertDataSource.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -5714,10 +5722,12 @@
62E980A63F3F8952B27F10D8 /* Views */ = {
isa = PBXGroup;
children = (
2C2E44CE24FE331F006B7303 /* CourseListCardStyle.swift */,
62E981EC390D038A96C5E2A7 /* CourseListCollectionViewCell.swift */,
62E9899FE9E7080CA1F99A45 /* CourseListCollectionViewDataSource.swift */,
62E987BE70EFAEF1B4888948 /* CourseListCollectionViewDelegate.swift */,
62E9814234BD471886A53A3F /* CourseListColorMode.swift */,
2C2E44D224FE474F006B7303 /* CourseListGridSize.swift */,
62E989D0C0B39B62D2EF9A05 /* CourseListView.swift */,
62E980F30C9CD714BC60ED0D /* CourseListViewDelegate.swift */,
62E98B6E6A8A4A321441115A /* Layouts */,
Expand Down Expand Up @@ -6596,6 +6606,7 @@
62E98E718321FFBD61C5A671 /* CourseWidgetStatsItemView.swift */,
62E98C0BB290D5BFB0F69A2E /* CourseWidgetStatsView.swift */,
62E981558CAEBFB426F04DD2 /* CourseWidgetView.swift */,
2C2E44D024FE3FBF006B7303 /* SmallCourseWidgetView.swift */,
);
path = Widget;
sourceTree = "<group>";
Expand Down Expand Up @@ -6748,6 +6759,7 @@
62E98FBA6AB1C2BD6EA95634 /* UnitNavigationService.swift */,
62E98EBA0AF48AD90775FF7E /* UserAccountService.swift */,
2C9BBE4024903AB500FFED49 /* UserCoursesObserver.swift */,
2C2E44D424FE5FEA006B7303 /* VisitedCoursesCleaner.swift */,
2C273264248BB4CC00BD065F /* AppData */,
2C273263248BB49500BD065F /* CodeEditor */,
2C273262248BB46300BD065F /* ContentLanguage */,
Expand Down Expand Up @@ -8015,6 +8027,7 @@
2C284DB92474418600669736 /* CoursePaymentsAPI.swift in Sources */,
080C5E7B1EFC13ED0036EB3D /* CodeSample.swift in Sources */,
2CB37E6623902BB80050D85E /* StorageUsageService.swift in Sources */,
2C2E44D524FE5FEA006B7303 /* VisitedCoursesCleaner.swift in Sources */,
2C2C4D91246B485400CF759D /* UIModalPresentationStyle+Fallback.swift in Sources */,
2C3DAB91233D735E00453B1C /* StepFontSize.swift in Sources */,
08C0A4341BF1276C0010F049 /* Messages.swift in Sources */,
Expand Down Expand Up @@ -8354,6 +8367,7 @@
2CF10C8B238426B300F8CC95 /* StepSourcesNetworkService.swift in Sources */,
2C04BA47240726BA00D74D4B /* SubmissionEntity+CoreDataProperties.swift in Sources */,
2CD6E25F234E392900F49303 /* EmailAddressesNetworkService.swift in Sources */,
2C2E44D124FE3FBF006B7303 /* SmallCourseWidgetView.swift in Sources */,
62E9862FEEA0320F590E1C3D /* UniqueIdentifiable.swift in Sources */,
2CC276FE23EB98CE00E88D6E /* UIBarButtonItem+StepikBarButtonItems.swift in Sources */,
62E98D1BBD212BF163DCAF48 /* SectionsPersistenceService.swift in Sources */,
Expand Down Expand Up @@ -8586,6 +8600,7 @@
62E98F674E6B10451E7397F9 /* ContentLanguageSwitchPresenter.swift in Sources */,
62E98273401D1360B07BAD0A /* ContentLanguageSwitchProvider.swift in Sources */,
2CB718DC249240FC00AEDF84 /* HTMLToAttributedStringConverter.swift in Sources */,
2C2E44D324FE474F006B7303 /* CourseListGridSize.swift in Sources */,
62E9889E935597A0ED849B0C /* ContentLanguageSwitchViewController.swift in Sources */,
62E982DE03DC1E9967B8B43B /* ContentLanguageSwitchViewModel.swift in Sources */,
62E98561DFB8CBB54B0CA2F7 /* ContentLanguageSwitchButton.swift in Sources */,
Expand All @@ -8604,6 +8619,7 @@
62E982D4C94E14388A291624 /* CourseListsCollectionAssembly.swift in Sources */,
62E983D1190F2A5B3A400598 /* CourseListsCollectionDataFlow.swift in Sources */,
62E984F88D4253FDA7C8D7BA /* CourseListsCollectionInteractor.swift in Sources */,
2C2E44CF24FE331F006B7303 /* CourseListCardStyle.swift in Sources */,
62E984EF97B59BCBB5FE7401 /* CourseListsCollectionPresenter.swift in Sources */,
62E98434178EA051C7B20A56 /* CourseListsCollectionViewController.swift in Sources */,
62E9871AD527F876580625C3 /* CourseListsCollectionViewModel.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ extension AnalyticsEvent {

enum CourseViewSource {
case myCourses
case visitedCourses
case downloads
case fastContinue
case search(query: String)
Expand All @@ -490,6 +491,8 @@ extension AnalyticsEvent {
switch self {
case .myCourses:
return "my_courses"
case .visitedCourses:
return "visited_courses"
case .downloads:
return "downloads"
case .fastContinue:
Expand All @@ -515,7 +518,7 @@ extension AnalyticsEvent {

var params: [String: Any]? {
switch self {
case .myCourses, .downloads, .fastContinue, .notification, .unknown:
case .myCourses, .visitedCourses, .downloads, .fastContinue, .notification, .unknown:
return nil
case .search(let query):
return ["query": query]
Expand Down
3 changes: 3 additions & 0 deletions Stepic/Legacy/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
private let applicationShortcutService: ApplicationShortcutServiceProtocol = ApplicationShortcutService()
private let notificationPermissionStatusSettingsObserver = NotificationPermissionStatusSettingsObserver()
private let userCoursesObserver: UserCoursesObserverProtocol = UserCoursesObserver()
private let visitedCoursesCleaner: VisitedCoursesCleanerProtocol = VisitedCoursesCleaner()
private lazy var analytics: Analytics = { StepikAnalytics.shared }()

deinit {
Expand Down Expand Up @@ -147,12 +148,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
NotificationsBadgesManager.shared.set(number: application.applicationIconBadgeNumber)
self.notificationsService.removeRetentionNotifications()
self.userCoursesObserver.startObserving()
self.visitedCoursesCleaner.addObserves()
IAPService.shared.prefetchProducts()
}

func applicationWillResignActive(_ application: UIApplication) {
self.notificationsService.scheduleRetentionNotifications()
self.userCoursesObserver.stopObserving()
self.visitedCoursesCleaner.removeObservers()
}

func applicationWillTerminate(_ application: UIApplication) {
Expand Down
5 changes: 5 additions & 0 deletions Stepic/Sources/Modules/CourseInfo/CourseInfoAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ final class CourseInfoAssembly: Assembly {
progressesNetworkService: ProgressesNetworkService(progressesAPI: ProgressesAPI())
)

let visitedCourseListPersistenceService = CourseListServicesFactory(
type: VisitedCourseListType()
).makePersistenceService() as? VisitedCourseListPersistenceServiceProtocol

let interactor = CourseInfoInteractor(
courseID: self.courseID,
presenter: presenter,
Expand All @@ -58,6 +62,7 @@ final class CourseInfoAssembly: Assembly {
notificationSuggestionManager: NotificationSuggestionManager(),
notificationsRegistrationService: notificationsRegistrationService,
spotlightIndexingService: SpotlightIndexingService.shared,
visitedCourseListPersistenceService: visitedCourseListPersistenceService.require(),
urlFactory: StepikURLFactory(),
dataBackUpdateService: dataBackUpdateService,
iapService: IAPService.shared,
Expand Down
10 changes: 9 additions & 1 deletion Stepic/Sources/Modules/CourseInfo/CourseInfoInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ final class CourseInfoInteractor: CourseInfoInteractorProtocol {
private let notificationSuggestionManager: NotificationSuggestionManager
private let notificationsRegistrationService: NotificationsRegistrationServiceProtocol
private let spotlightIndexingService: SpotlightIndexingServiceProtocol
private let visitedCourseListPersistenceService: VisitedCourseListPersistenceServiceProtocol
private let urlFactory: StepikURLFactory
private let analytics: Analytics
private let courseViewSource: AnalyticsEvent.CourseViewSource
Expand Down Expand Up @@ -89,6 +90,7 @@ final class CourseInfoInteractor: CourseInfoInteractorProtocol {
notificationSuggestionManager: NotificationSuggestionManager,
notificationsRegistrationService: NotificationsRegistrationServiceProtocol,
spotlightIndexingService: SpotlightIndexingServiceProtocol,
visitedCourseListPersistenceService: VisitedCourseListPersistenceServiceProtocol,
urlFactory: StepikURLFactory,
dataBackUpdateService: DataBackUpdateServiceProtocol,
iapService: IAPServiceProtocol,
Expand All @@ -104,6 +106,7 @@ final class CourseInfoInteractor: CourseInfoInteractorProtocol {
self.notificationSuggestionManager = notificationSuggestionManager
self.notificationsRegistrationService = notificationsRegistrationService
self.spotlightIndexingService = spotlightIndexingService
self.visitedCourseListPersistenceService = visitedCourseListPersistenceService
self.urlFactory = urlFactory
self.dataBackUpdateService = dataBackUpdateService
self.iapService = iapService
Expand Down Expand Up @@ -284,7 +287,12 @@ final class CourseInfoInteractor: CourseInfoInteractorProtocol {
}.done { course in
self.currentCourse = course

if self.currentCourse != nil {
if let currentCourse = self.currentCourse {
DispatchQueue.main.async {
self.visitedCourseListPersistenceService.insert(course: currentCourse)
self.dataBackUpdateService.triggerVisitedCourseListUpdate()
}

seal.fulfill(.init(result: .success(self.makeCourseData())))
} else {
// Offline mode: present empty state only if get nil from network
Expand Down
18 changes: 18 additions & 0 deletions Stepic/Sources/Modules/CourseList/CourseListAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import UIKit
class CourseListAssembly: Assembly {
let type: CourseListType
let colorMode: CourseListColorMode
let cardStyle: CourseListCardStyle
let gridSize: CourseListGridSize

private let courseViewSource: AnalyticsEvent.CourseViewSource

Expand All @@ -22,11 +24,15 @@ class CourseListAssembly: Assembly {
fileprivate init(
type: CourseListType,
colorMode: CourseListColorMode,
cardStyle: CourseListCardStyle,
gridSize: CourseListGridSize,
courseViewSource: AnalyticsEvent.CourseViewSource,
output: CourseListOutputProtocol? = nil
) {
self.type = type
self.colorMode = colorMode
self.cardStyle = cardStyle
self.gridSize = gridSize
self.courseViewSource = courseViewSource
self.moduleOutput = output
}
Expand Down Expand Up @@ -94,13 +100,17 @@ final class HorizontalCourseListAssembly: CourseListAssembly {
HorizontalCourseListViewController(
interactor: interactor,
colorMode: self.colorMode,
cardStyle: self.cardStyle,
gridSize: self.gridSize,
maxNumberOfDisplayedCourses: self.maxNumberOfDisplayedCourses
)
}

init(
type: CourseListType,
colorMode: CourseListColorMode,
cardStyle: CourseListCardStyle = .default,
gridSize: CourseListGridSize = .default,
courseViewSource: AnalyticsEvent.CourseViewSource,
maxNumberOfDisplayedCourses: Int? = HorizontalCourseListAssembly.defaultMaxNumberOfDisplayedCourses,
output: CourseListOutputProtocol? = nil
Expand All @@ -109,6 +119,8 @@ final class HorizontalCourseListAssembly: CourseListAssembly {
super.init(
type: type,
colorMode: colorMode,
cardStyle: cardStyle,
gridSize: gridSize,
courseViewSource: courseViewSource,
output: output
)
Expand All @@ -124,13 +136,17 @@ final class VerticalCourseListAssembly: CourseListAssembly {
VerticalCourseListViewController(
interactor: interactor,
colorMode: self.colorMode,
cardStyle: self.cardStyle,
gridSize: self.gridSize,
presentationDescription: self.presentationDescription
)
}

init(
type: CourseListType,
colorMode: CourseListColorMode,
cardStyle: CourseListCardStyle = .default,
gridSize: CourseListGridSize = .default,
courseViewSource: AnalyticsEvent.CourseViewSource,
presentationDescription: CourseList.PresentationDescription?,
output: CourseListOutputProtocol? = nil
Expand All @@ -139,6 +155,8 @@ final class VerticalCourseListAssembly: CourseListAssembly {
super.init(
type: type,
colorMode: colorMode,
cardStyle: cardStyle,
gridSize: gridSize,
courseViewSource: courseViewSource,
output: output
)
Expand Down
21 changes: 18 additions & 3 deletions Stepic/Sources/Modules/CourseList/CourseListViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,23 @@ class CourseListViewController: UIViewController {
lazy var courseListView = self.view as? CourseListView

let colorMode: CourseListColorMode
let cardStyle: CourseListCardStyle
let gridSize: CourseListGridSize
fileprivate var canTriggerPagination = true

fileprivate init(
interactor: CourseListInteractorProtocol,
initialState: CourseList.ViewControllerState = .loading,
colorMode: CourseListColorMode = .default,
cardStyle: CourseListCardStyle = .default,
gridSize: CourseListGridSize = .default,
maxNumberOfDisplayedCourses: Int? = nil
) {
self.interactor = interactor
self.state = initialState
self.colorMode = colorMode
self.cardStyle = cardStyle
self.gridSize = gridSize

self.listDelegate = CourseListCollectionViewDelegate()
self.listDataSource = CourseListCollectionViewDataSource(
Expand Down Expand Up @@ -139,12 +145,16 @@ final class HorizontalCourseListViewController: CourseListViewController {
interactor: CourseListInteractorProtocol,
initialState: CourseList.ViewControllerState = .loading,
colorMode: CourseListColorMode = .default,
cardStyle: CourseListCardStyle = .default,
gridSize: CourseListGridSize = .default,
maxNumberOfDisplayedCourses: Int? = nil
) {
super.init(
interactor: interactor,
initialState: initialState,
colorMode: colorMode,
cardStyle: cardStyle,
gridSize: gridSize,
maxNumberOfDisplayedCourses: maxNumberOfDisplayedCourses
)
}
Expand All @@ -157,9 +167,9 @@ final class HorizontalCourseListViewController: CourseListViewController {
override func loadView() {
let view = HorizontalCourseListView(
frame: UIScreen.main.bounds,
columnsCount: HorizontalCourseListView.adaptiveColumnsCount,
rowsCount: 2,
gridSize: self.gridSize,
colorMode: self.colorMode,
cardStyle: self.cardStyle,
delegate: self.listDelegate,
dataSource: self.listDataSource,
viewDelegate: self
Expand All @@ -176,13 +186,17 @@ final class VerticalCourseListViewController: CourseListViewController {
interactor: CourseListInteractorProtocol,
initialState: CourseList.ViewControllerState = .loading,
colorMode: CourseListColorMode = .default,
cardStyle: CourseListCardStyle = .default,
gridSize: CourseListGridSize = .default,
presentationDescription: CourseList.PresentationDescription?
) {
self.presentationDescription = presentationDescription
super.init(
interactor: interactor,
initialState: initialState,
colorMode: colorMode,
cardStyle: cardStyle,
gridSize: gridSize,
maxNumberOfDisplayedCourses: nil
)
}
Expand All @@ -195,8 +209,9 @@ final class VerticalCourseListViewController: CourseListViewController {
override func loadView() {
let view = VerticalCourseListView(
frame: UIScreen.main.bounds,
columnsCount: VerticalCourseListView.adaptiveColumnsCount,
colorMode: self.colorMode,
cardStyle: self.cardStyle,
gridSize: self.gridSize,
delegate: self.listDelegate,
dataSource: self.listDataSource,
viewDelegate: self,
Expand Down
Loading