<repo_name>dangduycuong/MasterSearch<file_sep>/TestFilter/TestFilter/BaseRouter/BaseNetwork.swift
//
//  BaseNetwork.swift
//  TestFilter
//
//  Created by <NAME> on 2/4/20.
//  Copyright © 2020 <NAME>. All rights reserved.
//

import UIKit
import SwiftyJSON

enum HTTPMethod {
    case get
    case post
    case put
    
    var value: String {
        get {
            switch self {
            case .get:
                return "GET"
            case .post:
                return "POST"
            case .put:
                return "PUT"
            }
        }
    }
}

enum ServerAPI: NSInteger {
    case Youtube_v3_API //https://rapidapi.com/ytdlfree/api/youtube-v31/endpoints
    case VivaCityDocumentationAPIDocumentation //https://rapidapi.com/din-dins-club-limited-din-dins-club-limited-default/api/viva-city-documentation
}

enum Result<Success, Error: Swift.Error> {
    case success(Success)
    case failure(Error)
}

// override the Result.get() method
extension Result {
    func get() throws -> Success {
        switch self {
        case .success(let value):
            return value
        case .failure(let error):
            throw error
        }
    }
}

// use generics - this is where you can decode your data
extension Result where Success == Data {
    func decoded<T: Decodable>(using decoder: JSONDecoder = .init()) throws -> T {
        let data = try get()
        return try decoder.decode(T.self, from: data)
    }
}

class BaseNetwork {
//    static let shared: BaseNetwork = BaseNetwork()
    
    static var SERVER: ServerAPI = ServerAPI.Youtube_v3_API
    
    var fullURL: URL {
        switch (BaseNetwork.SERVER) {
        case .Youtube_v3_API:
            return  URL.init(string: "\(baseURLString)\(contextPathString)\(path)")!
        case .VivaCityDocumentationAPIDocumentation:
            return  URL.init(string: "\(baseURLString)\(contextPathString)\(path)")!
        }
    }
    
    var fullStringURL: String {
        switch (BaseNetwork.SERVER) {
        case .Youtube_v3_API:
            return  "\(baseURLString)\(contextPathString)\(path)"
        case .VivaCityDocumentationAPIDocumentation:
            return  "\(baseURLString)\(contextPathString)\(path)"
        }
    }
    
    var serverURL: URL {
        switch (BaseNetwork.SERVER) {
        case .Youtube_v3_API:
            return  URL.init(string: "\(baseURLString)\(contextPathString)")!
        case .VivaCityDocumentationAPIDocumentation:
            return  URL.init(string: "\(baseURLString)\(contextPathString)")!
        }
    }
    
    var baseURLString: String {
        switch (BaseNetwork.SERVER) {
        case .Youtube_v3_API:
            return "https://youtube-v31.p.rapidapi.com" //https://viva-city-documentation.p.rapidapi.com
        case .VivaCityDocumentationAPIDocumentation:
            return "https://viva-city-documentation.p.rapidapi.com"
        }
    }
    
    var contextPathString: String {
        switch (BaseNetwork.SERVER) {
        case .Youtube_v3_API:
            return ""
        case .VivaCityDocumentationAPIDocumentation:
            return "/venue-i18n/"
        }
    }
    
    var basePORTString: UInt16 {
        switch (BaseNetwork.SERVER) {
        case .Youtube_v3_API:
            return 8761
        case .VivaCityDocumentationAPIDocumentation:
            return 9898
        }
    }
    
    var path: String {
        fatalError("[\(#function))] Must be overridden in subclass")
    }
    
    var method: HTTPMethod {
        fatalError("[\(#function))] Must be overridden in subclass")
    }
    
    var parameters: [URLQueryItem]? {
        fatalError("[\(#function))] Must be overridden in subclass")
    }
    
    var headerFields: [String: String]? {
        fatalError("[\(#function))] Must be overridden in subclass")
    }
    
