-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHeroDetailInteractor.swift
More file actions
114 lines (96 loc) · 3.17 KB
/
HeroDetailInteractor.swift
File metadata and controls
114 lines (96 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import UIKit
protocol HeroDetailInput {
func reloadData()
func showLoading()
func hideLoading()
func favorite()
func unfavorite()
}
enum DetailCellType {
case poster
case card
}
protocol HeroDetailOutput {
var view: HeroDetailInput! { get set }
var numberOfSections: Int { get }
var hero: MarvelHero { get }
func viewDidLoad()
func numberOfItemsInSection(_ section: Int) -> Int
func cellTypeForSection(_ section: Int) -> DetailCellType
func product(at indexPath: IndexPath) -> HeroProduct
func titleForSection(_ section: Int) -> String
func favoriteButtonTapped()
}
class HeroDetailInteractor: HeroDetailOutput {
private struct Section {
let title: String
let products: [HeroProduct]
}
var view: HeroDetailInput!
let hero: MarvelHero
var numberOfSections: Int {
return sections.count + 1
}
private var sections: [Section] = []
private let dispatchGroup = DispatchGroup()
init(hero: MarvelHero) {
self.hero = hero
}
func viewDidLoad() {
fetchData()
configureFavorite()
}
func numberOfItemsInSection(_ section: Int) -> Int {
return section == 0 ? 1 : sections[section - 1].products.count
}
func cellTypeForSection(_ section: Int) -> DetailCellType {
return section == 0 ? .poster : .card
}
func product(at indexPath: IndexPath) -> HeroProduct {
return sections[indexPath.section - 1].products[indexPath.row]
}
func titleForSection(_ section: Int) -> String {
return sections[section - 1].title
}
func favoriteButtonTapped() {
AppEnvironment.current.favorites.toggle(with: hero.id)
configureFavorite()
}
private func fetchData() {
func addSection(kind: HeroProductsRequest.Kind, products: [HeroProduct]) {
if products.isEmpty { return }
let section = Section(title: kind.sectionTitle, products: products)
self.sections.append(section)
}
view.showLoading()
HeroProductsRequest.Kind.allCases
.forEach { fetchData(ofKind: $0, withUpdate: addSection(kind: products:)) }
dispatchGroup.notify(queue: DispatchQueue.main) { [weak self] in
self?.view.reloadData()
self?.view.hideLoading()
}
}
private func fetchData(ofKind kind: HeroProductsRequest.Kind,
withUpdate update: @escaping (HeroProductsRequest.Kind, [HeroProduct]) -> Void) {
dispatchGroup.enter()
AppEnvironment.current.api.getHeroProducts(kind: kind, heroId: hero.id, limit: 3) { [weak self] result in
update(kind, result.value?.results ?? [])
self?.dispatchGroup.leave()
}
}
private func configureFavorite() {
AppEnvironment.current.favorites.isFavorite(hero.id) ?
view.favorite():
view.unfavorite()
}
}
extension HeroProductsRequest.Kind {
fileprivate var sectionTitle: String {
switch self {
case .comics: return "Comics"
case .series: return "Series"
case .stories: return "Stories"
case .events: return "Events"
}
}
}