Merge lp:~rockstar/ubuntuone-ios-music/replace-streaming-player into lp:ubuntuone-ios-music
- replace-streaming-player
- Merge into trunk
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 |
Related bugs: |
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://
http://
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.
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 U1AutoDownloads
- 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 clockStringFrom
Seconds - 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
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.
Mike McCracken (mikemc) : | # |
Preview Diff
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> |
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 omSeconds: "...
like "+clockStringFr
2. UIImage+UbuntuOne: (~MINOR)
reflectedImage:(1) toImageView:(2) wasn't clear from the name what it mageView: (1)" or something.
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) toReflectionOfI
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 withStartingInd ex:".
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:
(MINOR): IMO, enums are more readable with underscores: e.g. REPEAT_OFF