    func getData(completion: @escaping(Result<Data, Error>) -> Void) {
        var builder = URLComponents(string: fullStringURL)
        builder?.queryItems = parameters
        guard let url = builder?.url else { return }
        var request  = URLRequest(url: url)
        request.httpMethod = method.value
        //        let boundary = "Boundary-\(UUID().uuidString)"
        //    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
        request.cachePolicy = .useProtocolCachePolicy
        request.timeoutInterval = 30
        
        request.allHTTPHeaderFields = headerFields
        let dataTask = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
            print("fullURL: ", self.fullStringURL)
            print("params: ", url.queryDictionary as Any)
            print("header: ", self.headerFields as Any)
            print("json: ")
            if let error = error {
                completion(.failure(error))
                return
            }
            if let response = response {
                let httpResponse = response as! HTTPURLResponse
                let status = httpResponse.statusCode
                
                switch status {
                case 200:
                break //print("Thanh cong")
                default:
                    break
                }
                
                if !(200...299).contains(httpResponse.statusCode) && !(httpResponse.statusCode == 304) {
                    if let httpError = error {// ... convert httpResponse.statusCode into a more readable error
                        //                        completion(.failure(httpError as! Error))
                        completion(.failure(httpError))
                    }
                }
                
                if let data = data {
                    completion(.success(data))
                    if let json = try? JSON(data: data) {
                        print(json as Any)
                    }
                }
            }
        })
        dataTask.resume()
    }
}




//class BaseNetwork {
//    static let shared: BaseNetwork = BaseNetwork()
//
//    func getDataFromAPI<T: Codable>(url: URL, completion: @escaping(T)->()) {
//        URLSession.shared.dataTask(with: url) { (data, response, error) in
//            if error != nil {
//                print(error as Any)
//                return
//            }
//
//            guard let data = data else { return }
//
//            do {
//                let data = try JSONDecoder().decode(T.self, from: data)
//
//                DispatchQueue.main.async {
//                    completion(data)
//                    print("urlRequest: ", url)
//    //                    if let data = data, let dataString = String(data: data, encoding: .utf8) {
//    //                        print("Response json:\n", dataString)
//    //                    }
//                }
//            } catch let error {
//                print("decode error: ", error)
//            }
//            }.resume()
//    }
//}
//
//////
//////  BaseURL.swift
//////  GenericsAPI
//////
//////  Created by <NAME> on 1/3/20.
//////  Copyright © 2020 <NAME>. All rights reserved.
//////
////
//
//enum URLFactory: String {
//    case login
//    case chi_tiet
//    case thiet_bi
//    case diem_xung_yeu
//    case search
//
//    var URL: URL {
//        func generalUrlComponent(host: String, port: Int?, path: String, queryItems: [URLQueryItem]) -> URL {
//            var urlComponents = URLComponents()
//            urlComponents.scheme = "http"
//            urlComponents.host = host
//            urlComponents.port = port
//            urlComponents.path = path
//            urlComponents.queryItems = queryItems
//
//            return urlComponents.url!
//        }
//
//        //path of url
//        switch self {
//        case .chi_tiet:
//            return generalUrlComponent(host: "10.240.232.79",
//                                       port: 145,
//                                       path: "",
//                                       queryItems: [URLQueryItem(name: "", value: "")])
//        case .thiet_bi:
//            return generalUrlComponent(host: "", port: 8060, path: "", queryItems: [URLQueryItem(name: "", value: "")])
//        case .diem_xung_yeu:
//            return generalUrlComponent(host: "10.240.232.79", port: 8060, path: "/QLCTKT/rest/bts360Controller/getListCriticalPoint", queryItems: [
//                URLQueryItem(name: "fromDate", value: "04/10/2019"),
//                URLQueryItem(name: "toDate", value: "04/10/2019"),
//                URLQueryItem(name: "pageIndex", value: "0"),
//                URLQueryItem(name: "rowPage", value: "10")
//                ])
//        case .login:
//            return generalUrlComponent(host: "10.240.232.68", port: 8060, path: "/QLCTKT/rest/authen/login", queryItems: [
//                URLQueryItem(name: "username", value: "UserDefaults.standard.string(forKey: UserDefaultKeys.userName)"),
//                URLQueryItem(name: "password", value: "UserDefaults.standard.string(forKey: UserDefaultKeys.password)"),
//                URLQueryItem(name: "imeiMoblie", value: "IOS")
//                ])
//        case .search:
//            return generalUrlComponent(host: "www.thecocktaildb.com", port: nil, path: "/api/json/v1/1/search.php", queryItems: [
//                URLQueryItem(name: "rowPage", value: "10")
//                ])
//        }
//    }
//}
<file_sep>/TestFilter/TestFilter/Controller/YoutubeSuggestViewController.swift
//
//  YoutubeSuggestViewController.swift
//  TestFilter
//
//  Created by <NAME> on 3/11/21.
//  Copyright © 2021 <NAME>. All rights reserved.
//

