Compare commits
12 Commits
master
...
feature/VI
Author | SHA1 | Date |
---|---|---|
![]() |
f3cfa9a622 | |
![]() |
f53d097d67 | |
![]() |
8054c4c707 | |
![]() |
dced6087d7 | |
![]() |
479d89a47c | |
![]() |
c4b072dcf0 | |
![]() |
93fcb4f3a2 | |
![]() |
54aee8775c | |
![]() |
439a7e2bde | |
![]() |
6dc64129f2 | |
![]() |
a8ec22590f | |
![]() |
635b637ef9 |
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// Array+Extension.swift
|
||||
// iMoviesMVC
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 1.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension Array {
|
||||
|
||||
struct IndexOutOfBoundsError: Error { }
|
||||
|
||||
func element(at index: Int) throws -> Element {
|
||||
guard index >= 0 && index < self.count else {
|
||||
throw IndexOutOfBoundsError()
|
||||
}
|
||||
return self[index]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// Optional+Extension.swift
|
||||
// iMoviesMVC
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 1.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension Optional {
|
||||
|
||||
struct FoundNilWhileUnwrappingError: Error { }
|
||||
|
||||
func unwrap() throws -> Wrapped {
|
||||
switch self {
|
||||
case .some(let wrapped):
|
||||
return wrapped
|
||||
case .none:
|
||||
throw FoundNilWhileUnwrappingError()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// UICollectionView+Extension.swift
|
||||
// iMovies
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 18.12.2022.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UICollectionView {
|
||||
func registerCell<T: UICollectionViewCell>(type: T.Type) where T: Reuseable {
|
||||
self.register(UINib(nibName: T.reuseIdentifier, bundle: nil), forCellWithReuseIdentifier: T.reuseIdentifier)
|
||||
}
|
||||
|
||||
func dequeueReusableCell<T: UICollectionViewCell> (forIndexPath indexPath: IndexPath) -> T where T: Reuseable {
|
||||
return dequeueReusableCell(withReuseIdentifier: T.reuseIdentifier, for: indexPath as IndexPath) as! T
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// UIImageView+Extension.swift
|
||||
// iMovies
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 2.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Kingfisher
|
||||
|
||||
// MARK: - Kingfiher
|
||||
extension UIImageView {
|
||||
|
||||
func setKfImage(for urlString: String?) {
|
||||
guard let urlString = urlString else {
|
||||
return
|
||||
}
|
||||
let url = URL(string: urlString)
|
||||
self.kf.indicatorType = .activity
|
||||
self.kf.setImage(with: url, options: KingfisherManager.shared.defaultOptions)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// UITableView+Extension.swift
|
||||
// iMovies
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 18.12.2022.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UITableView {
|
||||
func registerCell<T: UITableViewCell>(type: T.Type) where T: Reuseable {
|
||||
self.register(T.self, forCellReuseIdentifier: T.reuseIdentifier)
|
||||
}
|
||||
|
||||
func dequeueReusableCell<T: UITableViewCell> (forIndexPath indexPath: IndexPath) -> T where T: Reuseable {
|
||||
return dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath as IndexPath) as! T
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// UIViewController+Extension.swift
|
||||
// iMoviesMVC
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 18.12.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
extension UIViewController {
|
||||
|
||||
func embedInNavigationController(
|
||||
_ modalPresentationStyle: UIModalPresentationStyle = .fullScreen
|
||||
) -> UINavigationController {
|
||||
let navigationController = UINavigationController(rootViewController: self)
|
||||
navigationController.modalPresentationStyle = modalPresentationStyle
|
||||
return navigationController
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// MoviePresentation.swift
|
||||
// MovieBoxMVC
|
||||
//
|
||||
// Created by Ilter Cengiz on 18/11/18.
|
||||
// Copyright © 2018 Late Night Muhabbetleri. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import iMoviesAPI
|
||||
|
||||
typealias MoviePresentations = [MoviePresentation]
|
||||
|
||||
final class MoviePresentation: NSObject {
|
||||
|
||||
let title: String?
|
||||
let summary: String?
|
||||
let imageUrl: String?
|
||||
|
||||
init(
|
||||
title: String?,
|
||||
summary: String?,
|
||||
imageUrl: String?
|
||||
) {
|
||||
self.title = title
|
||||
self.summary = summary
|
||||
self.imageUrl = imageUrl
|
||||
super.init()
|
||||
}
|
||||
|
||||
override func isEqual(_ object: Any?) -> Bool {
|
||||
guard let other = object as? MoviePresentation else { return false }
|
||||
return self.title == other.title && self.summary == other.summary
|
||||
}
|
||||
}
|
||||
|
||||
extension MoviePresentation {
|
||||
|
||||
convenience init(movie: Movie) {
|
||||
self.init(title: movie.displayTitle,
|
||||
summary: movie.summaryShort,
|
||||
imageUrl: movie.multimedia?.src)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// Reuseable.swift
|
||||
// iMovies
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 18.12.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
protocol Reuseable: AnyObject {
|
||||
static var reuseIdentifier: String { get }
|
||||
}
|
||||
|
||||
extension Reuseable {
|
||||
static var reuseIdentifier: String {
|
||||
return String(describing: self)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// ThemeManager.swift
|
||||
// iMovies
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 18.12.2022.
|
||||
//
|
||||
|
||||
#if canImport(UIKit)
|
||||
import UIKit
|
||||
|
||||
public enum Theme: String {
|
||||
case light, dark // , graphical
|
||||
|
||||
var barStyle: UIBarStyle {
|
||||
.default
|
||||
}
|
||||
}
|
||||
|
||||
public struct ThemeManager {
|
||||
public enum Font: String {
|
||||
/// Avenir-Book
|
||||
case Book = "Avenir-Book"
|
||||
/// Avenir-Roman
|
||||
case Roman = "Avenir-Roman"
|
||||
/// Avenir-Light
|
||||
case Light = "Avenir-Light"
|
||||
/// Avenir-Medium
|
||||
case Medium = "Avenir-Medium"
|
||||
/// Avenir-Heavy
|
||||
case Heavy = "Avenir-Heavy"
|
||||
/// Avenir-Black
|
||||
case Black = "Avenir-Black"
|
||||
|
||||
public enum Size: CGFloat {
|
||||
/// 10pt
|
||||
case xxsmall = 10
|
||||
/// 12.4pt
|
||||
case xsmall = 12.4
|
||||
/// 13pt
|
||||
case small = 13
|
||||
/// 14pt
|
||||
case smallmedium = 14
|
||||
/// 15pt
|
||||
case medium = 15
|
||||
/// 18pt
|
||||
case mediumlarge = 18
|
||||
///20pt
|
||||
case large = 20
|
||||
/// 22pt
|
||||
case larger = 22
|
||||
/// 24pt
|
||||
case xlarge = 24
|
||||
/// 28pt
|
||||
case xxlarge = 28
|
||||
}
|
||||
|
||||
/// size as predifined size
|
||||
public func font(size: Size) -> UIFont? {
|
||||
let fontSize = size.rawValue
|
||||
let fontName = self.rawValue
|
||||
return UIFont(name: fontName, size: fontSize)
|
||||
}
|
||||
|
||||
/// size as CGFloat
|
||||
public func font(size: CGFloat) -> UIFont? {
|
||||
let fontSize = size
|
||||
let fontName = self.rawValue
|
||||
return UIFont(name: fontName, size: fontSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
|
@ -7,33 +7,33 @@
|
|||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Splash Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="SplashController" id="BYZ-38-t0r" customClass="SplashController" customModule="iMoviesMVC" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="applelogo" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="ge7-OE-eno">
|
||||
<rect key="frame" x="40" y="403.5" width="334" height="88.5"/>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="applelogo" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="cWH-AK-2bM">
|
||||
<rect key="frame" x="157" y="398.5" width="100" height="98.5"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="90" id="XE6-sM-vQZ"/>
|
||||
<constraint firstAttribute="height" constant="100" id="c4m-pu-aDN"/>
|
||||
<constraint firstAttribute="width" constant="100" id="mkQ-bz-G7M"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
|
||||
<color key="backgroundColor" white="0.95615433673469385" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="ge7-OE-eno" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="40" id="8in-U5-78v"/>
|
||||
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="ge7-OE-eno" secondAttribute="trailing" constant="40" id="aaX-mF-hX0"/>
|
||||
<constraint firstItem="ge7-OE-eno" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="lZp-th-Wgi"/>
|
||||
<constraint firstItem="cWH-AK-2bM" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="Map-pc-UHU"/>
|
||||
<constraint firstItem="cWH-AK-2bM" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="puy-o2-8Yu"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="3" y="54"/>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
|
@ -7,12 +7,10 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
5F002485294DC32900E2D56B /* SplashBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F002484294DC32900E2D56B /* SplashBuilder.swift */; };
|
||||
5F002488294EFF2200E2D56B /* UIViewController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F002487294EFF2200E2D56B /* UIViewController+Extension.swift */; };
|
||||
5F0024A8294F332200E2D56B /* MoviePresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F002498294F332200E2D56B /* MoviePresentation.swift */; };
|
||||
5F0024A9294F332200E2D56B /* MoviePresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F002498294F332200E2D56B /* MoviePresentation.swift */; };
|
||||
5F0024AD294F386000E2D56B /* HomeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F0024AC294F386000E2D56B /* HomeCell.swift */; };
|
||||
5F0024AE294F386000E2D56B /* HomeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F0024AC294F386000E2D56B /* HomeCell.swift */; };
|
||||
5F0024B1294F38CE00E2D56B /* Reuseable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F0024B0294F38CE00E2D56B /* Reuseable.swift */; };
|
||||
5F0024B2294F38CE00E2D56B /* Reuseable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F0024B0294F38CE00E2D56B /* Reuseable.swift */; };
|
||||
5F0024B4294F395F00E2D56B /* UITableView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F0024B3294F395F00E2D56B /* UITableView+Extension.swift */; };
|
||||
|
@ -22,30 +20,82 @@
|
|||
5F0024BA294F3A3100E2D56B /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F0024B9294F3A3100E2D56B /* ThemeManager.swift */; };
|
||||
5F0024BB294F3A3100E2D56B /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F0024B9294F3A3100E2D56B /* ThemeManager.swift */; };
|
||||
5F071769293FA18600A54133 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F071768293FA18600A54133 /* AppDelegate.swift */; };
|
||||
5F07176D293FA18600A54133 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F07176C293FA18600A54133 /* ViewController.swift */; };
|
||||
5F071770293FA18600A54133 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F07176E293FA18600A54133 /* Main.storyboard */; };
|
||||
5F071772293FA18700A54133 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5F071771293FA18700A54133 /* Assets.xcassets */; };
|
||||
5F071775293FA18700A54133 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F071773293FA18700A54133 /* LaunchScreen.storyboard */; };
|
||||
5F071780293FA18700A54133 /* iMoviesMVVMTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F07177F293FA18700A54133 /* iMoviesMVVMTests.swift */; };
|
||||
5F168BC3296328FC0073BE71 /* UIViewController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F002487294EFF2200E2D56B /* UIViewController+Extension.swift */; };
|
||||
5F168BC4296328FF0073BE71 /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B3FD29619886008090DD /* Array+Extension.swift */; };
|
||||
5F168BC5296329230073BE71 /* ViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BBB29631A9F0073BE71 /* ViewProtocol.swift */; };
|
||||
5F168BC6296329270073BE71 /* ControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BBD29631B570073BE71 /* ControllerProtocol.swift */; };
|
||||
5F168BC8296329900073BE71 /* HomeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BC7296329900073BE71 /* HomeCell.swift */; };
|
||||
5F168BCA29632A4F0073BE71 /* UIImageView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BC929632A4F0073BE71 /* UIImageView+Extension.swift */; };
|
||||
5F168BCB29632A4F0073BE71 /* UIImageView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BC929632A4F0073BE71 /* UIImageView+Extension.swift */; };
|
||||
5F168BCE29632BBC0073BE71 /* iMoviesAPI in Frameworks */ = {isa = PBXBuildFile; productRef = 5F168BCD29632BBC0073BE71 /* iMoviesAPI */; };
|
||||
5F168BD129632BE70073BE71 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 5F168BD029632BE70073BE71 /* Kingfisher */; };
|
||||
5F168BD429632EAF0073BE71 /* DetailBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BD329632EAF0073BE71 /* DetailBuilder.swift */; };
|
||||
5F168BD529632EAF0073BE71 /* DetailBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BD329632EAF0073BE71 /* DetailBuilder.swift */; };
|
||||
5F168BD729632EB80073BE71 /* DetailController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BD629632EB80073BE71 /* DetailController.swift */; };
|
||||
5F168BD829632EB80073BE71 /* DetailController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BD629632EB80073BE71 /* DetailController.swift */; };
|
||||
5F168BDA29632ED00073BE71 /* DetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BD929632ED00073BE71 /* DetailViewModel.swift */; };
|
||||
5F168BDB29632ED00073BE71 /* DetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BD929632ED00073BE71 /* DetailViewModel.swift */; };
|
||||
5F168BDD29632EDA0073BE71 /* DetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BDC29632EDA0073BE71 /* DetailView.swift */; };
|
||||
5F168BDE29632EDA0073BE71 /* DetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BDC29632EDA0073BE71 /* DetailView.swift */; };
|
||||
5F23B3E5295F1767008090DD /* iMoviesAPI in Frameworks */ = {isa = PBXBuildFile; productRef = 5F23B3E4295F1767008090DD /* iMoviesAPI */; };
|
||||
5F23B3EA295F68A9008090DD /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 5F23B3E9295F68A9008090DD /* Kingfisher */; };
|
||||
5F23B3EE295F7689008090DD /* DetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B3ED295F7689008090DD /* DetailView.swift */; };
|
||||
5F23B3F0295F7B38008090DD /* DetailController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B3EF295F7B38008090DD /* DetailController.swift */; };
|
||||
5F23B3F429600471008090DD /* DetailBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B3F329600471008090DD /* DetailBuilder.swift */; };
|
||||
5F23B3FA296197CD008090DD /* ResourceLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B3F9296197CD008090DD /* ResourceLoader.swift */; };
|
||||
5F23B3FC29619821008090DD /* Optional+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B3FB29619821008090DD /* Optional+Extension.swift */; };
|
||||
5F23B3FE29619886008090DD /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B3FD29619886008090DD /* Array+Extension.swift */; };
|
||||
5F23B40029619CE7008090DD /* movie1.json in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B3FF29619CE7008090DD /* movie1.json */; };
|
||||
5F23B40229619F06008090DD /* movie2.json in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B40129619F06008090DD /* movie2.json */; };
|
||||
5F23B40429619F0C008090DD /* movie3.json in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B40329619F0C008090DD /* movie3.json */; };
|
||||
5F23B41029631510008090DD /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B40F29631510008090DD /* HomeView.swift */; };
|
||||
5F23B41229631519008090DD /* HomeController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B41129631519008090DD /* HomeController.swift */; };
|
||||
5F23B41429631523008090DD /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B41329631523008090DD /* HomeViewModel.swift */; };
|
||||
5F23B4162963152C008090DD /* HomeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B4152963152C008090DD /* HomeBuilder.swift */; };
|
||||
5F4D7F7A296881C4007180AA /* DetailContracts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F4D7F79296881C4007180AA /* DetailContracts.swift */; };
|
||||
5F9292972967001400B2CBC8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292962967001400B2CBC8 /* AppDelegate.swift */; };
|
||||
5F9292A02967001500B2CBC8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5F92929F2967001500B2CBC8 /* Assets.xcassets */; };
|
||||
5F9292AE2967001500B2CBC8 /* iMoviesVIPERTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292AD2967001500B2CBC8 /* iMoviesVIPERTests.swift */; };
|
||||
5F9292C42967004A00B2CBC8 /* UIViewController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F002487294EFF2200E2D56B /* UIViewController+Extension.swift */; };
|
||||
5F9292C52967004D00B2CBC8 /* UIImageView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F168BC929632A4F0073BE71 /* UIImageView+Extension.swift */; };
|
||||
5F9292C62967004F00B2CBC8 /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B3FD29619886008090DD /* Array+Extension.swift */; };
|
||||
5F9292C72967005200B2CBC8 /* UITableView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F0024B3294F395F00E2D56B /* UITableView+Extension.swift */; };
|
||||
5F9292C82967005400B2CBC8 /* UICollectionView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F0024B6294F397E00E2D56B /* UICollectionView+Extension.swift */; };
|
||||
5F9292C92967005800B2CBC8 /* Optional+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B3FB29619821008090DD /* Optional+Extension.swift */; };
|
||||
5F9292CA2967005800B2CBC8 /* Optional+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F23B3FB29619821008090DD /* Optional+Extension.swift */; };
|
||||
5F9292CB2967006C00B2CBC8 /* MoviePresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F002498294F332200E2D56B /* MoviePresentation.swift */; };
|
||||
5F9292CE296700BD00B2CBC8 /* AppContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292CD296700BD00B2CBC8 /* AppContainer.swift */; };
|
||||
5F9292D0296700D000B2CBC8 /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292CF296700D000B2CBC8 /* AppRouter.swift */; };
|
||||
5F9292D12967014A00B2CBC8 /* Reuseable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F0024B0294F38CE00E2D56B /* Reuseable.swift */; };
|
||||
5F9292D22967015000B2CBC8 /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F0024B9294F3A3100E2D56B /* ThemeManager.swift */; };
|
||||
5F9292D5296743F400B2CBC8 /* iMoviesAPI in Frameworks */ = {isa = PBXBuildFile; productRef = 5F9292D4296743F400B2CBC8 /* iMoviesAPI */; };
|
||||
5F9292D82967440E00B2CBC8 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 5F9292D72967440E00B2CBC8 /* Kingfisher */; };
|
||||
5F9292DA2967474100B2CBC8 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F9292D92967474100B2CBC8 /* Launch Screen.storyboard */; };
|
||||
5F9292DB2967477200B2CBC8 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F9292D92967474100B2CBC8 /* Launch Screen.storyboard */; };
|
||||
5F9292DC2967477400B2CBC8 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F9292D92967474100B2CBC8 /* Launch Screen.storyboard */; };
|
||||
5F9292E2296749BA00B2CBC8 /* HomeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292E1296749BA00B2CBC8 /* HomeBuilder.swift */; };
|
||||
5F9292E4296749C200B2CBC8 /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292E3296749C200B2CBC8 /* HomeViewController.swift */; };
|
||||
5F9292E8296749E100B2CBC8 /* HomePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292E7296749E100B2CBC8 /* HomePresenter.swift */; };
|
||||
5F9292EA296749EA00B2CBC8 /* HomeInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292E9296749EA00B2CBC8 /* HomeInteractor.swift */; };
|
||||
5F9292EC296749FE00B2CBC8 /* HomeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292EB296749FE00B2CBC8 /* HomeRouter.swift */; };
|
||||
5F9292EE29674A0C00B2CBC8 /* DetailBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292ED29674A0C00B2CBC8 /* DetailBuilder.swift */; };
|
||||
5F9292F029674A1600B2CBC8 /* DetailPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292EF29674A1600B2CBC8 /* DetailPresenter.swift */; };
|
||||
5F9292F229674A2500B2CBC8 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292F129674A2500B2CBC8 /* DetailViewController.swift */; };
|
||||
5F9292F52968038A00B2CBC8 /* HomeContracts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292F42968038A00B2CBC8 /* HomeContracts.swift */; };
|
||||
5F9292F72968048800B2CBC8 /* HomeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9292F62968048800B2CBC8 /* HomeCell.swift */; };
|
||||
5FA4D079293FB304005D5501 /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F071760293F9F6E00A54133 /* AppRouter.swift */; };
|
||||
5FA4D07A293FB304005D5501 /* AppContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F07175E293F9F5300A54133 /* AppContainer.swift */; };
|
||||
5FA4D082293FB349005D5501 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FA4D081293FB349005D5501 /* AppDelegate.swift */; };
|
||||
5FA4D086293FB349005D5501 /* HomeController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FA4D085293FB349005D5501 /* HomeController.swift */; };
|
||||
5FA4D089293FB349005D5501 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5FA4D087293FB349005D5501 /* Main.storyboard */; };
|
||||
5FA4D08B293FB34A005D5501 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5FA4D08A293FB34A005D5501 /* Assets.xcassets */; };
|
||||
5FA4D08E293FB34A005D5501 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5FA4D08C293FB34A005D5501 /* LaunchScreen.storyboard */; };
|
||||
5FA4D0B0293FB384005D5501 /* AppContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FA4D0AF293FB384005D5501 /* AppContainer.swift */; };
|
||||
5FA4D0B2293FB398005D5501 /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FA4D0B1293FB398005D5501 /* AppRouter.swift */; };
|
||||
5FA4D0BC293FB499005D5501 /* iMoviesMVCTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FA4D0BB293FB499005D5501 /* iMoviesMVCTests.swift */; };
|
||||
5FE686ED294DB17300318A15 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE686EC294DB17300318A15 /* HomeView.swift */; };
|
||||
5FE686F0294DB1DC00318A15 /* ViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE686EF294DB1DC00318A15 /* ViewProtocol.swift */; };
|
||||
5FE686F4294DBD1F00318A15 /* ControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE686F3294DBD1F00318A15 /* ControllerProtocol.swift */; };
|
||||
5FE686F6294DBE7A00318A15 /* SplashController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE686F5294DBE7A00318A15 /* SplashController.swift */; };
|
||||
5FE686F0294DB1DC00318A15 /* BaseAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE686EF294DB1DC00318A15 /* BaseAppView.swift */; };
|
||||
5FE686F4294DBD1F00318A15 /* BaseAppController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE686F3294DBD1F00318A15 /* BaseAppController.swift */; };
|
||||
5FE686F8294DC07900318A15 /* HomeBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE686F7294DC07900318A15 /* HomeBuilder.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
|
@ -57,6 +107,13 @@
|
|||
remoteGlobalIDString = 5F071765293FA18600A54133;
|
||||
remoteInfo = iMoviesMVVM;
|
||||
};
|
||||
5F9292AA2967001500B2CBC8 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5F69D2C6293CE36100768933 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 5F9292932967001400B2CBC8;
|
||||
remoteInfo = iMoviesVIPER;
|
||||
};
|
||||
5FA4D095293FB34A005D5501 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 5F69D2C6293CE36100768933 /* Project object */;
|
||||
|
@ -90,7 +147,6 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
5F002484294DC32900E2D56B /* SplashBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashBuilder.swift; sourceTree = "<group>"; };
|
||||
5F002487294EFF2200E2D56B /* UIViewController+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extension.swift"; sourceTree = "<group>"; };
|
||||
5F002498294F332200E2D56B /* MoviePresentation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoviePresentation.swift; sourceTree = "<group>"; };
|
||||
5F0024AC294F386000E2D56B /* HomeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeCell.swift; sourceTree = "<group>"; };
|
||||
|
@ -102,31 +158,63 @@
|
|||
5F071760293F9F6E00A54133 /* AppRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouter.swift; sourceTree = "<group>"; };
|
||||
5F071766293FA18600A54133 /* iMoviesMVVM.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iMoviesMVVM.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5F071768293FA18600A54133 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
5F07176C293FA18600A54133 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
5F07176F293FA18600A54133 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
5F071771293FA18700A54133 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
5F071774293FA18700A54133 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
5F071776293FA18700A54133 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
5F07177B293FA18700A54133 /* iMoviesMVVMTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iMoviesMVVMTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5F07177F293FA18700A54133 /* iMoviesMVVMTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iMoviesMVVMTests.swift; sourceTree = "<group>"; };
|
||||
5F168BBB29631A9F0073BE71 /* ViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewProtocol.swift; sourceTree = "<group>"; };
|
||||
5F168BBD29631B570073BE71 /* ControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControllerProtocol.swift; sourceTree = "<group>"; };
|
||||
5F168BC7296329900073BE71 /* HomeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeCell.swift; sourceTree = "<group>"; };
|
||||
5F168BC929632A4F0073BE71 /* UIImageView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImageView+Extension.swift"; sourceTree = "<group>"; };
|
||||
5F168BD329632EAF0073BE71 /* DetailBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailBuilder.swift; sourceTree = "<group>"; };
|
||||
5F168BD629632EB80073BE71 /* DetailController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailController.swift; sourceTree = "<group>"; };
|
||||
5F168BD929632ED00073BE71 /* DetailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewModel.swift; sourceTree = "<group>"; };
|
||||
5F168BDC29632EDA0073BE71 /* DetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailView.swift; sourceTree = "<group>"; };
|
||||
5F23B3ED295F7689008090DD /* DetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailView.swift; sourceTree = "<group>"; };
|
||||
5F23B3EF295F7B38008090DD /* DetailController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailController.swift; sourceTree = "<group>"; };
|
||||
5F23B3F329600471008090DD /* DetailBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailBuilder.swift; sourceTree = "<group>"; };
|
||||
5F23B3F9296197CD008090DD /* ResourceLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceLoader.swift; sourceTree = "<group>"; };
|
||||
5F23B3FB29619821008090DD /* Optional+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Extension.swift"; sourceTree = "<group>"; };
|
||||
5F23B3FD29619886008090DD /* Array+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extension.swift"; sourceTree = "<group>"; };
|
||||
5F23B3FF29619CE7008090DD /* movie1.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = movie1.json; sourceTree = "<group>"; };
|
||||
5F23B40129619F06008090DD /* movie2.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = movie2.json; sourceTree = "<group>"; };
|
||||
5F23B40329619F0C008090DD /* movie3.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = movie3.json; sourceTree = "<group>"; };
|
||||
5F23B40F29631510008090DD /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
|
||||
5F23B41129631519008090DD /* HomeController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeController.swift; sourceTree = "<group>"; };
|
||||
5F23B41329631523008090DD /* HomeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = "<group>"; };
|
||||
5F23B4152963152C008090DD /* HomeBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeBuilder.swift; sourceTree = "<group>"; };
|
||||
5F4D7F79296881C4007180AA /* DetailContracts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailContracts.swift; sourceTree = "<group>"; };
|
||||
5F9292942967001400B2CBC8 /* iMoviesVIPER.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iMoviesVIPER.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5F9292962967001400B2CBC8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
5F92929F2967001500B2CBC8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
5F9292A42967001500B2CBC8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
5F9292A92967001500B2CBC8 /* iMoviesVIPERTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iMoviesVIPERTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5F9292AD2967001500B2CBC8 /* iMoviesVIPERTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iMoviesVIPERTests.swift; sourceTree = "<group>"; };
|
||||
5F9292CD296700BD00B2CBC8 /* AppContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppContainer.swift; sourceTree = "<group>"; };
|
||||
5F9292CF296700D000B2CBC8 /* AppRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouter.swift; sourceTree = "<group>"; };
|
||||
5F9292D92967474100B2CBC8 /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = "<group>"; };
|
||||
5F9292E1296749BA00B2CBC8 /* HomeBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeBuilder.swift; sourceTree = "<group>"; };
|
||||
5F9292E3296749C200B2CBC8 /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = "<group>"; };
|
||||
5F9292E7296749E100B2CBC8 /* HomePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomePresenter.swift; sourceTree = "<group>"; };
|
||||
5F9292E9296749EA00B2CBC8 /* HomeInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeInteractor.swift; sourceTree = "<group>"; };
|
||||
5F9292EB296749FE00B2CBC8 /* HomeRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeRouter.swift; sourceTree = "<group>"; };
|
||||
5F9292ED29674A0C00B2CBC8 /* DetailBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailBuilder.swift; sourceTree = "<group>"; };
|
||||
5F9292EF29674A1600B2CBC8 /* DetailPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailPresenter.swift; sourceTree = "<group>"; };
|
||||
5F9292F129674A2500B2CBC8 /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = "<group>"; };
|
||||
5F9292F42968038A00B2CBC8 /* HomeContracts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeContracts.swift; sourceTree = "<group>"; };
|
||||
5F9292F62968048800B2CBC8 /* HomeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeCell.swift; sourceTree = "<group>"; };
|
||||
5FA4D07F293FB349005D5501 /* iMoviesMVC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iMoviesMVC.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5FA4D081293FB349005D5501 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
5FA4D085293FB349005D5501 /* HomeController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeController.swift; sourceTree = "<group>"; };
|
||||
5FA4D088293FB349005D5501 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
5FA4D08A293FB34A005D5501 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
5FA4D08D293FB34A005D5501 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
5FA4D08F293FB34A005D5501 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
5FA4D094293FB34A005D5501 /* iMoviesMVCTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iMoviesMVCTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5FA4D0AF293FB384005D5501 /* AppContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppContainer.swift; sourceTree = "<group>"; };
|
||||
5FA4D0B1293FB398005D5501 /* AppRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouter.swift; sourceTree = "<group>"; };
|
||||
5FA4D0BB293FB499005D5501 /* iMoviesMVCTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iMoviesMVCTests.swift; sourceTree = "<group>"; };
|
||||
5FE686EC294DB17300318A15 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
|
||||
5FE686EF294DB1DC00318A15 /* ViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewProtocol.swift; sourceTree = "<group>"; };
|
||||
5FE686F3294DBD1F00318A15 /* ControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControllerProtocol.swift; sourceTree = "<group>"; };
|
||||
5FE686F5294DBE7A00318A15 /* SplashController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashController.swift; sourceTree = "<group>"; };
|
||||
5FE686EF294DB1DC00318A15 /* BaseAppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseAppView.swift; sourceTree = "<group>"; };
|
||||
5FE686F3294DBD1F00318A15 /* BaseAppController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseAppController.swift; sourceTree = "<group>"; };
|
||||
5FE686F7294DC07900318A15 /* HomeBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeBuilder.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
|
@ -135,6 +223,8 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5F168BD129632BE70073BE71 /* Kingfisher in Frameworks */,
|
||||
5F168BCE29632BBC0073BE71 /* iMoviesAPI in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -145,6 +235,22 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5F9292912967001400B2CBC8 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5F9292D82967440E00B2CBC8 /* Kingfisher in Frameworks */,
|
||||
5F9292D5296743F400B2CBC8 /* iMoviesAPI in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5F9292A62967001500B2CBC8 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5FA4D07C293FB349005D5501 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -168,8 +274,11 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
5F002487294EFF2200E2D56B /* UIViewController+Extension.swift */,
|
||||
5F168BC929632A4F0073BE71 /* UIImageView+Extension.swift */,
|
||||
5F23B3FD29619886008090DD /* Array+Extension.swift */,
|
||||
5F0024B3294F395F00E2D56B /* UITableView+Extension.swift */,
|
||||
5F0024B6294F397E00E2D56B /* UICollectionView+Extension.swift */,
|
||||
5F23B3FB29619821008090DD /* Optional+Extension.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
|
@ -189,8 +298,6 @@
|
|||
5FA4D0C0293FB57D005D5501 /* App */,
|
||||
5FA4D0C1293FB58D005D5501 /* Scenes */,
|
||||
5FA4D0C2293FB599005D5501 /* Resources */,
|
||||
5F07176E293FA18600A54133 /* Main.storyboard */,
|
||||
5F071773293FA18700A54133 /* LaunchScreen.storyboard */,
|
||||
5F071776293FA18700A54133 /* Info.plist */,
|
||||
);
|
||||
path = iMoviesMVVM;
|
||||
|
@ -204,12 +311,24 @@
|
|||
path = iMoviesMVVMTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F23B3EB295F6F0E008090DD /* Presentations */ = {
|
||||
5F168BBA29631A600073BE71 /* BaseProtocols */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F002498294F332200E2D56B /* MoviePresentation.swift */,
|
||||
5F168BBB29631A9F0073BE71 /* ViewProtocol.swift */,
|
||||
5F168BBD29631B570073BE71 /* ControllerProtocol.swift */,
|
||||
);
|
||||
path = Presentations;
|
||||
path = BaseProtocols;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F168BD229632E9F0073BE71 /* Detail */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F168BD329632EAF0073BE71 /* DetailBuilder.swift */,
|
||||
5F168BD629632EB80073BE71 /* DetailController.swift */,
|
||||
5F168BD929632ED00073BE71 /* DetailViewModel.swift */,
|
||||
5F168BDC29632EDA0073BE71 /* DetailView.swift */,
|
||||
);
|
||||
path = Detail;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F23B3EC295F766E008090DD /* Detail */ = {
|
||||
|
@ -222,13 +341,58 @@
|
|||
path = Detail;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F23B3F8296197C1008090DD /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F23B3F9296197CD008090DD /* ResourceLoader.swift */,
|
||||
5F23B3FF29619CE7008090DD /* movie1.json */,
|
||||
5F23B40129619F06008090DD /* movie2.json */,
|
||||
5F23B40329619F0C008090DD /* movie3.json */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F23B405296313E7008090DD /* Presentations */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F002498294F332200E2D56B /* MoviePresentation.swift */,
|
||||
);
|
||||
path = Presentations;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F23B4082963147E008090DD /* Commons */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F002486294EFF0D00E2D56B /* Extensions */,
|
||||
5F0024AF294F38BD00E2D56B /* Utils */,
|
||||
5F23B405296313E7008090DD /* Presentations */,
|
||||
);
|
||||
path = Commons;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F23B40E29631501008090DD /* Home */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F23B4152963152C008090DD /* HomeBuilder.swift */,
|
||||
5F23B40F29631510008090DD /* HomeView.swift */,
|
||||
5F23B41129631519008090DD /* HomeController.swift */,
|
||||
5F23B41329631523008090DD /* HomeViewModel.swift */,
|
||||
5F168BC7296329900073BE71 /* HomeCell.swift */,
|
||||
);
|
||||
path = Home;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F69D2C5293CE36100768933 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F9292D92967474100B2CBC8 /* Launch Screen.storyboard */,
|
||||
5F23B4082963147E008090DD /* Commons */,
|
||||
5FA4D080293FB349005D5501 /* iMoviesMVC */,
|
||||
5FA4D097293FB34A005D5501 /* iMoviesMVCTests */,
|
||||
5F071767293FA18600A54133 /* iMoviesMVVM */,
|
||||
5F07177E293FA18700A54133 /* iMoviesMVVMTests */,
|
||||
5F9292952967001400B2CBC8 /* iMoviesVIPER */,
|
||||
5F9292AC2967001500B2CBC8 /* iMoviesVIPERTests */,
|
||||
5F69D2CF293CE36100768933 /* Products */,
|
||||
5F69D304293DAE9000768933 /* Frameworks */,
|
||||
);
|
||||
|
@ -241,6 +405,8 @@
|
|||
5F07177B293FA18700A54133 /* iMoviesMVVMTests.xctest */,
|
||||
5FA4D07F293FB349005D5501 /* iMoviesMVC.app */,
|
||||
5FA4D094293FB34A005D5501 /* iMoviesMVCTests.xctest */,
|
||||
5F9292942967001400B2CBC8 /* iMoviesVIPER.app */,
|
||||
5F9292A92967001500B2CBC8 /* iMoviesVIPERTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
|
@ -252,17 +418,83 @@
|
|||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F9292952967001400B2CBC8 /* iMoviesVIPER */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F9292CC2967008A00B2CBC8 /* App */,
|
||||
5F9292DD2967498D00B2CBC8 /* Scenes */,
|
||||
5F9292F329674A4800B2CBC8 /* Resources */,
|
||||
5F9292A42967001500B2CBC8 /* Info.plist */,
|
||||
);
|
||||
path = iMoviesVIPER;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F9292AC2967001500B2CBC8 /* iMoviesVIPERTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F9292AD2967001500B2CBC8 /* iMoviesVIPERTests.swift */,
|
||||
);
|
||||
path = iMoviesVIPERTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F9292CC2967008A00B2CBC8 /* App */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F9292962967001400B2CBC8 /* AppDelegate.swift */,
|
||||
5F9292CD296700BD00B2CBC8 /* AppContainer.swift */,
|
||||
5F9292CF296700D000B2CBC8 /* AppRouter.swift */,
|
||||
);
|
||||
path = App;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F9292DD2967498D00B2CBC8 /* Scenes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F9292DE2967499A00B2CBC8 /* Home */,
|
||||
5F9292E0296749A900B2CBC8 /* Detail */,
|
||||
);
|
||||
path = Scenes;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F9292DE2967499A00B2CBC8 /* Home */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F9292E1296749BA00B2CBC8 /* HomeBuilder.swift */,
|
||||
5F9292EB296749FE00B2CBC8 /* HomeRouter.swift */,
|
||||
5F9292E3296749C200B2CBC8 /* HomeViewController.swift */,
|
||||
5F9292E7296749E100B2CBC8 /* HomePresenter.swift */,
|
||||
5F9292E9296749EA00B2CBC8 /* HomeInteractor.swift */,
|
||||
5F9292F42968038A00B2CBC8 /* HomeContracts.swift */,
|
||||
5F9292F62968048800B2CBC8 /* HomeCell.swift */,
|
||||
);
|
||||
path = Home;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F9292E0296749A900B2CBC8 /* Detail */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F9292ED29674A0C00B2CBC8 /* DetailBuilder.swift */,
|
||||
5F9292F129674A2500B2CBC8 /* DetailViewController.swift */,
|
||||
5F9292EF29674A1600B2CBC8 /* DetailPresenter.swift */,
|
||||
5F4D7F79296881C4007180AA /* DetailContracts.swift */,
|
||||
);
|
||||
path = Detail;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F9292F329674A4800B2CBC8 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F92929F2967001500B2CBC8 /* Assets.xcassets */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5FA4D080293FB349005D5501 /* iMoviesMVC */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F23B3EB295F6F0E008090DD /* Presentations */,
|
||||
5F0024AF294F38BD00E2D56B /* Utils */,
|
||||
5F002486294EFF0D00E2D56B /* Extensions */,
|
||||
5FA4D0BD293FB4BD005D5501 /* App */,
|
||||
5FA4D0BE293FB526005D5501 /* Scenes */,
|
||||
5FA4D0BF293FB541005D5501 /* Resources */,
|
||||
5FA4D087293FB349005D5501 /* Main.storyboard */,
|
||||
5FA4D08C293FB34A005D5501 /* LaunchScreen.storyboard */,
|
||||
5FA4D08F293FB34A005D5501 /* Info.plist */,
|
||||
);
|
||||
path = iMoviesMVC;
|
||||
|
@ -271,6 +503,7 @@
|
|||
5FA4D097293FB34A005D5501 /* iMoviesMVCTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F23B3F8296197C1008090DD /* Resources */,
|
||||
5FA4D0BB293FB499005D5501 /* iMoviesMVCTests.swift */,
|
||||
);
|
||||
path = iMoviesMVCTests;
|
||||
|
@ -289,8 +522,7 @@
|
|||
5FA4D0BE293FB526005D5501 /* Scenes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5FE686EE294DB1C900318A15 /* Base */,
|
||||
5FE686F1294DBCB200318A15 /* Splash */,
|
||||
5FE686EE294DB1C900318A15 /* BaseProtocols */,
|
||||
5FE686EB294DB16200318A15 /* Home */,
|
||||
5F23B3EC295F766E008090DD /* Detail */,
|
||||
);
|
||||
|
@ -318,7 +550,9 @@
|
|||
5FA4D0C1293FB58D005D5501 /* Scenes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F07176C293FA18600A54133 /* ViewController.swift */,
|
||||
5F168BBA29631A600073BE71 /* BaseProtocols */,
|
||||
5F23B40E29631501008090DD /* Home */,
|
||||
5F168BD229632E9F0073BE71 /* Detail */,
|
||||
);
|
||||
path = Scenes;
|
||||
sourceTree = "<group>";
|
||||
|
@ -342,22 +576,13 @@
|
|||
path = Home;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5FE686EE294DB1C900318A15 /* Base */ = {
|
||||
5FE686EE294DB1C900318A15 /* BaseProtocols */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5FE686EF294DB1DC00318A15 /* ViewProtocol.swift */,
|
||||
5FE686F3294DBD1F00318A15 /* ControllerProtocol.swift */,
|
||||
5FE686EF294DB1DC00318A15 /* BaseAppView.swift */,
|
||||
5FE686F3294DBD1F00318A15 /* BaseAppController.swift */,
|
||||
);
|
||||
path = Base;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5FE686F1294DBCB200318A15 /* Splash */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F002484294DC32900E2D56B /* SplashBuilder.swift */,
|
||||
5FE686F5294DBE7A00318A15 /* SplashController.swift */,
|
||||
);
|
||||
path = Splash;
|
||||
path = BaseProtocols;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
@ -377,6 +602,10 @@
|
|||
dependencies = (
|
||||
);
|
||||
name = iMoviesMVVM;
|
||||
packageProductDependencies = (
|
||||
5F168BCD29632BBC0073BE71 /* iMoviesAPI */,
|
||||
5F168BD029632BE70073BE71 /* Kingfisher */,
|
||||
);
|
||||
productName = iMoviesMVVM;
|
||||
productReference = 5F071766293FA18600A54133 /* iMoviesMVVM.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
|
@ -399,6 +628,45 @@
|
|||
productReference = 5F07177B293FA18700A54133 /* iMoviesMVVMTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
5F9292932967001400B2CBC8 /* iMoviesVIPER */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 5F9292BB2967001500B2CBC8 /* Build configuration list for PBXNativeTarget "iMoviesVIPER" */;
|
||||
buildPhases = (
|
||||
5F9292902967001400B2CBC8 /* Sources */,
|
||||
5F9292912967001400B2CBC8 /* Frameworks */,
|
||||
5F9292922967001400B2CBC8 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = iMoviesVIPER;
|
||||
packageProductDependencies = (
|
||||
5F9292D4296743F400B2CBC8 /* iMoviesAPI */,
|
||||
5F9292D72967440E00B2CBC8 /* Kingfisher */,
|
||||
);
|
||||
productName = iMoviesVIPER;
|
||||
productReference = 5F9292942967001400B2CBC8 /* iMoviesVIPER.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
5F9292A82967001500B2CBC8 /* iMoviesVIPERTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 5F9292BE2967001500B2CBC8 /* Build configuration list for PBXNativeTarget "iMoviesVIPERTests" */;
|
||||
buildPhases = (
|
||||
5F9292A52967001500B2CBC8 /* Sources */,
|
||||
5F9292A62967001500B2CBC8 /* Frameworks */,
|
||||
5F9292A72967001500B2CBC8 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
5F9292AB2967001500B2CBC8 /* PBXTargetDependency */,
|
||||
);
|
||||
name = iMoviesVIPERTests;
|
||||
productName = iMoviesVIPERTests;
|
||||
productReference = 5F9292A92967001500B2CBC8 /* iMoviesVIPERTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
5FA4D07E293FB349005D5501 /* iMoviesMVC */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 5FA4D0A6293FB34B005D5501 /* Build configuration list for PBXNativeTarget "iMoviesMVC" */;
|
||||
|
@ -456,6 +724,13 @@
|
|||
CreatedOnToolsVersion = 13.4.1;
|
||||
TestTargetID = 5F071765293FA18600A54133;
|
||||
};
|
||||
5F9292932967001400B2CBC8 = {
|
||||
CreatedOnToolsVersion = 13.4.1;
|
||||
};
|
||||
5F9292A82967001500B2CBC8 = {
|
||||
CreatedOnToolsVersion = 13.4.1;
|
||||
TestTargetID = 5F9292932967001400B2CBC8;
|
||||
};
|
||||
5FA4D07E293FB349005D5501 = {
|
||||
CreatedOnToolsVersion = 13.4.1;
|
||||
};
|
||||
|
@ -478,6 +753,10 @@
|
|||
packageReferences = (
|
||||
5F23B3E3295F1767008090DD /* XCRemoteSwiftPackageReference "iMoviesAPI" */,
|
||||
5F23B3E8295F68A9008090DD /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||
5F168BCC29632BBC0073BE71 /* XCRemoteSwiftPackageReference "iMoviesAPI" */,
|
||||
5F168BCF29632BE70073BE71 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||
5F9292D3296743F400B2CBC8 /* XCRemoteSwiftPackageReference "iMoviesAPI" */,
|
||||
5F9292D62967440E00B2CBC8 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||
);
|
||||
productRefGroup = 5F69D2CF293CE36100768933 /* Products */;
|
||||
projectDirPath = "";
|
||||
|
@ -487,6 +766,8 @@
|
|||
5FA4D093293FB34A005D5501 /* iMoviesMVCTests */,
|
||||
5F071765293FA18600A54133 /* iMoviesMVVM */,
|
||||
5F07177A293FA18700A54133 /* iMoviesMVVMTests */,
|
||||
5F9292932967001400B2CBC8 /* iMoviesVIPER */,
|
||||
5F9292A82967001500B2CBC8 /* iMoviesVIPERTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
@ -496,9 +777,8 @@
|
|||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5F071775293FA18700A54133 /* LaunchScreen.storyboard in Resources */,
|
||||
5F9292DA2967474100B2CBC8 /* Launch Screen.storyboard in Resources */,
|
||||
5F071772293FA18700A54133 /* Assets.xcassets in Resources */,
|
||||
5F071770293FA18600A54133 /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -509,13 +789,28 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5F9292922967001400B2CBC8 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5F9292DC2967477400B2CBC8 /* Launch Screen.storyboard in Resources */,
|
||||
5F9292A02967001500B2CBC8 /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5F9292A72967001500B2CBC8 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5FA4D07D293FB349005D5501 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5FA4D08E293FB34A005D5501 /* LaunchScreen.storyboard in Resources */,
|
||||
5F9292DB2967477200B2CBC8 /* Launch Screen.storyboard in Resources */,
|
||||
5FA4D08B293FB34A005D5501 /* Assets.xcassets in Resources */,
|
||||
5FA4D089293FB349005D5501 /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -534,13 +829,26 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5F0024A9294F332200E2D56B /* MoviePresentation.swift in Sources */,
|
||||
5F168BDE29632EDA0073BE71 /* DetailView.swift in Sources */,
|
||||
5FA4D079293FB304005D5501 /* AppRouter.swift in Sources */,
|
||||
5F07176D293FA18600A54133 /* ViewController.swift in Sources */,
|
||||
5F0024AE294F386000E2D56B /* HomeCell.swift in Sources */,
|
||||
5F168BD829632EB80073BE71 /* DetailController.swift in Sources */,
|
||||
5F168BC8296329900073BE71 /* HomeCell.swift in Sources */,
|
||||
5F0024B2294F38CE00E2D56B /* Reuseable.swift in Sources */,
|
||||
5F168BC3296328FC0073BE71 /* UIViewController+Extension.swift in Sources */,
|
||||
5F0024B8294F397E00E2D56B /* UICollectionView+Extension.swift in Sources */,
|
||||
5F23B41229631519008090DD /* HomeController.swift in Sources */,
|
||||
5F168BC5296329230073BE71 /* ViewProtocol.swift in Sources */,
|
||||
5F168BC4296328FF0073BE71 /* Array+Extension.swift in Sources */,
|
||||
5F168BDB29632ED00073BE71 /* DetailViewModel.swift in Sources */,
|
||||
5F168BCB29632A4F0073BE71 /* UIImageView+Extension.swift in Sources */,
|
||||
5FA4D07A293FB304005D5501 /* AppContainer.swift in Sources */,
|
||||
5F23B41429631523008090DD /* HomeViewModel.swift in Sources */,
|
||||
5F168BD529632EAF0073BE71 /* DetailBuilder.swift in Sources */,
|
||||
5F0024BB294F3A3100E2D56B /* ThemeManager.swift in Sources */,
|
||||
5F168BC6296329270073BE71 /* ControllerProtocol.swift in Sources */,
|
||||
5F23B41029631510008090DD /* HomeView.swift in Sources */,
|
||||
5F23B4162963152C008090DD /* HomeBuilder.swift in Sources */,
|
||||
5F9292C92967005800B2CBC8 /* Optional+Extension.swift in Sources */,
|
||||
5F071769293FA18600A54133 /* AppDelegate.swift in Sources */,
|
||||
5F0024B5294F395F00E2D56B /* UITableView+Extension.swift in Sources */,
|
||||
);
|
||||
|
@ -554,28 +862,71 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5F9292902967001400B2CBC8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5F9292CB2967006C00B2CBC8 /* MoviePresentation.swift in Sources */,
|
||||
5F9292E4296749C200B2CBC8 /* HomeViewController.swift in Sources */,
|
||||
5F9292E2296749BA00B2CBC8 /* HomeBuilder.swift in Sources */,
|
||||
5F9292EA296749EA00B2CBC8 /* HomeInteractor.swift in Sources */,
|
||||
5F9292E8296749E100B2CBC8 /* HomePresenter.swift in Sources */,
|
||||
5F9292C82967005400B2CBC8 /* UICollectionView+Extension.swift in Sources */,
|
||||
5F9292C52967004D00B2CBC8 /* UIImageView+Extension.swift in Sources */,
|
||||
5F9292C42967004A00B2CBC8 /* UIViewController+Extension.swift in Sources */,
|
||||
5F9292EC296749FE00B2CBC8 /* HomeRouter.swift in Sources */,
|
||||
5F9292F52968038A00B2CBC8 /* HomeContracts.swift in Sources */,
|
||||
5F9292C72967005200B2CBC8 /* UITableView+Extension.swift in Sources */,
|
||||
5F9292F029674A1600B2CBC8 /* DetailPresenter.swift in Sources */,
|
||||
5F9292CA2967005800B2CBC8 /* Optional+Extension.swift in Sources */,
|
||||
5F9292D22967015000B2CBC8 /* ThemeManager.swift in Sources */,
|
||||
5F9292F72968048800B2CBC8 /* HomeCell.swift in Sources */,
|
||||
5F9292F229674A2500B2CBC8 /* DetailViewController.swift in Sources */,
|
||||
5F9292D12967014A00B2CBC8 /* Reuseable.swift in Sources */,
|
||||
5F9292D0296700D000B2CBC8 /* AppRouter.swift in Sources */,
|
||||
5F9292EE29674A0C00B2CBC8 /* DetailBuilder.swift in Sources */,
|
||||
5F4D7F7A296881C4007180AA /* DetailContracts.swift in Sources */,
|
||||
5F9292CE296700BD00B2CBC8 /* AppContainer.swift in Sources */,
|
||||
5F9292C62967004F00B2CBC8 /* Array+Extension.swift in Sources */,
|
||||
5F9292972967001400B2CBC8 /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5F9292A52967001500B2CBC8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5F9292AE2967001500B2CBC8 /* iMoviesVIPERTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
5FA4D07B293FB349005D5501 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5FE686F6294DBE7A00318A15 /* SplashController.swift in Sources */,
|
||||
5F23B3EE295F7689008090DD /* DetailView.swift in Sources */,
|
||||
5FA4D086293FB349005D5501 /* HomeController.swift in Sources */,
|
||||
5F23B3FE29619886008090DD /* Array+Extension.swift in Sources */,
|
||||
5F168BCA29632A4F0073BE71 /* UIImageView+Extension.swift in Sources */,
|
||||
5F002488294EFF2200E2D56B /* UIViewController+Extension.swift in Sources */,
|
||||
5FE686F4294DBD1F00318A15 /* ControllerProtocol.swift in Sources */,
|
||||
5F23B3FC29619821008090DD /* Optional+Extension.swift in Sources */,
|
||||
5FE686F4294DBD1F00318A15 /* BaseAppController.swift in Sources */,
|
||||
5F168BD429632EAF0073BE71 /* DetailBuilder.swift in Sources */,
|
||||
5F168BDA29632ED00073BE71 /* DetailViewModel.swift in Sources */,
|
||||
5F0024AD294F386000E2D56B /* HomeCell.swift in Sources */,
|
||||
5F0024B4294F395F00E2D56B /* UITableView+Extension.swift in Sources */,
|
||||
5F23B3F0295F7B38008090DD /* DetailController.swift in Sources */,
|
||||
5FA4D0B0293FB384005D5501 /* AppContainer.swift in Sources */,
|
||||
5FE686F0294DB1DC00318A15 /* ViewProtocol.swift in Sources */,
|
||||
5FE686F0294DB1DC00318A15 /* BaseAppView.swift in Sources */,
|
||||
5F0024B1294F38CE00E2D56B /* Reuseable.swift in Sources */,
|
||||
5FA4D082293FB349005D5501 /* AppDelegate.swift in Sources */,
|
||||
5F0024BA294F3A3100E2D56B /* ThemeManager.swift in Sources */,
|
||||
5F0024B7294F397E00E2D56B /* UICollectionView+Extension.swift in Sources */,
|
||||
5F168BDD29632EDA0073BE71 /* DetailView.swift in Sources */,
|
||||
5F168BD729632EB80073BE71 /* DetailController.swift in Sources */,
|
||||
5FE686F8294DC07900318A15 /* HomeBuilder.swift in Sources */,
|
||||
5FE686ED294DB17300318A15 /* HomeView.swift in Sources */,
|
||||
5F23B3F429600471008090DD /* DetailBuilder.swift in Sources */,
|
||||
5F002485294DC32900E2D56B /* SplashBuilder.swift in Sources */,
|
||||
5F0024A8294F332200E2D56B /* MoviePresentation.swift in Sources */,
|
||||
5FA4D0B2293FB398005D5501 /* AppRouter.swift in Sources */,
|
||||
);
|
||||
|
@ -585,6 +936,10 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5F23B40029619CE7008090DD /* movie1.json in Sources */,
|
||||
5F23B40429619F0C008090DD /* movie3.json in Sources */,
|
||||
5F23B40229619F06008090DD /* movie2.json in Sources */,
|
||||
5F23B3FA296197CD008090DD /* ResourceLoader.swift in Sources */,
|
||||
5FA4D0BC293FB499005D5501 /* iMoviesMVCTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -597,6 +952,11 @@
|
|||
target = 5F071765293FA18600A54133 /* iMoviesMVVM */;
|
||||
targetProxy = 5F07177C293FA18700A54133 /* PBXContainerItemProxy */;
|
||||
};
|
||||
5F9292AB2967001500B2CBC8 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 5F9292932967001400B2CBC8 /* iMoviesVIPER */;
|
||||
targetProxy = 5F9292AA2967001500B2CBC8 /* PBXContainerItemProxy */;
|
||||
};
|
||||
5FA4D096293FB34A005D5501 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 5FA4D07E293FB349005D5501 /* iMoviesMVC */;
|
||||
|
@ -604,41 +964,6 @@
|
|||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
5F07176E293FA18600A54133 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
5F07176F293FA18600A54133 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5F071773293FA18700A54133 /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
5F071774293FA18700A54133 /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5FA4D087293FB349005D5501 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
5FA4D088293FB349005D5501 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5FA4D08C293FB34A005D5501 /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
5FA4D08D293FB34A005D5501 /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
5F07178E293FA18700A54133 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
|
@ -651,8 +976,7 @@
|
|||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = iMoviesMVVM/Info.plist;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = Main;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = "Launch Screen";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -679,8 +1003,7 @@
|
|||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = iMoviesMVVM/Info.plist;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = Main;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = "Launch Screen";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -850,6 +1173,100 @@
|
|||
};
|
||||
name = Release;
|
||||
};
|
||||
5F9292BC2967001500B2CBC8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = JGMV95L4F7;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = iMoviesVIPER/Info.plist;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = "Launch Screen";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.eyupyasuntimur.iMoviesVIPER;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
5F9292BD2967001500B2CBC8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = JGMV95L4F7;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = iMoviesVIPER/Info.plist;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = "Launch Screen";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.eyupyasuntimur.iMoviesVIPER;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
5F9292BF2967001500B2CBC8 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = JGMV95L4F7;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.5;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.eyupyasuntimur.iMoviesVIPERTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iMoviesVIPER.app/iMoviesVIPER";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
5F9292C02967001500B2CBC8 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = JGMV95L4F7;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.5;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.eyupyasuntimur.iMoviesVIPERTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iMoviesVIPER.app/iMoviesVIPER";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
5FA4D0A7293FB34B005D5501 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
|
@ -861,8 +1278,7 @@
|
|||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = iMoviesMVC/Info.plist;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = Main;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = "Launch Screen";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -889,8 +1305,7 @@
|
|||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = iMoviesMVC/Info.plist;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = Main;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = "Launch Screen";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -989,6 +1404,24 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
5F9292BB2967001500B2CBC8 /* Build configuration list for PBXNativeTarget "iMoviesVIPER" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
5F9292BC2967001500B2CBC8 /* Debug */,
|
||||
5F9292BD2967001500B2CBC8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
5F9292BE2967001500B2CBC8 /* Build configuration list for PBXNativeTarget "iMoviesVIPERTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
5F9292BF2967001500B2CBC8 /* Debug */,
|
||||
5F9292C02967001500B2CBC8 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
5FA4D0A6293FB34B005D5501 /* Build configuration list for PBXNativeTarget "iMoviesMVC" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
@ -1010,6 +1443,22 @@
|
|||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
5F168BCC29632BBC0073BE71 /* XCRemoteSwiftPackageReference "iMoviesAPI" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/yasuntimure/iMoviesAPI.git";
|
||||
requirement = {
|
||||
branch = development;
|
||||
kind = branch;
|
||||
};
|
||||
};
|
||||
5F168BCF29632BE70073BE71 /* XCRemoteSwiftPackageReference "Kingfisher" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/onevcat/Kingfisher.git";
|
||||
requirement = {
|
||||
branch = master;
|
||||
kind = branch;
|
||||
};
|
||||
};
|
||||
5F23B3E3295F1767008090DD /* XCRemoteSwiftPackageReference "iMoviesAPI" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/yasuntimure/iMoviesAPI.git";
|
||||
|
@ -1026,9 +1475,35 @@
|
|||
minimumVersion = 7.0.0;
|
||||
};
|
||||
};
|
||||
5F9292D3296743F400B2CBC8 /* XCRemoteSwiftPackageReference "iMoviesAPI" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/yasuntimure/iMoviesAPI.git";
|
||||
requirement = {
|
||||
branch = development;
|
||||
kind = branch;
|
||||
};
|
||||
};
|
||||
5F9292D62967440E00B2CBC8 /* XCRemoteSwiftPackageReference "Kingfisher" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/onevcat/Kingfisher.git";
|
||||
requirement = {
|
||||
branch = master;
|
||||
kind = branch;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
5F168BCD29632BBC0073BE71 /* iMoviesAPI */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 5F23B3E3295F1767008090DD /* XCRemoteSwiftPackageReference "iMoviesAPI" */;
|
||||
productName = iMoviesAPI;
|
||||
};
|
||||
5F168BD029632BE70073BE71 /* Kingfisher */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 5F168BCF29632BE70073BE71 /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
||||
productName = Kingfisher;
|
||||
};
|
||||
5F23B3E4295F1767008090DD /* iMoviesAPI */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 5F23B3E3295F1767008090DD /* XCRemoteSwiftPackageReference "iMoviesAPI" */;
|
||||
|
@ -1039,6 +1514,16 @@
|
|||
package = 5F23B3E8295F68A9008090DD /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
||||
productName = Kingfisher;
|
||||
};
|
||||
5F9292D4296743F400B2CBC8 /* iMoviesAPI */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 5F23B3E3295F1767008090DD /* XCRemoteSwiftPackageReference "iMoviesAPI" */;
|
||||
productName = iMoviesAPI;
|
||||
};
|
||||
5F9292D72967440E00B2CBC8 /* Kingfisher */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 5F168BCF29632BE70073BE71 /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
||||
productName = Kingfisher;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 5F69D2C6293CE36100768933 /* Project object */;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
import UIKit
|
||||
|
||||
@main
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
|
|
|
@ -16,7 +16,7 @@ final class AppRouter {
|
|||
}
|
||||
|
||||
func start() {
|
||||
window.rootViewController = SplashBuilder.make()
|
||||
window.rootViewController = HomeBuilder.make()
|
||||
window.makeKeyAndVisible()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,17 +3,3 @@
|
|||
<plist version="1.0">
|
||||
<dict/>
|
||||
</plist>
|
||||
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>https://api.nytimes.com</key>
|
||||
<dict>
|
||||
<key>NSExceptionRequiresForwardSecrecy</key>
|
||||
<false/>
|
||||
<key>NSIncludesSubdomains</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// ControllerProtocol.swift
|
||||
// iMoviesMVC
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 17.12.2022.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public protocol BaseAppController {
|
||||
associatedtype ViewType: BaseAppView
|
||||
var viewImpl: ViewType? { get set }
|
||||
func registerObservers()
|
||||
func configureController()
|
||||
}
|
||||
|
||||
extension BaseAppController where Self: UIViewController {
|
||||
public var viewImpl: ViewType? {
|
||||
get { return self.view as? ViewType }
|
||||
set {}
|
||||
}
|
||||
|
||||
public func configureController() {
|
||||
self.registerObservers()
|
||||
self.navigationController?.isNavigationBarHidden = false
|
||||
self.setNeedsStatusBarAppearanceUpdate()
|
||||
}
|
||||
}
|
|
@ -8,17 +8,17 @@
|
|||
import Combine
|
||||
import UIKit
|
||||
|
||||
// MARK: Base View Protocol
|
||||
// MARK: Base App View Protocol
|
||||
|
||||
public protocol ViewProtocol: AnyObject {
|
||||
public protocol BaseAppView: AnyObject {
|
||||
func setup()
|
||||
func setConstraints()
|
||||
func registerObservers()
|
||||
}
|
||||
|
||||
extension ViewProtocol where Self: UIView {
|
||||
extension BaseAppView where Self: UIView {
|
||||
|
||||
/// Start initializing the base `AppView` protocol methods
|
||||
/// Start initializing the base `BaseAppView` protocol methods
|
||||
public func configureContents() {
|
||||
self.setup()
|
||||
self.registerObservers()
|
|
@ -9,7 +9,7 @@ import UIKit
|
|||
import Combine
|
||||
import iMoviesAPI
|
||||
|
||||
class DetailController: UIViewController, ControllerProtocol {
|
||||
class DetailController: UIViewController, BaseAppController {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import UIKit
|
|||
import Combine
|
||||
import iMoviesAPI
|
||||
|
||||
final class DetailView: UIView, ViewProtocol, UIScrollViewDelegate {
|
||||
final class DetailView: UIView, BaseAppView, UIScrollViewDelegate {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
|
@ -69,7 +69,7 @@ final class DetailView: UIView, ViewProtocol, UIScrollViewDelegate {
|
|||
}
|
||||
|
||||
|
||||
final class HeaderView: UIView, ViewProtocol {
|
||||
final class HeaderView: UIView, BaseAppView {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
|
@ -132,7 +132,7 @@ final class HeaderView: UIView, ViewProtocol {
|
|||
|
||||
}
|
||||
|
||||
final class BodyView: UIView, ViewProtocol {
|
||||
final class BodyView: UIView, BaseAppView {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ final class HomeBuilder {
|
|||
|
||||
static func make() -> HomeController {
|
||||
let view = HomeView()
|
||||
let controller = HomeController(view: view, service: app.service)
|
||||
let controller = HomeController(view: view,
|
||||
service: app.service)
|
||||
return controller
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import Combine
|
|||
import Kingfisher
|
||||
import iMoviesAPI
|
||||
|
||||
class HomeCell: UITableViewCell, ViewProtocol, Reuseable {
|
||||
class HomeCell: UITableViewCell, BaseAppView, Reuseable {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
|
@ -87,18 +87,3 @@ class HomeCell: UITableViewCell, ViewProtocol, Reuseable {
|
|||
])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Kingfiher
|
||||
extension UIImageView {
|
||||
|
||||
func setKfImage(for urlString: String?) {
|
||||
guard let urlString = urlString else {
|
||||
return
|
||||
}
|
||||
let url = URL(string: urlString)
|
||||
self.kf.indicatorType = .activity
|
||||
self.kf.setImage(with: url, options: KingfisherManager.shared.defaultOptions)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import UIKit
|
|||
import Combine
|
||||
import iMoviesAPI
|
||||
|
||||
class HomeController: UIViewController, ControllerProtocol {
|
||||
class HomeController: UIViewController, BaseAppController {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
|
||||
import UIKit
|
||||
import Combine
|
||||
import iMoviesAPI
|
||||
|
||||
final class HomeView: UIView, ViewProtocol {
|
||||
final class HomeView: UIView, BaseAppView {
|
||||
|
||||
var onCellSelect: ((_ movie: MoviePresentation) -> Void)?
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
@Published public var movies: [MoviePresentation] = []
|
||||
@Published public var movies: MoviePresentations = []
|
||||
@Published public var isLoading: Bool = false
|
||||
|
||||
lazy var tableView: UITableView = {
|
||||
|
@ -45,6 +44,7 @@ final class HomeView: UIView, ViewProtocol {
|
|||
|
||||
func registerObservers() {
|
||||
$movies
|
||||
.dropFirst()
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { _ in
|
||||
self.tableView.reloadData()
|
||||
|
@ -80,6 +80,7 @@ extension HomeView: UITableViewDelegate {
|
|||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: false)
|
||||
self.onCellSelect?(movies[indexPath.row])
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
//
|
||||
// SplashBuilder.swift
|
||||
// iMoviesMVC
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 17.12.2022.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
final class SplashBuilder {
|
||||
|
||||
static func make() -> SplashController {
|
||||
let storyboard = UIStoryboard(name: "Main", bundle: nil)
|
||||
let controller = storyboard.instantiateViewController(withIdentifier: "SplashController") as! SplashController
|
||||
return controller
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
//
|
||||
// SplashController.swift
|
||||
// iMoviesMVC
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 17.12.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
final class SplashController: UIViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
|
||||
let homeController = HomeBuilder.make()
|
||||
self.present(homeController.embedInNavigationController(), animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// ResourceLoader.swift
|
||||
// iMoviesMVCTests
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 1.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import iMoviesAPI
|
||||
|
||||
class ResourceLoader {
|
||||
|
||||
enum MovieResource: String {
|
||||
case movie1
|
||||
case movie2
|
||||
case movie3
|
||||
}
|
||||
|
||||
static func loadMovie(resource: MovieResource) throws -> Movie {
|
||||
let bundle = Bundle.test
|
||||
let url = try bundle.url(forResource: resource.rawValue, withExtension: ".json").unwrap()
|
||||
let data = try Data(contentsOf: url)
|
||||
let decoder = Decoders.plainDateDecoder
|
||||
let movie = try decoder.decode(Movie.self, from: data)
|
||||
return movie
|
||||
}
|
||||
}
|
||||
|
||||
private extension Bundle {
|
||||
class Dummy { }
|
||||
static let test = Bundle(for: Dummy.self)
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"display_title": "The 22nd Annual Animation Show of Shows",
|
||||
"mpaa_rating": "",
|
||||
"critics_pick": 0,
|
||||
"byline": "Jeannette Catsoulis",
|
||||
"headline": "‘Annual Animation Show of Shows’ Review: A Mix of Whimsy and Dread",
|
||||
"summary_short": "This festival’s 22nd edition covers themes of crisis, both personal and planetary, with short works from the likes of Gil Alkabetz and Frédéric Back.",
|
||||
"publication_date": "2022-12-29",
|
||||
"opening_date": null,
|
||||
"date_updated": "2022-12-29 19:42:13",
|
||||
"link": {
|
||||
"type": "article",
|
||||
"url": "https://www.nytimes.com/2022/12/29/movies/annual-animation-show-of-shows-review.html",
|
||||
"suggested_link_text": "Read the New York Times Review of The 22nd Annual Animation Show of Shows"
|
||||
},
|
||||
"multimedia": {
|
||||
"type": "mediumThreeByTwo210",
|
||||
"src": "https://static01.nyt.com/images/2022/12/29/multimedia/29animation-show-review-1-856a/29animation-show-review-1-856a-mediumThreeByTwo440.jpg",
|
||||
"height": 140,
|
||||
"width": 210
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
|
||||
{
|
||||
"display_title": "Farha",
|
||||
"mpaa_rating": "",
|
||||
"critics_pick": 0,
|
||||
"byline": "Beatrice Loayza",
|
||||
"headline": "‘Farha’ Review: A Most Brutal Coming-of-Age Story",
|
||||
"summary_short": "Set in the early days of the Israeli-Palestinian conflict, this drama depicts the upheaval of Palestinian society from a 14-year-old girl’s perspective.",
|
||||
"publication_date": "2022-12-01",
|
||||
"opening_date": null,
|
||||
"date_updated": "2022-12-01 16:32:03",
|
||||
"link": {
|
||||
"type": "article",
|
||||
"url": "https://www.nytimes.com/2022/12/01/movies/farha-review.html",
|
||||
"suggested_link_text": "Read the New York Times Review of Farha"
|
||||
},
|
||||
"multimedia": {
|
||||
"type": "mediumThreeByTwo210",
|
||||
"src": "https://static01.nyt.com/images/2022/12/01/multimedia/01farha-review-1-26c4/01farha-review-1-26c4-mediumThreeByTwo440.jpg",
|
||||
"height": 140,
|
||||
"width": 210
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
{
|
||||
"display_title": "A Man Called Otto",
|
||||
"mpaa_rating": "PG-13",
|
||||
"critics_pick": 0,
|
||||
"byline": "Glenn Kenny",
|
||||
"headline": "‘A Man Called Otto’ Review: Tom Hanks Learns Life Lessons",
|
||||
"summary_short": "Going against nice-guy type (at first), the star plays a misanthrope who’s pulled into caring for a neighboring family in need.",
|
||||
"publication_date": "2022-12-29",
|
||||
"opening_date": "2023-01-04",
|
||||
"date_updated": "2022-12-29 12:02:02",
|
||||
"link": {
|
||||
"type": "article",
|
||||
"url": "https://www.nytimes.com/2022/12/29/movies/a-man-called-otto-review.html",
|
||||
"suggested_link_text": "Read the New York Times Review of A Man Called Otto"
|
||||
},
|
||||
"multimedia": {
|
||||
"type": "mediumThreeByTwo210",
|
||||
"src": "https://static01.nyt.com/images/2022/12/30/multimedia/29man-called-otto-1-438a/29man-called-otto-1-438a-mediumThreeByTwo440.jpg",
|
||||
"height": 140,
|
||||
"width": 210
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6,30 +6,49 @@
|
|||
//
|
||||
|
||||
import XCTest
|
||||
@testable import iMoviesAPI
|
||||
@testable import iMoviesMVC
|
||||
|
||||
class iMoviesMVCTests: XCTestCase {
|
||||
|
||||
fileprivate var service: MockService!
|
||||
var view: HomeView!
|
||||
var controller: HomeController!
|
||||
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
service = MockService()
|
||||
view = HomeView()
|
||||
controller = HomeController()
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
service = nil
|
||||
view = nil
|
||||
controller = nil
|
||||
}
|
||||
|
||||
func testExample() throws {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
// Any test you write for XCTest can be annotated as throws and async.
|
||||
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
|
||||
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
|
||||
}
|
||||
func testMovieList() throws {
|
||||
|
||||
func testPerformanceExample() throws {
|
||||
// This is an example of a performance test case.
|
||||
self.measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
// Given
|
||||
let movie1 = try ResourceLoader.loadMovie(resource: .movie1)
|
||||
service.movies = [movie1]
|
||||
|
||||
// When
|
||||
controller.loadViewIfNeeded()
|
||||
|
||||
// Then
|
||||
XCTAssertEqual(view.movies.count, 1)
|
||||
XCTAssertEqual(try view.movies.element(at: 0).title, movie1.displayTitle)
|
||||
}
|
||||
}
|
||||
|
||||
private final class MockService: WebServiceProtocol {
|
||||
|
||||
var movies: [Movie] = []
|
||||
|
||||
func search(movie: String, completion: @escaping ([Movie]?) -> Void) {
|
||||
completion(movies)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
//import iMoviesAPI
|
||||
import iMoviesAPI
|
||||
|
||||
let app = AppContainer()
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ import UIKit
|
|||
@main
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
func application(_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
app.router.start()
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@ final class AppRouter {
|
|||
}
|
||||
|
||||
func start() {
|
||||
let viewController = ViewController()
|
||||
let navigationController = UINavigationController(rootViewController: viewController)
|
||||
let homeController = HomeBuilder.make()
|
||||
let navigationController = homeController.embedInNavigationController()
|
||||
window.rootViewController = navigationController
|
||||
window.makeKeyAndVisible()
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Home Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="HomeController" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "logo.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 10 KiB |
|
@ -1,10 +1,11 @@
|
|||
//
|
||||
// ControllerProtocol.swift
|
||||
// iMoviesMVC
|
||||
// iMoviesMVVM
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 17.12.2022.
|
||||
// Created by Eyüp Yasuntimur on 2.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public protocol ControllerProtocol {
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// BaseViewProtocol.swift
|
||||
// iMoviesMVVM
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 2.01.2023.
|
||||
//
|
||||
|
||||
#if canImport(UIKit)
|
||||
import UIKit
|
||||
|
||||
// MARK: View Protocol
|
||||
|
||||
public protocol ViewProtocol: AnyObject {
|
||||
associatedtype ViewModel
|
||||
var viewModel: ViewModel? { get set }
|
||||
func setup()
|
||||
func registerObservers()
|
||||
func setConstraints()
|
||||
func configureView(_ viewModel: ViewModel?)
|
||||
}
|
||||
|
||||
extension ViewProtocol where Self: UIView {
|
||||
|
||||
/// Start initializing the base `ViewProtocol` methods
|
||||
public func configureContents() {
|
||||
self.setup()
|
||||
self.registerObservers()
|
||||
self.setConstraints()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// DetailBuilder.swift
|
||||
// iMovies
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 2.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
final class DetailBuilder {
|
||||
|
||||
static func make(movie: MoviePresentation) -> DetailController {
|
||||
let view = DetailView()
|
||||
let viewModel = DetailViewModel(movie: movie)
|
||||
let controller = DetailController(view: view,
|
||||
viewModel: viewModel)
|
||||
return controller
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// DetailController.swift
|
||||
// iMovies
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 2.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
import iMoviesAPI
|
||||
|
||||
class DetailController: UIViewController, ControllerProtocol {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
@Published internal var viewImpl: DetailView?
|
||||
@Published internal var viewModel: DetailViewModel?
|
||||
|
||||
convenience init(
|
||||
view: DetailView?,
|
||||
viewModel: DetailViewModel?
|
||||
) {
|
||||
self.init(nibName: nil, bundle: nil)
|
||||
self.viewImpl = view
|
||||
self.viewModel = viewModel
|
||||
self.configureController()
|
||||
}
|
||||
|
||||
func registerObservers() {
|
||||
|
||||
$viewImpl.sink { [weak self] _view in
|
||||
guard let view = _view else { return }
|
||||
view.frame = UIScreen.main.bounds
|
||||
// TODO: view implementation
|
||||
self?.view.addSubview(view)
|
||||
}.store(in: &subscribers)
|
||||
|
||||
viewModel?.$movie.sink { [weak self] (movie) in
|
||||
self?.viewImpl?.viewModel = movie
|
||||
}.store(in: &subscribers)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
//
|
||||
// DetailView.swift
|
||||
// iMovies
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 2.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
final class DetailView: UIView, ViewProtocol {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
@Published public var viewModel: MoviePresentation?
|
||||
@Published public var isLoading: Bool = false
|
||||
|
||||
lazy var headerView: HeaderView = {
|
||||
let view = HeaderView()
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var bodyView: BodyView = {
|
||||
let view = BodyView()
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
configureContents()
|
||||
registerObservers()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func setup() {
|
||||
self.backgroundColor = .systemBackground
|
||||
addSubview(headerView)
|
||||
addSubview(bodyView)
|
||||
}
|
||||
|
||||
func registerObservers() {
|
||||
$viewModel
|
||||
.dropFirst()
|
||||
.sink { model in
|
||||
self.configureView(model)
|
||||
}.store(in: &subscribers)
|
||||
}
|
||||
|
||||
func configureView(_ viewModel: MoviePresentation?) {
|
||||
self.headerView.viewModel = viewModel
|
||||
self.bodyView.viewModel = viewModel?.summary
|
||||
}
|
||||
|
||||
func setConstraints() {
|
||||
headerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
bodyView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
headerView.topAnchor.constraint(equalTo: topAnchor),
|
||||
headerView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
headerView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
headerView.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.height / 3),
|
||||
|
||||
bodyView.topAnchor.constraint(equalTo: headerView.bottomAnchor),
|
||||
bodyView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
bodyView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
bodyView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
final class HeaderView: UIView, ViewProtocol {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
@Published public var viewModel: MoviePresentation?
|
||||
|
||||
lazy var thumbImage: UIImageView = {
|
||||
let view = UIImageView()
|
||||
view.contentMode = .scaleAspectFill
|
||||
view.alpha = 0.7
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = ThemeManager.Font.Black.font(size: .xlarge)
|
||||
label.textColor = .white
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
configureContents()
|
||||
registerObservers()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func setup() {
|
||||
self.backgroundColor = .black
|
||||
[thumbImage, titleLabel].forEach({ addSubview($0) })
|
||||
}
|
||||
|
||||
func registerObservers() {
|
||||
$viewModel
|
||||
.dropFirst()
|
||||
.sink { model in
|
||||
self.configureView(model)
|
||||
}.store(in: &subscribers)
|
||||
}
|
||||
|
||||
func configureView(_ viewModel: MoviePresentation?) {
|
||||
self.titleLabel.text = viewModel?.title
|
||||
self.thumbImage.setKfImage(for: viewModel?.imageUrl)
|
||||
}
|
||||
|
||||
func setConstraints() {
|
||||
[thumbImage, titleLabel].forEach({
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
})
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
thumbImage.topAnchor.constraint(equalTo: topAnchor),
|
||||
thumbImage.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
thumbImage.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
thumbImage.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
|
||||
titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 15),
|
||||
titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -15),
|
||||
titleLabel.bottomAnchor.constraint(equalTo: thumbImage.bottomAnchor, constant: -5)
|
||||
])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final class BodyView: UIView, ViewProtocol {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
@Published public var viewModel: String?
|
||||
|
||||
lazy var summaryLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = ThemeManager.Font.Book.font(size: .medium)
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
configureContents()
|
||||
registerObservers()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func setup() {
|
||||
self.backgroundColor = .systemBackground
|
||||
addSubview(summaryLabel)
|
||||
}
|
||||
|
||||
func registerObservers() {
|
||||
$viewModel
|
||||
.dropFirst()
|
||||
.sink { model in
|
||||
self.configureView(model)
|
||||
}.store(in: &subscribers)
|
||||
}
|
||||
|
||||
func configureView(_ viewModel: String?) {
|
||||
self.summaryLabel.text = viewModel
|
||||
}
|
||||
|
||||
func setConstraints() {
|
||||
summaryLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
summaryLabel.topAnchor.constraint(equalTo: topAnchor, constant: 25),
|
||||
summaryLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20),
|
||||
summaryLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20),
|
||||
])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// DetailViewModel.swift
|
||||
// iMovies
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 2.01.2023.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import iMoviesAPI
|
||||
|
||||
final class DetailViewModel {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
@Published var movie: MoviePresentation?
|
||||
|
||||
init(movie: MoviePresentation?) {
|
||||
self.movie = movie
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// HomeBuilder.swift
|
||||
// iMoviesMVVM
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 2.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
final class HomeBuilder {
|
||||
|
||||
static func make() -> HomeController {
|
||||
let view = HomeView()
|
||||
let viewModel = HomeViewModel(service: app.service)
|
||||
let controller = HomeController(view: view,
|
||||
viewModel: viewModel)
|
||||
return controller
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
//
|
||||
// HomeCell.swift
|
||||
// iMoviesMVVM
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 2.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Combine
|
||||
import Kingfisher
|
||||
import iMoviesAPI
|
||||
|
||||
class HomeCell: UITableViewCell, ViewProtocol, Reuseable {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
@Published internal var viewModel: MoviePresentation?
|
||||
|
||||
lazy var thumbImage: UIImageView = {
|
||||
let view = UIImageView()
|
||||
view.contentMode = .scaleAspectFill
|
||||
view.layer.cornerRadius = 12
|
||||
view.clipsToBounds = true
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = ThemeManager.Font.Medium.font(size: .mediumlarge)
|
||||
label.numberOfLines = 1
|
||||
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var detailLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = ThemeManager.Font.Roman.font(size: .smallmedium)
|
||||
label.numberOfLines = 3
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
self.configureContents()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func setup() {
|
||||
[thumbImage, titleLabel, detailLabel].forEach { contentView.addSubview($0) }
|
||||
}
|
||||
|
||||
func registerObservers() {
|
||||
$viewModel.sink { model in
|
||||
self.configureView(model)
|
||||
}.store(in: &subscribers)
|
||||
}
|
||||
|
||||
func configureView(_ viewModel: MoviePresentation?) {
|
||||
self.titleLabel.text = viewModel?.title
|
||||
self.detailLabel.text = viewModel?.summary
|
||||
self.thumbImage.setKfImage(for: viewModel?.imageUrl)
|
||||
}
|
||||
|
||||
func setConstraints() {
|
||||
[contentView, thumbImage, titleLabel, detailLabel]
|
||||
.forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
contentView.topAnchor.constraint(equalTo: topAnchor),
|
||||
contentView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
contentView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
contentView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
|
||||
thumbImage.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20),
|
||||
thumbImage.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 18),
|
||||
thumbImage.heightAnchor.constraint(equalToConstant: 85),
|
||||
thumbImage.widthAnchor.constraint(equalToConstant: 100),
|
||||
|
||||
titleLabel.topAnchor.constraint(equalTo: thumbImage.topAnchor),
|
||||
titleLabel.leadingAnchor.constraint(equalTo: thumbImage.trailingAnchor, constant: 15),
|
||||
titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15),
|
||||
|
||||
detailLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 5),
|
||||
detailLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor),
|
||||
detailLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -18),
|
||||
detailLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -15)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// HomeController.swift
|
||||
// iMoviesMVVM
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 2.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
class HomeController: UIViewController, ControllerProtocol {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
@Published internal var viewImpl: HomeView?
|
||||
@Published internal var viewModel: HomeViewModel?
|
||||
|
||||
convenience init(
|
||||
view: HomeView?,
|
||||
viewModel: HomeViewModel?
|
||||
) {
|
||||
self.init(nibName: nil, bundle: nil)
|
||||
self.viewImpl = view
|
||||
self.viewModel = viewModel
|
||||
self.configureController()
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
viewModel?.searchReviews(for: "all")
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
title = "iMovies"
|
||||
}
|
||||
|
||||
func registerObservers() {
|
||||
$viewImpl.sink { [weak self] _view in
|
||||
guard let view = _view else { return }
|
||||
view.frame = UIScreen.main.bounds
|
||||
|
||||
view.onCellSelect = { movie in
|
||||
let controller = DetailBuilder.make(movie: movie)
|
||||
self?.navigationController?.pushViewController(controller, animated: true)
|
||||
}
|
||||
|
||||
self?.view.addSubview(view)
|
||||
}.store(in: &subscribers)
|
||||
|
||||
viewModel?.$movies.sink{ [weak self] (movies) in
|
||||
self?.viewImpl?.movies = movies
|
||||
}.store(in: &subscribers)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
//
|
||||
// HomeView.swift
|
||||
// iMoviesMVVM
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 2.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
final class HomeView: UIView, ViewProtocol {
|
||||
|
||||
var onCellSelect: ((_ movie: MoviePresentation) -> Void)?
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
var viewModel: String?
|
||||
|
||||
@Published public var movies: MoviePresentations = []
|
||||
@Published public var isLoading: Bool = false
|
||||
|
||||
lazy var tableView: UITableView = {
|
||||
let tableView = UITableView()
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
return tableView
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
configureContents()
|
||||
registerObservers()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func setup() {
|
||||
self.backgroundColor = .systemBackground
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.registerCell(type: HomeCell.self)
|
||||
|
||||
addSubview(tableView)
|
||||
}
|
||||
|
||||
func registerObservers() {
|
||||
$movies
|
||||
.dropFirst()
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { _ in
|
||||
self.tableView.reloadData()
|
||||
}.store(in: &subscribers)
|
||||
|
||||
$isLoading.sink { isLoading in
|
||||
//
|
||||
}.store(in: &subscribers)
|
||||
}
|
||||
|
||||
func configureView(_ viewModel: String?) { }
|
||||
|
||||
func setConstraints() {
|
||||
tableView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
tableView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor),
|
||||
tableView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
tableView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
tableView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UITableViewDelegate
|
||||
|
||||
extension HomeView: UITableViewDelegate {
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(forIndexPath: indexPath) as HomeCell
|
||||
cell.viewModel = movies[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: false)
|
||||
self.onCellSelect?(movies[indexPath.row])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UITableViewDataSource
|
||||
|
||||
extension HomeView: UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return movies.count
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// HomeViewModel.swift
|
||||
// iMoviesMVVM
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 2.01.2023.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import iMoviesAPI
|
||||
|
||||
final class HomeViewModel {
|
||||
|
||||
private var subscribers = Set<AnyCancellable>()
|
||||
|
||||
@Published var movies: MoviePresentations = []
|
||||
|
||||
internal var service: WebServiceProtocol?
|
||||
|
||||
init(service: WebServiceProtocol?) {
|
||||
self.service = service
|
||||
}
|
||||
|
||||
func searchReviews(for movie: String) {
|
||||
service?.search(movie: movie, completion: { [weak self] (response) in
|
||||
guard let response = response else {
|
||||
return
|
||||
}
|
||||
self?.movies = response.map(MoviePresentation.init)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// AppContainer.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import iMoviesAPI
|
||||
|
||||
let app = AppContainer()
|
||||
|
||||
final class AppContainer {
|
||||
|
||||
let router = AppRouter()
|
||||
let service = WebService()
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// AppDelegate.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@main
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
func application(_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
app.router.start()
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// AppRouter.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
final class AppRouter {
|
||||
|
||||
let window: UIWindow
|
||||
|
||||
init() {
|
||||
window = UIWindow(frame: UIScreen.main.bounds)
|
||||
}
|
||||
|
||||
func start() {
|
||||
let homeController = HomeBuilder.make()
|
||||
let navigationController = homeController.embedInNavigationController()
|
||||
window.rootViewController = navigationController
|
||||
window.makeKeyAndVisible()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict/>
|
||||
</plist>
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "76x76"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "76x76"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "83.5x83.5"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"scale" : "1x",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// DetailBuilder.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
final class DetailBuilder {
|
||||
|
||||
static func make(moviePresentation: MoviePresentation) -> DetailViewController {
|
||||
let viewController = DetailViewController()
|
||||
let presenter = DetailPresenter(view: viewController, moviePresentation: moviePresentation)
|
||||
viewController.presenter = presenter
|
||||
return viewController
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// DetailContracts.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 6.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
protocol DetailPresenterProtocol {
|
||||
func load()
|
||||
}
|
||||
|
||||
protocol DetailViewProtocol: AnyObject {
|
||||
func update(_ presentation: MoviePresentation)
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// DetailPresenter.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
final class DetailPresenter: DetailPresenterProtocol {
|
||||
|
||||
unowned var view: DetailViewProtocol
|
||||
|
||||
private let moviePresentation: MoviePresentation
|
||||
|
||||
init(
|
||||
view: DetailViewProtocol,
|
||||
moviePresentation: MoviePresentation
|
||||
) {
|
||||
self.view = view
|
||||
self.moviePresentation = moviePresentation
|
||||
}
|
||||
|
||||
func load() {
|
||||
view.update(moviePresentation)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
//
|
||||
// DetailView.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
final class DetailViewController: UIViewController, DetailViewProtocol {
|
||||
|
||||
internal var presenter: DetailPresenterProtocol?
|
||||
|
||||
lazy var headerView: HeaderView = {
|
||||
let view = HeaderView()
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var bodyView: BodyView = {
|
||||
let view = BodyView()
|
||||
return view
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
setup()
|
||||
presenter?.load()
|
||||
}
|
||||
|
||||
func setup() {
|
||||
view.backgroundColor = .systemBackground
|
||||
view.addSubview(headerView)
|
||||
view.addSubview(bodyView)
|
||||
setConstraints()
|
||||
}
|
||||
|
||||
func setConstraints() {
|
||||
headerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
bodyView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
headerView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
headerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
headerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
headerView.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.height / 3),
|
||||
|
||||
bodyView.topAnchor.constraint(equalTo: headerView.bottomAnchor),
|
||||
bodyView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
bodyView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
bodyView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
func update(_ presentation: MoviePresentation) {
|
||||
self.headerView.movie = presentation
|
||||
self.bodyView.summary = presentation.summary
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Header View
|
||||
|
||||
final class HeaderView: UIView {
|
||||
|
||||
internal var movie: MoviePresentation? {
|
||||
didSet {
|
||||
self.titleLabel.text = movie?.title
|
||||
self.thumbImage.setKfImage(for: movie?.imageUrl)
|
||||
}
|
||||
}
|
||||
|
||||
lazy var thumbImage: UIImageView = {
|
||||
let view = UIImageView()
|
||||
view.contentMode = .scaleAspectFill
|
||||
view.alpha = 0.7
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = ThemeManager.Font.Black.font(size: .xlarge)
|
||||
label.textColor = .white
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setup()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func setup() {
|
||||
self.backgroundColor = .black
|
||||
[thumbImage, titleLabel].forEach({ addSubview($0) })
|
||||
setConstraints()
|
||||
}
|
||||
|
||||
func setConstraints() {
|
||||
[thumbImage, titleLabel].forEach({
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
})
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
thumbImage.topAnchor.constraint(equalTo: topAnchor),
|
||||
thumbImage.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
thumbImage.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
thumbImage.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
|
||||
titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 15),
|
||||
titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -15),
|
||||
titleLabel.bottomAnchor.constraint(equalTo: thumbImage.bottomAnchor, constant: -5)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Body View
|
||||
|
||||
final class BodyView: UIView {
|
||||
|
||||
internal var summary: String? {
|
||||
didSet {
|
||||
self.summaryLabel.text = summary
|
||||
}
|
||||
}
|
||||
|
||||
lazy var summaryLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = ThemeManager.Font.Book.font(size: .medium)
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setup()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func setup() {
|
||||
self.backgroundColor = .systemBackground
|
||||
addSubview(summaryLabel)
|
||||
setConstraints()
|
||||
}
|
||||
|
||||
func setConstraints() {
|
||||
summaryLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
summaryLabel.topAnchor.constraint(equalTo: topAnchor, constant: 25),
|
||||
summaryLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20),
|
||||
summaryLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// HomeBuilder.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
final class HomeBuilder {
|
||||
|
||||
static func make() -> HomeViewController {
|
||||
let view = HomeViewController()
|
||||
let router = HomeRouter(view: view)
|
||||
let interactor = HomeInteractor(service: app.service)
|
||||
let presenter = HomePresenter(view: view,
|
||||
interactor: interactor,
|
||||
router: router)
|
||||
view.presenter = presenter
|
||||
return view
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// HomeCell.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 6.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Kingfisher
|
||||
|
||||
class HomeCell: UITableViewCell, Reuseable {
|
||||
|
||||
lazy var thumbImage: UIImageView = {
|
||||
let view = UIImageView()
|
||||
view.contentMode = .scaleAspectFill
|
||||
view.layer.cornerRadius = 12
|
||||
view.clipsToBounds = true
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = ThemeManager.Font.Medium.font(size: .mediumlarge)
|
||||
label.numberOfLines = 1
|
||||
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var detailLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = ThemeManager.Font.Roman.font(size: .smallmedium)
|
||||
label.numberOfLines = 3
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
setup()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func setup() {
|
||||
[thumbImage, titleLabel, detailLabel].forEach { contentView.addSubview($0) }
|
||||
setConstraints()
|
||||
}
|
||||
|
||||
func update(_ presentation: MoviePresentation?) {
|
||||
self.titleLabel.text = presentation?.title
|
||||
self.detailLabel.text = presentation?.summary
|
||||
self.thumbImage.setKfImage(for: presentation?.imageUrl)
|
||||
}
|
||||
|
||||
func setConstraints() {
|
||||
[contentView, thumbImage, titleLabel, detailLabel]
|
||||
.forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
contentView.topAnchor.constraint(equalTo: topAnchor),
|
||||
contentView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
contentView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
contentView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
|
||||
thumbImage.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20),
|
||||
thumbImage.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 18),
|
||||
thumbImage.heightAnchor.constraint(equalToConstant: 85),
|
||||
thumbImage.widthAnchor.constraint(equalToConstant: 100),
|
||||
|
||||
titleLabel.topAnchor.constraint(equalTo: thumbImage.topAnchor),
|
||||
titleLabel.leadingAnchor.constraint(equalTo: thumbImage.trailingAnchor, constant: 15),
|
||||
titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15),
|
||||
|
||||
detailLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 5),
|
||||
detailLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor),
|
||||
detailLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -18),
|
||||
detailLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -15)
|
||||
])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// HomeContracts.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 6.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import iMoviesAPI
|
||||
|
||||
// MARK: - Interactor
|
||||
|
||||
protocol HomeInteractorProtocol: AnyObject {
|
||||
var delegate: HomeInteractorDelegate? { get set }
|
||||
var service: WebServiceProtocol { get set }
|
||||
var movies: [Movie] { get set }
|
||||
func searchReviews()
|
||||
func selectMovie(at index: Int)
|
||||
}
|
||||
|
||||
protocol HomeInteractorDelegate: AnyObject {
|
||||
func handleOutput(_ output: HomeInteractorOutput)
|
||||
}
|
||||
|
||||
enum HomeInteractorOutput {
|
||||
case showMovies([Movie])
|
||||
case showMovieDetail(MoviePresentation)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Presenter
|
||||
|
||||
protocol HomePresenterProtocol: AnyObject {
|
||||
var view: HomeViewProtocol { get set }
|
||||
var router: HomeRouterProtocol { get set }
|
||||
var interactor: HomeInteractorProtocol { get set }
|
||||
func load()
|
||||
func selectMovie(at index: Int)
|
||||
}
|
||||
|
||||
enum HomePresenterOutput {
|
||||
case updateTitle(String)
|
||||
case showMovies([MoviePresentation])
|
||||
}
|
||||
|
||||
|
||||
// MARK: - View
|
||||
|
||||
protocol HomeViewProtocol: AnyObject {
|
||||
var movies: MoviePresentations { get set }
|
||||
var presenter: HomePresenterProtocol? { get set }
|
||||
func handleOutput(_ output: HomePresenterOutput)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Router
|
||||
|
||||
protocol HomeRouterProtocol: AnyObject {
|
||||
func navigate(to route: HomeRoute)
|
||||
}
|
||||
|
||||
enum HomeRoute {
|
||||
case detail(MoviePresentation)
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// HomeInteractor.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import iMoviesAPI
|
||||
|
||||
final class HomeInteractor: HomeInteractorProtocol {
|
||||
|
||||
var delegate: HomeInteractorDelegate?
|
||||
|
||||
internal var movies: [Movie] = []
|
||||
|
||||
internal var service: WebServiceProtocol
|
||||
|
||||
init(service: WebServiceProtocol) {
|
||||
self.service = service
|
||||
}
|
||||
|
||||
func searchReviews() {
|
||||
service.search(movie: "all", completion: { [weak self] (response) in
|
||||
guard let response = response else {
|
||||
return
|
||||
}
|
||||
self?.movies = response
|
||||
self?.delegate?.handleOutput(.showMovies(response))
|
||||
})
|
||||
}
|
||||
|
||||
func selectMovie(at index: Int) {
|
||||
let movie = movies[index]
|
||||
let moviePresentation = MoviePresentation(movie: movie)
|
||||
self.delegate?.handleOutput(.showMovieDetail(moviePresentation))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// HomePresenter.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
final class HomePresenter: HomePresenterProtocol {
|
||||
|
||||
internal var view: HomeViewProtocol
|
||||
internal var router: HomeRouterProtocol
|
||||
internal var interactor: HomeInteractorProtocol
|
||||
|
||||
init(view: HomeViewProtocol,
|
||||
interactor: HomeInteractorProtocol,
|
||||
router: HomeRouter
|
||||
) {
|
||||
self.view = view
|
||||
self.interactor = interactor
|
||||
self.router = router
|
||||
|
||||
interactor.delegate = self
|
||||
|
||||
view.handleOutput(.updateTitle("Movies"))
|
||||
}
|
||||
|
||||
func load() {
|
||||
interactor.searchReviews()
|
||||
}
|
||||
|
||||
func selectMovie(at index: Int) {
|
||||
interactor.selectMovie(at: index)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Home Interactor Delegate
|
||||
|
||||
extension HomePresenter: HomeInteractorDelegate {
|
||||
|
||||
func handleOutput(_ output: HomeInteractorOutput) {
|
||||
switch output {
|
||||
case .showMovies(let movies):
|
||||
let moviePresentations = movies.map(MoviePresentation.init)
|
||||
view.handleOutput(.showMovies(moviePresentations))
|
||||
case .showMovieDetail(let movie):
|
||||
router.navigate(to: .detail(movie))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// HomeRouter.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
final class HomeRouter: HomeRouterProtocol {
|
||||
|
||||
unowned let view: UIViewController
|
||||
|
||||
init(view: UIViewController) {
|
||||
self.view = view
|
||||
}
|
||||
|
||||
func navigate(to route: HomeRoute) {
|
||||
switch route {
|
||||
case .detail(let moviePresentation):
|
||||
let detailView = DetailBuilder.make(moviePresentation: moviePresentation)
|
||||
view.show(detailView, sender: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// HomeView.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
final class HomeViewController: UIViewController, HomeViewProtocol {
|
||||
|
||||
internal var presenter: HomePresenterProtocol?
|
||||
|
||||
internal var movies: MoviePresentations = []
|
||||
|
||||
lazy var tableView: UITableView = {
|
||||
let tableView = UITableView()
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.registerCell(type: HomeCell.self)
|
||||
return tableView
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
setup()
|
||||
presenter?.load()
|
||||
}
|
||||
|
||||
func setup() {
|
||||
view.backgroundColor = .systemBackground
|
||||
view.addSubview(tableView)
|
||||
setConstraints()
|
||||
}
|
||||
|
||||
func setConstraints() {
|
||||
tableView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
|
||||
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
||||
])
|
||||
}
|
||||
|
||||
func handleOutput(_ output: HomePresenterOutput) {
|
||||
switch output {
|
||||
case .updateTitle(let title):
|
||||
self.title = title
|
||||
case .showMovies(let movies):
|
||||
self.movies = movies
|
||||
DispatchQueue.main.async {
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UITableViewDelegate
|
||||
|
||||
extension HomeViewController: UITableViewDelegate {
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(forIndexPath: indexPath) as HomeCell
|
||||
cell.update(movies[indexPath.row])
|
||||
return cell
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
tableView.deselectRow(at: indexPath, animated: false)
|
||||
presenter?.selectMovie(at: indexPath.row)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - UITableViewDataSource
|
||||
|
||||
extension HomeViewController: UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return movies.count
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// AppDelegate.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@main
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: UISceneSession Lifecycle
|
||||
|
||||
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
|
||||
// Called when a new scene session is being created.
|
||||
// Use this method to select a configuration to create the new scene with.
|
||||
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
|
||||
// Called when the user discards a scene session.
|
||||
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
|
||||
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "76x76"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "83.5x83.5"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"scale" : "1x",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
|
@ -7,19 +7,18 @@
|
|||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<false/>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UISceneConfigurationName</key>
|
||||
<string>Default Configuration</string>
|
||||
<key>UISceneDelegateClassName</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
||||
<key>UISceneStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// SceneDelegate.swift
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
|
||||
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
||||
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
|
||||
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
|
||||
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
|
||||
guard let _ = (scene as? UIWindowScene) else { return }
|
||||
}
|
||||
|
||||
func sceneDidDisconnect(_ scene: UIScene) {
|
||||
// Called as the scene is being released by the system.
|
||||
// This occurs shortly after the scene enters the background, or when its session is discarded.
|
||||
// Release any resources associated with this scene that can be re-created the next time the scene connects.
|
||||
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
|
||||
}
|
||||
|
||||
func sceneDidBecomeActive(_ scene: UIScene) {
|
||||
// Called when the scene has moved from an inactive state to an active state.
|
||||
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
|
||||
}
|
||||
|
||||
func sceneWillResignActive(_ scene: UIScene) {
|
||||
// Called when the scene will move from an active state to an inactive state.
|
||||
// This may occur due to temporary interruptions (ex. an incoming phone call).
|
||||
}
|
||||
|
||||
func sceneWillEnterForeground(_ scene: UIScene) {
|
||||
// Called as the scene transitions from the background to the foreground.
|
||||
// Use this method to undo the changes made on entering the background.
|
||||
}
|
||||
|
||||
func sceneDidEnterBackground(_ scene: UIScene) {
|
||||
// Called as the scene transitions from the foreground to the background.
|
||||
// Use this method to save data, release shared resources, and store enough scene-specific state information
|
||||
// to restore the scene back to its current state.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
//
|
||||
// ViewController.swift
|
||||
// iMoviesMVVM
|
||||
// iMoviesVIPER
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 6.12.2022.
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
@ -11,8 +11,7 @@ class ViewController: UIViewController {
|
|||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
print("Hello MVVM")
|
||||
view.backgroundColor = .green
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// iMoviesVIPERTests.swift
|
||||
// iMoviesVIPERTests
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import iMoviesVIPER
|
||||
|
||||
class iMoviesVIPERTests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() throws {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
// Any test you write for XCTest can be annotated as throws and async.
|
||||
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
|
||||
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
|
||||
}
|
||||
|
||||
func testPerformanceExample() throws {
|
||||
// This is an example of a performance test case.
|
||||
self.measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// iMoviesVIPERUITests.swift
|
||||
// iMoviesVIPERUITests
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class iMoviesVIPERUITests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
|
||||
// In UI tests it is usually best to stop immediately when a failure occurs.
|
||||
continueAfterFailure = false
|
||||
|
||||
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() throws {
|
||||
// UI tests must launch the application that they test.
|
||||
let app = XCUIApplication()
|
||||
app.launch()
|
||||
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
}
|
||||
|
||||
func testLaunchPerformance() throws {
|
||||
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
|
||||
// This measures how long it takes to launch your application.
|
||||
measure(metrics: [XCTApplicationLaunchMetric()]) {
|
||||
XCUIApplication().launch()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// iMoviesVIPERUITestsLaunchTests.swift
|
||||
// iMoviesVIPERUITests
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class iMoviesVIPERUITestsLaunchTests: XCTestCase {
|
||||
|
||||
override class var runsForEachTargetApplicationUIConfiguration: Bool {
|
||||
true
|
||||
}
|
||||
|
||||
override func setUpWithError() throws {
|
||||
continueAfterFailure = false
|
||||
}
|
||||
|
||||
func testLaunch() throws {
|
||||
let app = XCUIApplication()
|
||||
app.launch()
|
||||
|
||||
// Insert steps here to perform after app launch but before taking a screenshot,
|
||||
// such as logging into a test account or navigating somewhere in the app
|
||||
|
||||
let attachment = XCTAttachment(screenshot: app.screenshot())
|
||||
attachment.name = "Launch Screen"
|
||||
attachment.lifetime = .keepAlways
|
||||
add(attachment)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// iMoviesVIPERTests.swift
|
||||
// iMoviesVIPERTests
|
||||
//
|
||||
// Created by Eyüp Yasuntimur on 5.01.2023.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import iMoviesVIPER
|
||||
|
||||
class iMoviesVIPERTests: XCTestCase {
|
||||
|
||||
override func setUpWithError() throws {
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
func testExample() throws {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
// Any test you write for XCTest can be annotated as throws and async.
|
||||
// Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
|
||||
// Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
|
||||
}
|
||||
|
||||
func testPerformanceExample() throws {
|
||||
// This is an example of a performance test case.
|
||||
self.measure {
|
||||
// Put the code you want to measure the time of here.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue