Skip to content

Commit

Permalink
Merge pull request #6 from maamjadi/after-5-hours
Browse files Browse the repository at this point in the history
search functionality implemented
  • Loading branch information
maamjadi authored May 24, 2019
2 parents fd391ea + 6e953e0 commit bbb3539
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 42 deletions.
8 changes: 4 additions & 4 deletions SCMovieApp/SCMovieApp/Data/Database/Movie+CoreDataClass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import CoreData
@objc(Movie)
public class Movie: NSManagedObject {

class func fetchRates(for id: Int, context: NSManagedObjectContext) -> NSFetchedResultsController<Movie>? {
class func fetchMovies(for id: Int, context: NSManagedObjectContext) -> NSFetchedResultsController<Movie>? {
return Movie.cd_fetchAll(withPredicate: NSPredicate(format: "id == \(id)"),
sortedBy: [("date", .desc)],
delegate: nil,
Expand All @@ -33,11 +33,11 @@ public class Movie: NSManagedObject {
return results
}

class func addOrUpdateRates(from content: GeneralResponseDTO, date: String? = nil, context: NSManagedObjectContext) -> [Movie] {
return addOrUpdateRates(from: content.results, context: context)
class func addOrUpdateMovies(from content: GeneralResponseDTO, date: String? = nil, context: NSManagedObjectContext) -> [Movie] {
return addOrUpdateMovies(from: content.results, context: context)
}

class func addOrUpdateRates(from content: [MovieObjectDTO], date: String? = nil, context: NSManagedObjectContext) -> [Movie] {
class func addOrUpdateMovies(from content: [MovieObjectDTO], date: String? = nil, context: NSManagedObjectContext) -> [Movie] {
var movies = [Movie]()
content.forEach { movieDTO in
if let id = movieDTO.id, let movie = Movie.getItem(by: id,
Expand Down
77 changes: 47 additions & 30 deletions SCMovieApp/SCMovieApp/Data/Handler/MovieHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class MovieHandler: NSObject {

static let shared = MovieHandler()

private let baseURL = "https://api.themoviedb.org/3/movie/"
private let baseURL = "https://api.themoviedb.org/3/"
private let apiKey = "api_key=43a7ea280d085bd0376e108680615c7f"
private let imageBaseURL = "https://image.tmdb.org/t/p/w500/"

Expand All @@ -41,48 +41,65 @@ class MovieHandler: NSObject {
func getPopularMovies(completionHandler: @escaping (_ success:Bool, _ error: String?, _ data: [Movie]?) -> Void) {

let date = Date().getFormattedString()

//checking if we have fetch the todaysRates before, to just return it
if let movies = Movie.getItems(for: date, context: MovieHandler.mainContext), !movies.isEmpty {
completionHandler(true, nil, movies)
} else {
let urlString = "\(baseURL)popular?page=1&language=en-US&\(apiKey)"
let urlString = "\(baseURL)movie/popular?page=1&language=en-US&\(apiKey)"
guard let url = URL(string: urlString) else {
return
}
URLSession.shared.dataTask(with: getRequest(for: url)) { (data, _, error) in
//start the asynchronous task on main thread
DispatchQueue.main.async {
if let error = error {
completionHandler(false, "Fail to get data from url:\(error)", nil)
return
}
getGeneralMovies(with: getRequest(for: url), date: date, completionHandler: completionHandler)
}
}

guard let data = data else {
completionHandler(false, nil, nil)
return
}
func getSearchedMovies(for searchText: String,
completionHandler: @escaping (_ success:Bool, _ error: String?, _ data: [Movie]?) -> Void) {
let queryString = "query=" + searchText.replacingOccurrences(of: " ",
with: "%20",
options: .literal,
range: nil)
let urlString = "\(baseURL)search/movie?page=1&language=en-US&\(apiKey)&\(queryString)"
guard let url = URL(string: urlString) else {
return
}
getGeneralMovies(with: getRequest(for: url), completionHandler: completionHandler)
}

do {
//decoding the json data
let decoder = JSONDecoder()
let movieGeneralObject = try decoder.decode(GeneralResponseDTO.self, from: data)
let movies = Movie.addOrUpdateRates(from: movieGeneralObject, date: date, context: MovieHandler.mainContext)
MovieHandler.mainContext.cd_saveToPersistentStore()
completionHandler(true, nil, movies)
} catch let jsonErr {
completionHandler(false, "Fail to decode:\(jsonErr)", nil)
}
private func getGeneralMovies(with request: URLRequest,
date: String? = nil,
completionHandler: @escaping (_ success:Bool, _ error: String?, _ data: [Movie]?) -> Void) {
URLSession.shared.dataTask(with: request) { (data, _, error) in
//start the asynchronous task on main thread
DispatchQueue.main.async {
if let error = error {
completionHandler(false, "Fail to get data from url:\(error)", nil)
return
}
}.resume()
}

guard let data = data else {
completionHandler(false, nil, nil)
return
}

do {
//decoding the json data
let decoder = JSONDecoder()
let movieGeneralObject = try decoder.decode(GeneralResponseDTO.self, from: data)
let movies = Movie.addOrUpdateMovies(from: movieGeneralObject, date: date, context: MovieHandler.mainContext)
MovieHandler.mainContext.cd_saveToPersistentStore()
completionHandler(true, nil, movies)
} catch let jsonErr {
completionHandler(false, "Fail to decode:\(jsonErr)", nil)
}
}
}.resume()
}

func getMovie(with id: Int, completionHandler: @escaping (_ success:Bool, _ error: String?, _ data: Movie?) -> Void) {
if let movie = Movie.getItem(by: id, context: MovieHandler.mainContext) {
completionHandler(true, nil, movie)
} else {
let urlString = "\(baseURL)\(id)?language=en-US&\(apiKey)"
let urlString = "\(baseURL)movie/\(id)?language=en-US&\(apiKey)"
guard let url = URL(string: urlString) else {
return
}
Expand All @@ -104,7 +121,7 @@ class MovieHandler: NSObject {
//decoding the json data
let decoder = JSONDecoder()
let movieObject = try decoder.decode(MovieObjectDTO.self, from: data)
let movies = Movie.addOrUpdateRates(from: [movieObject], context: MovieHandler.mainContext)
let movies = Movie.addOrUpdateMovies(from: [movieObject], context: MovieHandler.mainContext)
MovieHandler.mainContext.cd_saveToPersistentStore()
completionHandler(true, nil, movies[0])
} catch let jsonErr {
Expand All @@ -120,7 +137,7 @@ class MovieHandler: NSObject {
let url = URL(string: imageBaseURL + urlString) {
return url
}
return nil
return nil
}


Expand Down
30 changes: 24 additions & 6 deletions SCMovieApp/SCMovieApp/UI/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,42 @@
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="W7N-Bx-Fu0">
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kke-gj-bLf">
<rect key="frame" x="0.0" y="88" width="414" height="808"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="W7N-Bx-Fu0">
<rect key="frame" x="0.0" y="0.0" width="414" height="808"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tableView>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="9iL-Se-Vls">
<rect key="frame" x="197" y="192" width="20" height="20"/>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tableView>
<constraints>
<constraint firstItem="9iL-Se-Vls" firstAttribute="centerY" secondItem="kke-gj-bLf" secondAttribute="centerY" multiplier="0.5" id="9Uw-zq-bK1"/>
<constraint firstItem="W7N-Bx-Fu0" firstAttribute="leading" secondItem="kke-gj-bLf" secondAttribute="leading" id="EXm-d2-fLG"/>
<constraint firstAttribute="bottom" secondItem="W7N-Bx-Fu0" secondAttribute="bottom" id="HeW-HA-sXQ"/>
<constraint firstItem="9iL-Se-Vls" firstAttribute="centerX" secondItem="kke-gj-bLf" secondAttribute="centerX" id="PdF-Dl-Mbb"/>
<constraint firstItem="W7N-Bx-Fu0" firstAttribute="top" secondItem="kke-gj-bLf" secondAttribute="top" id="XTv-9n-fVd"/>
<constraint firstAttribute="trailing" secondItem="W7N-Bx-Fu0" secondAttribute="trailing" id="wMp-2P-OTm"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="W7N-Bx-Fu0" secondAttribute="bottom" id="Bly-Pf-6WP"/>
<constraint firstItem="W7N-Bx-Fu0" firstAttribute="top" secondItem="SRd-Gf-7D1" secondAttribute="top" id="iae-D1-v3a"/>
<constraint firstItem="W7N-Bx-Fu0" firstAttribute="leading" secondItem="SRd-Gf-7D1" secondAttribute="leading" id="scO-S6-6T9"/>
<constraint firstItem="SRd-Gf-7D1" firstAttribute="trailing" secondItem="W7N-Bx-Fu0" secondAttribute="trailing" id="vtL-Kj-SG9"/>
<constraint firstItem="kke-gj-bLf" firstAttribute="top" secondItem="SRd-Gf-7D1" secondAttribute="top" id="N8n-26-L7y"/>
<constraint firstItem="kke-gj-bLf" firstAttribute="leading" secondItem="81S-XX-ItB" secondAttribute="leading" id="SIH-3D-F8a"/>
<constraint firstAttribute="bottom" secondItem="kke-gj-bLf" secondAttribute="bottom" id="VRC-Ex-T2Q"/>
<constraint firstAttribute="trailing" secondItem="kke-gj-bLf" secondAttribute="trailing" id="egW-bS-CAy"/>
</constraints>
<viewLayoutGuide key="safeArea" id="SRd-Gf-7D1"/>
</view>
<navigationItem key="navigationItem" id="HEx-g5-TC2">
<nil key="title"/>
</navigationItem>
<connections>
<outlet property="loadingSpinner" destination="9iL-Se-Vls" id="2hj-ez-NLP"/>
<outlet property="tableView" destination="W7N-Bx-Fu0" id="W1Q-bf-g3Y"/>
</connections>
</viewController>
Expand Down
23 changes: 21 additions & 2 deletions SCMovieApp/SCMovieApp/UI/MainViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import UIKit

class MainViewController: UIViewController {

@IBOutlet weak var navigationTitle: UILabel!
@IBOutlet weak var loadingSpinner: UIActivityIndicatorView!
@IBOutlet weak var tableView: UITableView!

var tableViewData = [Movie]() {
Expand All @@ -30,13 +30,15 @@ class MainViewController: UIViewController {
forCellReuseIdentifier: cellIdentifier)
self.tableView.contentInset = UIEdgeInsets(top: 16, left: 0, bottom: 0, right: 0)
setupNavigationBar()
getPopularMovies()
}

private func getPopularMovies() {
MovieHandler.shared.getPopularMovies { [weak self] (success, error, movies) in
if let movies = movies, success, error == nil {
self?.tableViewData = movies
}
}

}

private func addNavigationBarTitle() {
Expand Down Expand Up @@ -76,6 +78,21 @@ class MainViewController: UIViewController {
func searchBarIsEmpty() -> Bool {
return searchController.searchBar.text?.isEmpty ?? true
}

private func getContent(for seachedText: String?) {
if searchBarIsEmpty() {
getPopularMovies()
} else if let seachedText = seachedText {
tableViewData = []
loadingSpinner.startAnimating()
MovieHandler.shared.getSearchedMovies(for: seachedText) { [weak self] (success, error, movies) in
if let movies = movies, success, error == nil {
self?.tableViewData = movies
}
self?.loadingSpinner.stopAnimating()
}
}
}
}

extension MainViewController: UITableViewDelegate, UITableViewDataSource {
Expand Down Expand Up @@ -111,11 +128,13 @@ extension MainViewController: UITableViewDelegate, UITableViewDataSource {
extension MainViewController: UISearchBarDelegate {
// MARK: - UISearchBar Delegate
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
getContent(for: searchBar.text)
}
}

extension MainViewController: UISearchResultsUpdating {
// MARK: - UISearchResultsUpdating Delegate
func updateSearchResults(for searchController: UISearchController) {
getContent(for: searchController.searchBar.text)
}
}

0 comments on commit bbb3539

Please sign in to comment.