Advertisement
Guest User

Untitled

a guest
Oct 18th, 2019
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.25 KB | None | 0 0
  1. import UIKit
  2. import Delayed
  3. import RxSwift
  4. import RxCocoa
  5. import RxDataSources
  6.  
  7.  
  8. protocol MoviesCollectionViewProtocol:AnyObject {
  9. func didSelect(movie : Movie) //todo pass selected index and/or object
  10. }
  11.  
  12. class MoviesCollectionView: UIView {
  13.  
  14. let PADDING : Int = 8
  15. let SEARCHBAR_HEIGHT: Int = 60
  16. let disposeBag = DisposeBag()
  17.  
  18. var page = 1
  19. var isLoading = false
  20. var lastMoviesCount = 0
  21.  
  22. var collectionView: UICollectionView!
  23. var refreshControl : UIRefreshControl!
  24. var searchbar : UISearchBar!
  25. var searchString : String? = nil
  26. weak var delegate :MoviesCollectionViewProtocol?
  27.  
  28.  
  29. var movies: [Movie] = []
  30. var sections: [MoviesSection] = []
  31. var dataSource : RxCollectionViewSectionedAnimatedDataSource<MoviesSection>!
  32. var dataSubject : PublishSubject<[MoviesSection]>!
  33.  
  34. func dataFiltered()->[MoviesSection] {
  35.  
  36. let sectionTitle = "Trending"
  37. let uniqueMovies = uniq(movies)
  38.  
  39. guard let searchString = searchString else {
  40. return [MoviesSection(header: sectionTitle, items: uniqueMovies)]
  41. }
  42.  
  43. guard searchString.count > 2 else{
  44. return [MoviesSection(header: sectionTitle, items: uniqueMovies)]
  45. }
  46.  
  47. let string = searchString.lowercased()
  48.  
  49. let moviesFiltered = uniqueMovies.filter({ (movie) -> Bool in
  50. return movie.title.lowercased().contains(string) || movie.description.lowercased().contains(string)
  51. })
  52.  
  53. return [MoviesSection(header: sectionTitle, items: moviesFiltered)]
  54. }
  55.  
  56. }
  57.  
  58. extension MoviesCollectionView{
  59.  
  60. func setupRx(){
  61.  
  62. let dataSubject = PublishSubject<[MoviesSection]>()
  63. let dataSource = RxCollectionViewSectionedAnimatedDataSource<MoviesSection>(
  64. configureCell:{ dataSource, tableView, indexPath, item in
  65. let cell = tableView.dequeueReusableCell(withReuseIdentifier: self.cellName(), for: indexPath) as! MovieViewCell
  66.  
  67. cell.setupWithMovie(item)
  68.  
  69. return cell
  70. })
  71.  
  72. dataSource.canMoveItemAtIndexPath = { dataSource, indexPath in
  73. return true
  74. }
  75. dataSubject
  76. .bind(to: collectionView.rx.items(dataSource: dataSource))
  77. .disposed(by: disposeBag)
  78.  
  79. self.dataSubject = dataSubject
  80. self.dataSource = dataSource
  81.  
  82. }
  83. }
  84.  
  85.  
  86. extension MoviesCollectionView : UISearchBarDelegate{
  87.  
  88. func setupSearch(){
  89. let searchBar = UISearchBar(frame: .zero)
  90. searchBar.searchBarStyle = .prominent
  91. searchBar.tintColor = .white
  92. searchBar.barTintColor = .white
  93. searchBar.delegate = self
  94. searchBar.placeholder = "Filter..."
  95. searchBar.isTranslucent = true
  96. searchBar.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.75)
  97. searchBar.backgroundImage = UIImage()
  98.  
  99. if let txfSearchField = searchBar .value(forKey: "_searchField") as? UITextField {
  100. txfSearchField.backgroundColor = .clear
  101. }
  102.  
  103.  
  104. addSubview(searchBar)
  105.  
  106. searchBar.snp_makeConstraints { (make) in
  107. make.top.equalTo(snp_topMargin)
  108. make.bottom.lessThanOrEqualTo(snp_topMargin).offset(SEARCHBAR_HEIGHT)
  109. make.left.equalTo(0)
  110. make.width.equalToSuperview()
  111. }
  112.  
  113. self.searchbar = searchBar
  114. }
  115.  
  116. func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
  117.  
  118. if searchText == "" {
  119. cancelSearching()
  120. endEditing(true)
  121. }
  122.  
  123. syncCollectionView()
  124. scrollToTop()
  125. }
  126.  
  127.  
  128.  
  129. func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
  130. endEditing(true)
  131. }
  132.  
  133. func cancelSearching(){
  134. DispatchQueue.main.async {
  135. self.searchbar.resignFirstResponder()
  136. self.searchbar.text = ""
  137. }
  138.  
  139. }
  140.  
  141.  
  142. }
  143.  
  144. extension MoviesCollectionView {
  145.  
  146. func setup(){
  147. setupCollectionView()
  148. setupRx()
  149. setupPullToRefresh()
  150. setupSearch()
  151. }
  152.  
  153. func setupCollectionView(){
  154.  
  155. let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
  156.  
  157. collectionView.backgroundColor = .clear
  158. collectionView.rx.setDelegate(self).disposed(by: disposeBag)
  159.  
  160.  
  161. collectionView.register(MovieViewCell.self, forCellWithReuseIdentifier: cellName())
  162.  
  163. let top = CGFloat(SEARCHBAR_HEIGHT + PADDING)
  164. collectionView.contentInset = UIEdgeInsets(top: top , left: CGFloat(0), bottom: CGFloat(0), right: CGFloat(0))
  165.  
  166. addSubview(collectionView)
  167.  
  168. collectionView.snp_makeConstraints { (make) in
  169. make.edges.equalToSuperview()
  170. make.center.equalToSuperview()
  171. }
  172.  
  173. self.collectionView = collectionView
  174.  
  175. }
  176.  
  177. func setupPullToRefresh(){
  178.  
  179. refreshControl = UIRefreshControl()
  180. refreshControl.addTarget(self, action:
  181. #selector(self.handleRefresh),for: .valueChanged)
  182.  
  183. collectionView.addSubview(refreshControl)
  184. }
  185.  
  186. }
  187.  
  188. extension MoviesCollectionView {
  189.  
  190. @objc func handleRefresh(_ refreshControl: UIRefreshControl) {
  191. loadMovies()
  192. }
  193.  
  194. @objc func loadMovies(){
  195.  
  196. guard !isLoading else {
  197. return
  198. }
  199. isLoading = true
  200. page+=1
  201.  
  202. Services.api.getMoviesList(from : page) { [weak self] (movies) in
  203. self?.isLoading = false
  204. self?.refreshControl.endRefreshing()
  205. self?.movies.append(contentsOf: movies)
  206.  
  207. self?.syncCollectionView()
  208. }
  209. }
  210.  
  211. @objc func isInfiniteFeed()->Bool{
  212. return true
  213. }
  214.  
  215. @objc func cellName()->String{
  216. return "MovieCell"
  217. }
  218.  
  219. func syncCollectionView() {
  220. Kron.debounceLast(timeOut: 0.25, resetKey: self) { (key, ctx) in
  221. self._syncCollectionView()
  222. }
  223.  
  224. }
  225.  
  226. func _syncCollectionView(){
  227. searchString = searchbar.text
  228. dataSubject.onNext(dataFiltered())
  229. }
  230.  
  231. func scrollToTop(){
  232. if dataFiltered()[0].items.count > 1 {
  233. collectionView.scrollToItem(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
  234. }
  235. }
  236. }
  237.  
  238.  
  239. extension MoviesCollectionView: UICollectionViewDelegate {
  240.  
  241. func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
  242.  
  243. let movie = dataSource[indexPath]
  244. delegate?.didSelect(movie: movie)
  245. }
  246.  
  247. func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
  248.  
  249. if isInfiniteFeed() && indexPath.row == movies.count - 2 {
  250. loadMovies()
  251. }
  252. }
  253. }
  254.  
  255. extension MoviesCollectionView: UICollectionViewDelegateFlowLayout {
  256.  
  257.  
  258. func collectionView(_ collectionView: UICollectionView,
  259. layout collectionViewLayout: UICollectionViewLayout,
  260. sizeForItemAt indexPath: IndexPath) -> CGSize {
  261.  
  262. let width = Int(collectionView.bounds.size.width) - ( PADDING * 2 )
  263. let height = Services.theme.CELLS_HEIGHT
  264. return CGSize( width: width , height: height )
  265. }
  266. func collectionView(_ collectionView: UICollectionView,
  267. layout collectionViewLayout: UICollectionViewLayout,
  268. minimumLineSpacingForSectionAt section: Int) -> CGFloat {
  269. return CGFloat(PADDING)
  270. }
  271.  
  272. func collectionView(_ collectionView: UICollectionView,
  273. layout collectionViewLayout: UICollectionViewLayout,
  274. minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
  275. return 0
  276. }
  277.  
  278. func collectionView(_ collectionView: UICollectionView,
  279. layout collectionViewLayout: UICollectionViewLayout,
  280. insetForSectionAt section: Int) -> UIEdgeInsets {
  281. return UIEdgeInsets.init(top: 8, left: 8, bottom: 8, right: 8)
  282. }
  283. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement