Skip to content

Commit

Permalink
Migrate AddCard scene from MVC to VIP
Browse files Browse the repository at this point in the history
  • Loading branch information
dogo committed Dec 30, 2023
1 parent 1003673 commit f97eb3a
Show file tree
Hide file tree
Showing 12 changed files with 302 additions and 128 deletions.
111 changes: 16 additions & 95 deletions SWDestinyTrades/Classes/AddCard/Controller/AddCardViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,17 @@

import UIKit

enum AddCardType {
case lent
case borrow
case collection
}

final class AddCardViewController: UIViewController {

private let addCardView: AddCardViewType
private let destinyService: SWDestinyServiceProtocol
private let addCardType: AddCardType
private var cards = [CardDTO]()
private var personDTO: PersonDTO?
private var userCollectionDTO: UserCollectionDTO?
private lazy var navigator = AddCardNavigator(self.navigationController)
private let database: DatabaseProtocol?

var presenter: AddCardPresenterProtocol?

// MARK: - Life Cycle

init(with view: AddCardViewType = AddCardView(),
service: SWDestinyServiceProtocol = SWDestinyService(),
database: DatabaseProtocol?,
person: PersonDTO? = nil,
userCollection: UserCollectionDTO? = nil,
type: AddCardType) {
init(with view: AddCardViewType = AddCardView()) {
addCardView = view
destinyService = service
self.database = database
addCardType = type
super.init(nibName: nil, bundle: nil)
personDTO = person
userCollectionDTO = userCollection
}

@available(*, unavailable)
Expand All @@ -54,100 +33,42 @@ final class AddCardViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()

fetchAllCards()
presenter?.fetchAllCards()

addCardView.didSelectCard = { [weak self] card in
self?.insert(card: card)
self?.presenter?.insert(card: card)
}

addCardView.didSelectAccessory = { [weak self] card in
self?.navigateToNextController(with: card)
self?.presenter?.cardDetailButtonTouched(with: card)
}

addCardView.doingSearch = { [weak self] query in
self?.addCardView.doingSearch(query)
self?.presenter?.doingSearch(query)
}
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationItem.title = L10n.addCard
}
}

