Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
7bff2b2
correçoes aula classes
ppedroam Feb 6, 2025
b5f68eb
[Refactor] - Improve UI component creation in RumContactUsViewController
rayanaprata Feb 4, 2025
d2cc78c
[Refactor] - Improve UI components, create new methods to setup views…
rayanaprata Feb 5, 2025
3220523
[Refactor] - Improve some action methods
rayanaprata Feb 5, 2025
9126b63
[Refactor] - Rename action button methods name
rayanaprata Feb 5, 2025
79d1e52
[Added] - Create UIButton extension to set symbol image for buttons
rayanaprata Feb 5, 2025
741e65e
applied solid and clean code for the first time in the code
alexandrecesarba Feb 4, 2025
9b1a159
applied SRP in recoverPasswordButton and validateForm functions
alexandrecesarba Feb 6, 2025
1c1c0be
changed(): refactor contact us view controller
lfoliveir4 Feb 6, 2025
83a17a6
added(): applink
lfoliveir4 Feb 6, 2025
42bbb44
chore(): remove whitespaces
lfoliveir4 Feb 6, 2025
1d6851e
added(): refactor stackviews
lfoliveir4 Feb 7, 2025
08b4c35
refactor more class
lfoliveir4 Feb 7, 2025
0dea448
fixed(): return func on open
lfoliveir4 Feb 7, 2025
b193e27
Removing white spaces
joorgeroberto Feb 4, 2025
cee5e06
Refactor ResetPassword setupView functions
joorgeroberto Feb 4, 2025
476f786
Refactor Reset Password Request Functions
joorgeroberto Feb 5, 2025
0bf8a44
Adjuste code with Code Review feedback
joorgeroberto Feb 6, 2025
2ce712a
Adjust Reset Password code with Code Review sugestions
joorgeroberto Feb 7, 2025
872a360
3 - nomenclatura
ppedroam Feb 8, 2025
1d2281a
feat tratar funções
elyndiaye Feb 5, 2025
9abd3eb
code review referente a aula 01
elyndiaye Feb 6, 2025
41bd2d4
Aplica conceitos da aula 2
elyndiaye Feb 7, 2025
408899f
fix: code review aplica throws na funcao
elyndiaye Feb 8, 2025
4e367a1
code review: srp para funcionalidades externas
elyndiaye Feb 8, 2025
6da5370
4-oop
ppedroam Feb 10, 2025
484695d
Updating main
ThaisaFujii Feb 11, 2025
b7f7fd8
Solving conflicts
ThaisaFujii Feb 13, 2025
219b317
Merge remote-tracking branch 'upstream/main'
ThaisaFujii Feb 13, 2025
e709c2d
Applying Class Lesson
ThaisaFujii Feb 18, 2025
fdad58b
Undoing changes on FozResetPasswordViewController
ThaisaFujii Feb 18, 2025
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
@@ -0,0 +1,18 @@
//
// RioAlertHelper.swift
// CleanCode
//
// Created by thaisa on 17/02/25.
//

import Foundation
import UIKit

