Skip to content

Commit

Permalink
Merge pull request #20 from raccoongang/develop
Browse files Browse the repository at this point in the history
Develop to main. Release v1.1
  • Loading branch information
volodymyr-chekyrta authored Apr 19, 2023
2 parents 4294bd1 + c46237c commit bd2b7fb
Show file tree
Hide file tree
Showing 142 changed files with 5,896 additions and 1,543 deletions.
263 changes: 262 additions & 1 deletion Authorization/Authorization.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

62 changes: 1 addition & 61 deletions Authorization/Authorization/Presentation/Login/SignInView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public struct SignInView: View {

@State private var email: String = ""
@State private var password: String = ""
@State private var isRecoveryPassword = false

@ObservedObject
private var viewModel: SignInViewModel
Expand All @@ -37,58 +36,6 @@ public struct SignInView: View {

ScrollView {
VStack {
if isRecoveryPassword {
VStack(alignment: .leading) {
Text(AuthLocalization.Forgot.forgotPassword)
.font(Theme.Fonts.displaySmall)
.foregroundColor(CoreAssets.textPrimary.swiftUIColor)
.padding(.bottom, 4)
Text(AuthLocalization.Forgot.description)
.font(Theme.Fonts.titleSmall)
.foregroundColor(CoreAssets.textPrimary.swiftUIColor)
.padding(.bottom, 20)
Text(AuthLocalization.SignIn.email)
.font(Theme.Fonts.labelLarge)
.foregroundColor(CoreAssets.textPrimary.swiftUIColor)
TextField(AuthLocalization.SignIn.email, text: $email)
.keyboardType(.emailAddress)
.textContentType(.emailAddress)
.autocapitalization(.none)
.autocorrectionDisabled()
.padding(.all, 14)
.background(
Theme.Shapes.textInputShape
.fill(CoreAssets.textInputBackground.swiftUIColor)
)
.overlay(
Theme.Shapes.textInputShape
.stroke(lineWidth: 1)
.fill(CoreAssets.textInputStroke.swiftUIColor)
)
if viewModel.isShowProgress {
HStack(alignment: .center) {
ProgressBar(size: 40, lineWidth: 8)
.padding(20)
}.frame(maxWidth: .infinity)
} else {
StyledButton(AuthLocalization.Forgot.request) {
Task {
await viewModel.resetPassword(email: email,
isRecoveryPassord: $isRecoveryPassword)
}
}
.padding(.top, 30)
.frame(maxWidth: .infinity)
HStack(alignment: .center) {
Button(AuthLocalization.Forgot.back) {
isRecoveryPassword = false
}.foregroundColor(CoreAssets.accentColor.swiftUIColor)
}.frame(maxWidth: .infinity)
.padding(.top, 10)

}
}.rotation3DEffect(Angle(degrees: 180), axis: (x: CGFloat(0), y: CGFloat(100), z: CGFloat(0)))
} else {
VStack(alignment: .leading) {
Text(AuthLocalization.SignIn.logInTitle)
.font(Theme.Fonts.displaySmall)
Expand Down Expand Up @@ -142,7 +89,7 @@ public struct SignInView: View {
Spacer()

Button(AuthLocalization.SignIn.forgotPassBtn) {
isRecoveryPassword = true
viewModel.router.showForgotPasswordScreen()
}.foregroundColor(CoreAssets.accentColor.swiftUIColor)
}
.padding(.top, 10)
Expand All @@ -161,16 +108,9 @@ public struct SignInView: View {
}
}
Spacer()
}

}
.padding(.horizontal, 24)
.padding(.top, 50)
.rotation3DEffect( isRecoveryPassword ? Angle(degrees: 180):
Angle(degrees: 0), axis: (x: CGFloat(0),
y: CGFloat(100),
z: CGFloat(0)))
.animation(/*@START_MENU_TOKEN@*/.easeIn/*@END_MENU_TOKEN@*/)
}.roundedBackground(CoreAssets.background.swiftUIColor)
.scrollAvoidKeyboard(dismissKeyboardByTap: true)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,30 +69,4 @@ public class SignInViewModel: ObservableObject {
}
}
}

@MainActor
func resetPassword(email: String, isRecoveryPassord: Binding<Bool>) async {
guard validator.isValidEmail(email) else {
errorMessage = AuthLocalization.Error.invalidEmailAddress
return
}
isShowProgress = true
do {
alertMessage = try await interactor.resetPassword(email: email).responseText.hideHtmlTagsAndUrls()
isRecoveryPassord.wrappedValue.toggle()
isShowProgress = false
} catch {
isShowProgress = false
if let validationError = error.validationError,
let value = validationError.data?["value"] as? String {
errorMessage = value
} else if case APIError.invalidGrant = error {
errorMessage = CoreLocalization.Error.invalidCredentials
} else if error.isInternetError {
errorMessage = CoreLocalization.Error.slowOrNoInternetConnection
} else {
errorMessage = CoreLocalization.Error.unknownError
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
//
// ResetPasswordView.swift
// Authorization
//
// Created by  Stepanok Ivan on 27.03.2023.
//

import SwiftUI
import Core

public struct ResetPasswordView: View {

@State private var email: String = ""

@State private var isRecovered: Bool = false

@ObservedObject
private var viewModel: ResetPasswordViewModel

public init(viewModel: ResetPasswordViewModel) {
self.viewModel = viewModel
}

public var body: some View {
ZStack(alignment: .top) {
VStack {
CoreAssets.authBackground.swiftUIImage
.resizable()
.edgesIgnoringSafeArea(.top)
}.frame(maxWidth: .infinity, maxHeight: 200)

VStack(alignment: .center) {
NavigationBar(title: AuthLocalization.Forgot.title,
titleColor: .white,
leftButtonColor: .white,
leftButtonAction: {
viewModel.router.back()
})

ScrollView {
VStack {
if isRecovered {
ZStack {
VStack {
CoreAssets.checkEmail.swiftUIImage
.resizable()
.frame(width: 100, height: 100)
.padding(.bottom, 40)
.padding(.top, 100)

Text(AuthLocalization.Forgot.checkTitle)
.font(Theme.Fonts.titleLarge)
.multilineTextAlignment(.center)
.foregroundColor(CoreAssets.textPrimary.swiftUIColor)
.padding(.bottom, 4)
Text(AuthLocalization.Forgot.checkDescription + email)
.font(Theme.Fonts.bodyMedium)
.multilineTextAlignment(.center)
.foregroundColor(CoreAssets.textPrimary.swiftUIColor)
.padding(.bottom, 20)
StyledButton(AuthLocalization.SignIn.logInBtn) {
viewModel.router.backToRoot(animated: true)
}
.padding(.top, 30)
.frame(maxWidth: .infinity)
}
}

} else {
VStack(alignment: .leading) {
Text(AuthLocalization.Forgot.title)
.font(Theme.Fonts.displaySmall)
.foregroundColor(CoreAssets.textPrimary.swiftUIColor)
.padding(.bottom, 4)
Text(AuthLocalization.Forgot.description)
.font(Theme.Fonts.titleSmall)
.foregroundColor(CoreAssets.textPrimary.swiftUIColor)
.padding(.bottom, 20)
Text(AuthLocalization.SignIn.email)
.font(Theme.Fonts.labelLarge)
.foregroundColor(CoreAssets.textPrimary.swiftUIColor)
TextField(AuthLocalization.SignIn.email, text: $email)
.keyboardType(.emailAddress)
.textContentType(.emailAddress)
.autocapitalization(.none)
.autocorrectionDisabled()
.padding(.all, 14)
.background(
Theme.Shapes.textInputShape
.fill(CoreAssets.textInputBackground.swiftUIColor)
)
.overlay(
Theme.Shapes.textInputShape
.stroke(lineWidth: 1)
.fill(CoreAssets.textInputStroke.swiftUIColor)
)
if viewModel.isShowProgress {
HStack(alignment: .center) {
ProgressBar(size: 40, lineWidth: 8)
.padding(20)
}.frame(maxWidth: .infinity)
} else {
StyledButton(AuthLocalization.Forgot.request) {
Task {
await viewModel.resetPassword(email: email, isRecovered: $isRecovered)
}
}
.padding(.top, 30)
.frame(maxWidth: .infinity)
}
}
}
}
.padding(.horizontal, 24)
.padding(.top, 50)
}.roundedBackground(CoreAssets.background.swiftUIColor)
.scrollAvoidKeyboard(dismissKeyboardByTap: true)

}

// MARK: - Alert
if viewModel.showAlert {
VStack {
Text(viewModel.alertMessage ?? "")
.shadowCardStyle(bgColor: CoreAssets.accentColor.swiftUIColor,
textColor: .white)
.padding(.top, 80)
Spacer()

}
.transition(.move(edge: .top))
.onAppear {
doAfter(Theme.Timeout.snackbarMessageLongTimeout) {
viewModel.alertMessage = nil
}
}
}

// MARK: - Show error
if viewModel.showError {
VStack {
Spacer()
SnackBarView(message: viewModel.errorMessage)
}.transition(.move(edge: .bottom))
.onAppear {
doAfter(Theme.Timeout.snackbarMessageLongTimeout) {
viewModel.errorMessage = nil
}
}
}
}
.background(CoreAssets.background.swiftUIColor.ignoresSafeArea(.all))
}
}

#if DEBUG
struct ResetPasswordView_Previews: PreviewProvider {
static var previews: some View {
let vm = ResetPasswordViewModel(
interactor: AuthInteractor.mock,
router: AuthorizationRouterMock(),
validator: Validator()
)
ResetPasswordView(viewModel: vm)
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// ResetPasswordViewModel.swift
// Authorization
//
// Created by  Stepanok Ivan on 28.03.2023.
//

import SwiftUI
import Core

public class ResetPasswordViewModel: ObservableObject {

@Published private(set) var isShowProgress = false
@Published private(set) var showError: Bool = false
@Published private(set) var showAlert: Bool = false
var errorMessage: String? {
didSet {
withAnimation {
showError = errorMessage != nil
}
}
}
var alertMessage: String? {
didSet {
withAnimation {
showAlert = alertMessage != nil
}
}
}

private let interactor: AuthInteractorProtocol
let router: AuthorizationRouter
private let validator: Validator

public init(interactor: AuthInteractorProtocol, router: AuthorizationRouter, validator: Validator) {
self.interactor = interactor
self.router = router
self.validator = validator
}

@MainActor
func resetPassword(email: String, isRecovered: Binding<Bool>) async {
guard validator.isValidEmail(email) else {
errorMessage = AuthLocalization.Error.invalidEmailAddress
return
}
isShowProgress = true
do {
_ = try await interactor.resetPassword(email: email).responseText.hideHtmlTagsAndUrls()
isRecovered.wrappedValue.toggle()
isShowProgress = false
} catch {
isShowProgress = false
if let validationError = error.validationError,
let value = validationError.data?["value"] as? String {
errorMessage = value
} else if case APIError.invalidGrant = error {
errorMessage = CoreLocalization.Error.invalidCredentials
} else if error.isInternetError {
errorMessage = CoreLocalization.Error.slowOrNoInternetConnection
} else {
errorMessage = CoreLocalization.Error.unknownError
}
}
}
}

18 changes: 10 additions & 8 deletions Authorization/Authorization/SwiftGen/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ public enum AuthLocalization {
public static let invalidPasswordLenght = AuthLocalization.tr("Localizable", "ERROR.INVALID_PASSWORD_LENGHT", fallback: "Invalid password lenght")
}
public enum Forgot {
/// Back to Sign in
public static let back = AuthLocalization.tr("Localizable", "FORGOT.BACK", fallback: "Back to Sign in")
/// Please enter the email you use to sign in to EDX.
public static let description = AuthLocalization.tr("Localizable", "FORGOT.DESCRIPTION", fallback: "Please enter the email you use to sign in to EDX.")
/// Forgot your password?
public static let forgotPassword = AuthLocalization.tr("Localizable", "FORGOT.FORGOT_PASSWORD", fallback: "Forgot your password?")
/// Request password reset
public static let request = AuthLocalization.tr("Localizable", "FORGOT.REQUEST", fallback: "Request password reset")
/// We have sent a password recover instructions to your email
public static let checkDescription = AuthLocalization.tr("Localizable", "FORGOT.CHECK_Description", fallback: "We have sent a password recover instructions to your email ")
/// Check your email
public static let checkTitle = AuthLocalization.tr("Localizable", "FORGOT.CHECK_TITLE", fallback: "Check your email")
/// Please enter your log-in or recovery email address below and we will send you an email with instructions.
public static let description = AuthLocalization.tr("Localizable", "FORGOT.DESCRIPTION", fallback: "Please enter your log-in or recovery email address below and we will send you an email with instructions.")
/// Reset password
public static let request = AuthLocalization.tr("Localizable", "FORGOT.REQUEST", fallback: "Reset password")
/// Forgot password
public static let title = AuthLocalization.tr("Localizable", "FORGOT.TITLE", fallback: "Forgot password")
}
public enum SignIn {
/// Email
Expand Down
Loading

0 comments on commit bd2b7fb

Please sign in to comment.