Skip to content

Commit 255b34f

Browse files
committedJan 24, 2016
Thomas commit
1 parent feb015a commit 255b34f

File tree

10 files changed

+280
-42
lines changed

10 files changed

+280
-42
lines changed
 

‎NewTextExchange.xcodeproj/project.pbxproj

+16
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
4EB84C7A1C54F8FE00C06088 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB84C791C54F8FE00C06088 /* Router.swift */; };
11+
4EB84C7C1C54FA1F00C06088 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB84C7B1C54FA1F00C06088 /* Database.swift */; };
1012
A12742861C53F40100A37B5C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A12742851C53F40100A37B5C /* AppDelegate.swift */; };
1113
A12742881C53F40100A37B5C /* BooksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A12742871C53F40100A37B5C /* BooksViewController.swift */; };
1214
A127428D1C53F40100A37B5C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A127428C1C53F40100A37B5C /* Assets.xcassets */; };
@@ -26,6 +28,8 @@
2628
/* End PBXBuildFile section */
2729

2830
/* Begin PBXFileReference section */
31+
4EB84C791C54F8FE00C06088 /* Router.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = "<group>"; };
32+
4EB84C7B1C54FA1F00C06088 /* Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Database.swift; sourceTree = "<group>"; };
2933
58266334CD05C88D35DD41AB /* Pods-NewTextExchange.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewTextExchange.release.xcconfig"; path = "Pods/Target Support Files/Pods-NewTextExchange/Pods-NewTextExchange.release.xcconfig"; sourceTree = "<group>"; };
3034
75280F513FCE9742D7B642C0 /* Pods_NewTextExchange.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NewTextExchange.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3135
8F1D4CD39C4171871F9EB8A4 /* Pods-NewTextExchange.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewTextExchange.debug.xcconfig"; path = "Pods/Target Support Files/Pods-NewTextExchange/Pods-NewTextExchange.debug.xcconfig"; sourceTree = "<group>"; };
@@ -66,6 +70,15 @@
6670
/* End PBXFrameworksBuildPhase section */
6771

