-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
375 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
151 changes: 151 additions & 0 deletions
151
SWDestinyTrades/Classes/UserCollection/Presenter/UserCollectionPresenter.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
SWDestinyTrades/Classes/UserCollection/Protocols/UserCollectionViewControllerProtocol.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
57 changes: 57 additions & 0 deletions
57
SWDestinyTradesTests/Screens/UserCollection/Doubles/UserCollectionViewControllerSpy.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
149 changes: 149 additions & 0 deletions
149
SWDestinyTradesTests/Screens/UserCollection/Presenter/UserCollectionPresenterTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |