123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- //
- // GifListViewController.swift
- import UIKit
- class GifListViewController: UIViewController {
- private var presenter: GifListPresenter = GifListPresenter()
-
- private lazy var collectionView: UICollectionView = {
- let collectionView = UICollectionView(frame: .zero, collectionViewLayout: GifListCollectionViewFlowLayout())
- collectionView.register(GifCollectionViewCell.self, forCellWithReuseIdentifier: GifCollectionViewCell.reuseIdentifier)
- collectionView.keyboardDismissMode = .onDrag
- return collectionView
- }()
-
- private lazy var searchBar: UISearchBar = {
- let sb = UISearchBar()
- sb.delegate = self
- sb.placeholder = "search library..."
- return sb
- }()
-
- /// Indicator view that we expect to show when no data is present
- private lazy var activityIndicator: UIActivityIndicatorView = {
- let aIndicator = UIActivityIndicatorView()
- aIndicator.hidesWhenStopped = true
- return aIndicator
- }()
-
- /// Delay the search by couple of ms so the web devs will like us
- private var delayedWorkItem: DispatchWorkItem?
-
- override func viewDidLoad() {
- super.viewDidLoad()
- self.setupUI()
- self.setupSelf()
- self.presenter.getData(query: "")
- }
-
- private func setupUI() {
-
- self.view.addSubview(self.collectionView)
- self.view.addSubview(self.activityIndicator)
-
- self.initialConstraintSetup()
-
- }
-
- private func setupSelf() {
-
- self.navigationItem.titleView = self.searchBar
-
- presenter.delegate = self
-
- collectionView.delegate = self
- collectionView.dataSource = self
- collectionView.prefetchDataSource = self
-
- }
- }
- // MARK: - Constraints
- extension GifListViewController {
-
- /*!
- Initial constraints setup
- */
- private func initialConstraintSetup() {
-
- self.collectionView.translatesAutoresizingMaskIntoConstraints = false
- self.activityIndicator.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
-
- self.collectionView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
- self.collectionView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor),
- self.collectionView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor),
- self.collectionView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
-
- self.activityIndicator.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
- self.activityIndicator.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
-
- ])
- }
- }
- // MARK: - Presenter delegate
- extension GifListViewController: GifListPresenterDelegate {
-
- func presenterDidReceiveInitialData() {
-
- DispatchQueue.main.async {
-
- self.collectionView.setContentOffset(CGPoint(x: 0, y: self.collectionView.safeAreaInsets.top), animated: false)
- self.collectionView.reloadData()
-
- if self.activityIndicator.isAnimating == true {
- self.activityIndicator.stopAnimating()
- }
-
- }
- }
-
-
- func presenterDidReceiveAdditionalData(at indexPaths: [IndexPath]) {
- DispatchQueue.main.async {
- self.collectionView.insertItems(at: indexPaths)
- }
- }
-
-
- func presenterWillStartLoadingForEmptyData() {
- DispatchQueue.main.async {
- self.activityIndicator.startAnimating()
- }
- }
-
- }
- // MARK: - SearchBar delegate
- extension GifListViewController: UISearchBarDelegate {
- func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
-
- self.delayedWorkItem?.cancel()
-
- delayedWorkItem = DispatchWorkItem { [weak self] in
- self?.presenter.getData(query: searchText)
- }
-
- DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.2, execute: delayedWorkItem!)
- }
- }
- // MARK: - CollectionView delegate and data source
- extension GifListViewController: UICollectionViewDataSource, UICollectionViewDelegate {
-
- func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
- return presenter.gifsList.count
- }
-
- func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
-
- let cell = collectionView.dequeueReusableCell(withReuseIdentifier: GifCollectionViewCell.reuseIdentifier, for: indexPath) as! GifCollectionViewCell
- cell.gif = presenter.gifsList[indexPath.row]
- return cell
- }
-
- }
- extension GifListViewController: UICollectionViewDataSourcePrefetching {
-
- func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
-
- guard presenter.isLoadingNewPage == false else { return }
-
- for indexPath in indexPaths {
- if indexPath.row > presenter.gifsList.count - Constants.GiphyPaginationLimit/2 {
- delayedWorkItem?.cancel()
- presenter.getData(query: self.searchBar.text ?? "")
- break
- }
- }
-
- }
-
-
- }
|