import UIKit
import SwiftyJSON

class YoutubeSuggestViewController: BaseViewController {
    
    @IBOutlet weak var tableView: UITableView!
    
    var listSuggestVideo = [SuggestedVideosModel]()
    var params = [URLQueryItem]()
    var data = SuggestedVideosModel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.register(SuggestedVideosCell.nib(), forCellReuseIdentifier: SuggestedVideosCell.identifier())
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        callAPI(apiType: .suggestedVideos)
    }
    
    func validateParams(apiType: Youtubev3APIType) {
        params.removeAll()
        switch apiType {
        case .suggestedVideos:
            let relatedToVideoId = data.id?.videoId
            params = [
                //Required Parameters
                URLQueryItem(name: "relatedToVideoId", value: relatedToVideoId),
                URLQueryItem(name: "part", value: "id,snippet"),
                URLQueryItem(name: "type", value: "video"),
                //Optional Parameters
                URLQueryItem(name: "maxResults", value: "50"),
            ]
        default:
            break
        }
        
    }
    
    func callAPI(apiType: Youtubev3APIType) {
        validateParams(apiType: apiType)
        switch apiType {
        case .suggestedVideos:
            suggestedVideos()
        case .search:
            break
        }
    }
    
    func suggestedVideos() {
        showLoading()
        // all properties params is OPTIONAL
        let params: [URLQueryItem] = [
            //Required Parameters
            URLQueryItem(name: "relatedToVideoId", value: "7ghhRHRP6t4"),
            URLQueryItem(name: "part", value: "id,snippet"),
            URLQueryItem(name: "type", value: "video"),
            //Optional Parameters
            URLQueryItem(name: "maxResults", value: "50"),
        ]
        
        Youtubev3Router.init(endpoint: .suggestedVideos(params: params)).getData(completion: { [weak self] result in
            self?.hideLoading()
            switch result {
            case .success(let data):
                if let json = try? JSON(data: data) {
                    let array = [SuggestedVideosModel](byJSON: json["items"])
                    self?.listSuggestVideo = array
                    DispatchQueue.main.async {
                        self?.tableView.reloadData()
                    }
                }
            default:
                print("tram cam")
            }
        })
    }
    
}

extension YoutubeSuggestViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return listSuggestVideo.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: SuggestedVideosCell.identifier(), for: indexPath) as! SuggestedVideosCell
        cell.data = listSuggestVideo[indexPath.row]
        cell.fillData()
        
        return cell
    }
    
}

extension YoutubeSuggestViewController: UITableViewDelegate {
    
}
<file_sep>/TestFilter/TestFilter/Controller/Youtubev3VC.swift
//
//  Youtubev3VC.swift
//  TestFilter
//
//  Created by <NAME> on 2/4/20.
//  Copyright © 2020 <NAME>. All rights reserved.
//

import UIKit
import SwiftyJSON
import AVKit
import AVFoundation

enum Youtubev3APIType {
    case suggestedVideos
    case search
}

class Youtubev3VC: BaseViewController {
    
    @IBOutlet weak var searchBar: UISearchBar!
    @IBOutlet weak var tableView: UITableView!
    