class RioAlertHelper {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

futuramente vou sugerir para usar composição para essa funcao (aula de LI)
mas por enquanto sugiro apenas usar enum ao inves de classe
já que nao tem necessidade de instanciar esse objeto


static func showErrorAlert(on viewController: UIViewController, message: String) {
let alert = UIAlertController(title: "Ops...", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
viewController.present(alert, animated: true)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// RioCommonErrors.swift
// CleanCode
//
// Created by thaisa on 17/02/25.
//

import Foundation

enum RioCommonErrors: Error {
case noInternet
case invalidEmail

var alertDescription: String {
switch self {
case .noInternet:
return "Você não tem conexão no momento."
case .invalidEmail:
return "O e-mail informado é inválido."
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// RioResetPasswordService.swift
// CleanCode
//
// Created by thaisa on 17/02/25.
//

import Foundation
import UIKit

class RioResetPasswordService {

func resetPassword(email: String, completion: @escaping (Bool) -> Void) {
let parameters = ["email": email]

if let topController = UIApplication.shared.windows.first?.rootViewController {
BadNetworkLayer.shared.resetPassword(topController, parameters: parameters) { success in
completion(success)
}
} else {
completion(false)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// RioResetPasswordViewConfigurator.swift
// CleanCode
//
// Created by thaisa on 17/02/25.
//

import Foundation
import UIKit

class RioResetPasswordViewConfigurator {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nao interessante performar operações da viewController fora dela (com exceção do coordinator)
todas as funcoes desse objeto recebem viewController de parâmetro para performar acoes nela
eu sugiro duas opções:

  • deixar tudo na viewController mesmo
  • tirar View da ViewController e fazer ajustes de layout na View (igual mostrado ontem na aula)


func setupView(for viewController: RioResetPasswordViewController) {
setupButtons(for: viewController)
setupTextField(for: viewController)
setupEmail(for: viewController)
updateRecoverPasswordButtonState(for: viewController)
viewController.viewSuccess.isHidden = true
}

private func setupButtons(for vc: RioResetPasswordViewController) {
styleButton(vc.recoverPasswordButton, backgroundColor: .blue, titleColor: .white, borderWidth: 0)
styleButton(vc.loginButton, backgroundColor: .white, titleColor: .blue, borderWidth: 1)
styleButton(vc.helpButton, backgroundColor: .white, titleColor: .blue, borderWidth: 1)
styleButton(vc.createAccountButton, backgroundColor: .white, titleColor: .blue, borderWidth: 1)
}

private func styleButton(_ button: UIButton, backgroundColor: UIColor, titleColor: UIColor, borderWidth: CGFloat) {
button.layer.cornerRadius = button.bounds.height / 2
button.layer.borderWidth = borderWidth
button.layer.borderColor = UIColor.blue.cgColor
button.setTitleColor(titleColor, for: .normal)
button.backgroundColor = backgroundColor
}

private func setupTextField(for vc: RioResetPasswordViewController) {
vc.emailTextfield.setDefaultColor()
}

private func setupEmail(for vc: RioResetPasswordViewController) {
guard !vc.email.isEmpty else { return }
vc.emailTextfield.text = vc.email
vc.emailTextfield.isEnabled = false
}

func updateRecoverPasswordButtonState(for vc: RioResetPasswordViewController) {
let isValid = !(vc.emailTextfield.text?.isEmpty ?? true)
vc.recoverPasswordButton.backgroundColor = isValid ? .blue : .gray
vc.recoverPasswordButton.setTitleColor(.white, for: .normal)
vc.recoverPasswordButton.isEnabled = isValid
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
import UIKit

enum RioCommonErrors: Error {
case noInternet
case invalidEmail

var alertDescription: String {
switch self {
case .noInternet:
return "Você não tem conexão no momento."
case .invalidEmail:
return "O e-mail informado é inválido."
}
}
protocol RioResetPasswordViewModelDelegate: AnyObject {
func didResetPasswordSuccess(email: String)
func didFailWithError(_ error: RioCommonErrors)
}

class RioResetPasswordViewController: UIViewController {

@IBOutlet weak var emailTextfield: UITextField!
@IBOutlet weak var recoverPasswordButton: UIButton!
@IBOutlet weak var loginButton: UIButton!
Expand All @@ -27,88 +18,32 @@ class RioResetPasswordViewController: UIViewController {
@IBOutlet weak var emailLabel: UILabel!

var email = ""
var recoveryEmail = false

private var recoveryEmail = false
private let viewModel = RioResetPasswordViewModel()
private let viewConfigurator = RioResetPasswordViewConfigurator()

override func viewDidLoad() {
super.viewDidLoad()
setupView()
viewModel.delegate = self
viewConfigurator.setupView(for: self)
}

open override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}

@IBAction func closeButtonAction(_ sender: Any) {
dismiss(animated: true)
}

@IBAction func recoverPasswordButton(_ sender: Any) {
if recoveryEmail {
dismiss(animated: true)
return
}

attemptPasswordReset()
}

// MARK: - Nova função de reset de senha com tratamento de erro

private func attemptPasswordReset() {
do {
try validateForm()
try validateInternetConnection()

let emailUser = emailTextfield.text!.trimmingCharacters(in: .whitespaces)
resetPassword(email: emailUser)
} catch let error as RioCommonErrors {
showErrorAlert(message: error.alertDescription)
} catch {
showErrorAlert(message: "Ocorreu um erro inesperado. Tente novamente.")
}
}

// MARK: - Validações

private func validateInternetConnection() throws {
guard ConnectivityManager.shared.isConnected else {
throw RioCommonErrors.noInternet
} else {
guard let emailUser = emailTextfield.text?.trimmingCharacters(in: .whitespaces) else { return }
viewModel.attemptPasswordReset(email: emailUser)
}
}

// MARK: - Reset de Senha

private func resetPassword(email: String) {
let parameters = ["email": email]

BadNetworkLayer.shared.resetPassword(self, parameters: parameters) { success in
success ? self.handleSuccess(email: email) : self.showErrorAlert(message: "Algo de errado aconteceu. Tente novamente mais tarde.")
}
}

private func handleSuccess(email: String) {
recoveryEmail = true
emailTextfield.isHidden = true
textLabel.isHidden = true
viewSuccess.isHidden = false
emailLabel.text = email
updateRecoverPasswordButton()
}

private func updateRecoverPasswordButton() {
recoverPasswordButton.titleLabel?.text = "REENVIAR E-MAIL"
recoverPasswordButton.setTitle("Voltar", for: .normal)
}

private func showErrorAlert(message: String) {
let alert = UIAlertController(
title: "Ops..",
message: message,
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}


@IBAction func loginButton(_ sender: Any) {
dismiss(animated: true)
Expand All @@ -118,7 +53,7 @@ class RioResetPasswordViewController: UIViewController {
let vc = RioContactUsViewController()
vc.modalPresentationStyle = .fullScreen
vc.modalTransitionStyle = .coverVertical
self.present(vc, animated: true, completion: nil)
present(vc, animated: true)
}

@IBAction func createAccountButton(_ sender: Any) {
Expand All @@ -127,82 +62,36 @@ class RioResetPasswordViewController: UIViewController {
present(newVc, animated: true)
}

func validateForm() throws {
guard let email = emailTextfield.text, !isEmailFormatInvalid(email) else {
throw RioCommonErrors.invalidEmail
}
}

func isEmailFormatInvalid(_ email: String) -> Bool {
return email.isEmpty ||
!email.contains(".") ||
!email.contains("@") ||
email.count <= 5
}
}

// MARK: - Comportamentos de layout
extension RioResetPasswordViewController {

func setupView() {
setupButtons()
setupTextField()
setupEmail()
updateRecoverPasswordButtonState()
}

// MARK: - Configuração dos Botões

private func setupButtons() {
styleButton(recoverPasswordButton, backgroundColor: .blue, titleColor: .white, borderWidth: 0)
styleButton(loginButton, backgroundColor: .white, titleColor: .blue, borderWidth: 1)
styleButton(helpButton, backgroundColor: .white, titleColor: .blue, borderWidth: 1)
styleButton(createAccountButton, backgroundColor: .white, titleColor: .blue, borderWidth: 1)
}

private func styleButton(_ button: UIButton, backgroundColor: UIColor, titleColor: UIColor, borderWidth: CGFloat) {
button.layer.cornerRadius = button.bounds.height / 2
button.layer.borderWidth = borderWidth
button.layer.borderColor = UIColor.blue.cgColor
button.setTitleColor(titleColor, for: .normal)
button.backgroundColor = backgroundColor
}

// MARK: - Configuração do Campo de Texto

private func setupTextField() {
emailTextfield.setDefaultColor()
}

// MARK: - Configuração do E-mail

private func setupEmail() {
guard !email.isEmpty else { return }
emailTextfield.text = email
emailTextfield.isEnabled = false
}

//email
@IBAction func emailBeginEditing(_ sender: Any) {
emailTextfield.setEditingColor()
}

@IBAction func emailEditing(_ sender: Any) {
emailTextfield.setEditingColor()
updateRecoverPasswordButtonState()
viewConfigurator.updateRecoverPasswordButtonState(for: self)
}

@IBAction func emailEndEditing(_ sender: Any) {
emailTextfield.setDefaultColor()
}
}

extension RioResetPasswordViewController {
extension RioResetPasswordViewController: RioResetPasswordViewModelDelegate {

func didResetPasswordSuccess(email: String) {
recoveryEmail = true
emailTextfield.isHidden = true
textLabel.isHidden = true
viewSuccess.isHidden = false
emailLabel.text = email
updateRecoverPasswordButtonTitleForSuccess()
}

func didFailWithError(_ error: RioCommonErrors) {
RioAlertHelper.showErrorAlert(on: self, message: error.alertDescription)
}

func updateRecoverPasswordButtonState() {
let isValid = !(emailTextfield.text?.isEmpty ?? true)
recoverPasswordButton.backgroundColor = isValid ? .blue : .gray
recoverPasswordButton.setTitleColor(.white, for: .normal)
recoverPasswordButton.isEnabled = isValid
private func updateRecoverPasswordButtonTitleForSuccess() {
recoverPasswordButton.setTitle("Voltar", for: .normal)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

n tem necessidade de uma funcao com 1 linha

}
}
Loading