Translate To Preferred Language

Search Obioku's Thoughts

Please Read Today's Featured Post

Things I Would Like To Happen Soon

For all those who believe in speaking ideas into existence and prayer in the universe will return to a person.  I simply want to write a lis...

Template for YouTube API Request With Programmatic Storyboard And Cocoapods in Swift (some bugs may occur)

//
//  ViewController.swift
//  Tutorial7
//
//  Created by Obioku Bassey Obotette on 4/25/19.
//  Copyright © 2019 Obioku Bassey Obotette. All rights reserved.
//

import UIKit
import Alamofire
import Kingfisher
import SwiftyJSON
import Realm
import SafariServices

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, SFSafariViewControllerDelegate {

    //struct for youtube data
    struct ParseData {
        
        var id: [Int]?
        var vidpic: [URL]?
        var highpic: [UIImage]?
        var titleLabel: [String]?
        var description: [String]?
        var count: [String]?
        var channel: [String]?
        var vidURL: [URL]?
        
        //init as empty to prevent "nil"
        init() {
            self.id = [0]
            self.vidpic = [URL.init(string: "https://www.youtube.com")] as? [URL]
            self.highpic = [UIImage.init()]
            self.titleLabel = [""]
            self.description = [""]
            self.count = [""]
            self.channel = [""]
            self.vidURL = [URL.init(string: "https://www.youtube.com")] as? [URL]
            
        }
    }
    
    //declare variables
    var object = ParseData()
    let search = UISearchBar.init()
    let scope = UISegmentedControl()
    let segment = UISegmentedControl()
    let table = UITableView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
        self.view.backgroundColor = UIColor.black
        //Search Bar Features
        search.delegate = self
        search.frame = CGRect.init(x: 0, y: 30, width: self.view.bounds.width, height: 60)
        search.searchBarStyle = .default
        search.returnKeyType = .search
        search.barTintColor = UIColor.red
        search.placeholder = "Search YouTube"
        search.isUserInteractionEnabled = true
        search.isMultipleTouchEnabled = true
        view.addSubview(search)
        
        //Scope and Segment Control Features
        scope.frame = CGRect.init(x: 0, y: 90, width: self.view.bounds.width, height: 30)
        scope.tintColor = UIColor.red
        scope.backgroundColor = UIColor.black
        scope.insertSegment(withTitle: "Videos", at: 0, animated: true)
        scope.insertSegment(withTitle: "Channels", at: 1, animated: true)
        scope.selectedSegmentIndex = 0
        scope.isUserInteractionEnabled = true
        scope.isMultipleTouchEnabled = true
        view.addSubview(scope)
        
        segment.frame = CGRect.init(x: 0, y: 120, width: self.view.bounds.width, height: 30)
        segment.tintColor = UIColor.red
        segment.backgroundColor = UIColor.black
        segment.insertSegment(withTitle: "10", at: 0, animated: true)
        segment.insertSegment(withTitle: "25", at: 1, animated: true)
        segment.selectedSegmentIndex = 0
        segment.isUserInteractionEnabled = true
        segment.isMultipleTouchEnabled = true
        view.addSubview(segment)
        
        //Table Features
        table.delegate = self
        table.dataSource = self
        table.frame = CGRect.init(x: 0, y: 150, width: self.view.bounds.width, height: self.view.bounds.height - 150)
        table.register(UITableViewCell.self, forCellReuseIdentifier: "cellID")
        table.register(UITableViewHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "headerID")
        table.isUserInteractionEnabled = true
        table.isScrollEnabled = true
        table.isSpringLoaded = true
        table.scrollsToTop = true
        table.flashScrollIndicators()
        table.backgroundColor = UIColor.black
        table.sectionIndexTrackingBackgroundColor = UIColor.red
        table.sectionIndexBackgroundColor = UIColor.red
        table.sectionIndexColor = UIColor.red
        table.separatorColor = UIColor.red
        view.addSubview(table)
        
        
        
    }
    
    //event for search entry
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        //print("Search Bar clicked")
        if searchBar.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "" {
            let alert = UIAlertController.init(title: "Blank Search Term", message: "Please Enter Value And Try Again", preferredStyle: .alert)
            let action = UIAlertAction.init(title: "Return", style: .cancel)
            alert.addAction(action)
            self.present(alert, animated: true)
        }else{
            //reset array properties with each search
            self.object = ParseData()
            DispatchQueue.main.async {
                self.table.reloadData()
            }
            var i = 0
            //url components
            var numResults = 0
            var urlString = ""
            let string = "https://www.googleapis.com/youtube/v3"
            let entered = searchBar.text?.replacingOccurrences(of: " ", with: "+")
            //let key = "dev key"
            let key = "dev key"
            
            //store amount of returns
            switch self.segment.selectedSegmentIndex {
            case 0: numResults = 10
            case 1: numResults = 25
            default:
                let alert = UIAlertController.init(title: "Return Amount Not Selected", message: "Please Chose 10 Or 25 And Try Again", preferredStyle: .alert)
                let action = UIAlertAction.init(title: "Return", style: .cancel)
                alert.addAction(action)
                self.present(alert, animated: true)
                
            }
            
            //retrieve segment choice
            switch self.scope.selectedSegmentIndex {
            case 0: urlString = "\(string)/search?part=snippet&maxResults=\(numResults ?? 5)&q=\(entered!)&type=video&videoCaption=closedCaption&key=\(key)"
            case 1: urlString = "\(string)/search?part=snippet&maxResults=\(numResults ?? 5)&q=\(entered!)&type=channel&key=\(key)"
            default:
                let alert = UIAlertController.init(title: "Search Format Not Selected", message: "Please Choose Video Or Channel And Try Again", preferredStyle: .alert)
                let action = UIAlertAction.init(title: "Return", style: .cancel)
                alert.addAction(action)
                self.present(alert, animated: true)
                
            }
            //return JSON with Alamofire
            if let url = URL.init(string: urlString) {
                AF.request(url).validate().responseJSON { (resp) in
                    //Parse with SwiftyJSON
                    let dictionary = JSON(resp.data!).dictionaryValue
                    //determine video or channel listing and assign url
                    for item in dictionary["items"]!.arrayValue {
                        if self.scope.selectedSegmentIndex  == 0 {
                            self.object.vidURL?.insert(URL(string: "https://www.youtube.com/watch?v=\(item["id"]["videoId"].stringValue)")!, at: i)
                        }
                        if self.scope.selectedSegmentIndex  == 1 {
                            self.object.vidURL?.insert(URL(string: "https://www.youtube.com/channel/\(item["id"]["channelId"].stringValue)")!, at: i)
                        }
                        
                        //collect index id, channel, date, title, description and picture
                        self.object.channel?.insert(item["snippet"]["channelTitle"].stringValue, at: i)
                        self.object.count?.insert(item["snippet"]["publishedAt"].stringValue, at: i)
                        self.object.titleLabel?.insert(item["snippet"]["title"].stringValue, at: i)
                        self.object.description?.insert(item["snippet"]["description"].stringValue, at: i)
                        guard let load = URL(string: item["snippet"]["thumbnails"]["high"]["url"].stringValue) else { return }
                        self.object.vidpic?.insert(load, at: i)
                        var thumbnail: UIImageView?
                        let datum = try! Data(contentsOf: load)
                        guard let fin = UIImage(data: datum) else { return }
                        thumbnail?.kf.setImage(with: load)
                        self.object.highpic?.insert(thumbnail?.image! ?? fin, at: i)
                        i += 1
                        
                        //reload returned results
                        DispatchQueue.main.async {
                            self.table.reloadData()
                        }
                    }
                  
                }
                
            }
            
            
            
        }
        
        //self.table.beginUpdates()
        //self.table.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
        //self.table.endUpdates()
        //self.table.setContentOffset(CGPoint.zero, animated: true)
        //self.table.scrollRectToVisible(CGRect.init(x: 0, y: 0, width: 1, height: 1), animated: true)
        
    }
    
    //one row per section
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }
    
    //table cell design
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellID", for: indexPath)
        tableView.dequeueReusableHeaderFooterView(withIdentifier: "headerID")
        //add identifier text to cell labels and image to imageView
        print(indexPath.section)
        cell.textLabel?.text = self.object.channel?[indexPath.section].replacingOccurrences(of: "'", with:
            "\'").replacingOccurrences(of: "&quot", with: "\"").replacingOccurrences(of: "&amp", with: "&")
        cell.textLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping
        cell.detailTextLabel?.text = self.object.count?[indexPath.section].replacingOccurrences(of: "'", with:
            "\'").replacingOccurrences(of: "&quot", with: "\"").replacingOccurrences(of: "&amp", with: "&")
        cell.detailTextLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping
        cell.imageView?.image = self.object.highpic?[indexPath.section]
        return cell
    }
    
    //section header is title of video or channel
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return self.object.titleLabel?[section].replacingOccurrences(of: "'", with:
            "\'").replacingOccurrences(of: "&quot", with: "\"").replacingOccurrences(of: "&amp", with: "&")
    }
    
    //fixed row height
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 170.0
    }
    
    //fized section header height
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 25.0
    }
    
    //give section header red color
    func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        view.tintColor = UIColor.red
        //view.backgroundColor = UIColor.red

    }
    
    //reverse cell colors
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        //cell.textLabel?.text = "Cell in section \(indexPath.section) and row \(indexPath.row)"
        cell.backgroundColor = UIColor.black
        cell.textLabel?.textColor = UIColor.white
    }
    
    //number of section depends on returned results
    func numberOfSections(in tableView: UITableView) -> Int {
        
        return self.object.count!.count - 1 ?? 0
    }
    
    //row selected displays video in new view using safari
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let vc = SFSafariViewController.init(url: (self.object.vidURL?[indexPath.section])!)
        vc.delegate = self
        vc.preferredContentSize = CGSize.init(width: 100, height: 200)
        vc.modalTransitionStyle = .crossDissolve
        self.present(vc, animated: true)
    }
    
    
    
}



No comments:

Post a Comment

Thank you very much for viewing this entry and I hope you are able to return soon to continue to enjoy more of the site.
Please share your thoughts in the comment section.
Be blessed and enjoy life!