    var listSuggestVideo = [SuggestedVideosModel]()
    var listVideo = [SuggestedVideosModel]()
    var params = [URLQueryItem]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.register(SearchYoutubeCell.nib(), forCellReuseIdentifier: SearchYoutubeCell.identifier())
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
//        callAPI(apiType: .suggestedVideos)
        
    }
    
    func validateParams(apiType: Youtubev3APIType) {
        params.removeAll()
        switch apiType {
        case .suggestedVideos:
            params = [
                //Required Parameters
                URLQueryItem(name: "relatedToVideoId", value: "7ghhRHRP6t4"),
                URLQueryItem(name: "part", value: "id,snippet"),
                URLQueryItem(name: "type", value: "video"),
                //Optional Parameters
                URLQueryItem(name: "maxResults", value: "50"),
            ]
        case .search:
            let q = searchBar.text
            params = [
                //Required Parameters
            
                URLQueryItem(name: "q", value: q),
                URLQueryItem(name: "part", value: "snippet,id"),
                //Optional Parameters
                URLQueryItem(name: "regionCode", value: "US"),
                URLQueryItem(name: "maxResults", value: "50"),
                URLQueryItem(name: "order", value: "date")
            ]
        }
        
    }
    
    func callAPI(apiType: Youtubev3APIType) {
        validateParams(apiType: apiType)
        switch apiType {
        case .suggestedVideos:
            suggestedVideos()
        case .search:
            search()
        }
    }
    
    func suggestedVideos() {
        showLoading()
        // all properties params is OPTIONAL
        let params: [URLQueryItem] = [
            //Required Parameters
            URLQueryItem(name: "relatedToVideoId", value: "7ghhRHRP6t4"),
            URLQueryItem(name: "part", value: "id,snippet"),
            URLQueryItem(name: "type", value: "video"),
            //Optional Parameters
            URLQueryItem(name: "maxResults", value: "50"),
        ]
        
        Youtubev3Router.init(endpoint: .suggestedVideos(params: params)).getData(completion: { [weak self] result in
            self?.hideLoading()
            switch result {
            case .success(let data):
                if let json = try? JSON(data: data) {
                    let array = [SuggestedVideosModel](byJSON: json["items"])
                    self?.listSuggestVideo = array
                    DispatchQueue.main.async {
                        self?.tableView.reloadData()
                    }
                }
            default:
                print("tram cam")
            }
        })
    }
    
    func search() {
        showLoading()
        Youtubev3Router.init(endpoint: .search(params: params)).getData(completion: { [weak self] result in
            self?.hideLoading()
            switch result {
            case .success(let data):
                if let json = try? JSON(data: data) {
                    let items = [SuggestedVideosModel](byJSON: json["items"])
                    self?.listVideo = items
                    DispatchQueue.main.async {
                        self?.tableView.reloadData()
                    }
                }
            default:
                break
            }
        })
    }
    
    func generalUrlComponent(host: String, path: String, queryItems: [URLQueryItem]) -> URL {
        var urlComponents = URLComponents()
        urlComponents.scheme = "https"
        urlComponents.host = host
        urlComponents.path = path
        urlComponents.queryItems = queryItems
        
        
        return urlComponents.url!
    }
    
    @IBAction func dismissButton(_ sender: UIButton) {
        //        dismiss(animated: true, completion: nil)
    }
}

extension Youtubev3VC: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return listVideo.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: SearchYoutubeCell.identifier(), for: indexPath) as! SearchYoutubeCell
        let data = listVideo[indexPath.row]
        cell.titleTextView.text = data.snippet?.title
        cell.descriptionTextView.text = data.snippet?.descriptionVideo
        if let link = data.snippet?.thumbnails?.medium?.url {
            cell.thumbnailsImageView.dowloadFromServer(link: link)
        }
        
        return cell
    }
    
}

extension Youtubev3VC: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        title = ""
        let vc = Storyboard.Main.youtubeSuggestViewController()
        vc.data = listVideo[indexPath.row]
        navigationController?.pushViewController(vc, animated: true)
    }
    
}

extension Youtubev3VC: UISearchBarDelegate {
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        callAPI(apiType: .search)
    }
}
<file_sep>/TestFilter/TestFilter/View/CocktailCell.swift
//
//  CocktailCell.swift
//  TestFilter
//
//  Created by <NAME> on 2/7/20.
//  Copyright © 2020 <NAME>. All rights reserved.
//

import UIKit

class CocktailCell: UITableViewCell {

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
    
}
<file_sep>/README.md
# MasterSearch
Hiển thị kết quả: Vừa nhập, lọc vừa hiển thị. Lọc xong rồi hiển thị.

thêm phần base network url, sử dụng kết hợp với swiftyjson
<file_sep>/TestFilter/TestFilter/Extension/View.swift
//
//  View.swift
//  TestFilter
//
//  Created by <NAME> on 3/11/21.
//  Copyright © 2021 <NAME>. All rights reserved.
//

import Foundation
import UIKit

extension UIView {
    
    func roundCorners(corners: UIRectCorner, radius: CGFloat) {
        let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        layer.mask = mask
    }
    
    static func nibName() -> String {
        let nameSpaceClassName = NSStringFromClass(self)
        let className = nameSpaceClassName.components(separatedBy: ".").last! as String
        return className
    }
    