// MARK: - Helpers
extension AddCardViewController: AddCardViewProtocol {

private func fetchAllCards() {
func startLoading() {
addCardView.startLoading()
Task { [weak self] in
guard let self else { return }

do {
let allCards = try await self.destinyService.retrieveAllCards()
self.addCardView.stopLoading()
self.addCardView.updateSearchList(allCards)
self.cards = allCards
} catch {
ToastMessages.showNetworkErrorMessage()
LoggerManager.shared.log(event: .allCards, parameters: ["error": error.localizedDescription])
}
}
}

private func insert(card: CardDTO) {
switch addCardType {
case .lent:
insertToLentMe(card: card)
case .borrow:
insertToBorrowed(card: card)
case .collection:
insertToCollection(card: card)
}
}

private func insertToBorrowed(card: CardDTO) {
if let person = personDTO, !person.borrowed.contains(where: { $0.code == card.code }) {
try? database?.update { [weak self] in
person.borrowed.append(card)
self?.showSuccessMessage(card: card)
}
let personDataDict: [String: PersonDTO] = ["personDTO": person]
NotificationCenter.default.post(name: NotificationKey.reloadTableViewNotification, object: nil, userInfo: personDataDict)
} else {
ToastMessages.showInfoMessage(title: "", message: L10n.alreadyAdded)
}
}

private func insertToLentMe(card: CardDTO) {
if let person = personDTO, !person.lentMe.contains(where: { $0.code == card.code }) {
try? database?.update { [weak self] in
person.lentMe.append(card)
self?.showSuccessMessage(card: card)
}
let personDataDict: [String: PersonDTO] = ["personDTO": person]
NotificationCenter.default.post(name: NotificationKey.reloadTableViewNotification, object: nil, userInfo: personDataDict)
} else {
ToastMessages.showInfoMessage(title: "", message: L10n.alreadyAdded)
}
func stopLoading() {
addCardView.stopLoading()
}

private func insertToCollection(card: CardDTO) {
if let userCollection = userCollectionDTO, !userCollection.myCollection.contains(where: { $0.code == card.code }) {
try? database?.update { [weak self] in
userCollection.myCollection.append(card)
self?.showSuccessMessage(card: card)
}
} else {
ToastMessages.showInfoMessage(title: "", message: L10n.alreadyAdded)
}
}

private func showSuccessMessage(card: CardDTO) {
LoadingHUD.show(.labeledSuccess(title: L10n.added, subtitle: card.name))
func updateSearchList(_ cards: [CardDTO]) {
addCardView.updateSearchList(cards)
}

// MARK: - Navigation

func navigateToNextController(with card: CardDTO) {
navigator.navigate(to: .cardDetail(database: database, with: cards, card: card))
func doingSearch(_ query: String) {
addCardView.doingSearch(query)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// AddCardViewControllerFactory.swift
// SWDestinyTrades
//
// Created by Diogo Autilio on 30/12/23.
// Copyright © 2023 Diogo Autilio. All rights reserved.
//

import Foundation
import UIKit

final class AddCardViewControllerFactory: ViewControllerFactory {

private let database: DatabaseProtocol?
private let addCardType: AddCardType
private let personDTO: PersonDTO?
private let userCollectionDTO: UserCollectionDTO?

init(database: DatabaseProtocol?,
addCardType: AddCardType,
personDTO: PersonDTO? = nil,
userCollectionDTO: UserCollectionDTO? = nil) {
self.database = database
self.addCardType = addCardType
self.personDTO = personDTO
self.userCollectionDTO = userCollectionDTO
}

func createViewController() -> UIViewController {
let viewController = AddCardViewController()
let router = AddCardNavigator(viewController)
let interactor = AddCardInteractor()
let viewModel = AddCardViewModel(person: personDTO, userCollection: userCollectionDTO, type: addCardType)
let presenter = AddCardPresenter(view: viewController,
interactor: interactor,
database: database,
navigator: router,
viewModel: viewModel)
viewController.presenter = presenter
return viewController
}
}
26 changes: 26 additions & 0 deletions SWDestinyTrades/Classes/AddCard/Interactor/AddCardInteractor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// AddCardInteractor.swift
// SWDestinyTrades
//
// Created by Diogo Autilio on 30/12/23.
// Copyright © 2023 Diogo Autilio. All rights reserved.
//

import Foundation

protocol AddCardInteractorProtocol {
func retrieveAllCards() async throws -> [CardDTO]
}

final class AddCardInteractor: AddCardInteractorProtocol {

private let service: SWDestinyServiceProtocol

init(service: SWDestinyServiceProtocol = SWDestinyService()) {
self.service = service
}

func retrieveAllCards() async throws -> [CardDTO] {
return try await service.retrieveAllCards()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,18 @@ final class AddCardNavigator: Navigator {
case cardDetail(database: DatabaseProtocol?, with: [CardDTO], card: CardDTO)
}

private weak var navigationController: UINavigationController?
private weak var viewController: UIViewController?

// MARK: - Initializer

init(_ navigationController: UINavigationController?) {
self.navigationController = navigationController
init(_ viewController: UIViewController?) {
self.viewController = viewController
}

// MARK: - Navigator

func navigate(to destination: Destination) {
let viewController = makeViewController(for: destination)
navigationController?.pushViewController(viewController, animated: true)
viewController?.navigationController?.pushViewController(makeViewController(for: destination), animated: true)
}

// MARK: - Private
Expand Down
122 changes: 122 additions & 0 deletions SWDestinyTrades/Classes/AddCard/Presenter/AddCardPresenter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//
// AddCardPresenter.swift
// SWDestinyTrades
//
// Created by Diogo Autilio on 30/12/23.
// Copyright © 2023 Diogo Autilio. All rights reserved.
//

import Foundation

protocol AddCardPresenterProtocol {
func fetchAllCards()
func insert(card: CardDTO)
func doingSearch(_ query: String)
func cardDetailButtonTouched(with card: CardDTO)
}

final class AddCardPresenter: AddCardPresenterProtocol {

private let interactor: AddCardInteractorProtocol
private let database: DatabaseProtocol?
private let navigator: AddCardNavigator
private let viewModel: AddCardViewModel

private weak var view: AddCardViewProtocol?
private var cards = [CardDTO]()

init(view: AddCardViewProtocol,
interactor: AddCardInteractorProtocol,
database: DatabaseProtocol?,
navigator: AddCardNavigator,
viewModel: AddCardViewModel) {
self.view = view
self.interactor = interactor
self.database = database
self.navigator = navigator
self.viewModel = viewModel
}

func fetchAllCards() {
view?.startLoading()
Task { [weak self] in
guard let self else { return }

do {
let allCards = try await self.interactor.retrieveAllCards()
await MainActor.run { [weak self] in
self?.view?.stopLoading()
self?.view?.updateSearchList(allCards)
self?.cards = allCards
}
} catch {
await MainActor.run {
ToastMessages.showNetworkErrorMessage()
LoggerManager.shared.log(event: .allCards, parameters: ["error": error.localizedDescription])
}
}
}
}

func insert(card: CardDTO) {
switch viewModel.type {
case .lent:
insertToLentMe(card: card)
case .borrow:
insertToBorrowed(card: card)
case .collection:
insertToCollection(card: card)
}
}

func doingSearch(_ query: String) {
view?.doingSearch(query)
}

func cardDetailButtonTouched(with card: CardDTO) {
navigator.navigate(to: .cardDetail(database: database, with: cards, card: card))
}

// MARK: - Helpers

private func insertToBorrowed(card: CardDTO) {
if let person = viewModel.person, !person.borrowed.contains(where: { $0.code == card.code }) {
try? database?.update { [weak self] in
person.borrowed.append(card)
self?.showSuccessMessage(card: card)
}
let personDataDict: [String: PersonDTO] = ["personDTO": person]
NotificationCenter.default.post(name: NotificationKey.reloadTableViewNotification, object: nil, userInfo: personDataDict)
} else {
ToastMessages.showInfoMessage(title: "", message: L10n.alreadyAdded)
}
}

private func insertToLentMe(card: CardDTO) {
if let person = viewModel.person, !person.lentMe.contains(where: { $0.code == card.code }) {
try? database?.update { [weak self] in
person.lentMe.append(card)
self?.showSuccessMessage(card: card)
}
let personDataDict: [String: PersonDTO] = ["personDTO": person]
NotificationCenter.default.post(name: NotificationKey.reloadTableViewNotification, object: nil, userInfo: personDataDict)
} else {
ToastMessages.showInfoMessage(title: "", message: L10n.alreadyAdded)
}
}

private func insertToCollection(card: CardDTO) {
if let userCollection = viewModel.userCollection, !userCollection.myCollection.contains(where: { $0.code == card.code }) {
try? database?.update { [weak self] in
userCollection.myCollection.append(card)
self?.showSuccessMessage(card: card)
}
} else {
ToastMessages.showInfoMessage(title: "", message: L10n.alreadyAdded)
}
}

private func showSuccessMessage(card: CardDTO) {
LoadingHUD.show(.labeledSuccess(title: L10n.added, subtitle: card.name))
}
}
7 changes: 7 additions & 0 deletions SWDestinyTrades/Classes/AddCard/View/AddCardView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@

import UIKit

protocol AddCardViewProtocol: AnyObject {
func startLoading()
func stopLoading()
func updateSearchList(_ cards: [CardDTO])
func doingSearch(_ query: String)
}

final class AddCardView: UIView, AddCardViewType {

private let searchBar = SearchBar(frame: .zero)
Expand Down
Loading

0 comments on commit f97eb3a

Please sign in to comment.