Showing preview only (281K chars total). Download the full file or copy to clipboard to get everything.
Repository: thiagolioy/marvelapp
Branch: master
Commit: ad1af1f5cb77
Files: 67
Total size: 261.0 KB
Directory structure:
gitextract_9es8icdz/
├── .gitignore
├── .ruby-version
├── .travis.yml
├── Dangerfile
├── Gemfile
├── LICENSE
├── Marvel/
│ ├── AppDelegate/
│ │ └── AppDelegate.swift
│ ├── ApperanceProxyHelper.swift
│ ├── Cells/
│ │ ├── CharacterCollectionCell.swift
│ │ ├── CharacterTableCell.swift
│ │ └── Xibs/
│ │ ├── CharacterCollectionCell.xib
│ │ └── CharacterTableCell.xib
│ ├── Controllers/
│ │ ├── CharacterViewController.swift
│ │ └── CharactersViewController.swift
│ ├── Datasources/
│ │ ├── CharactersCollectionDatasource.swift
│ │ ├── CharactersDatasource.swift
│ │ ├── ItemsCollectionViewDatasource.swift
│ │ └── ItemsTableViewDatasource.swift
│ ├── Models/
│ │ ├── Character.swift
│ │ └── ThumbImage.swift
│ ├── Network/
│ │ ├── MarvelAPI.swift
│ │ └── MarvelAPIManager.swift
│ ├── Resources/
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── Grid Icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ └── List Icon.imageset/
│ │ │ └── Contents.json
│ │ ├── ColorPalette.swift
│ │ ├── Info.plist
│ │ └── Storyboard.swift
│ ├── Storyboards/
│ │ └── Base.lproj/
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ └── UIImageView+Kingfisher.swift
├── Marvel.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ └── contents.xcworkspacedata
│ └── xcshareddata/
│ └── xcschemes/
│ └── Marvel.xcscheme
├── MarvelTests/
│ ├── CharacterSpec.swift
│ ├── CharacterViewControllerSpec.swift
│ ├── CharactersCollectionDatasourceSpec.swift
│ ├── CharactersCollectionDelegateSpec.swift
│ ├── CharactersDatasourceSpec.swift
│ ├── CharactersDelegateSpec.swift
│ ├── CharactersViewControllerSpec.swift
│ ├── Info.plist
│ ├── MockLoader.swift
│ ├── ThumbImageSpec.swift
│ ├── character.json
│ └── characters_response.json
├── Podfile
├── README.md
├── coverage/
│ ├── AppDelegate.swift.html
│ ├── Character.swift.html
│ ├── CharacterCollectionCell.swift.html
│ ├── CharacterTableCell.swift.html
│ ├── CharacterViewController.swift.html
│ ├── CharactersCollectionDatasource.swift.html
│ ├── CharactersDatasource.swift.html
│ ├── CharactersViewController.swift.html
│ ├── ItemsCollectionViewDatasource.swift.html
│ ├── ItemsTableViewDatasource.swift.html
│ ├── ThumbImage.swift.html
│ ├── UIImageView+Kingfisher.swift.html
│ ├── highlight.pack.js
│ ├── index.html
│ └── slather.css
└── fastlane/
├── Appfile
├── Fastfile
└── README.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
## Other
*.moved-aside
*.xcuserstate
## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
## Playgrounds
timeline.xctimeline
playground.xcworkspace
# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
.build/
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
Pods/
**/Marvel.xcworkspace/
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
**/fastlane/report.xml
**/fastlane/Preview.html
**/fastlane/screenshots
**/fastlane/test_output
================================================
FILE: .ruby-version
================================================
2.3.0
================================================
FILE: .travis.yml
================================================
language: objective-c
osx_image: xcode8.1
cache:
- bundler
- cocoapods
before_install:
- bundle install
- bundle exec pod keys set MarvelApiKey $MARVEL_API_SECRET Marvel
- bundle exec pod keys set MarvelPrivateKey $MARVEL_API_PUBLIC Marvel
- pod repo update
script:
- fastlane test
- bundle exec danger
after_success:
- bash <(curl -s https://codecov.io/bash)
env:
global:
- secure: iQP72QQ4U3N8v2qLSiU1lcPv9enJAMFY9Bs/5MxI6D8gmOlVreEZloKVW4zS2pLcJITlttXiCLGCwi203DxbfnfXcdeEr04IsbWNDWv2NggtdSK1A/iQZDVIJGss0Qgvi6JW7+BVaPemCMhlndWxo4l0qkpj5jNvwS8bPWSPKJ1MB6AZlMQShktUlDYWujMcx3AfTgczLJbhiFrP8gpa6XCgFOu7lzlw6C+aqvRQgywUeLL9MKWge3OVBZnOMFtStB2ehUeKxvcp6HXOBIGaG8FVVef/NI+YXyLlX4wwLkuUsnR61lO/hEDMtL59ZE6SKOXDhXi00GyITT/E1k0sa/3caMgnQ5apHQxjN5y5vhc96CqEYnMyyAnwsgAktXpHqy5qU7TUJQ4EOfg67oFHFcXXqBbvFIh1AVM15e8oMZdEs/9GrDllm2KTY57FznO+XqqbmzLeFudaoVeWnXWsmy/M68RQZNp6cdRsBU+wVHu2k8uNwaIF91ouHm9sXJLcICFgvGZ/mg5r4nWza9Hu0gRk8FWLVNQtahjboS2OMAn+ZvyybjOungMvZoXU4ZJcXV4izAw6WIdUZgrU5GmzknWNwO1x8+AhJ7Lo/pkCsm22zV6HwB41sIo1CvJRfB8f8UvL7YPtU1DURNn7KIdju2C8jdi8Ae8onfkMknJQhNo=
- secure: ZCih/6Pkg6kxc3V/GVfe29KYN1fL9EKVqdGz9vqMgfFyivDsz7a/WXXqoYBqyBXJ0Z9tT+13GZG1QidcZeLoxJ+RAvVvhtZhp4PBH4sa9dsy4laWZkA9hIRmgfoMR3M1Cuab+twmXBz/rPXkTWeOk9dBRlXe4BP5/QfzwrTz9NApezCV1vsGLGFVulQrClHE0USMA0eE6IiAACM7EsT4I4q063zJxQWAAsly9i/hbsL3J+1lUpqE4UcNamou/1Ri07VEFWYzM5Y87+dLB6pD1e96Cj7KjNfQVwBK9uw2K17i4oQt/kgwx8J2A4zdzCPF0kzu54Jmw6hUUrlv7sVscUfKKDPwtdqlQpS/ga7NgV43OzrhNrnnnjZQi7RRJAWvB33zsOjouEab9MVUS5vv6zi5uEUQj4eADgUlGbrhz9bw0Qdj2oX6UUWHnpyt5hS88cLqymZ5VLfvNwnrY3ZUzoGvFFu09KPrL1eUIgccanrpFqQHC0zqQZRiH1qKWH0dq8jgQNYE766mU1zypPge9wZW26dORatb8vat+lalt47wz38B2Wq818FgCN3PeeMyDr0xZoWInY0jTRB1eZzRhrVIX39MpyQ916bScCFr4Ex9biORiio0anUWUox1dyqSHvT/ZRpEdLf5YU2FhySh+9rEcAvluctXyHZvk5hYZUI=
================================================
FILE: Dangerfile
================================================
# Sometimes it's a README fix, or something like that - which isn't relevant for
# including in a project's CHANGELOG for example
declared_trivial = github.pr_title.include? "#trivial"
# Make it more obvious that a PR is a work in progress and shouldn't be merged yet
warn("PR is classed as Work in Progress") if github.pr_title.include? "[WIP]"
# Warn when there is a big PR
warn("Big PR") if git.lines_of_code > 500
message("Test Comment on PR")
# Don't let testing shortcuts get into master by accident
# fail("fdescribe left in tests") if `grep -r fdescribe specs/ `.length > 1
# fail("fit left in tests") if `grep -r fit specs/ `.length > 1
# Slater config
slather.configure("Marvel.xcodeproj", "Marvel", options: {
workspace: 'Marvel.xcworkspace',
output_directory: "coverage",
ignore_list: [
"**/Storyboard.swift",
"**/MarvelAPI.swift",
"**/MarvelAPIManager.swift"
],
ci_service: :travis,
coverage_service: :terminal,
})
slather.notify_if_coverage_is_less_than(minimum_coverage: 80)
slather.notify_if_modified_file_is_less_than(minimum_coverage: 60)
slather.show_coverage
================================================
FILE: Gemfile
================================================
# frozen_string_literal: true
source "https://rubygems.org"
# gem "rails"
gem "cocoapods", "1.1.1"
gem "cocoapods-keys", "1.7.0"
gem "slather", "2.3.0"
gem "fastlane", "1.110.0"
gem 'danger'
gem "danger-slather"
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2016 Thiago Lioy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Marvel/AppDelegate/AppDelegate.swift
================================================
//
// AppDelegate.swift
// Marvel
//
// Created by Thiago Lioy on 14/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
ApperanceProxyHelper.customizeNavigationBar()
return true
}
}
================================================
FILE: Marvel/ApperanceProxyHelper.swift
================================================
//
// ApperanceProxyHelper.swift
// Marvel
//
// Created by Thiago Lioy on 11/12/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Foundation
import UIKit
struct ApperanceProxyHelper {
static func customizeNavigationBar() {
let navigationBarAppearace = UINavigationBar.appearance()
navigationBarAppearace.tintColor = ColorPalette.white
navigationBarAppearace.titleTextAttributes = [NSForegroundColorAttributeName:ColorPalette.white]
}
}
================================================
FILE: Marvel/Cells/CharacterCollectionCell.swift
================================================
//
// CharacterCollectionCell.swift
// Marvel
//
// Created by Thiago Lioy on 20/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import UIKit
import Reusable
final class CharacterCollectionCell: UICollectionViewCell, NibReusable {
@IBOutlet weak var name: UILabel!
@IBOutlet weak var thumb: UIImageView!
static func size(for parentWidth: CGFloat) -> CGSize {
let numberOfCells = CGFloat(2)
let width = parentWidth / numberOfCells
return CGSize(width: width, height: width)
}
func setup(item: Character) {
name.text = item.name
thumb.download(image: item.thumImage?.fullPath() ?? "")
}
}
================================================
FILE: Marvel/Cells/CharacterTableCell.swift
================================================
//
// CharacterTableCell.swift
// Marvel
//
// Created by Thiago Lioy on 15/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import UIKit
import Reusable
final class CharacterTableCell: UITableViewCell, NibReusable {
@IBOutlet weak var name: UILabel!
@IBOutlet weak var characterDescription: UILabel!
@IBOutlet weak var thumb: UIImageView!
static func height() -> CGFloat {
return 80
}
func setup(item: Character) {
name.text = item.name
characterDescription.text = item.bio.isEmpty ? "No description" : item.bio
thumb.download(image: item.thumImage?.fullPath() ?? "")
}
}
================================================
FILE: Marvel/Cells/Xibs/CharacterCollectionCell.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2657" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="CharacterCollectionCell" id="dub-5O-5r3" customClass="CharacterCollectionCell" customModule="Marvel" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="316" height="311"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="316" height="311"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="qsZ-Mq-TPu">
<rect key="frame" x="0.0" y="0.0" width="316" height="311"/>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NMe-cL-xw2">
<rect key="frame" x="0.0" y="267" width="316" height="44"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3az-cb-fkg">
<rect key="frame" x="10" y="11.5" width="296" height="21"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="mBv-G1-VvS"/>
</constraints>
<fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.60370291095890416" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="3az-cb-fkg" firstAttribute="leading" secondItem="NMe-cL-xw2" secondAttribute="leading" constant="10" id="4df-yf-aJX"/>
<constraint firstItem="3az-cb-fkg" firstAttribute="centerY" secondItem="NMe-cL-xw2" secondAttribute="centerY" id="YhA-oa-Y3l"/>
<constraint firstAttribute="trailing" secondItem="3az-cb-fkg" secondAttribute="trailing" constant="10" id="jUo-9t-A7U"/>
<constraint firstAttribute="height" constant="44" id="lbv-sh-rHT"/>
</constraints>
</view>
</subviews>
</view>
<constraints>
<constraint firstAttribute="bottom" secondItem="NMe-cL-xw2" secondAttribute="bottom" id="F9X-h9-KDP"/>
<constraint firstItem="qsZ-Mq-TPu" firstAttribute="leading" secondItem="dub-5O-5r3" secondAttribute="leading" id="GZn-gu-a3t"/>
<constraint firstAttribute="trailing" secondItem="NMe-cL-xw2" secondAttribute="trailing" id="RQb-xW-hez"/>
<constraint firstAttribute="trailing" secondItem="qsZ-Mq-TPu" secondAttribute="trailing" id="XeP-om-SoN"/>
<constraint firstItem="NMe-cL-xw2" firstAttribute="leading" secondItem="dub-5O-5r3" secondAttribute="leading" id="ayu-7B-LOV"/>
<constraint firstAttribute="bottom" secondItem="qsZ-Mq-TPu" secondAttribute="bottom" id="qd2-h4-Boq"/>
<constraint firstItem="qsZ-Mq-TPu" firstAttribute="top" secondItem="dub-5O-5r3" secondAttribute="top" id="rrV-Uh-Jf6"/>
</constraints>
<size key="customSize" width="316" height="311"/>
<connections>
<outlet property="name" destination="3az-cb-fkg" id="RbX-d0-yUw"/>
<outlet property="thumb" destination="qsZ-Mq-TPu" id="bt9-ko-Yda"/>
</connections>
<point key="canvasLocation" x="6" y="44.5"/>
</collectionViewCell>
</objects>
</document>
================================================
FILE: Marvel/Cells/Xibs/CharacterTableCell.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2657" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="CharacterTableCell" rowHeight="80" id="7Dc-hd-PXe" customClass="CharacterTableCell" customModule="Marvel" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="80"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="7Dc-hd-PXe" id="Td0-f4-45U">
<rect key="frame" x="0.0" y="0.0" width="375" height="79.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ewx-XE-MgE">
<rect key="frame" x="95" y="10" width="265" height="21"/>
<constraints>
<constraint firstAttribute="height" constant="21" id="pQr-Iq-CMg"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="1" green="0.98823529409999999" blue="0.97647058819999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="WoA-qp-Juc">
<rect key="frame" x="0.0" y="0.0" width="80" height="80"/>
<constraints>
<constraint firstAttribute="width" constant="80" id="527-kp-Bxt"/>
<constraint firstAttribute="height" constant="80" id="tt7-Pj-d3i"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GgV-4R-szU">
<rect key="frame" x="95" y="31" width="265" height="41"/>
<fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="14"/>
<color key="textColor" red="1" green="0.98823529409999999" blue="0.97647058819999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.25098039220000001" green="0.2470588235" blue="0.29803921570000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="WoA-qp-Juc" firstAttribute="top" secondItem="Td0-f4-45U" secondAttribute="top" id="AJo-M6-Z0V"/>
<constraint firstItem="WoA-qp-Juc" firstAttribute="leading" secondItem="Td0-f4-45U" secondAttribute="leading" id="K2D-Q5-Ry4"/>
<constraint firstItem="GgV-4R-szU" firstAttribute="top" secondItem="ewx-XE-MgE" secondAttribute="bottom" id="KDY-T2-8mc"/>
<constraint firstAttribute="trailing" secondItem="GgV-4R-szU" secondAttribute="trailing" constant="15" id="KlM-ms-w6A"/>
<constraint firstItem="GgV-4R-szU" firstAttribute="leading" secondItem="WoA-qp-Juc" secondAttribute="trailing" constant="15" id="O3c-BL-9US"/>
<constraint firstAttribute="trailing" secondItem="ewx-XE-MgE" secondAttribute="trailing" constant="15" id="UnY-Ud-04x"/>
<constraint firstItem="ewx-XE-MgE" firstAttribute="top" secondItem="Td0-f4-45U" secondAttribute="top" constant="10" id="ZPz-Ly-zth"/>
<constraint firstItem="ewx-XE-MgE" firstAttribute="leading" secondItem="WoA-qp-Juc" secondAttribute="trailing" constant="15" id="nw8-ex-774"/>
<constraint firstAttribute="bottom" secondItem="GgV-4R-szU" secondAttribute="bottom" constant="8" id="o8v-ps-1lG"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="characterDescription" destination="GgV-4R-szU" id="9j4-F7-Q3n"/>
<outlet property="name" destination="ewx-XE-MgE" id="ydS-da-65d"/>
<outlet property="thumb" destination="WoA-qp-Juc" id="REy-5e-Pto"/>
</connections>
<point key="canvasLocation" x="33.5" y="79"/>
</tableViewCell>
</objects>
</document>
================================================
FILE: Marvel/Controllers/CharacterViewController.swift
================================================
//
// CharacterViewController.swift
// Marvel
//
// Created by Thiago Lioy on 14/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import UIKit
final class CharacterViewController: UIViewController {
@IBOutlet weak var characterDescription: UILabel!
@IBOutlet weak var image: UIImageView!
var character: Character?
}
extension CharacterViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.title = character?.name ?? ""
}
}
extension CharacterViewController {
func setupView() {
let bio = character?.bio ?? ""
characterDescription.text = bio.isEmpty ? "No description" : bio
image.download(image: character?.thumImage?.fullPath() ?? "")
}
}
================================================
FILE: Marvel/Controllers/CharactersViewController.swift
================================================
//
// CharactersViewController.swift
// Marvel
//
// Created by Thiago Lioy on 14/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import UIKit
protocol CharactersDelegate {
func didSelectCharacter(at index: IndexPath)
}
final class CharactersViewController: UIViewController {
var apiManager: MarvelAPICalls = MarvelAPIManager()
var tableDatasource: CharactersDatasource?
var tableDelegate: CharactersTableDelegate?
var collectionDatasource: CharactersCollectionDatasource?
var collectionDelegate: CharactersCollectionDelegate?
var characters: [Character] = []
var showingAsList = true
@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var collectionView: UICollectionView!
}
extension CharactersViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupSearchBar()
fetchCharacters()
}
}
extension CharactersViewController {
func fetchCharacters(for query: String? = nil) {
tableView.isHidden = true
collectionView.isHidden = true
activityIndicator.startAnimating()
apiManager.characters(query: query) { characters in
self.activityIndicator.stopAnimating()
if let characters = characters {
if self.showingAsList {
self.setupTableView(with: characters)
} else {
self.setupCollectionView(with: characters)
}
}
}
}
func setupSearchBar() {
self.searchBar.delegate = self
}
func setupTableView(with characters: [Character]) {
self.characters = characters
showingAsList = true
tableView.isHidden = false
collectionView.isHidden = true
tableDelegate = CharactersTableDelegate(self)
tableDatasource = CharactersDatasource(items: characters, tableView: self.tableView, delegate: tableDelegate!)
}
func setupCollectionView(with characters: [Character]) {
self.characters = characters
showingAsList = false
collectionView.isHidden = false
tableView.isHidden = true
collectionDelegate = CharactersCollectionDelegate(self)
collectionDatasource = CharactersCollectionDatasource(items: characters, collectionView: self.collectionView, delegate: collectionDelegate!)
}
}
extension CharactersViewController {
@IBAction func showAsGrid(_ sender: UIButton) {
setupCollectionView(with: characters)
}
@IBAction func showAsTable(_ sender: UIButton) {
setupTableView(with: characters)
}
}
extension CharactersViewController: CharactersDelegate {
func didSelectCharacter(at index: IndexPath) {
searchBar.resignFirstResponder()
guard let nextController = Storyboard.Main.characterViewControllerScene
.viewController() as? CharacterViewController else {
return
}
let character = characters[index.row]
nextController.character = character
self.navigationController?.pushViewController(nextController, animated: true)
}
}
extension CharactersViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
let query = searchBar.text ?? ""
if !query.isEmpty {
fetchCharacters(for: query)
}
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
}
}
================================================
FILE: Marvel/Datasources/CharactersCollectionDatasource.swift
================================================
//
// CharactersCollectionDatasource.swift
// Marvel
//
// Created by Thiago Lioy on 20/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import UIKit
final class CharactersCollectionDatasource: NSObject, ItemsCollectionViewDatasource {
var items:[Character] = []
weak var collectionView: UICollectionView?
weak var delegate: UICollectionViewDelegate?
required init(items: [Character], collectionView: UICollectionView, delegate: UICollectionViewDelegate) {
self.items = items
self.collectionView = collectionView
self.delegate = delegate
super.init()
collectionView.register(cellType: CharacterCollectionCell.self)
self.setupCollectionView()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(for: indexPath, cellType: CharacterCollectionCell.self)
let character = self.items[indexPath.row]
cell.setup(item: character)
return cell
}
}
class CharactersCollectionDelegate: NSObject, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
let delegate: CharactersDelegate
init(_ delegate: CharactersDelegate) {
self.delegate = delegate
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
delegate.didSelectCharacter(at: indexPath)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.bounds.size.width
return CharacterCollectionCell.size(for: width)
}
}
================================================
FILE: Marvel/Datasources/CharactersDatasource.swift
================================================
//
// CharactersDatasource.swift
// Marvel
//
// Created by Thiago Lioy on 17/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import UIKit
final class CharactersDatasource: NSObject, ItemsTableViewDatasource {
var items:[Character] = []
weak var tableView: UITableView?
weak var delegate: UITableViewDelegate?
required init(items: [Character], tableView: UITableView, delegate: UITableViewDelegate) {
self.items = items
self.tableView = tableView
self.delegate = delegate
super.init()
tableView.register(cellType: CharacterTableCell.self)
self.setupTableView()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(for: indexPath, cellType: CharacterTableCell.self)
let character = self.items[indexPath.row]
cell.setup(item: character)
return cell
}
}
class CharactersTableDelegate: NSObject, UITableViewDelegate {
let delegate: CharactersDelegate
init(_ delegate: CharactersDelegate) {
self.delegate = delegate
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return CharacterTableCell.height()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate.didSelectCharacter(at: indexPath)
}
}
================================================
FILE: Marvel/Datasources/ItemsCollectionViewDatasource.swift
================================================
//
// ItemsCollectionViewDatasource.swift
// Marvel
//
// Created by Thiago Lioy on 20/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import UIKit
protocol ItemsCollectionViewDatasource: UICollectionViewDataSource {
associatedtype T
var items:[T] {get}
weak var collectionView: UICollectionView? {get}
weak var delegate: UICollectionViewDelegate? {get}
init(items: [T], collectionView: UICollectionView, delegate: UICollectionViewDelegate)
func setupCollectionView()
}
extension ItemsCollectionViewDatasource {
func setupCollectionView() {
self.collectionView?.dataSource = self
self.collectionView?.delegate = self.delegate
self.collectionView?.reloadData()
}
}
================================================
FILE: Marvel/Datasources/ItemsTableViewDatasource.swift
================================================
//
// ItemsTableDatasource.swift
// Marvel
//
// Created by Thiago Lioy on 17/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import UIKit
protocol ItemsTableViewDatasource: UITableViewDataSource {
associatedtype T
var items:[T] {get}
weak var tableView: UITableView? {get}
weak var delegate: UITableViewDelegate? {get}
init(items: [T], tableView: UITableView, delegate: UITableViewDelegate)
func setupTableView()
}
extension ItemsTableViewDatasource {
func setupTableView() {
self.tableView?.dataSource = self
self.tableView?.delegate = self.delegate
self.tableView?.reloadData()
}
}
================================================
FILE: Marvel/Models/Character.swift
================================================
//
// Character.swift
// Marvel
//
// Created by Thiago Lioy on 14/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Foundation
import ObjectMapper
struct Character {
var id: Int = 0
var name: String = ""
var bio: String = ""
var thumImage: ThumbImage?
}
extension Character: Mappable {
init?(map: Map) {
}
mutating func mapping(map: Map) {
id <- map["id"]
name <- map["name"]
bio <- map["description"]
thumImage <- map["thumbnail"]
}
}
================================================
FILE: Marvel/Models/ThumbImage.swift
================================================
//
// ThumbImage.swift
// Marvel
//
// Created by Thiago Lioy on 17/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Foundation
import ObjectMapper
struct ThumbImage {
var path: String = ""
var imageExtension: String = ""
func fullPath() -> String {
return "\(path).\(imageExtension)"
}
}
extension ThumbImage: Mappable {
init?(map: Map) {
}
mutating func mapping(map: Map) {
path <- map["path"]
imageExtension <- map["extension"]
}
}
================================================
FILE: Marvel/Network/MarvelAPI.swift
================================================
//
// MarvelAPI.swift
// Marvel
//
// Created by Thiago Lioy on 14/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Foundation
import Moya
import CryptoSwift
import Dollar
import Keys
fileprivate struct MarvelAPIConfig {
fileprivate static let keys = MarvelKeys()
static let privatekey = keys.marvelPrivateKey()!
static let apikey = keys.marvelApiKey()!
static let ts = Date().timeIntervalSince1970.description
static let hash = "\(ts)\(privatekey)\(apikey)".md5()
}
enum MarvelAPI {
case characters(String?)
case character(String)
}
extension MarvelAPI: TargetType {
var baseURL: URL { return URL(string: "https://gateway.marvel.com:443")! }
var path: String {
switch self {
case .characters:
return "/v1/public/characters"
case .character(let characterId):
return "/v1/public/characters/\(characterId)"
}
}
var method: Moya.Method {
switch self {
case .characters, .character:
return .get
}
}
func authParameters() -> [String: String] {
return ["apikey": MarvelAPIConfig.apikey,
"ts": MarvelAPIConfig.ts,
"hash": MarvelAPIConfig.hash]
}
var parameters: [String: Any]? {
switch self {
case .characters(let query):
if let query = query {
return $.merge(authParameters(),
["nameStartsWith": query])
}
return authParameters()
case .character(let characterId):
return $.merge(authParameters(),
["characterId": characterId])
}
}
var task: Task {
return .request
}
var sampleData: Data {
switch self {
default:
return Data()
}
}
}
================================================
FILE: Marvel/Network/MarvelAPIManager.swift
================================================
//
// MarvelAPIManager.swift
// Marvel
//
// Created by Thiago Lioy on 14/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Foundation
import Moya
import RxSwift
import ObjectMapper
import Moya_ObjectMapper
extension Response {
func removeAPIWrappers() -> Response {
guard let json = try? self.mapJSON() as? Dictionary<String, AnyObject>,
let results = json?["data"]?["results"] ?? [],
let newData = try? JSONSerialization.data(withJSONObject: results, options: .prettyPrinted) else {
return self
}
let newResponse = Response(statusCode: self.statusCode,
data: newData,
response: self.response)
return newResponse
}
}
struct MarvelAPIManager {
let provider: RxMoyaProvider<MarvelAPI>
let disposeBag = DisposeBag()
init() {
provider = RxMoyaProvider<MarvelAPI>()
}
}
extension MarvelAPIManager {
typealias AdditionalStepsAction = (() -> ())
fileprivate func requestObject<T: Mappable>(_ token: MarvelAPI, type: T.Type,
completion: @escaping (T?) -> Void,
additionalSteps: AdditionalStepsAction? = nil) {
provider.request(token)
.debug()
.mapObject(T.self)
.subscribe { event -> Void in
switch event {
case .next(let parsedObject):
completion(parsedObject)
additionalSteps?()
case .error(let error):
print(error)
completion(nil)
default:
break
}
}.addDisposableTo(disposeBag)
}
fileprivate func requestArray<T: Mappable>(_ token: MarvelAPI, type: T.Type,
completion: @escaping ([T]?) -> Void,
additionalSteps: AdditionalStepsAction? = nil) {
provider.request(token)
.debug()
.map { response -> Response in
return response.removeAPIWrappers()
}
.mapArray(T.self)
.subscribe { event -> Void in
switch event {
case .next(let parsedArray):
completion(parsedArray)
additionalSteps?()
case .error(let error):
print(error)
completion(nil)
default:
break
}
}.addDisposableTo(disposeBag)
}
}
protocol MarvelAPICalls {
func characters(query: String?, completion: @escaping ([Character]?) -> Void)
}
extension MarvelAPIManager: MarvelAPICalls {
func characters(query: String? = nil, completion: @escaping ([Character]?) -> Void) {
requestArray(.characters(query),
type: Character.self,
completion: completion)
}
}
================================================
FILE: Marvel/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "spotilight_small.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "settings_small@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "settings_small@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "spotlight_medium.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "spotlight_large.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "iphone_small.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "iphone_medium.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: Marvel/Resources/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: Marvel/Resources/Assets.xcassets/Grid Icon.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "Grid Icon@1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Grid Icon@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "Grid Icon@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "original"
}
}
================================================
FILE: Marvel/Resources/Assets.xcassets/List Icon.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "List Icon.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "List Icon@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "List Icon@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "original"
}
}
================================================
FILE: Marvel/Resources/ColorPalette.swift
================================================
//
// ColorPalette.swift
// Marvel
//
// Created by Thiago Lioy on 11/12/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import UIKit
enum ColorPalette {
static let red = UIColor(red:0.910, green: 0.282, blue: 0.333, alpha: 1.000)
static let white = UIColor(red:1.000, green: 0.988, blue: 0.976, alpha: 1.000)
static let black = UIColor(red:0.251, green: 0.247, blue: 0.298, alpha: 1.000)
}
================================================
FILE: Marvel/Resources/Info.plist
================================================
<?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>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
================================================
FILE: Marvel/Resources/Storyboard.swift
================================================
// Generated using SwiftGen, by O.Halligon — https://github.com/AliSoftware/SwiftGen
import Foundation
import UIKit
protocol StoryboardSceneType {
static var storyboardName: String { get }
}
extension StoryboardSceneType {
static func storyboard() -> UIStoryboard {
return UIStoryboard(name: self.storyboardName, bundle: nil)
}
static func initialViewController() -> UIViewController {
guard let vc = storyboard().instantiateInitialViewController() else {
fatalError("Failed to instantiate initialViewController for \(self.storyboardName)")
}
return vc
}
}
extension StoryboardSceneType where Self: RawRepresentable, Self.RawValue == String {
func viewController() -> UIViewController {
return Self.storyboard().instantiateViewController(withIdentifier: self.rawValue)
}
static func viewController(identifier: Self) -> UIViewController {
return identifier.viewController()
}
}
protocol StoryboardSegueType: RawRepresentable { }
extension UIViewController {
func performSegue<S: StoryboardSegueType>(segue: S, sender: AnyObject? = nil) where S.RawValue == String {
performSegue(withIdentifier: segue.rawValue, sender: sender)
}
}
// swiftlint:disable file_length
// swiftlint:disable type_body_length
struct Storyboard {
enum LaunchScreen: StoryboardSceneType {
static let storyboardName = "LaunchScreen"
}
enum Main: String, StoryboardSceneType {
static let storyboardName = "Main"
static func initialViewController() -> UINavigationController {
guard let vc = storyboard().instantiateInitialViewController() as? UINavigationController else {
fatalError("Failed to instantiate initialViewController for \(self.storyboardName)")
}
return vc
}
case characterViewControllerScene = "CharacterViewController"
static func instantiateCharacterViewController() -> CharacterViewController {
guard let vc = Storyboard.Main.characterViewControllerScene.viewController() as? CharacterViewController
else {
fatalError("ViewController 'CharacterViewController' is not of the expected class CharacterViewController.")
}
return vc
}
case charactersViewControllerScene = "CharactersViewController"
static func instantiateCharactersViewController() -> CharactersViewController {
guard let vc = Storyboard.Main.charactersViewControllerScene.viewController() as? CharactersViewController
else {
fatalError("ViewController 'CharactersViewController' is not of the expected class CharactersViewController.")
}
return vc
}
}
}
struct StoryboardSegue {
}
================================================
FILE: Marvel/Storyboards/Base.lproj/LaunchScreen.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2657" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="MARVEL" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="z3M-5M-6r6">
<rect key="frame" x="20" y="326.5" width="335" height="80"/>
<constraints>
<constraint firstAttribute="height" constant="80" id="uve-cn-zho"/>
</constraints>
<fontDescription key="fontDescription" name="Arial-BoldMT" family="Arial" pointSize="60"/>
<color key="textColor" red="1" green="0.9882352941176471" blue="0.97647058823529409" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.90980392156862744" green="0.14509803921568626" blue="0.20784313725490194" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="z3M-5M-6r6" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" constant="20" id="317-Bu-aJT"/>
<constraint firstItem="z3M-5M-6r6" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" constant="33" id="6vj-Sk-vR8"/>
<constraint firstAttribute="trailing" secondItem="z3M-5M-6r6" secondAttribute="trailing" constant="20" id="V8P-7L-ttl"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="52" y="374.66266866566718"/>
</scene>
</scenes>
</document>
================================================
FILE: Marvel/Storyboards/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2657" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Z0N-wd-fHj">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
<capability name="Navigation items with more than one left or right bar item" minToolsVersion="7.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Characters-->
<scene sceneID="w3P-uW-srD">
<objects>
<viewController storyboardIdentifier="CharactersViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="7wy-Hx-css" customClass="CharactersViewController" customModule="Marvel" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="zib-5N-qOv"/>
<viewControllerLayoutGuide type="bottom" id="71u-47-5CQ"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="d7s-Jc-H7P">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<searchBar contentMode="redraw" showsCancelButton="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FSe-Lr-fZW">
<rect key="frame" x="0.0" y="64" width="375" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="sAP-aP-xrl"/>
</constraints>
<color key="barTintColor" red="0.25098039215686274" green="0.24705882352941178" blue="0.29803921568627451" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textInputTraits key="textInputTraits"/>
</searchBar>
<collectionView hidden="YES" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="ZU2-Kk-0z9">
<rect key="frame" x="0.0" y="108" width="375" height="559"/>
<color key="backgroundColor" red="0.25098039220000001" green="0.2470588235" blue="0.29803921570000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="Ohz-7M-pKz">
<size key="itemSize" width="50" height="50"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="2sP-Tn-TUf">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask"/>
</view>
</collectionViewCell>
</cells>
</collectionView>
<tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="ixD-Lv-jLy">
<rect key="frame" x="0.0" y="108" width="375" height="559"/>
<color key="backgroundColor" red="0.25098039220000001" green="0.2470588235" blue="0.29803921570000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</tableView>
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="zfM-hz-I4n">
<rect key="frame" x="0.5" y="323" width="375" height="20"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="8hU-2K-nuS"/>
<constraint firstAttribute="width" constant="375" id="ys7-OV-ky1"/>
</constraints>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" red="0.25098039220000001" green="0.2470588235" blue="0.29803921570000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="zfM-hz-I4n" firstAttribute="centerX" secondItem="d7s-Jc-H7P" secondAttribute="centerX" id="0K0-EX-45Y"/>
<constraint firstItem="FSe-Lr-fZW" firstAttribute="leading" secondItem="d7s-Jc-H7P" secondAttribute="leading" id="0sL-Bt-xb1"/>
<constraint firstItem="ixD-Lv-jLy" firstAttribute="top" secondItem="FSe-Lr-fZW" secondAttribute="bottom" id="3Eg-ka-cn5"/>
<constraint firstAttribute="trailing" secondItem="ixD-Lv-jLy" secondAttribute="trailing" id="AkI-CR-926"/>
<constraint firstItem="ZU2-Kk-0z9" firstAttribute="top" secondItem="FSe-Lr-fZW" secondAttribute="bottom" id="KE5-2g-tGe"/>
<constraint firstItem="71u-47-5CQ" firstAttribute="top" secondItem="ZU2-Kk-0z9" secondAttribute="bottom" id="St3-3s-cMG"/>
<constraint firstItem="FSe-Lr-fZW" firstAttribute="top" secondItem="zib-5N-qOv" secondAttribute="bottom" id="W4r-Bz-5Tp"/>
<constraint firstAttribute="trailing" secondItem="ZU2-Kk-0z9" secondAttribute="trailing" id="Y0I-J8-uJ8"/>
<constraint firstItem="71u-47-5CQ" firstAttribute="top" secondItem="ixD-Lv-jLy" secondAttribute="bottom" id="Y3M-Dh-lAx"/>
<constraint firstAttribute="trailing" secondItem="FSe-Lr-fZW" secondAttribute="trailing" id="aHi-LQ-Fbl"/>
<constraint firstItem="ixD-Lv-jLy" firstAttribute="leading" secondItem="d7s-Jc-H7P" secondAttribute="leading" id="k79-IR-91p"/>
<constraint firstItem="ZU2-Kk-0z9" firstAttribute="leading" secondItem="d7s-Jc-H7P" secondAttribute="leading" id="tMj-Nk-9QW"/>
<constraint firstItem="zfM-hz-I4n" firstAttribute="centerY" secondItem="d7s-Jc-H7P" secondAttribute="centerY" id="uek-EN-JmA"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Characters" id="edj-2g-NMS">
<barButtonItem key="backBarButtonItem" title=" " id="9nk-oM-bJT"/>
<rightBarButtonItems>
<barButtonItem image="Grid Icon" id="B43-Zz-GvA">
<color key="tintColor" red="1" green="0.98823529409999999" blue="0.97647058819999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="showAsGrid:" destination="7wy-Hx-css" id="Rqd-05-Hbo"/>
</connections>
</barButtonItem>
<barButtonItem image="List Icon" id="qeA-Rs-8CW">
<color key="tintColor" red="1" green="0.98823529409999999" blue="0.97647058819999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="showAsTable:" destination="7wy-Hx-css" id="tbZ-cn-bKk"/>
</connections>
</barButtonItem>
</rightBarButtonItems>
</navigationItem>
<connections>
<outlet property="activityIndicator" destination="zfM-hz-I4n" id="vDV-1q-1jQ"/>
<outlet property="collectionView" destination="ZU2-Kk-0z9" id="Ybi-UC-10S"/>
<outlet property="searchBar" destination="FSe-Lr-fZW" id="LSv-KC-z4D"/>
<outlet property="tableView" destination="ixD-Lv-jLy" id="D5i-F6-flR"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="BHJ-BB-ry4" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1015.2" y="98.50074962518741"/>
</scene>
<!--Character View Controller-->
<scene sceneID="MlC-fX-U7i">
<objects>
<viewController storyboardIdentifier="CharacterViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="Os0-jz-Fgx" customClass="CharacterViewController" customModule="Marvel" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="ok8-no-yJx"/>
<viewControllerLayoutGuide type="bottom" id="XiB-jz-7cn"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="3xQ-ny-OFa">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Z7i-md-Isc">
<rect key="frame" x="0.0" y="64" width="375" height="375"/>
<constraints>
<constraint firstAttribute="height" constant="375" id="POZ-Zj-zcK"/>
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nmU-N1-ZLO">
<rect key="frame" x="0.0" y="439" width="375" height="228"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="top" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Name" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WQK-6I-FJ3">
<rect key="frame" x="10" y="10" width="355" height="208"/>
<fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.25098039220000001" green="0.2470588235" blue="0.29803921570000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="WQK-6I-FJ3" secondAttribute="trailing" constant="10" id="QTX-5F-CYv"/>
<constraint firstItem="WQK-6I-FJ3" firstAttribute="leading" secondItem="nmU-N1-ZLO" secondAttribute="leading" constant="10" id="gJo-7t-bmn"/>
<constraint firstAttribute="bottom" secondItem="WQK-6I-FJ3" secondAttribute="bottom" constant="10" id="hDm-f5-MjQ"/>
<constraint firstItem="WQK-6I-FJ3" firstAttribute="top" secondItem="nmU-N1-ZLO" secondAttribute="top" constant="10" id="joY-Eo-gq6"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="0.98823529409999999" blue="0.97647058819999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="nmU-N1-ZLO" firstAttribute="top" secondItem="Z7i-md-Isc" secondAttribute="bottom" id="73U-5v-xDG"/>
<constraint firstItem="nmU-N1-ZLO" firstAttribute="leading" secondItem="3xQ-ny-OFa" secondAttribute="leading" id="LX0-HS-V8o"/>
<constraint firstAttribute="trailing" secondItem="nmU-N1-ZLO" secondAttribute="trailing" id="VCB-SW-xE0"/>
<constraint firstAttribute="trailing" secondItem="Z7i-md-Isc" secondAttribute="trailing" id="al6-Wj-pgG"/>
<constraint firstItem="Z7i-md-Isc" firstAttribute="leading" secondItem="3xQ-ny-OFa" secondAttribute="leading" id="ezg-LL-mdh"/>
<constraint firstItem="Z7i-md-Isc" firstAttribute="top" secondItem="ok8-no-yJx" secondAttribute="bottom" id="g0q-eG-Psw"/>
<constraint firstItem="XiB-jz-7cn" firstAttribute="top" secondItem="nmU-N1-ZLO" secondAttribute="bottom" id="stx-za-9zo"/>
</constraints>
</view>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
<connections>
<outlet property="characterDescription" destination="WQK-6I-FJ3" id="lKS-px-jQg"/>
<outlet property="image" destination="Z7i-md-Isc" id="JLU-Sg-aqe"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="5uo-fJ-dNi" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1724" y="98.50074962518741"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="fXh-Vh-ViE">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="Z0N-wd-fHj" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" misplaced="YES" id="d5w-FI-Zdg">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<color key="barTintColor" red="0.90980392160000001" green="0.1450980392" blue="0.20784313730000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes">
<color key="textColor" red="1" green="0.98823529409999999" blue="0.97647058819999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</textAttributes>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="7wy-Hx-css" kind="relationship" relationship="rootViewController" id="WuD-dp-L0Y"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="9d9-9c-s4r" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="76" y="98.50074962518741"/>
</scene>
</scenes>
<resources>
<image name="Grid Icon" width="18" height="18"/>
<image name="List Icon" width="22" height="22"/>
</resources>
</document>
================================================
FILE: Marvel/UIImageView+Kingfisher.swift
================================================
//
// UIImage+Kingfisher.swift
// Marvel
//
// Created by Thiago Lioy on 20/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import UIKit
import Kingfisher
extension UIImageView {
func download(image url: String) {
guard let imageURL = URL(string:url) else {
return
}
self.kf.setImage(with: ImageResource(downloadURL: imageURL))
}
}
================================================
FILE: Marvel.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
577769109DC3FB06E7D1882F /* Pods_Marvel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A8D7213E1EA596B7C60C8E59 /* Pods_Marvel.framework */; };
9922F1571DFDB69200237BFE /* ColorPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9922F1561DFDB69200237BFE /* ColorPalette.swift */; };
9922F15A1DFDC00900237BFE /* ApperanceProxyHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9922F1591DFDC00900237BFE /* ApperanceProxyHelper.swift */; };
9939CFC71DDA244A008CE399 /* CharactersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9939CFC61DDA244A008CE399 /* CharactersViewController.swift */; };
9939CFC91DDA245A008CE399 /* CharacterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9939CFC81DDA245A008CE399 /* CharacterViewController.swift */; };
9939CFCF1DDA2E07008CE399 /* MarvelAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9939CFCE1DDA2E07008CE399 /* MarvelAPI.swift */; };
9939CFD11DDA30DC008CE399 /* MarvelAPIManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9939CFD01DDA30DC008CE399 /* MarvelAPIManager.swift */; };
9939CFD41DDA333D008CE399 /* Character.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9939CFD31DDA333D008CE399 /* Character.swift */; };
993AFDFF1DEA764200857C4F /* CharactersViewControllerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 993AFDFE1DEA764200857C4F /* CharactersViewControllerSpec.swift */; };
9976B4F81DEA43F200D2D3C4 /* MockLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9976B4F71DEA43F200D2D3C4 /* MockLoader.swift */; };
999665411DEA242300E9A5BF /* CharacterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 999665401DEA242300E9A5BF /* CharacterSpec.swift */; };
99B248E31DDB427000027C10 /* CharacterTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99B248E21DDB427000027C10 /* CharacterTableCell.swift */; };
99C67AC21DEB007600FB1E68 /* CharacterViewControllerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C67AC11DEB007600FB1E68 /* CharacterViewControllerSpec.swift */; };
99C67AC51DEB032F00FB1E68 /* CharactersDatasourceSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C67AC41DEB032F00FB1E68 /* CharactersDatasourceSpec.swift */; };
99C67AC71DEB06C100FB1E68 /* CharactersDelegateSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C67AC61DEB06C100FB1E68 /* CharactersDelegateSpec.swift */; };
99C67ACA1DEB0B3D00FB1E68 /* CharactersCollectionDatasourceSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C67AC91DEB0B3D00FB1E68 /* CharactersCollectionDatasourceSpec.swift */; };
99C67ACC1DEB0CB800FB1E68 /* CharactersCollectionDelegateSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99C67ACB1DEB0CB800FB1E68 /* CharactersCollectionDelegateSpec.swift */; };
99D0DEB21DE2598F00FE34D7 /* ItemsCollectionViewDatasource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99D0DEB11DE2598F00FE34D7 /* ItemsCollectionViewDatasource.swift */; };
99D0DEB41DE259F100FE34D7 /* CharacterCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99D0DEB31DE259F100FE34D7 /* CharacterCollectionCell.swift */; };
99D0DEB61DE25AC900FE34D7 /* CharacterCollectionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 99D0DEB51DE25AC900FE34D7 /* CharacterCollectionCell.xib */; };
99D0DEB81DE25BF300FE34D7 /* CharactersCollectionDatasource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99D0DEB71DE25BF300FE34D7 /* CharactersCollectionDatasource.swift */; };
99D0DEBA1DE268D000FE34D7 /* UIImageView+Kingfisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99D0DEB91DE268D000FE34D7 /* UIImageView+Kingfisher.swift */; };
99D0DEBE1DE26D8100FE34D7 /* Storyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99D0DEBD1DE26D8100FE34D7 /* Storyboard.swift */; };
99E1DFE41DDA1F4C006F9D96 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99E1DFE31DDA1F4C006F9D96 /* AppDelegate.swift */; };
99E1DFE91DDA1F4C006F9D96 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 99E1DFE71DDA1F4C006F9D96 /* Main.storyboard */; };
99E1DFEB1DDA1F4C006F9D96 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 99E1DFEA1DDA1F4C006F9D96 /* Assets.xcassets */; };
99E1DFEE1DDA1F4C006F9D96 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 99E1DFEC1DDA1F4C006F9D96 /* LaunchScreen.storyboard */; };
99EF5DB61DEA5CCD00B5569F /* ThumbImageSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99EF5DB51DEA5CCD00B5569F /* ThumbImageSpec.swift */; };
99F8870E1DEA3E6D0044E3B0 /* characters_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 99F8870D1DEA3E6D0044E3B0 /* characters_response.json */; };
99F887101DEA3EA00044E3B0 /* character.json in Resources */ = {isa = PBXBuildFile; fileRef = 99F8870F1DEA3EA00044E3B0 /* character.json */; };
99FC2BC81DDDB0F3006CB7EE /* ItemsTableViewDatasource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99FC2BC71DDDB0F3006CB7EE /* ItemsTableViewDatasource.swift */; };
99FC2BCA1DDDB1BF006CB7EE /* CharactersDatasource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99FC2BC91DDDB1BF006CB7EE /* CharactersDatasource.swift */; };
99FC2BCD1DDDB8C7006CB7EE /* CharacterTableCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 99FC2BCC1DDDB8C7006CB7EE /* CharacterTableCell.xib */; };
99FC2BCF1DDDB966006CB7EE /* ThumbImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99FC2BCE1DDDB966006CB7EE /* ThumbImage.swift */; };
FAB8878D2CDDAC3D491738F7 /* Pods_MarvelTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C6A61295B862198BB138719 /* Pods_MarvelTests.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
9996653B1DEA236300E9A5BF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 99E1DFD81DDA1F4C006F9D96 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 99E1DFDF1DDA1F4C006F9D96;
remoteInfo = Marvel;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
46E32511C8C4E886533F9B7E /* Pods-Marvel.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Marvel.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Marvel/Pods-Marvel.debug.xcconfig"; sourceTree = "<group>"; };
8289D5AF9F3BDEDBC4EE6E82 /* Pods-Marvel.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Marvel.release.xcconfig"; path = "Pods/Target Support Files/Pods-Marvel/Pods-Marvel.release.xcconfig"; sourceTree = "<group>"; };
8C6A61295B862198BB138719 /* Pods_MarvelTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MarvelTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9922F1561DFDB69200237BFE /* ColorPalette.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPalette.swift; sourceTree = "<group>"; };
9922F1591DFDC00900237BFE /* ApperanceProxyHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApperanceProxyHelper.swift; sourceTree = "<group>"; };
9939CFC61DDA244A008CE399 /* CharactersViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharactersViewController.swift; sourceTree = "<group>"; };
9939CFC81DDA245A008CE399 /* CharacterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharacterViewController.swift; sourceTree = "<group>"; };
9939CFCE1DDA2E07008CE399 /* MarvelAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarvelAPI.swift; sourceTree = "<group>"; };
9939CFD01DDA30DC008CE399 /* MarvelAPIManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarvelAPIManager.swift; sourceTree = "<group>"; };
9939CFD31DDA333D008CE399 /* Character.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Character.swift; sourceTree = "<group>"; };
993AFDFE1DEA764200857C4F /* CharactersViewControllerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharactersViewControllerSpec.swift; sourceTree = "<group>"; };
9976B4F71DEA43F200D2D3C4 /* MockLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockLoader.swift; sourceTree = "<group>"; };
999665361DEA236300E9A5BF /* MarvelTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MarvelTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
9996653A1DEA236300E9A5BF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
999665401DEA242300E9A5BF /* CharacterSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharacterSpec.swift; sourceTree = "<group>"; };
99B248E21DDB427000027C10 /* CharacterTableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharacterTableCell.swift; sourceTree = "<group>"; };
99C67AC11DEB007600FB1E68 /* CharacterViewControllerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharacterViewControllerSpec.swift; sourceTree = "<group>"; };
99C67AC41DEB032F00FB1E68 /* CharactersDatasourceSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharactersDatasourceSpec.swift; sourceTree = "<group>"; };
99C67AC61DEB06C100FB1E68 /* CharactersDelegateSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharactersDelegateSpec.swift; sourceTree = "<group>"; };
99C67AC91DEB0B3D00FB1E68 /* CharactersCollectionDatasourceSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharactersCollectionDatasourceSpec.swift; sourceTree = "<group>"; };
99C67ACB1DEB0CB800FB1E68 /* CharactersCollectionDelegateSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharactersCollectionDelegateSpec.swift; sourceTree = "<group>"; };
99D0DEB11DE2598F00FE34D7 /* ItemsCollectionViewDatasource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemsCollectionViewDatasource.swift; sourceTree = "<group>"; };
99D0DEB31DE259F100FE34D7 /* CharacterCollectionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharacterCollectionCell.swift; sourceTree = "<group>"; };
99D0DEB51DE25AC900FE34D7 /* CharacterCollectionCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CharacterCollectionCell.xib; sourceTree = "<group>"; };
99D0DEB71DE25BF300FE34D7 /* CharactersCollectionDatasource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharactersCollectionDatasource.swift; sourceTree = "<group>"; };
99D0DEB91DE268D000FE34D7 /* UIImageView+Kingfisher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImageView+Kingfisher.swift"; sourceTree = "<group>"; };
99D0DEBD1DE26D8100FE34D7 /* Storyboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storyboard.swift; sourceTree = "<group>"; };
99E1DFE01DDA1F4C006F9D96 /* Marvel.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Marvel.app; sourceTree = BUILT_PRODUCTS_DIR; };
99E1DFE31DDA1F4C006F9D96 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
99E1DFE81DDA1F4C006F9D96 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
99E1DFEA1DDA1F4C006F9D96 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
99E1DFED1DDA1F4C006F9D96 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
99E1DFEF1DDA1F4C006F9D96 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
99EF5DB51DEA5CCD00B5569F /* ThumbImageSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbImageSpec.swift; sourceTree = "<group>"; };
99F8870D1DEA3E6D0044E3B0 /* characters_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = characters_response.json; sourceTree = "<group>"; };
99F8870F1DEA3EA00044E3B0 /* character.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = character.json; sourceTree = "<group>"; };
99FC2BC71DDDB0F3006CB7EE /* ItemsTableViewDatasource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemsTableViewDatasource.swift; sourceTree = "<group>"; };
99FC2BC91DDDB1BF006CB7EE /* CharactersDatasource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharactersDatasource.swift; sourceTree = "<group>"; };
99FC2BCC1DDDB8C7006CB7EE /* CharacterTableCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CharacterTableCell.xib; sourceTree = "<group>"; };
99FC2BCE1DDDB966006CB7EE /* ThumbImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbImage.swift; sourceTree = "<group>"; };
A8D7213E1EA596B7C60C8E59 /* Pods_Marvel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Marvel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BF2D032F8BA77A47BCBA607A /* Pods-MarvelTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MarvelTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MarvelTests/Pods-MarvelTests.debug.xcconfig"; sourceTree = "<group>"; };
E54675F9B824A595E2F0D533 /* Pods-MarvelTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MarvelTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-MarvelTests/Pods-MarvelTests.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
999665331DEA236300E9A5BF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
FAB8878D2CDDAC3D491738F7 /* Pods_MarvelTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
99E1DFDD1DDA1F4C006F9D96 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
577769109DC3FB06E7D1882F /* Pods_Marvel.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9922F1581DFDBFF400237BFE /* Apperance */ = {
isa = PBXGroup;
children = (
9922F1591DFDC00900237BFE /* ApperanceProxyHelper.swift */,
);
name = Apperance;
sourceTree = "<group>";
};
9939CFC51DDA2417008CE399 /* Controllers */ = {
isa = PBXGroup;
children = (
9939CFC81DDA245A008CE399 /* CharacterViewController.swift */,
9939CFC61DDA244A008CE399 /* CharactersViewController.swift */,
);
path = Controllers;
sourceTree = "<group>";
};
9939CFCA1DDA267D008CE399 /* Storyboards */ = {
isa = PBXGroup;
children = (
99E1DFEC1DDA1F4C006F9D96 /* LaunchScreen.storyboard */,
99E1DFE71DDA1F4C006F9D96 /* Main.storyboard */,
);
path = Storyboards;
sourceTree = "<group>";
};
9939CFCB1DDA26A3008CE399 /* Resources */ = {
isa = PBXGroup;
children = (
99D0DEBD1DE26D8100FE34D7 /* Storyboard.swift */,
99E1DFEA1DDA1F4C006F9D96 /* Assets.xcassets */,
99E1DFEF1DDA1F4C006F9D96 /* Info.plist */,
9922F1561DFDB69200237BFE /* ColorPalette.swift */,
);
path = Resources;
sourceTree = "<group>";
};
9939CFCC1DDA2716008CE399 /* AppDelegate */ = {
isa = PBXGroup;
children = (
99E1DFE31DDA1F4C006F9D96 /* AppDelegate.swift */,
);
path = AppDelegate;
sourceTree = "<group>";
};
9939CFCD1DDA2DF1008CE399 /* Network */ = {
isa = PBXGroup;
children = (
9939CFCE1DDA2E07008CE399 /* MarvelAPI.swift */,
9939CFD01DDA30DC008CE399 /* MarvelAPIManager.swift */,
);
path = Network;
sourceTree = "<group>";
};
9939CFD21DDA332A008CE399 /* Models */ = {
isa = PBXGroup;
children = (
9939CFD31DDA333D008CE399 /* Character.swift */,
99FC2BCE1DDDB966006CB7EE /* ThumbImage.swift */,
);
path = Models;
sourceTree = "<group>";
};
993AFDFD1DEA762C00857C4F /* Controllers */ = {
isa = PBXGroup;
children = (
993AFDFE1DEA764200857C4F /* CharactersViewControllerSpec.swift */,
99C67AC11DEB007600FB1E68 /* CharacterViewControllerSpec.swift */,
);
name = Controllers;
sourceTree = "<group>";
};
9976B4F61DEA43D100D2D3C4 /* TestHelpers */ = {
isa = PBXGroup;
children = (
9976B4F71DEA43F200D2D3C4 /* MockLoader.swift */,
);
name = TestHelpers;
sourceTree = "<group>";
};
999665371DEA236300E9A5BF /* MarvelTests */ = {
isa = PBXGroup;
children = (
99C67AC81DEB06C700FB1E68 /* Delegates */,
99C67AC31DEB031E00FB1E68 /* Datasources */,
993AFDFD1DEA762C00857C4F /* Controllers */,
99EF5DB41DEA5CBD00B5569F /* Models */,
9976B4F61DEA43D100D2D3C4 /* TestHelpers */,
99F8870C1DEA3E560044E3B0 /* Mocks */,
9996653A1DEA236300E9A5BF /* Info.plist */,
);
path = MarvelTests;
sourceTree = "<group>";
};
99B248E11DDB423900027C10 /* Cells */ = {
isa = PBXGroup;
children = (
99FC2BCB1DDDB8B1006CB7EE /* Xibs */,
99B248E21DDB427000027C10 /* CharacterTableCell.swift */,
99D0DEB31DE259F100FE34D7 /* CharacterCollectionCell.swift */,
);
path = Cells;
sourceTree = "<group>";
};
99C67AC31DEB031E00FB1E68 /* Datasources */ = {
isa = PBXGroup;
children = (
99C67AC41DEB032F00FB1E68 /* CharactersDatasourceSpec.swift */,
99C67AC91DEB0B3D00FB1E68 /* CharactersCollectionDatasourceSpec.swift */,
);
name = Datasources;
sourceTree = "<group>";
};
99C67AC81DEB06C700FB1E68 /* Delegates */ = {
isa = PBXGroup;
children = (
99C67AC61DEB06C100FB1E68 /* CharactersDelegateSpec.swift */,
99C67ACB1DEB0CB800FB1E68 /* CharactersCollectionDelegateSpec.swift */,
);
name = Delegates;
sourceTree = "<group>";
};
99D0DEBB1DE268D500FE34D7 /* Extensions */ = {
isa = PBXGroup;
children = (
99D0DEB91DE268D000FE34D7 /* UIImageView+Kingfisher.swift */,
);
name = Extensions;
sourceTree = "<group>";
};
99E1DFD71DDA1F4C006F9D96 = {
isa = PBXGroup;
children = (
A614E78BE86E798A7E93A6F8 /* Frameworks */,
99E1DFE21DDA1F4C006F9D96 /* Marvel */,
999665371DEA236300E9A5BF /* MarvelTests */,
F31159AB537646F3DA1B5700 /* Pods */,
99E1DFE11DDA1F4C006F9D96 /* Products */,
);
sourceTree = "<group>";
};
99E1DFE11DDA1F4C006F9D96 /* Products */ = {
isa = PBXGroup;
children = (
99E1DFE01DDA1F4C006F9D96 /* Marvel.app */,
999665361DEA236300E9A5BF /* MarvelTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
99E1DFE21DDA1F4C006F9D96 /* Marvel */ = {
isa = PBXGroup;
children = (
9922F1581DFDBFF400237BFE /* Apperance */,
99D0DEBB1DE268D500FE34D7 /* Extensions */,
9939CFCC1DDA2716008CE399 /* AppDelegate */,
99B248E11DDB423900027C10 /* Cells */,
9939CFC51DDA2417008CE399 /* Controllers */,
99FC2BC61DDDB0A5006CB7EE /* Datasources */,
9939CFD21DDA332A008CE399 /* Models */,
9939CFCD1DDA2DF1008CE399 /* Network */,
9939CFCB1DDA26A3008CE399 /* Resources */,
9939CFCA1DDA267D008CE399 /* Storyboards */,
);
path = Marvel;
sourceTree = "<group>";
};
99EF5DB41DEA5CBD00B5569F /* Models */ = {
isa = PBXGroup;
children = (
999665401DEA242300E9A5BF /* CharacterSpec.swift */,
99EF5DB51DEA5CCD00B5569F /* ThumbImageSpec.swift */,
);
name = Models;
sourceTree = "<group>";
};
99F8870C1DEA3E560044E3B0 /* Mocks */ = {
isa = PBXGroup;
children = (
99F8870D1DEA3E6D0044E3B0 /* characters_response.json */,
99F8870F1DEA3EA00044E3B0 /* character.json */,
);
name = Mocks;
sourceTree = "<group>";
};
99FC2BC61DDDB0A5006CB7EE /* Datasources */ = {
isa = PBXGroup;
children = (
99FC2BC91DDDB1BF006CB7EE /* CharactersDatasource.swift */,
99FC2BC71DDDB0F3006CB7EE /* ItemsTableViewDatasource.swift */,
99D0DEB11DE2598F00FE34D7 /* ItemsCollectionViewDatasource.swift */,
99D0DEB71DE25BF300FE34D7 /* CharactersCollectionDatasource.swift */,
);
path = Datasources;
sourceTree = "<group>";
};
99FC2BCB1DDDB8B1006CB7EE /* Xibs */ = {
isa = PBXGroup;
children = (
99FC2BCC1DDDB8C7006CB7EE /* CharacterTableCell.xib */,
99D0DEB51DE25AC900FE34D7 /* CharacterCollectionCell.xib */,
);
path = Xibs;
sourceTree = "<group>";
};
A614E78BE86E798A7E93A6F8 /* Frameworks */ = {
isa = PBXGroup;
children = (
A8D7213E1EA596B7C60C8E59 /* Pods_Marvel.framework */,
8C6A61295B862198BB138719 /* Pods_MarvelTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
F31159AB537646F3DA1B5700 /* Pods */ = {
isa = PBXGroup;
children = (
46E32511C8C4E886533F9B7E /* Pods-Marvel.debug.xcconfig */,
8289D5AF9F3BDEDBC4EE6E82 /* Pods-Marvel.release.xcconfig */,
BF2D032F8BA77A47BCBA607A /* Pods-MarvelTests.debug.xcconfig */,
E54675F9B824A595E2F0D533 /* Pods-MarvelTests.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
999665351DEA236300E9A5BF /* MarvelTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 9996653F1DEA236300E9A5BF /* Build configuration list for PBXNativeTarget "MarvelTests" */;
buildPhases = (
40FD7841A58E5007D40EC477 /* [CP] Check Pods Manifest.lock */,
999665321DEA236300E9A5BF /* Sources */,
999665331DEA236300E9A5BF /* Frameworks */,
999665341DEA236300E9A5BF /* Resources */,
AF9627A2960EE733DD7D8871 /* [CP] Embed Pods Frameworks */,
2163A2BCCD3A507A6B8CD6FB /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
9996653C1DEA236300E9A5BF /* PBXTargetDependency */,
);
name = MarvelTests;
productName = MarvelTests;
productReference = 999665361DEA236300E9A5BF /* MarvelTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
99E1DFDF1DDA1F4C006F9D96 /* Marvel */ = {
isa = PBXNativeTarget;
buildConfigurationList = 99E1DFF21DDA1F4C006F9D96 /* Build configuration list for PBXNativeTarget "Marvel" */;
buildPhases = (
349470B03A6A7FDAFB705949 /* [CP] Check Pods Manifest.lock */,
99D0DEBC1DE26D0F00FE34D7 /* SwiftGen */,
99E1DFDC1DDA1F4C006F9D96 /* Sources */,
99E1DFDD1DDA1F4C006F9D96 /* Frameworks */,
99E1DFDE1DDA1F4C006F9D96 /* Resources */,
65B66DF972813F1C9E6FAB9F /* [CP] Embed Pods Frameworks */,
572BC285D19F6AE624CEB662 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = Marvel;
productName = Marvel;
productReference = 99E1DFE01DDA1F4C006F9D96 /* Marvel.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
99E1DFD81DDA1F4C006F9D96 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0810;
LastUpgradeCheck = 0810;
ORGANIZATIONNAME = "Thiago Lioy";
TargetAttributes = {
999665351DEA236300E9A5BF = {
CreatedOnToolsVersion = 8.1;
DevelopmentTeam = 6UM2WYVE6K;
ProvisioningStyle = Automatic;
TestTargetID = 99E1DFDF1DDA1F4C006F9D96;
};
99E1DFDF1DDA1F4C006F9D96 = {
CreatedOnToolsVersion = 8.1;
DevelopmentTeam = 6UM2WYVE6K;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 99E1DFDB1DDA1F4C006F9D96 /* Build configuration list for PBXProject "Marvel" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 99E1DFD71DDA1F4C006F9D96;
productRefGroup = 99E1DFE11DDA1F4C006F9D96 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
99E1DFDF1DDA1F4C006F9D96 /* Marvel */,
999665351DEA236300E9A5BF /* MarvelTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
999665341DEA236300E9A5BF /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
99F8870E1DEA3E6D0044E3B0 /* characters_response.json in Resources */,
99F887101DEA3EA00044E3B0 /* character.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
99E1DFDE1DDA1F4C006F9D96 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
99FC2BCD1DDDB8C7006CB7EE /* CharacterTableCell.xib in Resources */,
99D0DEB61DE25AC900FE34D7 /* CharacterCollectionCell.xib in Resources */,
99E1DFEE1DDA1F4C006F9D96 /* LaunchScreen.storyboard in Resources */,
99E1DFEB1DDA1F4C006F9D96 /* Assets.xcassets in Resources */,
99E1DFE91DDA1F4C006F9D96 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
2163A2BCCD3A507A6B8CD6FB /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MarvelTests/Pods-MarvelTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
349470B03A6A7FDAFB705949 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
40FD7841A58E5007D40EC477 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
572BC285D19F6AE624CEB662 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Marvel/Pods-Marvel-resources.sh\"\n";
showEnvVarsInLog = 0;
};
65B66DF972813F1C9E6FAB9F /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Marvel/Pods-Marvel-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
99D0DEBC1DE26D0F00FE34D7 /* SwiftGen */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = SwiftGen;
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "$PODS_ROOT/SwiftGen/bin/swiftgen storyboards -t swift3 $SOURCE_ROOT --output $SOURCE_ROOT/Marvel/Resources/Storyboard.swift --sceneEnumName Storyboard";
};
AF9627A2960EE733DD7D8871 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MarvelTests/Pods-MarvelTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
999665321DEA236300E9A5BF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9976B4F81DEA43F200D2D3C4 /* MockLoader.swift in Sources */,
99C67AC51DEB032F00FB1E68 /* CharactersDatasourceSpec.swift in Sources */,
99C67AC71DEB06C100FB1E68 /* CharactersDelegateSpec.swift in Sources */,
999665411DEA242300E9A5BF /* CharacterSpec.swift in Sources */,
99C67AC21DEB007600FB1E68 /* CharacterViewControllerSpec.swift in Sources */,
99C67ACA1DEB0B3D00FB1E68 /* CharactersCollectionDatasourceSpec.swift in Sources */,
99EF5DB61DEA5CCD00B5569F /* ThumbImageSpec.swift in Sources */,
993AFDFF1DEA764200857C4F /* CharactersViewControllerSpec.swift in Sources */,
99C67ACC1DEB0CB800FB1E68 /* CharactersCollectionDelegateSpec.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
99E1DFDC1DDA1F4C006F9D96 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
99D0DEB81DE25BF300FE34D7 /* CharactersCollectionDatasource.swift in Sources */,
99D0DEBE1DE26D8100FE34D7 /* Storyboard.swift in Sources */,
99FC2BC81DDDB0F3006CB7EE /* ItemsTableViewDatasource.swift in Sources */,
9939CFD11DDA30DC008CE399 /* MarvelAPIManager.swift in Sources */,
9922F15A1DFDC00900237BFE /* ApperanceProxyHelper.swift in Sources */,
99D0DEBA1DE268D000FE34D7 /* UIImageView+Kingfisher.swift in Sources */,
9939CFC91DDA245A008CE399 /* CharacterViewController.swift in Sources */,
99D0DEB41DE259F100FE34D7 /* CharacterCollectionCell.swift in Sources */,
99B248E31DDB427000027C10 /* CharacterTableCell.swift in Sources */,
9939CFC71DDA244A008CE399 /* CharactersViewController.swift in Sources */,
99D0DEB21DE2598F00FE34D7 /* ItemsCollectionViewDatasource.swift in Sources */,
9939CFD41DDA333D008CE399 /* Character.swift in Sources */,
9922F1571DFDB69200237BFE /* ColorPalette.swift in Sources */,
99E1DFE41DDA1F4C006F9D96 /* AppDelegate.swift in Sources */,
99FC2BCA1DDDB1BF006CB7EE /* CharactersDatasource.swift in Sources */,
9939CFCF1DDA2E07008CE399 /* MarvelAPI.swift in Sources */,
99FC2BCF1DDDB966006CB7EE /* ThumbImage.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
9996653C1DEA236300E9A5BF /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 99E1DFDF1DDA1F4C006F9D96 /* Marvel */;
targetProxy = 9996653B1DEA236300E9A5BF /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
99E1DFE71DDA1F4C006F9D96 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
99E1DFE81DDA1F4C006F9D96 /* Base */,
);
name = Main.storyboard;
path = .;
sourceTree = "<group>";
};
99E1DFEC1DDA1F4C006F9D96 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
99E1DFED1DDA1F4C006F9D96 /* Base */,
);
name = LaunchScreen.storyboard;
path = .;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
9996653D1DEA236300E9A5BF /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = BF2D032F8BA77A47BCBA607A /* Pods-MarvelTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = 6UM2WYVE6K;
INFOPLIST_FILE = MarvelTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.tpioy.marvelapp.MarvelTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Marvel.app/Marvel";
};
name = Debug;
};
9996653E1DEA236300E9A5BF /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = E54675F9B824A595E2F0D533 /* Pods-MarvelTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = 6UM2WYVE6K;
INFOPLIST_FILE = MarvelTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.tpioy.marvelapp.MarvelTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Marvel.app/Marvel";
};
name = Release;
};
99E1DFF01DDA1F4C006F9D96 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
99E1DFF11DDA1F4C006F9D96 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
99E1DFF31DDA1F4C006F9D96 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 46E32511C8C4E886533F9B7E /* Pods-Marvel.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = 6UM2WYVE6K;
INFOPLIST_FILE = Marvel/Resources/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.tpioy.marvelapp.Marvel;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = 1;
};
name = Debug;
};
99E1DFF41DDA1F4C006F9D96 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8289D5AF9F3BDEDBC4EE6E82 /* Pods-Marvel.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = 6UM2WYVE6K;
INFOPLIST_FILE = Marvel/Resources/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.tpioy.marvelapp.Marvel;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = 1;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
9996653F1DEA236300E9A5BF /* Build configuration list for PBXNativeTarget "MarvelTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
9996653D1DEA236300E9A5BF /* Debug */,
9996653E1DEA236300E9A5BF /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
99E1DFDB1DDA1F4C006F9D96 /* Build configuration list for PBXProject "Marvel" */ = {
isa = XCConfigurationList;
buildConfigurations = (
99E1DFF01DDA1F4C006F9D96 /* Debug */,
99E1DFF11DDA1F4C006F9D96 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
99E1DFF21DDA1F4C006F9D96 /* Build configuration list for PBXNativeTarget "Marvel" */ = {
isa = XCConfigurationList;
buildConfigurations = (
99E1DFF31DDA1F4C006F9D96 /* Debug */,
99E1DFF41DDA1F4C006F9D96 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 99E1DFD81DDA1F4C006F9D96 /* Project object */;
}
================================================
FILE: Marvel.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:Marvel.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: Marvel.xcodeproj/xcshareddata/xcschemes/Marvel.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0810"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "99E1DFDF1DDA1F4C006F9D96"
BuildableName = "Marvel.app"
BlueprintName = "Marvel"
ReferencedContainer = "container:Marvel.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "999665351DEA236300E9A5BF"
BuildableName = "MarvelTests.xctest"
BlueprintName = "MarvelTests"
ReferencedContainer = "container:Marvel.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "99E1DFDF1DDA1F4C006F9D96"
BuildableName = "Marvel.app"
BlueprintName = "Marvel"
ReferencedContainer = "container:Marvel.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "99E1DFDF1DDA1F4C006F9D96"
BuildableName = "Marvel.app"
BlueprintName = "Marvel"
ReferencedContainer = "container:Marvel.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "99E1DFDF1DDA1F4C006F9D96"
BuildableName = "Marvel.app"
BlueprintName = "Marvel"
ReferencedContainer = "container:Marvel.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
================================================
FILE: MarvelTests/CharacterSpec.swift
================================================
//
// NewTestSpec.swift
// Marvel
//
// Created by Thiago Lioy on 26/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Quick
import Nimble
@testable import Marvel
class CharacterSpec: QuickSpec {
override func spec() {
describe("a character") {
var character: Marvel.Character!
beforeEach {
let testBundle = Bundle(for: type(of: self))
let mockLoader = MockLoader(file: "character", in: testBundle)
character = mockLoader?.map(to: Character.self)
}
it("should be able to create a chracter from json") {
expect(character).toNot(beNil())
}
it("should have a thumbImage") {
expect(character.thumImage).toNot(beNil())
}
}
}
}
================================================
FILE: MarvelTests/CharacterViewControllerSpec.swift
================================================
//
// CharacterViewControllerSpec.swift
// Marvel
//
// Created by Thiago Lioy on 27/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Foundation
import Quick
import Nimble
@testable import Marvel
class CharacterViewControllerSpec: QuickSpec {
override func spec() {
describe("CharacterViewController") {
var controller: CharacterViewController!
var character: Marvel.Character!
beforeEach {
let testBundle = Bundle(for: type(of: self))
let mockLoader = MockLoader(file: "character", in: testBundle)
character = (mockLoader?.map(to: Character.self))!
controller = Storyboard.Main.characterViewControllerScene.viewController() as! CharacterViewController
controller.character = character
//Load view components
let _ = controller.view
}
context("valid character") {
it("should setup properties with character information") {
controller.viewDidLoad()
let name = controller.name.text
expect(name).to(equal(character.name))
}
}
context("nil character") {
it("should setup properties with default values") {
controller.character = nil
controller.viewDidLoad()
let name = controller.name.text
expect(name).to(equal(""))
}
}
}
}
}
================================================
FILE: MarvelTests/CharactersCollectionDatasourceSpec.swift
================================================
//
// CharactersCollectionDatasourceSpec.swift
// Marvel
//
// Created by Thiago Lioy on 27/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Foundation
import Quick
import Nimble
@testable import Marvel
class CharactersCollectionDatasourceSpec: QuickSpec {
override func spec() {
describe("CharactersCollectionDatasource") {
var controller: CharactersViewController!
var character: Marvel.Character!
beforeEach {
let testBundle = Bundle(for: type(of: self))
let mockLoader = MockLoader(file: "character", in: testBundle)
character = (mockLoader?.map(to: Character.self))!
let apiMock = MarvelAPICallsMock(characters: [character])
controller = Storyboard.Main.charactersViewControllerScene.viewController() as! CharactersViewController
controller.apiManager = apiMock
//Load view components
let _ = controller.view
controller.showAsGrid(UIButton())
}
it("should have a valid datasource") {
expect(controller.collectionDatasource).toNot(beNil())
}
it("should have a cell of expected type") {
let indexPath = IndexPath(row: 0, section: 0)
let cell = controller.collectionDatasource!.collectionView(controller.collectionView, cellForItemAt: indexPath)
expect(cell.isKind(of: CharacterCollectionCell.self)).to(beTruthy())
}
it("should have a configured cell") {
let indexPath = IndexPath(row: 0, section: 0)
let cell = controller.collectionDatasource!.collectionView(controller.collectionView, cellForItemAt: indexPath) as! CharacterCollectionCell
let name = cell.name.text!
expect(name).to(equal(character.name))
}
it("should have the right numberOfRowsInSection") {
let count = controller.collectionDatasource!.collectionView(controller.collectionView, numberOfItemsInSection: 0)
expect(count).to(equal(1))
}
}
}
}
================================================
FILE: MarvelTests/CharactersCollectionDelegateSpec.swift
================================================
//
// CharactersCollectionDelegateSpec.swift
// Marvel
//
// Created by Thiago Lioy on 27/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Foundation
import Quick
import Nimble
@testable import Marvel
class CharactersCollectionDelegateMock: CharactersDelegate {
var didSelectRowTrigged = false
func didSelectCharacter(at index: IndexPath) {
didSelectRowTrigged = true
}
}
class CharactersCollectionDelegateSpec: QuickSpec {
override func spec() {
describe("CharactersCollectionDelegate") {
var controller: CharactersViewController!
var character: Marvel.Character!
beforeEach {
let testBundle = Bundle(for: type(of: self))
let mockLoader = MockLoader(file: "character", in: testBundle)
character = (mockLoader?.map(to: Character.self))!
let apiMock = MarvelAPICallsMock(characters: [character])
controller = Storyboard.Main.charactersViewControllerScene.viewController() as! CharactersViewController
controller.apiManager = apiMock
//Load view components
let _ = controller.view
controller.showAsGrid(UIButton())
}
it("should have a valid delegate") {
expect(controller.collectionDelegate).toNot(beNil())
}
it("should have a cell of expected size") {
let indexPath = IndexPath(row: 0, section: 0)
let size = controller.collectionDelegate!.collectionView(controller.collectionView, layout: controller.collectionView.collectionViewLayout, sizeForItemAt: indexPath)
let width = controller.collectionView.bounds.size.width
let expectedSize = CharacterCollectionCell.size(for: width)
expect(size.height).to(equal(expectedSize.height))
expect(size.width).to(equal(expectedSize.width))
}
it("should call delegate on didSelectedRowAt") {
let indexPath = IndexPath(row: 0, section: 0)
let charactersDelegateMock = CharactersCollectionDelegateMock()
controller.collectionDelegate = CharactersCollectionDelegate(charactersDelegateMock)
expect(charactersDelegateMock.didSelectRowTrigged).to(beFalsy())
controller.collectionDelegate!.collectionView(controller.collectionView, didSelectItemAt: indexPath)
expect(charactersDelegateMock.didSelectRowTrigged).to(beTruthy())
}
}
}
}
================================================
FILE: MarvelTests/CharactersDatasourceSpec.swift
================================================
//
// CharactersDatasourceSpec.swift
// Marvel
//
// Created by Thiago Lioy on 27/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Foundation
import Quick
import Nimble
@testable import Marvel
class CharactersDatasourceSpec: QuickSpec {
override func spec() {
describe("CharactersDatasource") {
var controller: CharactersViewController!
var character: Marvel.Character!
beforeEach {
let testBundle = Bundle(for: type(of: self))
let mockLoader = MockLoader(file: "character", in: testBundle)
character = (mockLoader?.map(to: Character.self))!
let apiMock = MarvelAPICallsMock(characters: [character])
controller = Storyboard.Main.charactersViewControllerScene.viewController() as! CharactersViewController
controller.apiManager = apiMock
//Load view components
let _ = controller.view
}
it("should have a valid datasource") {
expect(controller.tableDatasource).toNot(beNil())
}
it("should have a cell of expected type") {
let indexPath = IndexPath(row: 0, section: 0)
let cell = controller.tableDatasource!.tableView(controller.tableView, cellForRowAt: indexPath)
expect(cell.isKind(of: CharacterTableCell.self)).to(beTruthy())
}
it("should have a configured cell") {
let indexPath = IndexPath(row: 0, section: 0)
let cell = controller.tableDatasource!.tableView(controller.tableView, cellForRowAt: indexPath) as! CharacterTableCell
let name = cell.name.text!
expect(name).to(equal(character.name))
}
it("should have the right numberOfRowsInSection") {
let count = controller.tableDatasource!.tableView(controller.tableView, numberOfRowsInSection: 0)
expect(count).to(equal(1))
}
}
}
}
================================================
FILE: MarvelTests/CharactersDelegateSpec.swift
================================================
//
// CharactersDelegateSpec.swift
// Marvel
//
// Created by Thiago Lioy on 27/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Foundation
import Quick
import Nimble
@testable import Marvel
class CharactersDelegateMock: CharactersDelegate {
var didSelectRowTrigged = false
func didSelectCharacter(at index: IndexPath) {
didSelectRowTrigged = true
}
}
class CharactersDelegateSpec: QuickSpec {
override func spec() {
describe("CharactersDelegate") {
var controller: CharactersViewController!
var character: Marvel.Character!
beforeEach {
let testBundle = Bundle(for: type(of: self))
let mockLoader = MockLoader(file: "character", in: testBundle)
character = (mockLoader?.map(to: Character.self))!
let apiMock = MarvelAPICallsMock(characters: [character])
controller = Storyboard.Main.charactersViewControllerScene.viewController() as! CharactersViewController
controller.apiManager = apiMock
//Load view components
let _ = controller.view
}
it("should have a valid datasource") {
expect(controller.tableDelegate).toNot(beNil())
}
it("should have a cell of expected height") {
let indexPath = IndexPath(row: 0, section: 0)
let height = controller.tableDelegate!.tableView(controller.tableView, heightForRowAt: indexPath)
expect(height).to(equal(80))
}
it("should call delegate on didSelectedRowAt") {
let indexPath = IndexPath(row: 0, section: 0)
let charactersDelegateMock = CharactersDelegateMock()
controller.tableDelegate = CharactersTableDelegate(charactersDelegateMock)
expect(charactersDelegateMock.didSelectRowTrigged).to(beFalsy())
controller.tableDelegate!.tableView(controller.tableView, didSelectRowAt: indexPath)
expect(charactersDelegateMock.didSelectRowTrigged).to(beTruthy())
}
}
}
}
================================================
FILE: MarvelTests/CharactersViewControllerSpec.swift
================================================
//
// CharactersViewControllerSpec.swift
// Marvel
//
// Created by Thiago Lioy on 27/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Foundation
import Quick
import Nimble
@testable import Marvel
struct MarvelAPICallsMock: MarvelAPICalls {
let characters: [Marvel.Character]
func characters(query: String? = nil, completion: @escaping ([Marvel.Character]?) -> Void) {
completion(characters)
}
}
class CharactersViewControllerSpec: QuickSpec {
override func spec() {
describe("CharactersViewController") {
var controller: CharactersViewController!
var apiMock: MarvelAPICalls!
beforeEach {
let testBundle = Bundle(for: type(of: self))
let mockLoader = MockLoader(file: "character", in: testBundle)
let character = (mockLoader?.map(to: Character.self))!
apiMock = MarvelAPICallsMock(characters: [character])
controller = Storyboard.Main.charactersViewControllerScene.viewController() as! CharactersViewController
controller.apiManager = apiMock
//Load view components
let _ = controller.view
}
it("should have expected props setup") {
controller.viewDidLoad()
expect(controller.apiManager).toNot(beNil())
expect(controller.tableDatasource).toNot(beNil())
expect(controller.tableDelegate).toNot(beNil())
expect(controller.collectionDatasource).to(beNil())
expect(controller.collectionDelegate).to(beNil())
expect(controller.characters).toNot(beNil())
expect(controller.searchBar).toNot(beNil())
expect(controller.activityIndicator).toNot(beNil())
expect(controller.tableView).toNot(beNil())
expect(controller.collectionView).toNot(beNil())
}
it("should use mock response on fetchCharacters") {
controller.viewDidLoad()
let count = controller.tableDatasource?.items.count ?? 0
expect(count).toEventually(equal(1))
}
it("should be able to display content as tableView") {
controller.viewDidLoad()
controller.showAsTable(UIButton())
expect(controller.collectionView.isHidden).to(beTruthy())
expect(controller.tableView.isHidden).to(beFalsy())
}
it("should be able to display content as collectionView") {
controller.viewDidLoad()
controller.showAsGrid(UIButton())
expect(controller.tableView.isHidden).to(beTruthy())
expect(controller.collectionView.isHidden).to(beFalsy())
}
context("Empty search") {
it("should not fetchCharacters when no searchTerm is provided") {
controller.searchBar.text = ""
let searchBar = controller.searchBar
controller.characters = []
controller.searchBarSearchButtonClicked(searchBar!)
expect(controller.characters.isEmpty).to(beTruthy())
}
}
context("Not empty search") {
it("should fetchCharacters when searchTerm is provided") {
controller.searchBar.text = "searchThis"
let searchBar = controller.searchBar
controller.characters = []
controller.searchBarSearchButtonClicked(searchBar!)
expect(controller.characters.isEmpty).to(beFalsy())
}
}
it("should hide keyboard with click on searchbar cancel button") {
let searchBar = controller.searchBar!
searchBar.becomeFirstResponder()
controller.searchBarCancelButtonClicked(searchBar)
expect(searchBar.isFirstResponder).to(beFalsy())
}
context("didSelectCharacter") {
beforeEach {
let navController: UINavigationController = Storyboard.Main.initialViewController()
controller = navController.viewControllers.first as! CharactersViewController
controller.apiManager = apiMock
let _ = controller.view
controller.viewDidLoad()
}
it("should navigate do next controller when selecting a character") {
let indexPath = IndexPath(row: 0, section: 0)
let controllerCounts = controller.navigationController?.viewControllers.count
expect(controllerCounts).to(equal(1))
controller.didSelectCharacter(at: indexPath)
expect(controller.navigationController?.viewControllers.count ?? 0)
.toEventually(equal(2), timeout: 3)
}
}
}
}
}
================================================
FILE: MarvelTests/Info.plist
================================================
<?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>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
================================================
FILE: MarvelTests/MockLoader.swift
================================================
//
// MockLoader.swift
// Marvel
//
// Created by Thiago Lioy on 26/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Foundation
import ObjectMapper
@testable import Marvel
struct MockLoader {
let data: Data
let json: String
init?(file: String, withExtension fileExt: String = "json", in bundle:Bundle = Bundle.main) {
guard let path = bundle.path(forResource: file, ofType: fileExt) else {
return nil
}
let pathURL = URL(fileURLWithPath: path)
do {
data = try Data(contentsOf: pathURL, options: .dataReadingMapped)
if let decoded = NSString(data: data, encoding: 0) as? String {
json = decoded
} else {
return nil
}
} catch{
return nil
}
}
}
extension MockLoader {
func map<T: Mappable>(to type: T.Type) -> T? {
return Mapper<T>().map(JSONString: json)
}
}
================================================
FILE: MarvelTests/ThumbImageSpec.swift
================================================
//
// ThumbImageSpec.swift
// Marvel
//
// Created by Thiago Lioy on 26/11/16.
// Copyright © 2016 Thiago Lioy. All rights reserved.
//
import Foundation
import Quick
import Nimble
@testable import Marvel
class ThumbImageSpec: QuickSpec {
override func spec() {
describe("a thumbImage") {
var thumbImage = ThumbImage()
it("should be able to create a chracter from json") {
thumbImage.imageExtension = "png"
thumbImage.path = "whatever"
expect(thumbImage.fullPath()).to(equal("whatever.png"))
}
}
}
}
================================================
FILE: MarvelTests/character.json
================================================
{
"id": 1011334,
"name": "3-D Man",
"description": "",
"modified": "2014-04-29T14:18:17-0400",
"thumbnail": {
"path": "http://i.annihil.us/u/prod/marvel/i/mg/c/e0/535fecbbb9784",
"extension": "jpg"
},
"resourceURI": "http://gateway.marvel.com/v1/public/characters/1011334",
"comics": {
"available": 11,
"collectionURI": "http://gateway.marvel.com/v1/public/characters/1011334/comics",
"items": [
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/21366",
"name": "Avengers: The Initiative (2007) #14"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/24571",
"name": "Avengers: The Initiative (2007) #14 (SPOTLIGHT VARIANT)"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/21546",
"name": "Avengers: The Initiative (2007) #15"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/21741",
"name": "Avengers: The Initiative (2007) #16"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/21975",
"name": "Avengers: The Initiative (2007) #17"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/22299",
"name": "Avengers: The Initiative (2007) #18"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/22300",
"name": "Avengers: The Initiative (2007) #18 (ZOMBIE VARIANT)"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/22506",
"name": "Avengers: The Initiative (2007) #19"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/10223",
"name": "Marvel Premiere (1972) #35"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/10224",
"name": "Marvel Premiere (1972) #36"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/10225",
"name": "Marvel Premiere (1972) #37"
}
],
"returned": 11
},
"series": {
"available": 2,
"collectionURI": "http://gateway.marvel.com/v1/public/characters/1011334/series",
"items": [
{
"resourceURI": "http://gateway.marvel.com/v1/public/series/1945",
"name": "Avengers: The Initiative (2007 - 2010)"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/series/2045",
"name": "Marvel Premiere (1972 - 1981)"
}
],
"returned": 2
},
"stories": {
"available": 17,
"collectionURI": "http://gateway.marvel.com/v1/public/characters/1011334/stories",
"items": [
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/19947",
"name": "Cover #19947",
"type": "cover"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/19948",
"name": "The 3-D Man!",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/19949",
"name": "Cover #19949",
"type": "cover"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/19950",
"name": "The Devil's Music!",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/19951",
"name": "Cover #19951",
"type": "cover"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/19952",
"name": "Code-Name: The Cold Warrior!",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/47185",
"name": "Avengers: The Initiative (2007) #14 - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/47499",
"name": "Avengers: The Initiative (2007) #15 - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/47792",
"name": "Avengers: The Initiative (2007) #16",
"type": "cover"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/47793",
"name": "Avengers: The Initiative (2007) #16 - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/48362",
"name": "Avengers: The Initiative (2007) #17 - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/49104",
"name": "Avengers: The Initiative (2007) #18 - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/49106",
"name": "Avengers: The Initiative (2007) #18, Zombie Variant - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/49888",
"name": "Avengers: The Initiative (2007) #19",
"type": "cover"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/49889",
"name": "Avengers: The Initiative (2007) #19 - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/54371",
"name": "Avengers: The Initiative (2007) #14, Spotlight Variant - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/96303",
"name": "Deadpool (1997) #44",
"type": "interiorStory"
}
],
"returned": 17
},
"events": {
"available": 1,
"collectionURI": "http://gateway.marvel.com/v1/public/characters/1011334/events",
"items": [
{
"resourceURI": "http://gateway.marvel.com/v1/public/events/269",
"name": "Secret Invasion"
}
],
"returned": 1
},
"urls": [
{
"type": "detail",
"url": "http://marvel.com/characters/74/3-d_man?utm_campaign=apiRef&utm_source=c71376dc66cd17b7f74bfeed02a6b9c2"
},
{
"type": "wiki",
"url": "http://marvel.com/universe/3-D_Man_(Chandler)?utm_campaign=apiRef&utm_source=c71376dc66cd17b7f74bfeed02a6b9c2"
},
{
"type": "comiclink",
"url": "http://marvel.com/comics/characters/1011334/3-d_man?utm_campaign=apiRef&utm_source=c71376dc66cd17b7f74bfeed02a6b9c2"
}
]
}
================================================
FILE: MarvelTests/characters_response.json
================================================
{
"code": 200,
"status": "Ok",
"copyright": "© 2016 MARVEL",
"attributionText": "Data provided by Marvel. © 2016 MARVEL",
"attributionHTML": "<a href=\"http://marvel.com\">Data provided by Marvel. © 2016 MARVEL</a>",
"etag": "e1cef8a6e120071d86387f876a7eb1c011a1b0ac",
"data": {
"offset": 0,
"limit": 2,
"total": 1485,
"count": 2,
"results": [
{
"id": 1011334,
"name": "3-D Man",
"description": "",
"modified": "2014-04-29T14:18:17-0400",
"thumbnail": {
"path": "http://i.annihil.us/u/prod/marvel/i/mg/c/e0/535fecbbb9784",
"extension": "jpg"
},
"resourceURI": "http://gateway.marvel.com/v1/public/characters/1011334",
"comics": {
"available": 11,
"collectionURI": "http://gateway.marvel.com/v1/public/characters/1011334/comics",
"items": [
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/21366",
"name": "Avengers: The Initiative (2007) #14"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/24571",
"name": "Avengers: The Initiative (2007) #14 (SPOTLIGHT VARIANT)"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/21546",
"name": "Avengers: The Initiative (2007) #15"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/21741",
"name": "Avengers: The Initiative (2007) #16"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/21975",
"name": "Avengers: The Initiative (2007) #17"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/22299",
"name": "Avengers: The Initiative (2007) #18"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/22300",
"name": "Avengers: The Initiative (2007) #18 (ZOMBIE VARIANT)"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/22506",
"name": "Avengers: The Initiative (2007) #19"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/10223",
"name": "Marvel Premiere (1972) #35"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/10224",
"name": "Marvel Premiere (1972) #36"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/comics/10225",
"name": "Marvel Premiere (1972) #37"
}
],
"returned": 11
},
"series": {
"available": 2,
"collectionURI": "http://gateway.marvel.com/v1/public/characters/1011334/series",
"items": [
{
"resourceURI": "http://gateway.marvel.com/v1/public/series/1945",
"name": "Avengers: The Initiative (2007 - 2010)"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/series/2045",
"name": "Marvel Premiere (1972 - 1981)"
}
],
"returned": 2
},
"stories": {
"available": 17,
"collectionURI": "http://gateway.marvel.com/v1/public/characters/1011334/stories",
"items": [
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/19947",
"name": "Cover #19947",
"type": "cover"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/19948",
"name": "The 3-D Man!",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/19949",
"name": "Cover #19949",
"type": "cover"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/19950",
"name": "The Devil's Music!",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/19951",
"name": "Cover #19951",
"type": "cover"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/19952",
"name": "Code-Name: The Cold Warrior!",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/47185",
"name": "Avengers: The Initiative (2007) #14 - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/47499",
"name": "Avengers: The Initiative (2007) #15 - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/47792",
"name": "Avengers: The Initiative (2007) #16",
"type": "cover"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/47793",
"name": "Avengers: The Initiative (2007) #16 - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/48362",
"name": "Avengers: The Initiative (2007) #17 - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/49104",
"name": "Avengers: The Initiative (2007) #18 - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/49106",
"name": "Avengers: The Initiative (2007) #18, Zombie Variant - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/49888",
"name": "Avengers: The Initiative (2007) #19",
"type": "cover"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/49889",
"name": "Avengers: The Initiative (2007) #19 - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/54371",
"name": "Avengers: The Initiative (2007) #14, Spotlight Variant - Int",
"type": "interiorStory"
},
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/96303",
"name": "Deadpool (1997) #44",
"type": "interiorStory"
}
],
"returned": 17
},
"events": {
"available": 1,
"collectionURI": "http://gateway.marvel.com/v1/public/characters/1011334/events",
"items": [
{
"resourceURI": "http://gateway.marvel.com/v1/public/events/269",
"name": "Secret Invasion"
}
],
"returned": 1
},
"urls": [
{
"type": "detail",
"url": "http://marvel.com/characters/74/3-d_man?utm_campaign=apiRef&utm_source=c71376dc66cd17b7f74bfeed02a6b9c2"
},
{
"type": "wiki",
"url": "http://marvel.com/universe/3-D_Man_(Chandler)?utm_campaign=apiRef&utm_source=c71376dc66cd17b7f74bfeed02a6b9c2"
},
{
"type": "comiclink",
"url": "http://marvel.com/comics/characters/1011334/3-d_man?utm_campaign=apiRef&utm_source=c71376dc66cd17b7f74bfeed02a6b9c2"
}
]
},
{
"id": 1017100,
"name": "A-Bomb (HAS)",
"description": "Rick Jones has been Hulk's best bud since day one, but now he's more than a friend...he's a teammate! Transformed by a Gamma energy explosion, A-Bomb's thick, armored skin is just as strong and powerful as it is blue. And when he curls into action, he uses it like a giant bowling ball of destruction! ",
"modified": "2013-09-18T15:54:04-0400",
"thumbnail": {
"path": "http://i.annihil.us/u/prod/marvel/i/mg/3/20/5232158de5b16",
"extension": "jpg"
},
"resourceURI": "http://gateway.marvel.com/v1/public/characters/1017100",
"comics": {
"available": 0,
"collectionURI": "http://gateway.marvel.com/v1/public/characters/1017100/comics",
"items": [],
"returned": 0
},
"series": {
"available": 0,
"collectionURI": "http://gateway.marvel.com/v1/public/characters/1017100/series",
"items": [],
"returned": 0
},
"stories": {
"available": 1,
"collectionURI": "http://gateway.marvel.com/v1/public/characters/1017100/stories",
"items": [
{
"resourceURI": "http://gateway.marvel.com/v1/public/stories/105929",
"name": "cover from Free Comic Book Day 2013 (Avengers/Hulk) (2013) #1",
"type": "cover"
}
],
"returned": 1
},
"events": {
"available": 0,
"collectionURI": "http://gateway.marvel.com/v1/public/characters/1017100/events",
"items": [],
"returned": 0
},
"urls": [
{
"type": "detail",
"url": "http://marvel.com/characters/76/a-bomb?utm_campaign=apiRef&utm_source=c71376dc66cd17b7f74bfeed02a6b9c2"
},
{
"type": "comiclink",
"url": "http://marvel.com/comics/characters/1017100/a-bomb_has?utm_campaign=apiRef&utm_source=c71376dc66cd17b7f74bfeed02a6b9c2"
}
]
}
]
}
}
================================================
FILE: Podfile
================================================
# Uncomment the next line to define a global platform for your project
platform :ios, '9.0'
target 'Marvel' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
plugin 'cocoapods-keys', {
:project => "Marvel",
:target => "Marvel",
:keys => [
"MarvelApiKey",
"MarvelPrivateKey"
]}
# Pods for Marvel
pod 'SwiftGen'
pod 'RxSwift', '~> 3.0.0-beta.2'
pod 'Moya/RxSwift','~> 8.0.0-beta.1'
pod 'Moya-ObjectMapper/RxSwift', :git => 'https://github.com/ivanbruel/Moya-ObjectMapper'
pod 'CryptoSwift'
pod 'Dollar'
pod 'Kingfisher'
pod "Reusable"
end
target 'MarvelTests' do
use_frameworks!
pod 'Quick'
pod 'Nimble'
pod 'Fakery'
pod 'ObjectMapper'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = '3.0'
end
end
end
================================================
FILE: README.md
================================================
# Marvel App
[](https://twitter.com/tplioy)
[](https://github.com/thiagolioy/marvelapp/blob/master/LICENSE)
[](https://travis-ci.org/thiagolioy/marvelapp)
[](https://github.com/thiagolioy/marvelapp/network)
[](https://github.com/thiagolioy/marvelapp/stargazers)
[](https://github.com/thiagolioy/marvelapp/issues)
-------
<p align="center">
<a href="#appearance">Appearance</a> •
<a href="#motivation">Motivation</a> •
<a href="#posts">Posts</a> •
<a href="#installation">Installation</a>
</p>
-------
## Appearance
<h3 align="center">
<img src="assets/marvel_screens.png" alt="Marvel Screens" />
</h3>
## Motivation
This repository supports a series of posts that will show how to create an iOS app from scratch, using many different pods and tools that will make your life easier. The project will have Marvel's theme and use its [API](https://developer.marvel.com). You can usually find this information elsewhere but it is usually splitted in different unrelated tutorials, my approach here is to convey all within a single project
## Posts
Creating a Marvel iOS App from scratch..
- [Part 1 | Tools, pods, tricks of the trade and more](https://medium.com/cocoaacademymag/creating-a-ios-app-from-scratch-tools-pods-tricks-of-the-trade-and-more-part-1-a0a3f18fbd13#.fu8u4puxu)
- [Part 2 | Tests, coverage and more](https://medium.com/cocoaacademymag/creating-a-ios-app-from-scratch-part-2-tests-coverage-and-more-73b94178b695#.4s4omxm48)
- [Part 3 | Travis, Danger and Fastlane](https://medium.com/cocoaacademymag/creating-a-ios-app-from-scratch-part-3-travis-danger-and-fastlane-8ac91a003c95#.ii2fy9oc5)
- [Part 4 | Sketch for developers](https://medium.com/cocoaacademymag/creating-a-marvel-ios-app-from-scratch-part-4-sketch-for-developers-2344a221482a#.kr3lhhobz)
Other posts built upon Marvel's iOS App..
- [Migrating a Marvel's App to view code!](https://medium.com/cocoaacademymag/migrating-an-app-to-view-code-ffe3f1510408#.jwzemxaqa)
- [Testing Marvel's View Code project .. With 100 % Code coverage !!](https://medium.com/cocoaacademymag/testing-marvels-view-code-project-with-100-code-coverage-23c55de4053b#.j16lslb7k)
- [Marvel iOS App! Favoriting a character with View Code, Realm & RxSwift ..](https://medium.com/cocoaacademymag/marvel-ios-app-favoriting-a-character-with-view-code-realm-rxswift-e43b187c0f8e#.dd6bmjkil)
- [Architecture Thoughts: Migrating Marvel's iOS App to ReSwift](https://medium.com/cocoaacademymag/architecture-thoughts-migrating-marvels-ios-app-to-reswift-ef7f20e84e60#.nl0b3aizp)
## Installation
This project uses [Bundler](http://bundler.io) and [CocoaPods](https://cocoapods.org). All you need to setup it properly is:
```
bundle
bundle exec pod install
```
## Tests And Coverage
You can run the tests any time. All your need to do is:
```
bundle exec fastlane test
```
## License
This project is licensed under the terms of the MIT license. See the LICENSE file.
================================================
FILE: coverage/AppDelegate.swift.html
================================================
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>AppDelegate.swift - Slather</title>
<link href="slather.css" media="all" rel="stylesheet">
</head>
<body>
<header><div class="row"><a href="index.html"><img src="logo.jpg" alt="Slather logo"></a></div></header><div class="row"><div id="reports">
<h2 class="cov_title">
<span>Coverage for "AppDelegate.swift" : </span><span class="cov_high">100.00%</span>
</h2>
<h4 class="cov_subtitle">(4 of 4 relevant lines covered)</h4>
<h4 class="cov_filepath">Marvel/AppDelegate/AppDelegate.swift</h4>
<table class="source_code">
<tr class="never">
<td class="num">1</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">2</td>
<td class="src"><pre><code class="objc">// AppDelegate.swift</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">3</td>
<td class="src"><pre><code class="objc">// Marvel</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">4</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">5</td>
<td class="src"><pre><code class="objc">// Created by Thiago Lioy on 14/11/16.</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">6</td>
<td class="src"><pre><code class="objc">// Copyright �� 2016 Thiago Lioy. All rights reserved.</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">7</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">8</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">9</td>
<td class="src"><pre><code class="objc">import UIKit</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">10</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">11</td>
<td class="src"><pre><code class="objc">@UIApplicationMain</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">12</td>
<td class="src"><pre><code class="objc">class AppDelegate: UIResponder, UIApplicationDelegate {</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">13</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">14</td>
<td class="src"><pre><code class="objc"> var window: UIWindow?</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">15</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">16</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">17</td>
<td class="src"><pre><code class="objc"> func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {</code></pre></td>
<td class="coverage">1x</td>
</tr>
<tr class="covered">
<td class="num">18</td>
<td class="src"><pre><code class="objc"> // Override point for customization after application launch.</code></pre></td>
<td class="coverage">1x</td>
</tr>
<tr class="covered">
<td class="num">19</td>
<td class="src"><pre><code class="objc"> return true</code></pre></td>
<td class="coverage">1x</td>
</tr>
<tr class="covered">
<td class="num">20</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">1x</td>
</tr>
<tr class="never">
<td class="num">21</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">22</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">23</td>
<td class="src"><pre><code class="objc">}</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">24</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
</table>
</div></div>
<footer><div class="row">
<p><a href="https://github.com/SlatherOrg/slather">Fork me on Github</a></p>
<p>© 2016 Slather</p>
</div></footer><script src="highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script>
</body>
</html>
================================================
FILE: coverage/Character.swift.html
================================================
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>Character.swift - Slather</title>
<link href="slather.css" media="all" rel="stylesheet">
</head>
<body>
<header><div class="row"><a href="index.html"><img src="logo.jpg" alt="Slather logo"></a></div></header><div class="row"><div id="reports">
<h2 class="cov_title">
<span>Coverage for "Character.swift" : </span><span class="cov_high">100.00%</span>
</h2>
<h4 class="cov_subtitle">(8 of 8 relevant lines covered)</h4>
<h4 class="cov_filepath">Marvel/Models/Character.swift</h4>
<table class="source_code">
<tr class="never">
<td class="num">1</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">2</td>
<td class="src"><pre><code class="objc">// Character.swift</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">3</td>
<td class="src"><pre><code class="objc">// Marvel</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">4</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">5</td>
<td class="src"><pre><code class="objc">// Created by Thiago Lioy on 14/11/16.</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">6</td>
<td class="src"><pre><code class="objc">// Copyright �� 2016 Thiago Lioy. All rights reserved.</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">7</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">8</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">9</td>
<td class="src"><pre><code class="objc">import Foundation</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">10</td>
<td class="src"><pre><code class="objc">import ObjectMapper</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">11</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">12</td>
<td class="src"><pre><code class="objc">struct Character {</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">13</td>
<td class="src"><pre><code class="objc"> var id: Int = 0</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">14</td>
<td class="src"><pre><code class="objc"> var name: String = ""</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">15</td>
<td class="src"><pre><code class="objc"> var thumImage: ThumbImage?</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">16</td>
<td class="src"><pre><code class="objc">}</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">17</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">18</td>
<td class="src"><pre><code class="objc">extension Character: Mappable {</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">19</td>
<td class="src"><pre><code class="objc"> init?(map: Map) {</code></pre></td>
<td class="coverage">26x</td>
</tr>
<tr class="covered">
<td class="num">20</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage">26x</td>
</tr>
<tr class="covered">
<td class="num">21</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">26x</td>
</tr>
<tr class="never">
<td class="num">22</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">23</td>
<td class="src"><pre><code class="objc"> mutating func mapping(map: Map) {</code></pre></td>
<td class="coverage">26x</td>
</tr>
<tr class="covered">
<td class="num">24</td>
<td class="src"><pre><code class="objc"> id <- map["id"]</code></pre></td>
<td class="coverage">26x</td>
</tr>
<tr class="covered">
<td class="num">25</td>
<td class="src"><pre><code class="objc"> name <- map["name"]</code></pre></td>
<td class="coverage">26x</td>
</tr>
<tr class="covered">
<td class="num">26</td>
<td class="src"><pre><code class="objc"> thumImage <- map["thumbnail"]</code></pre></td>
<td class="coverage">26x</td>
</tr>
<tr class="covered">
<td class="num">27</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">26x</td>
</tr>
<tr class="never">
<td class="num">28</td>
<td class="src"><pre><code class="objc">}</code></pre></td>
<td class="coverage"></td>
</tr>
</table>
</div></div>
<footer><div class="row">
<p><a href="https://github.com/SlatherOrg/slather">Fork me on Github</a></p>
<p>© 2016 Slather</p>
</div></footer><script src="highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script>
</body>
</html>
================================================
FILE: coverage/CharacterCollectionCell.swift.html
================================================
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>CharacterCollectionCell.swift - Slather</title>
<link href="slather.css" media="all" rel="stylesheet">
</head>
<body>
<header><div class="row"><a href="index.html"><img src="logo.jpg" alt="Slather logo"></a></div></header><div class="row"><div id="reports">
<h2 class="cov_title">
<span>Coverage for "CharacterCollectionCell.swift" : </span><span class="cov_high">90.00%</span>
</h2>
<h4 class="cov_subtitle">(9 of 10 relevant lines covered)</h4>
<h4 class="cov_filepath">Marvel/Cells/CharacterCollectionCell.swift</h4>
<table class="source_code">
<tr class="never">
<td class="num">1</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">2</td>
<td class="src"><pre><code class="objc">// CharacterCollectionCell.swift</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">3</td>
<td class="src"><pre><code class="objc">// Marvel</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">4</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">5</td>
<td class="src"><pre><code class="objc">// Created by Thiago Lioy on 20/11/16.</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">6</td>
<td class="src"><pre><code class="objc">// Copyright �� 2016 Thiago Lioy. All rights reserved.</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">7</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">8</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">9</td>
<td class="src"><pre><code class="objc">import UIKit</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">10</td>
<td class="src"><pre><code class="objc">import Reusable</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">11</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">12</td>
<td class="src"><pre><code class="objc">final class CharacterCollectionCell: UICollectionViewCell, NibReusable {</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">13</td>
<td class="src"><pre><code class="objc"> @IBOutlet weak var name: UILabel!</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">14</td>
<td class="src"><pre><code class="objc"> @IBOutlet weak var thumb: UIImageView!</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">15</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">16</td>
<td class="src"><pre><code class="objc"> static let paddingBtwCells = CGFloat(10)</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">17</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">18</td>
<td class="src"><pre><code class="objc"> static func size(for parentWidth: CGFloat) -> CGSize {</code></pre></td>
<td class="coverage">4x</td>
</tr>
<tr class="covered">
<td class="num">19</td>
<td class="src"><pre><code class="objc"> let numberOfCells = CGFloat(2)</code></pre></td>
<td class="coverage">4x</td>
</tr>
<tr class="covered">
<td class="num">20</td>
<td class="src"><pre><code class="objc"> let totalPadding = CGFloat(numberOfCells+1) * paddingBtwCells</code></pre></td>
<td class="coverage">4x</td>
</tr>
<tr class="covered">
<td class="num">21</td>
<td class="src"><pre><code class="objc"> let width = (parentWidth - totalPadding) / numberOfCells</code></pre></td>
<td class="coverage">4x</td>
</tr>
<tr class="covered">
<td class="num">22</td>
<td class="src"><pre><code class="objc"> return CGSize(width: width, height: width)</code></pre></td>
<td class="coverage">4x</td>
</tr>
<tr class="covered">
<td class="num">23</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">4x</td>
</tr>
<tr class="never">
<td class="num">24</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">25</td>
<td class="src"><pre><code class="objc"> func setup(item: Character) {</code></pre></td>
<td class="coverage">2x</td>
</tr>
<tr class="covered">
<td class="num">26</td>
<td class="src"><pre><code class="objc"> name.text = item.name</code></pre></td>
<td class="coverage">2x</td>
</tr>
<tr class="missed">
<td class="num">27</td>
<td class="src"><pre><code class="objc"> thumb.download(image: item.thumImage?.fullPath() ?? "")</code></pre></td>
<td class="coverage">!</td>
</tr>
<tr class="covered">
<td class="num">28</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">2x</td>
</tr>
<tr class="never">
<td class="num">29</td>
<td class="src"><pre><code class="objc">}</code></pre></td>
<td class="coverage"></td>
</tr>
</table>
</div></div>
<footer><div class="row">
<p><a href="https://github.com/SlatherOrg/slather">Fork me on Github</a></p>
<p>© 2016 Slather</p>
</div></footer><script src="highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script>
</body>
</html>
================================================
FILE: coverage/CharacterTableCell.swift.html
================================================
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>CharacterTableCell.swift - Slather</title>
<link href="slather.css" media="all" rel="stylesheet">
</head>
<body>
<header><div class="row"><a href="index.html"><img src="logo.jpg" alt="Slather logo"></a></div></header><div class="row"><div id="reports">
<h2 class="cov_title">
<span>Coverage for "CharacterTableCell.swift" : </span><span class="cov_high">85.71%</span>
</h2>
<h4 class="cov_subtitle">(6 of 7 relevant lines covered)</h4>
<h4 class="cov_filepath">Marvel/Cells/CharacterTableCell.swift</h4>
<table class="source_code">
<tr class="never">
<td class="num">1</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">2</td>
<td class="src"><pre><code class="objc">// CharacterTableCell.swift</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">3</td>
<td class="src"><pre><code class="objc">// Marvel</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">4</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">5</td>
<td class="src"><pre><code class="objc">// Created by Thiago Lioy on 15/11/16.</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">6</td>
<td class="src"><pre><code class="objc">// Copyright �� 2016 Thiago Lioy. All rights reserved.</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">7</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">8</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">9</td>
<td class="src"><pre><code class="objc">import UIKit</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">10</td>
<td class="src"><pre><code class="objc">import Reusable</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">11</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">12</td>
<td class="src"><pre><code class="objc">final class CharacterTableCell: UITableViewCell, NibReusable {</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">13</td>
<td class="src"><pre><code class="objc"> @IBOutlet weak var name: UILabel!</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">14</td>
<td class="src"><pre><code class="objc"> @IBOutlet weak var thumb: UIImageView!</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">15</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">16</td>
<td class="src"><pre><code class="objc"> static func height() -> CGFloat {</code></pre></td>
<td class="coverage">33x</td>
</tr>
<tr class="covered">
<td class="num">17</td>
<td class="src"><pre><code class="objc"> return 80</code></pre></td>
<td class="coverage">33x</td>
</tr>
<tr class="covered">
<td class="num">18</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">33x</td>
</tr>
<tr class="never">
<td class="num">19</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">20</td>
<td class="src"><pre><code class="objc"> func setup(item: Character) {</code></pre></td>
<td class="coverage">2x</td>
</tr>
<tr class="covered">
<td class="num">21</td>
<td class="src"><pre><code class="objc"> name.text = item.name</code></pre></td>
<td class="coverage">2x</td>
</tr>
<tr class="missed">
<td class="num">22</td>
<td class="src"><pre><code class="objc"> thumb.download(image: item.thumImage?.fullPath() ?? "")</code></pre></td>
<td class="coverage">!</td>
</tr>
<tr class="covered">
<td class="num">23</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">2x</td>
</tr>
<tr class="never">
<td class="num">24</td>
<td class="src"><pre><code class="objc">}</code></pre></td>
<td class="coverage"></td>
</tr>
</table>
</div></div>
<footer><div class="row">
<p><a href="https://github.com/SlatherOrg/slather">Fork me on Github</a></p>
<p>© 2016 Slather</p>
</div></footer><script src="highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script>
</body>
</html>
================================================
FILE: coverage/CharacterViewController.swift.html
================================================
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>CharacterViewController.swift - Slather</title>
<link href="slather.css" media="all" rel="stylesheet">
</head>
<body>
<header><div class="row"><a href="index.html"><img src="logo.jpg" alt="Slather logo"></a></div></header><div class="row"><div id="reports">
<h2 class="cov_title">
<span>Coverage for "CharacterViewController.swift" : </span><span class="cov_high">100.00%</span>
</h2>
<h4 class="cov_subtitle">(8 of 8 relevant lines covered)</h4>
<h4 class="cov_filepath">Marvel/Controllers/CharacterViewController.swift</h4>
<table class="source_code">
<tr class="never">
<td class="num">1</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">2</td>
<td class="src"><pre><code class="objc">// CharacterViewController.swift</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">3</td>
<td class="src"><pre><code class="objc">// Marvel</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">4</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">5</td>
<td class="src"><pre><code class="objc">// Created by Thiago Lioy on 14/11/16.</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">6</td>
<td class="src"><pre><code class="objc">// Copyright �� 2016 Thiago Lioy. All rights reserved.</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">7</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">8</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">9</td>
<td class="src"><pre><code class="objc">import UIKit</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">10</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">11</td>
<td class="src"><pre><code class="objc">final class CharacterViewController: UIViewController {</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">12</td>
<td class="src"><pre><code class="objc"> @IBOutlet weak var name: UILabel!</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">13</td>
<td class="src"><pre><code class="objc"> @IBOutlet weak var image: UIImageView!</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">14</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">15</td>
<td class="src"><pre><code class="objc"> var character: Character?</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">16</td>
<td class="src"><pre><code class="objc">}</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">17</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">18</td>
<td class="src"><pre><code class="objc">extension CharacterViewController {</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">19</td>
<td class="src"><pre><code class="objc"> override func viewDidLoad() {</code></pre></td>
<td class="coverage">4x</td>
</tr>
<tr class="covered">
<td class="num">20</td>
<td class="src"><pre><code class="objc"> super.viewDidLoad()</code></pre></td>
<td class="coverage">4x</td>
</tr>
<tr class="covered">
<td class="num">21</td>
<td class="src"><pre><code class="objc"> setupView()</code></pre></td>
<td class="coverage">4x</td>
</tr>
<tr class="covered">
<td class="num">22</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">4x</td>
</tr>
<tr class="never">
<td class="num">23</td>
<td class="src"><pre><code class="objc">}</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">24</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">25</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">26</td>
<td class="src"><pre><code class="objc">extension CharacterViewController {</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">27</td>
<td class="src"><pre><code class="objc"> func setupView() {</code></pre></td>
<td class="coverage">4x</td>
</tr>
<tr class="covered">
<td class="num">28</td>
<td class="src"><pre><code class="objc"> name.text = character?.name ?? ""</code></pre></td>
<td class="coverage">1x</td>
</tr>
<tr class="covered">
<td class="num">29</td>
<td class="src"><pre><code class="objc"> image.download(image: character?.thumImage?.fullPath() ?? "")</code></pre></td>
<td class="coverage">1x</td>
</tr>
<tr class="covered">
<td class="num">30</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">4x</td>
</tr>
<tr class="never">
<td class="num">31</td>
<td class="src"><pre><code class="objc">}</code></pre></td>
<td class="coverage"></td>
</tr>
</table>
</div></div>
<footer><div class="row">
<p><a href="https://github.com/SlatherOrg/slather">Fork me on Github</a></p>
<p>© 2016 Slather</p>
</div></footer><script src="highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script>
</body>
</html>
================================================
FILE: coverage/CharactersCollectionDatasource.swift.html
================================================
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>CharactersCollectionDatasource.swift - Slather</title>
<link href="slather.css" media="all" rel="stylesheet">
</head>
<body>
<header><div class="row"><a href="index.html"><img src="logo.jpg" alt="Slather logo"></a></div></header><div class="row"><div id="reports">
<h2 class="cov_title">
<span>Coverage for "CharactersCollectionDatasource.swift" : </span><span class="cov_high">100.00%</span>
</h2>
<h4 class="cov_subtitle">(27 of 27 relevant lines covered)</h4>
<h4 class="cov_filepath">Marvel/Datasources/CharactersCollectionDatasource.swift</h4>
<table class="source_code">
<tr class="never">
<td class="num">1</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">2</td>
<td class="src"><pre><code class="objc">// CharactersCollectionDatasource.swift</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">3</td>
<td class="src"><pre><code class="objc">// Marvel</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">4</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">5</td>
<td class="src"><pre><code class="objc">// Created by Thiago Lioy on 20/11/16.</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">6</td>
<td class="src"><pre><code class="objc">// Copyright �� 2016 Thiago Lioy. All rights reserved.</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">7</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">8</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">9</td>
<td class="src"><pre><code class="objc">import UIKit</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">10</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">11</td>
<td class="src"><pre><code class="objc">final class CharactersCollectionDatasource: NSObject, ItemsCollectionViewDatasource {</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">12</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">13</td>
<td class="src"><pre><code class="objc"> var items:[Character] = []</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">14</td>
<td class="src"><pre><code class="objc"> weak var collectionView: UICollectionView?</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">15</td>
<td class="src"><pre><code class="objc"> weak var delegate: UICollectionViewDelegate?</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">16</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">17</td>
<td class="src"><pre><code class="objc"> required init(items: [Character], collectionView: UICollectionView, delegate: UICollectionViewDelegate) {</code></pre></td>
<td class="coverage">8x</td>
</tr>
<tr class="covered">
<td class="num">18</td>
<td class="src"><pre><code class="objc"> self.items = items</code></pre></td>
<td class="coverage">8x</td>
</tr>
<tr class="covered">
<td class="num">19</td>
<td class="src"><pre><code class="objc"> self.collectionView = collectionView</code></pre></td>
<td class="coverage">8x</td>
</tr>
<tr class="covered">
<td class="num">20</td>
<td class="src"><pre><code class="objc"> self.delegate = delegate</code></pre></td>
<td class="coverage">8x</td>
</tr>
<tr class="covered">
<td class="num">21</td>
<td class="src"><pre><code class="objc"> super.init()</code></pre></td>
<td class="coverage">8x</td>
</tr>
<tr class="covered">
<td class="num">22</td>
<td class="src"><pre><code class="objc"> collectionView.register(cellType: CharacterCollectionCell.self)</code></pre></td>
<td class="coverage">8x</td>
</tr>
<tr class="covered">
<td class="num">23</td>
<td class="src"><pre><code class="objc"> self.setupCollectionView()</code></pre></td>
<td class="coverage">8x</td>
</tr>
<tr class="covered">
<td class="num">24</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">8x</td>
</tr>
<tr class="never">
<td class="num">25</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">26</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">27</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">28</td>
<td class="src"><pre><code class="objc"> func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {</code></pre></td>
<td class="coverage">3x</td>
</tr>
<tr class="covered">
<td class="num">29</td>
<td class="src"><pre><code class="objc"> return self.items.count</code></pre></td>
<td class="coverage">3x</td>
</tr>
<tr class="covered">
<td class="num">30</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">3x</td>
</tr>
<tr class="never">
<td class="num">31</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">32</td>
<td class="src"><pre><code class="objc"> func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {</code></pre></td>
<td class="coverage">2x</td>
</tr>
<tr class="covered">
<td class="num">33</td>
<td class="src"><pre><code class="objc"> let cell = collectionView.dequeueReusableCell(for: indexPath, cellType: CharacterCollectionCell.self)</code></pre></td>
<td class="coverage">2x</td>
</tr>
<tr class="covered">
<td class="num">34</td>
<td class="src"><pre><code class="objc"> let character = self.items[indexPath.row]</code></pre></td>
<td class="coverage">2x</td>
</tr>
<tr class="covered">
<td class="num">35</td>
<td class="src"><pre><code class="objc"> cell.setup(item: character)</code></pre></td>
<td class="coverage">2x</td>
</tr>
<tr class="covered">
<td class="num">36</td>
<td class="src"><pre><code class="objc"> return cell</code></pre></td>
<td class="coverage">2x</td>
</tr>
<tr class="covered">
<td class="num">37</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">2x</td>
</tr>
<tr class="never">
<td class="num">38</td>
<td class="src"><pre><code class="objc">}</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">39</td>
<td class="src"><pre><code class="objc"></code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">40</td>
<td class="src"><pre><code class="objc">class CharactersCollectionDelegate: NSObject, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">41</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">42</td>
<td class="src"><pre><code class="objc"> let delegate: CharactersDelegate</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">43</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">44</td>
<td class="src"><pre><code class="objc"> init(_ delegate: CharactersDelegate) {</code></pre></td>
<td class="coverage">9x</td>
</tr>
<tr class="covered">
<td class="num">45</td>
<td class="src"><pre><code class="objc"> self.delegate = delegate</code></pre></td>
<td class="coverage">9x</td>
</tr>
<tr class="covered">
<td class="num">46</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">9x</td>
</tr>
<tr class="never">
<td class="num">47</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">48</td>
<td class="src"><pre><code class="objc"> func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {</code></pre></td>
<td class="coverage">1x</td>
</tr>
<tr class="covered">
<td class="num">49</td>
<td class="src"><pre><code class="objc"> delegate.didSelectCharacter(at: indexPath)</code></pre></td>
<td class="coverage">1x</td>
</tr>
<tr class="covered">
<td class="num">50</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">1x</td>
</tr>
<tr class="never">
<td class="num">51</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">52</td>
<td class="src"><pre><code class="objc"> </code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="covered">
<td class="num">53</td>
<td class="src"><pre><code class="objc"> func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {</code></pre></td>
<td class="coverage">3x</td>
</tr>
<tr class="covered">
<td class="num">54</td>
<td class="src"><pre><code class="objc"> let width = collectionView.bounds.size.width</code></pre></td>
<td class="coverage">3x</td>
</tr>
<tr class="covered">
<td class="num">55</td>
<td class="src"><pre><code class="objc"> return CharacterCollectionCell.size(for: width)</code></pre></td>
<td class="coverage">3x</td>
</tr>
<tr class="covered">
<td class="num">56</td>
<td class="src"><pre><code class="objc"> }</code></pre></td>
<td class="coverage">3x</td>
</tr>
<tr class="never">
<td class="num">57</td>
<td class="src"><pre><code class="objc">}</code></pre></td>
<td class="coverage"></td>
</tr>
</table>
</div></div>
<footer><div class="row">
<p><a href="https://github.com/SlatherOrg/slather">Fork me on Github</a></p>
<p>© 2016 Slather</p>
</div></footer><script src="highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script>
</body>
</html>
================================================
FILE: coverage/CharactersDatasource.swift.html
================================================
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>CharactersDatasource.swift - Slather</title>
<link href="slather.css" media="all" rel="stylesheet">
</head>
<body>
<header><div class="row"><a href="index.html"><img src="logo.jpg" alt="Slather logo"></a></div></header><div class="row"><div id="reports">
<h2 class="cov_title">
<span>Coverage for "CharactersDatasource.swift" : </span><span class="cov_high">100.00%</span>
</h2>
<h4 class="cov_subtitle">(26 of 26 relevant lines covered)</h4>
<h4 class="cov_filepath">Marvel/Datasources/CharactersDatasource.swift</h4>
<table class="source_code">
<tr class="never">
<td class="num">1</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">2</td>
<td class="src"><pre><code class="objc">// CharactersDatasource.swift</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">3</td>
<td class="src"><pre><code class="objc">// Marvel</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">4</td>
<td class="src"><pre><code class="objc">//</code></pre></td>
<td class="coverage"></td>
</tr>
<tr class="never">
<td class="num">5</td>
<td class="src"><pre><code class="objc">// Created by Thiago Lioy on 17/11/
gitextract_9es8icdz/
├── .gitignore
├── .ruby-version
├── .travis.yml
├── Dangerfile
├── Gemfile
├── LICENSE
├── Marvel/
│ ├── AppDelegate/
│ │ └── AppDelegate.swift
│ ├── ApperanceProxyHelper.swift
│ ├── Cells/
│ │ ├── CharacterCollectionCell.swift
│ │ ├── CharacterTableCell.swift
│ │ └── Xibs/
│ │ ├── CharacterCollectionCell.xib
│ │ └── CharacterTableCell.xib
│ ├── Controllers/
│ │ ├── CharacterViewController.swift
│ │ └── CharactersViewController.swift
│ ├── Datasources/
│ │ ├── CharactersCollectionDatasource.swift
│ │ ├── CharactersDatasource.swift
│ │ ├── ItemsCollectionViewDatasource.swift
│ │ └── ItemsTableViewDatasource.swift
│ ├── Models/
│ │ ├── Character.swift
│ │ └── ThumbImage.swift
│ ├── Network/
│ │ ├── MarvelAPI.swift
│ │ └── MarvelAPIManager.swift
│ ├── Resources/
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── Grid Icon.imageset/
│ │ │ │ └── Contents.json
│ │ │ └── List Icon.imageset/
│ │ │ └── Contents.json
│ │ ├── ColorPalette.swift
│ │ ├── Info.plist
│ │ └── Storyboard.swift
│ ├── Storyboards/
│ │ └── Base.lproj/
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ └── UIImageView+Kingfisher.swift
├── Marvel.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ └── contents.xcworkspacedata
│ └── xcshareddata/
│ └── xcschemes/
│ └── Marvel.xcscheme
├── MarvelTests/
│ ├── CharacterSpec.swift
│ ├── CharacterViewControllerSpec.swift
│ ├── CharactersCollectionDatasourceSpec.swift
│ ├── CharactersCollectionDelegateSpec.swift
│ ├── CharactersDatasourceSpec.swift
│ ├── CharactersDelegateSpec.swift
│ ├── CharactersViewControllerSpec.swift
│ ├── Info.plist
│ ├── MockLoader.swift
│ ├── ThumbImageSpec.swift
│ ├── character.json
│ └── characters_response.json
├── Podfile
├── README.md
├── coverage/
│ ├── AppDelegate.swift.html
│ ├── Character.swift.html
│ ├── CharacterCollectionCell.swift.html
│ ├── CharacterTableCell.swift.html
│ ├── CharacterViewController.swift.html
│ ├── CharactersCollectionDatasource.swift.html
│ ├── CharactersDatasource.swift.html
│ ├── CharactersViewController.swift.html
│ ├── ItemsCollectionViewDatasource.swift.html
│ ├── ItemsTableViewDatasource.swift.html
│ ├── ThumbImage.swift.html
│ ├── UIImageView+Kingfisher.swift.html
│ ├── highlight.pack.js
│ ├── index.html
│ └── slather.css
└── fastlane/
├── Appfile
├── Fastfile
└── README.md
SYMBOL INDEX (20 symbols across 1 files)
FILE: coverage/highlight.pack.js
function n (line 1) | function n(e){return e.replace(/&/gm,"&").replace(/</gm,"<").repl...
function t (line 1) | function t(e){return e.nodeName.toLowerCase()}
function r (line 1) | function r(e,n){var t=e&&e.exec(n);return t&&0==t.index}
function a (line 1) | function a(e){return/no-?highlight|plain|text/.test(e)}
function i (line 1) | function i(e){var n,t,r,i=e.className+" ";if(i+=e.parentNode?e.parentNod...
function o (line 1) | function o(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t...
function u (line 1) | function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i...
function c (line 1) | function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!=r[...
function s (line 1) | function s(e){function n(e){return e&&e.source||e}function t(t,r){return...
function f (line 1) | function f(e,t,a,i){function o(e,n){for(var t=0;t<n.c.length;t++)if(r(n....
function l (line 1) | function l(e,t){t=t||w.languages||Object.keys(x);var r={r:0,value:n(e)},...
function g (line 1) | function g(e){return w.tabReplace&&(e=e.replace(/^((<[^>]+>|\t)+)/gm,fun...
function h (line 1) | function h(e,n,t){var r=n?R[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)...
function p (line 1) | function p(e){var n=i(e);if(!a(n)){var t;w.useBR?(t=document.createEleme...
function d (line 1) | function d(e){w=o(w,e)}
function b (line 1) | function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll("...
function v (line 1) | function v(){addEventListener("DOMContentLoaded",b,!1),addEventListener(...
function m (line 1) | function m(n,t){var r=x[n]=t(e);r.aliases&&r.aliases.forEach(function(e)...
function N (line 1) | function N(){return Object.keys(x)}
function E (line 1) | function E(e){return x[e]||x[R[e]]}
Condensed preview — 67 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (291K chars).
[
{
"path": ".gitignore",
"chars": 1452,
"preview": "# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n"
},
{
"path": ".ruby-version",
"chars": 6,
"preview": "2.3.0\n"
},
{
"path": ".travis.yml",
"chars": 1771,
"preview": "language: objective-c\nosx_image: xcode8.1\ncache:\n- bundler\n- cocoapods\nbefore_install:\n- bundle install\n- bundle exec po"
},
{
"path": "Dangerfile",
"chars": 1108,
"preview": "# Sometimes it's a README fix, or something like that - which isn't relevant for\n# including in a project's CHANGELOG fo"
},
{
"path": "Gemfile",
"chars": 213,
"preview": "# frozen_string_literal: true\nsource \"https://rubygems.org\"\n\n# gem \"rails\"\ngem \"cocoapods\", \"1.1.1\"\ngem \"cocoapods-keys\""
},
{
"path": "LICENSE",
"chars": 1068,
"preview": "MIT License\n\nCopyright (c) 2016 Thiago Lioy\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
},
{
"path": "Marvel/AppDelegate/AppDelegate.swift",
"chars": 556,
"preview": "//\n// AppDelegate.swift\n// Marvel\n//\n// Created by Thiago Lioy on 14/11/16.\n// Copyright © 2016 Thiago Lioy. All rig"
},
{
"path": "Marvel/ApperanceProxyHelper.swift",
"chars": 505,
"preview": "//\n// ApperanceProxyHelper.swift\n// Marvel\n//\n// Created by Thiago Lioy on 11/12/16.\n// Copyright © 2016 Thiago Lioy"
},
{
"path": "Marvel/Cells/CharacterCollectionCell.swift",
"chars": 688,
"preview": "//\n// CharacterCollectionCell.swift\n// Marvel\n//\n// Created by Thiago Lioy on 20/11/16.\n// Copyright © 2016 Thiago L"
},
{
"path": "Marvel/Cells/CharacterTableCell.swift",
"chars": 664,
"preview": "//\n// CharacterTableCell.swift\n// Marvel\n//\n// Created by Thiago Lioy on 15/11/16.\n// Copyright © 2016 Thiago Lioy. "
},
{
"path": "Marvel/Cells/Xibs/CharacterCollectionCell.xib",
"chars": 5375,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "Marvel/Cells/Xibs/CharacterTableCell.xib",
"chars": 5979,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "Marvel/Controllers/CharacterViewController.swift",
"chars": 902,
"preview": "//\n// CharacterViewController.swift\n// Marvel\n//\n// Created by Thiago Lioy on 14/11/16.\n// Copyright © 2016 Thiago L"
},
{
"path": "Marvel/Controllers/CharactersViewController.swift",
"chars": 3708,
"preview": "//\n// CharactersViewController.swift\n// Marvel\n//\n// Created by Thiago Lioy on 14/11/16.\n// Copyright © 2016 Thiago "
},
{
"path": "Marvel/Datasources/CharactersCollectionDatasource.swift",
"chars": 1938,
"preview": "//\n// CharactersCollectionDatasource.swift\n// Marvel\n//\n// Created by Thiago Lioy on 20/11/16.\n// Copyright © 2016 T"
},
{
"path": "Marvel/Datasources/CharactersDatasource.swift",
"chars": 1611,
"preview": "//\n// CharactersDatasource.swift\n// Marvel\n//\n// Created by Thiago Lioy on 17/11/16.\n// Copyright © 2016 Thiago Lioy"
},
{
"path": "Marvel/Datasources/ItemsCollectionViewDatasource.swift",
"chars": 754,
"preview": "//\n// ItemsCollectionViewDatasource.swift\n// Marvel\n//\n// Created by Thiago Lioy on 20/11/16.\n// Copyright © 2016 Th"
},
{
"path": "Marvel/Datasources/ItemsTableViewDatasource.swift",
"chars": 674,
"preview": "//\n// ItemsTableDatasource.swift\n// Marvel\n//\n// Created by Thiago Lioy on 17/11/16.\n// Copyright © 2016 Thiago Lioy"
},
{
"path": "Marvel/Models/Character.swift",
"chars": 557,
"preview": "//\n// Character.swift\n// Marvel\n//\n// Created by Thiago Lioy on 14/11/16.\n// Copyright © 2016 Thiago Lioy. All right"
},
{
"path": "Marvel/Models/ThumbImage.swift",
"chars": 546,
"preview": "//\n// ThumbImage.swift\n// Marvel\n//\n// Created by Thiago Lioy on 17/11/16.\n// Copyright © 2016 Thiago Lioy. All righ"
},
{
"path": "Marvel/Network/MarvelAPI.swift",
"chars": 1932,
"preview": "//\n// MarvelAPI.swift\n// Marvel\n//\n// Created by Thiago Lioy on 14/11/16.\n// Copyright © 2016 Thiago Lioy. All right"
},
{
"path": "Marvel/Network/MarvelAPIManager.swift",
"chars": 3093,
"preview": "//\n// MarvelAPIManager.swift\n// Marvel\n//\n// Created by Thiago Lioy on 14/11/16.\n// Copyright © 2016 Thiago Lioy. Al"
},
{
"path": "Marvel/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1048,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"iphone\",\n \"size\" : \"20x20\",\n \"scale\" : \"2x\"\n },\n {\n \"size\" "
},
{
"path": "Marvel/Resources/Assets.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Marvel/Resources/Assets.xcassets/Grid Icon.imageset/Contents.json",
"chars": 456,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"Grid Icon@1x.png\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "Marvel/Resources/Assets.xcassets/List Icon.imageset/Contents.json",
"chars": 453,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"List Icon.png\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "Marvel/Resources/ColorPalette.swift",
"chars": 440,
"preview": "//\n// ColorPalette.swift\n// Marvel\n//\n// Created by Thiago Lioy on 11/12/16.\n// Copyright © 2016 Thiago Lioy. All ri"
},
{
"path": "Marvel/Resources/Info.plist",
"chars": 1568,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Marvel/Resources/Storyboard.swift",
"chars": 2638,
"preview": "// Generated using SwiftGen, by O.Halligon — https://github.com/AliSoftware/SwiftGen\n\nimport Foundation\nimport UIKit\n\npr"
},
{
"path": "Marvel/Storyboards/Base.lproj/LaunchScreen.storyboard",
"chars": 3609,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Marvel/Storyboards/Base.lproj/Main.storyboard",
"chars": 17495,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Marvel/UIImageView+Kingfisher.swift",
"chars": 398,
"preview": "//\n// UIImage+Kingfisher.swift\n// Marvel\n//\n// Created by Thiago Lioy on 20/11/16.\n// Copyright © 2016 Thiago Lioy. "
},
{
"path": "Marvel.xcodeproj/project.pbxproj",
"chars": 40072,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "Marvel.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 151,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:Marvel.xcodepro"
},
{
"path": "Marvel.xcodeproj/xcshareddata/xcschemes/Marvel.xcscheme",
"chars": 3752,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"0810\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "MarvelTests/CharacterSpec.swift",
"chars": 902,
"preview": "//\n// NewTestSpec.swift\n// Marvel\n//\n// Created by Thiago Lioy on 26/11/16.\n// Copyright © 2016 Thiago Lioy. All rig"
},
{
"path": "MarvelTests/CharacterViewControllerSpec.swift",
"chars": 1695,
"preview": "//\n// CharacterViewControllerSpec.swift\n// Marvel\n//\n// Created by Thiago Lioy on 27/11/16.\n// Copyright © 2016 Thia"
},
{
"path": "MarvelTests/CharactersCollectionDatasourceSpec.swift",
"chars": 2380,
"preview": "//\n// CharactersCollectionDatasourceSpec.swift\n// Marvel\n//\n// Created by Thiago Lioy on 27/11/16.\n// Copyright © 20"
},
{
"path": "MarvelTests/CharactersCollectionDelegateSpec.swift",
"chars": 2772,
"preview": "//\n// CharactersCollectionDelegateSpec.swift\n// Marvel\n//\n// Created by Thiago Lioy on 27/11/16.\n// Copyright © 2016"
},
{
"path": "MarvelTests/CharactersDatasourceSpec.swift",
"chars": 2212,
"preview": "//\n// CharactersDatasourceSpec.swift\n// Marvel\n//\n// Created by Thiago Lioy on 27/11/16.\n// Copyright © 2016 Thiago "
},
{
"path": "MarvelTests/CharactersDelegateSpec.swift",
"chars": 2341,
"preview": "//\n// CharactersDelegateSpec.swift\n// Marvel\n//\n// Created by Thiago Lioy on 27/11/16.\n// Copyright © 2016 Thiago Li"
},
{
"path": "MarvelTests/CharactersViewControllerSpec.swift",
"chars": 5351,
"preview": "//\n// CharactersViewControllerSpec.swift\n// Marvel\n//\n// Created by Thiago Lioy on 27/11/16.\n// Copyright © 2016 Thi"
},
{
"path": "MarvelTests/Info.plist",
"chars": 680,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "MarvelTests/MockLoader.swift",
"chars": 985,
"preview": "//\n// MockLoader.swift\n// Marvel\n//\n// Created by Thiago Lioy on 26/11/16.\n// Copyright © 2016 Thiago Lioy. All righ"
},
{
"path": "MarvelTests/ThumbImageSpec.swift",
"chars": 640,
"preview": "//\n// ThumbImageSpec.swift\n// Marvel\n//\n// Created by Thiago Lioy on 26/11/16.\n// Copyright © 2016 Thiago Lioy. All "
},
{
"path": "MarvelTests/character.json",
"chars": 8262,
"preview": "{\n \"id\": 1011334,\n \"name\": \"3-D Man\",\n \"description\": \"\",\n \"modified\": \"2014-04-29T14:18:17-0400\",\n \"thum"
},
{
"path": "MarvelTests/characters_response.json",
"chars": 13934,
"preview": "{\n \"code\": 200,\n \"status\": \"Ok\",\n \"copyright\": \"© 2016 MARVEL\",\n \"attributionText\": \"Data provided by Marvel"
},
{
"path": "Podfile",
"chars": 973,
"preview": "# Uncomment the next line to define a global platform for your project\nplatform :ios, '9.0'\n\ntarget 'Marvel' do\n # Comm"
},
{
"path": "README.md",
"chars": 3444,
"preview": "# Marvel App\n\n[](https://twitter.co"
},
{
"path": "coverage/AppDelegate.swift.html",
"chars": 4661,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html>\n<head>"
},
{
"path": "coverage/Character.swift.html",
"chars": 5207,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html>\n<head>"
},
{
"path": "coverage/CharacterCollectionCell.swift.html",
"chars": 5701,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html>\n<head>"
},
{
"path": "coverage/CharacterTableCell.swift.html",
"chars": 4713,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html>\n<head>"
},
{
"path": "coverage/CharacterViewController.swift.html",
"chars": 5792,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html>\n<head>"
},
{
"path": "coverage/CharactersCollectionDatasource.swift.html",
"chars": 10676,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html>\n<head>"
},
{
"path": "coverage/CharactersDatasource.swift.html",
"chars": 9930,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html>\n<head>"
},
{
"path": "coverage/CharactersViewController.swift.html",
"chars": 19710,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html>\n<head>"
},
{
"path": "coverage/ItemsCollectionViewDatasource.swift.html",
"chars": 5638,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html>\n<head>"
},
{
"path": "coverage/ItemsTableViewDatasource.swift.html",
"chars": 5414,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html>\n<head>"
},
{
"path": "coverage/ThumbImage.swift.html",
"chars": 5674,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html>\n<head>"
},
{
"path": "coverage/UIImageView+Kingfisher.swift.html",
"chars": 3913,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html>\n<head>"
},
{
"path": "coverage/highlight.pack.js",
"chars": 11432,
"preview": "!function(e){\"undefined\"!=typeof exports?e(exports):(window.hljs=e({}),\"function\"==typeof define&&define.amd&&define(\"hl"
},
{
"path": "coverage/index.html",
"chars": 5229,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html>\n<head>"
},
{
"path": "coverage/slather.css",
"chars": 6266,
"preview": "/* --------------------------------------------------------\nSlather stylesheet\n\nversion: 0.1\nauthor: Ikhsan Assaat (@ixn"
},
{
"path": "fastlane/Appfile",
"chars": 313,
"preview": "app_identifier \"\" # The bundle identifier of your app\napple_id \"\" # Your Apple email address\n\nteam_id \"\" # Developer Po"
},
{
"path": "fastlane/Fastfile",
"chars": 2446,
"preview": "# Customise this file, documentation can be found here:\n# https://github.com/fastlane/fastlane/tree/master/fastlane/docs"
},
{
"path": "fastlane/README.md",
"chars": 724,
"preview": "fastlane documentation\n================\n# Installation\n```\nsudo gem install fastlane\n```\n# Available Actions\n## iOS\n### "
}
]
About this extraction
This page contains the full source code of the thiagolioy/marvelapp GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 67 files (261.0 KB), approximately 77.0k tokens, and a symbol index with 20 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.