Merge lp:~rockstar/ubuntuone-ios-music/polish-list-views into lp:ubuntuone-ios-music
- polish-list-views
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Paul Hummer |
Approved revision: | 292 |
Merged at revision: | 249 |
Proposed branch: | lp:~rockstar/ubuntuone-ios-music/polish-list-views |
Merge into: | lp:ubuntuone-ios-music |
Prerequisite: | lp:~rockstar/ubuntuone-ios-music/replace-streaming-player |
Diff against target: |
1800 lines (+1037/-204) 27 files modified
Dependencies/SSPullToRefresh/LICENSE (+20/-0) Dependencies/SSPullToRefresh/SSPullToRefresh.h (+16/-0) Dependencies/SSPullToRefresh/SSPullToRefreshDefaultContentView.h (+17/-0) Dependencies/SSPullToRefresh/SSPullToRefreshDefaultContentView.m (+86/-0) Dependencies/SSPullToRefresh/SSPullToRefreshSimpleContentView.h (+16/-0) Dependencies/SSPullToRefresh/SSPullToRefreshSimpleContentView.m (+80/-0) Dependencies/SSPullToRefresh/SSPullToRefreshView.h (+205/-0) Dependencies/SSPullToRefresh/SSPullToRefreshView.m (+349/-0) Music/Models/Album.h (+2/-0) Music/Models/Album.m (+5/-0) Music/Storyboard_iPhone.storyboard (+78/-160) Music/Utilities/UOPlayer.h (+2/-0) Music/Utilities/UOPlayer.m (+1/-1) Music/View Controllers/AlbumViewController.h (+1/-0) Music/View Controllers/AlbumViewController.m (+12/-2) Music/View Controllers/AlbumsViewController.m (+5/-0) Music/View Controllers/ArtistViewController.m (+11/-5) Music/View Controllers/ArtistsViewController.m (+4/-0) Music/View Controllers/PlayerViewController.m (+2/-2) Music/View Controllers/PlaylistsViewController.m (+4/-0) Music/View Controllers/SongsViewController.m (+10/-6) Music/View Controllers/UOIndexedViewController.h (+1/-0) Music/View Controllers/UOIndexedViewController.m (+23/-27) Music/Views/Table Cells/ArtistCell.m (+2/-0) Music/Views/Table Cells/SongListCell.h (+15/-0) Music/Views/Table Cells/SongListCell.m (+34/-0) U1Music.xcodeproj/project.pbxproj (+36/-1) |
To merge this branch: | bzr merge lp:~rockstar/ubuntuone-ios-music/polish-list-views |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mike McCracken (community) | Approve | ||
Review via email: mp+147028@code.launchpad.net |
Commit message
Polish the list views
Description of the change
I just did a bunch of tweaks that make things more presentable on the list views and such. I changed the font to be more in line with what design had envisioned in the original settings view (and the new settings view followed suit), and made things a bit more pixel lined up (using Xcode's guides).
I also fixed a bug where you'd navigate from an artist, to a various artist album and the album listing shows all the songs, rather than filtered down to only the artist's songs on that album.
- 288. By Paul Hummer
-
Merge from previous pipe
- 289. By Paul Hummer
-
Merged replace-
streaming- player into polish-list-views. - 290. By Paul Hummer
-
Merged replace-
streaming- player into polish-list-views. - 291. By Paul Hummer
-
Reset the detailTextLabel
- 292. By Paul Hummer
-
Add SSPullToRefresh LICENSE
Paul Hummer (rockstar) wrote : | # |
With small changes, I don't see any problem in putting those changes in the same branch.
(1) Added LICENSE
(1a) I'll add the GPL headers to files prior to release. I'm trying to keep the diff size down, especially with stuff that is not needed in code review.
(2) We aren't currently focused on localization in any of the Ubuntu One properties. It might be nice in the future, but not now.
(3) art is actually a method that checks the filesystem for the file itself, so it won't get downloaded again. There is a chance that it'll get downloaded and re-written, but that's super unlikely at this point, and there are bigger problems with the album art (like storing multiple copies of the default album art...) At some point, I'll make the downloader smarter, and not queue a download if it already is queued.
Mike McCracken (mikemc) wrote : | # |
I won't fight you on branch size - I'll just explain my bias toward branches as small as possible.
On the desktop projects, we've tried pretty hard to make separate branches out of separate changes, and I've noticed that they're easier to review, issues with one change don't block landing other changes, and when doing bzr-blame log searching while fixing bugs, big multi-feature branches make tracing and understanding historical changes harder.
We also had a size guideline at one point: we decided to try to keep branches ~500 lines or less, even to the point of committing half of a feature in one branch and the other half in another. I thought that extreme was overkill (obviously e.g. adding a framework with headers is going to be big), and the specific number that makes sense will be different for different languages, but 500 seemed like a good rule of thumb.
Thanks for taking the time to write a detailed reply, too. I appreciate it.
Preview Diff
1 | === added directory 'Dependencies/SSPullToRefresh' |
2 | === added file 'Dependencies/SSPullToRefresh/LICENSE' |
3 | --- Dependencies/SSPullToRefresh/LICENSE 1970-01-01 00:00:00 +0000 |
4 | +++ Dependencies/SSPullToRefresh/LICENSE 2013-02-11 04:30:25 +0000 |
5 | @@ -0,0 +1,20 @@ |
6 | +Copyright (c) 2012 Sam Soffes |
7 | + |
8 | +Permission is hereby granted, free of charge, to any person obtaining |
9 | +a copy of this software and associated documentation files (the |
10 | +"Software"), to deal in the Software without restriction, including |
11 | +without limitation the rights to use, copy, modify, merge, publish, |
12 | +distribute, sublicense, and/or sell copies of the Software, and to |
13 | +permit persons to whom the Software is furnished to do so, subject to |
14 | +the following conditions: |
15 | + |
16 | +The above copyright notice and this permission notice shall be |
17 | +included in all copies or substantial portions of the Software. |
18 | + |
19 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
20 | +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
21 | +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
22 | +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
23 | +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
24 | +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
25 | +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
26 | |
27 | === added file 'Dependencies/SSPullToRefresh/SSPullToRefresh.h' |
28 | --- Dependencies/SSPullToRefresh/SSPullToRefresh.h 1970-01-01 00:00:00 +0000 |
29 | +++ Dependencies/SSPullToRefresh/SSPullToRefresh.h 2013-02-11 04:30:25 +0000 |
30 | @@ -0,0 +1,16 @@ |
31 | +// |
32 | +// SSPullToRefresh.h |
33 | +// SSPullToRefresh |
34 | +// |
35 | +// Created by Sam Soffes on 4/9/12. |
36 | +// Copyright (c) 2012 Sam Soffes. All rights reserved. |
37 | +// |
38 | + |
39 | +// Main pull to refresh view. This class contains all of the pulling logic. |
40 | +#import "SSPullToRefreshView.h" |
41 | + |
42 | +// Default content view. Similar to Facebook. |
43 | +#import "SSPullToRefreshDefaultContentView.h" |
44 | + |
45 | +// Simple content view. Similar to Path. |
46 | +#import "SSPullToRefreshSimpleContentView.h" |
47 | |
48 | === added file 'Dependencies/SSPullToRefresh/SSPullToRefreshDefaultContentView.h' |
49 | --- Dependencies/SSPullToRefresh/SSPullToRefreshDefaultContentView.h 1970-01-01 00:00:00 +0000 |
50 | +++ Dependencies/SSPullToRefresh/SSPullToRefreshDefaultContentView.h 2013-02-11 04:30:25 +0000 |
51 | @@ -0,0 +1,17 @@ |
52 | +// |
53 | +// SSPullToRefreshDefaultContentView |
54 | +// SSPullToRefresh |
55 | +// |
56 | +// Created by Sam Soffes on 4/9/12. |
57 | +// Copyright (c) 2012 Sam Soffes. All rights reserved. |
58 | +// |
59 | + |
60 | +#import "SSPullToRefreshView.h" |
61 | + |
62 | +@interface SSPullToRefreshDefaultContentView : UIView <SSPullToRefreshContentView> |
63 | + |
64 | +@property (nonatomic, strong, readonly) UILabel *statusLabel; |
65 | +@property (nonatomic, strong, readonly) UILabel *lastUpdatedAtLabel; |
66 | +@property (nonatomic, strong, readonly) UIActivityIndicatorView *activityIndicatorView; |
67 | + |
68 | +@end |
69 | |
70 | === added file 'Dependencies/SSPullToRefresh/SSPullToRefreshDefaultContentView.m' |
71 | --- Dependencies/SSPullToRefresh/SSPullToRefreshDefaultContentView.m 1970-01-01 00:00:00 +0000 |
72 | +++ Dependencies/SSPullToRefresh/SSPullToRefreshDefaultContentView.m 2013-02-11 04:30:25 +0000 |
73 | @@ -0,0 +1,86 @@ |
74 | +// |
75 | +// SSPullToRefreshDefaultContentView |
76 | +// SSPullToRefresh |
77 | +// |
78 | +// Created by Sam Soffes on 4/9/12. |
79 | +// Copyright (c) 2012 Sam Soffes. All rights reserved. |
80 | +// |
81 | + |
82 | +#import "SSPullToRefreshDefaultContentView.h" |
83 | + |
84 | +@implementation SSPullToRefreshDefaultContentView |
85 | + |
86 | +@synthesize statusLabel = _statusLabel; |
87 | +@synthesize lastUpdatedAtLabel = _lastUpdatedAtLabel; |
88 | +@synthesize activityIndicatorView = _activityIndicatorView; |
89 | + |
90 | +#pragma mark - UIView |
91 | + |
92 | +- (id)initWithFrame:(CGRect)frame { |
93 | + if ((self = [super initWithFrame:frame])) { |
94 | + CGFloat width = self.bounds.size.width; |
95 | + |
96 | + _statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 14.0f, width, 20.0f)]; |
97 | + _statusLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; |
98 | + _statusLabel.font = [UIFont boldSystemFontOfSize:14.0f]; |
99 | + _statusLabel.textColor = [UIColor blackColor]; |
100 | + _statusLabel.backgroundColor = [UIColor clearColor]; |
101 | + _statusLabel.textAlignment = UITextAlignmentCenter; |
102 | + [self addSubview:_statusLabel]; |
103 | + |
104 | + _lastUpdatedAtLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 34.0f, width, 20.0f)]; |
105 | + _lastUpdatedAtLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; |
106 | + _lastUpdatedAtLabel.font = [UIFont systemFontOfSize:12.0f]; |
107 | + _lastUpdatedAtLabel.textColor = [UIColor lightGrayColor]; |
108 | + _lastUpdatedAtLabel.backgroundColor = [UIColor clearColor]; |
109 | + _lastUpdatedAtLabel.textAlignment = UITextAlignmentCenter; |
110 | + [self addSubview:_lastUpdatedAtLabel]; |
111 | + |
112 | + _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; |
113 | + _activityIndicatorView.frame = CGRectMake(30.0f, 25.0f, 20.0f, 20.0f); |
114 | + [self addSubview:_activityIndicatorView]; |
115 | + } |
116 | + return self; |
117 | +} |
118 | + |
119 | + |
120 | +#pragma mark - SSPullToRefreshContentView |
121 | + |
122 | +- (void)setState:(SSPullToRefreshViewState)state withPullToRefreshView:(SSPullToRefreshView *)view { |
123 | + switch (state) { |
124 | + case SSPullToRefreshViewStateReady: { |
125 | + _statusLabel.text = @"Release to refresh..."; |
126 | + [_activityIndicatorView stopAnimating]; |
127 | + break; |
128 | + } |
129 | + |
130 | + case SSPullToRefreshViewStateNormal: { |
131 | + _statusLabel.text = @"Pull down to refresh..."; |
132 | + [_activityIndicatorView stopAnimating]; |
133 | + break; |
134 | + } |
135 | + |
136 | + case SSPullToRefreshViewStateLoading: |
137 | + case SSPullToRefreshViewStateClosing: { |
138 | + _statusLabel.text = @"Loading..."; |
139 | + [_activityIndicatorView startAnimating]; |
140 | + break; |
141 | + } |
142 | + } |
143 | +} |
144 | + |
145 | + |
146 | +- (void)setLastUpdatedAt:(NSDate *)date withPullToRefreshView:(SSPullToRefreshView *)view { |
147 | + static NSDateFormatter *dateFormatter = nil; |
148 | + static dispatch_once_t onceToken; |
149 | + dispatch_once(&onceToken, ^{ |
150 | + dateFormatter = [[NSDateFormatter alloc] init]; |
151 | + dateFormatter.formatterBehavior = NSDateFormatterBehavior10_4; |
152 | + dateFormatter.dateStyle = NSDateFormatterLongStyle; |
153 | + dateFormatter.timeStyle = NSDateFormatterShortStyle; |
154 | + }); |
155 | + |
156 | + _lastUpdatedAtLabel.text = [NSString stringWithFormat:@"Last Updated: %@", [dateFormatter stringForObjectValue:date]]; |
157 | +} |
158 | + |
159 | +@end |
160 | |
161 | === added file 'Dependencies/SSPullToRefresh/SSPullToRefreshSimpleContentView.h' |
162 | --- Dependencies/SSPullToRefresh/SSPullToRefreshSimpleContentView.h 1970-01-01 00:00:00 +0000 |
163 | +++ Dependencies/SSPullToRefresh/SSPullToRefreshSimpleContentView.h 2013-02-11 04:30:25 +0000 |
164 | @@ -0,0 +1,16 @@ |
165 | +// |
166 | +// SSPullToRefreshSimpleContentView.h |
167 | +// SSPullToRefresh |
168 | +// |
169 | +// Created by Sam Soffes on 5/17/12. |
170 | +// Copyright (c) 2012 Sam Soffes. All rights reserved. |
171 | +// |
172 | + |
173 | +#import "SSPullToRefreshView.h" |
174 | + |
175 | +@interface SSPullToRefreshSimpleContentView : UIView <SSPullToRefreshContentView> |
176 | + |
177 | +@property (nonatomic, strong, readonly) UILabel *statusLabel; |
178 | +@property (nonatomic, strong, readonly) UIActivityIndicatorView *activityIndicatorView; |
179 | + |
180 | +@end |
181 | |
182 | === added file 'Dependencies/SSPullToRefresh/SSPullToRefreshSimpleContentView.m' |
183 | --- Dependencies/SSPullToRefresh/SSPullToRefreshSimpleContentView.m 1970-01-01 00:00:00 +0000 |
184 | +++ Dependencies/SSPullToRefresh/SSPullToRefreshSimpleContentView.m 2013-02-11 04:30:25 +0000 |
185 | @@ -0,0 +1,80 @@ |
186 | +// |
187 | +// SSPullToRefreshSimpleContentView.m |
188 | +// SSPullToRefresh |
189 | +// |
190 | +// Created by Sam Soffes on 5/17/12. |
191 | +// Copyright (c) 2012 Sam Soffes. All rights reserved. |
192 | +// |
193 | + |
194 | +#import "SSPullToRefreshSimpleContentView.h" |
195 | + |
196 | +@implementation SSPullToRefreshSimpleContentView |
197 | + |
198 | +@synthesize statusLabel = _statusLabel; |
199 | +@synthesize activityIndicatorView = _activityIndicatorView; |
200 | + |
201 | + |
202 | +#pragma mark - UIView |
203 | + |
204 | +- (id)initWithFrame:(CGRect)frame { |
205 | + if ((self = [super initWithFrame:frame])) { |
206 | + CGFloat width = self.bounds.size.width; |
207 | + |
208 | + _statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 14.0f, width, 20.0f)]; |
209 | + _statusLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; |
210 | + _statusLabel.font = [UIFont boldSystemFontOfSize:14.0f]; |
211 | + _statusLabel.textColor = [UIColor blackColor]; |
212 | + _statusLabel.backgroundColor = [UIColor clearColor]; |
213 | + _statusLabel.textAlignment = UITextAlignmentCenter; |
214 | + [self addSubview:_statusLabel]; |
215 | + |
216 | + _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; |
217 | + _activityIndicatorView.frame = CGRectMake(30.0f, 25.0f, 20.0f, 20.0f); |
218 | + [self addSubview:_activityIndicatorView]; |
219 | + } |
220 | + return self; |
221 | +} |
222 | + |
223 | + |
224 | +- (void)layoutSubviews { |
225 | + CGSize size = self.bounds.size; |
226 | + self.statusLabel.frame = CGRectMake(20.0f, roundf((size.height - 30.0f) / 2.0f), size.width - 40.0f, 30.0f); |
227 | + self.activityIndicatorView.frame = CGRectMake(roundf((size.width - 20.0f) / 2.0f), roundf((size.height - 20.0f) / 2.0f), 20.0f, 20.0f); |
228 | +} |
229 | + |
230 | + |
231 | +#pragma mark - SSPullToRefreshContentView |
232 | + |
233 | +- (void)setState:(SSPullToRefreshViewState)state withPullToRefreshView:(SSPullToRefreshView *)view { |
234 | + switch (state) { |
235 | + case SSPullToRefreshViewStateReady: { |
236 | + self.statusLabel.text = @"Release to refresh"; |
237 | + [self.activityIndicatorView startAnimating]; |
238 | + self.activityIndicatorView.alpha = 0.0f; |
239 | + break; |
240 | + } |
241 | + |
242 | + case SSPullToRefreshViewStateNormal: { |
243 | + self.statusLabel.text = @"Pull down to refresh"; |
244 | + self.statusLabel.alpha = 1.0f; |
245 | + [self.activityIndicatorView stopAnimating]; |
246 | + self.activityIndicatorView.alpha = 0.0f; |
247 | + break; |
248 | + } |
249 | + |
250 | + case SSPullToRefreshViewStateLoading: { |
251 | + self.statusLabel.alpha = 0.0f; |
252 | + [self.activityIndicatorView startAnimating]; |
253 | + self.activityIndicatorView.alpha = 1.0f; |
254 | + break; |
255 | + } |
256 | + |
257 | + case SSPullToRefreshViewStateClosing: { |
258 | + self.statusLabel.text = nil; |
259 | + self.activityIndicatorView.alpha = 0.0f; |
260 | + break; |
261 | + } |
262 | + } |
263 | +} |
264 | + |
265 | +@end |
266 | |
267 | === added file 'Dependencies/SSPullToRefresh/SSPullToRefreshView.h' |
268 | --- Dependencies/SSPullToRefresh/SSPullToRefreshView.h 1970-01-01 00:00:00 +0000 |
269 | +++ Dependencies/SSPullToRefresh/SSPullToRefreshView.h 2013-02-11 04:30:25 +0000 |
270 | @@ -0,0 +1,205 @@ |
271 | +// |
272 | +// SSPullToRefreshView.h |
273 | +// SSPullToRefresh |
274 | +// |
275 | +// Created by Sam Soffes on 4/9/12. |
276 | +// Copyright (c) 2012 Sam Soffes. All rights reserved. |
277 | +// |
278 | + |
279 | +// |
280 | +// Example usage: |
281 | +// |
282 | +// - (void)viewDidLoad { |
283 | +// [super viewDidLoad]; |
284 | +// self.pullToRefreshView = [[SSPullToRefreshView alloc] initWithScrollView:self.tableView delegate:self]; |
285 | +// } |
286 | +// |
287 | +// - (void)viewDidUnload { |
288 | +// [super viewDidUnload]; |
289 | +// self.pullToRefreshView = nil; |
290 | +// } |
291 | +// |
292 | +// - (void)refresh { |
293 | +// [self.pullToRefreshView startLoading]; |
294 | +// // Load data... |
295 | +// [self.pullToRefreshView finishLoading]; |
296 | +// } |
297 | +// |
298 | +// - (void)pullToRefreshViewDidStartLoading:(SSPullToRefreshView *)view { |
299 | +// [self refresh]; |
300 | +// } |
301 | +// |
302 | + |
303 | +typedef enum { |
304 | + /// Most will say "Pull to refresh" in this state |
305 | + SSPullToRefreshViewStateNormal, |
306 | + |
307 | + /// Most will say "Release to refresh" in this state |
308 | + SSPullToRefreshViewStateReady, |
309 | + |
310 | + /// The view is loading |
311 | + SSPullToRefreshViewStateLoading, |
312 | + |
313 | + /// The view has finished loading and is animating |
314 | + SSPullToRefreshViewStateClosing |
315 | +} SSPullToRefreshViewState; |
316 | + |
317 | +@protocol SSPullToRefreshViewDelegate; |
318 | +@protocol SSPullToRefreshContentView; |
319 | + |
320 | +@interface SSPullToRefreshView : UIView |
321 | + |
322 | +/** |
323 | + The content view displayed when the `scrollView` is pulled down. By default this is an instance of `SSPullToRefreshDefaultContentView`. |
324 | + |
325 | + @see SSPullToRefreshContentView |
326 | + */ |
327 | +@property (nonatomic, strong) UIView<SSPullToRefreshContentView> *contentView; |
328 | + |
329 | +/** |
330 | + If you need to update the scroll view's content inset while it contains a pull to refresh view, you should set the |
331 | + `defaultContentInset` on the pull to refresh view and it will forward it to the scroll view taking into account the |
332 | + pull to refresh view's position. |
333 | + */ |
334 | +@property (nonatomic, assign) UIEdgeInsets defaultContentInset; |
335 | + |
336 | +/** |
337 | + The height of the fully expanded content view. The default is `70.0`. |
338 | + |
339 | + The `contentView`'s `sizeThatFits:` will be respected when displayed but does not effect the expanded height. You can use this |
340 | + to draw outside of the expanded area. If you don't implement `sizeThatFits:` it will automatically display at the default size. |
341 | + |
342 | + @see expanded |
343 | + */ |
344 | +@property (nonatomic, assign) CGFloat expandedHeight; |
345 | + |
346 | +/** |
347 | + A boolean indicating if the pull to refresh view is expanded. |
348 | + |
349 | + @see expandedHeight |
350 | + @see startLoadingAndExpand: |
351 | + */ |
352 | +@property (nonatomic, assign, readonly, getter = isExpanded) BOOL expanded; |
353 | + |
354 | +/** |
355 | + The scroll view containing the pull to refresh view. This is automatically set with `initWithScrollView:delegate:`. |
356 | + |
357 | + @see initWithScrollView:delegate: |
358 | + */ |
359 | +@property (nonatomic, assign, readonly) UIScrollView *scrollView; |
360 | + |
361 | +/** |
362 | + The delegate is sent messages when the pull to refresh view starts loading. This is automatically set with `initWithScrollView:delegate:`. |
363 | + |
364 | + @see initWithScrollView:delegate: |
365 | + @see SSPullToRefreshViewDelegate |
366 | + */ |
367 | +@property (nonatomic, weak) id<SSPullToRefreshViewDelegate> delegate; |
368 | + |
369 | +/** |
370 | + The state of the pull to refresh view. |
371 | + |
372 | + @see startLoading |
373 | + @see startLoadingAndExpand: |
374 | + @see finishLoading |
375 | + @see SSPullToRefreshViewState |
376 | + */ |
377 | +@property (nonatomic, assign, readonly) SSPullToRefreshViewState state; |
378 | + |
379 | +/** |
380 | + All you need to do to add this view to your scroll view is call this method (passing in the scroll view). That's it. |
381 | + You don't have to add it as subview or anything else. The rest is magic. |
382 | + |
383 | + You should only initalize with this method and never move it to another scroll view during its lifetime. |
384 | + */ |
385 | +- (id)initWithScrollView:(UIScrollView *)scrollView delegate:(id<SSPullToRefreshViewDelegate>)delegate; |
386 | + |
387 | +/** |
388 | + Call this method when you start loading. If you trigger loading another way besides pulling to refresh, call this |
389 | + method so the pull to refresh view will be in sync with the loading status. By default, it will not expand the view |
390 | + so it loads quietly out of view. |
391 | + */ |
392 | +- (void)startLoading; |
393 | + |
394 | +/** |
395 | + Call this method when you start loading. If you trigger loading another way besides pulling to refresh, call this |
396 | + method so the pull to refresh view will be in sync with the loading status. You may pass YES for shouldExpand to |
397 | + animate down the pull to refresh view to show that it's loading. |
398 | + */ |
399 | +- (void)startLoadingAndExpand:(BOOL)shouldExpand; |
400 | +/** |
401 | + Call this method if you wish to control animating the expansion. |
402 | + */ |
403 | +- (void)startLoadingAndExpand:(BOOL)shouldExpand animated:(BOOL)animated; |
404 | + |
405 | +/** |
406 | + Call this when you finish loading. |
407 | + */ |
408 | +- (void)finishLoading; |
409 | + |
410 | +/** |
411 | + Manually update the last updated at time. This will automatically get called when the pull to refresh view finishes laoding. |
412 | + */ |
413 | +- (void)refreshLastUpdatedAt; |
414 | + |
415 | +@end |
416 | + |
417 | + |
418 | +@protocol SSPullToRefreshViewDelegate <NSObject> |
419 | + |
420 | +@optional |
421 | + |
422 | +/** |
423 | + Return `NO` if the pull to refresh view should no start loading. |
424 | + */ |
425 | +- (BOOL)pullToRefreshViewShouldStartLoading:(SSPullToRefreshView *)view; |
426 | + |
427 | +/** |
428 | + The pull to refresh view started loading. You should kick off whatever you need to load when this is called. |
429 | + */ |
430 | +- (void)pullToRefreshViewDidStartLoading:(SSPullToRefreshView *)view; |
431 | + |
432 | +/** |
433 | + The pull to refresh view finished loading. This will get called when it receives `finishLoading`. |
434 | + */ |
435 | +- (void)pullToRefreshViewDidFinishLoading:(SSPullToRefreshView *)view; |
436 | + |
437 | +/** |
438 | + The date when data was last updated. This will get called when it finishes loading or if it receives `refreshLastUpdatedAt`. |
439 | + Some content views may display this date. |
440 | + */ |
441 | +- (NSDate *)pullToRefreshViewLastUpdatedAt:(SSPullToRefreshView *)view; |
442 | + |
443 | +/** |
444 | + The pull to refresh view updated its scroll view's content inset |
445 | + */ |
446 | +- (void)pullToRefreshView:(SSPullToRefreshView *)view didUpdateContentInset:(UIEdgeInsets)contentInset; |
447 | + |
448 | +@end |
449 | + |
450 | + |
451 | +@protocol SSPullToRefreshContentView <NSObject> |
452 | + |
453 | +@required |
454 | + |
455 | +/** |
456 | + The pull to refresh view's state has changed. The content view must update itself. All content view's must implement |
457 | + this method. |
458 | + */ |
459 | +- (void)setState:(SSPullToRefreshViewState)state withPullToRefreshView:(SSPullToRefreshView *)view; |
460 | + |
461 | +@optional |
462 | + |
463 | +/** |
464 | + The pull to refresh view will set send values from `0.0` to `1.0` as the user pulls down. `1.0` means it is fully expanded and |
465 | + will change to the `SSPullToRefreshViewStateReady` state. You can use this value to draw the progress of the pull |
466 | + (i.e. Tweetbot style). |
467 | + */ |
468 | +- (void)setPullProgress:(CGFloat)pullProgress; |
469 | + |
470 | +/** |
471 | + The pull to refresh view updated its last updated date. |
472 | + */ |
473 | +- (void)setLastUpdatedAt:(NSDate *)date withPullToRefreshView:(SSPullToRefreshView *)view; |
474 | + |
475 | +@end |
476 | |
477 | === added file 'Dependencies/SSPullToRefresh/SSPullToRefreshView.m' |
478 | --- Dependencies/SSPullToRefresh/SSPullToRefreshView.m 1970-01-01 00:00:00 +0000 |
479 | +++ Dependencies/SSPullToRefresh/SSPullToRefreshView.m 2013-02-11 04:30:25 +0000 |
480 | @@ -0,0 +1,349 @@ |
481 | +// |
482 | +// SSPullToRefreshView.m |
483 | +// SSPullToRefresh |
484 | +// |
485 | +// Created by Sam Soffes on 4/9/12. |
486 | +// Copyright (c) 2012 Sam Soffes. All rights reserved. |
487 | +// |
488 | + |
489 | +#import "SSPullToRefreshView.h" |
490 | +#import "SSPullToRefreshDefaultContentView.h" |
491 | + |
492 | +@interface SSPullToRefreshView () |
493 | +@property (nonatomic, assign, readwrite) SSPullToRefreshViewState state; |
494 | +@property (nonatomic, assign, readwrite) UIScrollView *scrollView; |
495 | +@property (nonatomic, assign, readwrite, getter = isExpanded) BOOL expanded; |
496 | +- (void)_setContentInsetTop:(CGFloat)topInset; |
497 | +- (void)_setState:(SSPullToRefreshViewState)state animated:(BOOL)animated expanded:(BOOL)expanded completion:(void (^)(void))completion; |
498 | +- (void)_setPullProgress:(CGFloat)pullProgress; |
499 | +@end |
500 | + |
501 | +@implementation SSPullToRefreshView { |
502 | + dispatch_semaphore_t _animationSemaphore; |
503 | + CGFloat _topInset; |
504 | +} |
505 | + |
506 | +@synthesize delegate = _delegate; |
507 | +@synthesize scrollView = _scrollView; |
508 | +@synthesize expandedHeight = _expandedHeight; |
509 | +@synthesize contentView = _contentView; |
510 | +@synthesize state = _state; |
511 | +@synthesize expanded = _expanded; |
512 | +@synthesize defaultContentInset = _defaultContentInset; |
513 | + |
514 | + |
515 | +#pragma mark - Accessors |
516 | + |
517 | +- (void)setState:(SSPullToRefreshViewState)state { |
518 | + BOOL wasLoading = _state == SSPullToRefreshViewStateLoading; |
519 | + _state = state; |
520 | + |
521 | + // Forward to content view |
522 | + [self.contentView setState:_state withPullToRefreshView:self]; |
523 | + |
524 | + // Update delegate |
525 | + if (wasLoading && _state != SSPullToRefreshViewStateLoading) { |
526 | + if ([_delegate respondsToSelector:@selector(pullToRefreshViewDidFinishLoading:)]) { |
527 | + [_delegate pullToRefreshViewDidFinishLoading:self]; |
528 | + } |
529 | + } else if (!wasLoading && _state == SSPullToRefreshViewStateLoading) { |
530 | + [self _setPullProgress:1.0f]; |
531 | + if ([_delegate respondsToSelector:@selector(pullToRefreshViewDidStartLoading:)]) { |
532 | + [_delegate pullToRefreshViewDidStartLoading:self]; |
533 | + } |
534 | + } |
535 | +} |
536 | + |
537 | + |
538 | +- (void)setExpanded:(BOOL)expanded { |
539 | + _expanded = expanded; |
540 | + [self _setContentInsetTop:expanded ? self.expandedHeight : 0.0f]; |
541 | +} |
542 | + |
543 | + |
544 | +- (void)setScrollView:(UIScrollView *)scrollView { |
545 | + void *context = (__bridge void *)self; |
546 | + if ([_scrollView respondsToSelector:@selector(removeObserver:forKeyPath:context:)]) { |
547 | + [_scrollView removeObserver:self forKeyPath:@"contentOffset" context:context]; |
548 | + } else if (_scrollView) { |
549 | + [_scrollView removeObserver:self forKeyPath:@"contentOffset"]; |
550 | + } |
551 | + |
552 | + _scrollView = scrollView; |
553 | + _defaultContentInset = _scrollView.contentInset; |
554 | + [_scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:context]; |
555 | +} |
556 | + |
557 | + |
558 | +- (UIView<SSPullToRefreshContentView> *)contentView { |
559 | + // Use the simple content view as the default |
560 | + if (!_contentView) { |
561 | + self.contentView = [[SSPullToRefreshDefaultContentView alloc] initWithFrame:CGRectZero]; |
562 | + } |
563 | + return _contentView; |
564 | +} |
565 | + |
566 | + |
567 | +- (void)setContentView:(UIView<SSPullToRefreshContentView> *)contentView { |
568 | + [_contentView removeFromSuperview]; |
569 | + _contentView = contentView; |
570 | + |
571 | + _contentView.autoresizingMask = UIViewAutoresizingNone; |
572 | + [_contentView setState:_state withPullToRefreshView:self]; |
573 | + [self refreshLastUpdatedAt]; |
574 | + [self addSubview:_contentView]; |
575 | +} |
576 | + |
577 | + |
578 | +- (void)setDefaultContentInset:(UIEdgeInsets)defaultContentInset { |
579 | + _defaultContentInset = defaultContentInset; |
580 | + [self _setContentInsetTop:_topInset]; |
581 | +} |
582 | + |
583 | + |
584 | +#pragma mark - NSObject |
585 | + |
586 | +- (void)dealloc { |
587 | + self.scrollView = nil; |
588 | + self.delegate = nil; |
589 | +#if !OS_OBJECT_USE_OBJC |
590 | + dispatch_release(_animationSemaphore); |
591 | +#endif |
592 | +} |
593 | + |
594 | + |
595 | +#pragma mark - UIView |
596 | + |
597 | +- (void)removeFromSuperview { |
598 | + self.scrollView = nil; |
599 | + [super removeFromSuperview]; |
600 | +} |
601 | + |
602 | + |
603 | +- (void)layoutSubviews { |
604 | + CGSize size = self.bounds.size; |
605 | + CGSize contentSize = [self.contentView sizeThatFits:size]; |
606 | + |
607 | + if (contentSize.width < size.width) { |
608 | + contentSize.width = size.width; |
609 | + } |
610 | + |
611 | + if (contentSize.height < _expandedHeight) { |
612 | + contentSize.height = _expandedHeight; |
613 | + } |
614 | + |
615 | + self.contentView.frame = CGRectMake(roundf((size.width - contentSize.width) / 2.0f), size.height - contentSize.height, contentSize.width, contentSize.height); |
616 | +} |
617 | + |
618 | + |
619 | +#pragma mark - Initializer |
620 | + |
621 | +- (id)initWithScrollView:(UIScrollView *)scrollView delegate:(id<SSPullToRefreshViewDelegate>)delegate { |
622 | + CGRect frame = CGRectMake(0.0f, 0.0f - scrollView.bounds.size.height, scrollView.bounds.size.width, |
623 | + scrollView.bounds.size.height); |
624 | + if ((self = [self initWithFrame:frame])) { |
625 | + self.autoresizingMask = UIViewAutoresizingFlexibleWidth; |
626 | + self.scrollView = scrollView; |
627 | + self.delegate = delegate; |
628 | + self.state = SSPullToRefreshViewStateNormal; |
629 | + self.expandedHeight = 70.0f; |
630 | + |
631 | + for (UIView *view in self.scrollView.subviews) { |
632 | + if ([view isKindOfClass:[SSPullToRefreshView class]]) { |
633 | + [[NSException exceptionWithName:@"SSPullToRefreshViewAlreadyAdded" reason:@"There is already a SSPullToRefreshView added to this scroll view. Unexpected things will happen. Don't do this." userInfo:nil] raise]; |
634 | + } |
635 | + } |
636 | + |
637 | + // Add to scroll view |
638 | + [self.scrollView addSubview:self]; |
639 | + |
640 | + // Semaphore is used to ensure only one animation plays at a time |
641 | + _animationSemaphore = dispatch_semaphore_create(0); |
642 | + dispatch_semaphore_signal(_animationSemaphore); |
643 | + } |
644 | + return self; |
645 | +} |
646 | + |
647 | + |
648 | +#pragma mark - Loading |
649 | + |
650 | +- (void)startLoading { |
651 | + [self startLoadingAndExpand:NO animated:NO]; |
652 | +} |
653 | + |
654 | + |
655 | +- (void)startLoadingAndExpand:(BOOL)shouldExpand { |
656 | + [self startLoadingAndExpand:shouldExpand animated:YES]; |
657 | +} |
658 | + |
659 | + |
660 | +- (void)startLoadingAndExpand:(BOOL)shouldExpand animated:(BOOL)animated { |
661 | + // If we're not loading, this method has no effect |
662 | + if (_state == SSPullToRefreshViewStateLoading) { |
663 | + return; |
664 | + } |
665 | + |
666 | + // Animate back to the loading state |
667 | + [self _setState:SSPullToRefreshViewStateLoading animated:animated expanded:shouldExpand completion:nil]; |
668 | +} |
669 | + |
670 | + |
671 | +- (void)finishLoading { |
672 | + // If we're not loading, this method has no effect |
673 | + if (_state != SSPullToRefreshViewStateLoading) { |
674 | + return; |
675 | + } |
676 | + |
677 | + // Animate back to the normal state |
678 | + __weak SSPullToRefreshView *blockSelf = self; |
679 | + [self _setState:SSPullToRefreshViewStateClosing animated:YES expanded:NO completion:^{ |
680 | + blockSelf.state = SSPullToRefreshViewStateNormal; |
681 | + }]; |
682 | +} |
683 | + |
684 | + |
685 | +- (void)refreshLastUpdatedAt { |
686 | + NSDate *date = nil; |
687 | + if ([_delegate respondsToSelector:@selector(pullToRefreshViewLastUpdatedAt:)]) { |
688 | + date = [_delegate pullToRefreshViewLastUpdatedAt:self]; |
689 | + } else { |
690 | + date = [NSDate date]; |
691 | + } |
692 | + |
693 | + // Forward to content view |
694 | + if ([self.contentView respondsToSelector:@selector(setLastUpdatedAt:withPullToRefreshView:)]) { |
695 | + [self.contentView setLastUpdatedAt:date withPullToRefreshView:self]; |
696 | + } |
697 | +} |
698 | + |
699 | + |
700 | +#pragma mark - Private |
701 | + |
702 | +- (void)_setContentInsetTop:(CGFloat)topInset { |
703 | + _topInset = topInset; |
704 | + |
705 | + // Default to the scroll view's initial content inset |
706 | + UIEdgeInsets inset = _defaultContentInset; |
707 | + |
708 | + // Add the top inset |
709 | + inset.top += _topInset; |
710 | + |
711 | + // Don't set it if that is already the current inset |
712 | + if (UIEdgeInsetsEqualToEdgeInsets(_scrollView.contentInset, inset)) { |
713 | + return; |
714 | + } |
715 | + |
716 | + // Update the content inset |
717 | + _scrollView.contentInset = inset; |
718 | + |
719 | + // If scrollView is on top, scroll again to the top (needed for scrollViews with content > scrollView). |
720 | + if (_scrollView.contentOffset.y == 0) { |
721 | + [_scrollView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; |
722 | + } |
723 | + |
724 | + // Tell the delegate |
725 | + if ([self.delegate respondsToSelector:@selector(pullToRefreshView:didUpdateContentInset:)]) { |
726 | + [self.delegate pullToRefreshView:self didUpdateContentInset:_scrollView.contentInset]; |
727 | + } |
728 | +} |
729 | + |
730 | + |
731 | +- (void)_setState:(SSPullToRefreshViewState)state animated:(BOOL)animated expanded:(BOOL)expanded completion:(void (^)(void))completion { |
732 | + if (!animated) { |
733 | + self.state = state; |
734 | + self.expanded = expanded; |
735 | + |
736 | + if (completion) { |
737 | + completion(); |
738 | + } |
739 | + return; |
740 | + } |
741 | + |
742 | + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ |
743 | + dispatch_semaphore_wait(_animationSemaphore, DISPATCH_TIME_FOREVER); |
744 | + dispatch_async(dispatch_get_main_queue(), ^{ |
745 | + [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^{ |
746 | + self.state = state; |
747 | + self.expanded = expanded; |
748 | + } completion:^(BOOL finished) { |
749 | + dispatch_semaphore_signal(_animationSemaphore); |
750 | + if (completion) { |
751 | + completion(); |
752 | + } |
753 | + }]; |
754 | + }); |
755 | + }); |
756 | +} |
757 | + |
758 | + |
759 | +- (void)_setPullProgress:(CGFloat)pullProgress { |
760 | + if ([self.contentView respondsToSelector:@selector(setPullProgress:)]) { |
761 | + [self.contentView setPullProgress:pullProgress]; |
762 | + } |
763 | +} |
764 | + |
765 | + |
766 | +#pragma mark - NSKeyValueObserving |
767 | + |
768 | +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { |
769 | + // Call super if we didn't register for this notification |
770 | + if (context != (__bridge void *)self) { |
771 | + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; |
772 | + return; |
773 | + } |
774 | + |
775 | + // We don't care about this notificaiton |
776 | + if (object != _scrollView || ![keyPath isEqualToString:@"contentOffset"]) { |
777 | + return; |
778 | + } |
779 | + |
780 | + // Get the offset out of the change notification |
781 | + CGFloat y = [[change objectForKey:NSKeyValueChangeNewKey] CGPointValue].y + _defaultContentInset.top; |
782 | + |
783 | + // Scroll view is dragging |
784 | + if (_scrollView.isDragging) { |
785 | + // Scroll view is ready |
786 | + if (_state == SSPullToRefreshViewStateReady) { |
787 | + // Dragged enough to refresh |
788 | + if (y > -_expandedHeight && y < 0.0f) { |
789 | + self.state = SSPullToRefreshViewStateNormal; |
790 | + } |
791 | + // Scroll view is normal |
792 | + } else if (_state == SSPullToRefreshViewStateNormal) { |
793 | + // Update the content view's pulling progressing |
794 | + [self _setPullProgress:-y / _expandedHeight]; |
795 | + |
796 | + // Dragged enough to be ready |
797 | + if (y < -_expandedHeight) { |
798 | + self.state = SSPullToRefreshViewStateReady; |
799 | + } |
800 | + // Scroll view is loading |
801 | + } else if (_state == SSPullToRefreshViewStateLoading) { |
802 | + [self _setContentInsetTop:_expandedHeight]; |
803 | + } |
804 | + return; |
805 | + } |
806 | + |
807 | + // If the scroll view isn't ready, we're not interested |
808 | + if (_state != SSPullToRefreshViewStateReady) { |
809 | + return; |
810 | + } |
811 | + |
812 | + // We're ready, prepare to switch to loading. Be default, we should refresh. |
813 | + SSPullToRefreshViewState newState = SSPullToRefreshViewStateLoading; |
814 | + |
815 | + // Ask the delegate if it's cool to start loading |
816 | + BOOL expand = YES; |
817 | + if ([_delegate respondsToSelector:@selector(pullToRefreshViewShouldStartLoading:)]) { |
818 | + if (![_delegate pullToRefreshViewShouldStartLoading:self]) { |
819 | + // Animate back to normal since the delegate said no |
820 | + newState = SSPullToRefreshViewStateNormal; |
821 | + expand = NO; |
822 | + } |
823 | + } |
824 | + |
825 | + // Animate to the new state |
826 | + [self _setState:newState animated:YES expanded:expand completion:nil]; |
827 | +} |
828 | + |
829 | +@end |
830 | |
831 | === modified file 'Music/Models/Album.h' |
832 | --- Music/Models/Album.h 2013-01-24 19:08:51 +0000 |
833 | +++ Music/Models/Album.h 2013-02-11 04:30:25 +0000 |
834 | @@ -27,4 +27,6 @@ |
835 | |
836 | @property (nonatomic, retain) NSSet *songs; |
837 | |
838 | +- (NSSet *)songsForArtistId:(NSString *)artistId; |
839 | + |
840 | @end |
841 | |
842 | === modified file 'Music/Models/Album.m' |
843 | --- Music/Models/Album.m 2013-01-24 19:08:51 +0000 |
844 | +++ Music/Models/Album.m 2013-02-11 04:30:25 +0000 |
845 | @@ -28,6 +28,11 @@ |
846 | |
847 | @dynamic songs; |
848 | |
849 | +- (NSSet *)songsForArtistId:(NSString *)_artistId { |
850 | + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"artist.artistId == %@ OR albumArtist.artistId == %@", _artistId, _artistId]; |
851 | + return [self.songs filteredSetUsingPredicate:predicate]; |
852 | +} |
853 | + |
854 | #pragma mark - UOModel methods |
855 | |
856 | + (RKEntityMapping *)objectMapping { |
857 | |
858 | === modified file 'Music/Storyboard_iPhone.storyboard' |
859 | --- Music/Storyboard_iPhone.storyboard 2013-02-11 04:30:25 +0000 |
860 | +++ Music/Storyboard_iPhone.storyboard 2013-02-11 04:30:25 +0000 |
861 | @@ -44,17 +44,17 @@ |
862 | <rect key="frame" x="0.0" y="0.0" width="320" height="43"/> |
863 | <autoresizingMask key="autoresizingMask"/> |
864 | <subviews> |
865 | - <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Wy4-11-qhh"> |
866 | - <rect key="frame" x="53" y="2" width="38" height="22"/> |
867 | + <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Artist" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Wy4-11-qhh"> |
868 | + <rect key="frame" x="53" y="1" width="45" height="23"/> |
869 | <autoresizingMask key="autoresizingMask"/> |
870 | - <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/> |
871 | + <fontDescription key="fontDescription" name="HelveticaNeue-Medium" family="Helvetica Neue" pointSize="18"/> |
872 | <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> |
873 | <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> |
874 | </label> |
875 | - <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="PUO-bG-eLt"> |
876 | - <rect key="frame" x="53" y="24" width="47" height="18"/> |
877 | + <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="2 albums" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="PUO-bG-eLt"> |
878 | + <rect key="frame" x="53" y="24" width="56" height="18"/> |
879 | <autoresizingMask key="autoresizingMask"/> |
880 | - <fontDescription key="fontDescription" type="system" pointSize="14"/> |
881 | + <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="14"/> |
882 | <color key="textColor" red="0.50196078431372548" green="0.50196078431372548" blue="0.50196078431372548" alpha="1" colorSpace="calibratedRGB"/> |
883 | <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> |
884 | </label> |
885 | @@ -86,7 +86,7 @@ |
886 | </objects> |
887 | <point key="canvasLocation" x="1047" y="-56"/> |
888 | </scene> |
889 | - <!--Artist View Controller--> |
890 | + <!--Artist View Controller - Artist--> |
891 | <scene sceneID="Y3A-G3-aF2"> |
892 | <objects> |
893 | <viewController storyboardIdentifier="ArtistViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="EDS-Dj-fjS" customClass="ArtistViewController" sceneMemberID="viewController"> |
894 | @@ -106,17 +106,17 @@ |
895 | <rect key="frame" x="0.0" y="0.0" width="320" height="43"/> |
896 | <autoresizingMask key="autoresizingMask"/> |
897 | <subviews> |
898 | - <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="G72-IX-jh9"> |
899 | - <rect key="frame" x="53" y="2" width="38" height="22"/> |
900 | + <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Album" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="G72-IX-jh9"> |
901 | + <rect key="frame" x="53" y="1" width="54" height="23"/> |
902 | <autoresizingMask key="autoresizingMask"/> |
903 | - <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/> |
904 | + <fontDescription key="fontDescription" name="HelveticaNeue-Medium" family="Helvetica Neue" pointSize="18"/> |
905 | <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> |
906 | <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> |
907 | </label> |
908 | - <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="VIc-Rn-YXm"> |
909 | - <rect key="frame" x="53" y="24" width="47" height="18"/> |
910 | + <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="11 songs" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="VIc-Rn-YXm"> |
911 | + <rect key="frame" x="53" y="24" width="57" height="18"/> |
912 | <autoresizingMask key="autoresizingMask"/> |
913 | - <fontDescription key="fontDescription" type="system" pointSize="14"/> |
914 | + <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="14"/> |
915 | <color key="textColor" red="0.50196078431372548" green="0.50196078431372548" blue="0.50196078431372548" alpha="1" colorSpace="calibratedRGB"/> |
916 | <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> |
917 | </label> |
918 | @@ -133,29 +133,29 @@ |
919 | </tableViewCell> |
920 | </prototypes> |
921 | </tableView> |
922 | - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" id="7CD-jP-Egt"> |
923 | - <rect key="frame" x="0.0" y="0.0" width="120" height="120"/> |
924 | + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="default-album-art-200.png" id="7CD-jP-Egt"> |
925 | + <rect key="frame" x="5" y="5" width="110" height="110"/> |
926 | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
927 | </imageView> |
928 | <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Artist" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="00M-r3-Ezp"> |
929 | - <rect key="frame" x="128" y="15" width="192" height="26"/> |
930 | + <rect key="frame" x="123" y="5" width="172" height="26"/> |
931 | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
932 | - <fontDescription key="fontDescription" type="system" pointSize="18"/> |
933 | + <fontDescription key="fontDescription" name="HelveticaNeue-Medium" family="Helvetica Neue" pointSize="18"/> |
934 | <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> |
935 | <nil key="highlightedColor"/> |
936 | <color key="shadowColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> |
937 | </label> |
938 | - <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="6 Albums" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="25K-Tf-YSQ"> |
939 | - <rect key="frame" x="128" y="49" width="63" height="21"/> |
940 | + <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="2 Albums" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="25K-Tf-YSQ"> |
941 | + <rect key="frame" x="123" y="39" width="172" height="21"/> |
942 | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
943 | - <fontDescription key="fontDescription" type="system" pointSize="15"/> |
944 | + <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="15"/> |
945 | <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> |
946 | <color key="highlightedColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> |
947 | </label> |
948 | </subviews> |
949 | <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> |
950 | </view> |
951 | - <navigationItem key="navigationItem" id="OM6-Kh-nGV"> |
952 | + <navigationItem key="navigationItem" title="Artist" id="OM6-Kh-nGV"> |
953 | <barButtonItem key="rightBarButtonItem" title="Now Playing" id="tdG-O0-4fc"> |
954 | <connections> |
955 | <segue destination="hRX-A4-gMJ" kind="modal" id="dlu-4W-myG"/> |
956 | @@ -174,7 +174,7 @@ |
957 | </objects> |
958 | <point key="canvasLocation" x="1515" y="-56"/> |
959 | </scene> |
960 | - <!--Album View Controller--> |
961 | + <!--Album View Controller - Album--> |
962 | <scene sceneID="24B-tK-YA0"> |
963 | <objects> |
964 | <viewController storyboardIdentifier="AlbumViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" id="8Ya-S8-w02" customClass="AlbumViewController" sceneMemberID="viewController"> |
965 | @@ -214,14 +214,14 @@ |
966 | <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="60:00" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="6u8-pY-Fu0"> |
967 | <rect key="frame" x="242" y="10" width="46" height="21"/> |
968 | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
969 | - <fontDescription key="fontDescription" type="system" pointSize="12"/> |
970 | + <fontDescription key="fontDescription" name="HelveticaNeue-Medium" family="Helvetica Neue" pointSize="12"/> |
971 | <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> |
972 | <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/> |
973 | </label> |
974 | <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QJk-JO-Hhy"> |
975 | - <rect key="frame" x="20" y="10" width="198" height="21"/> |
976 | + <rect key="frame" x="20" y="8" width="198" height="27"/> |
977 | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
978 | - <fontDescription key="fontDescription" type="boldSystem" pointSize="16"/> |
979 | + <fontDescription key="fontDescription" name="HelveticaNeue-Medium" family="Helvetica Neue" pointSize="18"/> |
980 | <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> |
981 | <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/> |
982 | </label> |
983 | @@ -250,29 +250,29 @@ |
984 | </tableViewCell> |
985 | </prototypes> |
986 | </tableView> |
987 | - <imageView userInteractionEnabled="NO" contentMode="scaleToFill" id="1ZL-7v-l7S"> |
988 | - <rect key="frame" x="0.0" y="0.0" width="120" height="120"/> |
989 | + <imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="default-album-art-200.png" id="1ZL-7v-l7S"> |
990 | + <rect key="frame" x="5" y="5" width="110" height="110"/> |
991 | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
992 | </imageView> |
993 | <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Album" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="dwO-gw-nTE"> |
994 | - <rect key="frame" x="128" y="15" width="192" height="26"/> |
995 | + <rect key="frame" x="123" y="5" width="192" height="26"/> |
996 | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
997 | - <fontDescription key="fontDescription" type="system" pointSize="18"/> |
998 | + <fontDescription key="fontDescription" name="HelveticaNeue-Medium" family="Helvetica Neue" pointSize="18"/> |
999 | <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> |
1000 | <nil key="highlightedColor"/> |
1001 | <color key="shadowColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> |
1002 | </label> |
1003 | <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Artist" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="G01-4v-qdB"> |
1004 | - <rect key="frame" x="128" y="49" width="63" height="21"/> |
1005 | + <rect key="frame" x="123" y="39" width="172" height="21"/> |
1006 | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
1007 | - <fontDescription key="fontDescription" type="system" pointSize="15"/> |
1008 | + <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="15"/> |
1009 | <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> |
1010 | <color key="highlightedColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/> |
1011 | </label> |
1012 | </subviews> |
1013 | <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> |
1014 | </view> |
1015 | - <navigationItem key="navigationItem" id="a61-1v-dxt"> |
1016 | + <navigationItem key="navigationItem" title="Album" id="a61-1v-dxt"> |
1017 | <barButtonItem key="rightBarButtonItem" title="Now Playing" id="wGH-uZ-TGk"> |
1018 | <connections> |
1019 | <segue destination="hRX-A4-gMJ" kind="modal" identifier="NowPlayingSegue" id="YJd-qV-EXm"/> |
1020 | @@ -395,7 +395,7 @@ |
1021 | <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="0:00" textAlignment="right" lineBreakMode="tailTruncation" minimumFontSize="10" id="pNU-Jr-yiV"> |
1022 | <rect key="frame" x="12" y="31" width="42" height="15"/> |
1023 | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
1024 | - <fontDescription key="fontDescription" name="Helvetica-Bold" family="Helvetica" pointSize="14"/> |
1025 | + <fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="14"/> |
1026 | <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/> |
1027 | <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/> |
1028 | <color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/> |
1029 | @@ -403,7 +403,7 @@ |
1030 | <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="10:00" lineBreakMode="tailTruncation" minimumFontSize="10" id="fsV-6P-1Kb"> |
1031 | <rect key="frame" x="266" y="31" width="42" height="15"/> |
1032 | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
1033 | - <fontDescription key="fontDescription" name="Helvetica-Bold" family="Helvetica" pointSize="14"/> |
1034 | + <fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="14"/> |
1035 | <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/> |
1036 | <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/> |
1037 | <color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/> |
1038 | @@ -411,7 +411,7 @@ |
1039 | <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="3 of 100" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" id="KsY-jo-7df"> |
1040 | <rect key="frame" x="12" y="5" width="296" height="19"/> |
1041 | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
1042 | - <fontDescription key="fontDescription" name="Helvetica-Bold" family="Helvetica" pointSize="14"/> |
1043 | + <fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="14"/> |
1044 | <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/> |
1045 | <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/> |
1046 | <color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/> |
1047 | @@ -528,17 +528,17 @@ |
1048 | <rect key="frame" x="0.0" y="0.0" width="320" height="43"/> |
1049 | <autoresizingMask key="autoresizingMask"/> |
1050 | <subviews> |
1051 | - <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="lHq-bS-Zm9"> |
1052 | - <rect key="frame" x="53" y="2" width="38" height="22"/> |
1053 | + <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Album" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="lHq-bS-Zm9"> |
1054 | + <rect key="frame" x="53" y="1" width="54" height="23"/> |
1055 | <autoresizingMask key="autoresizingMask"/> |
1056 | - <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/> |
1057 | + <fontDescription key="fontDescription" name="HelveticaNeue-Medium" family="Helvetica Neue" pointSize="18"/> |
1058 | <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> |
1059 | <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> |
1060 | </label> |
1061 | - <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="03B-YT-E7s"> |
1062 | - <rect key="frame" x="53" y="24" width="47" height="18"/> |
1063 | + <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Artist" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="03B-YT-E7s"> |
1064 | + <rect key="frame" x="53" y="24" width="31" height="18"/> |
1065 | <autoresizingMask key="autoresizingMask"/> |
1066 | - <fontDescription key="fontDescription" type="system" pointSize="14"/> |
1067 | + <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="14"/> |
1068 | <color key="textColor" red="0.50196078431372548" green="0.50196078431372548" blue="0.50196078431372548" alpha="1" colorSpace="calibratedRGB"/> |
1069 | <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> |
1070 | </label> |
1071 | @@ -579,41 +579,35 @@ |
1072 | <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> |
1073 | <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> |
1074 | <prototypes> |
1075 | - <tableViewCell contentMode="scaleToFill" selectionStyle="gray" indentationWidth="10" reuseIdentifier="Cell" id="EzM-5L-53C" customClass="SongCell"> |
1076 | + <tableViewCell contentMode="scaleToFill" selectionStyle="gray" indentationWidth="10" reuseIdentifier="Cell" textLabel="FGV-Wb-IfK" detailTextLabel="i6c-1Q-zdc" imageView="eTE-GK-6eP" style="IBUITableViewCellStyleSubtitle" id="EzM-5L-53C" customClass="SongListCell"> |
1077 | <rect key="frame" x="0.0" y="22" width="320" height="44"/> |
1078 | <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
1079 | <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center"> |
1080 | <rect key="frame" x="0.0" y="0.0" width="320" height="43"/> |
1081 | <autoresizingMask key="autoresizingMask"/> |
1082 | <subviews> |
1083 | - <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="00" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="URM-e4-2yc"> |
1084 | - <rect key="frame" x="20" y="11" width="31" height="21"/> |
1085 | - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
1086 | - <fontDescription key="fontDescription" type="boldSystem" pointSize="16"/> |
1087 | - <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> |
1088 | - <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/> |
1089 | - </label> |
1090 | - <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="60:00" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="vws-t4-lyH"> |
1091 | - <rect key="frame" x="254" y="11" width="46" height="21"/> |
1092 | - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
1093 | - <fontDescription key="fontDescription" type="system" pointSize="12"/> |
1094 | - <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> |
1095 | - <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/> |
1096 | - </label> |
1097 | - <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="cHc-6o-Le1"> |
1098 | - <rect key="frame" x="59" y="11" width="198" height="21"/> |
1099 | - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
1100 | - <fontDescription key="fontDescription" type="boldSystem" pointSize="16"/> |
1101 | - <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> |
1102 | - <color key="highlightedColor" white="1" alpha="1" colorSpace="calibratedWhite"/> |
1103 | - </label> |
1104 | + <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="FGV-Wb-IfK"> |
1105 | + <rect key="frame" x="53" y="1" width="36" height="23"/> |
1106 | + <autoresizingMask key="autoresizingMask"/> |
1107 | + <fontDescription key="fontDescription" name="HelveticaNeue-Medium" family="Helvetica Neue" pointSize="18"/> |
1108 | + <color key="textColor" cocoaTouchSystemColor="darkTextColor"/> |
1109 | + <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> |
1110 | + </label> |
1111 | + <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="i6c-1Q-zdc"> |
1112 | + <rect key="frame" x="53" y="24" width="46" height="18"/> |
1113 | + <autoresizingMask key="autoresizingMask"/> |
1114 | + <fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="14"/> |
1115 | + <color key="textColor" red="0.50196078431372548" green="0.50196078431372548" blue="0.50196078431372548" alpha="1" colorSpace="calibratedRGB"/> |
1116 | + <color key="highlightedColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> |
1117 | + </label> |
1118 | + <imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" image="default-album-art-120.png" id="eTE-GK-6eP"> |
1119 | + <rect key="frame" x="0.0" y="0.0" width="43" height="43"/> |
1120 | + <autoresizingMask key="autoresizingMask"/> |
1121 | + </imageView> |
1122 | </subviews> |
1123 | <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> |
1124 | </view> |
1125 | <connections> |
1126 | - <outlet property="clock" destination="vws-t4-lyH" id="Fb3-aG-7Ym"/> |
1127 | - <outlet property="title" destination="cHc-6o-Le1" id="XJD-HL-AWU"/> |
1128 | - <outlet property="track" destination="URM-e4-2yc" id="CNs-EV-tVd"/> |
1129 | <segue destination="hRX-A4-gMJ" kind="modal" id="ebj-wD-yft"/> |
1130 | </connections> |
1131 | </tableViewCell> |
1132 | @@ -960,24 +954,22 @@ |
1133 | </scene> |
1134 | </scenes> |
1135 | <resources> |
1136 | - <image name="03-loopback.png" width="32" height="22"/> |
1137 | - <image name="05-shuffle.png" width="28" height="20"/> |
1138 | - <image name="albums.png" width="30" height="30"/> |
1139 | - <image name="artists.png" width="30" height="30"/> |
1140 | - <image name="default-album-art-120.png" width="60" height="60"/> |
1141 | - <image name="default-album-art-640.png" width="320" height="320"/> |
1142 | - <image name="download-grey.png" width="28" height="28"/> |
1143 | - <image name="download.png" width="28" height="28"/> |
1144 | - <image name="grabber.png" width="22" height="44"/> |
1145 | - <image name="player_overlay_bg.png" width="320" height="100"/> |
1146 | - <image name="playlists.png" width="30" height="30"/> |
1147 | - <image name="settings.png" width="30" height="30"/> |
1148 | - <image name="songs.png" width="30" height="30"/> |
1149 | + <image name="03-loopback.png" width="16" height="16"/> |
1150 | + <image name="05-shuffle.png" width="16" height="16"/> |
1151 | + <image name="albums.png" width="16" height="16"/> |
1152 | + <image name="artists.png" width="16" height="16"/> |
1153 | + <image name="default-album-art-120.png" width="16" height="16"/> |
1154 | + <image name="default-album-art-200.png" width="16" height="16"/> |
1155 | + <image name="default-album-art-640.png" width="16" height="16"/> |
1156 | + <image name="download-grey.png" width="16" height="16"/> |
1157 | + <image name="download.png" width="16" height="16"/> |
1158 | + <image name="grabber.png" width="16" height="16"/> |
1159 | + <image name="player_overlay_bg.png" width="16" height="16"/> |
1160 | + <image name="playlists.png" width="16" height="16"/> |
1161 | + <image name="settings.png" width="16" height="16"/> |
1162 | + <image name="songs.png" width="16" height="16"/> |
1163 | </resources> |
1164 | <classes> |
1165 | - <class className="AlbumCell" superclassName="UITableViewCell"> |
1166 | - <source key="sourceIdentifier" type="project" relativePath="./Classes/AlbumCell.h"/> |
1167 | - </class> |
1168 | <class className="AlbumViewController" superclassName="UIViewController"> |
1169 | <source key="sourceIdentifier" type="project" relativePath="./Classes/AlbumViewController.h"/> |
1170 | <relationships> |
1171 | @@ -988,69 +980,16 @@ |
1172 | <relationship kind="outlet" name="tableView" candidateClass="UITableView"/> |
1173 | </relationships> |
1174 | </class> |
1175 | - <class className="AlbumsViewController" superclassName="UOIndexedViewController"> |
1176 | - <source key="sourceIdentifier" type="project" relativePath="./Classes/AlbumsViewController.h"/> |
1177 | - </class> |
1178 | - <class className="ArtistCell" superclassName="UITableViewCell"> |
1179 | - <source key="sourceIdentifier" type="project" relativePath="./Classes/ArtistCell.h"/> |
1180 | - </class> |
1181 | - <class className="ArtistViewController" superclassName="UIViewController"> |
1182 | + <class className="ArtistViewController"> |
1183 | <source key="sourceIdentifier" type="project" relativePath="./Classes/ArtistViewController.h"/> |
1184 | <relationships> |
1185 | <relationship kind="outlet" name="albumArt" candidateClass="UIImageView"/> |
1186 | <relationship kind="outlet" name="artistDescription" candidateClass="UILabel"/> |
1187 | <relationship kind="outlet" name="artistName" candidateClass="UILabel"/> |
1188 | - <relationship kind="outlet" name="nowPlayingButton" candidateClass="UIBarButtonItem"/> |
1189 | <relationship kind="outlet" name="tableView" candidateClass="UITableView"/> |
1190 | </relationships> |
1191 | </class> |
1192 | - <class className="ArtistsViewController" superclassName="UOIndexedViewController"> |
1193 | - <source key="sourceIdentifier" type="project" relativePath="./Classes/ArtistsViewController.h"/> |
1194 | - </class> |
1195 | - <class className="PlayerHeaderView" superclassName="UIView"> |
1196 | - <source key="sourceIdentifier" type="project" relativePath="./Classes/PlayerHeaderView.h"/> |
1197 | - <relationships> |
1198 | - <relationship kind="outlet" name="album" candidateClass="UILabel"/> |
1199 | - <relationship kind="outlet" name="artist" candidateClass="UILabel"/> |
1200 | - <relationship kind="outlet" name="title" candidateClass="UILabel"/> |
1201 | - </relationships> |
1202 | - </class> |
1203 | - <class className="PlayerViewController" superclassName="UIViewController"> |
1204 | - <source key="sourceIdentifier" type="project" relativePath="./Classes/PlayerViewController.h"/> |
1205 | - <relationships> |
1206 | - <relationship kind="action" name="changeRepeat:"/> |
1207 | - <relationship kind="action" name="changeShuffle:"/> |
1208 | - <relationship kind="action" name="hide:"/> |
1209 | - <relationship kind="action" name="next:"/> |
1210 | - <relationship kind="action" name="pause:"/> |
1211 | - <relationship kind="action" name="play:"/> |
1212 | - <relationship kind="action" name="previous:"/> |
1213 | - <relationship kind="action" name="toggleExtendedControls:"/> |
1214 | - <relationship kind="outlet" name="albumart" candidateClass="UIButton"/> |
1215 | - <relationship kind="outlet" name="artistLabel" candidateClass="UILabel"/> |
1216 | - <relationship kind="outlet" name="controlBar" candidateClass="UIToolbar"/> |
1217 | - <relationship kind="outlet" name="elapsedTime" candidateClass="UILabel"/> |
1218 | - <relationship kind="outlet" name="extendedControlView" candidateClass="UIView"/> |
1219 | - <relationship kind="outlet" name="nextButton" candidateClass="UIBarButtonItem"/> |
1220 | - <relationship kind="outlet" name="pauseButton" candidateClass="UIBarButtonItem"/> |
1221 | - <relationship kind="outlet" name="playButton" candidateClass="UIBarButtonItem"/> |
1222 | - <relationship kind="outlet" name="playlistInfo" candidateClass="UILabel"/> |
1223 | - <relationship kind="outlet" name="previousButton" candidateClass="UIBarButtonItem"/> |
1224 | - <relationship kind="outlet" name="progressView" candidateClass="UISlider"/> |
1225 | - <relationship kind="outlet" name="reflectionImage" candidateClass="UIImageView"/> |
1226 | - <relationship kind="outlet" name="repeatButton" candidateClass="UIButton"/> |
1227 | - <relationship kind="outlet" name="shuffleButton" candidateClass="UIButton"/> |
1228 | - <relationship kind="outlet" name="titleLabel" candidateClass="UILabel"/> |
1229 | - <relationship kind="outlet" name="totalTime" candidateClass="UILabel"/> |
1230 | - </relationships> |
1231 | - </class> |
1232 | - <class className="PlaylistCell" superclassName="UITableViewCell"> |
1233 | - <source key="sourceIdentifier" type="project" relativePath="./Classes/PlaylistCell.h"/> |
1234 | - </class> |
1235 | - <class className="PlaylistsViewController" superclassName="UOIndexedViewController"> |
1236 | - <source key="sourceIdentifier" type="project" relativePath="./Classes/PlaylistsViewController.h"/> |
1237 | - </class> |
1238 | - <class className="SettingsAuthenticationViewController" superclassName="UIViewController"> |
1239 | + <class className="SettingsAuthenticationViewController"> |
1240 | <source key="sourceIdentifier" type="project" relativePath="./Classes/SettingsAuthenticationViewController.h"/> |
1241 | <relationships> |
1242 | <relationship kind="action" name="authenticate:"/> |
1243 | @@ -1060,7 +999,7 @@ |
1244 | <relationship kind="outlet" name="usernameField" candidateClass="UITextField"/> |
1245 | </relationships> |
1246 | </class> |
1247 | - <class className="SettingsViewController" superclassName="UITableViewController"> |
1248 | + <class className="SettingsViewController"> |
1249 | <source key="sourceIdentifier" type="project" relativePath="./Classes/SettingsViewController.h"/> |
1250 | <relationships> |
1251 | <relationship kind="action" name="deleteCaches:"/> |
1252 | @@ -1071,27 +1010,6 @@ |
1253 | <relationship kind="outlet" name="versionNumber" candidateClass="UILabel"/> |
1254 | </relationships> |
1255 | </class> |
1256 | - <class className="SongCell" superclassName="UITableViewCell"> |
1257 | - <source key="sourceIdentifier" type="project" relativePath="./Classes/SongCell.h"/> |
1258 | - <relationships> |
1259 | - <relationship kind="outlet" name="cacheImageIndicator" candidateClass="UIImageView"/> |
1260 | - <relationship kind="outlet" name="cacheIndicator" candidateClass="UIView"/> |
1261 | - <relationship kind="outlet" name="clock" candidateClass="UILabel"/> |
1262 | - <relationship kind="outlet" name="handle" candidateClass="UIImageView"/> |
1263 | - <relationship kind="outlet" name="title" candidateClass="UILabel"/> |
1264 | - <relationship kind="outlet" name="topView" candidateClass="UIView"/> |
1265 | - <relationship kind="outlet" name="track" candidateClass="UILabel"/> |
1266 | - </relationships> |
1267 | - </class> |
1268 | - <class className="SongsViewController" superclassName="UOIndexedViewController"> |
1269 | - <source key="sourceIdentifier" type="project" relativePath="./Classes/SongsViewController.h"/> |
1270 | - </class> |
1271 | - <class className="UOIndexedViewController" superclassName="UITableViewController"> |
1272 | - <source key="sourceIdentifier" type="project" relativePath="./Classes/UOIndexedViewController.h"/> |
1273 | - <relationships> |
1274 | - <relationship kind="outlet" name="nowPlayingButton" candidateClass="UIBarButtonItem"/> |
1275 | - </relationships> |
1276 | - </class> |
1277 | </classes> |
1278 | <simulatedMetricsContainer key="defaultSimulatedMetrics"> |
1279 | <simulatedStatusBarMetrics key="statusBar"/> |
1280 | @@ -1100,6 +1018,6 @@ |
1281 | </simulatedMetricsContainer> |
1282 | <inferredMetricsTieBreakers> |
1283 | <segue reference="jMd-4K-zoU"/> |
1284 | - <segue reference="e8X-Xp-0ra"/> |
1285 | + <segue reference="ebj-wD-yft"/> |
1286 | </inferredMetricsTieBreakers> |
1287 | </document> |
1288 | \ No newline at end of file |
1289 | |
1290 | === modified file 'Music/Utilities/UOPlayer.h' |
1291 | --- Music/Utilities/UOPlayer.h 2013-02-11 04:30:25 +0000 |
1292 | +++ Music/Utilities/UOPlayer.h 2013-02-11 04:30:25 +0000 |
1293 | @@ -45,4 +45,6 @@ |
1294 | @property (nonatomic) BOOL shuffle; |
1295 | @property (nonatomic) RepeatState repeat; |
1296 | |
1297 | +- (double)streamerProgress; |
1298 | + |
1299 | @end |
1300 | |
1301 | === modified file 'Music/Utilities/UOPlayer.m' |
1302 | --- Music/Utilities/UOPlayer.m 2013-02-11 04:30:25 +0000 |
1303 | +++ Music/Utilities/UOPlayer.m 2013-02-11 04:30:25 +0000 |
1304 | @@ -106,7 +106,7 @@ |
1305 | |
1306 | #pragma mark - Player state |
1307 | |
1308 | -- (double)progress { |
1309 | +- (double)streamerProgress { |
1310 | return streamer.progress; |
1311 | } |
1312 | |
1313 | |
1314 | === modified file 'Music/View Controllers/AlbumViewController.h' |
1315 | --- Music/View Controllers/AlbumViewController.h 2013-01-24 15:46:16 +0000 |
1316 | +++ Music/View Controllers/AlbumViewController.h 2013-02-11 04:30:25 +0000 |
1317 | @@ -12,6 +12,7 @@ |
1318 | |
1319 | @interface AlbumViewController : UIViewController |
1320 | @property (nonatomic, retain) NSString *albumId; |
1321 | +@property (nonatomic, retain) NSString *artistId; |
1322 | |
1323 | @property (strong, nonatomic) IBOutlet UIBarButtonItem *nowPlayingButton; |
1324 | @end |
1325 | |
1326 | === modified file 'Music/View Controllers/AlbumViewController.m' |
1327 | --- Music/View Controllers/AlbumViewController.m 2013-02-11 04:30:25 +0000 |
1328 | +++ Music/View Controllers/AlbumViewController.m 2013-02-11 04:30:25 +0000 |
1329 | @@ -20,6 +20,7 @@ |
1330 | NSArray *tableData; |
1331 | |
1332 | Album *album; |
1333 | + Artist *artist; |
1334 | } |
1335 | @property (weak, nonatomic) IBOutlet UIImageView *albumArt; |
1336 | @property (weak, nonatomic) IBOutlet UILabel *albumTitle; |
1337 | @@ -30,6 +31,7 @@ |
1338 | |
1339 | @implementation AlbumViewController |
1340 | @synthesize albumId = _albumId; |
1341 | +@synthesize artistId = _artistId; |
1342 | |
1343 | - (void)viewDidLoad { |
1344 | [self.tableView setDataSource:self]; |
1345 | @@ -58,7 +60,11 @@ |
1346 | |
1347 | if ([album.songs count]) { |
1348 | NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"track" ascending:YES]; |
1349 | - tableData = [album.songs sortedArrayUsingDescriptors:@[sortDescriptor]]; |
1350 | + if (self.artistId) { |
1351 | + tableData = [[album songsForArtistId:self.artistId] sortedArrayUsingDescriptors:@[sortDescriptor]]; |
1352 | + } else { |
1353 | + tableData = [album.songs sortedArrayUsingDescriptors:@[sortDescriptor]]; |
1354 | + } |
1355 | [self.tableView reloadData]; |
1356 | } else { |
1357 | [[UOWebServiceController controller] updateSongs:self]; |
1358 | @@ -116,7 +122,11 @@ |
1359 | [managedObjectContext refreshObject:album mergeChanges:NO]; |
1360 | |
1361 | NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"track" ascending:YES]; |
1362 | - tableData = [album.songs sortedArrayUsingDescriptors:@[sortDescriptor]]; |
1363 | + if (self.artistId) { |
1364 | + tableData = [[album songsForArtistId:self.artistId] sortedArrayUsingDescriptors:@[sortDescriptor]]; |
1365 | + } else { |
1366 | + tableData = [album.songs sortedArrayUsingDescriptors:@[sortDescriptor]]; |
1367 | + } |
1368 | |
1369 | [self.tableView reloadData]; |
1370 | } |
1371 | |
1372 | === modified file 'Music/View Controllers/AlbumsViewController.m' |
1373 | --- Music/View Controllers/AlbumsViewController.m 2013-01-24 16:37:09 +0000 |
1374 | +++ Music/View Controllers/AlbumsViewController.m 2013-02-11 04:30:25 +0000 |
1375 | @@ -46,6 +46,10 @@ |
1376 | [[UOWebServiceController controller] updateAlbums:self]; |
1377 | } |
1378 | |
1379 | +- (void)refresh { |
1380 | + [[UOWebServiceController controller] updateAlbums:self clearCache:YES]; |
1381 | +} |
1382 | + |
1383 | #pragma mark - Storyboard methods |
1384 | |
1385 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { |
1386 | @@ -55,6 +59,7 @@ |
1387 | AlbumViewController *albumViewController = [segue destinationViewController]; |
1388 | Album *album = ((AlbumCell *)sender).album; |
1389 | albumViewController.albumId = album.albumId; |
1390 | + albumViewController.artistId = nil; |
1391 | } |
1392 | |
1393 | @end |
1394 | |
1395 | === modified file 'Music/View Controllers/ArtistViewController.m' |
1396 | --- Music/View Controllers/ArtistViewController.m 2013-02-11 04:30:25 +0000 |
1397 | +++ Music/View Controllers/ArtistViewController.m 2013-02-11 04:30:25 +0000 |
1398 | @@ -59,11 +59,7 @@ |
1399 | self.navigationItem.rightBarButtonItem = nil; |
1400 | } |
1401 | |
1402 | - NSString *pluralizedNoun = @"albums"; |
1403 | - if ([artist.albums count] == 1) { |
1404 | - pluralizedNoun = @"album"; |
1405 | - } |
1406 | - [_artistDescription setText:[NSString stringWithFormat:@"%d %@", [artist.albums count], pluralizedNoun]]; |
1407 | + [self setAlbumCount]; |
1408 | NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"year" ascending:NO]; |
1409 | tableData = [artist.albums sortedArrayUsingDescriptors:@[sortDescriptor]]; |
1410 | [self.tableView reloadData]; |
1411 | @@ -98,6 +94,7 @@ |
1412 | AlbumViewController *albumViewController = [segue destinationViewController]; |
1413 | Album *album = ((AlbumCell *)sender).album; |
1414 | albumViewController.albumId = album.albumId; |
1415 | + albumViewController.artistId = self.artistId; |
1416 | } |
1417 | |
1418 | #pragma mark - UOWebServiceDelegate methods |
1419 | @@ -110,6 +107,7 @@ |
1420 | tableData = [artist.albums sortedArrayUsingDescriptors:@[sortDescriptor]]; |
1421 | |
1422 | [self.tableView reloadData]; |
1423 | + [self setAlbumCount]; |
1424 | } |
1425 | |
1426 | - (void)webserviceUpdateError:(NSError *)error { |
1427 | @@ -139,4 +137,12 @@ |
1428 | artist = [results objectAtIndex:0]; |
1429 | } |
1430 | |
1431 | +- (void)setAlbumCount { |
1432 | + NSString *pluralizedNoun = @"albums"; |
1433 | + if ([artist.albums count] == 1) { |
1434 | + pluralizedNoun = @"album"; |
1435 | + } |
1436 | + [_artistDescription setText:[NSString stringWithFormat:@"%d %@", [artist.albums count], pluralizedNoun]]; |
1437 | +} |
1438 | + |
1439 | @end |
1440 | |
1441 | === modified file 'Music/View Controllers/ArtistsViewController.m' |
1442 | --- Music/View Controllers/ArtistsViewController.m 2013-01-24 15:46:16 +0000 |
1443 | +++ Music/View Controllers/ArtistsViewController.m 2013-02-11 04:30:25 +0000 |
1444 | @@ -49,6 +49,10 @@ |
1445 | [[UOWebServiceController controller] updateArtists:self]; |
1446 | } |
1447 | |
1448 | +- (void)refresh { |
1449 | + [[UOWebServiceController controller] updateArtists:self clearCache:YES]; |
1450 | +} |
1451 | + |
1452 | #pragma mark - Storyboard methods |
1453 | |
1454 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { |
1455 | |
1456 | === modified file 'Music/View Controllers/PlayerViewController.m' |
1457 | --- Music/View Controllers/PlayerViewController.m 2013-02-11 04:30:25 +0000 |
1458 | +++ Music/View Controllers/PlayerViewController.m 2013-02-11 04:30:25 +0000 |
1459 | @@ -185,8 +185,8 @@ |
1460 | } |
1461 | |
1462 | - (void)heartbeat:(NSTimer*)timer { |
1463 | - NSInteger progress = (NSInteger)[[UOPlayer player] progress]; |
1464 | - self.elapsedTime.text = [NSString clockStringFromSeconds:progress]; |
1465 | + double progress = [[UOPlayer player] streamerProgress]; |
1466 | + self.elapsedTime.text = [NSString clockStringFromSeconds:(int)progress]; |
1467 | self.progressView.value = progress; |
1468 | } |
1469 | |
1470 | |
1471 | === modified file 'Music/View Controllers/PlaylistsViewController.m' |
1472 | --- Music/View Controllers/PlaylistsViewController.m 2013-01-22 19:50:43 +0000 |
1473 | +++ Music/View Controllers/PlaylistsViewController.m 2013-02-11 04:30:25 +0000 |
1474 | @@ -45,4 +45,8 @@ |
1475 | [[UOWebServiceController controller] updatePlaylists:self]; |
1476 | } |
1477 | |
1478 | +- (void)refresh { |
1479 | + [[UOWebServiceController controller] updatePlaylists:self clearCache:YES]; |
1480 | +} |
1481 | + |
1482 | @end |
1483 | |
1484 | === modified file 'Music/View Controllers/SongsViewController.m' |
1485 | --- Music/View Controllers/SongsViewController.m 2013-02-11 04:30:25 +0000 |
1486 | +++ Music/View Controllers/SongsViewController.m 2013-02-11 04:30:25 +0000 |
1487 | @@ -9,7 +9,7 @@ |
1488 | #import "SongsViewController.h" |
1489 | #import "UONetworkStatusCoordinator.h" |
1490 | #import "Song.h" |
1491 | -#import "SongCell.h" |
1492 | +#import "SongListCell.h" |
1493 | #import "NSString+Extras.h" |
1494 | #import "UOWebServiceController.h" |
1495 | #import "UOPlayer.h" |
1496 | @@ -37,23 +37,27 @@ |
1497 | } |
1498 | |
1499 | - (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath { |
1500 | - SongCell *songCell = (SongCell *)cell; |
1501 | + SongListCell *songCell = (SongListCell *)cell; |
1502 | Song *song = [self.fetchedResultsController objectAtIndexPath:indexPath]; |
1503 | - songCell.showArt = YES; |
1504 | [songCell setSong:song]; |
1505 | } |
1506 | |
1507 | -- (void)viewWillAppear:(BOOL)animated { |
1508 | - [super viewWillAppear:animated]; |
1509 | +- (void)update { |
1510 | [[UOWebServiceController controller] updateSongs:self]; |
1511 | } |
1512 | |
1513 | +- (void)refresh { |
1514 | + [[UOWebServiceController controller] updateSongs:self clearCache:YES]; |
1515 | +} |
1516 | + |
1517 | +#pragma mark - UIStoryboard methods |
1518 | + |
1519 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { |
1520 | NSArray *songs = [[self.fetchedResultsController fetchedObjects] copy]; |
1521 | if (![sender respondsToSelector:@selector(song)]) { |
1522 | return; // Hit 'Now Playing' |
1523 | } |
1524 | - Song *song = ((SongCell *)sender).song; |
1525 | + Song *song = ((SongListCell *)sender).song; |
1526 | NSUInteger index = [songs indexOfObject:song]; |
1527 | |
1528 | UOPlayer *player = [UOPlayer player]; |
1529 | |
1530 | === modified file 'Music/View Controllers/UOIndexedViewController.h' |
1531 | --- Music/View Controllers/UOIndexedViewController.h 2013-01-24 15:46:16 +0000 |
1532 | +++ Music/View Controllers/UOIndexedViewController.h 2013-02-11 04:30:25 +0000 |
1533 | @@ -23,6 +23,7 @@ |
1534 | @property (readonly, nonatomic) NSString *lastUpdatedKey; |
1535 | @property (readonly, nonatomic) NSArray *sortDescriptors; |
1536 | - (void)update; |
1537 | +- (void)refresh; |
1538 | - (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath; |
1539 | |
1540 | - (NSFetchedResultsController *)fetchedResultsController; |
1541 | |
1542 | === modified file 'Music/View Controllers/UOIndexedViewController.m' |
1543 | --- Music/View Controllers/UOIndexedViewController.m 2013-02-11 04:30:25 +0000 |
1544 | +++ Music/View Controllers/UOIndexedViewController.m 2013-02-11 04:30:25 +0000 |
1545 | @@ -10,11 +10,12 @@ |
1546 | #import <RestKit/RestKit.h> |
1547 | #import "UOAppDelegate.h" |
1548 | #import "UOPlayer.h" |
1549 | +#import "SSPullToRefresh.h" |
1550 | |
1551 | -@interface UOIndexedViewController () { |
1552 | +@interface UOIndexedViewController () <SSPullToRefreshViewDelegate> { |
1553 | NSFetchedResultsController *_fetchedResultsController; |
1554 | } |
1555 | - |
1556 | +@property (nonatomic, strong) SSPullToRefreshView *pullToRefreshView; |
1557 | @end |
1558 | |
1559 | @implementation UOIndexedViewController |
1560 | @@ -48,13 +49,24 @@ |
1561 | - (void)update { |
1562 | } |
1563 | |
1564 | +- (void)refresh { |
1565 | +} |
1566 | + |
1567 | #pragma mark - UIViewController lifecycle |
1568 | |
1569 | - (void)viewDidLoad { |
1570 | [super viewDidLoad]; |
1571 | + |
1572 | + self.pullToRefreshView = [[SSPullToRefreshView alloc] initWithScrollView:self.tableView delegate:self]; |
1573 | + self.pullToRefreshView.contentView = [[SSPullToRefreshSimpleContentView alloc] initWithFrame:CGRectZero]; |
1574 | groupedTableData = [NSMutableDictionary dictionary]; |
1575 | } |
1576 | |
1577 | +- (void)viewDidUnload { |
1578 | + [super viewDidUnload]; |
1579 | + self.pullToRefreshView = nil; |
1580 | +} |
1581 | + |
1582 | - (void)viewWillAppear:(BOOL)animated { |
1583 | [super viewWillAppear:animated]; |
1584 | [self update]; |
1585 | @@ -66,12 +78,6 @@ |
1586 | } |
1587 | } |
1588 | |
1589 | -- (void)didReceiveMemoryWarning |
1590 | -{ |
1591 | - [super didReceiveMemoryWarning]; |
1592 | - // Dispose of any resources that can be recreated. |
1593 | -} |
1594 | - |
1595 | #pragma mark - Table view data source |
1596 | |
1597 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { |
1598 | @@ -114,25 +120,6 @@ |
1599 | NSLog(@"Error: %@", [error localizedDescription]); |
1600 | } |
1601 | |
1602 | -#pragma mark - RKObjectLoaderDelegate methods |
1603 | -/* |
1604 | -- (void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error { |
1605 | - [UONetworkStatusCoordinator removeNetworkActivity]; |
1606 | - if ([error code] == 2) { // Network is down. |
1607 | - return; |
1608 | - } |
1609 | - NSLog(@"Error: %@", [error localizedDescription]); |
1610 | - [[NSUserDefaults standardUserDefaults] setObject:nil forKey:[self lastUpdatedKey]]; |
1611 | -} |
1612 | - |
1613 | -- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects { |
1614 | - [UONetworkStatusCoordinator removeNetworkActivity]; |
1615 | - _fetchedResultsController = nil; |
1616 | - [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:[self lastUpdatedKey]]; |
1617 | - [self.tableView reloadData]; |
1618 | -} |
1619 | - */ |
1620 | - |
1621 | #pragma mark - Fetched results controller |
1622 | |
1623 | - (NSFetchedResultsController *)fetchedResultsController { |
1624 | @@ -166,4 +153,13 @@ |
1625 | [self.tableView reloadData]; |
1626 | } |
1627 | |
1628 | +#pragma mark - SSPullToRefreshViewDelegate methods |
1629 | + |
1630 | +- (void)pullToRefreshViewDidStartLoading:(SSPullToRefreshView *)view { |
1631 | + [self.pullToRefreshView startLoading]; |
1632 | + [self refresh]; |
1633 | + [self.pullToRefreshView finishLoading]; |
1634 | +} |
1635 | + |
1636 | + |
1637 | @end |
1638 | |
1639 | === modified file 'Music/Views/Table Cells/ArtistCell.m' |
1640 | --- Music/Views/Table Cells/ArtistCell.m 2013-01-28 00:40:22 +0000 |
1641 | +++ Music/Views/Table Cells/ArtistCell.m 2013-02-11 04:30:25 +0000 |
1642 | @@ -32,6 +32,8 @@ |
1643 | pluralizedNoun = @"album"; |
1644 | } |
1645 | [self.detailTextLabel setText:[NSString stringWithFormat:@"%d %@", [artist.albums count], pluralizedNoun]]; |
1646 | + } else { |
1647 | + [self.detailTextLabel setText:@" "]; |
1648 | } |
1649 | } |
1650 | |
1651 | |
1652 | === added file 'Music/Views/Table Cells/SongListCell.h' |
1653 | --- Music/Views/Table Cells/SongListCell.h 1970-01-01 00:00:00 +0000 |
1654 | +++ Music/Views/Table Cells/SongListCell.h 2013-02-11 04:30:25 +0000 |
1655 | @@ -0,0 +1,15 @@ |
1656 | +// |
1657 | +// SongListCell.h |
1658 | +// U1Music |
1659 | +// |
1660 | +// Created by Paul Hummer on 2/6/13. |
1661 | +// Copyright (c) 2013 Canonical. All rights reserved. |
1662 | +// |
1663 | + |
1664 | +#import <UIKit/UIKit.h> |
1665 | + |
1666 | +@class Song; |
1667 | + |
1668 | +@interface SongListCell : UITableViewCell |
1669 | +@property (nonatomic, retain) Song *song; |
1670 | +@end |
1671 | |
1672 | === added file 'Music/Views/Table Cells/SongListCell.m' |
1673 | --- Music/Views/Table Cells/SongListCell.m 1970-01-01 00:00:00 +0000 |
1674 | +++ Music/Views/Table Cells/SongListCell.m 2013-02-11 04:30:25 +0000 |
1675 | @@ -0,0 +1,34 @@ |
1676 | +// |
1677 | +// SongListCell.m |
1678 | +// U1Music |
1679 | +// |
1680 | +// Created by Paul Hummer on 2/6/13. |
1681 | +// Copyright (c) 2013 Canonical. All rights reserved. |
1682 | +// |
1683 | + |
1684 | +#import "SongListCell.h" |
1685 | +#import "UODownloader.h" |
1686 | +#import "Song.h" |
1687 | +#import "Artist.h" |
1688 | + |
1689 | +@implementation SongListCell |
1690 | +@synthesize song; |
1691 | + |
1692 | +- (void)setSong:(Song *)_song { |
1693 | + song = _song; |
1694 | + |
1695 | + if (!song.art) { |
1696 | + [self.imageView setImage:[UIImage imageNamed:@"default-album-art-120.png"]]; |
1697 | + [[UODownloader downloader] downloadArt:song.artUrl toPath:song.artPath completionBlock:^(UIImage *image){ |
1698 | + [self.imageView setImage:image]; |
1699 | + [self setNeedsDisplay]; |
1700 | + }]; |
1701 | + } else { |
1702 | + [self.imageView setImage:song.art]; |
1703 | + } |
1704 | + |
1705 | + [self.textLabel setText:song.title]; |
1706 | + [self.detailTextLabel setText:song.artist.name]; |
1707 | +} |
1708 | + |
1709 | +@end |
1710 | |
1711 | === modified file 'U1Music.xcodeproj/project.pbxproj' |
1712 | --- U1Music.xcodeproj/project.pbxproj 2013-02-11 04:30:25 +0000 |
1713 | +++ U1Music.xcodeproj/project.pbxproj 2013-02-11 04:30:25 +0000 |
1714 | @@ -28,6 +28,10 @@ |
1715 | 523B3CFA15B73BA0004394F4 /* download-grey@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 523B3CF615B73BA0004394F4 /* download-grey@2x.png */; }; |
1716 | 523B3CFB15B73BA0004394F4 /* download.png in Resources */ = {isa = PBXBuildFile; fileRef = 523B3CF715B73BA0004394F4 /* download.png */; }; |
1717 | 523B3CFC15B73BA0004394F4 /* download@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 523B3CF815B73BA0004394F4 /* download@2x.png */; }; |
1718 | + 5257414B16C37A0A00530CCC /* SongListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5257414A16C37A0A00530CCC /* SongListCell.m */; }; |
1719 | + 5257415416C37E1A00530CCC /* SSPullToRefreshDefaultContentView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5257414F16C37E1A00530CCC /* SSPullToRefreshDefaultContentView.m */; }; |
1720 | + 5257415516C37E1A00530CCC /* SSPullToRefreshSimpleContentView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5257415116C37E1A00530CCC /* SSPullToRefreshSimpleContentView.m */; }; |
1721 | + 5257415616C37E1A00530CCC /* SSPullToRefreshView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5257415316C37E1A00530CCC /* SSPullToRefreshView.m */; }; |
1722 | 5257417716C5CC5D00530CCC /* NSString+UbuntuOne.m in Sources */ = {isa = PBXBuildFile; fileRef = 5257417616C5CC5D00530CCC /* NSString+UbuntuOne.m */; }; |
1723 | 5257417A16C5CDA900530CCC /* UIImageView+UbuntuOne.m in Sources */ = {isa = PBXBuildFile; fileRef = 5257417916C5CDA900530CCC /* UIImageView+UbuntuOne.m */; }; |
1724 | 5257416D16C5653100530CCC /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5257416C16C5653100530CCC /* Crashlytics.framework */; }; |
1725 | @@ -274,6 +278,15 @@ |
1726 | 523B3CF615B73BA0004394F4 /* download-grey@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "download-grey@2x.png"; sourceTree = "<group>"; }; |
1727 | 523B3CF715B73BA0004394F4 /* download.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = download.png; sourceTree = "<group>"; }; |
1728 | 523B3CF815B73BA0004394F4 /* download@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "download@2x.png"; sourceTree = "<group>"; }; |
1729 | + 5257414916C37A0A00530CCC /* SongListCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SongListCell.h; sourceTree = "<group>"; }; |
1730 | + 5257414A16C37A0A00530CCC /* SongListCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SongListCell.m; sourceTree = "<group>"; }; |
1731 | + 5257414D16C37E1A00530CCC /* SSPullToRefresh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSPullToRefresh.h; sourceTree = "<group>"; }; |
1732 | + 5257414E16C37E1A00530CCC /* SSPullToRefreshDefaultContentView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSPullToRefreshDefaultContentView.h; sourceTree = "<group>"; }; |
1733 | + 5257414F16C37E1A00530CCC /* SSPullToRefreshDefaultContentView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSPullToRefreshDefaultContentView.m; sourceTree = "<group>"; }; |
1734 | + 5257415016C37E1A00530CCC /* SSPullToRefreshSimpleContentView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSPullToRefreshSimpleContentView.h; sourceTree = "<group>"; }; |
1735 | + 5257415116C37E1A00530CCC /* SSPullToRefreshSimpleContentView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSPullToRefreshSimpleContentView.m; sourceTree = "<group>"; }; |
1736 | + 5257415216C37E1A00530CCC /* SSPullToRefreshView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSPullToRefreshView.h; sourceTree = "<group>"; }; |
1737 | + 5257415316C37E1A00530CCC /* SSPullToRefreshView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSPullToRefreshView.m; sourceTree = "<group>"; }; |
1738 | 5257417516C5CC5D00530CCC /* NSString+UbuntuOne.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSString+UbuntuOne.h"; path = "Categories/NSString+UbuntuOne.h"; sourceTree = "<group>"; }; |
1739 | 5257417616C5CC5D00530CCC /* NSString+UbuntuOne.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+UbuntuOne.m"; path = "Categories/NSString+UbuntuOne.m"; sourceTree = "<group>"; }; |
1740 | 5257417816C5CDA900530CCC /* UIImageView+UbuntuOne.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImageView+UbuntuOne.h"; path = "Categories/UIImageView+UbuntuOne.h"; sourceTree = "<group>"; }; |
1741 | @@ -659,6 +672,7 @@ |
1742 | 29B97317FDCFA39411CA2CEA /* Resources */, |
1743 | 964FA39013CA5BE60018A65B /* Dependencies */, |
1744 | 29B97323FDCFA39411CA2CEA /* Frameworks */, |
1745 | + 5279764815F00B2600F8435F /* libz.dylib */, |
1746 | 19C28FACFE9D520D11CA2CBB /* Products */, |
1747 | ); |
1748 | name = CustomTemplate; |
1749 | @@ -713,6 +727,21 @@ |
1750 | name = Categories; |
1751 | sourceTree = "<group>"; |
1752 | }; |
1753 | + 5257414C16C37E1A00530CCC /* SSPullToRefresh */ = { |
1754 | + isa = PBXGroup; |
1755 | + children = ( |
1756 | + 5257414D16C37E1A00530CCC /* SSPullToRefresh.h */, |
1757 | + 5257414E16C37E1A00530CCC /* SSPullToRefreshDefaultContentView.h */, |
1758 | + 5257414F16C37E1A00530CCC /* SSPullToRefreshDefaultContentView.m */, |
1759 | + 5257415016C37E1A00530CCC /* SSPullToRefreshSimpleContentView.h */, |
1760 | + 5257415116C37E1A00530CCC /* SSPullToRefreshSimpleContentView.m */, |
1761 | + 5257415216C37E1A00530CCC /* SSPullToRefreshView.h */, |
1762 | + 5257415316C37E1A00530CCC /* SSPullToRefreshView.m */, |
1763 | + ); |
1764 | + name = SSPullToRefresh; |
1765 | + path = Dependencies/SSPullToRefresh; |
1766 | + sourceTree = "<group>"; |
1767 | + }; |
1768 | 5268508616AE516B001F65A6 /* Products */ = { |
1769 | isa = PBXGroup; |
1770 | children = ( |
1771 | @@ -801,6 +830,8 @@ |
1772 | 526850DB16AEFA7D001F65A6 /* PlaylistCell.m */, |
1773 | 526850DC16AEFA7D001F65A6 /* SongCell.h */, |
1774 | 526850DD16AEFA7D001F65A6 /* SongCell.m */, |
1775 | + 5257414916C37A0A00530CCC /* SongListCell.h */, |
1776 | + 5257414A16C37A0A00530CCC /* SongListCell.m */, |
1777 | ); |
1778 | path = "Table Cells"; |
1779 | sourceTree = "<group>"; |
1780 | @@ -1268,8 +1299,8 @@ |
1781 | 964FA39013CA5BE60018A65B /* Dependencies */ = { |
1782 | isa = PBXGroup; |
1783 | children = ( |
1784 | + 5257414C16C37E1A00530CCC /* SSPullToRefresh */, |
1785 | 93BC520A124C187700B7587C /* SynthesizeSingleton.h */, |
1786 | - 5279764815F00B2600F8435F /* libz.dylib */, |
1787 | 91328278144E07EA00395F40 /* TestFlight SDK */, |
1788 | ); |
1789 | name = Dependencies; |
1790 | @@ -1631,6 +1662,10 @@ |
1791 | 522B24EA16B4BC1E0084B023 /* UODownloadPanGestureRecognizer.m in Sources */, |
1792 | 520BBF2416B51F2A00307F32 /* UODownloader.m in Sources */, |
1793 | 5295FD2416B7559F00A07440 /* UOPlayer.m in Sources */, |
1794 | + 5257414B16C37A0A00530CCC /* SongListCell.m in Sources */, |
1795 | + 5257415416C37E1A00530CCC /* SSPullToRefreshDefaultContentView.m in Sources */, |
1796 | + 5257415516C37E1A00530CCC /* SSPullToRefreshSimpleContentView.m in Sources */, |
1797 | + 5257415616C37E1A00530CCC /* SSPullToRefreshView.m in Sources */, |
1798 | 5257417716C5CC5D00530CCC /* NSString+UbuntuOne.m in Sources */, |
1799 | 5257417A16C5CDA900530CCC /* UIImageView+UbuntuOne.m in Sources */, |
1800 | ); |
Separate changes I see in here that could have been multiple branches:
- adding SSPullToRefresh
- songsForArtistID bug fix
- songlistcell art downloading
1. The license for sspulltorefresh probably needs to be included: /github. com/soffes/ sspulltorefresh /blob/master/ LICENSE
https:/
1a. Do we need the GPL on each of the source files? That's what we do
in the python apps...
2. Do we localize this app? The hard-coded english pluralization made
me wonder.
3. In SongListCell.m, should the downloader completionBlock also set
song.art? Otherwise it looks like we'll be downloading it every time
it shows up...