-
Notifications
You must be signed in to change notification settings - Fork 10
Refactor: ContactUS - View Model / Async await / View Code #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import Foundation | ||
|
|
||
| protocol ContactUSServiceProtocol { | ||
| func fetch() async throws -> Data | ||
| func send(with parameters: [String: String]) async throws | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. send what? |
||
| } | ||
|
|
||
| final class ContactUSService: ContactUSServiceProtocol { | ||
| func fetch() async throws -> Data { | ||
| return try await withCheckedThrowingContinuation { continuation in | ||
| AF.shared.request( | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ja chegou na parte de parar de usar singleton? se n tiver chegado na parte de remover singlton, pode ignorar |
||
| Endpoints.contactUs, | ||
| method: .get, | ||
| parameters: nil, | ||
| headers: nil | ||
| ) { result in | ||
| switch result { | ||
| case .success(let data): | ||
| continuation.resume(returning: data) | ||
| case .failure(let error): | ||
| continuation.resume(throwing: error) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| func send(with parameters: [String: String]) async throws { | ||
| return try await withCheckedThrowingContinuation { continuation in | ||
| AF.shared.request( | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. mesmo comentario acima |
||
| Endpoints.sendMessage, | ||
| method: .post, | ||
| parameters: parameters, | ||
| headers: nil | ||
| ) { result in | ||
| switch result { | ||
| case .success: | ||
| continuation.resume() | ||
| case .failure(let error): | ||
| continuation.resume(throwing: error) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,211 @@ | ||
| import UIKit | ||
|
|
||
| final class ContactUSView: UIView { | ||
| let symbolConfiguration = UIImage.SymbolConfiguration(pointSize: 36) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tem propriedade com essa e outras que poderiam ser privates |
||
|
|
||
| lazy var textView: UITextView = { | ||
| let text = UITextView() | ||
| text.text = "Escreva sua mensagem aqui" | ||
| text.translatesAutoresizingMaskIntoConstraints = false | ||
| return text | ||
| }() | ||
|
|
||
| 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 | ||
| }() | ||
|
|
||
| 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 | ||
| lazy var phoneButton: UIButton = { | ||
| let button = UIButton() | ||
| button.backgroundColor = .systemGray4 | ||
| button.layer.cornerRadius = 10 | ||
| button.setImage( | ||
| .init(systemName: "phone")?.withConfiguration(symbolConfiguration), | ||
| for: .normal | ||
| ) | ||
| button.translatesAutoresizingMaskIntoConstraints = false | ||
| return button | ||
| }() | ||
|
|
||
| lazy var emailButton: UIButton = { | ||
| let button = UIButton() | ||
| button.backgroundColor = .systemGray4 | ||
| button.layer.cornerRadius = 10 | ||
| button.setImage( | ||
| .init(systemName: "envelope")?.withConfiguration(symbolConfiguration), | ||
| for: .normal | ||
| ) | ||
| button.translatesAutoresizingMaskIntoConstraints = false | ||
| return button | ||
| }() | ||
|
|
||
| lazy var chatButton: UIButton = { | ||
| let button = UIButton() | ||
| button.backgroundColor = .systemGray4 | ||
| button.layer.cornerRadius = 10 | ||
| button.setImage( | ||
| .init(systemName: "message")?.withConfiguration(symbolConfiguration), | ||
| for: .normal | ||
| ) | ||
| button.translatesAutoresizingMaskIntoConstraints = false | ||
| return button | ||
| }() | ||
|
|
||
| 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.translatesAutoresizingMaskIntoConstraints = false | ||
| return button | ||
| }() | ||
|
|
||
| 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.translatesAutoresizingMaskIntoConstraints = false | ||
| return button | ||
| }() | ||
|
|
||
| override init(frame: CGRect) { | ||
| super.init(frame: frame) | ||
| backgroundColor = .systemGray6 | ||
| configureUI() | ||
| setupLayout() | ||
| } | ||
|
|
||
| required init?(coder: NSCoder) { | ||
| fatalError("init(coder:) has not been implemented") | ||
| } | ||
|
|
||
| func configureUI() { | ||
| [ | ||
| titleLabel, | ||
| phoneButton, | ||
| emailButton, | ||
| chatButton, | ||
| messageLabel, | ||
| textView, | ||
| sendMessageButton, | ||
| closeButton | ||
| ].forEach { addSubview($0) } | ||
| } | ||
|
|
||
| func setupLayout() { | ||
| let contactButtonsStackView = createContactButtonsStackView() | ||
| let messageStackView = createMessageStackView() | ||
| let ctaStackView = createCTAStackView() | ||
|
|
||
| let mainStackView = UIStackView( | ||
| arrangedSubviews: [ | ||
| titleLabel, | ||
| contactButtonsStackView, | ||
| messageStackView, | ||
| ctaStackView | ||
| ] | ||
| ) | ||
| mainStackView.axis = .vertical | ||
| mainStackView.spacing = 30 | ||
| mainStackView.translatesAutoresizingMaskIntoConstraints = false | ||
|
|
||
| addSubview(mainStackView) | ||
|
|
||
| setupConstraints(for: mainStackView) | ||
| } | ||
|
|
||
| func setupConstraints(for mainStackView: UIStackView) { | ||
| NSLayoutConstraint.activate( | ||
| [ | ||
| mainStackView.topAnchor.constraint( | ||
| equalTo: safeAreaLayoutGuide.topAnchor, | ||
| constant: 30 | ||
| ), | ||
| mainStackView.leadingAnchor.constraint( | ||
| equalTo: safeAreaLayoutGuide.leadingAnchor, | ||
| constant: 20 | ||
| ), | ||
| mainStackView.trailingAnchor.constraint( | ||
| equalTo: safeAreaLayoutGuide.trailingAnchor, | ||
| constant: -20 | ||
| ), | ||
| mainStackView.bottomAnchor.constraint( | ||
| equalTo: safeAreaLayoutGuide.bottomAnchor, | ||
| constant: -20 | ||
| ) | ||
| ] | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| private extension ContactUSView { | ||
| 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 | ||
| } | ||
|
|
||
| func createMessageStackView() -> UIStackView { | ||
| let stackView = UIStackView( | ||
| arrangedSubviews: [ | ||
| messageLabel, | ||
| textView | ||
| ] | ||
| ) | ||
| stackView.axis = .vertical | ||
| stackView.spacing = 20 | ||
| return stackView | ||
| } | ||
|
|
||
| func createCTAStackView() -> UIStackView { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oq é CTA? |
||
| 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 | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import Foundation | ||
|
|
||
| final class LuzContactUSViewModel { | ||
| var model: ContactUsModel? | ||
| private let serivce: ContactUSServiceProtocol | ||
|
|
||
| init(serivce: ContactUSServiceProtocol) { | ||
| self.serivce = serivce | ||
| } | ||
|
|
||
| func fetch() async throws { | ||
| guard let data = try? await serivce.fetch() else { return } | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dar uma nome melhor para fetch fazer protocol para viewModel (se estiver no contexto desse PR) |
||
| let model = try? JSONDecoder().decode(ContactUsModel.self, from: data) | ||
| self.model = model | ||
| } | ||
|
|
||
| func send(parameters: [String: String]) async throws { | ||
| try? await serivce.send(with: parameters) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. melhorar nome e remover try opcional |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import UIKit | ||
|
|
||
| enum LuzContactUsFactory { | ||
| static func make() -> UIViewController { | ||
| let service = ContactUSService() | ||
| let viewModel = LuzContactUSViewModel(serivce: service) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. service* |
||
| return LuzContactUsViewController(viewModel: viewModel) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fetch what?
usa um nome mais claro