6872
/* Begin PBXGroup section */
73+
4EB84C781C54F8E900C06088 /* Networking */ = {
74+
isa = PBXGroup;
75+
children = (
76+
4EB84C791C54F8FE00C06088 /* Router.swift */,
77+
4EB84C7B1C54FA1F00C06088 /* Database.swift */,
78+
);
79+
name = Networking;
80+
sourceTree = "<group>";
81+
};
6982
8CF644AC69A16B9D63DC6F36 /* Frameworks */ = {
7083
isa = PBXGroup;
7184
children = (
@@ -104,6 +117,7 @@
104117
A1FD0ED81C54018700EAB849 /* Models */,
105118
A1FD0ED91C54019100EAB849 /* Controllers */,
106119
A6BB8C971C54802D00EA5142 /* Views */,
120+
4EB84C781C54F8E900C06088 /* Networking */,
107121
A69E66C21C544EEB00EBEE6C /* Bridging-Header.h */,
108122
A127428C1C53F40100A37B5C /* Assets.xcassets */,
109123
A6BB8C921C5466E200EA5142 /* Main.storyboard */,
@@ -271,11 +285,13 @@
271285
isa = PBXSourcesBuildPhase;
272286
buildActionMask = 2147483647;
273287
files = (
288+
4EB84C7A1C54F8FE00C06088 /* Router.swift in Sources */,
274289
A1FD0ED71C54017100EAB849 /* Book.swift in Sources */,
275290
A6BB8C991C5481BB00EA5142 /* BookDetailsNEWController.swift in Sources */,
276291
A69E66C81C54554500EBEE6C /* LoginViewController.swift in Sources */,
277292
A1FD0ED51C53FC5900EAB849 /* BookListingCell.swift in Sources */,
278293
A1FD0EE11C540B8100EAB849 /* BookDetailsViewController.swift in Sources */,
294+
4EB84C7C1C54FA1F00C06088 /* Database.swift in Sources */,
279295
A12742881C53F40100A37B5C /* BooksViewController.swift in Sources */,
280296
A12742861C53F40100A37B5C /* AppDelegate.swift in Sources */,
281297
);

‎NewTextExchange/Book.swift

+31-9
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,41 @@
88

99
import Foundation
1010

11-
class Book: NSObject {
11+
final class Book: NSObject, ResponseObjectSerializable, ResponseCollectionSerializable {
12+
var id: Int?
1213
var title: String?
1314
var course: String?
1415
var price: Int?
15-
var coverImage: NSURL?
16+
var coverPhotoURL: String?
17+
var thumbnailPhotoURL: String?
1618
var isbn: Int?
1719

18-
init(title: String?, course: String?, price: Int?, coverImage: NSURL?) {
19-
self.title = title
20-
self.course = course
21-
self.price = price
22-
self.coverImage = coverImage
23-
//self.isbn = isbn
20+
override init() {
21+
super.init()
2422
}
2523

26-
}
24+
init?(representation: AnyObject) {
25+
super.init()
26+
27+
self.id = representation.valueForKeyPath("id") as? Int
28+
self.title = representation.valueForKeyPath("title") as? String
29+
self.course = representation.valueForKeyPath("course") as? String
30+
self.price = representation.valueForKeyPath("price") as? Int
31+
self.thumbnailPhotoURL = representation.valueForKeyPath("thumbnail_photo_URL") as? String
32+
self.coverPhotoURL = representation.valueForKeyPath("cover_photo_URL") as? String
33+
}
34+
35+
static func collection(response response: NSHTTPURLResponse, representation: AnyObject) -> [Book] {
36+
var books: [Book] = []
37+
38+
if let dataRepresentation = representation as? [[String: AnyObject]] {
39+
for bookRepresentation in dataRepresentation {
40+
if let book = Book(representation: bookRepresentation) {
41+
books.append(book)
42+
}
43+
}
44+
}
45+
46+
return books
47+
}
48+
}

‎NewTextExchange/BookDetailsViewController.swift

-3
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,10 @@ class BookDetailsViewController: UIViewController {
2525
super.viewDidLoad()
2626

2727
// Do any additional setup after loading the view.
28-
bookCoverImageView.setImageWithURL((singleBook?.coverImage)!)
29-
3028
bookTitleLabel.text = singleBook?.title
3129
courseNumberLabel.text = singleBook?.course
3230
priceLabel.text = String(singleBook?.price)
3331

34-
3532
}
3633

3734
override func didReceiveMemoryWarning() {

‎NewTextExchange/BookListingCell.swift

+8-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,14 @@ class BookListingCell: UICollectionViewCell {
6666
bookPriceLabel.text = formattedPrice
6767
}
6868

69-
bookImageView.setImageWithURL(book.coverImage!)
69+
if let bookCoverPhotoURL = book.thumbnailPhotoURL as String! {
70+
print(bookCoverPhotoURL)
71+
Database.getImageFromURL(bookCoverPhotoURL).then { image -> Void in
72+
self.bookImageView.image = image
73+
}.error { error -> Void in
74+
print(error)
75+
}
76+
}
7077
}
7178

7279
override func updateConstraints() {

‎NewTextExchange/BooksViewController.swift

+26-11
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,24 @@
77
//
88

99
import UIKit
10-
import AFNetworking
1110

1211
let reuseIdentifier = "Cell"
1312

1413
class BooksViewController: UIViewController {
1514
var filteredBooks = [Book]()
16-
let books = [
17-
Book(
18-
title: "Operating Systems",
19-
course: "COP4600", price: 45, coverImage: NSURL(string: "http://ecx.images-amazon.com/images/I/51T73lIemvL._SX328_BO1,204,203,200_.jpg")),
20-
Book(title: "English Composition 1", course: "ENC1102", price: 60, coverImage: NSURL(string: "http://image.slidesharecdn.com/modernworldhistorytextbooksocialtb-140208031911-phpapp01/95/modern-world-history-textbook-social-tb-1-638.jpg?cb=1391830310"))
21-
22-
]
15+
var books = [Book]()
2316

2417
var collectionView: UICollectionView!
2518
let collectionViewInsets = UIEdgeInsets(top: 4, left: 4, bottom: 0, right: 4)
19+
20+
let refreshControl = UIRefreshControl()
2621

2722
@IBOutlet weak var searchField: UITextField!
2823

2924
override func viewDidLoad() {
3025
super.viewDidLoad()
3126
setupViews()
27+
refresh(refreshControl)
3228
}
3329

3430
func setupViews() {
@@ -54,8 +50,13 @@ class BooksViewController: UIViewController {
5450
collectionView!.setCollectionViewLayout(layout, animated: false)
5551
collectionView!.registerClass(BookListingCell.self, forCellWithReuseIdentifier: reuseIdentifier)
5652
collectionView.backgroundColor = .whiteColor()
57-
53+
collectionView.alwaysBounceVertical = true;
54+
collectionView.bounces = true
55+
56+
refreshControl.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
57+
5858
view.addSubview(collectionView)
59+
collectionView.addSubview(refreshControl)
5960
setupConstraints()
6061
}
6162

@@ -86,6 +87,16 @@ class BooksViewController: UIViewController {
8687
let array = (books as NSArray).filteredArrayUsingPredicate(searchPredicate)
8788
filteredBooks = array as! [Book]
8889
}
90+
91+
func refresh(sender: UIRefreshControl) {
92+
Database.getBooks().then { books -> Void in
93+
self.books = books
94+
self.collectionView.reloadData()
95+
sender.endRefreshing()
96+
}.error { error -> Void in
97+
print("Getting Books Error: \(error)")
98+
}
99+
}
89100
}
90101

91102
extension BooksViewController: UICollectionViewDelegate, UICollectionViewDataSource {
@@ -112,8 +123,12 @@ extension BooksViewController: UICollectionViewDelegate, UICollectionViewDataSou
112123

113124
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
114125
collectionView.deselectItemAtIndexPath(indexPath, animated: true)
115-
let bookDetailsViewController = storyboard?.instantiateViewControllerWithIdentifier("BookDetailsViewController")
116-
navigationController?.pushViewController(bookDetailsViewController!, animated: true)
126+
if let bookDetailsViewController = storyboard?.instantiateViewControllerWithIdentifier("BookDetailsViewController")
127+
as? BookDetailsNEWController {
128+
let book = searchField.text!.isEmpty ? books[indexPath.row] : filteredBooks[indexPath.row]
129+
bookDetailsViewController.book = book
130+
navigationController?.pushViewController(bookDetailsViewController, animated: true)
131+
}
117132
}
118133
}
119134

‎NewTextExchange/Database.swift

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// Database.swift
3+
// NewTextExchange
4+
//
5+
// Created by Thomas Baldwin on 1/24/16.
6+
// Copyright © 2016 Eric Suarez. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import Alamofire
11+
import PromiseKit
12+
13+
struct Database {
14+
static func getImageFromURL(URL: String) -> Promise<UIImage> {
15+
return Promise { fulfill, reject in
16+
Alamofire.request(.GET, URL)
17+
.responseImage { response in
18+
switch response.result {
19+
case .Success(let image):
20+
fulfill(image)
21+
case .Failure(let error):
22+
print("getImageFromURL error")
23+
reject(error)
24+
}
25+
}
26+
}
27+
}
28+
29+
static func getBooks() -> Promise<[Book]> {
30+
return Promise { fulfill,reject in
31+
Alamofire.request(Router.ReadBooks()).validate()
32+
.responseCollection { (response: Response<[Book], NSError>) in
33+
switch response.result {
34+
case .Success(let books):
35+
fulfill(books)
36+
case .Failure(let error):
37+
reject(error)
38+
}
39+
}
40+
}
41+
}
42+
43+
static func getBook(bookId: Int) -> Promise<Book> {
44+
return Promise { fulfill,reject in
45+
Alamofire.request(Router.ReadBook(bookId)).validate()
46+
.responseObject { (response: Response<Book, NSError>) in
47+
switch response.result {
48+
case .Success(let book):
49+
fulfill(book)
50+
case .Failure(let error):
51+
reject(error)
52+
}
53+
}
54+
}
55+
}
56+
}

‎NewTextExchange/Router.swift

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//
2+
// Router.swift
3+
// NewTextExchange
4+
//
5+
// Created by Thomas Baldwin on 1/24/16.
6+
// Copyright © 2016 Eric Suarez. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import Alamofire
11+
import AlamofireImage
12+
13+
enum Router: URLRequestConvertible {
14+
static let baseURLString = "http://10.136.104.227:9001/api"
15+
static let imageCache = AutoPurgingImageCache()
16+
17+
// APIs exposed - commented by derek zeng
18+
case ReadBooks()
19+
case ReadBook(Int)
20+
21+
var method: Alamofire.Method {
22+
switch self {
23+
case .ReadBooks:
24+
return .GET
25+
case .ReadBook:
26+
return .GET
27+
}
28+
}
29+
30+
var path: String {
31+
switch self {
32+
case .ReadBooks():
33+
return "/books"
34+
case .ReadBook(let bookId):
35+
return "/books/\(bookId)"
36+
}
37+
}
38+
39+
// MARK: URLRequestConvertible
40+
41+
var URLRequest: NSMutableURLRequest {
42+
let URL = NSURL(string:"\(Router.baseURLString)\(path)")!
43+
let mutableURLRequest = NSMutableURLRequest(URL: URL)
44+
mutableURLRequest.HTTPMethod = method.rawValue
45+
return mutableURLRequest
46+
}
47+
}
48+
49+
public protocol ResponseObjectSerializable {
50+
init?(representation: AnyObject)
51+
}
52+
53+
public protocol ResponseCollectionSerializable {
54+
static func collection(response response: NSHTTPURLResponse, representation: AnyObject) -> [Self]
55+
}
56+
57+
extension Request {
58+
public func responseObject<T: ResponseObjectSerializable>(completionHandler: Response<T, NSError> -> Void) -> Self {
59+
let responseSerializer = ResponseSerializer<T, NSError> { request, response, data, error in
60+
guard error == nil else { return .Failure(error!) }
61+
62+
let JSONResponseSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
63+
let result = JSONResponseSerializer.serializeResponse(request, response, data, error)
64+
65+
switch result {
66+
case .Success(let value):
67+
if let
68+
responseObject = T(representation: value)
69+
{
70+
return .Success(responseObject)
71+
} else {
72+
let failureReason = "JSON could not be serialized into response object: \(value)"
73+
let error = Error.errorWithCode(.JSONSerializationFailed, failureReason: failureReason)
74+
return .Failure(error)
75+
}
76+
case .Failure(let error):
77+
return .Failure(error)
78+
}
79+
}
80+
81+
return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
82+
}
83+
84+
public func responseCollection<T: ResponseCollectionSerializable>(completionHandler: Response<[T], NSError> -> Void) -> Self {
85+
let responseSerializer = ResponseSerializer<[T], NSError> { request, response, data, error in
86+
guard error == nil else { return .Failure(error!) }
87+
88+
let JSONSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
89+
let result = JSONSerializer.serializeResponse(request, response, data, error)
90+
91+
switch result {
92+
case .Success(let value):
93+
if let response = response {
94+
return .Success(T.collection(response: response, representation: value))
95+
} else {
96+
let failureReason = "Response collection could not be serialized due to nil response"
97+
let error = Error.errorWithCode(.JSONSerializationFailed, failureReason: failureReason)
98+
return .Failure(error)
99+
}
100+
case .Failure(let error):
101+
return .Failure(error)
102+
}
103+
}
104+
105+
return response(responseSerializer: responseSerializer, completionHandler: completionHandler)
106+
}
107+
}

‎Podfile

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ platform :ios, "8.0"
22
use_frameworks!
33

44
target "NewTextExchange" do
5-
pod "AFNetworking"
5+
pod "Alamofire", "~> 3.0.0"
6+
pod "AlamofireImage", "~> 2.0"
67
pod "Cosmos", "~> 1.1"
78
pod "PureLayout"
89
pod "FBSDKCoreKit", "~> 4.7.0"
910
pod "FBSDKLoginKit", "~> 4.7.0"
1011
pod "FBSDKShareKit", "~> 4.7.0"
12+
pod "PromiseKit"
13+
pod "FBSDKMessengerShareKit"
1114
end
1215

‎Podfile.lock

+32-17
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,7 @@
11
PODS:
2-
- AFNetworking (3.0.4):
3-
- AFNetworking/NSURLSession (= 3.0.4)
4-
- AFNetworking/Reachability (= 3.0.4)
5-
- AFNetworking/Security (= 3.0.4)
6-
- AFNetworking/Serialization (= 3.0.4)
7-
- AFNetworking/UIKit (= 3.0.4)
8-
- AFNetworking/NSURLSession (3.0.4):
9-
- AFNetworking/Reachability
10-
- AFNetworking/Security
11-
- AFNetworking/Serialization
12-
- AFNetworking/Reachability (3.0.4)
13-
- AFNetworking/Security (3.0.4)
14-
- AFNetworking/Serialization (3.0.4)
15-
- AFNetworking/UIKit (3.0.4):
16-
- AFNetworking/NSURLSession
2+
- Alamofire (3.0.1)
3+
- AlamofireImage (2.0.0):
4+
- Alamofire (~> 3.0)
175
- Bolts (1.6.0):
186
- Bolts/AppLinks (= 1.6.0)
197
- Bolts/Tasks (= 1.6.0)
@@ -32,25 +20,52 @@ PODS:
3220
- FBSDKCoreKit/arc
3321
- FBSDKLoginKit (4.7.1):
3422
- FBSDKCoreKit
23+
- FBSDKMessengerShareKit (1.3.2)
3524
- FBSDKShareKit (4.7.1):
3625
- FBSDKCoreKit
26+
- OMGHTTPURLRQ (3.0.2):
27+
- OMGHTTPURLRQ/RQ (= 3.0.2)
28+
- OMGHTTPURLRQ/FormURLEncode (3.0.2)
29+
- OMGHTTPURLRQ/RQ (3.0.2):
30+
- OMGHTTPURLRQ/FormURLEncode
31+
- OMGHTTPURLRQ/UserAgent
32+
- OMGHTTPURLRQ/UserAgent (3.0.2)
33+
- PromiseKit (3.0.1):
34+
- PromiseKit/Foundation (= 3.0.1)
35+
- PromiseKit/QuartzCore (= 3.0.1)
36+
- PromiseKit/UIKit (= 3.0.1)
37+
- PromiseKit/CorePromise (3.0.1)
38+
- PromiseKit/Foundation (3.0.1):
39+
- OMGHTTPURLRQ (~> 3.0.0)
40+
- PromiseKit/CorePromise
41+
- PromiseKit/QuartzCore (3.0.1):
42+
- PromiseKit/CorePromise
43+
- PromiseKit/UIKit (3.0.1):
44+
- PromiseKit/CorePromise
3745
- PureLayout (3.0.1)
3846

3947
DEPENDENCIES:
40-
- AFNetworking
48+
- Alamofire (~> 3.0.0)
49+
- AlamofireImage (~> 2.0)
4150
- Cosmos (~> 1.1)
4251
- FBSDKCoreKit (~> 4.7.0)
4352
- FBSDKLoginKit (~> 4.7.0)
53+
- FBSDKMessengerShareKit
4454
- FBSDKShareKit (~> 4.7.0)
55+
- PromiseKit
4556
- PureLayout
4657

4758
SPEC CHECKSUMS:
48-
AFNetworking: a0075feb321559dc78d9d85b55d11caa19eabb93
59+
Alamofire: 2457e1b2e6c46bb05c3a598c542b7bfd08893775
60+
AlamofireImage: 5cecda9b1031f86067c89ddba1d91ead0a8c3f0e
4961
Bolts: f52a250053bb517ca874523c3913776359ab3def
5062
Cosmos: d05465696561ccb50fa8b7574026326bb23d654b
5163
FBSDKCoreKit: 9141b70960a37930850370495fe565f4a27ac141
5264
FBSDKLoginKit: c11ed3c2833472db3bb4a4aecf27af4a6f69b173
65+
FBSDKMessengerShareKit: 41c0b1a667d685c9433f993eb9611b3d5074e1cb
5366
FBSDKShareKit: 213adf63e073f41a346b0e7a689805880dc5150e
67+
OMGHTTPURLRQ: 8376dc887d76a5a7e2a67881dc788f917a2f437c
68+
PromiseKit: 19d12914484a15c25a46f72fde38579204a5dac6
5469
PureLayout: f35f5384c9c4e4479df041dbe33ad7577b71ddfb
5570

5671
COCOAPODS: 0.39.0

0 commit comments

Comments
 (0)
Please sign in to comment.