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

Feature/App update #136

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
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import Foundation
import Core

//sourcery: AutoMockable
public protocol AuthorizationRouter: BaseRouter {}
public protocol AuthorizationRouter: BaseRouter {
func showUpdateRequiredView(showAccountLink: Bool)
}

// Mark - For testing and SwiftUI preview
#if DEBUG
public class AuthorizationRouterMock: BaseRouterMock, AuthorizationRouter {

public override init() {}

public func showUpdateRequiredView(showAccountLink: Bool) {}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ struct SignInView_Previews: PreviewProvider {
static var previews: some View {
let vm = SignInViewModel(
interactor: AuthInteractor.mock,
router: AuthorizationRouterMock(),
router: AuthorizationRouterMock(),
config: ConfigMock(),
analytics: AuthorizationAnalyticsMock(),
validator: Validator()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,21 @@ public class SignInViewModel: ObservableObject {
}

let router: AuthorizationRouter

private let config: Config
private let interactor: AuthInteractorProtocol
private let analytics: AuthorizationAnalytics
private let validator: Validator

public init(
interactor: AuthInteractorProtocol,
router: AuthorizationRouter,
config: Config,
analytics: AuthorizationAnalytics,
validator: Validator
) {
self.interactor = interactor
self.router = router
self.config = config
self.analytics = analytics
self.validator = validator
}
Expand All @@ -67,8 +69,10 @@ public class SignInViewModel: ObservableObject {
router.showMainOrWhatsNewScreen()
} catch let error {
isShowProgress = false
if let validationError = error.validationError,
let value = validationError.data?["error_description"] as? String {
if error.isUpdateRequeiredError {
router.showUpdateRequiredView(showAccountLink: false)
} else if let validationError = error.validationError,
let value = validationError.data?["error_description"] as? String {
errorMessage = value
} else if case APIError.invalidGrant = error {
errorMessage = CoreLocalization.Error.invalidCredentials
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public class SignUpViewModel: ObservableObject {
isShowProgress = false
if error.isInternetError {
errorMessage = CoreLocalization.Error.slowOrNoInternetConnection
} else if error.isUpdateRequeiredError {
router.showUpdateRequiredView(showAccountLink: false)
} else {
errorMessage = CoreLocalization.Error.unknownError
}
Expand Down
18 changes: 18 additions & 0 deletions Authorization/AuthorizationTests/AuthorizationMock.generated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,12 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {



open func showUpdateRequiredView(showAccountLink: Bool) {
addInvocation(.m_showUpdateRequiredView__showAccountLink_showAccountLink(Parameter<Bool>.value(`showAccountLink`)))
let perform = methodPerformValue(.m_showUpdateRequiredView__showAccountLink_showAccountLink(Parameter<Bool>.value(`showAccountLink`))) as? (Bool) -> Void
perform?(`showAccountLink`)
}

open func backToRoot(animated: Bool) {
addInvocation(.m_backToRoot__animated_animated(Parameter<Bool>.value(`animated`)))
let perform = methodPerformValue(.m_backToRoot__animated_animated(Parameter<Bool>.value(`animated`))) as? (Bool) -> Void
Expand Down Expand Up @@ -811,6 +817,7 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {


fileprivate enum MethodType {
case m_showUpdateRequiredView__showAccountLink_showAccountLink(Parameter<Bool>)
case m_backToRoot__animated_animated(Parameter<Bool>)
case m_back__animated_animated(Parameter<Bool>)
case m_backWithFade
Expand All @@ -827,6 +834,11 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {

static func compareParameters(lhs: MethodType, rhs: MethodType, matcher: Matcher) -> Matcher.ComparisonResult {
switch (lhs, rhs) {
case (.m_showUpdateRequiredView__showAccountLink_showAccountLink(let lhsShowaccountlink), .m_showUpdateRequiredView__showAccountLink_showAccountLink(let rhsShowaccountlink)):
var results: [Matcher.ParameterComparisonResult] = []
results.append(Matcher.ParameterComparisonResult(Parameter.compare(lhs: lhsShowaccountlink, rhs: rhsShowaccountlink, with: matcher), lhsShowaccountlink, rhsShowaccountlink, "showAccountLink"))
return Matcher.ComparisonResult(results)

case (.m_backToRoot__animated_animated(let lhsAnimated), .m_backToRoot__animated_animated(let rhsAnimated)):
var results: [Matcher.ParameterComparisonResult] = []
results.append(Matcher.ParameterComparisonResult(Parameter.compare(lhs: lhsAnimated, rhs: rhsAnimated, with: matcher), lhsAnimated, rhsAnimated, "animated"))
Expand Down Expand Up @@ -896,6 +908,7 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {

func intValue() -> Int {
switch self {
case let .m_showUpdateRequiredView__showAccountLink_showAccountLink(p0): return p0.intValue
case let .m_backToRoot__animated_animated(p0): return p0.intValue
case let .m_back__animated_animated(p0): return p0.intValue
case .m_backWithFade: return 0
Expand All @@ -913,6 +926,7 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {
}
func assertionName() -> String {
switch self {
case .m_showUpdateRequiredView__showAccountLink_showAccountLink: return ".showUpdateRequiredView(showAccountLink:)"
case .m_backToRoot__animated_animated: return ".backToRoot(animated:)"
case .m_back__animated_animated: return ".back(animated:)"
case .m_backWithFade: return ".backWithFade()"
Expand Down Expand Up @@ -944,6 +958,7 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {
public struct Verify {
fileprivate var method: MethodType

public static func showUpdateRequiredView(showAccountLink: Parameter<Bool>) -> Verify { return Verify(method: .m_showUpdateRequiredView__showAccountLink_showAccountLink(`showAccountLink`))}
public static func backToRoot(animated: Parameter<Bool>) -> Verify { return Verify(method: .m_backToRoot__animated_animated(`animated`))}
public static func back(animated: Parameter<Bool>) -> Verify { return Verify(method: .m_back__animated_animated(`animated`))}
public static func backWithFade() -> Verify { return Verify(method: .m_backWithFade)}
Expand All @@ -963,6 +978,9 @@ open class AuthorizationRouterMock: AuthorizationRouter, Mock {
fileprivate var method: MethodType
var performs: Any

public static func showUpdateRequiredView(showAccountLink: Parameter<Bool>, perform: @escaping (Bool) -> Void) -> Perform {
return Perform(method: .m_showUpdateRequiredView__showAccountLink_showAccountLink(`showAccountLink`), performs: perform)
}
public static func backToRoot(animated: Parameter<Bool>, perform: @escaping (Bool) -> Void) -> Perform {
return Perform(method: .m_backToRoot__animated_animated(`animated`), performs: perform)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ final class SignInViewModelTests: XCTestCase {
let analytics = AuthorizationAnalyticsMock()
let viewModel = SignInViewModel(
interactor: interactor,
router: router,
router: router,
config: ConfigMock(),
analytics: analytics,
validator: validator
)
Expand All @@ -51,6 +52,7 @@ final class SignInViewModelTests: XCTestCase {
let viewModel = SignInViewModel(
interactor: interactor,
router: router,
config: ConfigMock(),
analytics: analytics,
validator: validator
)
Expand All @@ -71,6 +73,7 @@ final class SignInViewModelTests: XCTestCase {
let viewModel = SignInViewModel(
interactor: interactor,
router: router,
config: ConfigMock(),
analytics: analytics,
validator: validator
)
Expand All @@ -96,6 +99,7 @@ final class SignInViewModelTests: XCTestCase {
let viewModel = SignInViewModel(
interactor: interactor,
router: router,
config: ConfigMock(),
analytics: analytics,
validator: validator
)
Expand Down Expand Up @@ -123,6 +127,7 @@ final class SignInViewModelTests: XCTestCase {
let viewModel = SignInViewModel(
interactor: interactor,
router: router,
config: ConfigMock(),
analytics: analytics,
validator: validator
)
Expand All @@ -146,6 +151,7 @@ final class SignInViewModelTests: XCTestCase {
let viewModel = SignInViewModel(
interactor: interactor,
router: router,
config: ConfigMock(),
analytics: analytics,
validator: validator
)
Expand All @@ -169,6 +175,7 @@ final class SignInViewModelTests: XCTestCase {
let viewModel = SignInViewModel(
interactor: interactor,
router: router,
config: ConfigMock(),
analytics: analytics,
validator: validator
)
Expand All @@ -194,6 +201,7 @@ final class SignInViewModelTests: XCTestCase {
let viewModel = SignInViewModel(
interactor: interactor,
router: router,
config: ConfigMock(),
analytics: analytics,
validator: validator
)
Expand All @@ -211,6 +219,7 @@ final class SignInViewModelTests: XCTestCase {
let viewModel = SignInViewModel(
interactor: interactor,
router: router,
config: ConfigMock(),
analytics: analytics,
validator: validator
)
Expand Down
12 changes: 12 additions & 0 deletions Core/Core/Assets.xcassets/warning_filled.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "warning_filled.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions Core/Core/Configuration/Config.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ public class Config {

public let feedbackEmail = "[email protected]"

private let appStoreId = "0000000000"
public var appStoreLink: String {
"itms-apps://itunes.apple.com/app/id\(appStoreId)?mt=8"
}
public let whatsNewEnabled: Bool = false

public init(baseURL: String, oAuthClientId: String) {
Expand Down
12 changes: 12 additions & 0 deletions Core/Core/Domain/Model/UserProfile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,16 @@ public struct UserProfile: Hashable {
self.shortBiography = shortBiography
self.isFullProfile = isFullProfile
}

public init() {
self.avatarUrl = ""
self.name = ""
self.username = ""
self.dateJoined = Date()
self.yearOfBirth = 0
self.country = ""
self.spokenLanguage = ""
self.shortBiography = ""
self.isFullProfile = true
}
}
3 changes: 3 additions & 0 deletions Core/Core/Extensions/Notification.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ import Foundation
public extension Notification.Name {
static let onCourseEnrolled = Notification.Name("onCourseEnrolled")
static let onTokenRefreshFailed = Notification.Name("onTokenRefreshFailed")
static let onActualVersionReceived = Notification.Name("onActualVersionReceived")
static let onAppUpgradeAccountSettingsTapped = Notification.Name("onAppUpgradeAccountSettingsTapped")
static let onNewVersionAvaliable = Notification.Name("onNewVersionAvaliable")
}
16 changes: 14 additions & 2 deletions Core/Core/Network/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,25 @@ public final class API {
if !route.path.isEmpty {
url = url.appendingPathComponent(route.path)
}
return try await session.request(

let result = session.request(
url,
method: route.httpMethod,
parameters: parameters,
encoding: encoding,
headers: route.headers
).validateResponse().serializingData().value
).validateResponse().serializingData()

let latestVersion = await result.response.response?.headers["EDX-APP-LATEST-VERSION"]

if await result.response.response?.statusCode != 426 {
if let latestVersion = latestVersion {
NotificationCenter.default.post(name: .onActualVersionReceived, object: latestVersion)
}
}

return try await result.value

}

private func callCookies(
Expand Down
4 changes: 4 additions & 0 deletions Core/Core/Network/Alamofire+Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
import Alamofire

public extension Error {
var isUpdateRequeiredError: Bool {
self.asAFError?.responseCode == 426
}

var isInternetError: Bool {
guard let afError = self.asAFError,
let urlError = afError.underlyingError as? URLError else {
Expand Down
17 changes: 17 additions & 0 deletions Core/Core/Network/RequestInterceptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,23 @@ final public class RequestInterceptor: Alamofire.RequestInterceptor {
urlRequest.setValue("\(config.tokenType.rawValue) \(token)", forHTTPHeaderField: "Authorization")
}

let userAgent: String = {
if let info = Bundle.main.infoDictionary {
let executable: AnyObject = info[kCFBundleExecutableKey as String] as AnyObject? ?? "Unknown" as AnyObject
let bundle: AnyObject = info[kCFBundleIdentifierKey as String] as AnyObject? ?? "Unknown" as AnyObject
let version: AnyObject = info["CFBundleShortVersionString"] as AnyObject? ?? "Unknown" as AnyObject
let os: AnyObject = ProcessInfo.processInfo.operatingSystemVersionString as AnyObject
var mutableUserAgent = NSMutableString(string: "\(executable)/\(bundle) (\(version); OS \(os))") as CFMutableString
let transform = NSString(string: "Any-Latin; Latin-ASCII; [:^ASCII:] Remove") as CFString
if CFStringTransform(mutableUserAgent, nil, transform, false) == true {
return mutableUserAgent as String
}
}
return "Alamofire"
}()

urlRequest.setValue(userAgent, forHTTPHeaderField: "User-Agent")

completion(.success(urlRequest))
}

Expand Down
1 change: 1 addition & 0 deletions Core/Core/SwiftGen/Assets.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ public enum CoreAssets {
public static let noCourseImage = ImageAsset(name: "noCourseImage")
public static let notAvaliable = ImageAsset(name: "notAvaliable")
public static let playVideo = ImageAsset(name: "playVideo")
public static let warningFilled = ImageAsset(name: "warning_filled")
}
// swiftlint:enable identifier_name line_length nesting type_body_length type_name

Expand Down
Loading