    static func nib() -> UINib {
        return UINib(nibName: self.nibName(), bundle: nil)
    }
    
    static func loadFromNib<T: UIView>() -> T {
        let nameStr = "\(self)"
        let arrName = nameStr.split { $0 == "." }
        let nibName = arrName.map(String.init).last!
        let nib = UINib(nibName: nibName, bundle: nil)
        return nib.instantiate(withOwner: self, options: nil).first as! T
    }
    func fill(left: CGFloat? = 0, top: CGFloat? = 0, right: CGFloat? = 0, bottom: CGFloat? = 0) {
        guard let superview = superview else {
            print("\(self.description): there is no superView")
            return
        }
        self.translatesAutoresizingMaskIntoConstraints = false
        if let left = left {
            self.leadingAnchor.constraint(equalTo: superview.leadingAnchor, constant: left).isActive = true
        }
        if let top = top  {
            self.topAnchor.constraint(equalTo: superview.topAnchor, constant: top).isActive = true
        }
        
        if let right = right {
            self.trailingAnchor.constraint(equalTo: superview.trailingAnchor, constant: -right).isActive = true
        }
        
        if let bottom = bottom {
            self.bottomAnchor.constraint(equalTo: superview.bottomAnchor, constant: -bottom).isActive = true
        }
    }
    
    @objc func setDefaultCorner() {
        self.layer.cornerRadius = 4.0
    }
    
    @objc func setCornerRadius(radius: CGFloat) {
        self.layer.cornerRadius = radius
    }
    
    @objc func setDefaultButton() {
        self.backgroundColor = #colorLiteral(red: 0.01568627451, green: 0.5333333333, blue: 0.8196078431, alpha: 1)
        self.setDefaultCorner()
        self.setShadow()
    }
    
    @objc func setBackgroundColor(color: UIColor) {
        self.backgroundColor = color
    }
    
    @objc func setDefaultButtonWithoutCorner(){
        //        self.backgroundColor = Constant.color.blueVSmart
        self.backgroundColor = #colorLiteral(red: 0.01568627451, green: 0.5333333333, blue: 0.8196078431, alpha: 1)
        self.setShadow()
    }
    
    @objc func setShadow(size: CGFloat = 2.0) {
        self.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.25).cgColor
        self.layer.shadowOffset = CGSize(width: 0, height: size)
        self.layer.shadowOpacity = 1.0
        self.layer.masksToBounds = false
    }
}
<file_sep>/TestFilter/TestFilter/Application/Storyboard.swift
//
//  Storyboard.swift
//  TestFilter
//
//  Created by <NAME> on 3/11/21.
//  Copyright © 2021 <NAME>. All rights reserved.
//

import UIKit

struct Storyboard {
    
}

extension Storyboard {
    
    struct Main {
        static let manager = UIStoryboard(name: "Main", bundle: nil)
        
        static func youtubeSuggestViewController() -> YoutubeSuggestViewController {
            return manager.instantiateViewController(withIdentifier: "YoutubeSuggestViewController") as! YoutubeSuggestViewController
        }
        
    }
}
<file_sep>/TestFilter/TestFilter/Model/SuggestedVideosModel.swift
//
//  SuggestedVideosModel.swift
//  TestFilter
//
//  Created by <NAME> on 3/11/21.
//  Copyright © 2021 <NAME>. All rights reserved.
//

import Foundation
import SwiftyJSON

class SuggestedVideosModel: BaseDataModel {
    var kind: String?
    var id: SuggestedVideosModelID?
    var snippet: SnippetModel?
    
    override func mapping(json: JSON) {
        kind = json["kind"].stringValue
        id = SuggestedVideosModelID(byJSON: json["id"])
        snippet = SnippetModel(byJSON: json["snippet"])
    }
}

class SuggestedVideosModelID: BaseDataModel {
    var kind: String?
    var videoId: String?
    
    override func mapping(json: JSON) {
        kind = json["kind"].stringValue
        videoId = json["videoId"].stringValue
    }
}

class SnippetModel: BaseDataModel {
    var publishedAt: String?
    var channelId: String?
    var title: String?
    var descriptionVideo: String?
    
    var thumbnails: ThumbnailsModel?
    
