From 7bff2b20146648b8a7393cb524cbb947d3cf4e33 Mon Sep 17 00:00:00 2001 From: ppedroam Date: Wed, 5 Feb 2025 21:09:40 -0300 Subject: [PATCH 01/29] =?UTF-8?q?corre=C3=A7oes=20aula=20classes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CleanCodeApp/LiveCode/2-classes/Factories.swift | 2 +- CleanCodeApp/LiveCode/2-classes/GameCoordinator.swift | 2 +- CleanCodeApp/LiveCode/LiveCodeExample.swift | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CleanCodeApp/LiveCode/2-classes/Factories.swift b/CleanCodeApp/LiveCode/2-classes/Factories.swift index 933c43f..fced2ee 100644 --- a/CleanCodeApp/LiveCode/2-classes/Factories.swift +++ b/CleanCodeApp/LiveCode/2-classes/Factories.swift @@ -19,7 +19,7 @@ enum LastLaunchingsFactory { enum GameFactory { static func make() -> UIViewController { - let coordinator = GameCoordinator() + var coordinator = GameCoordinator() let viewController = GameViewController() coordinator.viewController = viewController return viewController diff --git a/CleanCodeApp/LiveCode/2-classes/GameCoordinator.swift b/CleanCodeApp/LiveCode/2-classes/GameCoordinator.swift index 22570e5..69220b1 100644 --- a/CleanCodeApp/LiveCode/2-classes/GameCoordinator.swift +++ b/CleanCodeApp/LiveCode/2-classes/GameCoordinator.swift @@ -5,7 +5,7 @@ // Created by Pedro Menezes on 05/02/25. // -import Foundation +import UIKit struct GameCoordinator { diff --git a/CleanCodeApp/LiveCode/LiveCodeExample.swift b/CleanCodeApp/LiveCode/LiveCodeExample.swift index 3ba51db..42fc7f2 100644 --- a/CleanCodeApp/LiveCode/LiveCodeExample.swift +++ b/CleanCodeApp/LiveCode/LiveCodeExample.swift @@ -69,8 +69,9 @@ class GameViewController: UIViewController { } @objc func openNextScreen() { + let analytics = LastLaunchAnallytics() let service = LastLaunchingsService() - let viewModel = LastLaunchingsViewModel(service: service) + let viewModel = LastLaunchingsViewModel(service: service, analytics: analytics) let lastLaunchingsVC = LastLaunchingsViewController(viewModel: viewModel) navigationController?.pushViewController(lastLaunchingsVC, animated: true) } From b5f68ebad5fd852ef6abd43076d82d2170590ba9 Mon Sep 17 00:00:00 2001 From: Rayana Prata <50561896+rayanaprata@users.noreply.github.com> Date: Tue, 4 Feb 2025 20:15:13 -0300 Subject: [PATCH 02/29] [Refactor] - Improve UI component creation in RumContactUsViewController --- .../RumContactUsViewController.swift | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift b/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift index 3b12b02..2a5e2f7 100644 --- a/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift @@ -11,37 +11,49 @@ class RumContactUsViewController: LoadingInheritageController { var model: ContactUsModel? let textView = UITextView() - override func viewDidLoad() { - super.viewDidLoad() - - view.backgroundColor = .systemGray6 - let titleLabel = UILabel() - titleLabel.textColor = .black - titleLabel.font = UIFont.systemFont(ofSize: 24, weight: .semibold) - titleLabel.text = "Escolha o canal para contato" - - // Criar botões + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.textColor = .black + label.font = UIFont.systemFont(ofSize: 24, weight: .semibold) + label.text = "Escolha o canal para contato" + return label + }() + + private lazy var phoneButton: UIButton = { let phoneButton = UIButton() phoneButton.backgroundColor = .systemGray4 phoneButton.layer.cornerRadius = 10 phoneButton.addTarget(self, action: #selector(phoneClick), for: .touchUpInside) + return phoneButton + }() + + private lazy var emailButton: UIButton = { let emailButton = UIButton() emailButton.backgroundColor = .systemGray4 emailButton.layer.cornerRadius = 10 emailButton.addTarget(self, action: #selector(emailClick), for: .touchUpInside) - + return emailButton + }() + + private lazy var chatButton: UIButton = { let chatButton = UIButton() chatButton.backgroundColor = .systemGray4 chatButton.layer.cornerRadius = 10 chatButton.addTarget(self, action: #selector(chatClicked), for: .touchUpInside) - + return chatButton + }() + + private lazy var messageLabel: UILabel = { let messageLabel = UILabel() messageLabel.textColor = .black messageLabel.font = UIFont.systemFont(ofSize: 16, weight: .semibold) messageLabel.text = "Ou envie uma mensagem" messageLabel.numberOfLines = 2 messageLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) - + return messageLabel + }() + + private lazy var sendMessageButton: UIButton = { let sendMessageButton = UIButton() sendMessageButton.backgroundColor = .blue sendMessageButton.setTitle(" Enviar ", for: .normal) @@ -49,8 +61,10 @@ class RumContactUsViewController: LoadingInheritageController { sendMessageButton.layer.cornerRadius = 10 sendMessageButton.setContentHuggingPriority(.required, for: .horizontal) sendMessageButton.addTarget(self, action: #selector(messageSend), for: .touchUpInside) - - textView.text = "Escreva sua mensagem aqui" + return sendMessageButton + }() + + private lazy var closeButton: UIButton = { let closeButton = UIButton() closeButton.setTitle("Voltar", for: .normal) closeButton.setTitleColor(.blue, for: .normal) @@ -59,7 +73,15 @@ class RumContactUsViewController: LoadingInheritageController { closeButton.layer.borderColor = UIColor.blue.cgColor closeButton.layer.cornerRadius = 10 closeButton.addTarget(self, action: #selector(close), for: .touchUpInside) - + return closeButton + }() + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .systemGray6 + + textView.text = "Escreva sua mensagem aqui" let symbolConfiguration = UIImage.SymbolConfiguration(pointSize: 36) phoneButton.setImage(UIImage.init(systemName: "phone")?.withConfiguration(symbolConfiguration), for: .normal) From d2cc78ccfec74bac525d969dd70aab99d432a11f Mon Sep 17 00:00:00 2001 From: Rayana Prata <50561896+rayanaprata@users.noreply.github.com> Date: Tue, 4 Feb 2025 21:00:09 -0300 Subject: [PATCH 03/29] [Refactor] - Improve UI components, create new methods to setup views and add some marks --- .../RumContactUsViewController.swift | 84 +++++++++++-------- 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift b/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift index 2a5e2f7..91397e0 100644 --- a/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift @@ -8,15 +8,24 @@ import UIKit class RumContactUsViewController: LoadingInheritageController { + // MARK: - Model var model: ContactUsModel? - let textView = UITextView() + + // MARK: - UI Components + private lazy var textView: UITextView = { + let textView = UITextView() + textView.text = "Escreva sua mensagem aqui" + textView.translatesAutoresizingMaskIntoConstraints = false + return textView + }() private lazy var titleLabel: UILabel = { - let label = UILabel() - label.textColor = .black - label.font = UIFont.systemFont(ofSize: 24, weight: .semibold) - label.text = "Escolha o canal para contato" - return label + let titleLabel = UILabel() + titleLabel.textColor = .black + titleLabel.font = UIFont.systemFont(ofSize: 24, weight: .semibold) + titleLabel.text = "Escolha o canal para contato" + titleLabel.translatesAutoresizingMaskIntoConstraints = false + return titleLabel }() private lazy var phoneButton: UIButton = { @@ -24,6 +33,7 @@ class RumContactUsViewController: LoadingInheritageController { phoneButton.backgroundColor = .systemGray4 phoneButton.layer.cornerRadius = 10 phoneButton.addTarget(self, action: #selector(phoneClick), for: .touchUpInside) + phoneButton.translatesAutoresizingMaskIntoConstraints = false return phoneButton }() @@ -32,6 +42,7 @@ class RumContactUsViewController: LoadingInheritageController { emailButton.backgroundColor = .systemGray4 emailButton.layer.cornerRadius = 10 emailButton.addTarget(self, action: #selector(emailClick), for: .touchUpInside) + emailButton.translatesAutoresizingMaskIntoConstraints = false return emailButton }() @@ -40,6 +51,7 @@ class RumContactUsViewController: LoadingInheritageController { chatButton.backgroundColor = .systemGray4 chatButton.layer.cornerRadius = 10 chatButton.addTarget(self, action: #selector(chatClicked), for: .touchUpInside) + chatButton.translatesAutoresizingMaskIntoConstraints = false return chatButton }() @@ -50,6 +62,8 @@ class RumContactUsViewController: LoadingInheritageController { messageLabel.text = "Ou envie uma mensagem" messageLabel.numberOfLines = 2 messageLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) + messageLabel.translatesAutoresizingMaskIntoConstraints = false + return messageLabel }() @@ -61,6 +75,7 @@ class RumContactUsViewController: LoadingInheritageController { sendMessageButton.layer.cornerRadius = 10 sendMessageButton.setContentHuggingPriority(.required, for: .horizontal) sendMessageButton.addTarget(self, action: #selector(messageSend), for: .touchUpInside) + sendMessageButton.translatesAutoresizingMaskIntoConstraints = false return sendMessageButton }() @@ -73,30 +88,33 @@ class RumContactUsViewController: LoadingInheritageController { closeButton.layer.borderColor = UIColor.blue.cgColor closeButton.layer.cornerRadius = 10 closeButton.addTarget(self, action: #selector(close), for: .touchUpInside) + closeButton.translatesAutoresizingMaskIntoConstraints = false return closeButton }() + // MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() - + setupView() + pegarDados() + } + + // MARK: - Setup Methods + private func setupView() { view.backgroundColor = .systemGray6 - - textView.text = "Escreva sua mensagem aqui" - + setupButtonImages() + setupHierarchy() + setupConstraints() + } + + private func setupButtonImages() { let symbolConfiguration = UIImage.SymbolConfiguration(pointSize: 36) phoneButton.setImage(UIImage.init(systemName: "phone")?.withConfiguration(symbolConfiguration), for: .normal) emailButton.setImage(UIImage.init(systemName: "envelope")?.withConfiguration(symbolConfiguration), for: .normal) chatButton.setImage(UIImage.init(systemName: "message")?.withConfiguration(symbolConfiguration), for: .normal) - - titleLabel.translatesAutoresizingMaskIntoConstraints = false - phoneButton.translatesAutoresizingMaskIntoConstraints = false - emailButton.translatesAutoresizingMaskIntoConstraints = false - chatButton.translatesAutoresizingMaskIntoConstraints = false - messageLabel.translatesAutoresizingMaskIntoConstraints = false - textView.translatesAutoresizingMaskIntoConstraints = false - sendMessageButton.translatesAutoresizingMaskIntoConstraints = false - closeButton.translatesAutoresizingMaskIntoConstraints = false - + } + + private func setupHierarchy() { view.addSubview(titleLabel) view.addSubview(phoneButton) view.addSubview(emailButton) @@ -105,9 +123,10 @@ class RumContactUsViewController: LoadingInheritageController { view.addSubview(textView) view.addSubview(sendMessageButton) view.addSubview(closeButton) - + } + + private func setupConstraints() { NSLayoutConstraint.activate([ - titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 30), titleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), titleLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), @@ -131,14 +150,13 @@ class RumContactUsViewController: LoadingInheritageController { messageLabel.topAnchor.constraint(equalTo: phoneButton.bottomAnchor, constant: 30), messageLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), messageLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), -// stackView.heightAnchor.constraint(equalToConstant: 30), + // stackView.heightAnchor.constraint(equalToConstant: 30), textView.topAnchor.constraint(equalTo: messageLabel.bottomAnchor, constant: 20), textView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), textView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), textView.bottomAnchor.constraint(equalTo: sendMessageButton.topAnchor, constant: -30), - sendMessageButton.bottomAnchor.constraint(equalTo: closeButton.topAnchor, constant: -20), sendMessageButton.heightAnchor.constraint(equalToConstant: 40), sendMessageButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), @@ -149,28 +167,24 @@ class RumContactUsViewController: LoadingInheritageController { closeButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), closeButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), ]) - - pegarDados() } - @objc - func phoneClick() { + // MARK: - Actions + @objc func phoneClick() { if let tel = model?.phone, let url = URL(string: "tel://\(tel)") { UIApplication.shared.open(url, options: [:], completionHandler: nil) } } - @objc - func emailClick() { + @objc func emailClick() { if let mail = model?.mail, let url = URL(string: "mailto:\(mail)") { UIApplication.shared.open(url, options: [:], completionHandler: nil) } } - @objc - func chatClicked() { + @objc func chatClicked() { if let phoneNumber = model?.phone, let whatsappURL = URL(string: "whatsapp://send?phone=\(phoneNumber)&text=Oi)") { if UIApplication.shared.canOpenURL(whatsappURL) { UIApplication.shared.open(whatsappURL, options: [:], completionHandler: nil) @@ -182,8 +196,7 @@ class RumContactUsViewController: LoadingInheritageController { } } - @objc - func close() { + @objc func close() { dismiss(animated: true) } @@ -212,8 +225,7 @@ class RumContactUsViewController: LoadingInheritageController { } } - @objc - func messageSend() { + @objc func messageSend() { view.endEditing(true) let email = model?.mail ?? "" if let message = textView.text, textView.text.count > 0 { From 32205238ef7f3b36f9506b38cea55791ba9df58e Mon Sep 17 00:00:00 2001 From: Rayana Prata <50561896+rayanaprata@users.noreply.github.com> Date: Tue, 4 Feb 2025 22:09:10 -0300 Subject: [PATCH 04/29] [Refactor] - Improve some action methods --- .../RumContactUsViewController.swift | 92 ++++++++++--------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift b/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift index 91397e0..ab07e08 100644 --- a/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift @@ -96,7 +96,7 @@ class RumContactUsViewController: LoadingInheritageController { override func viewDidLoad() { super.viewDidLoad() setupView() - pegarDados() + fetchData() } // MARK: - Setup Methods @@ -171,60 +171,58 @@ class RumContactUsViewController: LoadingInheritageController { // MARK: - Actions @objc func phoneClick() { - if let tel = model?.phone, - let url = URL(string: "tel://\(tel)") { - UIApplication.shared.open(url, options: [:], completionHandler: nil) - } + guard let tel = model?.phone, let url = URL(string: "tel://\(tel)") else { return } + UIApplication.shared.open(url, options: [:], completionHandler: nil) } @objc func emailClick() { - if let mail = model?.mail, - let url = URL(string: "mailto:\(mail)") { - UIApplication.shared.open(url, options: [:], completionHandler: nil) - } + guard let mail = model?.mail, let url = URL(string: "mailto:\(mail)") else { return } + UIApplication.shared.open(url, options: [:], completionHandler: nil) } @objc func chatClicked() { - if let phoneNumber = model?.phone, let whatsappURL = URL(string: "whatsapp://send?phone=\(phoneNumber)&text=Oi)") { - if UIApplication.shared.canOpenURL(whatsappURL) { - UIApplication.shared.open(whatsappURL, options: [:], completionHandler: nil) - } else { - if let appStoreURL = URL(string: "https://apps.apple.com/app/whatsapp-messenger/id310633997") { - UIApplication.shared.open(appStoreURL, options: [:], completionHandler: nil) - } - } - } + guard let phoneNumber = model?.phone, let whatsappURL = URL(string: "whatsapp://send?phone=\(phoneNumber)&text=Oi)") else { return } + UIApplication.shared.canOpenURL(whatsappURL) ? openWhatsapp(whatsappURL) : openAppStore() + } + + private func openWhatsapp(_ whatsappURL: URL) { + UIApplication.shared.open(whatsappURL, options: [:], completionHandler: nil) + } + + private func openAppStore() { + guard let appStoreURL = URL(string: "https://apps.apple.com/app/whatsapp-messenger/id310633997") else { return } + UIApplication.shared.open(appStoreURL, options: [:], completionHandler: nil) } @objc func close() { dismiss(animated: true) } - - func pegarDados() { + func fetchData() { showLoadingView() let url = Endpoints.contactUs AF.shared.request(url, method: .get, parameters: nil, headers: nil) { result in self.removeLoadingView() switch result { case .success(let data): - let decoder = JSONDecoder() - if let returned = try? decoder.decode(ContactUsModel.self, from: data) { - self.model = returned - } else { - Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) { - self.dismiss(animated: true) - } - } + self.decodeData(data) case .failure(let error): print("error api: \(error.localizedDescription)") - Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) { - self.dismiss(animated: true) - } + self.handleAlertMessage(title: "Ops..", message: "Ocorreu algum erro", shouldDismiss: true) } } } + private func decodeData(_ data: Data) { + do { + let decoder = JSONDecoder() + let returned = try decoder.decode(ContactUsModel.self, from: data) + self.model = returned + } catch { + self.handleAlertMessage(title: "Ops..", message: "Ocorreu algum erro", shouldDismiss: true) + } + } + @objc func messageSend() { view.endEditing(true) let email = model?.mail ?? "" @@ -233,19 +231,27 @@ class RumContactUsViewController: LoadingInheritageController { "email": email, "mensagem": message ] - showLoadingView() - let url = Endpoints.sendMessage - AF.shared.request(url, method: .post, parameters: parameters, headers: nil) { result in - self.removeLoadingView() - switch result { - case .success: - Globals.alertMessage(title: "Sucesso..", message: "Sua mensagem foi enviada", targetVC: self) { - self.dismiss(animated: true) - } - case .failure: - Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) - } + sendMessage(parameters: parameters) + } + } + + private func sendMessage(parameters: [String: String]) { + showLoadingView() + let url = Endpoints.sendMessage + AF.shared.request(url, method: .post, parameters: parameters, headers: nil) { result in + self.removeLoadingView() + switch result { + case .success: + self.handleAlertMessage(title: "Sucesso..", message: "Sua mensagem foi enviada", shouldDismiss: true) + case .failure: + self.handleAlertMessage(title: "Ops..", message: "Ocorreu algum erro") } } } + + private func handleAlertMessage(title: String, message: String, shouldDismiss: Bool = false) { + Globals.alertMessage(title: title, message: message, targetVC: self) { + shouldDismiss ? self.dismiss(animated: true) : nil + } + } } From 9126b6333dc0c505aadbd6be5830d48d85e35f23 Mon Sep 17 00:00:00 2001 From: Rayana Prata <50561896+rayanaprata@users.noreply.github.com> Date: Tue, 4 Feb 2025 22:11:38 -0300 Subject: [PATCH 05/29] [Refactor] - Rename action button methods name --- .../RumContactUsViewController.swift | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift b/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift index ab07e08..9a39097 100644 --- a/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift @@ -32,7 +32,7 @@ class RumContactUsViewController: LoadingInheritageController { let phoneButton = UIButton() phoneButton.backgroundColor = .systemGray4 phoneButton.layer.cornerRadius = 10 - phoneButton.addTarget(self, action: #selector(phoneClick), for: .touchUpInside) + phoneButton.addTarget(self, action: #selector(didTapPhoneButton), for: .touchUpInside) phoneButton.translatesAutoresizingMaskIntoConstraints = false return phoneButton }() @@ -41,7 +41,7 @@ class RumContactUsViewController: LoadingInheritageController { let emailButton = UIButton() emailButton.backgroundColor = .systemGray4 emailButton.layer.cornerRadius = 10 - emailButton.addTarget(self, action: #selector(emailClick), for: .touchUpInside) + emailButton.addTarget(self, action: #selector(didTapEmailButton), for: .touchUpInside) emailButton.translatesAutoresizingMaskIntoConstraints = false return emailButton }() @@ -50,7 +50,7 @@ class RumContactUsViewController: LoadingInheritageController { let chatButton = UIButton() chatButton.backgroundColor = .systemGray4 chatButton.layer.cornerRadius = 10 - chatButton.addTarget(self, action: #selector(chatClicked), for: .touchUpInside) + chatButton.addTarget(self, action: #selector(didTapChatButton), for: .touchUpInside) chatButton.translatesAutoresizingMaskIntoConstraints = false return chatButton }() @@ -74,7 +74,7 @@ class RumContactUsViewController: LoadingInheritageController { sendMessageButton.setTitleColor(.white, for: .normal) sendMessageButton.layer.cornerRadius = 10 sendMessageButton.setContentHuggingPriority(.required, for: .horizontal) - sendMessageButton.addTarget(self, action: #selector(messageSend), for: .touchUpInside) + sendMessageButton.addTarget(self, action: #selector(didTapSendMessageButton), for: .touchUpInside) sendMessageButton.translatesAutoresizingMaskIntoConstraints = false return sendMessageButton }() @@ -87,7 +87,7 @@ class RumContactUsViewController: LoadingInheritageController { closeButton.layer.borderWidth = 1 closeButton.layer.borderColor = UIColor.blue.cgColor closeButton.layer.cornerRadius = 10 - closeButton.addTarget(self, action: #selector(close), for: .touchUpInside) + closeButton.addTarget(self, action: #selector(didTapCloseButton), for: .touchUpInside) closeButton.translatesAutoresizingMaskIntoConstraints = false return closeButton }() @@ -170,17 +170,17 @@ class RumContactUsViewController: LoadingInheritageController { } // MARK: - Actions - @objc func phoneClick() { + @objc func didTapPhoneButton() { guard let tel = model?.phone, let url = URL(string: "tel://\(tel)") else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) } - @objc func emailClick() { + @objc func didTapEmailButton() { guard let mail = model?.mail, let url = URL(string: "mailto:\(mail)") else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) } - @objc func chatClicked() { + @objc func didTapChatButton() { guard let phoneNumber = model?.phone, let whatsappURL = URL(string: "whatsapp://send?phone=\(phoneNumber)&text=Oi)") else { return } UIApplication.shared.canOpenURL(whatsappURL) ? openWhatsapp(whatsappURL) : openAppStore() } @@ -194,7 +194,7 @@ class RumContactUsViewController: LoadingInheritageController { UIApplication.shared.open(appStoreURL, options: [:], completionHandler: nil) } - @objc func close() { + @objc func didTapCloseButton() { dismiss(animated: true) } @@ -223,7 +223,7 @@ class RumContactUsViewController: LoadingInheritageController { } } - @objc func messageSend() { + @objc func didTapSendMessageButton() { view.endEditing(true) let email = model?.mail ?? "" if let message = textView.text, textView.text.count > 0 { From 79d1e52aad30fe113dd1ce474b2b0859e2df5e2d Mon Sep 17 00:00:00 2001 From: Rayana Prata <50561896+rayanaprata@users.noreply.github.com> Date: Wed, 5 Feb 2025 20:06:27 -0300 Subject: [PATCH 06/29] [Added] - Create UIButton extension to set symbol image for buttons --- .../ContactsUs/RumContactUsViewController.swift | 7 +++---- .../Rum/Extensions/RumUIButton+Extensions.swift | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 CleanCodeApp/Modules/Features/Rum/Extensions/RumUIButton+Extensions.swift diff --git a/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift b/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift index 9a39097..8d43779 100644 --- a/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Rum/ContactsUs/RumContactUsViewController.swift @@ -108,10 +108,9 @@ class RumContactUsViewController: LoadingInheritageController { } private func setupButtonImages() { - let symbolConfiguration = UIImage.SymbolConfiguration(pointSize: 36) - phoneButton.setImage(UIImage.init(systemName: "phone")?.withConfiguration(symbolConfiguration), for: .normal) - emailButton.setImage(UIImage.init(systemName: "envelope")?.withConfiguration(symbolConfiguration), for: .normal) - chatButton.setImage(UIImage.init(systemName: "message")?.withConfiguration(symbolConfiguration), for: .normal) + phoneButton.setSymbolImage(systemName: "phone", pointSize: 36) + emailButton.setSymbolImage(systemName: "envelope", pointSize: 36) + chatButton.setSymbolImage(systemName: "message", pointSize: 36) } private func setupHierarchy() { diff --git a/CleanCodeApp/Modules/Features/Rum/Extensions/RumUIButton+Extensions.swift b/CleanCodeApp/Modules/Features/Rum/Extensions/RumUIButton+Extensions.swift new file mode 100644 index 0000000..b05c2b4 --- /dev/null +++ b/CleanCodeApp/Modules/Features/Rum/Extensions/RumUIButton+Extensions.swift @@ -0,0 +1,16 @@ +// +// RumUIButton+Extensions.swift +// CleanCode +// +// Created by Rayana Prata Neves on 05/02/25. +// + +import UIKit + +extension UIButton { + func setSymbolImage(systemName: String, pointSize: CGFloat, for state: UIControl.State = .normal) { + let symbolConfiguration = UIImage.SymbolConfiguration(pointSize: pointSize) + let image = UIImage(systemName: systemName)?.withConfiguration(symbolConfiguration) + setImage(image, for: state) + } +} From 741e65e35e67c99f4c20d16ae6a894eebc66ddb0 Mon Sep 17 00:00:00 2001 From: alexandrecesarba Date: Tue, 4 Feb 2025 15:19:25 +0100 Subject: [PATCH 07/29] applied solid and clean code for the first time in the code --- .DS_Store | Bin 0 -> 6148 bytes .../Foz/Base.lproj/FozUser.storyboard | 8 +- .../FozResetPasswordViewController.swift | 169 ++++++++++-------- 3 files changed, 100 insertions(+), 77 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..34fbac3b04cc3793320dcf34b0a1787eb332f71d GIT binary patch literal 6148 zcmeHKy-veG47N*#AeK&u@kS=3zCkEqW$6phHVA|g5>=|in3rMTMHmr}#OEKXR)L{H zLa4GO`@3B1OZ+*C?}&(}>uN$YCZZfFI68*;M&!QeKt?{30a@30qAO~tqC2`Ac*n$l zWI$?nimKJ9*_^iP*HK3o^h`^yXh$oI9_#zbY}q!QCc_^u`^GnISuW~!fw=sAp52_k zzR9<;*E=+A_3JgdhpjxmzGO`*OfV1(1Oo@p0D87aeqtCl7zhS}fei!le@IZl!m&5h zUk8kCoPe^8RKZxz5)zXf3&-9NcOYz`KnrC*Vz7l{KDl4v*c)0nv2WSfpUi$jVSPH* zPwGxw7={f7f`MHIj_h(Q{r~#s^Z#y8Tm=Kcz(Fy|^5x?GW j6M})ZV)#lcK7*=YKFI)BIQE8^fy72YX$TVx{3!#U-Vj4N literal 0 HcmV?d00001 diff --git a/CleanCodeApp/Modules/Features/Foz/Base.lproj/FozUser.storyboard b/CleanCodeApp/Modules/Features/Foz/Base.lproj/FozUser.storyboard index b5a4363..6aeca74 100644 --- a/CleanCodeApp/Modules/Features/Foz/Base.lproj/FozUser.storyboard +++ b/CleanCodeApp/Modules/Features/Foz/Base.lproj/FozUser.storyboard @@ -1,9 +1,9 @@ - + - + @@ -444,10 +444,10 @@ E-mail enviado para: - + - + diff --git a/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift index 9abb177..87c67d0 100644 --- a/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift @@ -7,19 +7,19 @@ class FozResetPasswordViewController: UIViewController { @IBOutlet weak var loginButton: UIButton! @IBOutlet weak var helpButton: UIButton! @IBOutlet weak var createAccountButton: UIButton! - + @IBOutlet weak var textLabel: UILabel! @IBOutlet weak var viewSuccess: UIView! @IBOutlet weak var emailLabel: UILabel! - - var email = "" - var recoveryEmail = false + + var userEmail = "" + var hasRecoveryEmail = false override func viewDidLoad() { super.viewDidLoad() setupView() } - + open override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } @@ -28,130 +28,150 @@ class FozResetPasswordViewController: UIViewController { dismiss(animated: true) } +// MARK: Recover Password @IBAction func recoverPasswordButton(_ sender: Any) { - if recoveryEmail { + guard !hasRecoveryEmail else { dismiss(animated: true) return } - if validateForm() { - self.view.endEditing(true) - if !ConnectivityManager.shared.isConnected { - Globals.showNoInternetCOnnection(controller: self) - return - } + guard validateForm() else { + return + } + + view.endEditing(true) + + guard ConnectivityManager.shared.isConnected else { + Globals.showNoInternetCOnnection(controller: self) + return + } + + guard let email = emailTextfield.text?.trimmingCharacters(in: .whitespaces), !email.isEmpty else { + return + } + + let parameters = ["email": email] + performPasswordReset(with: parameters, email: email) + } - let emailUser = emailTextfield.text!.trimmingCharacters(in: .whitespaces) - - let parameters = [ - "email": emailUser - ] - - BadNetworkLayer.shared.resetPassword(self, parameters: parameters) { (success) in - if success { - self.recoveryEmail = true - self.emailTextfield.isHidden = true - self.textLabel.isHidden = true - self.viewSuccess.isHidden = false - self.emailLabel.text = self.emailTextfield.text?.trimmingCharacters(in: .whitespaces) - self.recoverPasswordButton.titleLabel?.text = "REENVIAR E-MAIL" - self.recoverPasswordButton.setTitle("Voltar", for: .normal) - } else { - let alertController = UIAlertController(title: "Ops..", message: "Algo de errado aconteceu. Tente novamente mais tarde.", preferredStyle: .alert) - let action = UIAlertAction(title: "OK", style: .default) - alertController.addAction(action) - self.present(alertController, animated: true) - } + private func performPasswordReset(with parameters: [String: String], email: String) { + BadNetworkLayer.shared.resetPassword(self, parameters: parameters) { [weak self] success in + DispatchQueue.main.async { + guard let self = self else { return } + success ? self.handlePasswordResetSuccess(withEmail: email) : self.handlePasswordResetFailure() } } } - + + private func handlePasswordResetSuccess(withEmail email: String) { + hasRecoveryEmail = true + emailTextfield.isHidden = true + textLabel.isHidden = true + viewSuccess.isHidden = false + emailLabel.text = email + recoverPasswordButton.setTitle("Voltar", for: .normal) + } + + private func handlePasswordResetFailure() { + let alertController = UIAlertController( + title: "Ops…", + message: "Algo de errado aconteceu. Tente novamente mais tarde.", + preferredStyle: .alert + ) + alertController.addAction(UIAlertAction(title: "OK", style: .default)) + present(alertController, animated: true) + } + + @IBAction func loginButton(_ sender: Any) { dismiss(animated: true) } - + @IBAction func helpButton(_ sender: Any) { let vc = FozContactUsViewController() vc.modalPresentationStyle = .fullScreen vc.modalTransitionStyle = .coverVertical self.present(vc, animated: true, completion: nil) } - + @IBAction func createAccountButton(_ sender: Any) { let newVc = FozCreateAccountViewController() newVc.modalPresentationStyle = .fullScreen present(newVc, animated: true) } - + + // TODO: Create validator in a separate file/class/struct func validateForm() -> Bool { let status = emailTextfield.text!.isEmpty || - !emailTextfield.text!.contains(".") || - !emailTextfield.text!.contains("@") || - emailTextfield.text!.count <= 5 - + !emailTextfield.text!.contains(".") || + !emailTextfield.text!.contains("@") || + emailTextfield.text!.count <= 5 + if status { emailTextfield.setErrorColor() textLabel.textColor = .red textLabel.text = "Verifique o e-mail informado" return false } - + return true } } // MARK: - Comportamentos de layout extension FozResetPasswordViewController { - + func setupView() { - recoverPasswordButton.layer.cornerRadius = recoverPasswordButton.bounds.height / 2 - recoverPasswordButton.backgroundColor = .blue - recoverPasswordButton.setTitleColor(.white, for: .normal) + stylePrimaryButton(recoverPasswordButton) + + styleSecondaryButton(loginButton) + + styleSecondaryButton(helpButton) + + styleSecondaryButton(createAccountButton) - loginButton.layer.cornerRadius = createAccountButton.frame.height / 2 - loginButton.layer.borderWidth = 1 - loginButton.layer.borderColor = UIColor.blue.cgColor - loginButton.setTitleColor(.blue, for: .normal) - loginButton.backgroundColor = .white - - helpButton.layer.cornerRadius = createAccountButton.frame.height / 2 - helpButton.layer.borderWidth = 1 - helpButton.layer.borderColor = UIColor.blue.cgColor - helpButton.setTitleColor(.blue, for: .normal) - helpButton.backgroundColor = .white - - createAccountButton.layer.cornerRadius = createAccountButton.frame.height / 2 - createAccountButton.layer.borderWidth = 1 - createAccountButton.layer.borderColor = UIColor.blue.cgColor - createAccountButton.setTitleColor(.blue, for: .normal) - createAccountButton.backgroundColor = .white - emailTextfield.setDefaultColor() - - if !email.isEmpty { - emailTextfield.text = email + + if !userEmail.isEmpty { + emailTextfield.text = userEmail emailTextfield.isEnabled = false } validateButton() } - + //email @IBAction func emailBeginEditing(_ sender: Any) { emailTextfield.setEditingColor() } - + @IBAction func emailEditing(_ sender: Any) { emailTextfield.setEditingColor() validateButton() } - + @IBAction func emailEndEditing(_ sender: Any) { emailTextfield.setDefaultColor() } + + // MARK: Button Styler + func stylePrimaryButton(_ button: UIButton){ + button.layer.cornerRadius = button.bounds.height / 2 + button.backgroundColor = .blue + button.setTitleColor(.white, for: .normal) + } + + func styleSecondaryButton(_ button: UIButton){ + button.layer.cornerRadius = button.bounds.height / 2 + button.layer.borderWidth = 1 + button.layer.borderColor = UIColor.blue.cgColor + button.backgroundColor = .white + button.setTitleColor(.blue, for: .normal) + } + } extension FozResetPasswordViewController { - + func validateButton() { if !emailTextfield.text!.isEmpty { enableCreateButton() @@ -159,16 +179,19 @@ extension FozResetPasswordViewController { disableCreateButton() } } - + func disableCreateButton() { recoverPasswordButton.backgroundColor = .gray recoverPasswordButton.setTitleColor(.white, for: .normal) recoverPasswordButton.isEnabled = false } - + func enableCreateButton() { recoverPasswordButton.backgroundColor = .blue recoverPasswordButton.setTitleColor(.white, for: .normal) recoverPasswordButton.isEnabled = true } + } + + From 9b1a159220e90a96881a468144302a656691b9e9 Mon Sep 17 00:00:00 2001 From: alexandrecesarba Date: Thu, 6 Feb 2025 20:02:11 +0100 Subject: [PATCH 08/29] applied SRP in recoverPasswordButton and validateForm functions --- .DS_Store | Bin 6148 -> 6148 bytes .../FozResetPasswordViewController.swift | 60 ++++++++++++------ 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/.DS_Store b/.DS_Store index 34fbac3b04cc3793320dcf34b0a1787eb332f71d..0dfa4b577c21139a038dca3f3faed29cfc2f9625 100644 GIT binary patch delta 19 acmZoMXffE}#l&>AZ}J2tqs?_pZK422#|G~J delta 19 acmZoMXffE}#l&=B>EsDaMw{!H+C%|Jb_W3f diff --git a/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift index 87c67d0..9e22520 100644 --- a/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift @@ -13,7 +13,7 @@ class FozResetPasswordViewController: UIViewController { @IBOutlet weak var emailLabel: UILabel! var userEmail = "" - var hasRecoveryEmail = false + var userPressedRecoveryButton = false override func viewDidLoad() { super.viewDidLoad() @@ -30,22 +30,23 @@ class FozResetPasswordViewController: UIViewController { // MARK: Recover Password @IBAction func recoverPasswordButton(_ sender: Any) { - guard !hasRecoveryEmail else { - dismiss(animated: true) - return + if !userPressedRecoveryButton { + validateRecovering() } - - guard validateForm() else { - return + else { + dismiss(animated: true) } view.endEditing(true) + } - guard ConnectivityManager.shared.isConnected else { - Globals.showNoInternetCOnnection(controller: self) + private func validateRecovering(){ + guard validateForm() else { return } + checkUserConnection() + guard let email = emailTextfield.text?.trimmingCharacters(in: .whitespaces), !email.isEmpty else { return } @@ -54,6 +55,13 @@ class FozResetPasswordViewController: UIViewController { performPasswordReset(with: parameters, email: email) } + private func checkUserConnection (){ + guard ConnectivityManager.shared.isConnected else { + Globals.showNoInternetCOnnection(controller: self) + return + } + } + private func performPasswordReset(with parameters: [String: String], email: String) { BadNetworkLayer.shared.resetPassword(self, parameters: parameters) { [weak self] success in DispatchQueue.main.async { @@ -64,7 +72,7 @@ class FozResetPasswordViewController: UIViewController { } private func handlePasswordResetSuccess(withEmail email: String) { - hasRecoveryEmail = true + userPressedRecoveryButton = true emailTextfield.isHidden = true textLabel.isHidden = true viewSuccess.isHidden = false @@ -100,21 +108,31 @@ class FozResetPasswordViewController: UIViewController { present(newVc, animated: true) } - // TODO: Create validator in a separate file/class/struct func validateForm() -> Bool { - let status = emailTextfield.text!.isEmpty || - !emailTextfield.text!.contains(".") || - !emailTextfield.text!.contains("@") || - emailTextfield.text!.count <= 5 - - if status { - emailTextfield.setErrorColor() - textLabel.textColor = .red - textLabel.text = "Verifique o e-mail informado" + let isEmailValid = EmailValidator.isValid(emailTextfield.text) + + if isEmailValid { + return true + } + + else { + setupErrorMessage() return false } - return true + } + + private func setupErrorMessage(){ + emailTextfield.setErrorColor() + textLabel.textColor = .red + textLabel.text = "Verifique o e-mail informado" + } +} + +struct EmailValidator { + static func isValid(_ email: String?) -> Bool { + guard let email = email?.trimmingCharacters(in: .whitespaces), !email.isEmpty else { return false } + return email.contains("@") && email.contains(".") && email.count > 5 } } From 1c1c0be8d5f9a4f4ed465c7ec545179d4fde7fb1 Mon Sep 17 00:00:00 2001 From: lfoliveira Date: Wed, 5 Feb 2025 21:56:42 -0300 Subject: [PATCH 09/29] changed(): refactor contact us view controller --- .../Features/Luz/ContactsUs/AppLink.swift | 0 .../LuzContactUsViewController.swift | 317 +++++++++++------- 2 files changed, 192 insertions(+), 125 deletions(-) create mode 100644 CleanCodeApp/Modules/Features/Luz/ContactsUs/AppLink.swift diff --git a/CleanCodeApp/Modules/Features/Luz/ContactsUs/AppLink.swift b/CleanCodeApp/Modules/Features/Luz/ContactsUs/AppLink.swift new file mode 100644 index 0000000..e69de29 diff --git a/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift b/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift index 52e3988..e4150b3 100644 --- a/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift @@ -1,172 +1,209 @@ -// -// ContactUsViewController.swift -// DeliveryAppChallenge -// -// Created by Pedro Menezes on 17/07/22. -// - import UIKit -class LuzContactUsViewController: LoadingInheritageController { +final class LuzContactUsViewController: LoadingInheritageController { var model: ContactUsModel? - let textView = UITextView() - + let symbolConfiguration = UIImage.SymbolConfiguration(pointSize: 36) + + // MARK: - TextView + private lazy var textView: UITextView = { + let text = UITextView() + text.text = "Escreva sua mensagem aqui" + text.translatesAutoresizingMaskIntoConstraints = false + return text + }() + + // MARK: - UILabel's + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.textColor = .black + label.font = UIFont.systemFont(ofSize: 24, weight: .semibold) + label.text = "Escolha o canal para contato" + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + private lazy var messageLabel: UILabel = { + let label = UILabel() + label.textColor = .black + label.font = UIFont.systemFont(ofSize: 16, weight: .semibold) + label.text = "Ou envie uma mensagem" + label.numberOfLines = 2 + label.setContentHuggingPriority(.defaultLow, for: .horizontal) + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + // MARK: - UIButton's + private lazy var phoneButton: UIButton = { + let button = UIButton() + button.backgroundColor = .systemGray4 + button.layer.cornerRadius = 10 + button.addTarget( + self, + action: #selector(phoneDidTap), + for: .touchUpInside + ) + button.setImage( + .init(systemName: "phone")?.withConfiguration(symbolConfiguration), + for: .normal + ) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + private lazy var emailButton: UIButton = { + let button = UIButton() + button.backgroundColor = .systemGray4 + button.layer.cornerRadius = 10 + button.addTarget( + self, + action: #selector(emailDipTap), + for: .touchUpInside + ) + button.setImage( + .init(systemName: "envelope")?.withConfiguration(symbolConfiguration), + for: .normal + ) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + private lazy var chatButton: UIButton = { + let button = UIButton() + button.backgroundColor = .systemGray4 + button.layer.cornerRadius = 10 + button.addTarget( + self, + action: #selector(chatDidTap), + for: .touchUpInside + ) + button.setImage( + .init(systemName: "message")?.withConfiguration(symbolConfiguration), + for: .normal + ) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + private lazy var sendMessageButton: UIButton = { + let button = UIButton() + button.backgroundColor = .blue + button.setTitle(" Enviar ", for: .normal) + button.setTitleColor(.white, for: .normal) + button.layer.cornerRadius = 10 + button.setContentHuggingPriority(.required, for: .horizontal) + button.addTarget( + self, + action: #selector(send), + for: .touchUpInside + ) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + private lazy var closeButton: UIButton = { + let button = UIButton() + button.setTitle("Voltar", for: .normal) + button.setTitleColor(.blue, for: .normal) + button.backgroundColor = .clear + button.layer.borderWidth = 1 + button.layer.borderColor = UIColor.blue.cgColor + button.layer.cornerRadius = 10 + button.addTarget(self, action: #selector(close), for: .touchUpInside) + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + // MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .systemGray6 - let titleLabel = UILabel() - titleLabel.textColor = .black - titleLabel.font = UIFont.systemFont(ofSize: 24, weight: .semibold) - titleLabel.text = "Escolha o canal para contato" - - // Criar botões - let phoneButton = UIButton() - phoneButton.backgroundColor = .systemGray4 - phoneButton.layer.cornerRadius = 10 - phoneButton.addTarget(self, action: #selector(phoneClick), for: .touchUpInside) - let emailButton = UIButton() - emailButton.backgroundColor = .systemGray4 - emailButton.layer.cornerRadius = 10 - emailButton.addTarget(self, action: #selector(emailClick), for: .touchUpInside) - - let chatButton = UIButton() - chatButton.backgroundColor = .systemGray4 - chatButton.layer.cornerRadius = 10 - chatButton.addTarget(self, action: #selector(chatClicked), for: .touchUpInside) - - let messageLabel = UILabel() - messageLabel.textColor = .black - messageLabel.font = UIFont.systemFont(ofSize: 16, weight: .semibold) - messageLabel.text = "Ou envie uma mensagem" - messageLabel.numberOfLines = 2 - messageLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) - - let sendMessageButton = UIButton() - sendMessageButton.backgroundColor = .blue - sendMessageButton.setTitle(" Enviar ", for: .normal) - sendMessageButton.setTitleColor(.white, for: .normal) - sendMessageButton.layer.cornerRadius = 10 - sendMessageButton.setContentHuggingPriority(.required, for: .horizontal) - sendMessageButton.addTarget(self, action: #selector(messageSend), for: .touchUpInside) - - textView.text = "Escreva sua mensagem aqui" - let closeButton = UIButton() - closeButton.setTitle("Voltar", for: .normal) - closeButton.setTitleColor(.blue, for: .normal) - closeButton.backgroundColor = .clear - closeButton.layer.borderWidth = 1 - closeButton.layer.borderColor = UIColor.blue.cgColor - closeButton.layer.cornerRadius = 10 - closeButton.addTarget(self, action: #selector(close), for: .touchUpInside) - - - let symbolConfiguration = UIImage.SymbolConfiguration(pointSize: 36) - phoneButton.setImage(UIImage.init(systemName: "phone")?.withConfiguration(symbolConfiguration), for: .normal) - emailButton.setImage(UIImage.init(systemName: "envelope")?.withConfiguration(symbolConfiguration), for: .normal) - chatButton.setImage(UIImage.init(systemName: "message")?.withConfiguration(symbolConfiguration), for: .normal) - - titleLabel.translatesAutoresizingMaskIntoConstraints = false - phoneButton.translatesAutoresizingMaskIntoConstraints = false - emailButton.translatesAutoresizingMaskIntoConstraints = false - chatButton.translatesAutoresizingMaskIntoConstraints = false - messageLabel.translatesAutoresizingMaskIntoConstraints = false - textView.translatesAutoresizingMaskIntoConstraints = false - sendMessageButton.translatesAutoresizingMaskIntoConstraints = false - closeButton.translatesAutoresizingMaskIntoConstraints = false - - view.addSubview(titleLabel) - view.addSubview(phoneButton) - view.addSubview(emailButton) - view.addSubview(chatButton) - view.addSubview(messageLabel) - view.addSubview(textView) - view.addSubview(sendMessageButton) - view.addSubview(closeButton) - - NSLayoutConstraint.activate([ + configureUI() + setupConstraints() + fetch() + } + func configureUI() { + [ + titleLabel, + phoneButton, + emailButton, + chatButton, + messageLabel, + textView, + sendMessageButton, + closeButton + ].forEach { view.addSubview($0) } + } + + func setupConstraints() { + NSLayoutConstraint.activate([ titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 30), titleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), titleLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), - + phoneButton.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 30), emailButton.centerYAnchor.constraint(equalTo: phoneButton.centerYAnchor), chatButton.centerYAnchor.constraint(equalTo: phoneButton.centerYAnchor), - + phoneButton.widthAnchor.constraint(equalToConstant: 80), phoneButton.heightAnchor.constraint(equalToConstant: 80), phoneButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), - + emailButton.widthAnchor.constraint(equalToConstant: 80), emailButton.heightAnchor.constraint(equalToConstant: 80), emailButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), - + chatButton.widthAnchor.constraint(equalToConstant: 80), chatButton.heightAnchor.constraint(equalToConstant: 80), chatButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), - + messageLabel.topAnchor.constraint(equalTo: phoneButton.bottomAnchor, constant: 30), messageLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), messageLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), -// stackView.heightAnchor.constraint(equalToConstant: 30), - + textView.topAnchor.constraint(equalTo: messageLabel.bottomAnchor, constant: 20), textView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), textView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), textView.bottomAnchor.constraint(equalTo: sendMessageButton.topAnchor, constant: -30), - - + + sendMessageButton.bottomAnchor.constraint(equalTo: closeButton.topAnchor, constant: -20), sendMessageButton.heightAnchor.constraint(equalToConstant: 40), sendMessageButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), sendMessageButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), - + closeButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20), closeButton.heightAnchor.constraint(equalToConstant: 40), closeButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), closeButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), ]) - - pegarDados() } - + @objc - func phoneClick() { - if let tel = model?.phone, - let url = URL(string: "tel://\(tel)") { - UIApplication.shared.open(url, options: [:], completionHandler: nil) - } + func phoneDidTap() { + guard let phone = model?.phone else { return } + open(appLink: .phone(phone)) } - + @objc - func emailClick() { - if let mail = model?.mail, - let url = URL(string: "mailto:\(mail)") { - UIApplication.shared.open(url, options: [:], completionHandler: nil) - } + func emailDipTap() { + guard let email = model?.mail else { return } + open(appLink: .email(email)) } - + @objc - func chatClicked() { - if let phoneNumber = model?.phone, let whatsappURL = URL(string: "whatsapp://send?phone=\(phoneNumber)&text=Oi)") { - if UIApplication.shared.canOpenURL(whatsappURL) { - UIApplication.shared.open(whatsappURL, options: [:], completionHandler: nil) - } else { - if let appStoreURL = URL(string: "https://apps.apple.com/app/whatsapp-messenger/id310633997") { - UIApplication.shared.open(appStoreURL, options: [:], completionHandler: nil) - } - } - } + func chatDidTap() { + guard let phone = model?.phone else { return } + open(appLink: .whatsapp(phone)) } - + @objc func close() { dismiss(animated: true) } - - - func pegarDados() { + + func fetch() { showLoadingView() let url = Endpoints.contactUs AF.shared.request(url, method: .get, parameters: nil, headers: nil) { result in @@ -189,9 +226,9 @@ class LuzContactUsViewController: LoadingInheritageController { } } } - + @objc - func messageSend() { + func send() { view.endEditing(true) let email = model?.mail ?? "" if let message = textView.text, textView.text.count > 0 { @@ -201,17 +238,47 @@ class LuzContactUsViewController: LoadingInheritageController { ] showLoadingView() let url = Endpoints.sendMessage - AF.shared.request(url, method: .post, parameters: parameters, headers: nil) { result in + AF.shared.request( + url, + method: .post, + parameters: parameters, + headers: nil + ) { result in self.removeLoadingView() switch result { case .success: - Globals.alertMessage(title: "Sucesso..", message: "Sua mensagem foi enviada", targetVC: self) { + Globals.alertMessage( + title: "Sucesso..", + message: "Sua mensagem foi enviada", + targetVC: self + ) { self.dismiss(animated: true) } case .failure: - Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) + Globals.alertMessage( + title: "Ops..", + message: "Ocorreu algum erro", + targetVC: self + ) } } } } + + // MARK: - private funcs + private func open(appLink: AppLink) { + guard let url = appLink.url else { return } + + if appLink.fallbackURL != nil, !UIApplication.shared.canOpenURL(url) { + if let fallback = appLink.fallbackURL { + UIApplication.shared.open(fallback, options: [:], completionHandler: nil) + } + } else { + UIApplication.shared.open(url, options: [:], completionHandler: nil) + } + } +} + +#Preview { + LuzContactUsViewController() } From 83a17a6ea49f3dd062c6d8a729c8ba116053bc63 Mon Sep 17 00:00:00 2001 From: lfoliveira Date: Wed, 5 Feb 2025 22:00:54 -0300 Subject: [PATCH 10/29] added(): applink --- .../Features/Luz/ContactsUs/AppLink.swift | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/CleanCodeApp/Modules/Features/Luz/ContactsUs/AppLink.swift b/CleanCodeApp/Modules/Features/Luz/ContactsUs/AppLink.swift index e69de29..af18bca 100644 --- a/CleanCodeApp/Modules/Features/Luz/ContactsUs/AppLink.swift +++ b/CleanCodeApp/Modules/Features/Luz/ContactsUs/AppLink.swift @@ -0,0 +1,27 @@ +import Foundation + +enum AppLink { + case phone(String) + case email(String) + case whatsapp(String) + + var url: URL? { + switch self { + case .phone(let number): + return URL(string: "tel://\(number)") + case .email(let email): + return URL(string: "mailto://\(email)") + case .whatsapp(let phoneNumber): + return URL(string: "whatsapp://send?phone=\(phoneNumber)&text=Oi") + } + } + + var fallbackURL: URL? { + switch self { + case .whatsapp: + return URL(string: "https://apps.apple.com/app/whatsapp-messenger/id310633997") + default: + return nil + } + } +} From 42bbb445110b5fb16c84f14bdf04b2957e6c0dc5 Mon Sep 17 00:00:00 2001 From: lfoliveira Date: Wed, 5 Feb 2025 22:04:31 -0300 Subject: [PATCH 11/29] chore(): remove whitespaces --- .../Features/Luz/ContactsUs/LuzContactUsViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift b/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift index e4150b3..ed92eea 100644 --- a/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift @@ -88,7 +88,7 @@ final class LuzContactUsViewController: LoadingInheritageController { private lazy var sendMessageButton: UIButton = { let button = UIButton() button.backgroundColor = .blue - button.setTitle(" Enviar ", for: .normal) + button.setTitle("Enviar", for: .normal) button.setTitleColor(.white, for: .normal) button.layer.cornerRadius = 10 button.setContentHuggingPriority(.required, for: .horizontal) From 1d6851e762c8c63ff75ef956a2ff400eaa8b80b4 Mon Sep 17 00:00:00 2001 From: lfoliveira Date: Thu, 6 Feb 2025 22:48:39 -0300 Subject: [PATCH 12/29] added(): refactor stackviews --- .../LuzContactUsViewController.swift | 115 ++++++++++++------ 1 file changed, 77 insertions(+), 38 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift b/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift index ed92eea..449d148 100644 --- a/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift @@ -119,7 +119,7 @@ final class LuzContactUsViewController: LoadingInheritageController { super.viewDidLoad() view.backgroundColor = .systemGray6 configureUI() - setupConstraints() + setupLayout() fetch() } @@ -136,47 +136,34 @@ final class LuzContactUsViewController: LoadingInheritageController { ].forEach { view.addSubview($0) } } - func setupConstraints() { - NSLayoutConstraint.activate([ - titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 30), - titleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), - titleLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), - - phoneButton.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 30), - emailButton.centerYAnchor.constraint(equalTo: phoneButton.centerYAnchor), - chatButton.centerYAnchor.constraint(equalTo: phoneButton.centerYAnchor), - - phoneButton.widthAnchor.constraint(equalToConstant: 80), - phoneButton.heightAnchor.constraint(equalToConstant: 80), - phoneButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), - - emailButton.widthAnchor.constraint(equalToConstant: 80), - emailButton.heightAnchor.constraint(equalToConstant: 80), - emailButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), + func setupLayout() { + let contactButtonsStackView = createContactButtonsStackView() + let messageStackView = createMessageStackView() + let ctaStackView = createCTAStackView() - chatButton.widthAnchor.constraint(equalToConstant: 80), - chatButton.heightAnchor.constraint(equalToConstant: 80), - chatButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), - - messageLabel.topAnchor.constraint(equalTo: phoneButton.bottomAnchor, constant: 30), - messageLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), - messageLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), - - textView.topAnchor.constraint(equalTo: messageLabel.bottomAnchor, constant: 20), - textView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), - textView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), - textView.bottomAnchor.constraint(equalTo: sendMessageButton.topAnchor, constant: -30), + let mainStackView = UIStackView( + arrangedSubviews: [ + titleLabel, + contactButtonsStackView, + messageStackView, + ctaStackView + ] + ) + mainStackView.axis = .vertical + mainStackView.spacing = 30 + mainStackView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(mainStackView) - sendMessageButton.bottomAnchor.constraint(equalTo: closeButton.topAnchor, constant: -20), - sendMessageButton.heightAnchor.constraint(equalToConstant: 40), - sendMessageButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), - sendMessageButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + setupConstraints(for: mainStackView) + } - closeButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20), - closeButton.heightAnchor.constraint(equalToConstant: 40), - closeButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), - closeButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), + func setupConstraints(for mainStackView: UIStackView) { + NSLayoutConstraint.activate([ + mainStackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 30), + mainStackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20), + mainStackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20), + mainStackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20) ]) } @@ -279,6 +266,58 @@ final class LuzContactUsViewController: LoadingInheritageController { } } +// MARK: - StackView's +extension LuzContactUsViewController { + private func createContactButtonsStackView() -> UIStackView { + let stackView = UIStackView( + arrangedSubviews: [ + phoneButton, + emailButton, + chatButton + ] + ) + stackView.axis = .horizontal + stackView.alignment = .center + stackView.distribution = .equalSpacing + + [phoneButton, emailButton, chatButton].forEach { view in + view.widthAnchor.constraint(equalToConstant: 80).isActive = true + view.heightAnchor.constraint(equalToConstant: 80).isActive = true + } + + return stackView + } + + private func createMessageStackView() -> UIStackView { + let stackView = UIStackView( + arrangedSubviews: [ + messageLabel, + textView + ] + ) + stackView.axis = .vertical + stackView.spacing = 20 + return stackView + } + + private func createCTAStackView() -> UIStackView { + let stackView = UIStackView( + arrangedSubviews: [ + sendMessageButton, + closeButton + ] + ) + stackView.axis = .vertical + stackView.spacing = 20 + + [sendMessageButton, closeButton].forEach { view in + view.heightAnchor.constraint(equalToConstant: 40).isActive = true + } + return stackView + } + +} + #Preview { LuzContactUsViewController() } From 08b4c35cefe321e24030184dbfc9e9257463a142 Mon Sep 17 00:00:00 2001 From: lfoliveira Date: Thu, 6 Feb 2025 22:58:43 -0300 Subject: [PATCH 13/29] refactor more class --- .../LuzContactUsViewController.swift | 76 ++++++++++++------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift b/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift index 449d148..b795979 100644 --- a/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift @@ -192,28 +192,39 @@ final class LuzContactUsViewController: LoadingInheritageController { func fetch() { showLoadingView() - let url = Endpoints.contactUs - AF.shared.request(url, method: .get, parameters: nil, headers: nil) { result in + AF.shared.request( + Endpoints.contactUs, + method: .get, + parameters: nil, + headers: nil + ) { result in self.removeLoadingView() switch result { case .success(let data): - let decoder = JSONDecoder() - if let returned = try? decoder.decode(ContactUsModel.self, from: data) { - self.model = returned - } else { - Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) { - self.dismiss(animated: true) - } - } + self.handleSuccess(data: data) case .failure(let error): - print("error api: \(error.localizedDescription)") - Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) { - self.dismiss(animated: true) - } + self.handleError(error) } } } + // MARK: - Handlers + private func handleSuccess(data: Data) { + return if let returned = try? JSONDecoder().decode( + ContactUsModel.self, + from: data + ) { + self.model = returned + } else { + showAlertError() + } + } + + private func handleError(_ error: Error) { + print("error api: \(error.localizedDescription)") + showAlertError() + } + @objc func send() { view.endEditing(true) @@ -224,9 +235,8 @@ final class LuzContactUsViewController: LoadingInheritageController { "mensagem": message ] showLoadingView() - let url = Endpoints.sendMessage AF.shared.request( - url, + Endpoints.sendMessage, method: .post, parameters: parameters, headers: nil @@ -234,19 +244,9 @@ final class LuzContactUsViewController: LoadingInheritageController { self.removeLoadingView() switch result { case .success: - Globals.alertMessage( - title: "Sucesso..", - message: "Sua mensagem foi enviada", - targetVC: self - ) { - self.dismiss(animated: true) - } + self.showAlertSuccess() case .failure: - Globals.alertMessage( - title: "Ops..", - message: "Ocorreu algum erro", - targetVC: self - ) + self.showAlertError() } } } @@ -264,6 +264,26 @@ final class LuzContactUsViewController: LoadingInheritageController { UIApplication.shared.open(url, options: [:], completionHandler: nil) } } + + private func showAlertSuccess() { + Globals.alertMessage( + title: "Sucesso..", + message: "Sua mensagem foi enviada", + targetVC: self + ) { + self.dismiss(animated: true) + } + } + + private func showAlertError() { + Globals.alertMessage( + title: "Ops..", + message: "Ocorreu algum erro", + targetVC: self + ) { + self.dismiss(animated: true) + } + } } // MARK: - StackView's From 0dea448ef540561a2b25f7afc24235d59a572145 Mon Sep 17 00:00:00 2001 From: lfoliveira Date: Thu, 6 Feb 2025 22:59:34 -0300 Subject: [PATCH 14/29] fixed(): return func on open --- .../LuzContactUsViewController.swift | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift b/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift index b795979..76d5cf9 100644 --- a/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift @@ -256,12 +256,18 @@ final class LuzContactUsViewController: LoadingInheritageController { private func open(appLink: AppLink) { guard let url = appLink.url else { return } - if appLink.fallbackURL != nil, !UIApplication.shared.canOpenURL(url) { - if let fallback = appLink.fallbackURL { - UIApplication.shared.open(fallback, options: [:], completionHandler: nil) - } - } else { - UIApplication.shared.open(url, options: [:], completionHandler: nil) + if UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open( + url, + options: [:], + completionHandler: nil + ) + } else if let fallback = appLink.fallbackURL { + UIApplication.shared.open( + fallback, + options: [:], + completionHandler: nil + ) } } From b193e27b191aa3369cbf1f2b8a9ea97a69b59011 Mon Sep 17 00:00:00 2001 From: Jorge Roberto Date: Tue, 4 Feb 2025 20:35:50 -0300 Subject: [PATCH 15/29] Removing white spaces --- .../CeuResetPasswordViewController.swift | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift index 036a32e..c49c4ea 100644 --- a/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift @@ -7,11 +7,11 @@ class CeuResetPasswordViewController: UIViewController { @IBOutlet weak var loginButton: UIButton! @IBOutlet weak var helpButton: UIButton! @IBOutlet weak var createAccountButton: UIButton! - + @IBOutlet weak var textLabel: UILabel! @IBOutlet weak var viewSuccess: UIView! @IBOutlet weak var emailLabel: UILabel! - + var email = "" var recoveryEmail = false @@ -19,7 +19,7 @@ class CeuResetPasswordViewController: UIViewController { super.viewDidLoad() setupView() } - + open override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } @@ -42,11 +42,11 @@ class CeuResetPasswordViewController: UIViewController { } let emailUser = emailTextfield.text!.trimmingCharacters(in: .whitespaces) - + let parameters = [ "email": emailUser ] - + BadNetworkLayer.shared.resetPassword(self, parameters: parameters) { (success) in if success { self.recoveryEmail = true @@ -65,44 +65,44 @@ class CeuResetPasswordViewController: UIViewController { } } } - + @IBAction func loginButton(_ sender: Any) { dismiss(animated: true) } - + @IBAction func helpButton(_ sender: Any) { let vc = CeuContactUsViewController() vc.modalPresentationStyle = .fullScreen vc.modalTransitionStyle = .coverVertical self.present(vc, animated: true, completion: nil) } - + @IBAction func createAccountButton(_ sender: Any) { let newVc = CeuCreateAccountViewController() newVc.modalPresentationStyle = .fullScreen present(newVc, animated: true) } - + func validateForm() -> Bool { let status = emailTextfield.text!.isEmpty || - !emailTextfield.text!.contains(".") || - !emailTextfield.text!.contains("@") || - emailTextfield.text!.count <= 5 - + !emailTextfield.text!.contains(".") || + !emailTextfield.text!.contains("@") || + emailTextfield.text!.count <= 5 + if status { emailTextfield.setErrorColor() textLabel.textColor = .red textLabel.text = "Verifique o e-mail informado" return false } - + return true } } // MARK: - Comportamentos de layout extension CeuResetPasswordViewController { - + func setupView() { recoverPasswordButton.layer.cornerRadius = recoverPasswordButton.bounds.height / 2 recoverPasswordButton.backgroundColor = .blue @@ -113,45 +113,45 @@ extension CeuResetPasswordViewController { loginButton.layer.borderColor = UIColor.blue.cgColor loginButton.setTitleColor(.blue, for: .normal) loginButton.backgroundColor = .white - + helpButton.layer.cornerRadius = createAccountButton.frame.height / 2 helpButton.layer.borderWidth = 1 helpButton.layer.borderColor = UIColor.blue.cgColor helpButton.setTitleColor(.blue, for: .normal) helpButton.backgroundColor = .white - + createAccountButton.layer.cornerRadius = createAccountButton.frame.height / 2 createAccountButton.layer.borderWidth = 1 createAccountButton.layer.borderColor = UIColor.blue.cgColor createAccountButton.setTitleColor(.blue, for: .normal) createAccountButton.backgroundColor = .white - + emailTextfield.setDefaultColor() - + if !email.isEmpty { emailTextfield.text = email emailTextfield.isEnabled = false } validateButton() } - + //email @IBAction func emailBeginEditing(_ sender: Any) { emailTextfield.setEditingColor() } - + @IBAction func emailEditing(_ sender: Any) { emailTextfield.setEditingColor() validateButton() } - + @IBAction func emailEndEditing(_ sender: Any) { emailTextfield.setDefaultColor() } } extension CeuResetPasswordViewController { - + func validateButton() { if !emailTextfield.text!.isEmpty { enableCreateButton() @@ -159,16 +159,17 @@ extension CeuResetPasswordViewController { disableCreateButton() } } - + func disableCreateButton() { recoverPasswordButton.backgroundColor = .gray recoverPasswordButton.setTitleColor(.white, for: .normal) recoverPasswordButton.isEnabled = false } - + func enableCreateButton() { recoverPasswordButton.backgroundColor = .blue recoverPasswordButton.setTitleColor(.white, for: .normal) recoverPasswordButton.isEnabled = true } } + From cee5e06d216a3f6f2ce4a74d1976091cb7a88d58 Mon Sep 17 00:00:00 2001 From: Jorge Roberto Date: Tue, 4 Feb 2025 20:49:35 -0300 Subject: [PATCH 16/29] Refactor ResetPassword setupView functions --- .../CeuResetPasswordViewController.swift | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift index c49c4ea..b87fc10 100644 --- a/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift @@ -103,39 +103,57 @@ class CeuResetPasswordViewController: UIViewController { // MARK: - Comportamentos de layout extension CeuResetPasswordViewController { + // MARK: - Setup Views func setupView() { + setupRecoverPasswordButton() + setupLoginButton() + setupHelpButton() + setupCreateAccountButton() + setupEmailTextfield() + + validateButton() + } + + private func setupRecoverPasswordButton() { recoverPasswordButton.layer.cornerRadius = recoverPasswordButton.bounds.height / 2 recoverPasswordButton.backgroundColor = .blue recoverPasswordButton.setTitleColor(.white, for: .normal) + } + private func setupLoginButton() { loginButton.layer.cornerRadius = createAccountButton.frame.height / 2 loginButton.layer.borderWidth = 1 loginButton.layer.borderColor = UIColor.blue.cgColor loginButton.setTitleColor(.blue, for: .normal) loginButton.backgroundColor = .white + } + private func setupHelpButton() { helpButton.layer.cornerRadius = createAccountButton.frame.height / 2 helpButton.layer.borderWidth = 1 helpButton.layer.borderColor = UIColor.blue.cgColor helpButton.setTitleColor(.blue, for: .normal) helpButton.backgroundColor = .white + } + private func setupCreateAccountButton() { createAccountButton.layer.cornerRadius = createAccountButton.frame.height / 2 createAccountButton.layer.borderWidth = 1 createAccountButton.layer.borderColor = UIColor.blue.cgColor createAccountButton.setTitleColor(.blue, for: .normal) createAccountButton.backgroundColor = .white + } + private func setupEmailTextfield() { emailTextfield.setDefaultColor() if !email.isEmpty { emailTextfield.text = email emailTextfield.isEnabled = false } - validateButton() } - //email + // MARK: - Email TextField Editing Functions @IBAction func emailBeginEditing(_ sender: Any) { emailTextfield.setEditingColor() } From 476f78645ab1ef820e77cf40d2ece634a0977ff0 Mon Sep 17 00:00:00 2001 From: Jorge Roberto Date: Tue, 4 Feb 2025 21:33:20 -0300 Subject: [PATCH 17/29] Refactor Reset Password Request Functions --- .../CeuResetPasswordViewController.swift | 103 ++++++++++++------ 1 file changed, 69 insertions(+), 34 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift index b87fc10..5a582b3 100644 --- a/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift @@ -24,6 +24,44 @@ class CeuResetPasswordViewController: UIViewController { return .lightContent } + // MARK: - Reset Password Request functions + + private func handleResetPasswordRequestSuccess() { + self.recoveryEmail = true + self.emailTextfield.isHidden = true + self.textLabel.isHidden = true + self.viewSuccess.isHidden = false + self.emailLabel.text = self.emailTextfield.text?.trimmingCharacters(in: .whitespaces) + self.recoverPasswordButton.titleLabel?.text = "REENVIAR E-MAIL" + self.recoverPasswordButton.setTitle("Voltar", for: .normal) + } + + private func handleResetPasswordRequestError() { + let alertController = UIAlertController(title: "Ops..", message: "Algo de errado aconteceu. Tente novamente mais tarde.", preferredStyle: .alert) + let action = UIAlertAction(title: "OK", style: .default) + alertController.addAction(action) + self.present(alertController, animated: true) + } + + private func makeResetPasswordRequest(parameters: [String : String]) { + BadNetworkLayer.shared.resetPassword(self, parameters: parameters) { (success) in + if success { + return self.handleResetPasswordRequestSuccess() + } + self.handleResetPasswordRequestError() + } + } + + private func setupResetPasswordRequestParameters() -> [String: String] { + let emailUser = emailTextfield.text!.trimmingCharacters(in: .whitespaces) + let parameters = [ + "email": emailUser + ] + + return parameters + } + + // MARK: - IBAction functions @IBAction func closeButtonAction(_ sender: Any) { dismiss(animated: true) } @@ -41,28 +79,8 @@ class CeuResetPasswordViewController: UIViewController { return } - let emailUser = emailTextfield.text!.trimmingCharacters(in: .whitespaces) - - let parameters = [ - "email": emailUser - ] - - BadNetworkLayer.shared.resetPassword(self, parameters: parameters) { (success) in - if success { - self.recoveryEmail = true - self.emailTextfield.isHidden = true - self.textLabel.isHidden = true - self.viewSuccess.isHidden = false - self.emailLabel.text = self.emailTextfield.text?.trimmingCharacters(in: .whitespaces) - self.recoverPasswordButton.titleLabel?.text = "REENVIAR E-MAIL" - self.recoverPasswordButton.setTitle("Voltar", for: .normal) - } else { - let alertController = UIAlertController(title: "Ops..", message: "Algo de errado aconteceu. Tente novamente mais tarde.", preferredStyle: .alert) - let action = UIAlertAction(title: "OK", style: .default) - alertController.addAction(action) - self.present(alertController, animated: true) - } - } + let parameters = setupResetPasswordRequestParameters() + makeResetPasswordRequest(parameters: parameters) } } @@ -71,24 +89,42 @@ class CeuResetPasswordViewController: UIViewController { } @IBAction func helpButton(_ sender: Any) { - let vc = CeuContactUsViewController() - vc.modalPresentationStyle = .fullScreen - vc.modalTransitionStyle = .coverVertical - self.present(vc, animated: true, completion: nil) + let viewController = setupContactUsViewController() + self.present(viewController, animated: true, completion: nil) } @IBAction func createAccountButton(_ sender: Any) { - let newVc = CeuCreateAccountViewController() - newVc.modalPresentationStyle = .fullScreen - present(newVc, animated: true) + let viewController = setupCreateAccountViewController() + present(viewController, animated: true) } - func validateForm() -> Bool { + private func setupContactUsViewController() -> UIViewController { + let viewController = CeuContactUsViewController() + viewController.modalPresentationStyle = .fullScreen + viewController.modalTransitionStyle = .coverVertical + + return viewController + } + + private func setupCreateAccountViewController() -> UIViewController { + let viewController = CeuCreateAccountViewController() + viewController.modalPresentationStyle = .fullScreen + + return viewController + } + + private func setupStatus() -> Bool { let status = emailTextfield.text!.isEmpty || !emailTextfield.text!.contains(".") || !emailTextfield.text!.contains("@") || emailTextfield.text!.count <= 5 + return status + } + + func validateForm() -> Bool { + let status = setupStatus() + if status { emailTextfield.setErrorColor() textLabel.textColor = .red @@ -171,11 +207,10 @@ extension CeuResetPasswordViewController { extension CeuResetPasswordViewController { func validateButton() { - if !emailTextfield.text!.isEmpty { - enableCreateButton() - } else { - disableCreateButton() + if emailTextfield.text!.isEmpty { + return disableCreateButton() } + return enableCreateButton() } func disableCreateButton() { From 0bf8a44413be45bed9300fd92d74d1c8e5e6895b Mon Sep 17 00:00:00 2001 From: Jorge Roberto Date: Thu, 6 Feb 2025 20:50:54 -0300 Subject: [PATCH 18/29] Adjuste code with Code Review feedback --- .../CeuResetPasswordViewController.swift | 105 +++++++++--------- 1 file changed, 54 insertions(+), 51 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift index 5a582b3..df349c4 100644 --- a/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift @@ -24,43 +24,6 @@ class CeuResetPasswordViewController: UIViewController { return .lightContent } - // MARK: - Reset Password Request functions - - private func handleResetPasswordRequestSuccess() { - self.recoveryEmail = true - self.emailTextfield.isHidden = true - self.textLabel.isHidden = true - self.viewSuccess.isHidden = false - self.emailLabel.text = self.emailTextfield.text?.trimmingCharacters(in: .whitespaces) - self.recoverPasswordButton.titleLabel?.text = "REENVIAR E-MAIL" - self.recoverPasswordButton.setTitle("Voltar", for: .normal) - } - - private func handleResetPasswordRequestError() { - let alertController = UIAlertController(title: "Ops..", message: "Algo de errado aconteceu. Tente novamente mais tarde.", preferredStyle: .alert) - let action = UIAlertAction(title: "OK", style: .default) - alertController.addAction(action) - self.present(alertController, animated: true) - } - - private func makeResetPasswordRequest(parameters: [String : String]) { - BadNetworkLayer.shared.resetPassword(self, parameters: parameters) { (success) in - if success { - return self.handleResetPasswordRequestSuccess() - } - self.handleResetPasswordRequestError() - } - } - - private func setupResetPasswordRequestParameters() -> [String: String] { - let emailUser = emailTextfield.text!.trimmingCharacters(in: .whitespaces) - let parameters = [ - "email": emailUser - ] - - return parameters - } - // MARK: - IBAction functions @IBAction func closeButtonAction(_ sender: Any) { dismiss(animated: true) @@ -78,9 +41,12 @@ class CeuResetPasswordViewController: UIViewController { Globals.showNoInternetCOnnection(controller: self) return } - - let parameters = setupResetPasswordRequestParameters() - makeResetPasswordRequest(parameters: parameters) + do { + let parameters = try setupResetPasswordRequestParameters() + makeResetPasswordRequest(parameters: parameters) + } catch { + Globals.alertMessage(title: "Ops...", message: "Tente novamente mais tarde", targetVC: self) + } } } @@ -98,6 +64,45 @@ class CeuResetPasswordViewController: UIViewController { present(viewController, animated: true) } + // MARK: - Reset Password Request functions + + private func makeResetPasswordRequest(parameters: [String : String]) { + BadNetworkLayer.shared.resetPassword(self, parameters: parameters) { (success) in + if success { + return self.handleResetPasswordRequestSuccess() + } + self.handleResetPasswordRequestError() + } + } + + private func handleResetPasswordRequestSuccess() { + self.recoveryEmail = true + self.emailTextfield.isHidden = true + self.textLabel.isHidden = true + self.viewSuccess.isHidden = false + self.emailLabel.text = self.emailTextfield.text?.trimmingCharacters(in: .whitespaces) + self.recoverPasswordButton.titleLabel?.text = "REENVIAR E-MAIL" + self.recoverPasswordButton.setTitle("Voltar", for: .normal) + } + + private func handleResetPasswordRequestError() { + let alertController = UIAlertController(title: "Ops..", message: "Algo de errado aconteceu. Tente novamente mais tarde.", preferredStyle: .alert) + let action = UIAlertAction(title: "OK", style: .default) + alertController.addAction(action) + self.present(alertController, animated: true) + } + + private func setupResetPasswordRequestParameters() throws -> [String: String] { + guard let text = emailTextfield.text else { throw CommonsErros.invalidData } + + let emailUser = text.trimmingCharacters(in: .whitespaces) + let parameters = [ + "email": emailUser + ] + + return parameters + } + private func setupContactUsViewController() -> UIViewController { let viewController = CeuContactUsViewController() viewController.modalPresentationStyle = .fullScreen @@ -208,21 +213,19 @@ extension CeuResetPasswordViewController { func validateButton() { if emailTextfield.text!.isEmpty { - return disableCreateButton() + return createButtonIs(enable: false) } - return enableCreateButton() + return createButtonIs(enable: true) } - func disableCreateButton() { - recoverPasswordButton.backgroundColor = .gray + func createButtonIs(enable: Bool) { + recoverPasswordButton.backgroundColor = enable ? .blue : .gray recoverPasswordButton.setTitleColor(.white, for: .normal) - recoverPasswordButton.isEnabled = false - } - - func enableCreateButton() { - recoverPasswordButton.backgroundColor = .blue - recoverPasswordButton.setTitleColor(.white, for: .normal) - recoverPasswordButton.isEnabled = true + recoverPasswordButton.isEnabled = enable } } + +enum CommonsErros: Error { + case invalidData +} From 2ce712ae156f9e2c425fe24e1d55229bdb75655c Mon Sep 17 00:00:00 2001 From: Jorge Roberto Date: Fri, 7 Feb 2025 12:18:27 -0300 Subject: [PATCH 19/29] Adjust Reset Password code with Code Review sugestions --- .../CeuResetPasswordViewController.swift | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift index df349c4..5795434 100644 --- a/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift @@ -32,21 +32,8 @@ class CeuResetPasswordViewController: UIViewController { @IBAction func recoverPasswordButton(_ sender: Any) { if recoveryEmail { dismiss(animated: true) - return - } - - if validateForm() { - self.view.endEditing(true) - if !ConnectivityManager.shared.isConnected { - Globals.showNoInternetCOnnection(controller: self) - return - } - do { - let parameters = try setupResetPasswordRequestParameters() - makeResetPasswordRequest(parameters: parameters) - } catch { - Globals.alertMessage(title: "Ops...", message: "Tente novamente mais tarde", targetVC: self) - } + } else { + startRecoverPassword() } } @@ -127,17 +114,42 @@ class CeuResetPasswordViewController: UIViewController { return status } - func validateForm() -> Bool { + private func startRecoverPassword() { + do { + try validateForm() + try verifyInternet() + + let parameters = try setupResetPasswordRequestParameters() + makeResetPasswordRequest(parameters: parameters) + } catch CommonsErros.invalidEmail { + showAlert(message: "Verifique o e-mail informado.") + } catch { + showAlert(message: "Algo de errado aconteceu. Tente novamente mais tarde.") + } + } + + private func showAlert(message: String) { + return Globals.alertMessage(title: "Ops...", message: message, targetVC: self) + } + + private func verifyInternet() throws { + if !ConnectivityManager.shared.isConnected { + Globals.showNoInternetCOnnection(controller: self) + throw CommonsErros.networkError + } + } + + private func validateForm() throws { let status = setupStatus() if status { emailTextfield.setErrorColor() textLabel.textColor = .red textLabel.text = "Verifique o e-mail informado" - return false + throw CommonsErros.invalidEmail } - return true + self.view.endEditing(true) } } @@ -228,4 +240,6 @@ extension CeuResetPasswordViewController { enum CommonsErros: Error { case invalidData + case invalidEmail + case networkError } From 872a360b3489758281a467d3eba58f28e8898013 Mon Sep 17 00:00:00 2001 From: ppedroam Date: Sat, 8 Feb 2025 19:36:44 -0300 Subject: [PATCH 20/29] 3 - nomenclatura --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 1 + CleanCodeApp/LiveCode/3-nomes/codigo3.swift | 128 ++++++++++++++++++ .../CeuResetPasswordViewController.swift | 8 +- .../RumResetPasswordViewController.swift | 3 +- .../Modules/Utils/Globals/Globals.swift | 6 + 6 files changed, 141 insertions(+), 5 deletions(-) delete mode 100644 .DS_Store create mode 100644 CleanCodeApp/LiveCode/3-nomes/codigo3.swift diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 0dfa4b577c21139a038dca3f3faed29cfc2f9625..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKy-veG47N*#AeK&u@kS=3zCkEqW$6phHVA|g5>=|im?z*pco9Z6-iOaWRILI- zg@jOLOZIoU*q8Wo6yFgMPuJCiXiP*oRB&_*^Nq-T(SeM7CIhmr@kCeDQbl)kIq;5& z|Hy#U?i5w4QL{O1*RP|FF6fz-UeS(L7(Leali9LuI!%T@UiOV|+Ok~K?E-Q6`#ifj ze|?j0Wv_Q=+UnP9bPrp3e0|B9RG45O7zhRqo&of1k^ICkY%mZE1Opoexb^oFybCITnt+A?`rfLV*^_e#Br4$9!_X!m&5BaAM!Gu|Jvpgu?oC zte@1KxG)SG3?|zSo;6<&*%T$ptuSKf`Nl#fU|N|PLY!L)1FR(u9k!F-YduyE`RF$0N>fYJ~q82D2LJ^@z*Lnr_M diff --git a/.gitignore b/.gitignore index 2313c29..2392252 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ xcuserdata/ *.ipa *.dSYM.zip *.dSYM +*.DS_Store ## Playgrounds timeline.xctimeline diff --git a/CleanCodeApp/LiveCode/3-nomes/codigo3.swift b/CleanCodeApp/LiveCode/3-nomes/codigo3.swift new file mode 100644 index 0000000..151c851 --- /dev/null +++ b/CleanCodeApp/LiveCode/3-nomes/codigo3.swift @@ -0,0 +1,128 @@ +// +// codigo3.swift +// CleanCode +// +// Created by Pedro Menezes on 07/02/25. +// + +import UIKit +import WebKit + +class GameViewController4: UIViewController { + let htmlBuilder = HtmlBuilder() + let webView = WKWebView() + var webViewContent: WebViewContent? + var coordinator = GameCoordinator2() + + lazy var goToLauchingsButton : UIButton = { + let launchButton = UIButton(type: .system) + launchButton.setTitle("Ver lançamentos", for: .normal) + launchButton.addTarget(self, action: #selector(openLastLaunchingsScreen), for: .touchUpInside) + launchButton.translatesAutoresizingMaskIntoConstraints = false + return launchButton + }() + + override func viewDidLoad() { + super.viewDidLoad() + setupNavigationBar() + setupGoToLaunchingsButton() + fillWebViewContent() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + webView.frame = view.frame + view.addSubview(webView) + } + + @objc + func openFAQ() { + coordinator.openFaqScreen() + } + + @objc func openLastLaunchingsScreen() { + coordinator.openLastLaunchingScreen() + } + + func setupNavigationBar() { + navigationItem.rightBarButtonItem = UIBarButtonItem( + image: UIImage(named: "message.square"), + style: .plain, + target: self, + action: #selector(openFAQ) + ) + } + + func setupGoToLaunchingsButton() { + view.addSubview(goToLauchingsButton) + NSLayoutConstraint.activate([ + goToLauchingsButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), + goToLauchingsButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20) + ]) + } + + func fillWebViewContent() { + guard let content = webViewContent else { return } + do { + let deviceUrls = try htmlBuilder.createWebViewUrls(content: content) + webView.loadFileURL(deviceUrls.htmlURL, allowingReadAccessTo: deviceUrls.pathURL.absoluteURL) + } catch { + Globals.showAlertMessage(title: "Oops...", message: "Tente novamente mais tarde", targetVC: self) + } + } +} + +struct GameCoordinator2 { + + weak var viewController: UIViewController? + + func openFaqScreen() { + let faqViewController = FAQViewController(type: .lastUpdates) + viewController?.navigationController?.pushViewController(faqViewController, animated: true) + } + + func openLastLaunchingScreen() { + let lastLaunchingsViewController = LastLaunchingsFactory.make() + viewController?.navigationController?.pushViewController(lastLaunchingsViewController, animated: true) + } +} + +struct HtmlBuilder2 { + let realmManager = RealmManager() + + func createWebViewUrls(content: WebViewContent) throws -> DeviceUrls { + let htmlAfterCustomization = try configureHtmlAppearence(content: content) + let data = try convertHtmlToData(html: htmlAfterCustomization) + let deviceUrls = getDeviceHtmlPathToSave() + try data.write(to: deviceUrls.htmlURL) + return deviceUrls + } + + func configureHtmlAppearence(content: WebViewContent) throws -> String { + guard let rHtmlConfig = realmManager.getObjects(HtmlConfig.self), + let htmlConfig = rHtmlConfig.last as? HtmlConfig, + let js = htmlConfig.jsContent, + let css = htmlConfig.cssContent else { + throw CommonsErros.invalidData + } + let body = RuntimeRoutine().runMustache(content: content) + let htmlFinal = Globals.buildHtml(html: body, css: css, js: js) + return htmlFinal + } + + func convertHtmlToData(html: String) throws -> Data { + guard let data = html.data(using: .utf8) else { + print("Erro ao converter string html") + throw CommonsErros.invalidData + } + return data + } + + func getDeviceHtmlPathToSave() -> DeviceUrls { + let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) + let pathURL = URL(fileURLWithPath: paths[0]).appendingPathComponent(RealmFilesNames.imagesFatherPath.rawValue) + let htmlURL = URL(fileURLWithPath: "content_html", relativeTo: pathURL).appendingPathExtension("html") + let deviceUrls = DeviceUrls(pathURL: pathURL, htmlURL: htmlURL) + return deviceUrls + } +} diff --git a/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift index 5795434..ddc68e2 100644 --- a/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Ceu/ResetPassword/CeuResetPasswordViewController.swift @@ -121,7 +121,7 @@ class CeuResetPasswordViewController: UIViewController { let parameters = try setupResetPasswordRequestParameters() makeResetPasswordRequest(parameters: parameters) - } catch CommonsErros.invalidEmail { + } catch CeuCommonsErros.invalidEmail { showAlert(message: "Verifique o e-mail informado.") } catch { showAlert(message: "Algo de errado aconteceu. Tente novamente mais tarde.") @@ -135,7 +135,7 @@ class CeuResetPasswordViewController: UIViewController { private func verifyInternet() throws { if !ConnectivityManager.shared.isConnected { Globals.showNoInternetCOnnection(controller: self) - throw CommonsErros.networkError + throw CeuCommonsErros.networkError } } @@ -146,7 +146,7 @@ class CeuResetPasswordViewController: UIViewController { emailTextfield.setErrorColor() textLabel.textColor = .red textLabel.text = "Verifique o e-mail informado" - throw CommonsErros.invalidEmail + throw CeuCommonsErros.invalidEmail } self.view.endEditing(true) @@ -238,7 +238,7 @@ extension CeuResetPasswordViewController { } -enum CommonsErros: Error { +enum CeuCommonsErros: Error { case invalidData case invalidEmail case networkError diff --git a/CleanCodeApp/Modules/Features/Rum/ResetPassword/RumResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Rum/ResetPassword/RumResetPasswordViewController.swift index 9713158..b370fd1 100644 --- a/CleanCodeApp/Modules/Features/Rum/ResetPassword/RumResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Rum/ResetPassword/RumResetPasswordViewController.swift @@ -27,7 +27,7 @@ class RumResetPasswordViewController: UIViewController { @IBAction func closeButtonAction(_ sender: Any) { dismiss(animated: true) } - + @IBAction func recoverPasswordButton(_ sender: Any) { if recoveryEmail { dismiss(animated: true) @@ -56,6 +56,7 @@ class RumResetPasswordViewController: UIViewController { self.emailLabel.text = self.emailTextfield.text?.trimmingCharacters(in: .whitespaces) self.recoverPasswordButton.titleLabel?.text = "REENVIAR E-MAIL" self.recoverPasswordButton.setTitle("Voltar", for: .normal) + } else { let alertController = UIAlertController(title: "Ops..", message: "Algo de errado aconteceu. Tente novamente mais tarde.", preferredStyle: .alert) let action = UIAlertAction(title: "OK", style: .default) diff --git a/CleanCodeApp/Modules/Utils/Globals/Globals.swift b/CleanCodeApp/Modules/Utils/Globals/Globals.swift index f5c97bc..af7c4b4 100644 --- a/CleanCodeApp/Modules/Utils/Globals/Globals.swift +++ b/CleanCodeApp/Modules/Utils/Globals/Globals.swift @@ -1,7 +1,13 @@ import UIKit struct Globals { + + @available(*, deprecated, message: "usar showAlertMessage") static func alertMessage(title: String, message: String, targetVC: UIViewController, action: (() -> Void)? = nil) { + showAlertMessage(title: title, message: message, targetVC: targetVC) + } + + static func showAlertMessage(title: String, message: String, targetVC: UIViewController, action: (() -> Void)? = nil) { let alert = UIAlertController(title: title, message: message, preferredStyle: .actionSheet) alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { _ in action?() From 1d2281a4911816b33de163f3ab4949bdbefcf8c9 Mon Sep 17 00:00:00 2001 From: elyndiaye Date: Wed, 5 Feb 2025 07:31:42 -0300 Subject: [PATCH 21/29] =?UTF-8?q?feat=20tratar=20fun=C3=A7=C3=B5es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CleanCodeApp/AppDelegate/SceneDelegate.swift | 8 ++ .../Model/SolContanctUsViewModel.swift | 44 ++++++ .../SolContactUsViewController.swift | 134 +++++++++++------- .../SolResetPasswordViewController.swift | 2 +- 4 files changed, 132 insertions(+), 56 deletions(-) create mode 100644 CleanCodeApp/Modules/Features/Sol/ContactsUs/Model/SolContanctUsViewModel.swift diff --git a/CleanCodeApp/AppDelegate/SceneDelegate.swift b/CleanCodeApp/AppDelegate/SceneDelegate.swift index 6583f57..eb158bf 100644 --- a/CleanCodeApp/AppDelegate/SceneDelegate.swift +++ b/CleanCodeApp/AppDelegate/SceneDelegate.swift @@ -45,7 +45,11 @@ func getRootViewController(forUser user: Users) -> UIViewController { userIdentifier = "Rio" case .rayanaPrata: userIdentifier = "Rum" +<<<<<<< HEAD case .elyAssuncao: +======= + case .elyAssumpcao: +>>>>>>> 5d781b2 (feat tratar funções) userIdentifier = "Sol" } let storyboard = UIStoryboard(name: "\(userIdentifier)User", bundle: nil) @@ -63,5 +67,9 @@ enum Users { case giuliaKetlin case thaisaAmanda case rayanaPrata +<<<<<<< HEAD case elyAssuncao +======= + case elyAssumpcao +>>>>>>> 5d781b2 (feat tratar funções) } diff --git a/CleanCodeApp/Modules/Features/Sol/ContactsUs/Model/SolContanctUsViewModel.swift b/CleanCodeApp/Modules/Features/Sol/ContactsUs/Model/SolContanctUsViewModel.swift new file mode 100644 index 0000000..8bc0911 --- /dev/null +++ b/CleanCodeApp/Modules/Features/Sol/ContactsUs/Model/SolContanctUsViewModel.swift @@ -0,0 +1,44 @@ +// +// SolContanctUsViewModel.swift +// CleanCode +// +// Created by Ely Assumpcao Ndiaye on 03/02/25. +// + +import Foundation +// TODO +protocol SolContactUsProtocol: AnyObject { + func showLoadingView2() + func removeLoadingView2() + func showMessageModel(result: ContactUsModel) + func showAnyErrorOcurres() + func errorMessage(message: String) +} + +class SolContactUsViewModel { + + weak var viewController: SolContactUsProtocol? + + func fetchData() { + self.viewController?.showLoadingView2() + let url = Endpoints.contactUs + AF.shared.request(url, method: .get, parameters: nil, headers: nil) { [weak self] result in + self?.viewController?.removeLoadingView2() + switch result { + case .success(let data): + let decoder = JSONDecoder() + if let returned = try? decoder.decode(ContactUsModel.self, from: data) { + self?.viewController?.showMessageModel(result: returned) + } else { + self?.viewController?.showAnyErrorOcurres() + + } + case .failure(let error): + print("error api: \(error.localizedDescription)") + self?.viewController?.errorMessage(message: error.localizedDescription) + } + } + } + + +} diff --git a/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift b/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift index b03b4e3..77f20ea 100644 --- a/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift @@ -11,37 +11,49 @@ class SolContactUsViewController: LoadingInheritageController { var model: ContactUsModel? let textView = UITextView() - override func viewDidLoad() { - super.viewDidLoad() - - view.backgroundColor = .systemGray6 - let titleLabel = UILabel() - titleLabel.textColor = .black - titleLabel.font = UIFont.systemFont(ofSize: 24, weight: .semibold) - titleLabel.text = "Escolha o canal para contato" - - // Criar botões + lazy var titleLabel: UILabel = { + let label = UILabel() + label.textColor = .black + label.font = UIFont.systemFont(ofSize: 24, weight: .semibold) + label.text = "Escolha o canal para contato" + return label + }() + + // Criar botões + lazy var phoneButton: UIButton = { let phoneButton = UIButton() phoneButton.backgroundColor = .systemGray4 phoneButton.layer.cornerRadius = 10 phoneButton.addTarget(self, action: #selector(phoneClick), for: .touchUpInside) - let emailButton = UIButton() - emailButton.backgroundColor = .systemGray4 - emailButton.layer.cornerRadius = 10 - emailButton.addTarget(self, action: #selector(emailClick), for: .touchUpInside) - + return phoneButton + }() + lazy var emailButton: UIButton = { + let emailButton = UIButton() + emailButton.backgroundColor = .systemGray4 + emailButton.layer.cornerRadius = 10 + emailButton.addTarget(self, action: #selector(emailClick), for: .touchUpInside) + return emailButton + }() + + lazy var chatButton: UIButton = { let chatButton = UIButton() chatButton.backgroundColor = .systemGray4 chatButton.layer.cornerRadius = 10 chatButton.addTarget(self, action: #selector(chatClicked), for: .touchUpInside) - + return chatButton + }() + + lazy var messageLabel: UILabel = { let messageLabel = UILabel() messageLabel.textColor = .black messageLabel.font = UIFont.systemFont(ofSize: 16, weight: .semibold) messageLabel.text = "Ou envie uma mensagem" messageLabel.numberOfLines = 2 messageLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) - + return messageLabel + }() + + lazy var sendMessageButton: UIButton = { let sendMessageButton = UIButton() sendMessageButton.backgroundColor = .blue sendMessageButton.setTitle(" Enviar ", for: .normal) @@ -49,8 +61,10 @@ class SolContactUsViewController: LoadingInheritageController { sendMessageButton.layer.cornerRadius = 10 sendMessageButton.setContentHuggingPriority(.required, for: .horizontal) sendMessageButton.addTarget(self, action: #selector(messageSend), for: .touchUpInside) - - textView.text = "Escreva sua mensagem aqui" + return sendMessageButton + }() + + lazy var closeButton: UIButton = { let closeButton = UIButton() closeButton.setTitle("Voltar", for: .normal) closeButton.setTitleColor(.blue, for: .normal) @@ -59,30 +73,42 @@ class SolContactUsViewController: LoadingInheritageController { closeButton.layer.borderColor = UIColor.blue.cgColor closeButton.layer.cornerRadius = 10 closeButton.addTarget(self, action: #selector(close), for: .touchUpInside) - - - let symbolConfiguration = UIImage.SymbolConfiguration(pointSize: 36) + return closeButton + }() + + let symbolConfiguration = UIImage.SymbolConfiguration(pointSize: 36) + + private let viewModel: SolContactUsViewModel + + init (viewModel: SolContactUsViewModel){ + self.viewModel = viewModel + super.init(nibName: "SolContactUsViewController", bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .systemGray6 + textView.text = "Escreva sua mensagem aqui" + setButtonImages() + setupConstraints() + pegarDados() + } + + func setButtonImages() { phoneButton.setImage(UIImage.init(systemName: "phone")?.withConfiguration(symbolConfiguration), for: .normal) emailButton.setImage(UIImage.init(systemName: "envelope")?.withConfiguration(symbolConfiguration), for: .normal) chatButton.setImage(UIImage.init(systemName: "message")?.withConfiguration(symbolConfiguration), for: .normal) - - titleLabel.translatesAutoresizingMaskIntoConstraints = false - phoneButton.translatesAutoresizingMaskIntoConstraints = false - emailButton.translatesAutoresizingMaskIntoConstraints = false - chatButton.translatesAutoresizingMaskIntoConstraints = false - messageLabel.translatesAutoresizingMaskIntoConstraints = false - textView.translatesAutoresizingMaskIntoConstraints = false - sendMessageButton.translatesAutoresizingMaskIntoConstraints = false - closeButton.translatesAutoresizingMaskIntoConstraints = false - - view.addSubview(titleLabel) - view.addSubview(phoneButton) - view.addSubview(emailButton) - view.addSubview(chatButton) - view.addSubview(messageLabel) - view.addSubview(textView) - view.addSubview(sendMessageButton) - view.addSubview(closeButton) + } + + func setupConstraints() { + [titleLabel, phoneButton, emailButton, chatButton, messageLabel, textView, sendMessageButton, closeButton].forEach { uiView in + uiView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(uiView) + } NSLayoutConstraint.activate([ @@ -127,8 +153,6 @@ class SolContactUsViewController: LoadingInheritageController { closeButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), closeButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), ]) - - pegarDados() } @objc @@ -169,27 +193,29 @@ class SolContactUsViewController: LoadingInheritageController { func pegarDados() { showLoadingView() let url = Endpoints.contactUs - AF.shared.request(url, method: .get, parameters: nil, headers: nil) { result in - self.removeLoadingView() + AF.shared.request(url, method: .get, parameters: nil, headers: nil) { [weak self] result in + self?.removeLoadingView() switch result { case .success(let data): let decoder = JSONDecoder() if let returned = try? decoder.decode(ContactUsModel.self, from: data) { - self.model = returned + self?.model = returned } else { - Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) { - self.dismiss(animated: true) - } + self?.showAlertMessage(title: "Ops..", message: "Ocorreu algum erro", dissmiss: true) } case .failure(let error): print("error api: \(error.localizedDescription)") - Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) { - self.dismiss(animated: true) - } + self?.showAlertMessage(title: "Ops..", message: "Ocorreu algum erro", dissmiss: true) } } } + func showAlertMessage(title: String, message: String, dissmiss: Bool) { + Globals.alertMessage(title: title, message: message, targetVC: self) { + self.dismiss(animated: dissmiss) + } + } + @objc func messageSend() { view.endEditing(true) @@ -201,13 +227,11 @@ class SolContactUsViewController: LoadingInheritageController { ] showLoadingView() let url = Endpoints.sendMessage - AF.shared.request(url, method: .post, parameters: parameters, headers: nil) { result in + AF.shared.request(url, method: .post, parameters: parameters, headers: nil) { result in self.removeLoadingView() switch result { case .success: - Globals.alertMessage(title: "Sucesso..", message: "Sua mensagem foi enviada", targetVC: self) { - self.dismiss(animated: true) - } + self.showAlertMessage(title: "Sucesso..", message: "Sua mensagem foi enviada", dissmiss: true) case .failure: Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) } diff --git a/CleanCodeApp/Modules/Features/Sol/ResetPassword/SolResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Sol/ResetPassword/SolResetPasswordViewController.swift index a0ec4c6..505433f 100644 --- a/CleanCodeApp/Modules/Features/Sol/ResetPassword/SolResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Sol/ResetPassword/SolResetPasswordViewController.swift @@ -71,7 +71,7 @@ class SolResetPasswordViewController: UIViewController { } @IBAction func helpButton(_ sender: Any) { - let vc = SolContactUsViewController() + let vc = SolContactUsViewController(viewModel: SolContactUsViewModel()) vc.modalPresentationStyle = .fullScreen vc.modalTransitionStyle = .coverVertical self.present(vc, animated: true, completion: nil) From 9abd3eb4bd40ef460325d35b73b7f34684db2521 Mon Sep 17 00:00:00 2001 From: elyndiaye Date: Thu, 6 Feb 2025 07:10:49 -0300 Subject: [PATCH 22/29] code review referente a aula 01 --- .../SolContactUsViewController.swift | 78 ++++++++++++------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift b/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift index 77f20ea..71f0327 100644 --- a/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift @@ -24,14 +24,15 @@ class SolContactUsViewController: LoadingInheritageController { let phoneButton = UIButton() phoneButton.backgroundColor = .systemGray4 phoneButton.layer.cornerRadius = 10 - phoneButton.addTarget(self, action: #selector(phoneClick), for: .touchUpInside) + phoneButton.addTarget(self, action: #selector(didTapPhone), for: .touchUpInside) return phoneButton }() + lazy var emailButton: UIButton = { - let emailButton = UIButton() - emailButton.backgroundColor = .systemGray4 - emailButton.layer.cornerRadius = 10 - emailButton.addTarget(self, action: #selector(emailClick), for: .touchUpInside) + let emailButton = UIButton() + emailButton.backgroundColor = .systemGray4 + emailButton.layer.cornerRadius = 10 + emailButton.addTarget(self, action: #selector(didTapEmail), for: .touchUpInside) return emailButton }() @@ -39,7 +40,7 @@ class SolContactUsViewController: LoadingInheritageController { let chatButton = UIButton() chatButton.backgroundColor = .systemGray4 chatButton.layer.cornerRadius = 10 - chatButton.addTarget(self, action: #selector(chatClicked), for: .touchUpInside) + chatButton.addTarget(self, action: #selector(didTapChat), for: .touchUpInside) return chatButton }() @@ -95,7 +96,7 @@ class SolContactUsViewController: LoadingInheritageController { textView.text = "Escreva sua mensagem aqui" setButtonImages() setupConstraints() - pegarDados() + fetchData() } func setButtonImages() { @@ -111,7 +112,7 @@ class SolContactUsViewController: LoadingInheritageController { } NSLayoutConstraint.activate([ - + titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 30), titleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), titleLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), @@ -135,7 +136,7 @@ class SolContactUsViewController: LoadingInheritageController { messageLabel.topAnchor.constraint(equalTo: phoneButton.bottomAnchor, constant: 30), messageLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), messageLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), -// stackView.heightAnchor.constraint(equalToConstant: 30), + // stackView.heightAnchor.constraint(equalToConstant: 30), textView.topAnchor.constraint(equalTo: messageLabel.bottomAnchor, constant: 20), textView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), @@ -156,7 +157,7 @@ class SolContactUsViewController: LoadingInheritageController { } @objc - func phoneClick() { + func didTapPhone() { if let tel = model?.phone, let url = URL(string: "tel://\(tel)") { UIApplication.shared.open(url, options: [:], completionHandler: nil) @@ -164,7 +165,7 @@ class SolContactUsViewController: LoadingInheritageController { } @objc - func emailClick() { + func didTapEmail() { if let mail = model?.mail, let url = URL(string: "mailto:\(mail)") { UIApplication.shared.open(url, options: [:], completionHandler: nil) @@ -172,7 +173,7 @@ class SolContactUsViewController: LoadingInheritageController { } @objc - func chatClicked() { + func didTapChat() { if let phoneNumber = model?.phone, let whatsappURL = URL(string: "whatsapp://send?phone=\(phoneNumber)&text=Oi)") { if UIApplication.shared.canOpenURL(whatsappURL) { UIApplication.shared.open(whatsappURL, options: [:], completionHandler: nil) @@ -190,26 +191,32 @@ class SolContactUsViewController: LoadingInheritageController { } - func pegarDados() { + func fetchData() { showLoadingView() let url = Endpoints.contactUs AF.shared.request(url, method: .get, parameters: nil, headers: nil) { [weak self] result in self?.removeLoadingView() + guard let self = self else {return} switch result { case .success(let data): - let decoder = JSONDecoder() - if let returned = try? decoder.decode(ContactUsModel.self, from: data) { - self?.model = returned - } else { - self?.showAlertMessage(title: "Ops..", message: "Ocorreu algum erro", dissmiss: true) - } + self.decodeData(data: data) case .failure(let error): print("error api: \(error.localizedDescription)") - self?.showAlertMessage(title: "Ops..", message: "Ocorreu algum erro", dissmiss: true) + self.showAlertMessage(title: "Ops..", message: "Ocorreu algum erro", dissmiss: true) } } } + private func decodeData(data: Data) { + do { + let decoder = JSONDecoder() + let returned = try decoder.decode(ContactUsModel.self, from: data) + self.model = returned + } catch { + self.showAlertMessage(title: "Ops..", message: "Ocorreu algum erro", dissmiss: true) + } + } + func showAlertMessage(title: String, message: String, dissmiss: Bool) { Globals.alertMessage(title: title, message: message, targetVC: self) { self.dismiss(animated: dissmiss) @@ -219,22 +226,33 @@ class SolContactUsViewController: LoadingInheritageController { @objc func messageSend() { view.endEditing(true) + let parameters = sendParameters() + showLoadingView() + requestSendMessage(parameters: parameters) + } + + func sendParameters() -> [String: String] { let email = model?.mail ?? "" if let message = textView.text, textView.text.count > 0 { let parameters: [String: String] = [ "email": email, "mensagem": message ] - showLoadingView() - let url = Endpoints.sendMessage - AF.shared.request(url, method: .post, parameters: parameters, headers: nil) { result in - self.removeLoadingView() - switch result { - case .success: - self.showAlertMessage(title: "Sucesso..", message: "Sua mensagem foi enviada", dissmiss: true) - case .failure: - Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) - } + return parameters + } + return [:] + } + + func requestSendMessage(parameters:[ String: String]) { + let url = Endpoints.sendMessage + AF.shared.request(url, method: .post, parameters: parameters, headers: nil) { [weak self] result in + guard let self = self else {return} + self.removeLoadingView() + switch result { + case .success: + self.showAlertMessage(title: "Sucesso..", message: "Sua mensagem foi enviada", dissmiss: true) + case .failure: + Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) } } } From 41bd2d43a43184d127c9f471f78a331ec210af5d Mon Sep 17 00:00:00 2001 From: elyndiaye Date: Fri, 7 Feb 2025 08:28:13 -0300 Subject: [PATCH 23/29] Aplica conceitos da aula 2 --- CleanCodeApp/AppDelegate/SceneDelegate.swift | 2 +- .../Model/SolContanctUsViewModel.swift | 44 ----------- .../SolContactUsViewController.swift | 73 ++++++++----------- .../ViewModel/SolContanctUsViewModel.swift | 62 ++++++++++++++++ 4 files changed, 94 insertions(+), 87 deletions(-) delete mode 100644 CleanCodeApp/Modules/Features/Sol/ContactsUs/Model/SolContanctUsViewModel.swift create mode 100644 CleanCodeApp/Modules/Features/Sol/ContactsUs/ViewModel/SolContanctUsViewModel.swift diff --git a/CleanCodeApp/AppDelegate/SceneDelegate.swift b/CleanCodeApp/AppDelegate/SceneDelegate.swift index eb158bf..4d5d619 100644 --- a/CleanCodeApp/AppDelegate/SceneDelegate.swift +++ b/CleanCodeApp/AppDelegate/SceneDelegate.swift @@ -17,7 +17,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { guard let windowScene = (scene as? UIWindowScene) else { return } self.window = UIWindow(frame: UIScreen.main.bounds) - let rootViewController = getRootViewController(forUser: .luisOliveira) + let rootViewController = getRootViewController(forUser: .elyAssumpcao) self.window?.rootViewController = UINavigationController(rootViewController: rootViewController) self.window?.windowScene = windowScene self.window?.makeKeyAndVisible() diff --git a/CleanCodeApp/Modules/Features/Sol/ContactsUs/Model/SolContanctUsViewModel.swift b/CleanCodeApp/Modules/Features/Sol/ContactsUs/Model/SolContanctUsViewModel.swift deleted file mode 100644 index 8bc0911..0000000 --- a/CleanCodeApp/Modules/Features/Sol/ContactsUs/Model/SolContanctUsViewModel.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// SolContanctUsViewModel.swift -// CleanCode -// -// Created by Ely Assumpcao Ndiaye on 03/02/25. -// - -import Foundation -// TODO -protocol SolContactUsProtocol: AnyObject { - func showLoadingView2() - func removeLoadingView2() - func showMessageModel(result: ContactUsModel) - func showAnyErrorOcurres() - func errorMessage(message: String) -} - -class SolContactUsViewModel { - - weak var viewController: SolContactUsProtocol? - - func fetchData() { - self.viewController?.showLoadingView2() - let url = Endpoints.contactUs - AF.shared.request(url, method: .get, parameters: nil, headers: nil) { [weak self] result in - self?.viewController?.removeLoadingView2() - switch result { - case .success(let data): - let decoder = JSONDecoder() - if let returned = try? decoder.decode(ContactUsModel.self, from: data) { - self?.viewController?.showMessageModel(result: returned) - } else { - self?.viewController?.showAnyErrorOcurres() - - } - case .failure(let error): - print("error api: \(error.localizedDescription)") - self?.viewController?.errorMessage(message: error.localizedDescription) - } - } - } - - -} diff --git a/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift b/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift index 71f0327..0ea8d9e 100644 --- a/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift @@ -7,7 +7,15 @@ import UIKit -class SolContactUsViewController: LoadingInheritageController { +protocol SolContactUsProtocol: AnyObject { + func callLoadingView() + func callRemoveLoadingView() + func showMessageReturnModel(result: ContactUsModel) + func displayAlertMessage(title: String, message: String, dissmiss: Bool) + func displayGlobalAlertMessage() +} + +class SolContactUsViewController: LoadingInheritageController, SolContactUsProtocol { var model: ContactUsModel? let textView = UITextView() @@ -84,6 +92,7 @@ class SolContactUsViewController: LoadingInheritageController { init (viewModel: SolContactUsViewModel){ self.viewModel = viewModel super.init(nibName: "SolContactUsViewController", bundle: nil) + self.viewModel.viewController = self } required init?(coder: NSCoder) { @@ -96,7 +105,7 @@ class SolContactUsViewController: LoadingInheritageController { textView.text = "Escreva sua mensagem aqui" setButtonImages() setupConstraints() - fetchData() + viewModel.fetchData() } func setButtonImages() { @@ -190,33 +199,6 @@ class SolContactUsViewController: LoadingInheritageController { dismiss(animated: true) } - - func fetchData() { - showLoadingView() - let url = Endpoints.contactUs - AF.shared.request(url, method: .get, parameters: nil, headers: nil) { [weak self] result in - self?.removeLoadingView() - guard let self = self else {return} - switch result { - case .success(let data): - self.decodeData(data: data) - case .failure(let error): - print("error api: \(error.localizedDescription)") - self.showAlertMessage(title: "Ops..", message: "Ocorreu algum erro", dissmiss: true) - } - } - } - - private func decodeData(data: Data) { - do { - let decoder = JSONDecoder() - let returned = try decoder.decode(ContactUsModel.self, from: data) - self.model = returned - } catch { - self.showAlertMessage(title: "Ops..", message: "Ocorreu algum erro", dissmiss: true) - } - } - func showAlertMessage(title: String, message: String, dissmiss: Bool) { Globals.alertMessage(title: title, message: message, targetVC: self) { self.dismiss(animated: dissmiss) @@ -228,7 +210,7 @@ class SolContactUsViewController: LoadingInheritageController { view.endEditing(true) let parameters = sendParameters() showLoadingView() - requestSendMessage(parameters: parameters) + viewModel.requestSendMessage(parameters: parameters) } func sendParameters() -> [String: String] { @@ -243,17 +225,24 @@ class SolContactUsViewController: LoadingInheritageController { return [:] } - func requestSendMessage(parameters:[ String: String]) { - let url = Endpoints.sendMessage - AF.shared.request(url, method: .post, parameters: parameters, headers: nil) { [weak self] result in - guard let self = self else {return} - self.removeLoadingView() - switch result { - case .success: - self.showAlertMessage(title: "Sucesso..", message: "Sua mensagem foi enviada", dissmiss: true) - case .failure: - Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) - } - } + func callLoadingView() { + showLoading() + } + + func callRemoveLoadingView() { + removeLoadingView() + } + + func showMessageReturnModel(result: ContactUsModel) { + self.model = result + } + + func displayAlertMessage(title: String, message: String, dissmiss: Bool) { + self.showAlertMessage(title: title, message: message , dissmiss: dissmiss) + } + + func displayGlobalAlertMessage() { + Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) } } + diff --git a/CleanCodeApp/Modules/Features/Sol/ContactsUs/ViewModel/SolContanctUsViewModel.swift b/CleanCodeApp/Modules/Features/Sol/ContactsUs/ViewModel/SolContanctUsViewModel.swift new file mode 100644 index 0000000..1a71d07 --- /dev/null +++ b/CleanCodeApp/Modules/Features/Sol/ContactsUs/ViewModel/SolContanctUsViewModel.swift @@ -0,0 +1,62 @@ +// +// SolContanctUsViewModel.swift +// CleanCode +// +// Created by Ely Assumpcao Ndiaye on 03/02/25. +// + +import Foundation +// TODO + + +protocol SolContactUsViewModelProtocol: AnyObject { + func fetchData() + func requestSendMessage(parameters:[ String: String]) +} + +class SolContactUsViewModel: SolContactUsViewModelProtocol { + + weak var viewController: SolContactUsProtocol? + + func fetchData() { + self.viewController?.callLoadingView() + let url = Endpoints.contactUs + AF.shared.request(url, method: .get, parameters: nil, headers: nil) { [weak self] result in + guard let self = self else {return} + self.viewController?.callRemoveLoadingView() + switch result { + case .success(let data): + self.decodeData(data: data) + case .failure(let error): + print("error api: \(error.localizedDescription)") + self.viewController?.displayAlertMessage(title: "Ops..", message: "Ocorreu algum erro", dissmiss: true) + } + } + } + + private func decodeData(data: Data) { + do { + let decoder = JSONDecoder() + let returned = try decoder.decode(ContactUsModel.self, from: data) + viewController?.showMessageReturnModel(result: returned) + } catch { + self.viewController?.displayAlertMessage(title: "Ops..", message: "Ocorreu algum erro", dissmiss: true) + } + } + + func requestSendMessage(parameters:[ String: String]) { + let url = Endpoints.sendMessage + AF.shared.request(url, method: .post, parameters: parameters, headers: nil) { [weak self] result in + guard let self = self else {return} + self.viewController?.callRemoveLoadingView() + switch result { + case .success: + self.viewController?.displayAlertMessage(title: "Sucesso..", message: "Sua mensagem foi enviada", dissmiss: true) + case .failure: + self.viewController?.displayGlobalAlertMessage() + } + } + } + + +} From 408899f3fbf5fa66ba933eb29536556ea8beeae8 Mon Sep 17 00:00:00 2001 From: elyndiaye Date: Sat, 8 Feb 2025 10:35:31 -0300 Subject: [PATCH 24/29] fix: code review aplica throws na funcao --- .../SolContactUsViewController.swift | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift b/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift index 0ea8d9e..e6d5312 100644 --- a/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift @@ -207,22 +207,28 @@ class SolContactUsViewController: LoadingInheritageController, SolContactUsProto @objc func messageSend() { - view.endEditing(true) - let parameters = sendParameters() - showLoadingView() - viewModel.requestSendMessage(parameters: parameters) + do{ + view.endEditing(true) + let parameters = try sendParameters() + showLoadingView() + viewModel.requestSendMessage(parameters: parameters) + } + catch { + Globals.alertMessage(title: "Ops..", message: "Ocorreu algum erro", targetVC: self) + } } - func sendParameters() -> [String: String] { + func sendParameters() throws -> [String: String] { let email = model?.mail ?? "" - if let message = textView.text, textView.text.count > 0 { - let parameters: [String: String] = [ - "email": email, - "mensagem": message - ] - return parameters + guard let message = textView.text, textView.text.count > 0 else { + throw CommonsError.invalidMessage } - return [:] + + let parameters: [String: String] = [ + "email": email, + "mensagem": message + ] + return parameters } func callLoadingView() { @@ -246,3 +252,6 @@ class SolContactUsViewController: LoadingInheritageController, SolContactUsProto } } +enum CommonsError: Error { + case invalidMessage +} From 4e367a1a911fcab7b8fc822acee2b1dad5128ac5 Mon Sep 17 00:00:00 2001 From: elyndiaye Date: Sat, 8 Feb 2025 12:13:18 -0300 Subject: [PATCH 25/29] code review: srp para funcionalidades externas --- .../ContactsUs/ExternalActionsHandler.swift | 35 +++++++++++++++++ .../SolContactUsViewController.swift | 39 ++++++++++++------- 2 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 CleanCodeApp/Modules/Features/Sol/ContactsUs/ExternalActionsHandler.swift diff --git a/CleanCodeApp/Modules/Features/Sol/ContactsUs/ExternalActionsHandler.swift b/CleanCodeApp/Modules/Features/Sol/ContactsUs/ExternalActionsHandler.swift new file mode 100644 index 0000000..1ff85e1 --- /dev/null +++ b/CleanCodeApp/Modules/Features/Sol/ContactsUs/ExternalActionsHandler.swift @@ -0,0 +1,35 @@ +// +// UrlLinks.swift +// CleanCode +// +// Created by Ely Assumpcao Ndiaye on 08/02/25. +// + +import Foundation + + +enum ExternalActionsHandler { + case phone(String) + case email(String) + case whatsapp(String) + + var url: URL? { + switch self { + case .phone(let number): + return URL(string: "tel://\(number)") + case .email(let email): + return URL(string: "mailto://\(email)") + case .whatsapp(let phoneNumber): + return URL(string: "whatsapp://send?phone=\(phoneNumber)&text=Oi") + } + } + + var fallbackURL: URL? { + switch self { + case .whatsapp: + return URL(string: "https://apps.apple.com/app/whatsapp-messenger/id310633997") + default: + return nil + } + } +} diff --git a/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift b/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift index e6d5312..43e0975 100644 --- a/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift @@ -167,33 +167,44 @@ class SolContactUsViewController: LoadingInheritageController, SolContactUsProto @objc func didTapPhone() { - if let tel = model?.phone, - let url = URL(string: "tel://\(tel)") { - UIApplication.shared.open(url, options: [:], completionHandler: nil) + if let phone = model?.phone { + openAppLinks(appLink: .phone(phone)) } } @objc func didTapEmail() { - if let mail = model?.mail, - let url = URL(string: "mailto:\(mail)") { - UIApplication.shared.open(url, options: [:], completionHandler: nil) + if let mail = model?.mail{ + openAppLinks(appLink: .email(mail)) } } @objc func didTapChat() { - if let phoneNumber = model?.phone, let whatsappURL = URL(string: "whatsapp://send?phone=\(phoneNumber)&text=Oi)") { - if UIApplication.shared.canOpenURL(whatsappURL) { - UIApplication.shared.open(whatsappURL, options: [:], completionHandler: nil) - } else { - if let appStoreURL = URL(string: "https://apps.apple.com/app/whatsapp-messenger/id310633997") { - UIApplication.shared.open(appStoreURL, options: [:], completionHandler: nil) - } - } + if let phoneNumber = model?.phone { + openAppLinks(appLink: .whatsapp(phoneNumber)) } } + private func openAppLinks(appLink: ExternalActionsHandler) { + guard let url = appLink.url else { return } + + if UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open( + url, + options: [:], + completionHandler: nil + ) + } else if let fallback = appLink.fallbackURL { + UIApplication.shared.open( + fallback, + options: [:], + completionHandler: nil + ) + } + } + + @objc func close() { dismiss(animated: true) From 6da53706d98fcc62dcb4c92bba8a1c3d17f9ef5a Mon Sep 17 00:00:00 2001 From: ppedroam Date: Mon, 10 Feb 2025 19:55:23 -0300 Subject: [PATCH 26/29] 4-oop --- .../GameViewController.swift} | 0 .../2-classes/GameViewController.swift | 4 + .../LiveCode/3-nomes/GameCoordinator.swift | 23 ++++++ ...codigo3.swift => GameViewController.swift} | 55 ------------- .../LiveCode/3-nomes/HtmlBuilder.swift | 48 ++++++++++++ .../LiveCode/4-OOP/GameCoordinator.swift | 23 ++++++ .../LiveCode/4-OOP/GameViewController.swift | 77 +++++++++++++++++++ CleanCodeApp/LiveCode/4-OOP/HtmlBuilder.swift | 50 ++++++++++++ .../SomResetPasswordViewController.swift | 1 + .../Modules/Utils/Globals/Globals.swift | 9 +++ 10 files changed, 235 insertions(+), 55 deletions(-) rename CleanCodeApp/LiveCode/{1LiveCodeFunctions.swift => 1-funcoes/GameViewController.swift} (100%) create mode 100644 CleanCodeApp/LiveCode/3-nomes/GameCoordinator.swift rename CleanCodeApp/LiveCode/3-nomes/{codigo3.swift => GameViewController.swift} (50%) create mode 100644 CleanCodeApp/LiveCode/3-nomes/HtmlBuilder.swift create mode 100644 CleanCodeApp/LiveCode/4-OOP/GameCoordinator.swift create mode 100644 CleanCodeApp/LiveCode/4-OOP/GameViewController.swift create mode 100644 CleanCodeApp/LiveCode/4-OOP/HtmlBuilder.swift diff --git a/CleanCodeApp/LiveCode/1LiveCodeFunctions.swift b/CleanCodeApp/LiveCode/1-funcoes/GameViewController.swift similarity index 100% rename from CleanCodeApp/LiveCode/1LiveCodeFunctions.swift rename to CleanCodeApp/LiveCode/1-funcoes/GameViewController.swift diff --git a/CleanCodeApp/LiveCode/2-classes/GameViewController.swift b/CleanCodeApp/LiveCode/2-classes/GameViewController.swift index dbb30fd..fd27905 100644 --- a/CleanCodeApp/LiveCode/2-classes/GameViewController.swift +++ b/CleanCodeApp/LiveCode/2-classes/GameViewController.swift @@ -44,6 +44,10 @@ class GameViewController3: UIViewController { view.addSubview(webView) } + func teste() { + + } + @objc func openFAQ() { coordinator.openFaq() diff --git a/CleanCodeApp/LiveCode/3-nomes/GameCoordinator.swift b/CleanCodeApp/LiveCode/3-nomes/GameCoordinator.swift new file mode 100644 index 0000000..47d1c31 --- /dev/null +++ b/CleanCodeApp/LiveCode/3-nomes/GameCoordinator.swift @@ -0,0 +1,23 @@ +// +// GameCoordinator.swift +// CleanCode +// +// Created by Pedro Menezes on 10/02/25. +// + +import UIKit + +struct GameCoordinator2 { + + weak var viewController: UIViewController? + + func openFaqScreen() { + let faqViewController = FAQViewController(type: .lastUpdates) + viewController?.navigationController?.pushViewController(faqViewController, animated: true) + } + + func openLastLaunchingScreen() { + let lastLaunchingsViewController = LastLaunchingsFactory.make() + viewController?.navigationController?.pushViewController(lastLaunchingsViewController, animated: true) + } +} diff --git a/CleanCodeApp/LiveCode/3-nomes/codigo3.swift b/CleanCodeApp/LiveCode/3-nomes/GameViewController.swift similarity index 50% rename from CleanCodeApp/LiveCode/3-nomes/codigo3.swift rename to CleanCodeApp/LiveCode/3-nomes/GameViewController.swift index 151c851..0c2236d 100644 --- a/CleanCodeApp/LiveCode/3-nomes/codigo3.swift +++ b/CleanCodeApp/LiveCode/3-nomes/GameViewController.swift @@ -71,58 +71,3 @@ class GameViewController4: UIViewController { } } } - -struct GameCoordinator2 { - - weak var viewController: UIViewController? - - func openFaqScreen() { - let faqViewController = FAQViewController(type: .lastUpdates) - viewController?.navigationController?.pushViewController(faqViewController, animated: true) - } - - func openLastLaunchingScreen() { - let lastLaunchingsViewController = LastLaunchingsFactory.make() - viewController?.navigationController?.pushViewController(lastLaunchingsViewController, animated: true) - } -} - -struct HtmlBuilder2 { - let realmManager = RealmManager() - - func createWebViewUrls(content: WebViewContent) throws -> DeviceUrls { - let htmlAfterCustomization = try configureHtmlAppearence(content: content) - let data = try convertHtmlToData(html: htmlAfterCustomization) - let deviceUrls = getDeviceHtmlPathToSave() - try data.write(to: deviceUrls.htmlURL) - return deviceUrls - } - - func configureHtmlAppearence(content: WebViewContent) throws -> String { - guard let rHtmlConfig = realmManager.getObjects(HtmlConfig.self), - let htmlConfig = rHtmlConfig.last as? HtmlConfig, - let js = htmlConfig.jsContent, - let css = htmlConfig.cssContent else { - throw CommonsErros.invalidData - } - let body = RuntimeRoutine().runMustache(content: content) - let htmlFinal = Globals.buildHtml(html: body, css: css, js: js) - return htmlFinal - } - - func convertHtmlToData(html: String) throws -> Data { - guard let data = html.data(using: .utf8) else { - print("Erro ao converter string html") - throw CommonsErros.invalidData - } - return data - } - - func getDeviceHtmlPathToSave() -> DeviceUrls { - let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) - let pathURL = URL(fileURLWithPath: paths[0]).appendingPathComponent(RealmFilesNames.imagesFatherPath.rawValue) - let htmlURL = URL(fileURLWithPath: "content_html", relativeTo: pathURL).appendingPathExtension("html") - let deviceUrls = DeviceUrls(pathURL: pathURL, htmlURL: htmlURL) - return deviceUrls - } -} diff --git a/CleanCodeApp/LiveCode/3-nomes/HtmlBuilder.swift b/CleanCodeApp/LiveCode/3-nomes/HtmlBuilder.swift new file mode 100644 index 0000000..76d2d9a --- /dev/null +++ b/CleanCodeApp/LiveCode/3-nomes/HtmlBuilder.swift @@ -0,0 +1,48 @@ +// +// HtmlBuilder.swift +// CleanCode +// +// Created by Pedro Menezes on 10/02/25. +// + +import Foundation + +struct HtmlBuilder2 { + let realmManager = RealmManager() + + func createWebViewUrls(content: WebViewContent) throws -> DeviceUrls { + let htmlAfterCustomization = try configureHtmlAppearence(content: content) + let data = try convertHtmlToData(html: htmlAfterCustomization) + let deviceUrls = getDeviceHtmlPathToSave() + try data.write(to: deviceUrls.htmlURL) + return deviceUrls + } + + func configureHtmlAppearence(content: WebViewContent) throws -> String { + guard let rHtmlConfig = realmManager.getObjects(HtmlConfig.self), + let htmlConfig = rHtmlConfig.last as? HtmlConfig, + let js = htmlConfig.jsContent, + let css = htmlConfig.cssContent else { + throw CommonsErros.invalidData + } + let body = RuntimeRoutine().runMustache(content: content) + let htmlFinal = Globals.buildHtml(html: body, css: css, js: js) + return htmlFinal + } + + func convertHtmlToData(html: String) throws -> Data { + guard let data = html.data(using: .utf8) else { + print("Erro ao converter string html") + throw CommonsErros.invalidData + } + return data + } + + func getDeviceHtmlPathToSave() -> DeviceUrls { + let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) + let pathURL = URL(fileURLWithPath: paths[0]).appendingPathComponent(RealmFilesNames.imagesFatherPath.rawValue) + let htmlURL = URL(fileURLWithPath: "content_html", relativeTo: pathURL).appendingPathExtension("html") + let deviceUrls = DeviceUrls(pathURL: pathURL, htmlURL: htmlURL) + return deviceUrls + } +} diff --git a/CleanCodeApp/LiveCode/4-OOP/GameCoordinator.swift b/CleanCodeApp/LiveCode/4-OOP/GameCoordinator.swift new file mode 100644 index 0000000..4c52260 --- /dev/null +++ b/CleanCodeApp/LiveCode/4-OOP/GameCoordinator.swift @@ -0,0 +1,23 @@ +// +// GameCoordinator.swift +// CleanCode +// +// Created by Pedro Menezes on 10/02/25. +// + +import Foundation + +struct GameCoordinator3 { + weak var viewController: UIViewController? + + func openFaqScreen() { + let faqViewController = FAQViewController(type: .lastUpdates) + viewController?.navigationController?.pushViewController(faqViewController, animated: true) + } + + func openLastLaunchingScreen() { + let lastLaunchingsViewController = LastLaunchingsFactory.make() + viewController?.navigationController?.pushViewController(lastLaunchingsViewController, animated: true) + } +} + diff --git a/CleanCodeApp/LiveCode/4-OOP/GameViewController.swift b/CleanCodeApp/LiveCode/4-OOP/GameViewController.swift new file mode 100644 index 0000000..8bcc700 --- /dev/null +++ b/CleanCodeApp/LiveCode/4-OOP/GameViewController.swift @@ -0,0 +1,77 @@ +// +// 4aula.swift +// CleanCode +// +// Created by Pedro Menezes on 10/02/25. +// + +import UIKit +import WebKit + +final class GameViewController5: UIViewController { + private let htmlBuilder = HtmlBuilder3() + private let webView = WKWebView() + private var webViewContent: WebViewContent? + private var coordinator = GameCoordinator2() + + private lazy var goToLauchingsButton : UIButton = { + let launchButton = UIButton(type: .system) + launchButton.setTitle("Ver lançamentos", for: .normal) + launchButton.addTarget(self, action: #selector(openLastLaunchingsScreen), for: .touchUpInside) + launchButton.translatesAutoresizingMaskIntoConstraints = false + return launchButton + }() + + override func viewDidLoad() { + super.viewDidLoad() + setupNavigationBar() + setupGoToLaunchingsButton() + fillWebViewContent() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + webView.frame = view.frame + view.addSubview(webView) + } +} + +// MARK: Setup Layout + +private extension GameViewController5 { + @objc + func openFAQ() { + coordinator.openFaqScreen() + } + + @objc func openLastLaunchingsScreen() { + coordinator.openLastLaunchingScreen() + } + + func setupNavigationBar() { + navigationItem.rightBarButtonItem = UIBarButtonItem( + image: UIImage(named: "message.square"), + style: .plain, + target: self, + action: #selector(openFAQ) + ) + } + + func setupGoToLaunchingsButton() { + view.addSubview(goToLauchingsButton) + NSLayoutConstraint.activate([ + goToLauchingsButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), + goToLauchingsButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20) + ]) + } + + func fillWebViewContent() { + guard let content = webViewContent else { return } + do { + let deviceUrls = try htmlBuilder.createWebViewUrls(content: content) + webView.loadFileURL(deviceUrls.htmlURL, allowingReadAccessTo: deviceUrls.pathURL.absoluteURL) + } catch { + Globals.showAlertMessage(title: "Oops...", message: "Tente novamente mais tarde", targetVC: self) + } + } +} diff --git a/CleanCodeApp/LiveCode/4-OOP/HtmlBuilder.swift b/CleanCodeApp/LiveCode/4-OOP/HtmlBuilder.swift new file mode 100644 index 0000000..d5e6b18 --- /dev/null +++ b/CleanCodeApp/LiveCode/4-OOP/HtmlBuilder.swift @@ -0,0 +1,50 @@ +// +// HtmlBuilder.swift +// CleanCode +// +// Created by Pedro Menezes on 10/02/25. +// + +import Foundation + +struct HtmlBuilder3 { + private let realmManager = RealmManager() + + func createWebViewUrls(content: WebViewContent) throws -> DeviceUrls { + let htmlAfterCustomization = try configureHtmlAppearence(content: content) + let data = try convertHtmlToData(html: htmlAfterCustomization) + let deviceUrls = getDeviceHtmlPathToSave() + try data.write(to: deviceUrls.htmlURL) + return deviceUrls + } +} + +private extension HtmlBuilder3 { + func configureHtmlAppearence(content: WebViewContent) throws -> String { + guard let rHtmlConfig = realmManager.getObjects(HtmlConfig.self), + let htmlConfig = rHtmlConfig.last as? HtmlConfig, + let js = htmlConfig.jsContent, + let css = htmlConfig.cssContent else { + throw CommonsErros.invalidData + } + let body = RuntimeRoutine().runMustache(content: content) + let htmlFinal = Globals.buildHtml(html: body, css: css, js: js) + return htmlFinal + } + + func convertHtmlToData(html: String) throws -> Data { + guard let data = html.data(using: .utf8) else { + print("Erro ao converter string html") + throw CommonsErros.invalidData + } + return data + } + + func getDeviceHtmlPathToSave() -> DeviceUrls { + let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) + let pathURL = URL(fileURLWithPath: paths[0]).appendingPathComponent(RealmFilesNames.imagesFatherPath.rawValue) + let htmlURL = URL(fileURLWithPath: "content_html", relativeTo: pathURL).appendingPathExtension("html") + let deviceUrls = DeviceUrls(pathURL: pathURL, htmlURL: htmlURL) + return deviceUrls + } +} diff --git a/CleanCodeApp/Modules/Features/Som/ResetPassword/SomResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Som/ResetPassword/SomResetPasswordViewController.swift index 4c96e07..ed4f593 100644 --- a/CleanCodeApp/Modules/Features/Som/ResetPassword/SomResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Som/ResetPassword/SomResetPasswordViewController.swift @@ -57,6 +57,7 @@ class SomResetPasswordViewController: UIViewController { self.recoverPasswordButton.titleLabel?.text = "REENVIAR E-MAIL" self.recoverPasswordButton.setTitle("Voltar", for: .normal) } else { + Logger.shared.log("[ERRO API] - erro endpoint de reset") let alertController = UIAlertController(title: "Ops..", message: "Algo de errado aconteceu. Tente novamente mais tarde.", preferredStyle: .alert) let action = UIAlertAction(title: "OK", style: .default) alertController.addAction(action) diff --git a/CleanCodeApp/Modules/Utils/Globals/Globals.swift b/CleanCodeApp/Modules/Utils/Globals/Globals.swift index af7c4b4..4c99249 100644 --- a/CleanCodeApp/Modules/Utils/Globals/Globals.swift +++ b/CleanCodeApp/Modules/Utils/Globals/Globals.swift @@ -22,3 +22,12 @@ struct Globals { controller.present(alertController, animated: true) } } + + +class Logger { + static let shared = Logger() + + func log(_ text: String) { + + } +} From b7f7fd8594fd46f46fa87925697aaedd0bc807da Mon Sep 17 00:00:00 2001 From: ThaisaFujii Date: Thu, 13 Feb 2025 20:38:12 -0300 Subject: [PATCH 27/29] Solving conflicts --- CleanCodeApp/AppDelegate/SceneDelegate.swift | 20 --- .../1-funcoes/GameViewController.swift | 123 -------------- .../LiveCode/3-nomes/GameCoordinator.swift | 23 --- .../LiveCode/3-nomes/GameViewController.swift | 73 --------- .../LiveCode/3-nomes/HtmlBuilder.swift | 48 ------ .../LiveCode/4-OOP/GameCoordinator.swift | 23 --- .../LiveCode/4-OOP/GameViewController.swift | 77 --------- CleanCodeApp/LiveCode/4-OOP/HtmlBuilder.swift | 50 ------ .../FozResetPasswordViewController.swift | 151 +++++------------- .../LuzContactUsViewController.swift | 59 ------- .../SolContactUsViewController.swift | 8 - 11 files changed, 39 insertions(+), 616 deletions(-) delete mode 100644 CleanCodeApp/LiveCode/1-funcoes/GameViewController.swift delete mode 100644 CleanCodeApp/LiveCode/3-nomes/GameCoordinator.swift delete mode 100644 CleanCodeApp/LiveCode/3-nomes/GameViewController.swift delete mode 100644 CleanCodeApp/LiveCode/3-nomes/HtmlBuilder.swift delete mode 100644 CleanCodeApp/LiveCode/4-OOP/GameCoordinator.swift delete mode 100644 CleanCodeApp/LiveCode/4-OOP/GameViewController.swift delete mode 100644 CleanCodeApp/LiveCode/4-OOP/HtmlBuilder.swift diff --git a/CleanCodeApp/AppDelegate/SceneDelegate.swift b/CleanCodeApp/AppDelegate/SceneDelegate.swift index 24f4b51..9ddf20a 100644 --- a/CleanCodeApp/AppDelegate/SceneDelegate.swift +++ b/CleanCodeApp/AppDelegate/SceneDelegate.swift @@ -17,11 +17,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { guard let windowScene = (scene as? UIWindowScene) else { return } self.window = UIWindow(frame: UIScreen.main.bounds) -<<<<<<< HEAD - let rootViewController = getRootViewController(forUser: .elyAssumpcao) -======= let rootViewController = getRootViewController(forUser: .thaisaAmanda) ->>>>>>> upstream/main self.window?.rootViewController = UINavigationController(rootViewController: rootViewController) self.window?.windowScene = windowScene self.window?.makeKeyAndVisible() @@ -49,15 +45,7 @@ func getRootViewController(forUser user: Users) -> UIViewController { userIdentifier = "Rio" case .rayanaPrata: userIdentifier = "Rum" -<<<<<<< HEAD -<<<<<<< HEAD - case .elyAssuncao: -======= case .elyAssumpcao: ->>>>>>> 5d781b2 (feat tratar funções) -======= - case .elyAssumpcao: ->>>>>>> upstream/main userIdentifier = "Sol" } let storyboard = UIStoryboard(name: "\(userIdentifier)User", bundle: nil) @@ -75,13 +63,5 @@ enum Users { case giuliaKetlin case thaisaAmanda case rayanaPrata -<<<<<<< HEAD -<<<<<<< HEAD - case elyAssuncao -======= - case elyAssumpcao ->>>>>>> 5d781b2 (feat tratar funções) -======= case elyAssumpcao ->>>>>>> upstream/main } diff --git a/CleanCodeApp/LiveCode/1-funcoes/GameViewController.swift b/CleanCodeApp/LiveCode/1-funcoes/GameViewController.swift deleted file mode 100644 index 4446d98..0000000 --- a/CleanCodeApp/LiveCode/1-funcoes/GameViewController.swift +++ /dev/null @@ -1,123 +0,0 @@ -// -// 1LiveCodeFunctions.swift -// CleanCode -// -// Created by Pedro Menezes on 04/02/25. -// - -import UIKit -import WebKit - -class GameViewController1: UIViewController { - - let webView = WKWebView() - var content: WebViewContent? - let realmManager = RealmManager() - - lazy var bottomButton: UIButton = { - let launchButton = UIButton(type: .system) - launchButton.setTitle("Ver lançamentos", for: .normal) - launchButton.addTarget(self, action: #selector(openNextScreen), for: .touchUpInside) - launchButton.translatesAutoresizingMaskIntoConstraints = false - return launchButton - }() - - override func viewDidLoad() { - super.viewDidLoad() - setupNavigationBar() - setupBottomButton() - setupWebView() - } - - func setupNavigationBar() { - navigationItem.rightBarButtonItem = UIBarButtonItem( - image: UIImage(named: "message.square"), - style: .plain, - target: self, - action: #selector(openFAQ) - ) - } - - func setupBottomButton() { - view.addSubview(bottomButton) - NSLayoutConstraint.activate([ - bottomButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), - bottomButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20) - ]) - } - - func setupWebView() { - guard let content = content else { return } - do { - let deviceUrls = try createWebViewUrls(content: content) - webView.loadFileURL(deviceUrls.htmlURL, allowingReadAccessTo: deviceUrls.pathURL.absoluteURL) - } catch { - Globals.alertMessage(title: "Oops...", message: "Tente novamente mais tarde", targetVC: self) - } - } - - func createWebViewUrls(content: WebViewContent) throws -> DeviceUrls { - let htmlFinal = try configHtml(content: content) - let data = try saveHtml(html: htmlFinal) - let deviceUrls = getDeviceUrls() - try data.write(to: deviceUrls.htmlURL) - return deviceUrls - } - - func configHtml(content: WebViewContent) throws -> String { - guard let rHtmlConfig = realmManager.getObjects(HtmlConfig.self), - let htmlConfig = rHtmlConfig.last as? HtmlConfig, - let js = htmlConfig.jsContent, - let css = htmlConfig.cssContent else { - throw CommonsErros.invalidData - } - let body = RuntimeRoutine().runMustache(content: content) - let htmlFinal = Globals.buildHtml(html: body, css: css, js: js) - return htmlFinal - } - - func saveHtml(html: String) throws -> Data { - guard let data = html.data(using: .utf8) else { - print("Erro ao converter string html") - throw CommonsErros.invalidData - } - return data - } - - func getDeviceUrls() -> DeviceUrls { - let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) - let pathURL = URL(fileURLWithPath: paths[0]).appendingPathComponent(RealmFilesNames.imagesFatherPath.rawValue) - let htmlURL = URL(fileURLWithPath: "content_html", relativeTo: pathURL).appendingPathExtension("html") - let deviceUrls = DeviceUrls(pathURL: pathURL, htmlURL: htmlURL) - return deviceUrls - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - webView.frame = view.frame - view.addSubview(webView) - } - - - @objc func openFAQ() { - let faqVC = FAQViewController(type: .lastUpdates) - navigationController?.pushViewController(faqVC, animated: true) - } - - @objc func openNextScreen() { - let analytics = LastLaunchAnallytics() - let service = LastLaunchingsService() - let viewModel = LastLaunchingsViewModel(service: service, analytics: analytics) - let lastLaunchingsVC = LastLaunchingsViewController(viewModel: viewModel) - navigationController?.pushViewController(lastLaunchingsVC, animated: true) - } -} - -struct DeviceUrls { - let pathURL: URL - let htmlURL: URL -} - -enum CommonsErros: Error { - case invalidData -} diff --git a/CleanCodeApp/LiveCode/3-nomes/GameCoordinator.swift b/CleanCodeApp/LiveCode/3-nomes/GameCoordinator.swift deleted file mode 100644 index 47d1c31..0000000 --- a/CleanCodeApp/LiveCode/3-nomes/GameCoordinator.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// GameCoordinator.swift -// CleanCode -// -// Created by Pedro Menezes on 10/02/25. -// - -import UIKit - -struct GameCoordinator2 { - - weak var viewController: UIViewController? - - func openFaqScreen() { - let faqViewController = FAQViewController(type: .lastUpdates) - viewController?.navigationController?.pushViewController(faqViewController, animated: true) - } - - func openLastLaunchingScreen() { - let lastLaunchingsViewController = LastLaunchingsFactory.make() - viewController?.navigationController?.pushViewController(lastLaunchingsViewController, animated: true) - } -} diff --git a/CleanCodeApp/LiveCode/3-nomes/GameViewController.swift b/CleanCodeApp/LiveCode/3-nomes/GameViewController.swift deleted file mode 100644 index 0c2236d..0000000 --- a/CleanCodeApp/LiveCode/3-nomes/GameViewController.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// codigo3.swift -// CleanCode -// -// Created by Pedro Menezes on 07/02/25. -// - -import UIKit -import WebKit - -class GameViewController4: UIViewController { - let htmlBuilder = HtmlBuilder() - let webView = WKWebView() - var webViewContent: WebViewContent? - var coordinator = GameCoordinator2() - - lazy var goToLauchingsButton : UIButton = { - let launchButton = UIButton(type: .system) - launchButton.setTitle("Ver lançamentos", for: .normal) - launchButton.addTarget(self, action: #selector(openLastLaunchingsScreen), for: .touchUpInside) - launchButton.translatesAutoresizingMaskIntoConstraints = false - return launchButton - }() - - override func viewDidLoad() { - super.viewDidLoad() - setupNavigationBar() - setupGoToLaunchingsButton() - fillWebViewContent() - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - webView.frame = view.frame - view.addSubview(webView) - } - - @objc - func openFAQ() { - coordinator.openFaqScreen() - } - - @objc func openLastLaunchingsScreen() { - coordinator.openLastLaunchingScreen() - } - - func setupNavigationBar() { - navigationItem.rightBarButtonItem = UIBarButtonItem( - image: UIImage(named: "message.square"), - style: .plain, - target: self, - action: #selector(openFAQ) - ) - } - - func setupGoToLaunchingsButton() { - view.addSubview(goToLauchingsButton) - NSLayoutConstraint.activate([ - goToLauchingsButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), - goToLauchingsButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20) - ]) - } - - func fillWebViewContent() { - guard let content = webViewContent else { return } - do { - let deviceUrls = try htmlBuilder.createWebViewUrls(content: content) - webView.loadFileURL(deviceUrls.htmlURL, allowingReadAccessTo: deviceUrls.pathURL.absoluteURL) - } catch { - Globals.showAlertMessage(title: "Oops...", message: "Tente novamente mais tarde", targetVC: self) - } - } -} diff --git a/CleanCodeApp/LiveCode/3-nomes/HtmlBuilder.swift b/CleanCodeApp/LiveCode/3-nomes/HtmlBuilder.swift deleted file mode 100644 index 76d2d9a..0000000 --- a/CleanCodeApp/LiveCode/3-nomes/HtmlBuilder.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// HtmlBuilder.swift -// CleanCode -// -// Created by Pedro Menezes on 10/02/25. -// - -import Foundation - -struct HtmlBuilder2 { - let realmManager = RealmManager() - - func createWebViewUrls(content: WebViewContent) throws -> DeviceUrls { - let htmlAfterCustomization = try configureHtmlAppearence(content: content) - let data = try convertHtmlToData(html: htmlAfterCustomization) - let deviceUrls = getDeviceHtmlPathToSave() - try data.write(to: deviceUrls.htmlURL) - return deviceUrls - } - - func configureHtmlAppearence(content: WebViewContent) throws -> String { - guard let rHtmlConfig = realmManager.getObjects(HtmlConfig.self), - let htmlConfig = rHtmlConfig.last as? HtmlConfig, - let js = htmlConfig.jsContent, - let css = htmlConfig.cssContent else { - throw CommonsErros.invalidData - } - let body = RuntimeRoutine().runMustache(content: content) - let htmlFinal = Globals.buildHtml(html: body, css: css, js: js) - return htmlFinal - } - - func convertHtmlToData(html: String) throws -> Data { - guard let data = html.data(using: .utf8) else { - print("Erro ao converter string html") - throw CommonsErros.invalidData - } - return data - } - - func getDeviceHtmlPathToSave() -> DeviceUrls { - let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) - let pathURL = URL(fileURLWithPath: paths[0]).appendingPathComponent(RealmFilesNames.imagesFatherPath.rawValue) - let htmlURL = URL(fileURLWithPath: "content_html", relativeTo: pathURL).appendingPathExtension("html") - let deviceUrls = DeviceUrls(pathURL: pathURL, htmlURL: htmlURL) - return deviceUrls - } -} diff --git a/CleanCodeApp/LiveCode/4-OOP/GameCoordinator.swift b/CleanCodeApp/LiveCode/4-OOP/GameCoordinator.swift deleted file mode 100644 index 4c52260..0000000 --- a/CleanCodeApp/LiveCode/4-OOP/GameCoordinator.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// GameCoordinator.swift -// CleanCode -// -// Created by Pedro Menezes on 10/02/25. -// - -import Foundation - -struct GameCoordinator3 { - weak var viewController: UIViewController? - - func openFaqScreen() { - let faqViewController = FAQViewController(type: .lastUpdates) - viewController?.navigationController?.pushViewController(faqViewController, animated: true) - } - - func openLastLaunchingScreen() { - let lastLaunchingsViewController = LastLaunchingsFactory.make() - viewController?.navigationController?.pushViewController(lastLaunchingsViewController, animated: true) - } -} - diff --git a/CleanCodeApp/LiveCode/4-OOP/GameViewController.swift b/CleanCodeApp/LiveCode/4-OOP/GameViewController.swift deleted file mode 100644 index 8bcc700..0000000 --- a/CleanCodeApp/LiveCode/4-OOP/GameViewController.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// 4aula.swift -// CleanCode -// -// Created by Pedro Menezes on 10/02/25. -// - -import UIKit -import WebKit - -final class GameViewController5: UIViewController { - private let htmlBuilder = HtmlBuilder3() - private let webView = WKWebView() - private var webViewContent: WebViewContent? - private var coordinator = GameCoordinator2() - - private lazy var goToLauchingsButton : UIButton = { - let launchButton = UIButton(type: .system) - launchButton.setTitle("Ver lançamentos", for: .normal) - launchButton.addTarget(self, action: #selector(openLastLaunchingsScreen), for: .touchUpInside) - launchButton.translatesAutoresizingMaskIntoConstraints = false - return launchButton - }() - - override func viewDidLoad() { - super.viewDidLoad() - setupNavigationBar() - setupGoToLaunchingsButton() - fillWebViewContent() - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - webView.frame = view.frame - view.addSubview(webView) - } -} - -// MARK: Setup Layout - -private extension GameViewController5 { - @objc - func openFAQ() { - coordinator.openFaqScreen() - } - - @objc func openLastLaunchingsScreen() { - coordinator.openLastLaunchingScreen() - } - - func setupNavigationBar() { - navigationItem.rightBarButtonItem = UIBarButtonItem( - image: UIImage(named: "message.square"), - style: .plain, - target: self, - action: #selector(openFAQ) - ) - } - - func setupGoToLaunchingsButton() { - view.addSubview(goToLauchingsButton) - NSLayoutConstraint.activate([ - goToLauchingsButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), - goToLauchingsButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20) - ]) - } - - func fillWebViewContent() { - guard let content = webViewContent else { return } - do { - let deviceUrls = try htmlBuilder.createWebViewUrls(content: content) - webView.loadFileURL(deviceUrls.htmlURL, allowingReadAccessTo: deviceUrls.pathURL.absoluteURL) - } catch { - Globals.showAlertMessage(title: "Oops...", message: "Tente novamente mais tarde", targetVC: self) - } - } -} diff --git a/CleanCodeApp/LiveCode/4-OOP/HtmlBuilder.swift b/CleanCodeApp/LiveCode/4-OOP/HtmlBuilder.swift deleted file mode 100644 index d5e6b18..0000000 --- a/CleanCodeApp/LiveCode/4-OOP/HtmlBuilder.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// HtmlBuilder.swift -// CleanCode -// -// Created by Pedro Menezes on 10/02/25. -// - -import Foundation - -struct HtmlBuilder3 { - private let realmManager = RealmManager() - - func createWebViewUrls(content: WebViewContent) throws -> DeviceUrls { - let htmlAfterCustomization = try configureHtmlAppearence(content: content) - let data = try convertHtmlToData(html: htmlAfterCustomization) - let deviceUrls = getDeviceHtmlPathToSave() - try data.write(to: deviceUrls.htmlURL) - return deviceUrls - } -} - -private extension HtmlBuilder3 { - func configureHtmlAppearence(content: WebViewContent) throws -> String { - guard let rHtmlConfig = realmManager.getObjects(HtmlConfig.self), - let htmlConfig = rHtmlConfig.last as? HtmlConfig, - let js = htmlConfig.jsContent, - let css = htmlConfig.cssContent else { - throw CommonsErros.invalidData - } - let body = RuntimeRoutine().runMustache(content: content) - let htmlFinal = Globals.buildHtml(html: body, css: css, js: js) - return htmlFinal - } - - func convertHtmlToData(html: String) throws -> Data { - guard let data = html.data(using: .utf8) else { - print("Erro ao converter string html") - throw CommonsErros.invalidData - } - return data - } - - func getDeviceHtmlPathToSave() -> DeviceUrls { - let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) - let pathURL = URL(fileURLWithPath: paths[0]).appendingPathComponent(RealmFilesNames.imagesFatherPath.rawValue) - let htmlURL = URL(fileURLWithPath: "content_html", relativeTo: pathURL).appendingPathExtension("html") - let deviceUrls = DeviceUrls(pathURL: pathURL, htmlURL: htmlURL) - return deviceUrls - } -} diff --git a/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift index 60891bd..87ea0f3 100644 --- a/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift @@ -1,85 +1,76 @@ import UIKit class FozResetPasswordViewController: UIViewController { - + @IBOutlet weak var emailTextfield: UITextField! @IBOutlet weak var recoverPasswordButton: UIButton! @IBOutlet weak var loginButton: UIButton! @IBOutlet weak var helpButton: UIButton! @IBOutlet weak var createAccountButton: UIButton! -<<<<<<< HEAD @IBOutlet weak var textLabel: UILabel! @IBOutlet weak var viewSuccess: UIView! @IBOutlet weak var emailLabel: UILabel! var userEmail = "" var userPressedRecoveryButton = false -======= @IBOutlet weak var verifyUserEmailLabel: UILabel! @IBOutlet weak var passwordRecoveredSuccessView: UIView! @IBOutlet weak var emailDisplayLabel: UILabel! - + var didUserPutEmail: String = "" var didUserPressRecoverPasswordButton: Bool = false - + private let emailValidator: EmailValidating = EmailValidatorUseCase() - ->>>>>>> upstream/main - + + override func viewDidLoad() { super.viewDidLoad() configureRecoverPasswordView() } - + open override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } - + @IBAction func closeButtonAction(_ sender: Any) { dismiss(animated: true) } - -<<<<<<< HEAD -// MARK: Recover Password - @IBAction func recoverPasswordButton(_ sender: Any) { - if !userPressedRecoveryButton { -======= + // MARK: Recover Password @IBAction func recoverPasswordButton(_ sender: Any) { if !didUserPressRecoverPasswordButton { ->>>>>>> upstream/main validateRecovering() } else { dismiss(animated: true) } - + view.endEditing(true) } - + private func validateRecovering(){ guard validateForm() else { return } - + checkUserConnection() - + guard let email = emailTextfield.text?.trimmingCharacters(in: .whitespaces), !email.isEmpty else { return } - + let parameters = ["email": email] performPasswordReset(with: parameters, email: email) } - + private func checkUserConnection (){ guard ConnectivityManager.shared.isConnected else { Globals.showNoInternetCOnnection(controller: self) return } } - + private func performPasswordReset(with parameters: [String: String], email: String) { BadNetworkLayer.shared.resetPassword(self, parameters: parameters) { [weak self] success in DispatchQueue.main.async { @@ -88,24 +79,16 @@ class FozResetPasswordViewController: UIViewController { } } } - + private func handlePasswordResetSuccess(withEmail email: String) { -<<<<<<< HEAD - userPressedRecoveryButton = true - emailTextfield.isHidden = true - textLabel.isHidden = true - viewSuccess.isHidden = false - emailLabel.text = email -======= didUserPressRecoverPasswordButton = true emailTextfield.isHidden = true verifyUserEmailLabel.isHidden = true passwordRecoveredSuccessView.isHidden = false emailDisplayLabel.text = email ->>>>>>> upstream/main recoverPasswordButton.setTitle("Voltar", for: .normal) } - + private func handlePasswordResetFailure() { let alertController = UIAlertController( title: "Ops…", @@ -115,130 +98,87 @@ class FozResetPasswordViewController: UIViewController { alertController.addAction(UIAlertAction(title: "OK", style: .default)) present(alertController, animated: true) } - - + + @IBAction func loginButton(_ sender: Any) { dismiss(animated: true) } - + @IBAction func helpButton(_ sender: Any) { let vc = FozContactUsViewController() vc.modalPresentationStyle = .fullScreen vc.modalTransitionStyle = .coverVertical self.present(vc, animated: true, completion: nil) } - + @IBAction func createAccountButton(_ sender: Any) { let newVc = FozCreateAccountViewController() newVc.modalPresentationStyle = .fullScreen present(newVc, animated: true) } - + func validateForm() -> Bool { -<<<<<<< HEAD - let isEmailValid = EmailValidator.isValid(emailTextfield.text) -======= let isEmailValid = emailValidator.isValid(emailTextfield.text) ->>>>>>> upstream/main - + if isEmailValid { return true } - + else { setupErrorMessage() return false } - + } - + private func setupErrorMessage(){ emailTextfield.setErrorColor() -<<<<<<< HEAD textLabel.textColor = .red textLabel.text = "Verifique o e-mail informado" } } -struct EmailValidator { - static func isValid(_ email: String?) -> Bool { - guard let email = email?.trimmingCharacters(in: .whitespaces), !email.isEmpty else { return false } - return email.contains("@") && email.contains(".") && email.count > 5 -======= - verifyUserEmailLabel.textColor = .red - verifyUserEmailLabel.text = "Verifique o e-mail informado" ->>>>>>> upstream/main - } -} - - // MARK: - Comportamentos de layout extension FozResetPasswordViewController { - -<<<<<<< HEAD - func setupView() { - stylePrimaryButton(recoverPasswordButton) - - styleSecondaryButton(loginButton) - - styleSecondaryButton(helpButton) - - styleSecondaryButton(createAccountButton) - - emailTextfield.setDefaultColor() - - if !userEmail.isEmpty { - emailTextfield.text = userEmail -======= + func configureRecoverPasswordView() { recoverPasswordButton.applyPrimaryButtonStyle() - + loginButton.applySecondaryButtonStyle() - + helpButton.applySecondaryButtonStyle() - + createAccountButton.applySecondaryButtonStyle() - + emailTextfield.setDefaultColor() - + if !didUserPutEmail.isEmpty { emailTextfield.text = didUserPutEmail ->>>>>>> upstream/main emailTextfield.isEnabled = false } updateRecoverPasswordButtonState() } - -<<<<<<< HEAD - //email - @IBAction func emailBeginEditing(_ sender: Any) { - emailTextfield.setEditingColor() - } - - @IBAction func emailEditing(_ sender: Any) { -======= + @IBAction func emailEditingDidBegin(_ sender: Any) { emailTextfield.setEditingColor() } @IBAction func emailEditingChanged(_ sender: Any) { ->>>>>>> upstream/main emailTextfield.setEditingColor() updateRecoverPasswordButtonState() } - -<<<<<<< HEAD + @IBAction func emailEndEditing(_ sender: Any) { emailTextfield.setDefaultColor() } - + // MARK: Button Styler func stylePrimaryButton(_ button: UIButton){ button.layer.cornerRadius = button.bounds.height / 2 button.backgroundColor = .blue button.setTitleColor(.white, for: .normal) } - + func styleSecondaryButton(_ button: UIButton){ button.layer.cornerRadius = button.bounds.height / 2 button.layer.borderWidth = 1 @@ -246,20 +186,17 @@ extension FozResetPasswordViewController { button.backgroundColor = .white button.setTitleColor(.blue, for: .normal) } - + } extension FozResetPasswordViewController { - - func validateButton() { -======= - @IBAction func emailEditingDidEnd(_ sender: Any) { + + func emailEditingDidEnd(_ sender: Any) { emailTextfield.setDefaultColor() } func updateRecoverPasswordButtonState() { ->>>>>>> upstream/main if !emailTextfield.text!.isEmpty { enableRecoverPasswordButton() } @@ -268,26 +205,16 @@ extension FozResetPasswordViewController { } } -<<<<<<< HEAD - func disableCreateButton() { -======= func disableRecoverPasswordButton() { ->>>>>>> upstream/main recoverPasswordButton.backgroundColor = .gray recoverPasswordButton.setTitleColor(.white, for: .normal) recoverPasswordButton.isEnabled = false } -<<<<<<< HEAD - func enableCreateButton() { -======= func enableRecoverPasswordButton() { ->>>>>>> upstream/main recoverPasswordButton.backgroundColor = .blue recoverPasswordButton.setTitleColor(.white, for: .normal) recoverPasswordButton.isEnabled = true } } - - diff --git a/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift b/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift index f8c84e9..58caa17 100644 --- a/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Luz/ContactsUs/LuzContactUsViewController.swift @@ -290,65 +290,6 @@ final class LuzContactUsViewController: LoadingInheritageController { self.dismiss(animated: true) } } -<<<<<<< HEAD -} - -// MARK: - StackView's -extension LuzContactUsViewController { - private func createContactButtonsStackView() -> UIStackView { - let stackView = UIStackView( - arrangedSubviews: [ - phoneButton, - emailButton, - chatButton - ] - ) - stackView.axis = .horizontal - stackView.alignment = .center - stackView.distribution = .equalSpacing - - [phoneButton, emailButton, chatButton].forEach { view in - view.widthAnchor.constraint(equalToConstant: 80).isActive = true - view.heightAnchor.constraint(equalToConstant: 80).isActive = true - } - - return stackView - } - - private func createMessageStackView() -> UIStackView { - let stackView = UIStackView( - arrangedSubviews: [ - messageLabel, - textView - ] - ) - stackView.axis = .vertical - stackView.spacing = 20 - return stackView - } - - private func createCTAStackView() -> UIStackView { - let stackView = UIStackView( - arrangedSubviews: [ - sendMessageButton, - closeButton - ] - ) - stackView.axis = .vertical - stackView.spacing = 20 - - [sendMessageButton, closeButton].forEach { view in - view.heightAnchor.constraint(equalToConstant: 40).isActive = true - } - return stackView - } - -} - -#Preview { - LuzContactUsViewController() -======= ->>>>>>> upstream/main } // MARK: - StackView's diff --git a/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift b/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift index 5a8043d..b088acf 100644 --- a/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift +++ b/CleanCodeApp/Modules/Features/Sol/ContactsUs/SolContactUsViewController.swift @@ -232,11 +232,7 @@ class SolContactUsViewController: LoadingInheritageController, SolContactUsProto func sendParameters() throws -> [String: String] { let email = model?.mail ?? "" guard let message = textView.text, textView.text.count > 0 else { -<<<<<<< HEAD - throw CommonsError.invalidMessage -======= throw SolCommonsError.invalidMessage ->>>>>>> upstream/main } let parameters: [String: String] = [ @@ -267,10 +263,6 @@ class SolContactUsViewController: LoadingInheritageController, SolContactUsProto } } -<<<<<<< HEAD -enum CommonsError: Error { -======= enum SolCommonsError: Error { ->>>>>>> upstream/main case invalidMessage } From e709c2d8c7ca39992ba939da3731557cf68fc63f Mon Sep 17 00:00:00 2001 From: ThaisaFujii Date: Mon, 17 Feb 2025 22:00:33 -0300 Subject: [PATCH 28/29] Applying Class Lesson --- .../Helpers/RioAlertHelper.swift | 18 ++ .../Helpers/RioCommonErrors.swift | 22 +++ .../RioResetPasswordService.swift | 24 +++ .../RioResetPasswordViewConfigurator.swift | 52 +++++ .../RioResetPasswordViewController.swift | 177 ++++-------------- .../RioResetPasswordViewModel.swift | 54 ++++++ 6 files changed, 203 insertions(+), 144 deletions(-) create mode 100644 CleanCodeApp/Modules/Features/Rio/ResetPassword/Helpers/RioAlertHelper.swift create mode 100644 CleanCodeApp/Modules/Features/Rio/ResetPassword/Helpers/RioCommonErrors.swift create mode 100644 CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordService.swift create mode 100644 CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordViewConfigurator.swift create mode 100644 CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordViewModel.swift diff --git a/CleanCodeApp/Modules/Features/Rio/ResetPassword/Helpers/RioAlertHelper.swift b/CleanCodeApp/Modules/Features/Rio/ResetPassword/Helpers/RioAlertHelper.swift new file mode 100644 index 0000000..1911ba7 --- /dev/null +++ b/CleanCodeApp/Modules/Features/Rio/ResetPassword/Helpers/RioAlertHelper.swift @@ -0,0 +1,18 @@ +// +// RioAlertHelper.swift +// CleanCode +// +// Created by thaisa on 17/02/25. +// + +import Foundation +import UIKit + +class RioAlertHelper { + + 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) + } +} diff --git a/CleanCodeApp/Modules/Features/Rio/ResetPassword/Helpers/RioCommonErrors.swift b/CleanCodeApp/Modules/Features/Rio/ResetPassword/Helpers/RioCommonErrors.swift new file mode 100644 index 0000000..54f2972 --- /dev/null +++ b/CleanCodeApp/Modules/Features/Rio/ResetPassword/Helpers/RioCommonErrors.swift @@ -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." + } + } +} diff --git a/CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordService.swift b/CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordService.swift new file mode 100644 index 0000000..955e527 --- /dev/null +++ b/CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordService.swift @@ -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) + } + } +} diff --git a/CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordViewConfigurator.swift b/CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordViewConfigurator.swift new file mode 100644 index 0000000..6231cc4 --- /dev/null +++ b/CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordViewConfigurator.swift @@ -0,0 +1,52 @@ +// +// RioResetPasswordViewConfigurator.swift +// CleanCode +// +// Created by thaisa on 17/02/25. +// + +import Foundation +import UIKit + +class RioResetPasswordViewConfigurator { + + 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 + } +} diff --git a/CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordViewController.swift index 2ff498b..f4bf420 100644 --- a/CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordViewController.swift @@ -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! @@ -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) @@ -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) { @@ -127,69 +62,13 @@ 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) { @@ -197,12 +76,22 @@ extension RioResetPasswordViewController { } } -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) } } diff --git a/CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordViewModel.swift b/CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordViewModel.swift new file mode 100644 index 0000000..4f597c9 --- /dev/null +++ b/CleanCodeApp/Modules/Features/Rio/ResetPassword/RioResetPasswordViewModel.swift @@ -0,0 +1,54 @@ +// +// RioResetPasswordViewModel.swift +// CleanCode +// +// Created by thaisa on 17/02/25. +// + +import Foundation + +class RioResetPasswordViewModel { + + weak var delegate: RioResetPasswordViewModelDelegate? + private let service: RioResetPasswordService + + init(service: RioResetPasswordService = RioResetPasswordService()) { + self.service = service + } + + func validateEmail(_ email: String) throws { + guard !email.isEmpty, + email.contains("@"), + email.contains("."), + email.count > 5 else { + throw RioCommonErrors.invalidEmail + } + } + + func validateInternetConnection() throws { + guard ConnectivityManager.shared.isConnected else { + throw RioCommonErrors.noInternet + } + } + + func attemptPasswordReset(email: String) { + do { + try validateEmail(email) + try validateInternetConnection() + + service.resetPassword(email: email) { [weak self] success in + DispatchQueue.main.async { + if success { + self?.delegate?.didResetPasswordSuccess(email: email) + } else { + self?.delegate?.didFailWithError(.noInternet) + } + } + } + } catch let error as RioCommonErrors { + delegate?.didFailWithError(error) + } catch { + delegate?.didFailWithError(.noInternet) + } + } +} From fdad58b7128b766fb32c75c18ca2600e0ad08f33 Mon Sep 17 00:00:00 2001 From: ThaisaFujii Date: Mon, 17 Feb 2025 22:05:52 -0300 Subject: [PATCH 29/29] Undoing changes on FozResetPasswordViewController --- .../FozResetPasswordViewController.swift | 102 +++++++----------- 1 file changed, 37 insertions(+), 65 deletions(-) diff --git a/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift b/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift index 87ea0f3..dfd5234 100644 --- a/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift +++ b/CleanCodeApp/Modules/Features/Foz/ResetPassword/FozResetPasswordViewController.swift @@ -1,42 +1,36 @@ import UIKit class FozResetPasswordViewController: UIViewController { - + @IBOutlet weak var emailTextfield: UITextField! @IBOutlet weak var recoverPasswordButton: UIButton! @IBOutlet weak var loginButton: UIButton! @IBOutlet weak var helpButton: UIButton! @IBOutlet weak var createAccountButton: UIButton! - @IBOutlet weak var textLabel: UILabel! - @IBOutlet weak var viewSuccess: UIView! - @IBOutlet weak var emailLabel: UILabel! - - var userEmail = "" - var userPressedRecoveryButton = false @IBOutlet weak var verifyUserEmailLabel: UILabel! @IBOutlet weak var passwordRecoveredSuccessView: UIView! @IBOutlet weak var emailDisplayLabel: UILabel! - + var didUserPutEmail: String = "" var didUserPressRecoverPasswordButton: Bool = false - + private let emailValidator: EmailValidating = EmailValidatorUseCase() - - + + override func viewDidLoad() { super.viewDidLoad() configureRecoverPasswordView() } - + open override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } - + @IBAction func closeButtonAction(_ sender: Any) { dismiss(animated: true) } - + // MARK: Recover Password @IBAction func recoverPasswordButton(_ sender: Any) { if !didUserPressRecoverPasswordButton { @@ -45,32 +39,32 @@ class FozResetPasswordViewController: UIViewController { else { dismiss(animated: true) } - + view.endEditing(true) } - + private func validateRecovering(){ guard validateForm() else { return } - + checkUserConnection() - + guard let email = emailTextfield.text?.trimmingCharacters(in: .whitespaces), !email.isEmpty else { return } - + let parameters = ["email": email] performPasswordReset(with: parameters, email: email) } - + private func checkUserConnection (){ guard ConnectivityManager.shared.isConnected else { Globals.showNoInternetCOnnection(controller: self) return } } - + private func performPasswordReset(with parameters: [String: String], email: String) { BadNetworkLayer.shared.resetPassword(self, parameters: parameters) { [weak self] success in DispatchQueue.main.async { @@ -79,7 +73,7 @@ class FozResetPasswordViewController: UIViewController { } } } - + private func handlePasswordResetSuccess(withEmail email: String) { didUserPressRecoverPasswordButton = true emailTextfield.isHidden = true @@ -88,7 +82,7 @@ class FozResetPasswordViewController: UIViewController { emailDisplayLabel.text = email recoverPasswordButton.setTitle("Voltar", for: .normal) } - + private func handlePasswordResetFailure() { let alertController = UIAlertController( title: "Ops…", @@ -98,67 +92,68 @@ class FozResetPasswordViewController: UIViewController { alertController.addAction(UIAlertAction(title: "OK", style: .default)) present(alertController, animated: true) } - - + + @IBAction func loginButton(_ sender: Any) { dismiss(animated: true) } - + @IBAction func helpButton(_ sender: Any) { let vc = FozContactUsViewController() vc.modalPresentationStyle = .fullScreen vc.modalTransitionStyle = .coverVertical self.present(vc, animated: true, completion: nil) } - + @IBAction func createAccountButton(_ sender: Any) { let newVc = FozCreateAccountViewController() newVc.modalPresentationStyle = .fullScreen present(newVc, animated: true) } - + func validateForm() -> Bool { let isEmailValid = emailValidator.isValid(emailTextfield.text) - + if isEmailValid { return true } - + else { setupErrorMessage() return false } - + } - + private func setupErrorMessage(){ emailTextfield.setErrorColor() - textLabel.textColor = .red - textLabel.text = "Verifique o e-mail informado" + verifyUserEmailLabel.textColor = .red + verifyUserEmailLabel.text = "Verifique o e-mail informado" } } + // MARK: - Comportamentos de layout extension FozResetPasswordViewController { - + func configureRecoverPasswordView() { recoverPasswordButton.applyPrimaryButtonStyle() - + loginButton.applySecondaryButtonStyle() - + helpButton.applySecondaryButtonStyle() - + createAccountButton.applySecondaryButtonStyle() - + emailTextfield.setDefaultColor() - + if !didUserPutEmail.isEmpty { emailTextfield.text = didUserPutEmail emailTextfield.isEnabled = false } updateRecoverPasswordButtonState() } - + @IBAction func emailEditingDidBegin(_ sender: Any) { emailTextfield.setEditingColor() } @@ -167,31 +162,8 @@ extension FozResetPasswordViewController { emailTextfield.setEditingColor() updateRecoverPasswordButtonState() } - - @IBAction func emailEndEditing(_ sender: Any) { - emailTextfield.setDefaultColor() - } - - // MARK: Button Styler - func stylePrimaryButton(_ button: UIButton){ - button.layer.cornerRadius = button.bounds.height / 2 - button.backgroundColor = .blue - button.setTitleColor(.white, for: .normal) - } - - func styleSecondaryButton(_ button: UIButton){ - button.layer.cornerRadius = button.bounds.height / 2 - button.layer.borderWidth = 1 - button.layer.borderColor = UIColor.blue.cgColor - button.backgroundColor = .white - button.setTitleColor(.blue, for: .normal) - } - -} -extension FozResetPasswordViewController { - - func emailEditingDidEnd(_ sender: Any) { + @IBAction func emailEditingDidEnd(_ sender: Any) { emailTextfield.setDefaultColor() }