Merge lp:~rockstar/ubuntuone-ios-music/replace-streaming-player into lp:ubuntuone-ios-music

Proposed by Paul Hummer
Status: Merged
Approved by: Paul Hummer
Approved revision: 290
Merged at revision: 248
Proposed branch: lp:~rockstar/ubuntuone-ios-music/replace-streaming-player
Merge into: lp:ubuntuone-ios-music
Diff against target: 1495 lines (+773/-133)
19 files modified
Music/Categories/NSString+UbuntuOne.h (+13/-0)
Music/Categories/NSString+UbuntuOne.m (+24/-0)
Music/Categories/UIImageView+UbuntuOne.h (+13/-0)
Music/Categories/UIImageView+UbuntuOne.m (+53/-0)
Music/Models/Song.h (+1/-1)
Music/Storyboard_iPhone.storyboard (+121/-19)
Music/UOMusic.xcdatamodeld/UOMusic.xcdatamodel/contents (+2/-2)
Music/Utilities/UOPlayer.h (+48/-0)
Music/Utilities/UOPlayer.m (+286/-0)
Music/View Controllers/AlbumViewController.m (+9/-15)
Music/View Controllers/ArtistViewController.m (+4/-4)
Music/View Controllers/PlayerViewController.h (+17/-0)
Music/View Controllers/PlayerViewController.m (+105/-30)
Music/View Controllers/SongsViewController.m (+7/-14)
Music/View Controllers/UOIndexedViewController.m (+4/-4)
Music/Views/Table Cells/SongCell.m (+2/-3)
U1Music.xcodeproj/project.pbxproj (+26/-0)
utilities/StreamingPlayer.m (+1/-1)
xibs/SongViewController.xib (+37/-40)
To merge this branch: bzr merge lp:~rockstar/ubuntuone-ios-music/replace-streaming-player
Reviewer Review Type Date Requested Status
Mike McCracken (community) Approve
Review via email: mp+147017@code.launchpad.net

Commit message

Replace StreamingPlayer with UOPlayer

Description of the change

This branch adds the polish to the Player View Controller. Most of the UI is copied directly from the older app. I just learned while working on this that you can tap the album art and get extended controls (scrubbing, shuffle, and repeat). Here's some screenshots.

http://ubuntuone.com/1Qba6PUSOgHgk6bNp29ktt

http://ubuntuone.com/7E2Eq9pSTdCYgmC8co7mY0

I also implemented a new player. The one problem I still have is that I can't quite get the app to react to remote control events. I'll look into that once I have the polish applied to the other views.

To post a comment you must log in.
Revision history for this message
Mike McCracken (mikemc) wrote :

Needs-fixing because of the currentIndex issues in UOPlayer, otherwise please treat my naming comments as friendly suggestions, I won't complain if you decide you don't like them.

General comment: this really could have been split into a few smaller
branches to ease reviewing. For example, these all seem like
independent changes:

- adding the CGImage reflection
- updating duration to int64
- the secondsToClock change
- adding UOPlayer
- maybe also the XIB changes, if only to de-clutter the other branches

1. NSNumber+UbuntuOne:

Why is secondsToClock a category on NSNumber? NSNumber isn't
involved. Why not just make it a function?

Or if you really want a category, maybe a category on NSString
like "+clockStringFromSeconds:"...

2. UIImage+UbuntuOne: (~MINOR)

reflectedImage:(1) toImageView:(2) wasn't clear from the name what it
does. For one, both args are image views but the name makes it sound
like they're different. Also I think it needs a verb, like
"setImageView:(2) toReflectionOfImageView:(1)" or something.

Just my 2c, it's up to you.

3. UOPlayer.m:

In -next, I think that the two tests of (currentIndex +1 >
[... count]) might be off by one - if there are ten tracks and I'm on
track #10 (index 9), this will evaluate (10 > 10) = false and set
currentIndex to 10, which will be an invalid index into songs.

In prev, if currentIndex is 0, won't we get an invalid index there
too? I'm not 100% sure what unsigneds do when you do 0-1, but it's
probably not a good idea anyway. What should it do in that case?
Actually, prev looks unfinished, right? Should it always set the state
to stop?

addSongs:atIndex: was a confusing name, and it made it hard to understand
prepareForSegue in the view controller, because I was wondering what
happened to the indexing if there were already songs in the player
when you called it from prepareForSegue...
But - we're not *adding* songs, we're *replacing* the songs array
completely. I think the method would be much clearer if it was named
something like "setSongs:withStartingIndex:".

(MINOR): IMO, enums are more readable with underscores: e.g. REPEAT_OFF

review: Needs Fixing
Revision history for this message
Paul Hummer (rockstar) wrote :

