-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHeroListInteractor.swift
More file actions
100 lines (85 loc) · 3.21 KB
/
HeroListInteractor.swift
File metadata and controls
100 lines (85 loc) · 3.21 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
protocol HeroListInput {
func reloadData()
func showLoading()
func hideLoading()
}
protocol HeroListOutput {
var view: HeroListInput! { get set }
var shouldShowFooter: Bool { get }
var numberOfHeroes: Int { get }
func viewDidLoad()
func viewDidAppear()
func willDisplayCellAtIndex(_ index: Int)
func heroForIndex(_ index: Int) -> MarvelHero
func searchBarDidEndEditingWithText(_ text: String?)
func willDismissSearch()
}
class HeroListInteractor: HeroListOutput {
var view: HeroListInput!
fileprivate var heroes: [MarvelHero] = []
private var searchResults: [MarvelHero] = []
private var isInSearchMode = false
private var paginationGenerator = PageOffsetGenerator()
private var nextPageFetchingInProgress = false
private var allPagesLoaded: Bool { return paginationGenerator.allPagesLoaded && !nextPageFetchingInProgress }
var shouldShowFooter: Bool { return !heroes.isEmpty && !isInSearchMode && !allPagesLoaded }
var numberOfHeroes: Int { return isInSearchMode ? searchResults.count : heroes.count }
func viewDidLoad() {
fetchFirstHeroes()
}
func viewDidAppear() {
view.reloadData()
}
func willDisplayCellAtIndex(_ index: Int) {
guard shouldFetchNextPage(at: index) else { return }
fetchNextHeroes()
}
func heroForIndex(_ index: Int) -> MarvelHero {
let array = isInSearchMode ? searchResults : heroes
return array[index]
}
func willDismissSearch() {
isInSearchMode = false
view.reloadData()
}
func searchBarDidEndEditingWithText(_ text: String?) {
guard let text = text, !text.isEmpty else { return }
isInSearchMode = true
AppEnvironment.current.api.getHeroes(name: text) { [weak self] (result) in
guard let results = result.value?.results else { return }
self?.searchResults = results
self?.view.reloadData()
}
}
private func fetchFirstHeroes() {
view.showLoading()
AppEnvironment.current.api.getHeroes { [weak self] result in
self?.view.hideLoading()
guard let collection = result.value else { return }
self?.paginationGenerator = .init(pageSize: collection.limit,
maxItemsCount: collection.total,
currentOffset: collection.limit)
self?.heroes = collection.results
self?.view.reloadData()
}
}
private func fetchNextHeroes() {
nextPageFetchingInProgress = true
AppEnvironment.current.api.getHeroes(offset: paginationGenerator.next()) { [weak self] result in
switch result {
case .success(let collection):
self?.heroes += collection.results
self?.view.reloadData()
case .failure:
self?.paginationGenerator.rewind()
}
self?.nextPageFetchingInProgress = false
}
}
private func shouldFetchNextPage(at index: Int) -> Bool {
return index + 1 >= heroes.count &&
!nextPageFetchingInProgress &&
!allPagesLoaded &&
!isInSearchMode
}
}