    override func mapping(json: JSON) {
        publishedAt = json["publishedAt"].stringValue
        channelId = json["channelId"].stringValue
        title = json["title"].stringValue
        descriptionVideo = json["description"].stringValue
        
        thumbnails = ThumbnailsModel(byJSON: json["thumbnails"])
    }
}

class ThumbnailsModel: BaseDataModel {
    var medium: MediumModel?
    var maxres: MaxresModel?
    
    override func mapping(json: JSON) {
        medium = MediumModel(byJSON: json["medium"])
        maxres = MaxresModel(byJSON: json["maxres"])
    }
}

class MediumModel: BaseDataModel {
    var url: String?
    var width: Int?
    var height: Int?
    
    override func mapping(json: JSON) {
        url = json["url"].stringValue
        width = json["width"].intValue
        height = json["height"].intValue
    }
}

class MaxresModel: BaseDataModel {
    var url: String?
    var width: Int?
    var height: Int?
    
    override func mapping(json: JSON) {
        url = json["url"].stringValue
        width = json["width"].intValue
        height = json["height"].intValue
    }
}
<file_sep>/TestFilter/TestFilter/View/SuggestedVideosCell/SuggestedVideosCell.swift
//
//  SuggestedVideosCell.swift
//  TestFilter
//
//  Created by <NAME> on 3/11/21.
//  Copyright © 2021 <NAME>. All rights reserved.
//

import UIKit

class SuggestedVideosCell: BaseTableViewCell {
    @IBOutlet weak var kindTextView: UITextView!
    @IBOutlet weak var videoIdTextView: UITextView!
    
    @IBOutlet weak var thumbnailsImageView: UIImageView!
    var data = SuggestedVideosModel()
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
    
    func fillData() {
        kindTextView.text = data.snippet?.title
        videoIdTextView.text = data.snippet?.descriptionVideo
        if let url = data.snippet?.thumbnails?.maxres?.url {
            thumbnailsImageView.dowloadFromServer(link: url)
        }
        
    }
    
}
<file_sep>/TestFilter/TestFilter/View/SearchYoutubeCell/SearchYoutubeCell.swift
//
//  SearchYoutubeCell.swift
//  TestFilter
//
//  Created by <NAME> on 3/11/21.
//  Copyright © 2021 <NAME>. All rights reserved.
//

import UIKit

class SearchYoutubeCell: BaseTableViewCell {

    
    @IBOutlet weak var thumbnailsImageView: UIImageView!
    @IBOutlet weak var titleTextView: UITextView!
    @IBOutlet weak var descriptionTextView: UITextView!
    
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
    
}
<file_sep>/TestFilter/TestFilter/BaseRouter/Youtubev3Router.swift
//
//  Youtubev3.swift
//  TestFilter
//
//  Created by <NAME> on 3/11/21.
//  Copyright © 2021 <NAME>. All rights reserved.
//

import SwiftyJSON
import Foundation

enum Youtubev3APIEndpoint {
    case suggestedVideos(params: [URLQueryItem])
    case search(params: [URLQueryItem])
}

class Youtubev3Router: BaseNetwork {
    var endpoint: Youtubev3APIEndpoint
    
    init(endpoint: Youtubev3APIEndpoint) {
        self.endpoint = endpoint
    }
    
    override var path: String {
        switch endpoint {
        case .suggestedVideos(_):
            return "/search"
        case .search(_):
            return "/search"
        }
    }
    
    override var method: HTTPMethod {
        switch endpoint {
        default:
            return .get
        }
    }
    
    override var parameters: [URLQueryItem]? {
        var params: [URLQueryItem]?
        switch endpoint {
        case .suggestedVideos(let addParams):
            params = addParams
        case .search(let addParams):
            params = addParams
        }
        return params
    }
    
