<repo_name>laneskell/pokedex_swift<file_sep>/Pokedex/Pokedex/ViewModel/ParsePokedex.swift
//  Created by <NAME> on 06/07/21.

import Foundation

typealias ParseReponseDict = [String: Any]?
typealias PokemonSpriteDict = [String: Any]

class ParsePokedex
{
    func parseAllPokedex(response: ParseReponseDict) -> PokedexModel
    {
        //Faço o unwrap do dicionario enviado pelo request, caso for nulo aciono a função de init para criar model vazio
        guard let response = response else { return PokedexModel() }
        //Coloco os valores do dicionario em variaveis
        //Caso alguma dessas chaves estiverem vazias o valor atribuido na variavel será oque está depois do ??
        let count = response["count"] as? Int ?? 0
        let next = response["next"] as? String ?? ""
        let previous = response["previous"] as? String ?? ""
        //Preciso apenas da quantidade de filhos do array
        let resultList = response["results"] as? [[String: Any]] ?? []
        let results = resultList.count
        return PokedexModel(count: count, next: next, previous: previous, results: results)
    }
    
    
    func parsePokemon(response: ParseReponseDict) -> PokemonModel
    {
        guard let response = response else { return PokemonModel() }
        let name = response["name"] as? String ?? ""
        let id = response["id"] as? Int ?? 0
        let sprites = response["sprites"] as? PokemonSpriteDict
        let urlImage = sprites?["front_default"] as? String ?? ""
        return PokemonModel(id: id, name: name, urlImage: urlImage)
    }
}
<file_sep>/Pokedex/Pokedex/PokedexViewController.swift
//
//  PokedexViewController.swift
//  Pokedex
//
//  Created by <NAME> on 06/07/21.
//

import Foundation
import UIKit

class PokedexViewController: UITableViewController {
    //Variável responsável pelos Requests
    var requestPokedex: ResquestPokedex = ResquestPokedex()
    //Guarda todos os pokemons
    var resultModel: PokedexModel?
    //Guarda a quantidade de resultados que serão exibidos
    var resultCount = 0
    //Guarda as informações de cada pokemon separadamente
    var pokemons = [PokemonModel]()
    //Guarda as imagens de cada pokemon separadamente
    var imagePokemons = [Data]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    //requests todos pokemons
    fileprivate func loadPokedex(url: String?)
    {
        requestPokedex.getAllPokemons(url: url) { (response) in
            switch response
            {
            case .success(let model):
                //Passa o model geral para nossa variavel
                self.resultModel = model
                //Essa função será criada futuramente
                //Pedimos para carregar um pokemon especifico, estamos      passando self.resultCount+1 porque os ids dos pokemons na API    começam a partir do 1
                self.loadPokemon(self.resultCount+1)
                //Incrementamos a quantidade de resultados que serão exibidos
                self.resultCount += model.results
            case .serverError(let description):
                print(description)
            case .timeOut(let description):
                print(description)
            case .noConnection(let description):
                print(description)
            }
        }
    }
    
    //request 1 pokemon
    fileprivate func loadPokemon(_ id: Int)
    {
        requestPokedex.getPokemon(id: id) { (response) in
            switch response
            {
            case .success(let model):
                //Adiciona o pokemon em nossa variavel
                self.pokemons.append(model)
                //Manda fazer load da imagem do pokemon carregado
                self.loadImagePokemon(url: model.urlImage)
            case .serverError(let description):
                print(description)
            case .timeOut(let description):
                print(description)
            case .noConnection(let description):
                print(description)
            }
        }
    }

    //request imagem pokemon
    fileprivate func loadImagePokemon(url: String)
    {
        requestPokedex.getImagePokemon(url: url) { (response) in
            switch response
            {
            case .success(let model):
                //Salva a imagem em nossa variavel
                self.imagePokemons.append(model)
                //If inline
                //Se o ultimo pokemon carregado ainda nao for o ultimo pokemon da lista de todos pokemons que nos temos, mandamos ele carregar o proximo pokemon
                //Se já tiver sido carregado todos os pokemons eu mando atualizar a tabela
                self.pokemons.last!.id < self.resultCount ?
                    self.loadPokemon(self.pokemons.last!.id + 1) :
                    self.tableView.reloadData()
            case .noConnection(let description):
                print(description)
            case .serverError(let description):
                print(description)
            case .timeOut(let description):
                print(description)
            }
        }
    }
    
    //quantos itens na tabela
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
        //Se tiver próxima página será adicionado a quantidade de resultados mais uma célula que irá carregar mais pokemons
        return resultModel?.next == "" ? resultCount : resultCount + 1
    }
    
    //recarrega pokemons
    override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if indexPath.row == resultCount {
            loadPokedex(url:resultModel?.next)
        }
    }

    //visual das celulas da tabela
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        //Se for a ultima célula carrego a célula de load
        if indexPath.row == resultCount {
            guard let cellLoad =    tableView.dequeueReusableCell(withIdentifier: "loadCell", for: indexPath) as? LoadViewCell else {
                return tableView.dequeueReusableCell(withIdentifier: "emptyCell", for: indexPath)
            }
            //Inicio a animação de load
            cellLoad.loadActivity.startAnimating()
            return cellLoad
        }
        //Se tiver tudo ok carrego a célula de pokemon
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? PokemonViewCell else {
            return tableView.dequeueReusableCell(withIdentifier: "emptyCell", for: indexPath)
        }
        //Configuro o visual da célula
        cell.configureCell(withModel: pokemons[indexPath.row],   pokemonSpriteData: imagePokemons[indexPath.row])
        return cell
    }

    
}
<file_sep>/Pokedex/Pokedex/Models/PokedexModel.swift