Yeah, I noticed the problems with currentIndex yesterday, but there's also another problem where we're not fetching enough of the songs from the U1AutoDownloadsManager (that needs to be replaced because it's both not smart enough and too smart...)

283. By Paul Hummer

Move NSNumber+UbuntuOne to NSString+UbuntuOne

284. By Paul Hummer

Move [NSNumber secondsToClock] to [NSString secondsToClock]

285. By Paul Hummer

Rename secondsToClock to clockStringFromSeconds

286. By Paul Hummer

Move UIImage+UbuntuOne to UIImageView+UbuntuOne

287. By Paul Hummer

Change the reflection method to be a UIImageView category method

288. By Paul Hummer

Fix downloadManager bug and the off by one errors in next/prev

289. By Paul Hummer

Reset album art image view

290. By Paul Hummer

Merge in trunk, resolve conflicts

Revision history for this message
Paul Hummer (rockstar) wrote :

Changes have now been made. I found a few other bugs while I was testing this, which I fixed here, because that was most appropriate.

Revision history for this message
Mike McCracken (mikemc) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'Music/Categories'
2=== added file 'Music/Categories/NSString+UbuntuOne.h'
3--- Music/Categories/NSString+UbuntuOne.h 1970-01-01 00:00:00 +0000
4+++ Music/Categories/NSString+UbuntuOne.h 2013-02-09 04:48:21 +0000
5@@ -0,0 +1,13 @@
6+//
7+// NSNumber+UbuntuOne.h
8+// U1Music
9+//
10+// Created by Paul Hummer on 2/6/13.
11+// Copyright (c) 2013 Canonical. All rights reserved.
12+//
13+
14+#import <Foundation/Foundation.h>
15+
16+@interface NSString (UbuntuOne)
17++ (NSString *)clockStringFromSeconds:(int)seconds;
18+@end
19
20=== added file 'Music/Categories/NSString+UbuntuOne.m'
21--- Music/Categories/NSString+UbuntuOne.m 1970-01-01 00:00:00 +0000
22+++ Music/Categories/NSString+UbuntuOne.m 2013-02-09 04:48:21 +0000
23@@ -0,0 +1,24 @@
24+//
25+// NSNumber+UbuntuOne.m
26+// U1Music
27+//
28+// Created by Paul Hummer on 2/6/13.
29+// Copyright (c) 2013 Canonical. All rights reserved.
30+//
31+
32+#import "NSString+UbuntuOne.h"
33+
34+@implementation NSString (UbuntuOne)
35+
36++ (NSString *)clockStringFromSeconds:(int)_seconds {
37+ NSUInteger hours = _seconds / (60 * 60);
38+ NSUInteger minutes = (_seconds / 60) % 60;
39+ NSUInteger seconds = _seconds % 60;
40+ if (hours > 0) {
41+ return [NSString stringWithFormat:@"%d:%02d:%02d", hours, minutes, seconds];
42+ } else {
43+ return [NSString stringWithFormat:@"%d:%02d", minutes, seconds];
44+ }
45+}
46+
47+@end
48
49=== added file 'Music/Categories/UIImageView+UbuntuOne.h'
50--- Music/Categories/UIImageView+UbuntuOne.h 1970-01-01 00:00:00 +0000
51+++ Music/Categories/UIImageView+UbuntuOne.h 2013-02-09 04:48:21 +0000
52@@ -0,0 +1,13 @@
53+//
54+// UIImage+UbuntuOne.h
55+// U1Music
56+//
57+// Created by Paul Hummer on 2/6/13.
58+// Copyright (c) 2013 Canonical. All rights reserved.
59+//
60+
61+#import <UIKit/UIKit.h>
62+
63+@interface UIImageView (UbuntuOne)
64+- (void)reflectOn:(UIImageView *)toImageView;
65+@end
66
67=== added file 'Music/Categories/UIImageView+UbuntuOne.m'
68--- Music/Categories/UIImageView+UbuntuOne.m 1970-01-01 00:00:00 +0000
69+++ Music/Categories/UIImageView+UbuntuOne.m 2013-02-09 04:48:21 +0000
70@@ -0,0 +1,53 @@
71+//
72+// UIImage+UbuntuOne.m
73+// U1Music
74+//
75+// Created by Paul Hummer on 2/6/13.
76+// Copyright (c) 2013 Canonical. All rights reserved.
77+//
78+
79+#import "UIImageView+UbuntuOne.h"
80+
81+@implementation UIImageView (UbuntuOne)
82+
83+- (void)reflectOn:(UIImageView *)toImageView {
84+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
85+ CGContextRef context = CGBitmapContextCreate(NULL, self.bounds.size.width, toImageView.bounds.size.height,
86+ 8, 0, colorSpace, (kCGBitmapByteOrder32Little|kCGImageAlphaPremultipliedFirst));
87+ CGColorSpaceRelease(colorSpace);
88+
89+ colorSpace = CGColorSpaceCreateDeviceGray();
90+ CGContextRef gradientBitmapContext = CGBitmapContextCreate(NULL, 1, toImageView.bounds.size.height,
91+ 8, 0, colorSpace, kCGImageAlphaNone);
92+ /* Start and end grayscale values */
93+ CGFloat colors[] = {0.0, 1.0, 1.0, 1.0};
94+
95+ CGGradientRef grayScaleGradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2);
96+ CGColorSpaceRelease(colorSpace);
97+ CGPoint gradientStartPoint = CGPointZero;
98+ CGPoint gradientEndPoint = CGPointMake(0, toImageView.bounds.size.height);
99+
100+ CGContextDrawLinearGradient(gradientBitmapContext, grayScaleGradient, gradientStartPoint,
101+ gradientEndPoint, kCGGradientDrawsAfterEndLocation);
102+ CGGradientRelease(grayScaleGradient);
103+
104+ CGImageRef mask = CGBitmapContextCreateImage(gradientBitmapContext);
105+ CGContextRelease(gradientBitmapContext);
106+
107+ CGContextClipToMask(context, CGRectMake(0.f, 0.f, self.bounds.size.width, toImageView.bounds.size.height), mask);
108+ CGImageRelease(mask);
109+
110+ CGContextTranslateCTM(context, 0.f, toImageView.bounds.size.height);
111+ CGContextScaleCTM(context, 1.0, -1.0);
112+ CGContextDrawImage(context, self.bounds, self.image.CGImage);
113+
114+ CGImageRef reflectionImageRef = CGBitmapContextCreateImage(context);
115+ CGContextRelease(context);
116+
117+ UIImage *reflectionImage = [UIImage imageWithCGImage:reflectionImageRef];
118+ CGImageRelease(reflectionImageRef);
119+
120+ [toImageView setImage:reflectionImage];
121+}
122+
123+@end
124
125=== modified file 'Music/Models/Song.h'
126--- Music/Models/Song.h 2013-01-27 21:34:28 +0000
127+++ Music/Models/Song.h 2013-02-09 04:48:21 +0000
128@@ -20,7 +20,7 @@
129 @property (nonatomic, retain) NSString *title;
130 @property (nonatomic) int32_t bitRate;
131 @property (nonatomic, retain) NSString *songId;
132-@property (nonatomic) int32_t duration;
133+@property (nonatomic) int64_t duration;
134 @property (nonatomic, retain) NSString *discNumber;
135 @property (nonatomic, retain) NSString *streamUrl;
136 @property (nonatomic, retain) NSString *contentType;
137
138=== modified file 'Music/Storyboard_iPhone.storyboard'
139--- Music/Storyboard_iPhone.storyboard 2013-01-28 22:16:30 +0000
140+++ Music/Storyboard_iPhone.storyboard 2013-02-09 04:48:21 +0000
141@@ -299,7 +299,7 @@
142 <rect key="frame" x="0.0" y="20" width="320" height="460"/>
143 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
144 <subviews>
145- <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" barStyle="blackTranslucent" id="uGB-Cu-Aav">
146+ <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" barStyle="blackOpaque" id="uGB-Cu-Aav">
147 <rect key="frame" x="0.0" y="416" width="320" height="44"/>
148 <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
149 <items>
150@@ -329,8 +329,8 @@
151 <barButtonItem style="plain" systemItem="flexibleSpace" id="MBV-c6-BMY"/>
152 </items>
153 </toolbar>
154- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="Yam-lV-Vc9">
155- <rect key="frame" x="0.0" y="58" width="320" height="321"/>
156+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" id="Yam-lV-Vc9">
157+ <rect key="frame" x="10" y="54" width="300" height="300"/>
158 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
159 <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
160 <state key="normal" backgroundImage="default-album-art-640.png">
161@@ -339,10 +339,98 @@
162 </state>
163 <state key="disabled" backgroundImage="default-album-art-640.png"/>
164 <state key="selected" backgroundImage="default-album-art-640.png"/>
165- <state key="highlighted" backgroundImage="default-album-art-640.png">
166- <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
167- </state>
168+ <state key="highlighted" backgroundImage="default-album-art-640.png"/>
169+ <connections>
170+ <action selector="toggleExtendedControls:" destination="hRX-A4-gMJ" eventType="touchUpInside" id="0nY-gN-scF"/>
171+ </connections>
172 </button>
173+ <view hidden="YES" contentMode="scaleToFill" id="S10-hS-OX1">
174+ <rect key="frame" x="0.0" y="44" width="320" height="100"/>
175+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
176+ <subviews>
177+ <imageView userInteractionEnabled="NO" alpha="0.79999999999999993" contentMode="scaleToFill" image="player_overlay_bg.png" id="2dO-51-f8w">
178+ <rect key="frame" x="0.0" y="0.0" width="320" height="100"/>
179+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
180+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
181+ </imageView>
182+ <slider opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" id="AzX-yt-lI2">
183+ <rect key="frame" x="58" y="28" width="204" height="23"/>
184+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
185+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
186+ <accessibility key="accessibilityConfiguration">
187+ <accessibilityTraits key="traits" none="YES" notEnabled="YES"/>
188+ <bool key="isElement" value="NO"/>
189+ </accessibility>
190+ </slider>
191+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="mWB-Z0-neD">
192+ <rect key="frame" x="14" y="47" width="44" height="44"/>
193+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
194+ <fontDescription key="fontDescription" name="Helvetica-Bold" family="Helvetica" pointSize="15"/>
195+ <state key="normal" image="03-loopback.png">
196+ <color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
197+ <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
198+ </state>
199+ <state key="highlighted">
200+ <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
201+ </state>
202+ <connections>
203+ <action selector="changeRepeat:" destination="hRX-A4-gMJ" eventType="touchUpInside" id="FKm-JK-m5u"/>
204+ </connections>
205+ </button>
206+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="VtE-rw-Yf4">
207+ <rect key="frame" x="264" y="48" width="44" height="44"/>
208+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
209+ <fontDescription key="fontDescription" name="Helvetica-Bold" family="Helvetica" pointSize="15"/>
210+ <state key="normal" image="05-shuffle.png">
211+ <color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
212+ <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
213+ </state>
214+ <state key="highlighted">
215+ <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
216+ </state>
217+ <connections>
218+ <action selector="changeShuffle:" destination="hRX-A4-gMJ" eventType="touchUpInside" id="Ve2-P1-mUH"/>
219+ </connections>
220+ </button>
221+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="0:00" textAlignment="right" lineBreakMode="tailTruncation" minimumFontSize="10" id="pNU-Jr-yiV">
222+ <rect key="frame" x="12" y="31" width="42" height="15"/>
223+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
224+ <fontDescription key="fontDescription" name="Helvetica-Bold" family="Helvetica" pointSize="14"/>
225+ <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
226+ <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
227+ <color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
228+ </label>
229+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="10:00" lineBreakMode="tailTruncation" minimumFontSize="10" id="fsV-6P-1Kb">
230+ <rect key="frame" x="266" y="31" width="42" height="15"/>
231+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
232+ <fontDescription key="fontDescription" name="Helvetica-Bold" family="Helvetica" pointSize="14"/>
233+ <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
234+ <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
235+ <color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
236+ </label>
237+ <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="3 of 100" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" id="KsY-jo-7df">
238+ <rect key="frame" x="12" y="5" width="296" height="19"/>
239+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
240+ <fontDescription key="fontDescription" name="Helvetica-Bold" family="Helvetica" pointSize="14"/>
241+ <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
242+ <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
243+ <color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
244+ </label>
245+ </subviews>
246+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
247+ <attributedString key="userComments">
248+ <fragment content="XXX: Return to normal size when we figure out the loop/shuffle buttons">
249+ <attributes>
250+ <font key="NSFont" size="12" name="Helvetica"/>
251+ <paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
252+ </attributes>
253+ </fragment>
254+ </attributedString>
255+ </view>
256+ <imageView userInteractionEnabled="NO" contentMode="scaleToFill" id="ljH-X3-s0I">
257+ <rect key="frame" x="10" y="359" width="300" height="57"/>
258+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
259+ </imageView>
260 <navigationBar contentMode="scaleToFill" barStyle="blackTranslucent" id="oeU-qV-gKe">
261 <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
262 <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
263@@ -387,11 +475,19 @@
264 <outlet property="albumart" destination="Yam-lV-Vc9" id="5e5-A4-rMc"/>
265 <outlet property="artistLabel" destination="h2R-82-j69" id="Juf-cx-6ta"/>
266 <outlet property="controlBar" destination="uGB-Cu-Aav" id="Wgb-Ct-TjW"/>
267+ <outlet property="elapsedTime" destination="pNU-Jr-yiV" id="D3O-1N-k6n"/>
268+ <outlet property="extendedControlView" destination="S10-hS-OX1" id="7bJ-7h-Oce"/>
269 <outlet property="nextButton" destination="QEO-UP-PKx" id="ZgA-sN-VU1"/>
270 <outlet property="pauseButton" destination="DQV-3Q-HbM" id="nKw-2H-EHB"/>
271 <outlet property="playButton" destination="1LC-YT-al7" id="2PE-Uy-AbM"/>
272+ <outlet property="playlistInfo" destination="KsY-jo-7df" id="hc5-Rd-tM8"/>
273 <outlet property="previousButton" destination="1xR-vh-5t6" id="ekr-RG-Qqb"/>
274+ <outlet property="progressView" destination="AzX-yt-lI2" id="vdA-4u-TTx"/>
275+ <outlet property="reflectionImage" destination="ljH-X3-s0I" id="8fj-Fq-yMJ"/>
276+ <outlet property="repeatButton" destination="mWB-Z0-neD" id="gau-aR-t4J"/>
277+ <outlet property="shuffleButton" destination="VtE-rw-Yf4" id="cWi-Rz-4Cf"/>
278 <outlet property="titleLabel" destination="eua-we-ECS" id="XMu-px-khb"/>
279+ <outlet property="totalTime" destination="fsV-6P-1Kb" id="Tmf-XN-8VS"/>
280 </connections>
281 </viewController>
282 <placeholder placeholderIdentifier="IBFirstResponder" id="ase-Pp-0S0" userLabel="First Responder" sceneMemberID="firstResponder"/>
283@@ -518,6 +614,7 @@
284 <outlet property="clock" destination="vws-t4-lyH" id="Fb3-aG-7Ym"/>
285 <outlet property="title" destination="cHc-6o-Le1" id="XJD-HL-AWU"/>
286 <outlet property="track" destination="URM-e4-2yc" id="CNs-EV-tVd"/>
287+ <segue destination="hRX-A4-gMJ" kind="modal" id="ebj-wD-yft"/>
288 </connections>
289 </tableViewCell>
290 </prototypes>
291@@ -863,6 +960,8 @@
292 </scene>
293 </scenes>
294 <resources>
295+ <image name="03-loopback.png" width="32" height="22"/>
296+ <image name="05-shuffle.png" width="28" height="20"/>
297 <image name="albums.png" width="30" height="30"/>
298 <image name="artists.png" width="30" height="30"/>
299 <image name="default-album-art-120.png" width="60" height="60"/>
300@@ -870,6 +969,7 @@
301 <image name="download-grey.png" width="28" height="28"/>
302 <image name="download.png" width="28" height="28"/>
303 <image name="grabber.png" width="22" height="44"/>
304+ <image name="player_overlay_bg.png" width="320" height="100"/>
305 <image name="playlists.png" width="30" height="30"/>
306 <image name="settings.png" width="30" height="30"/>
307 <image name="songs.png" width="30" height="30"/>
308@@ -894,12 +994,13 @@
309 <class className="ArtistCell" superclassName="UITableViewCell">
310 <source key="sourceIdentifier" type="project" relativePath="./Classes/ArtistCell.h"/>
311 </class>
312- <class className="ArtistViewController" superclassName="SubsonicTableViewController">
313+ <class className="ArtistViewController" superclassName="UIViewController">
314 <source key="sourceIdentifier" type="project" relativePath="./Classes/ArtistViewController.h"/>
315 <relationships>
316 <relationship kind="outlet" name="albumArt" candidateClass="UIImageView"/>
317 <relationship kind="outlet" name="artistDescription" candidateClass="UILabel"/>
318 <relationship kind="outlet" name="artistName" candidateClass="UILabel"/>
319+ <relationship kind="outlet" name="nowPlayingButton" candidateClass="UIBarButtonItem"/>
320 <relationship kind="outlet" name="tableView" candidateClass="UITableView"/>
321 </relationships>
322 </class>
323@@ -917,19 +1018,30 @@
324 <class className="PlayerViewController" superclassName="UIViewController">
325 <source key="sourceIdentifier" type="project" relativePath="./Classes/PlayerViewController.h"/>
326 <relationships>
327+ <relationship kind="action" name="changeRepeat:"/>
328+ <relationship kind="action" name="changeShuffle:"/>
329 <relationship kind="action" name="hide:"/>
330 <relationship kind="action" name="next:"/>
331 <relationship kind="action" name="pause:"/>
332 <relationship kind="action" name="play:"/>
333 <relationship kind="action" name="previous:"/>
334+ <relationship kind="action" name="toggleExtendedControls:"/>
335 <relationship kind="outlet" name="albumart" candidateClass="UIButton"/>
336 <relationship kind="outlet" name="artistLabel" candidateClass="UILabel"/>
337 <relationship kind="outlet" name="controlBar" candidateClass="UIToolbar"/>
338+ <relationship kind="outlet" name="elapsedTime" candidateClass="UILabel"/>
339+ <relationship kind="outlet" name="extendedControlView" candidateClass="UIView"/>
340 <relationship kind="outlet" name="nextButton" candidateClass="UIBarButtonItem"/>
341 <relationship kind="outlet" name="pauseButton" candidateClass="UIBarButtonItem"/>
342 <relationship kind="outlet" name="playButton" candidateClass="UIBarButtonItem"/>
343+ <relationship kind="outlet" name="playlistInfo" candidateClass="UILabel"/>
344 <relationship kind="outlet" name="previousButton" candidateClass="UIBarButtonItem"/>
345+ <relationship kind="outlet" name="progressView" candidateClass="UISlider"/>
346+ <relationship kind="outlet" name="reflectionImage" candidateClass="UIImageView"/>
347+ <relationship kind="outlet" name="repeatButton" candidateClass="UIButton"/>
348+ <relationship kind="outlet" name="shuffleButton" candidateClass="UIButton"/>
349 <relationship kind="outlet" name="titleLabel" candidateClass="UILabel"/>
350+ <relationship kind="outlet" name="totalTime" candidateClass="UILabel"/>
351 </relationships>
352 </class>
353 <class className="PlaylistCell" superclassName="UITableViewCell">
354@@ -938,9 +1050,6 @@
355 <class className="PlaylistsViewController" superclassName="UOIndexedViewController">
356 <source key="sourceIdentifier" type="project" relativePath="./Classes/PlaylistsViewController.h"/>
357 </class>
358- <class className="PullRefreshTableViewController" superclassName="UITableViewController">
359- <source key="sourceIdentifier" type="project" relativePath="./Classes/PullRefreshTableViewController.h"/>
360- </class>
361 <class className="SettingsAuthenticationViewController" superclassName="UIViewController">
362 <source key="sourceIdentifier" type="project" relativePath="./Classes/SettingsAuthenticationViewController.h"/>
363 <relationships>
364@@ -951,7 +1060,7 @@
365 <relationship kind="outlet" name="usernameField" candidateClass="UITextField"/>
366 </relationships>
367 </class>
368- <class className="SettingsViewController" superclassName="UIViewController">
369+ <class className="SettingsViewController" superclassName="UITableViewController">
370 <source key="sourceIdentifier" type="project" relativePath="./Classes/SettingsViewController.h"/>
371 <relationships>
372 <relationship kind="action" name="deleteCaches:"/>
373@@ -977,13 +1086,6 @@
374 <class className="SongsViewController" superclassName="UOIndexedViewController">
375 <source key="sourceIdentifier" type="project" relativePath="./Classes/SongsViewController.h"/>
376 </class>
377- <class className="SubsonicTableViewController" superclassName="PullRefreshTableViewController">
378- <source key="sourceIdentifier" type="project" relativePath="./Classes/SubsonicTableViewController.h"/>
379- <relationships>
380- <relationship kind="action" name="nowPlayingAction:"/>
381- <relationship kind="action" name="reload:"/>
382- </relationships>
383- </class>
384 <class className="UOIndexedViewController" superclassName="UITableViewController">
385 <source key="sourceIdentifier" type="project" relativePath="./Classes/UOIndexedViewController.h"/>
386 <relationships>
387@@ -998,6 +1100,6 @@
388 </simulatedMetricsContainer>
389 <inferredMetricsTieBreakers>
390 <segue reference="jMd-4K-zoU"/>
391- <segue reference="kr6-1e-khR"/>
392+ <segue reference="e8X-Xp-0ra"/>
393 </inferredMetricsTieBreakers>
394 </document>
395\ No newline at end of file
396
397=== modified file 'Music/UOMusic.xcdatamodeld/UOMusic.xcdatamodel/contents'
398--- Music/UOMusic.xcdatamodeld/UOMusic.xcdatamodel/contents 2013-01-24 19:08:51 +0000
399+++ Music/UOMusic.xcdatamodeld/UOMusic.xcdatamodel/contents 2013-02-09 04:48:21 +0000
400@@ -1,5 +1,5 @@
401 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
402-<model name="" userDefinedModelVersionIdentifier="UOMusic0" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="12C60" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
403+<model name="" userDefinedModelVersionIdentifier="UOMusic0" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="2057" systemVersion="12C60" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
404 <entity name="Album" representedClassName="Album" syncable="YES">
405 <attribute name="albumId" attributeType="String" indexed="YES" syncable="YES"/>
406 <attribute name="artHash" optional="YES" attributeType="String" syncable="YES"/>
407@@ -36,7 +36,7 @@
408 <attribute name="contentType" optional="YES" attributeType="String" syncable="YES"/>
409 <attribute name="dearticlizedTitle" attributeType="String" syncable="YES"/>
410 <attribute name="discNumber" optional="YES" attributeType="String" syncable="YES"/>
411- <attribute name="duration" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
412+ <attribute name="duration" optional="YES" attributeType="Integer 64" defaultValueString="0" syncable="YES"/>
413 <attribute name="genre" optional="YES" attributeType="String" syncable="YES"/>
414 <attribute name="index" optional="YES" transient="YES" attributeType="String" syncable="YES"/>
415 <attribute name="path" attributeType="String" syncable="YES"/>
416
417=== added file 'Music/Utilities/UOPlayer.h'
418--- Music/Utilities/UOPlayer.h 1970-01-01 00:00:00 +0000
419+++ Music/Utilities/UOPlayer.h 2013-02-09 04:48:21 +0000
420@@ -0,0 +1,48 @@
421+//
422+// UOPlayer.h
423+// U1Music
424+//
425+// Created by Paul Hummer on 1/28/13.
426+// Copyright (c) 2013 Canonical. All rights reserved.
427+//
428+
429+#import <Foundation/Foundation.h>
430+
431+@class Song;
432+
433+#define kPlayerStateChanged @"UOPlayerStateChanged"
434+#define kPlayerSongChanged @"UOPlayerSongChanged"
435+#define kPlayerShuffleChanged @"UOPlayerShuffleChanged"
436+#define kPlayerRepeatChanged @"UOPlayerRepeatChanged"
437+
438+typedef enum {
439+ REPEATOFF,
440+ REPEATONE,
441+ REPEATALL
442+} RepeatState;
443+
444+typedef enum {
445+ PLAYERSTATESTOP,
446+ PLAYERSTATEPLAY,
447+ PLAYERSTATEPAUSE
448+} PlayerState;
449+
450+@interface UOPlayer : NSObject
451++ (id)player;
452+
453+- (void)addSongs:(NSArray *)songs;
454+- (void)addSongs:(NSArray *)songs withIndex:(NSUInteger)index;
455+
456+- (void)playPause;
457+- (void)next;
458+- (void)prev;
459+
460+@property (nonatomic, readonly) NSUInteger currentIndex;
461+@property (nonatomic, readonly) Song *currentSong;
462+@property (nonatomic, readonly) NSArray *currentPlaylist;
463+@property PlayerState state;
464+
465+@property (nonatomic) BOOL shuffle;
466+@property (nonatomic) RepeatState repeat;
467+
468+@end
469
470=== added file 'Music/Utilities/UOPlayer.m'
471--- Music/Utilities/UOPlayer.m 1970-01-01 00:00:00 +0000
472+++ Music/Utilities/UOPlayer.m 2013-02-09 04:48:21 +0000
473@@ -0,0 +1,286 @@
474+//
475+// UOPlayer.m
476+// U1Music
477+//
478+// Created by Paul Hummer on 1/28/13.
479+// Copyright (c) 2013 Canonical. All rights reserved.
480+//
481+
482+#import "UOPlayer.h"
483+#import "AudioStreamer.h"
484+#import "Song.h"
485+
486+#import "U1AutoDownloadsManager.h"
487+
488+@interface UOPlayer () {
489+ NSArray *songs;
490+ NSArray *shuffledSongs;
491+
492+ AudioStreamer *streamer;
493+ float seekTime;
494+}
495+@property (nonatomic, readwrite) NSUInteger currentIndex;
496+@property (nonatomic, strong) U1AutoDownloadsManager *downloadManager;
497+@end
498+
499+@implementation UOPlayer
500+@synthesize currentPlaylist;
501+@synthesize currentIndex;
502+
503+@synthesize state;
504+@synthesize downloadManager;
505+
506+@synthesize shuffle;
507+@synthesize repeat;
508+
509++ (id)player {
510+ static UOPlayer *instance = nil;
511+ static dispatch_once_t once;
512+ dispatch_once(&once, ^{
513+ instance = [[UOPlayer alloc] init];
514+ });
515+ return instance;
516+}
517+
518+- (id)init {
519+ self = [super init];
520+ if (self == nil) { return self; }
521+
522+ [self restoreSettings];
523+
524+ self.downloadManager = [[U1AutoDownloadsManager alloc] init];
525+
526+ self.state = PLAYERSTATESTOP;
527+ [[NSNotificationCenter defaultCenter] postNotificationName:kPlayerStateChanged object:nil];
528+
529+ [self addObserver:self forKeyPath:@"currentIndex" options:nil context:NULL];
530+
531+ return self;
532+}
533+
534+- (void)dealloc {
535+ if (streamer) {
536+ [streamer stop];
537+ streamer = nil;
538+ }
539+ songs = nil;
540+ shuffledSongs = nil;
541+ downloadManager = nil;
542+}
543+
544+#pragma mark - KVO methods
545+
546+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
547+ if ([keyPath isEqual:@"currentIndex"]) {
548+ [self.downloadManager setPlaylist:[self currentPlaylist] andIndex:self.currentIndex];
549+ } else {
550+ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
551+ }
552+}
553+
554+#pragma mark - Settings
555+
556+- (void)saveSettings {
557+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
558+ [defaults setBool:shuffle forKey:@"playerShuffle"];
559+ [defaults setInteger:repeat forKey:@"playerRepeat"];
560+ [defaults synchronize];
561+}
562+
563+- (void)restoreSettings {
564+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
565+
566+ shuffle = [defaults boolForKey:@"playerShuffle"];
567+ NSUInteger repeatMode = [defaults integerForKey:@"playerRepeat"];
568+ switch (repeatMode) {
569+ case REPEATALL:
570+ case REPEATONE:
571+ case REPEATOFF:
572+ repeat = repeatMode;
573+ break;
574+ default:
575+ repeat = REPEATOFF;
576+ break;
577+ }
578+}
579+
580+#pragma mark - Player state
581+
582+- (double)progress {
583+ return streamer.progress;
584+}
585+
586+#pragma mark - Play queue management
587+
588+- (Song *)currentSong {
589+ if ([songs count] == 0) {
590+ return nil;
591+ }
592+ return [[self currentPlaylist] objectAtIndex:self.currentIndex];
593+}
594+
595+- (NSArray *)currentPlaylist {
596+ return (shuffle ? shuffledSongs : songs);
597+}
598+
599+- (void)addSongs:(NSArray *)_songs {
600+ [self addSongs:_songs withIndex:0];
601+}
602+
603+- (void)addSongs:(NSArray *)_songs withIndex:(NSUInteger)index {
604+ if (streamer != nil) {
605+ [[NSNotificationCenter defaultCenter] postNotificationName:kPlayerStateChanged object:nil];
606+ self.state = PLAYERSTATESTOP;
607+ [streamer stop];
608+ streamer = nil;
609+ }
610+
611+ songs = _songs;
612+
613+ NSMutableArray *_shuffled = [_songs mutableCopy];
614+ NSUInteger count = [_shuffled count];
615+ for (NSUInteger i = 0; i < count; ++i) {
616+ NSInteger nElements = count - i;
617+ NSInteger n = (arc4random() % nElements) + i;
618+ [_shuffled exchangeObjectAtIndex:i withObjectAtIndex:n];
619+ }
620+ shuffledSongs = _shuffled;
621+
622+ if (shuffle) {
623+ self.currentIndex = [shuffledSongs indexOfObject:[songs objectAtIndex:index]];
624+ } else {
625+ self.currentIndex = index;
626+ }
627+
628+
629+}
630+
631+#pragma mark - Player controls
632+
633+- (void)playPause {
634+ if ([streamer isPaused]) {
635+ self.state = PLAYERSTATEPLAY;
636+ [streamer start];
637+ } else if ([streamer isPlaying]) {
638+ self.state = PLAYERSTATEPAUSE;
639+ [streamer pause];
640+ } else {
641+ [self _playCurrentSong];
642+ }
643+ [[NSNotificationCenter defaultCenter] postNotificationName:kPlayerStateChanged object:nil];
644+}
645+
646+- (void)next {
647+ switch (repeat) {
648+ case REPEATOFF:
649+ [streamer stop];
650+ self.state = PLAYERSTATESTOP;
651+ if (self.currentIndex == ([[self currentPlaylist] count] - 1)) {
652+ [streamer stop];
653+ streamer = nil;
654+ } else {
655+ self.currentIndex = self.currentIndex + 1;
656+ [self playPause];
657+ }
658+ break;
659+ case REPEATONE:
660+ [streamer stop];
661+ [self playPause];
662+ break;
663+ case REPEATALL:
664+ if (self.currentIndex == [[self currentPlaylist] count] - 1) {
665+ self.currentIndex = 0;
666+ } else {
667+ self.currentIndex = self.currentIndex + 1;
668+ }
669+ self.state = PLAYERSTATESTOP;
670+ [streamer stop];
671+ [self playPause];
672+ break;
673+ }
674+ [[NSNotificationCenter defaultCenter] postNotificationName:kPlayerStateChanged object:nil];
675+}
676+
677+- (void)prev {
678+ switch (repeat) {
679+ case REPEATOFF:
680+ [streamer stop];
681+ self.state = PLAYERSTATESTOP;
682+ if (self.currentIndex == 0) {
683+ [streamer stop];
684+ streamer = nil;
685+ } else {
686+ self.currentIndex = self.currentIndex - 1;
687+ [self playPause];
688+ }
689+ break;
690+ case REPEATONE:
691+ [streamer stop];
692+ [self playPause];
693+ break;
694+ case REPEATALL:
695+ if (self.currentIndex == 0) {
696+ self.currentIndex = [[self currentPlaylist] count] - 1;
697+ } else {
698+ self.currentIndex = self.currentIndex - 1;
699+ }
700+ self.state = PLAYERSTATESTOP;
701+ [streamer stop];
702+ [self playPause];
703+ break;
704+ }
705+ [[NSNotificationCenter defaultCenter] postNotificationName:kPlayerStateChanged object:nil];
706+}
707+
708+#pragma mark - Setters
709+
710+- (void)setShuffle:(BOOL)_shuffle {
711+ shuffle = _shuffle;
712+
713+ if (shuffle) {
714+ self.currentIndex = [shuffledSongs indexOfObject:[songs objectAtIndex:self.currentIndex]];
715+ } else {
716+ self.currentIndex = [songs indexOfObject:[shuffledSongs objectAtIndex:self.currentIndex]];
717+ }
718+
719+ [[NSNotificationCenter defaultCenter] postNotificationName:kPlayerShuffleChanged object:nil];
720+ [self saveSettings];
721+}
722+
723+- (void)setRepeat:(RepeatState)_repeat {
724+ repeat = _repeat;
725+ [[NSNotificationCenter defaultCenter] postNotificationName:kPlayerRepeatChanged object:nil];
726+ [self saveSettings];
727+}
728+
729+#pragma mark - Private methods
730+
731+- (void)_playCurrentSong {
732+ if (streamer != nil) {
733+ [streamer stop];
734+ streamer = nil;
735+ }
736+
737+ seekTime = 0.0;
738+
739+ Song *currentSong = [[self currentPlaylist] objectAtIndex:self.currentIndex];
740+
741+ NSString *songPath = [[currentSong idPath] urlParameterEncodedString];
742+ NSURL *localURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:9990/%@", songPath]];
743+ streamer = [[AudioStreamer alloc] initWithURL:localURL];
744+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(streamerStateChanged:) name:ASStatusChangedNotification object:streamer];
745+
746+ [[NSNotificationCenter defaultCenter] postNotificationName:kPlayerStateChanged object:nil];
747+ self.state = PLAYERSTATEPLAY;
748+ [streamer start];
749+
750+ [[NSNotificationCenter defaultCenter] postNotificationName:kPlayerSongChanged object:nil];
751+}
752+
753+- (void)streamerStateChanged:(NSNotification *)notification {
754+ if ([streamer isIdle]) {
755+ [self next];
756+ }
757+}
758+
759+@end
760
761=== modified file 'Music/View Controllers/AlbumViewController.m'
762--- Music/View Controllers/AlbumViewController.m 2013-01-28 00:40:22 +0000
763+++ Music/View Controllers/AlbumViewController.m 2013-02-09 04:48:21 +0000
764@@ -14,7 +14,7 @@
765 #import "UOWebServiceController.h"
766 #import "UODownloader.h"
767
768-#import "StreamingPlayer.h"
769+#import "UOPlayer.h"
770
771 @interface AlbumViewController () <UITableViewDataSource, UOWebServiceDelegate> {
772 NSArray *tableData;
773@@ -38,10 +38,10 @@
774 - (void)viewWillAppear:(BOOL)animated {
775 [self fetchAlbum];
776
777- if (![[StreamingPlayer sharedStreamingPlayer] currentSong]) {
778+ if ([[UOPlayer player] currentSong]) {
779+ self.navigationItem.rightBarButtonItem = self.nowPlayingButton;
780+ } else {
781 self.navigationItem.rightBarButtonItem = nil;
782- } else {
783- self.navigationItem.rightBarButtonItem = self.nowPlayingButton;
784 }
785
786 self.title = album.title;
787@@ -136,17 +136,11 @@
788 return; // Hit 'Now Playing'
789 }
790 Song *song = ((SongCell *)sender).song;
791-
792- StreamingPlayer *player = [StreamingPlayer sharedStreamingPlayer];
793- player.currentSong = song;
794- player.currentPlaylist = songs;
795- player.isNewSong = YES;
796- player.isShuffle = NO;
797-
798- if (player.streamer) {
799- [player.streamer stop];
800- }
801- [player playPauseSong];
802+ NSUInteger index = [songs indexOfObject:song];
803+
804+ UOPlayer *player = [UOPlayer player];
805+ [player addSongs:songs withIndex:index];
806+ [player playPause];
807 }
808
809 @end
810
811=== modified file 'Music/View Controllers/ArtistViewController.m'
812--- Music/View Controllers/ArtistViewController.m 2013-01-28 00:40:22 +0000
813+++ Music/View Controllers/ArtistViewController.m 2013-02-09 04:48:21 +0000
814@@ -16,7 +16,7 @@
815 #import "AlbumViewController.h"
816 #import "UOWebServiceController.h"
817 #import "UOAppDelegate.h"
818-#import "StreamingPlayer.h"
819+#import "UOPlayer.h"
820 #import "UODownloader.h"
821
822 @interface ArtistViewController () <UITableViewDataSource, UOWebServiceDelegate> {
823@@ -53,10 +53,10 @@
824 [self.albumArt setImage:artist.art];
825 }
826
827- if (![[StreamingPlayer sharedStreamingPlayer] currentSong]) {
828+ if ([[UOPlayer player] currentSong]) {
829+ self.navigationItem.rightBarButtonItem = self.nowPlayingButton;
830+ } else {
831 self.navigationItem.rightBarButtonItem = nil;
832- } else {
833- self.navigationItem.rightBarButtonItem = self.nowPlayingButton;
834 }
835
836 NSString *pluralizedNoun = @"albums";
837
838=== modified file 'Music/View Controllers/PlayerViewController.h'
839--- Music/View Controllers/PlayerViewController.h 2013-01-24 16:30:26 +0000
840+++ Music/View Controllers/PlayerViewController.h 2013-02-09 04:48:21 +0000
841@@ -14,11 +14,22 @@
842 @property (weak, nonatomic) IBOutlet UIToolbar *controlBar;
843
844 @property (weak, nonatomic) IBOutlet UIButton *albumart;
845+@property (weak, nonatomic) IBOutlet UIImageView *reflectionImage;
846 @property (weak, nonatomic) IBOutlet UIBarButtonItem *previousButton;
847 @property (strong, nonatomic) IBOutlet UIBarButtonItem *playButton;
848 @property (strong, nonatomic) IBOutlet UIBarButtonItem *pauseButton;
849 @property (weak, nonatomic) IBOutlet UIBarButtonItem *nextButton;
850
851+@property (weak, nonatomic) IBOutlet UIView *extendedControlView;
852+@property (weak, nonatomic) IBOutlet UISlider *progressView;
853+@property (weak, nonatomic) IBOutlet UIButton *repeatButton;
854+@property (weak, nonatomic) IBOutlet UIButton *shuffleButton;
855+@property (weak, nonatomic) IBOutlet UILabel *elapsedTime;
856+@property (weak, nonatomic) IBOutlet UILabel *totalTime;
857+
858+@property (weak, nonatomic) IBOutlet UILabel *playlistInfo;
859+
860+
861 - (IBAction)hide:(id)sender;
862
863 - (IBAction)previous:(id)sender;
864@@ -26,6 +37,12 @@
865 - (IBAction)pause:(id)sender;
866 - (IBAction)next:(id)sender;
867
868+- (IBAction)changeRepeat:(id)sender;
869+- (IBAction)changeShuffle:(id)sender;
870+
871+
872+- (IBAction)toggleExtendedControls:(id)sender;
873+
874 @property (weak, nonatomic) IBOutlet UILabel *artistLabel;
875 @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
876 @end
877
878=== modified file 'Music/View Controllers/PlayerViewController.m'
879--- Music/View Controllers/PlayerViewController.m 2013-01-24 16:30:26 +0000
880+++ Music/View Controllers/PlayerViewController.m 2013-02-09 04:48:21 +0000
881@@ -7,13 +7,16 @@
882 //
883
884 #import "PlayerViewController.h"
885+#import "NSString+UbuntuOne.h"
886+#import "UIImageView+UbuntuOne.h"
887 #import "Song.h"
888 #import "Artist.h"
889 #import "Album.h"
890-
891-#import "StreamingPlayer.h"
892-
893-@interface PlayerViewController ()
894+#import "UOPlayer.h"
895+
896+@interface PlayerViewController () {
897+ NSTimer *heartbeat;
898+}
899
900 @end
901
902@@ -28,21 +31,30 @@
903
904 - (void)viewWillAppear:(BOOL)animated {
905 [super viewWillAppear:animated];
906- [[StreamingPlayer sharedStreamingPlayer] addObserver:self forKeyPath:@"currentSong" options:0 context:NULL];
907- [[StreamingPlayer sharedStreamingPlayer] addObserver:self forKeyPath:@"isPlaying" options:0 context:NULL];
908-
909- [self updatePlayPause];
910+
911+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(songChanged:) name:kPlayerSongChanged object:nil];
912+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(syncControls:) name:kPlayerShuffleChanged object:nil];
913+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(syncControls:) name:kPlayerStateChanged object:nil];
914+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(syncControls:) name:kPlayerRepeatChanged object:nil];
915+
916+ [self syncControls:nil];
917 [self updateCurrentSong];
918+
919+ heartbeat = [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:@selector(heartbeat:) userInfo:nil repeats:YES];
920 }
921
922-- (void)viewWillDisappear:(BOOL)animated {
923- [super viewWillDisappear:animated];
924+- (void)viewDidDisappear:(BOOL)animated {
925+ [[NSNotificationCenter defaultCenter] removeObserver:self name:kPlayerSongChanged object:nil];
926+ [[NSNotificationCenter defaultCenter] removeObserver:self name:kPlayerShuffleChanged object:nil];
927+ [[NSNotificationCenter defaultCenter] removeObserver:self name:kPlayerStateChanged object:nil];
928+ [[NSNotificationCenter defaultCenter] removeObserver:self name:kPlayerRepeatChanged object:nil];
929
930- [[StreamingPlayer sharedStreamingPlayer] removeObserver:self forKeyPath:@"currentSong"];
931- [[StreamingPlayer sharedStreamingPlayer] removeObserver:self forKeyPath:@"isPlaying"];
932+ [heartbeat invalidate];
933+ heartbeat = nil;
934 }
935
936 - (void)viewDidUnload {
937+
938 [self setAlbumart:nil];
939 [self setPreviousButton:nil];
940 [self setPlayButton:nil];
941@@ -51,17 +63,18 @@
942 [self setControlBar:nil];
943 [self setArtistLabel:nil];
944 [self setTitleLabel:nil];
945+ [self setExtendedControlView:nil];
946+ [self setProgressView:nil];
947+ [self setShuffleButton:nil];
948+ [self setRepeatButton:nil];
949+ [self setShuffleButton:nil];
950+ [self setPlaylistInfo:nil];
951+ [self setTotalTime:nil];
952+ [self setElapsedTime:nil];
953+ [self setReflectionImage:nil];
954 [super viewDidUnload];
955 }
956
957-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
958- if ([keyPath isEqual:@"currentSong"]) {
959- [self updateCurrentSong];
960- } else if ([keyPath isEqual:@"isPlaying"]) {
961- [self updatePlayPause];
962- }
963-}
964-
965 #pragma mark - IBAction methods
966
967 - (IBAction)hide:(id)sender {
968@@ -69,28 +82,56 @@
969 }
970
971 - (IBAction)previous:(id)sender {
972- [[StreamingPlayer sharedStreamingPlayer] prevSong];
973+ [[UOPlayer player] prev];
974 }
975
976 - (IBAction)play:(id)sender {
977- [[StreamingPlayer sharedStreamingPlayer] playPauseSong];
978- [self updatePlayPause];
979+ [[UOPlayer player] playPause];
980 }
981
982 - (IBAction)next:(id)sender {
983- [[StreamingPlayer sharedStreamingPlayer] nextSong];
984+ [[UOPlayer player] next];
985+}
986+
987+- (IBAction)changeRepeat:(id)sender {
988+ if ([[UOPlayer player] repeat] == REPEATOFF) {
989+ [[UOPlayer player] setRepeat:REPEATONE];
990+ } else if ([[UOPlayer player] repeat] == REPEATONE) {
991+ [[UOPlayer player] setRepeat:REPEATALL];
992+ } else {
993+ [[UOPlayer player] setRepeat:REPEATOFF];
994+ }
995+}
996+
997+- (IBAction)changeShuffle:(id)sender {
998+ if ([[UOPlayer player] shuffle]) {
999+ [[UOPlayer player] setShuffle:NO];
1000+ } else {
1001+ [[UOPlayer player] setShuffle:YES];
1002+ }
1003+}
1004+
1005+- (IBAction)toggleExtendedControls:(id)sender {
1006+ if (self.extendedControlView.hidden) {
1007+ [self.extendedControlView setHidden:NO];
1008+ } else {
1009+ [self.extendedControlView setHidden:YES];
1010+ }
1011 }
1012
1013 - (IBAction)pause:(id)sender {
1014- [[StreamingPlayer sharedStreamingPlayer] playPauseSong];
1015- [self updatePlayPause];
1016+ [[UOPlayer player] playPause];
1017 }
1018
1019 #pragma mark - Private methods
1020
1021-- (void)updatePlayPause {
1022+- (void)songChanged:(id)sender {
1023+ [self updateCurrentSong];
1024+}
1025+
1026+- (void)syncControls:(id)sender {
1027 NSMutableArray *controlItems = [[self.controlBar items] mutableCopy];
1028- if ([[StreamingPlayer sharedStreamingPlayer] isPlaying]) {
1029+ if ([[UOPlayer player] state] == PLAYERSTATEPLAY) {
1030 if ([controlItems containsObject:self.playButton]) {
1031 NSInteger index = [controlItems indexOfObject:self.playButton];
1032 [controlItems removeObjectAtIndex:index];
1033@@ -105,14 +146,48 @@
1034 [self.controlBar setItems:controlItems];
1035 }
1036 }
1037+
1038+ if ([[UOPlayer player] shuffle]) {
1039+ [self.shuffleButton setImage:[UIImage imageNamed:@"shuffle-highlight.png"] forState:UIControlStateNormal];
1040+ } else {
1041+ [self.shuffleButton setImage:[UIImage imageNamed:@"05-shuffle.png"] forState:UIControlStateNormal];
1042+ }
1043+
1044+ if ([[UOPlayer player] repeat] == REPEATOFF) {
1045+ [self.repeatButton setImage:[UIImage imageNamed:@"03-loopback.png"] forState:UIControlStateNormal];
1046+ } else if ([[UOPlayer player] repeat] == REPEATONE) {
1047+ [self.repeatButton setImage:[UIImage imageNamed:@"loopback-one-highlight.png"] forState:UIControlStateNormal];
1048+ } else {
1049+ [self.repeatButton setImage:[UIImage imageNamed:@"loopback-highlight.png"] forState:UIControlStateNormal];
1050+ }
1051 }
1052
1053 - (void)updateCurrentSong {
1054- Song *song = [StreamingPlayer sharedStreamingPlayer].currentSong;
1055+ /* Update the "X of Y" text */
1056+ self.playlistInfo.text = [NSString stringWithFormat:@"%d of %d", [[UOPlayer player] currentIndex]+1, [[[UOPlayer player] currentPlaylist] count]];
1057+
1058+ Song *song = [[UOPlayer player] currentSong];
1059+
1060+ /* Update duration and progress view */
1061+ self.totalTime.text = [NSString clockStringFromSeconds:song.duration];
1062+ self.progressView.maximumValue = (float)song.duration;
1063+
1064+ /* Update song header */
1065 [self.artistLabel setText:song.artist.name];
1066 [self.titleLabel setText:song.title];
1067
1068- [self.albumart setImage:song.art forState:UIControlStateNormal];
1069+ if (song.art) {
1070+ [self.albumart setImage:song.art forState:UIControlStateNormal];
1071+ } else {
1072+ [self.albumart setImage:[UIImage imageNamed:@"default-album-art-640.png"] forState:UIControlStateNormal];
1073+ }
1074+ [self.albumart.imageView reflectOn:self.reflectionImage];
1075+}
1076+
1077+- (void)heartbeat:(NSTimer*)timer {
1078+ NSInteger progress = (NSInteger)[[UOPlayer player] progress];
1079+ self.elapsedTime.text = [NSString clockStringFromSeconds:progress];
1080+ self.progressView.value = progress;
1081 }
1082
1083 @end
1084
1085=== modified file 'Music/View Controllers/SongsViewController.m'
1086--- Music/View Controllers/SongsViewController.m 2013-01-24 18:31:49 +0000
1087+++ Music/View Controllers/SongsViewController.m 2013-02-09 04:48:21 +0000
1088@@ -12,7 +12,7 @@
1089 #import "SongCell.h"
1090 #import "NSString+Extras.h"
1091 #import "UOWebServiceController.h"
1092-#import "StreamingPlayer.h"
1093+#import "UOPlayer.h"
1094
1095 @interface SongsViewController ()
1096
1097@@ -49,23 +49,16 @@
1098 }
1099
1100 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
1101+ NSArray *songs = [[self.fetchedResultsController fetchedObjects] copy];
1102 if (![sender respondsToSelector:@selector(song)]) {
1103 return; // Hit 'Now Playing'
1104 }
1105-
1106- NSArray *songs = [[self.fetchedResultsController fetchedObjects] copy];
1107 Song *song = ((SongCell *)sender).song;
1108-
1109- StreamingPlayer *player = [StreamingPlayer sharedStreamingPlayer];
1110- player.currentSong = song;
1111- player.currentPlaylist = songs;
1112- player.isNewSong = YES;
1113- player.isShuffle = NO;
1114-
1115- if (player.streamer) {
1116- [player.streamer stop];
1117- }
1118- [player playPauseSong];
1119+ NSUInteger index = [songs indexOfObject:song];
1120+
1121+ UOPlayer *player = [UOPlayer player];
1122+ [player addSongs:songs withIndex:index];
1123+ [player playPause];
1124 }
1125
1126 @end
1127
1128=== modified file 'Music/View Controllers/UOIndexedViewController.m'
1129--- Music/View Controllers/UOIndexedViewController.m 2013-01-24 15:46:16 +0000
1130+++ Music/View Controllers/UOIndexedViewController.m 2013-02-09 04:48:21 +0000
1131@@ -9,7 +9,7 @@
1132 #import "UOIndexedViewController.h"
1133 #import <RestKit/RestKit.h>
1134 #import "UOAppDelegate.h"
1135-#import "StreamingPlayer.h"
1136+#import "UOPlayer.h"
1137
1138 @interface UOIndexedViewController () {
1139 NSFetchedResultsController *_fetchedResultsController;
1140@@ -59,10 +59,10 @@
1141 [super viewWillAppear:animated];
1142 [self update];
1143
1144- if (![[StreamingPlayer sharedStreamingPlayer] currentSong]) {
1145+ if ([[UOPlayer player] currentSong]) {
1146+ self.navigationItem.rightBarButtonItem = self.nowPlayingButton;
1147+ } else {
1148 self.navigationItem.rightBarButtonItem = nil;
1149- } else {
1150- self.navigationItem.rightBarButtonItem = self.nowPlayingButton;
1151 }
1152 }
1153
1154
1155=== modified file 'Music/Views/Table Cells/SongCell.m'
1156--- Music/Views/Table Cells/SongCell.m 2013-01-28 00:40:22 +0000
1157+++ Music/Views/Table Cells/SongCell.m 2013-02-09 04:48:21 +0000
1158@@ -10,6 +10,7 @@
1159 #import "Artist.h"
1160 #import "UODownloader.h"
1161 #import "UODownloadPanGestureRecognizer.h"
1162+#import "NSString+UbuntuOne.h"
1163
1164 @implementation SongCell
1165 @synthesize song = _song;
1166@@ -46,9 +47,7 @@
1167 [self.track setText:[NSString stringWithFormat:@"%d", song.track]];
1168 [self updateCacheIndicator];
1169
1170- NSInteger minutes = song.duration / 60;
1171- NSInteger seconds = song.duration % 60;
1172- [self.clock setText:[NSString stringWithFormat:@"%d:%02d", minutes, seconds]];
1173+ [self.clock setText:[NSString clockStringFromSeconds:song.duration]];
1174 }
1175
1176 #pragma mark - Private methods
1177
1178=== modified file 'U1Music.xcodeproj/project.pbxproj'
1179--- U1Music.xcodeproj/project.pbxproj 2013-02-08 17:05:40 +0000
1180+++ U1Music.xcodeproj/project.pbxproj 2013-02-09 04:48:21 +0000
1181@@ -28,6 +28,8 @@
1182 523B3CFA15B73BA0004394F4 /* download-grey@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 523B3CF615B73BA0004394F4 /* download-grey@2x.png */; };
1183 523B3CFB15B73BA0004394F4 /* download.png in Resources */ = {isa = PBXBuildFile; fileRef = 523B3CF715B73BA0004394F4 /* download.png */; };
1184 523B3CFC15B73BA0004394F4 /* download@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 523B3CF815B73BA0004394F4 /* download@2x.png */; };
1185+ 5257417716C5CC5D00530CCC /* NSString+UbuntuOne.m in Sources */ = {isa = PBXBuildFile; fileRef = 5257417616C5CC5D00530CCC /* NSString+UbuntuOne.m */; };
1186+ 5257417A16C5CDA900530CCC /* UIImageView+UbuntuOne.m in Sources */ = {isa = PBXBuildFile; fileRef = 5257417916C5CDA900530CCC /* UIImageView+UbuntuOne.m */; };
1187 5257416D16C5653100530CCC /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5257416C16C5653100530CCC /* Crashlytics.framework */; };
1188 5268509716AE5267001F65A6 /* libRestKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5268509016AE516C001F65A6 /* libRestKit.a */; };
1189 526850A816AEE4E1001F65A6 /* Storyboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 526850A516AEE4E1001F65A6 /* Storyboard_iPhone.storyboard */; };
1190@@ -60,6 +62,7 @@
1191 5268510616AEFCB2001F65A6 /* U1CachedFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 960E4B3414E58844002AAB79 /* U1CachedFile.m */; };
1192 5268510816AEFD20001F65A6 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5268510716AEFD20001F65A6 /* MobileCoreServices.framework */; };
1193 5279764915F00B2600F8435F /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5279764815F00B2600F8435F /* libz.dylib */; };
1194+ 5295FD2416B7559F00A07440 /* UOPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 5295FD2316B7559F00A07440 /* UOPlayer.m */; };
1195 52AC3D671604513E00B4785D /* about_logo.png in Resources */ = {isa = PBXBuildFile; fileRef = 52AC3D4B1604513E00B4785D /* about_logo.png */; };
1196 52AC3D681604513E00B4785D /* albums.png in Resources */ = {isa = PBXBuildFile; fileRef = 52AC3D4C1604513E00B4785D /* albums.png */; };
1197 52AC3D691604513E00B4785D /* albums@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 52AC3D4D1604513E00B4785D /* albums@2x.png */; };
1198@@ -271,6 +274,10 @@
1199 523B3CF615B73BA0004394F4 /* download-grey@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "download-grey@2x.png"; sourceTree = "<group>"; };
1200 523B3CF715B73BA0004394F4 /* download.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = download.png; sourceTree = "<group>"; };
1201 523B3CF815B73BA0004394F4 /* download@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "download@2x.png"; sourceTree = "<group>"; };
1202+ 5257417516C5CC5D00530CCC /* NSString+UbuntuOne.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSString+UbuntuOne.h"; path = "Categories/NSString+UbuntuOne.h"; sourceTree = "<group>"; };
1203+ 5257417616C5CC5D00530CCC /* NSString+UbuntuOne.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+UbuntuOne.m"; path = "Categories/NSString+UbuntuOne.m"; sourceTree = "<group>"; };
1204+ 5257417816C5CDA900530CCC /* UIImageView+UbuntuOne.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImageView+UbuntuOne.h"; path = "Categories/UIImageView+UbuntuOne.h"; sourceTree = "<group>"; };
1205+ 5257417916C5CDA900530CCC /* UIImageView+UbuntuOne.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+UbuntuOne.m"; path = "Categories/UIImageView+UbuntuOne.m"; sourceTree = "<group>"; };
1206 5257416C16C5653100530CCC /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Crashlytics.framework; sourceTree = "<group>"; };
1207 5268508516AE516B001F65A6 /* RestKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RestKit.xcodeproj; path = ../RestKit/RestKit.xcodeproj; sourceTree = "<group>"; };
1208 526850A516AEE4E1001F65A6 /* Storyboard_iPhone.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard_iPhone.storyboard; sourceTree = "<group>"; };
1209@@ -324,6 +331,8 @@
1210 5268510716AEFD20001F65A6 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
1211 5279764815F00B2600F8435F /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
1212 5285158E1604F16B004A1F7C /* UbuntuOneAuthKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = UbuntuOneAuthKit.xcodeproj; path = ../UbuntuOneAuthKit/UbuntuOneAuthKit.xcodeproj; sourceTree = "<group>"; };
1213+ 5295FD2216B7559F00A07440 /* UOPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UOPlayer.h; sourceTree = "<group>"; };
1214+ 5295FD2316B7559F00A07440 /* UOPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UOPlayer.m; sourceTree = "<group>"; };
1215 52AC3D4B1604513E00B4785D /* about_logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = about_logo.png; sourceTree = "<group>"; };
1216 52AC3D4C1604513E00B4785D /* albums.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = albums.png; sourceTree = "<group>"; };
1217 52AC3D4D1604513E00B4785D /* albums@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "albums@2x.png"; sourceTree = "<group>"; };
1218@@ -693,6 +702,17 @@
1219 name = Controls;
1220 sourceTree = "<group>";
1221 };
1222+ 5257413916C3405800530CCC /* Categories */ = {
1223+ isa = PBXGroup;
1224+ children = (
1225+ 5257417516C5CC5D00530CCC /* NSString+UbuntuOne.h */,
1226+ 5257417616C5CC5D00530CCC /* NSString+UbuntuOne.m */,
1227+ 5257417816C5CDA900530CCC /* UIImageView+UbuntuOne.h */,
1228+ 5257417916C5CDA900530CCC /* UIImageView+UbuntuOne.m */,
1229+ );
1230+ name = Categories;
1231+ sourceTree = "<group>";
1232+ };
1233 5268508616AE516B001F65A6 /* Products */ = {
1234 isa = PBXGroup;
1235 children = (
1236@@ -752,6 +772,8 @@
1237 children = (
1238 520BBF2216B51F2A00307F32 /* UODownloader.h */,
1239 520BBF2316B51F2A00307F32 /* UODownloader.m */,
1240+ 5295FD2216B7559F00A07440 /* UOPlayer.h */,
1241+ 5295FD2316B7559F00A07440 /* UOPlayer.m */,
1242 526850D016AEFA7C001F65A6 /* UOWebServiceController.h */,
1243 526850D116AEFA7C001F65A6 /* UOWebServiceController.m */,
1244 );
1245@@ -1084,6 +1106,7 @@
1246 93F3346C1247FB78006C6707 /* Music */ = {
1247 isa = PBXGroup;
1248 children = (
1249+ 5257413916C3405800530CCC /* Categories */,
1250 522B24E716B4BBC30084B023 /* Controls */,
1251 526850F416AEFC6A001F65A6 /* Models */,
1252 528515571604EED8004A1F7C /* Supporting Files */,
1253@@ -1607,6 +1630,9 @@
1254 5268510316AEFC6A001F65A6 /* UOModel.m in Sources */,
1255 522B24EA16B4BC1E0084B023 /* UODownloadPanGestureRecognizer.m in Sources */,
1256 520BBF2416B51F2A00307F32 /* UODownloader.m in Sources */,
1257+ 5295FD2416B7559F00A07440 /* UOPlayer.m in Sources */,
1258+ 5257417716C5CC5D00530CCC /* NSString+UbuntuOne.m in Sources */,
1259+ 5257417A16C5CDA900530CCC /* UIImageView+UbuntuOne.m in Sources */,
1260 );
1261 runOnlyForDeploymentPostprocessing = 0;
1262 };
1263
1264=== modified file 'utilities/StreamingPlayer.m'
1265--- utilities/StreamingPlayer.m 2013-01-26 02:37:04 +0000
1266+++ utilities/StreamingPlayer.m 2013-02-09 04:48:21 +0000
1267@@ -87,7 +87,7 @@
1268 case RepeatModeOff:
1269 self.repeatMode = savedRepeatMode;
1270 break;
1271-
1272+
1273 default:
1274 self.repeatMode = RepeatModeOff;
1275 break;
1276
1277=== modified file 'xibs/SongViewController.xib'
1278--- xibs/SongViewController.xib 2012-06-22 17:57:12 +0000
1279+++ xibs/SongViewController.xib 2013-02-09 04:48:21 +0000
1280@@ -1,14 +1,14 @@
1281 <?xml version="1.0" encoding="UTF-8"?>
1282 <archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00">
1283 <data>
1284- <int key="IBDocument.SystemTarget">1536</int>
1285- <string key="IBDocument.SystemVersion">11E2620</string>
1286- <string key="IBDocument.InterfaceBuilderVersion">2541</string>
1287- <string key="IBDocument.AppKitVersion">1138.47</string>
1288- <string key="IBDocument.HIToolboxVersion">569.00</string>
1289+ <int key="IBDocument.SystemTarget">1552</int>
1290+ <string key="IBDocument.SystemVersion">12C60</string>
1291+ <string key="IBDocument.InterfaceBuilderVersion">3084</string>
1292+ <string key="IBDocument.AppKitVersion">1187.34</string>
1293+ <string key="IBDocument.HIToolboxVersion">625.00</string>
1294 <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
1295 <string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
1296- <string key="NS.object.0">1875</string>
1297+ <string key="NS.object.0">2083</string>
1298 </object>
1299 <array key="IBDocument.IntegratedClassDependencies">
1300 <string>IBProxyObject</string>
1301@@ -189,6 +189,11 @@
1302 <int key="IBUIContentMode">7</int>
1303 <bool key="IBUIUserInteractionEnabled">NO</bool>
1304 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
1305+ <string key="IBUIText">Interpol</string>
1306+ <object class="NSColor" key="IBUITextColor">
1307+ <int key="NSColorSpace">1</int>
1308+ <bytes key="NSRGB">MC42MjM1Mjk0MTE4IDAuNjIzNTI5NDExOCAwLjYyMzUyOTQxMTgAA</bytes>
1309+ </object>
1310 <object class="NSColor" key="IBUIHighlightedColor">
1311 <int key="NSColorSpace">3</int>
1312 <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
1313@@ -196,14 +201,10 @@
1314 <object class="NSColor" key="IBUIShadowColor" id="207782929">
1315 <int key="NSColorSpace">1</int>
1316 <bytes key="NSRGB">MCAwIDAAA</bytes>
1317+ <string key="IBUIColorCocoaTouchKeyPath">darkTextColor</string>
1318 </object>
1319 <int key="IBUIBaselineAdjustment">1</int>
1320 <float key="IBUIMinimumFontSize">10</float>
1321- <string key="IBUIText">Interpol</string>
1322- <object class="NSColor" key="IBUITextColor">
1323- <int key="NSColorSpace">1</int>
1324- <bytes key="NSRGB">MC42MjM1Mjk0MTE4IDAuNjIzNTI5NDExOCAwLjYyMzUyOTQxMTgAA</bytes>
1325- </object>
1326 <int key="IBUITextAlignment">1</int>
1327 <object class="IBUIFontDescription" key="IBUIFontDescription" id="295205315">
1328 <string key="name">Helvetica-Bold</string>
1329@@ -217,7 +218,6 @@
1330 <int key="NSfFlags">16</int>
1331 </object>
1332 <bool key="IBUIAdjustsFontSizeToFit">NO</bool>
1333- <int key="IBUIAutoshrinkMode">0</int>
1334 </object>
1335 <object class="IBUILabel" id="188765676">
1336 <reference key="NSNextResponder" ref="962247428"/>
1337@@ -230,17 +230,16 @@
1338 <int key="IBUIContentMode">7</int>
1339 <bool key="IBUIUserInteractionEnabled">NO</bool>
1340 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
1341- <reference key="IBUIHighlightedColor" ref="193107363"/>
1342- <reference key="IBUIShadowColor" ref="207782929"/>
1343- <int key="IBUIBaselineAdjustment">1</int>
1344- <float key="IBUIMinimumFontSize">10</float>
1345 <string key="IBUIText">Interpol</string>
1346 <reference key="IBUITextColor" ref="193107363"/>
1347+ <reference key="IBUIHighlightedColor" ref="193107363"/>
1348+ <reference key="IBUIShadowColor" ref="207782929"/>
1349+ <int key="IBUIBaselineAdjustment">1</int>
1350+ <float key="IBUIMinimumFontSize">10</float>
1351 <int key="IBUITextAlignment">1</int>
1352 <reference key="IBUIFontDescription" ref="295205315"/>
1353 <reference key="IBUIFont" ref="956421100"/>
1354 <bool key="IBUIAdjustsFontSizeToFit">NO</bool>
1355- <int key="IBUIAutoshrinkMode">0</int>
1356 </object>
1357 <object class="IBUILabel" id="405973632">
1358 <reference key="NSNextResponder" ref="962247428"/>
1359@@ -252,20 +251,19 @@
1360 <int key="IBUIContentMode">7</int>
1361 <bool key="IBUIUserInteractionEnabled">NO</bool>
1362 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
1363- <reference key="IBUIHighlightedColor" ref="193107363"/>
1364- <reference key="IBUIShadowColor" ref="207782929"/>
1365- <int key="IBUIBaselineAdjustment">1</int>
1366- <float key="IBUIMinimumFontSize">10</float>
1367 <string key="IBUIText">Interpol</string>
1368 <object class="NSColor" key="IBUITextColor">
1369 <int key="NSColorSpace">1</int>
1370 <bytes key="NSRGB">MC42MjM1Mjk0MTE4IDAuNjIzNTI5NDExOCAwLjYyMzUyOTQxMTgAA</bytes>
1371 </object>
1372+ <reference key="IBUIHighlightedColor" ref="193107363"/>
1373+ <reference key="IBUIShadowColor" ref="207782929"/>
1374+ <int key="IBUIBaselineAdjustment">1</int>
1375+ <float key="IBUIMinimumFontSize">10</float>
1376 <int key="IBUITextAlignment">1</int>
1377 <reference key="IBUIFontDescription" ref="295205315"/>
1378 <reference key="IBUIFont" ref="956421100"/>
1379 <bool key="IBUIAdjustsFontSizeToFit">NO</bool>
1380- <int key="IBUIAutoshrinkMode">0</int>
1381 </object>
1382 </array>
1383 <string key="NSFrameSize">{200, 45}</string>
1384@@ -274,9 +272,10 @@
1385 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
1386 </object>
1387 <object class="IBUIButton" id="959908150">
1388- <nil key="NSNextResponder"/>
1389+ <reference key="NSNextResponder"/>
1390 <int key="NSvFlags">292</int>
1391 <string key="NSFrameSize">{44, 29}</string>
1392+ <reference key="NSSuperview"/>
1393 <bool key="IBUIOpaque">NO</bool>
1394 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
1395 <int key="IBUIContentHorizontalAlignment">0</int>
1396@@ -304,7 +303,7 @@
1397 </object>
1398 </object>
1399 <object class="IBUIView" id="938289822">
1400- <nil key="NSNextResponder"/>
1401+ <reference key="NSNextResponder"/>
1402 <int key="NSvFlags">292</int>
1403 <array class="NSMutableArray" key="NSSubviews">
1404 <object class="IBUIImageView" id="169132852">
1405@@ -396,10 +395,6 @@
1406 <int key="IBUIContentMode">7</int>
1407 <bool key="IBUIUserInteractionEnabled">NO</bool>
1408 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
1409- <reference key="IBUIHighlightedColor" ref="193107363"/>
1410- <reference key="IBUIShadowColor" ref="207782929"/>
1411- <int key="IBUIBaselineAdjustment">1</int>
1412- <float key="IBUIMinimumFontSize">10</float>
1413 <string key="IBUIText">0:00</string>
1414 <object class="NSColor" key="IBUITextColor">
1415 <int key="NSColorSpace">1</int>
1416@@ -408,6 +403,10 @@
1417 <int key="NSID">1</int>
1418 </object>
1419 </object>
1420+ <reference key="IBUIHighlightedColor" ref="193107363"/>
1421+ <reference key="IBUIShadowColor" ref="207782929"/>
1422+ <int key="IBUIBaselineAdjustment">1</int>
1423+ <float key="IBUIMinimumFontSize">10</float>
1424 <int key="IBUITextAlignment">2</int>
1425 <object class="IBUIFontDescription" key="IBUIFontDescription" id="911767061">
1426 <string key="name">Helvetica-Bold</string>
1427@@ -420,7 +419,6 @@
1428 <double key="NSSize">14</double>
1429 <int key="NSfFlags">16</int>
1430 </object>
1431- <int key="IBUIAutoshrinkMode">2</int>
1432 </object>
1433 <object class="IBUILabel" id="451378775">
1434 <reference key="NSNextResponder" ref="938289822"/>
1435@@ -433,19 +431,18 @@
1436 <int key="IBUIContentMode">7</int>
1437 <bool key="IBUIUserInteractionEnabled">NO</bool>
1438 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
1439- <reference key="IBUIHighlightedColor" ref="193107363"/>
1440- <reference key="IBUIShadowColor" ref="207782929"/>
1441- <int key="IBUIBaselineAdjustment">1</int>
1442- <float key="IBUIMinimumFontSize">10</float>
1443 <string key="IBUIText">-18:88</string>
1444 <object class="NSColor" key="IBUITextColor">
1445 <int key="NSColorSpace">1</int>
1446 <bytes key="NSRGB">MSAxIDEAA</bytes>
1447 <reference key="NSCustomColorSpace" ref="400680623"/>
1448 </object>
1449+ <reference key="IBUIHighlightedColor" ref="193107363"/>
1450+ <reference key="IBUIShadowColor" ref="207782929"/>
1451+ <int key="IBUIBaselineAdjustment">1</int>
1452+ <float key="IBUIMinimumFontSize">10</float>
1453 <reference key="IBUIFontDescription" ref="911767061"/>
1454 <reference key="IBUIFont" ref="733486606"/>
1455- <int key="IBUIAutoshrinkMode">2</int>
1456 </object>
1457 <object class="IBUILabel" id="650617321">
1458 <reference key="NSNextResponder" ref="938289822"/>
1459@@ -458,23 +455,23 @@
1460 <int key="IBUIContentMode">7</int>
1461 <bool key="IBUIUserInteractionEnabled">NO</bool>
1462 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
1463- <reference key="IBUIHighlightedColor" ref="193107363"/>
1464- <reference key="IBUIShadowColor" ref="207782929"/>
1465- <int key="IBUIBaselineAdjustment">1</int>
1466- <float key="IBUIMinimumFontSize">10</float>
1467 <string key="IBUIText">10 of 11</string>
1468 <object class="NSColor" key="IBUITextColor">
1469 <int key="NSColorSpace">1</int>
1470 <bytes key="NSRGB">MSAxIDEAA</bytes>
1471 <reference key="NSCustomColorSpace" ref="400680623"/>
1472 </object>
1473+ <reference key="IBUIHighlightedColor" ref="193107363"/>
1474+ <reference key="IBUIShadowColor" ref="207782929"/>
1475+ <int key="IBUIBaselineAdjustment">1</int>
1476+ <float key="IBUIMinimumFontSize">10</float>
1477 <int key="IBUITextAlignment">1</int>
1478 <reference key="IBUIFontDescription" ref="911767061"/>
1479 <reference key="IBUIFont" ref="733486606"/>
1480- <int key="IBUIAutoshrinkMode">2</int>
1481 </object>
1482 </array>
1483 <string key="NSFrameSize">{320, 100}</string>
1484+ <reference key="NSSuperview"/>
1485 <reference key="NSNextKeyView" ref="169132852"/>
1486 <reference key="IBUIBackgroundColor" ref="811861181"/>
1487 <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
1488@@ -964,6 +961,6 @@
1489 <string key="player_back.png">{44, 29}</string>
1490 <string key="player_overlay_bg.png">{320, 100}</string>
1491 </dictionary>
1492- <string key="IBCocoaTouchPluginVersion">1875</string>
1493+ <string key="IBCocoaTouchPluginVersion">2083</string>
1494 </data>
1495 </archive>

Subscribers

People subscribed via source and target branches