-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSearchMovieViewModel.swift
More file actions
157 lines (127 loc) · 4.61 KB
/
SearchMovieViewModel.swift
File metadata and controls
157 lines (127 loc) · 4.61 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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//
// SearchMovieViewModel.swift
// Smashing-Assignment
//
// Created by 홍준범 on 1/8/26.
//
import Foundation
import Combine
protocol InputOutputProtocol {
associatedtype Input
associatedtype Output
func transform(input: AnyPublisher<Input, Never>) -> Output
}
//
//protocol SearchPeopleViewModelProtocol {
// associatedtype Input
// associatedtype Output
//
// func transform(input: AnyPublisher<Input, Never>) -> Output
//
// var people: [PeopleDTO] { get }
// var numberOfPeople: Int { get }
// func person(at index: Int) -> PeopleDTO?
//
//}
protocol SearchPeopleViewModelProtocol: InputOutputProtocol where Input == SearchPeopleViewModel.Input, Output == SearchPeopleViewModel.Output {
var people: [PeopleDTO] { get }
var numberOfPeople: Int { get }
func person(at index: Int) -> PeopleDTO?
}
class SearchPeopleViewModel: SearchPeopleViewModelProtocol {
enum Input {
case searchTextChanged(String)
case scrollReachedBottom
}
struct Output {
let people = PassthroughSubject<[PeopleDTO], Never>.init()
let error = PassthroughSubject<Error, Never>.init()
let isLoading = CurrentValueSubject<Bool, Never>.init(false)
}
// struct Output {
// let people: PassthroughSubject<[PeopleDTO], Never>
// let error: PassthroughSubject<Error, Never>
// let isLoading: CurrentValueSubject<Bool, Never>
// }
//
// private let output = Output(
// people: PassthroughSubject(),
// error: PassthroughSubject(),
// isLoading: CurrentValueSubject(false)
// )
//
// private let outputPublisher = PassthroughSubject<Output, Never>()
var people: [PeopleDTO] {
return peopleList
}
var numberOfPeople: Int {
return peopleList.count
}
func person(at index: Int) -> PeopleDTO? {
guard index < peopleList.count else { return nil }
return peopleList[index]
}
private let output = Output()
// private let outputPublisher = PassthroughSubject<Output, Never>()
private var cancellables = Set<AnyCancellable>()
private var peopleList: [PeopleDTO] = []
private var currentSearchText = ""
private var currentPage = 1
private var isPeopleFetching = false
func transform(input: AnyPublisher<Input, Never>) -> Output {
input
.filter { if case .searchTextChanged = $0 { return true }
return false }
.compactMap { if case .searchTextChanged(let text) = $0 { return text }
return nil
}
.debounce(for: .seconds(0.3), scheduler: DispatchQueue.main)
.removeDuplicates()
.sink { [weak self] searchText in
self?.handleSearchTextChanged(searchText)
}
.store(in: &cancellables)
input
.filter { if case .scrollReachedBottom = $0 { return true }; return false }
.throttle(for: .seconds(0.3), scheduler: DispatchQueue.main, latest: true)
.sink { [weak self] _ in
self?.handleScrollReachedBottom()
}
.store(in: &cancellables)
return output
}
private func handleSearchTextChanged(_ text: String) {
currentSearchText = text
currentPage = 1
peopleList.removeAll()
guard !text.isEmpty else {
output.people.send([])
return
}
fetchPeople()
}
private func handleScrollReachedBottom() {
print("서버 호출")
fetchPeople()
}
private func fetchPeople() {
guard !isPeopleFetching else { return }
guard !currentSearchText.isEmpty else { return }
isPeopleFetching = true
output.isLoading.send(true)
NetworkProvider<PeopleAPI>
.request(.fetchPeople(name: currentSearchText, page: currentPage), type: PeopleListResponse.self) { [weak self] result in
guard let self = self else { return }
self.isPeopleFetching = false
output.isLoading.send(false)
switch result {
case .success(let response):
self.peopleList.append(contentsOf: response.peopleListResult.peopleList)
output.people.send(self.peopleList)
self.currentPage += 1
case .failure(let error):
output.error.send(error)
}
}
}
}