Skip to content

Commit f18eb8d

Browse files
committed
Part 7
1 parent b029717 commit f18eb8d

File tree

8 files changed

+237
-24
lines changed

8 files changed

+237
-24
lines changed

MusicPlayer.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
0270482B19C8EC3000FDA1C5 /* Blank52.png in Resources */ = {isa = PBXBuildFile; fileRef = 0270482A19C8EC3000FDA1C5 /* Blank52.png */; };
1818
0270482D19C8F35700FDA1C5 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0270482C19C8F35700FDA1C5 /* Album.swift */; };
1919
0270482F19C8F43500FDA1C5 /* DetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0270482E19C8F43500FDA1C5 /* DetailsViewController.swift */; };
20+
0270483119C8F6D000FDA1C5 /* Track.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0270483019C8F6D000FDA1C5 /* Track.swift */; };
21+
0270483519C8F80000FDA1C5 /* TrackCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0270483419C8F80000FDA1C5 /* TrackCell.swift */; };
2022
/* End PBXBuildFile section */
2123

2224
/* Begin PBXContainerItemProxy section */
@@ -44,6 +46,8 @@
4446
0270482A19C8EC3000FDA1C5 /* Blank52.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Blank52.png; sourceTree = "<group>"; };
4547
0270482C19C8F35700FDA1C5 /* Album.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = "<group>"; };
4648
0270482E19C8F43500FDA1C5 /* DetailsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailsViewController.swift; sourceTree = "<group>"; };
49+
0270483019C8F6D000FDA1C5 /* Track.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Track.swift; sourceTree = "<group>"; };
50+
0270483419C8F80000FDA1C5 /* TrackCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrackCell.swift; sourceTree = "<group>"; };
4751
/* End PBXFileReference section */
4852

4953
/* Begin PBXFrameworksBuildPhase section */
@@ -95,6 +99,8 @@
9599
0270482819C8E2E700FDA1C5 /* APIController.swift */,
96100
0270482C19C8F35700FDA1C5 /* Album.swift */,
97101
0270482E19C8F43500FDA1C5 /* DetailsViewController.swift */,
102+
0270483019C8F6D000FDA1C5 /* Track.swift */,
103+
0270483419C8F80000FDA1C5 /* TrackCell.swift */,
98104
);
99105
path = MusicPlayer;
100106
sourceTree = "<group>";
@@ -225,11 +231,13 @@
225231
isa = PBXSourcesBuildPhase;
226232
buildActionMask = 2147483647;
227233
files = (
234+
0270483519C8F80000FDA1C5 /* TrackCell.swift in Sources */,
228235
0270480B19C8E08B00FDA1C5 /* SearchResultsViewController.swift in Sources */,
229236
0270480919C8E08B00FDA1C5 /* AppDelegate.swift in Sources */,
230237
0270482919C8E2E700FDA1C5 /* APIController.swift in Sources */,
231238
0270482D19C8F35700FDA1C5 /* Album.swift in Sources */,
232239
0270482F19C8F43500FDA1C5 /* DetailsViewController.swift in Sources */,
240+
0270483119C8F6D000FDA1C5 /* Track.swift in Sources */,
233241
);
234242
runOnlyForDeploymentPostprocessing = 0;
235243
};

MusicPlayer/APIController.swift

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,27 @@ class APIController {
2020
self.delegate = delegate
2121
}
2222

23+
func get(path: String) {
24+
let url = NSURL(string: path)
25+
let session = NSURLSession.sharedSession()
26+
let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in
27+
println("Task completed")
28+
if(error != nil) {
29+
// If there is an error in the web request, print it to the console
30+
println(error.localizedDescription)
31+
}
32+
var err: NSError?
33+
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
34+
if(err != nil) {
35+
// If there is an error parsing JSON, print it to the console
36+
println("JSON Error \(err!.localizedDescription)")
37+
}
38+
let results: NSArray = jsonResult["results"] as NSArray
39+
self.delegate.didReceiveAPIResults(jsonResult) // THIS IS THE NEW LINE!!
40+
})
41+
task.resume()
42+
}
43+
2344
func searchItunesFor(searchTerm: String) {
2445

2546
// The iTunes API wants multiple terms separated by + symbols, so replace spaces with + signs
@@ -28,27 +49,12 @@ class APIController {
2849
// Now escape anything else that isn't URL-friendly
2950
if let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
3051
let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music&entity=album"
31-
let url: NSURL = NSURL(string: urlPath)
32-
let session = NSURLSession.sharedSession()
33-
let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in
34-
println("Task completed")
35-
if(error != nil) {
36-
// If there is an error in the web request, print it to the console
37-
println(error.localizedDescription)
38-
}
39-
var err: NSError?
40-
41-
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
42-
if(err != nil) {
43-
// If there is an error parsing JSON, print it to the console
44-
println("JSON Error \(err!.localizedDescription)")
45-
}
46-
let results: NSArray = jsonResult["results"] as NSArray
47-
self.delegate.didReceiveAPIResults(jsonResult)
48-
})
49-
50-
task.resume()
52+
get(urlPath)
5153
}
5254
}
5355

56+
func lookupAlbum(collectionId: Int) {
57+
get("https://itunes.apple.com/lookup?id=\(collectionId)&entity=song")
58+
}
59+
5460
}

MusicPlayer/Album.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,16 @@ class Album {
1515
var largeImageURL: String
1616
var itemURL: String
1717
var artistURL: String
18+
var collectionId: Int
1819

19-
init(name: String, price: String, thumbnailImageURL: String, largeImageURL: String, itemURL: String, artistURL: String) {
20+
init(name: String, price: String, thumbnailImageURL: String, largeImageURL: String, itemURL: String, artistURL: String, collectionId: Int) {
2021
self.title = name
2122
self.price = price
2223
self.thumbnailImageURL = thumbnailImageURL
2324
self.largeImageURL = largeImageURL
2425
self.itemURL = itemURL
2526
self.artistURL = artistURL
27+
self.collectionId = collectionId
2628
}
2729

2830
class func albumsWithJSON(allResults: NSArray) -> [Album] {
@@ -64,8 +66,11 @@ class Album {
6466
itemURL = result["trackViewUrl"] as? String
6567
}
6668

67-
var newAlbum = Album(name: name!, price: price!, thumbnailImageURL: thumbnailURL, largeImageURL: imageURL, itemURL: itemURL!, artistURL: artistURL)
69+
var collectionId = result["collectionId"] as? Int
70+
71+
var newAlbum = Album(name: name!, price: price!, thumbnailImageURL: thumbnailURL, largeImageURL: imageURL, itemURL: itemURL!, artistURL: artistURL, collectionId: collectionId!)
6872
albums.append(newAlbum)
73+
6974
}
7075
}
7176
return albums

MusicPlayer/Base.lproj/Main.storyboard

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,24 +83,72 @@
8383
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kNM-6v-NNF">
8484
<rect key="frame" x="16" y="87" width="100" height="100"/>
8585
</imageView>
86+
<tableView clipsSubviews="YES" contentMode="scaleToFill" ambiguous="YES" misplaced="YES" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="cNg-v9-bFx">
87+
<rect key="frame" x="0.0" y="195" width="600" height="405"/>
88+
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
89+
<prototypes>
90+
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="TrackCell" id="Pev-dG-cIl" customClass="TrackCell" customModule="MusicPlayer" customModuleProvider="target">
91+
<autoresizingMask key="autoresizingMask"/>
92+
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Pev-dG-cIl" id="2eV-zK-AfF">
93+
<autoresizingMask key="autoresizingMask"/>
94+
<subviews>
95+
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" misplaced="YES" text="▶️" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="G27-wX-fuE">
96+
<rect key="frame" x="13" y="11" width="23" height="23"/>
97+
<constraints>
98+
<constraint firstAttribute="height" constant="23" id="70W-c5-Xqm"/>
99+
<constraint firstAttribute="width" constant="23" id="Y0A-A3-D4O"/>
100+
</constraints>
101+
<fontDescription key="fontDescription" type="system" pointSize="17"/>
102+
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
103+
<nil key="highlightedColor"/>
104+
</label>
105+
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" misplaced="YES" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ryd-dB-0fM">
106+
<rect key="frame" x="44" y="12" width="548" height="23"/>
107+
<fontDescription key="fontDescription" type="system" pointSize="17"/>
108+
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
109+
<nil key="highlightedColor"/>
110+
</label>
111+
</subviews>
112+
<constraints>
113+
<constraint firstItem="G27-wX-fuE" firstAttribute="leading" secondItem="2eV-zK-AfF" secondAttribute="leadingMargin" constant="5" id="02m-zc-7iD"/>
114+
<constraint firstItem="Ryd-dB-0fM" firstAttribute="leading" secondItem="G27-wX-fuE" secondAttribute="trailing" constant="8" id="N3l-NE-wKz"/>
115+
<constraint firstItem="Ryd-dB-0fM" firstAttribute="trailing" secondItem="2eV-zK-AfF" secondAttribute="trailingMargin" id="nAe-es-ekH"/>
116+
</constraints>
117+
</tableViewCellContentView>
118+
<connections>
119+
<outlet property="playIcon" destination="G27-wX-fuE" id="ibb-NM-h8W"/>
120+
<outlet property="titleLabel" destination="Ryd-dB-0fM" id="qX4-bm-UFf"/>
121+
</connections>
122+
</tableViewCell>
123+
</prototypes>
124+
<connections>
125+
<outlet property="dataSource" destination="RmI-eG-YqA" id="cte-rB-pfH"/>
126+
<outlet property="delegate" destination="RmI-eG-YqA" id="O91-w8-BgW"/>
127+
</connections>
128+
</tableView>
86129
</subviews>
87130
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
88131
<constraints>
89132
<constraint firstItem="kNM-6v-NNF" firstAttribute="top" secondItem="jIA-3D-enV" secondAttribute="bottom" constant="23" id="1tc-ry-Twa"/>
90133
<constraint firstItem="tgX-ID-J9t" firstAttribute="top" secondItem="jIA-3D-enV" secondAttribute="bottom" constant="23" id="GsN-uA-1Oz"/>
134+
<constraint firstItem="cNg-v9-bFx" firstAttribute="top" secondItem="kNM-6v-NNF" secondAttribute="bottom" constant="8" id="JZr-Jq-WMT"/>
91135
<constraint firstItem="kNM-6v-NNF" firstAttribute="leading" secondItem="tx9-2C-w8M" secondAttribute="leadingMargin" id="Kov-2n-EHq"/>
136+
<constraint firstItem="cNg-v9-bFx" firstAttribute="leading" secondItem="tx9-2C-w8M" secondAttribute="leadingMargin" constant="-16" id="UeL-J8-8XL"/>
137+
<constraint firstItem="ZRL-jn-HDo" firstAttribute="top" secondItem="cNg-v9-bFx" secondAttribute="bottom" id="avb-rq-wX2"/>
92138
<constraint firstItem="tgX-ID-J9t" firstAttribute="leading" secondItem="kNM-6v-NNF" secondAttribute="trailing" constant="15" id="pdf-qR-eTd"/>
93139
<constraint firstItem="tgX-ID-J9t" firstAttribute="trailing" secondItem="tx9-2C-w8M" secondAttribute="trailingMargin" id="sZi-kR-uEl"/>
140+
<constraint firstAttribute="trailingMargin" secondItem="cNg-v9-bFx" secondAttribute="trailing" constant="-16" id="zZv-IE-5Ig"/>
94141
</constraints>
95142
</view>
96143
<connections>
97144
<outlet property="albumCover" destination="kNM-6v-NNF" id="Gd3-ly-zMD"/>
98145
<outlet property="titleLabel" destination="tgX-ID-J9t" id="2Ji-Nc-kgE"/>
146+
<outlet property="tracksTableView" destination="cNg-v9-bFx" id="YO7-Fn-1sm"/>
99147
</connections>
100148
</viewController>
101149
<placeholder placeholderIdentifier="IBFirstResponder" id="pYL-YU-PSv" userLabel="First Responder" sceneMemberID="firstResponder"/>
102150
</objects>
103-
<point key="canvasLocation" x="1233" y="-557"/>
151+
<point key="canvasLocation" x="1233" y="-558"/>
104152
</scene>
105153
<!--Navigation Controller-->
106154
<scene sceneID="YCI-QZ-c2A">

MusicPlayer/DetailsViewController.swift

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@
77
//
88

99
import UIKit
10+
import MediaPlayer
1011

11-
class DetailsViewController: UIViewController {
12+
class DetailsViewController: UIViewController, APIControllerProtocol, UITableViewDelegate, UITableViewDataSource {
1213

1314
var album: Album?
15+
var tracks = [Track]()
1416

1517
@IBOutlet weak var titleLabel: UILabel!
1618
@IBOutlet weak var albumCover: UIImageView!
19+
@IBOutlet weak var tracksTableView: UITableView!
20+
lazy var api : APIController = APIController(delegate: self)
21+
var mediaPlayer: MPMoviePlayerController = MPMoviePlayerController()
1722

1823
required init(coder aDecoder: NSCoder) {
1924
super.init(coder: aDecoder)
@@ -23,5 +28,51 @@ class DetailsViewController: UIViewController {
2328
super.viewDidLoad()
2429
titleLabel.text = self.album?.title
2530
albumCover.image = UIImage(data: NSData(contentsOfURL: NSURL(string: self.album!.largeImageURL)))
31+
32+
if self.album != nil {
33+
api.lookupAlbum(self.album!.collectionId)
34+
}
2635
}
36+
37+
// MARK: UITableViewDataSource
38+
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
39+
return tracks.count
40+
}
41+
42+
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
43+
let cell = tableView.dequeueReusableCellWithIdentifier("TrackCell") as TrackCell
44+
let track = tracks[indexPath.row]
45+
cell.titleLabel.text = track.title
46+
cell.playIcon.text = "▶️"
47+
48+
return cell
49+
}
50+
51+
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
52+
var track = tracks[indexPath.row]
53+
mediaPlayer.stop()
54+
mediaPlayer.contentURL = NSURL(string: track.previewUrl)
55+
mediaPlayer.play()
56+
if let cell = tableView.cellForRowAtIndexPath(indexPath) as? TrackCell {
57+
cell.playIcon.text = "◾️"
58+
}
59+
}
60+
61+
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
62+
cell.layer.transform = CATransform3DMakeScale(0.1,0.1,1)
63+
UIView.animateWithDuration(0.25, animations: {
64+
cell.layer.transform = CATransform3DMakeScale(1,1,1)
65+
})
66+
}
67+
68+
// MARK: APIControllerProtocol
69+
func didReceiveAPIResults(results: NSDictionary) {
70+
var resultsArr: NSArray = results["results"] as NSArray
71+
dispatch_async(dispatch_get_main_queue(), {
72+
self.tracks = Track.tracksWithJSON(resultsArr)
73+
self.tracksTableView.reloadData()
74+
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
75+
})
76+
}
77+
2778
}

MusicPlayer/SearchResultsViewController.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa
2929
}
3030

3131

32+
// MARK: UITableViewDataSource
33+
3234
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
3335
return albums.count
3436
}
@@ -89,6 +91,14 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa
8991
return cell
9092
}
9193

94+
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
95+
cell.layer.transform = CATransform3DMakeScale(0.1,0.1,1)
96+
UIView.animateWithDuration(0.25, animations: {
97+
cell.layer.transform = CATransform3DMakeScale(1,1,1)
98+
})
99+
}
100+
101+
92102
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
93103
var detailsViewController: DetailsViewController = segue.destinationViewController as DetailsViewController
94104
var albumIndex = appsTableView!.indexPathForSelectedRow()!.row

0 commit comments

Comments
 (0)