    override var headerFields: [String : String]? {
        var headers: [String: String]?
        switch endpoint {
        case .suggestedVideos(_):
            headers = [
                "x-rapidapi-key": "<KEY>",
                "x-rapidapi-host": "youtube-v31.p.rapidapi.com"
            ]
        default:
            headers = [
                "x-rapidapi-key": "<KEY>",
                "x-rapidapi-host": "youtube-v31.p.rapidapi.com"
            ]
        }
        return headers
    }
}
<file_sep>/TestFilter/TestFilter/Controller/ViewController.swift
//
//  ViewController.swift
//  TestFilter
//
//  Created by <NAME> on 2/4/20.
//  Copyright © 2020 <NAME>. All rights reserved.
//

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var sourceArrayLabel: UILabel!
    @IBOutlet weak var resultArrayLabel: UILabel!
    @IBOutlet weak var searchTextField: UITextField!
    @IBOutlet weak var noteLabel: UILabel!
    
    
    @IBOutlet weak var searchBar: UISearchBar!
    
    var sourceArray = ["Khanh Linh", "Huyen Linh", "Hien Linh", "Dieu Linh", "Ngoc Tram"]
    var resultArray = [String]()
    
    var searchActive: Bool = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        searchTextField.delegate = self
        setDisplay()
        
        // SearchBar
        searchBar.delegate = self
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
        noteLabel.text = note
        
        // Ẩn bàn phím khi ấn ra bên ngoài
        let tapGestureReconizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
        tapGestureReconizer.cancelsTouchesInView = false
        view.addGestureRecognizer(tapGestureReconizer)
    }
    
    @objc func dismissKeyboard() {
        view.endEditing(true)
    }

    let note = """
    Lưu ý khi thực hiện xong bài này. Nhập xong với lọc và vừa nhập vừa lọc ra kết quả. Action trong keyboard, textField...
    Ẩn bàn phím khi thực hiện action. Ẩn khi ấn ra ngoài.
    """
    func setDisplay() {
        var source: String = """
        \(sourceArray)
        """
        let vowels: Set<Character> = ["\\", "[", "]"]
        source.removeAll(where: { vowels.contains($0) })
        
        sourceArrayLabel.text = source
        var result: String = """
        \(resultArray)
        """
        result.removeAll(where: { vowels.contains($0) })
        resultArrayLabel.text = result
    }
    
    func filtering(keyWord: String) {
        resultArray = sourceArray.filter({ (laptop: String) in
            laptop.lowercased().contains(keyWord.lowercased())
        })
    }
    
    @IBAction func onClickedFilter(_ sender: UIButton) {
        filtering(keyWord: searchTextField.text!)
        setDisplay()
        view.endEditing(true)
    }
    
//    func textFieldDidBeginEditing(_ textField: UITextField) {
//        if textField == searchTextField {
//            filtering(keyWord: searchTextField.text!)
//            setDisplay()
//        }
//    }
    
    // Action cho textField
    // Dùng func
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        filtering(keyWord: searchTextField.text!)
        setDisplay()
        return true
    }
    // Kéo Action  @IBAction func onClickToFiltering(_ sender: UITextField) {
//        filtering(keyWord: searchTextField.text!)
//        setDisplay()
//        view.endEditing(true)
//    }
    
    
    @IBAction func nextCooktail(_ sender: UIButton) {
//        let vc = storyboard?.instantiateViewController(identifier: "CocktaildbVC") as! Youtube v3VC
//        present(vc, animated: true, completion: nil)
    }
    
}

extension ViewController: UISearchResultsUpdating {
    func updateSearchResults(for searchController: UISearchController) {
        resultArray = sourceArray.filter({ (laptop: String) in
            laptop.lowercased().contains(searchBar.text!.lowercased())
        })
        setDisplay()
    }
}

extension ViewController: UISearchBarDelegate {
    func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
//        filterContentForSearch(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
        filtering(keyWord: searchBar.text!)
    }
    
    // khi bắt dầu chạm vào search
    func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
        searchActive = true
    }
    
    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
        searchActive = false
    }
    
    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
        searchActive = false
    }
    
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        searchActive = false
        filtering(keyWord: searchBar.text!)
        setDisplay()
        view.endEditing(true)
    }
    
    // Nhập đến đâu lọc đến đó
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        let searchText = searchBar.text ?? ""
        
        resultArray = sourceArray.filter { word in
            word.lowercased().contains(searchText.lowercased())
        }
        
        
        if (resultArray.count == 0) {
            searchActive = false
        } else {
            searchActive = true
        }
        setDisplay()
    }
}
<file_sep>/TestFilter/TestFilter/Model/BaseCocktaildbModel.swift
//
//  BaseCocktaildbModel.swift
//  TestFilter
//
//  Created by <NAME> on 2/4/20.
//  Copyright © 2020 <NAME>. All rights reserved.
//

import UIKit

struct BaseCocktaildbModel: Codable {
    var drinks: [Drinks]
}

struct Drinks: Codable {
    var strDrink: String?
}