//
//  PokedexModel.swift
//  Pokedex
//
//  Created by <NAME> on 06/07/21.

import Foundation

struct PokedexModel
{
    let count: Int
    let next: String
    let previous: String
    let results: Int
}

extension PokedexModel
{
    init()
    {
        self.count = 0
        self.next = ""
        self.previous = ""
        self.results = 0
    }
}
<file_sep>/Pokedex/Pokedex/LoadViewCell.swift
//
//  LoadViewCell.swift
//  Pokedex
//
//  Created by <NAME> on 12/05/19.
//  Copyright © 2019 alesefs. All rights reserved.
//

import Foundation
import UIKit

class LoadViewCell: UITableViewCell {
    
    @IBOutlet weak var loadActivity: UIActivityIndicatorView!
    
}
<file_sep>/Pokedex/Pokedex/Models/ServerError.swift
//
//  ServerError.swift
//  Pokedex
//
//  Created by <NAME> on 06/07/21.
//

import Foundation

struct ServerError
{
    let msgError:String
    let statusCode:Int
}
<file_sep>/Pokedex/Pokedex/ViewController.swift
//
//  ViewController.swift
//  Pokedex
//
//  Created by <NAME> on 06/07/21.
//

import UIKit

class ViewController: UIViewController {

    //Variavel responsvel por realizar todos os request
    let request = ResquestPokedex()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        showPokedex()
    }
    
    func showPokedex()
    {
        //Passando nil como URL ele vai pegar a URL padrão
        request.getAllPokemons(url: nil)
        { (response) in
            switch response
            {
            case .success(let model):
                //Print do model
                print("X GET ALL POKEMONS \(model) \n")
                //Chamo a proxima função para exibir um pokemon especifico
                self.showPokemons()
            case .serverError(let description):
                print("Server Erro \(description)")
            case .noConnection(let description):
                print("No Connection \(description)")
            case .timeOut(let description):
                print("Time Out \(description)")
            }
        }
    }
    
    
    func showPokemons()
    {
        //Um id é passado para que busque um pokemon especifico
        request.getPokemon(id: 1)
        { (response) in
            switch response
            {
            case .success(let model):
                //Print do model do pokemon
                print("Y GET POKEMON \(model) \n")
                //Chamo a proxima função para exibir a imagem
                self.showImagePokemon(urlImage: model.urlImage)
            case .serverError(let description):
                print("Server Erro \(description)")
            case .noConnection(let description):
                print("No Connection \(description)")
            case .timeOut(let description):
                print("Time Out \(description)")
            }
        }
    }

    
    func showImagePokemon(urlImage:String)
    {
        //Passa a url da imagem
        request.getImagePokemon(url: urlImage)
        { (response) in
            switch response
            {
            case .success(let model):
                //Print do model da imagem
                print("Z IMAGE POKEMON \(model)")
            case .serverError(let description):
                print("Server Erro \(description)")
            case .noConnection(let description):
                print("No Connection \(description)")
            case .timeOut(let description):
                print("Time Out \(description)")
            }
        }
    }



}

<file_sep>/Pokedex/Pokedex/Models/PokemonModel.swift
//
//  PokemonModel.swift
//  Pokedex
//
//  Created by <NAME> on 06/07/21.

import Foundation

struct PokemonModel
{
    var id: Int
    var name: String
    var urlImage: String
}
extension PokemonModel
{
    init()
    {
        self.id = 0
        self.name = ""
        self.urlImage = ""
    }
}
<file_sep>/Pokedex/Pokedex/PokemonViewCell.swift
//
//  PokemonViewCell.swift
//  Pokedex
//
//  Created by <NAME> on 06/07/21.
//

import Foundation
import UIKit

class PokemonViewCell: UITableViewCell {
    
    
    @IBOutlet weak var imgView: UIImageView!
    @IBOutlet weak var pokemonIdLb: UILabel!
    @IBOutlet weak var pokemonNameLb: UILabel!
    
    
    func configureCell(withModel model: PokemonModel, pokemonSpriteData data:Data) {
        //TODO: Adicionar campos
        self.pokemonIdLb.text = "#\(model.id)"
        self.pokemonNameLb.text = model.name
        self.imgView.image = UIImage(data: data)
    }
    
}
<file_sep>/Pokedex/Pokedex/ViewModel/PokedexResponses.swift
//  Created by <NAME> on 06/07/21.

import Foundation

enum PokedexResponse
{
    case success(model: PokedexModel)
    case serverError(description: ServerError)
    case timeOut(description: ServerError)
    case noConnection(description: ServerError)
}

enum PokemonResponse
{
    case success(model: PokemonModel)
    case serverError(description: ServerError)
    case timeOut(description: ServerError)
    case noConnection(description: ServerError)
}

enum ImageResponse
{
    case success(model: Data)
    case serverError(description: ServerError)
    case timeOut(description: ServerError)
    case noConnection(description: ServerError)
}
