Skip to content
120 changes: 120 additions & 0 deletions Stepic.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion Stepic/Legacy/Model/RemoteConfig/RemoteConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ final class RemoteConfig {

private static let defaultShowStreaksNotificationTrigger = ShowStreaksNotificationTrigger.loginAndSubmission

private static let defaultCoursePurchaseFlowType = CoursePurchaseFlowType.web

static let shared = RemoteConfig()

var loadingDoneCallback: (() -> Void)?
Expand All @@ -29,7 +31,8 @@ final class RemoteConfig {
Key.arQuickLookAvailable.rawValue: NSNumber(value: false),
Key.searchResultsQueryParams.rawValue: NSDictionary(dictionary: ["is_popular": "true", "is_public": "true"]),
Key.isCoursePricesEnabled.rawValue: NSNumber(value: false),
Key.isCourseRevenueAvailable.rawValue: NSNumber(value: false)
Key.isCourseRevenueAvailable.rawValue: NSNumber(value: false),
Key.purchaseFlow.rawValue: NSString(string: Self.defaultCoursePurchaseFlowType.rawValue)
]

var showStreaksNotificationTrigger: ShowStreaksNotificationTrigger {
Expand Down Expand Up @@ -121,6 +124,16 @@ final class RemoteConfig {
#endif
}

var coursePurchaseFlow: CoursePurchaseFlowType {
guard let configValue = FirebaseRemoteConfig.RemoteConfig.remoteConfig().configValue(
forKey: Key.purchaseFlow.rawValue
).stringValue else {
return Self.defaultCoursePurchaseFlowType
}

return CoursePurchaseFlowType(rawValue: configValue) ?? Self.defaultCoursePurchaseFlowType
}

init() {
self.setConfigDefaults()
self.fetchRemoteConfigData()
Expand Down Expand Up @@ -199,6 +212,7 @@ final class RemoteConfig {
case searchResultsQueryParams = "search_query_params_ios"
case isCoursePricesEnabled = "is_course_prices_enabled_ios"
case isCourseRevenueAvailable = "is_course_revenue_available_ios"
case purchaseFlow = "purchase_flow_ios"

var analyticsUserPropertyKey: String { "\(RemoteConfig.analyticsUserPropertyKeyPrefix)\(self.rawValue)" }
}
Expand Down
12 changes: 12 additions & 0 deletions Stepic/Sources/Common/DataFetchPolicy.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Foundation

enum DataFetchPolicy {
/// Firstly executes the request against the cache.
/// If requested data is present in the cache, that data is returned.
/// Otherwise, executes the request against the network and returns that data after caching it.
case cacheFirst
/// Firstly executes the request against the network.
/// If server-side returns the result, that data is returned.
/// Otherwise, executes the request against the cache and returns that data.
case remoteFirst
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ class PanModalPresentableViewController: UIViewController, PanModalPresentable {
: self.longFormHeight
}

var longFormHeight: PanModalHeight {
guard let scrollView = self.panScrollable else {
return .maxHeight
}

scrollView.layoutIfNeeded()
return .contentHeight(scrollView.contentSize.height)
}

var anchorModalToLongForm: Bool { false }

var isShortFormEnabled = true
Expand Down
6 changes: 6 additions & 0 deletions Stepic/Sources/Model/CoursePurchaseFlowType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Foundation

enum CoursePurchaseFlowType: String {
case web
case iap
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import UIKit

final class CourseInfoPurchaseModalAssembly: Assembly {
var moduleInput: CourseInfoPurchaseModalInputProtocol?

private let courseID: Course.IdType

private weak var moduleOutput: CourseInfoPurchaseModalOutputProtocol?

init(courseID: Course.IdType, output: CourseInfoPurchaseModalOutputProtocol? = nil) {
self.courseID = courseID
self.moduleOutput = output
}

func makeModule() -> UIViewController {
let provider = CourseInfoPurchaseModalProvider(
courseID: self.courseID,
coursesRepository: CoursesRepository.default
)
let presenter = CourseInfoPurchaseModalPresenter()
let interactor = CourseInfoPurchaseModalInteractor(
courseID: self.courseID,
presenter: presenter,
provider: provider
)
let viewController = CourseInfoPurchaseModalViewController(interactor: interactor)

presenter.viewController = viewController
self.moduleInput = interactor
interactor.moduleOutput = self.moduleOutput

return viewController
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Foundation

enum CourseInfoPurchaseModal {
enum ModalLoad {
struct Request {}

struct Response {}

struct ViewModel {
let state: ViewControllerState
}
}

enum ViewControllerState {
case loading
case result(data: CourseInfoPurchaseModalViewModel)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Foundation
import PromiseKit

protocol CourseInfoPurchaseModalInteractorProtocol {
func doModalLoad(request: CourseInfoPurchaseModal.ModalLoad.Request)
}

final class CourseInfoPurchaseModalInteractor: CourseInfoPurchaseModalInteractorProtocol {
weak var moduleOutput: CourseInfoPurchaseModalOutputProtocol?

private let presenter: CourseInfoPurchaseModalPresenterProtocol
private let provider: CourseInfoPurchaseModalProviderProtocol

private let courseID: Course.IdType

init(
courseID: Course.IdType,
presenter: CourseInfoPurchaseModalPresenterProtocol,
provider: CourseInfoPurchaseModalProviderProtocol
) {
self.courseID = courseID
self.presenter = presenter
self.provider = provider
}

func doModalLoad(request: CourseInfoPurchaseModal.ModalLoad.Request) {}

enum Error: Swift.Error {
case something
}
}

extension CourseInfoPurchaseModalInteractor: CourseInfoPurchaseModalInputProtocol {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import UIKit

protocol CourseInfoPurchaseModalPresenterProtocol {
func presentModal(response: CourseInfoPurchaseModal.ModalLoad.Response)
}

final class CourseInfoPurchaseModalPresenter: CourseInfoPurchaseModalPresenterProtocol {
weak var viewController: CourseInfoPurchaseModalViewControllerProtocol?

func presentModal(response: CourseInfoPurchaseModal.ModalLoad.Response) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import Foundation
import PromiseKit

protocol CourseInfoPurchaseModalProviderProtocol {
func fetchCourseFromCache() -> Promise<Course?>
func fetchCourseFromRemote() -> Promise<Course?>
func fetchCourseFromCacheOrRemote() -> Promise<Course?>
}

final class CourseInfoPurchaseModalProvider: CourseInfoPurchaseModalProviderProtocol {
private let courseID: Course.IdType

private let coursesRepository: CoursesRepositoryProtocol

init(
courseID: Course.IdType,
coursesRepository: CoursesRepositoryProtocol
) {
self.courseID = courseID
self.coursesRepository = coursesRepository
}

func fetchCourseFromCache() -> Promise<Course?> {
Promise { seal in
self.coursesRepository.fetch(id: self.courseID, dataSourceType: .cache).done { course in
seal.fulfill(course)
}.catch { _ in
seal.reject(Error.persistenceFetchFailed)
}
}
}

func fetchCourseFromRemote() -> Promise<Course?> {
Promise { seal in
self.coursesRepository.fetch(id: self.courseID, dataSourceType: .remote).done { course in
seal.fulfill(course)
}.catch { _ in
seal.reject(Error.networkFetchFailed)
}
}
}

func fetchCourseFromCacheOrRemote() -> Promise<Course?> {
Promise { seal in
self.coursesRepository.fetch(id: self.courseID, fetchPolicy: .cacheFirst).done { course in
seal.fulfill(course)
}.catch { _ in
seal.reject(Error.networkFetchFailed)
}
}
}

enum Error: Swift.Error {
case persistenceFetchFailed
case networkFetchFailed
}
}
Loading