Skip to content

Commit

Permalink
Add UserCollectionPresenter
Browse files Browse the repository at this point in the history
  • Loading branch information
dogo committed Mar 23, 2024
1 parent c145614 commit f51026d
Show file tree
Hide file tree
Showing 5 changed files with 375 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,6 @@ final class UserCollectionViewController: UIViewController {
return config
}

private func addToCollection(carDTO: CardDTO) {
let user = getUserCollection()
try? database?.update {
let predicate = NSPredicate(format: "code == %@", carDTO.code)
if let index = user.myCollection.index(matching: predicate) {
let newCard = user.myCollection[index]
newCard.quantity += 1
} else {
user.myCollection.append(carDTO)
}
}
}

private func getUserCollection() -> UserCollectionDTO {
var user = UserCollectionDTO()
try? database?.fetch(UserCollectionDTO.self, predicate: nil, sorted: nil) { [weak self] results in
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
//
// UserCollectionPresenter.swift
// SWDestinyTrades
//
// Created by Diogo Autilio on 22/03/24.
// Copyright © 2024 Diogo Autilio. All rights reserved.
//

import Foundation
import FTPopOverMenu
import UIKit

protocol UserCollectionPresenterProtocol {
func setNavigationTitle()
func setupNavigationItems(completion: ([UIBarButtonItem]?, [UIBarButtonItem]?) -> Void)
func loadDataFromRealm()
func navigateToCardDetail(cardList: [CardDTO], card: CardDTO)
func navigateToAddCard()
}

final class UserCollectionPresenter: UserCollectionPresenterProtocol {

private weak var controller: UserCollectionViewControllerProtocol?
private let dispatchQueue: DispatchQueueType
private let database: DatabaseProtocol?
private let navigator: UserCollectionNavigator
private var currentSortIndex = 0

init(controller: UserCollectionViewControllerProtocol,
dispatchQueue: DispatchQueueType = DispatchQueue.main,
database: DatabaseProtocol?,
navigator: UserCollectionNavigator) {
self.controller = controller
self.dispatchQueue = dispatchQueue
self.database = database
self.navigator = navigator
}

func setNavigationTitle() {
controller?.setNavigationTitle(L10n.myCollection)
}

func setupNavigationItems(completion: ([UIBarButtonItem]?, [UIBarButtonItem]?) -> Void) {
let shareBarItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(share(_:)))
let addCardBarItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(navigateToAddCard))

let rightBarButtonItems = [addCardBarItem, shareBarItem]
let leftBarButtonItem = UIBarButtonItem(image: Asset.NavigationBar.icSort.image, style: .plain, target: self, action: #selector(sort(_:event:)))

completion([leftBarButtonItem], rightBarButtonItems)
}

func loadDataFromRealm() {
let user = getUserCollection()
controller?.updateTableViewData(collection: user)
controller?.sort(currentSortIndex)
}

func navigateToCardDetail(cardList: [CardDTO], card: CardDTO) {
navigator.navigate(to: .cardDetail(database: database, with: cardList, card: card))
}

@objc
func navigateToAddCard() {
navigator.navigate(to: .addCard(database: database, with: getUserCollection()))
}

private func createDatabase(object: UserCollectionDTO) {
try? database?.save(object: object)
}

private func popOverMenuConfiguration() -> FTConfiguration {
let config = FTConfiguration()
config.backgoundTintColor = ColorPalette.appTheme
config.borderColor = ColorPalette.appTheme
config.menuSeparatorColor = .lightGray
config.textColor = .white
config.textAlignment = .center
return config
}

private func getUserCollection() -> UserCollectionDTO {
var user = UserCollectionDTO()
try? database?.fetch(UserCollectionDTO.self, predicate: nil, sorted: nil) { [weak self] results in
if let userCollection = results.first {
user = userCollection
} else {
self?.createDatabase(object: user)
}
}
return user
}

@objc
private func share(_ sender: UIBarButtonItem) {
var collectionList = ""

if let cardList = controller?.getCardList() {
for card in cardList {
collectionList.append(String(format: "%d %@\n", card.quantity, card.name))
}
}

let activityVC = UIActivityViewController(activityItems: [
SwdShareProvider(subject: L10n.myCollection, text: collectionList),
L10n.shareText
], applicationActivities: nil)

activityVC.excludedActivityTypes = [
.saveToCameraRoll,
.postToFlickr,
.postToVimeo,
.assignToContact,
.addToReadingList,
.postToFacebook
]

activityVC.popoverPresentationController?.barButtonItem = sender
dispatchQueue.globalAsync { [weak self] in
self?.dispatchQueue.async {
self?.controller?.presentViewController(activityVC, animated: true)
}
}
}

@objc
private func sort(_ sender: UIBarButtonItem, event: UIEvent) {
FTPopOverMenu.showForEvent(event: event,
with: [L10n.aToZ, L10n.cardNumber, L10n.color],
config: popOverMenuConfiguration(),
done: { [weak self] selectedIndex in
self?.controller?.sort(selectedIndex)
self?.currentSortIndex = selectedIndex
}, cancel: {})
}
}

extension UserCollectionPresenter: UserCollectionProtocol {

func stepperValueChanged(newValue: Int, card: CardDTO) {
try? database?.update {
card.quantity = newValue
}
}

func remove(at index: Int) {
try? database?.update { [weak self] in
self?.getUserCollection().myCollection.remove(at: index)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// UserCollectionViewControllerProtocol.swift
// SWDestinyTrades
//
// Created by Diogo Autilio on 22/03/24.
// Copyright © 2024 Diogo Autilio. All rights reserved.
//

import Foundation
import UIKit

protocol UserCollectionViewControllerProtocol: AnyObject {
func setNavigationTitle(_ title: String)
func updateTableViewData(collection: UserCollectionDTO)
func sort(_ selectedIndex: Int)
func getCardList() -> [CardDTO]?
func presentViewController(_ controller: UIViewController, animated: Bool)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// UserCollectionViewControllerSpy.swift
// SWDestinyTradesTests
//
// Created by Diogo Autilio on 22/03/24.
// Copyright © 2024 Diogo Autilio. All rights reserved.
//

import Foundation
import UIKit

@testable import SWDestinyTrades

final class UserCollectionViewControllerSpy: UIViewController, UserCollectionViewControllerProtocol, UserCollectionProtocol {

private(set) var didCallSetNavigationTitle = [String]()
func setNavigationTitle(_ title: String) {
didCallSetNavigationTitle.append(title)
}

private(set) var didCallUpdateTableViewData = [UserCollectionDTO]()
func updateTableViewData(collection: UserCollectionDTO) {
didCallUpdateTableViewData.append(collection)
}

private(set) var didCallSort = [Int]()
func sort(_ selectedIndex: Int) {
didCallSort.append(selectedIndex)
}

private(set) var didCallGetCardListCount = 0
var cardList: [CardDTO]? = [.stub()]
func getCardList() -> [CardDTO]? {
didCallGetCardListCount += 1
return cardList
}

private(set) var didCallPresentViewController = [(controller: UIViewController, animated: Bool)]()
func presentViewController(_ controller: UIViewController, animated: Bool) {
didCallPresentViewController.append((controller, animated))
}

private(set) var didCallStepperValueChangedValues: [(newValue: Int, card: CardDTO)] = []
func stepperValueChanged(newValue: Int, card: CardDTO) {
didCallStepperValueChangedValues.append((newValue, card))
}

private(set) var didCallRemoveValues: [Int] = []
func remove(at index: Int) {
didCallRemoveValues.append(index)
}

private(set) var didCallUpdateSetList = [SetDTO]()
func updateSetList(_ setList: [SetDTO]) {
didCallUpdateSetList.append(contentsOf: setList)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
//
// UserCollectionPresenterTests.swift
// SWDestinyTradesTests
//
// Created by Diogo Autilio on 22/03/24.
// Copyright © 2024 Diogo Autilio. All rights reserved.
//

import UIKit
import XCTest

@testable import SWDestinyTrades

final class UserCollectionPresenterTests: XCTestCase {

private var sut: UserCollectionPresenter!
private var navigationController: UINavigationControllerMock!
private var controller: UserCollectionViewControllerSpy!
private var navigator: UserCollectionNavigator!
private var database: RealmDatabase?

override func setUp() {
super.setUp()
controller = UserCollectionViewControllerSpy()
navigationController = UINavigationControllerMock(rootViewController: controller)
database = RealmDatabaseHelper.createMemoryDatabase(identifier: #function)
navigator = UserCollectionNavigator(controller)
sut = UserCollectionPresenter(controller: controller,
dispatchQueue: DispatchQueueSpy(),
database: database,
navigator: navigator)
}

override func tearDown() {
navigator = nil
navigationController = nil
controller = nil
database = nil
sut = nil
super.tearDown()
}

// MARK: - Test setNavigationTitle

func test_setNavigationTitle() {
sut.setNavigationTitle()

XCTAssertEqual(controller.didCallSetNavigationTitle.count, 1)
XCTAssertEqual(controller.didCallSetNavigationTitle[0], "My Collection")
}

// MARK: - Test setupNavigationItems

func test_setupNavigationItems() {
var expectedItems: ([UIBarButtonItem]?, [UIBarButtonItem]?)?
sut.setupNavigationItems { leftItems, rightItems in
expectedItems = (leftItems, rightItems)
}

XCTAssertEqual(expectedItems?.0?.count, 1)
XCTAssertEqual(expectedItems?.1?.count, 2)
}

// MARK: - Test sort

func test_sort() {
var barButtonItems: ([UIBarButtonItem]?, [UIBarButtonItem]?)?
sut.setupNavigationItems { leftItems, rightItems in
barButtonItems = (leftItems, rightItems)
}
let sortButton = barButtonItems?.0?[0]
_ = sortButton?.target?.perform(sortButton!.action, with: nil)

// XCTAssertTrue(navigationController.currentPushedViewController is AddCardViewController)
}

// MARK: - Test addCard

func test_addCard() {
var barButtonItems: ([UIBarButtonItem]?, [UIBarButtonItem]?)?
sut.setupNavigationItems { leftItems, rightItems in
barButtonItems = (leftItems, rightItems)
}
let addCardButton = barButtonItems?.1?[0]
_ = addCardButton?.target?.perform(addCardButton!.action, with: nil)

XCTAssertTrue(navigationController.currentPushedViewController is AddCardViewController)
}

// MARK: - Test share

func test_share() {
var barButtonItems: ([UIBarButtonItem]?, [UIBarButtonItem]?)?
sut.setupNavigationItems { leftItems, rightItems in
barButtonItems = (leftItems, rightItems)
}
let shareButton = barButtonItems?.1?[1]
_ = shareButton?.target?.perform(shareButton!.action, with: nil)

XCTAssertEqual(controller.didCallPresentViewController.count, 1)
}

// MARK: - Test loadDataFromRealm

func test_loadDataFromRealm() {
sut.loadDataFromRealm()

XCTAssertEqual(controller.didCallUpdateTableViewData.count, 1)
XCTAssertNotNil(controller.didCallUpdateTableViewData[0])

XCTAssertEqual(controller.didCallSort.count, 1)
XCTAssertEqual(controller.didCallSort[0], 0)
}

// MARK: - Test navigateToCardDetail

func test_navigateToCardDetail() {
sut.navigateToCardDetail(cardList: [.stub()], card: .stub())

XCTAssertTrue(navigationController.currentPushedViewController is CardDetailViewController)
}

// MARK: - Test navigateToAddCard

func test_navigateToAddCard() {
sut.navigateToAddCard()

XCTAssertTrue(navigationController.currentPushedViewController is AddCardViewController)
}

// MARK: - Test stepperValueChanged

func test_stepperValueChanged() {
let card: CardDTO = .stub()
sut.stepperValueChanged(newValue: 4, card: card)

XCTAssertEqual(card.quantity, 4)
}

// MARK: - Test remove

func test_remove() {
// XCTAssertEqual(deckDTO.list.count, 22)

// sut.remove(at: 0)

// XCTAssertEqual(deckDTO.list.count, 21)
}
}

0 comments on commit f51026d

Please sign in to comment.