VLCPlaylistViewController.m 29.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
/*****************************************************************************
 * VLCPlaylistViewController.m
 * VLC for iOS
 *****************************************************************************
 * Copyright (c) 2013 VideoLAN. All rights reserved.
 * $Id$
 *
 * Authors: Felix Paul Kühne <fkuehne # videolan.org>
 *          Gleb Pinigin <gpinigin # gmail.com>
 *          Tamas Timar <ttimar.vlc # gmail.com>
 *
 * Refer to the COPYING file of the official project for license.
 *****************************************************************************/
Felix Paul Kühne's avatar
Felix Paul Kühne committed
14
15

#import "VLCPlaylistViewController.h"
16
#import "VLCMovieViewController.h"
17
#import "VLCPlaylistTableViewCell.h"
18
#import "VLCPlaylistCollectionViewCell.h"
Romain Goyet's avatar
Romain Goyet committed
19
#import "UINavigationController+Theme.h"
20
#import "NSString+SupportedMedia.h"
21
#import "VLCBugreporter.h"
22
#import "VLCAppDelegate.h"
23
#import "UIBarButtonItem+Theme.h"
24
#import "VLCFirstStepsViewController.h"
25

26
27
28
/* prefs keys */
static NSString *kDisplayedFirstSteps = @"Did we display the first steps tutorial?";

29
@implementation EmptyLibraryView
30
31
32
33
34
35
36
37
38
39

- (IBAction)learnMore:(id)sender
{
    UIViewController *firstStepsVC = [[VLCFirstStepsViewController alloc] initWithNibName:nil bundle:nil];
    UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:firstStepsVC];
    navCon.modalPresentationStyle = UIModalPresentationFormSheet;
    [navCon loadTheme];
    [self.window.rootViewController presentViewController:navCon animated:YES completion:nil];
}

40
41
@end

Felix Paul Kühne's avatar
Felix Paul Kühne committed
42
@interface VLCPlaylistViewController () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UITableViewDataSource, UITableViewDelegate, MLMediaLibrary> {
Felix Paul Kühne's avatar
Felix Paul Kühne committed
43
    NSMutableArray *_foundMedia;
44
    VLCLibraryMode _libraryMode;
45
    UIBarButtonItem *_menuButton;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
46
}
47
48

@property (nonatomic, strong) UITableView *tableView;
49
@property (nonatomic, strong) UICollectionView *collectionView;
50
51
@property (nonatomic, strong) EmptyLibraryView *emptyLibraryView;

Felix Paul Kühne's avatar
Felix Paul Kühne committed
52
53
54
55
@end

@implementation VLCPlaylistViewController

56
57
58
59
60
61
+ (void)initialize
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults registerDefaults:@{kDisplayedFirstSteps : [NSNumber numberWithBool:NO]}];
}

62
63
64
- (void)loadView {
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        _tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStylePlain];
65
        _tableView.backgroundColor = [UIColor colorWithWhite:.122 alpha:1.];
66
67
        _tableView.rowHeight = [VLCPlaylistTableViewCell heightOfCell];
        _tableView.separatorColor = [UIColor colorWithWhite:.122 alpha:1.];
68
69
        _tableView.delegate = self;
        _tableView.dataSource = self;
70
        _tableView.opaque = YES;
71
        self.view = _tableView;
72

Felix Paul Kühne's avatar
Felix Paul Kühne committed
73
        if (SYSTEM_RUNS_IOS7_OR_LATER) {
74
75
76
            UILongPressGestureRecognizer *gestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(tableViewLongTouchGestureAction:)];
            [self.view addGestureRecognizer:gestureRecognizer];
        }
77
    } else {
Felix Paul Kühne's avatar
Felix Paul Kühne committed
78
79
80
81
82
83
84
        UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];

        _collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:flowLayout];
        _collectionView.alwaysBounceVertical = YES;
        _collectionView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
        _collectionView.delegate = self;
        _collectionView.dataSource = self;
85
86
        _collectionView.opaque = YES;
        _collectionView.backgroundColor = [UIColor colorWithWhite:.122 alpha:1.];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
87
88
        self.view = _collectionView;

89
        if (SYSTEM_RUNS_IOS7_OR_LATER)
90
            [_collectionView registerNib:[UINib nibWithNibName:@"VLCFuturePlaylistCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:@"PlaylistCell"];
91
        else
92
            [_collectionView registerNib:[UINib nibWithNibName:@"VLCPlaylistCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:@"PlaylistCell"];
93
        self.view.backgroundColor = [UIColor colorWithWhite:.122 alpha:1.];
94
95
    }

96
    _libraryMode = VLCLibraryModeAllFiles;
97

98
99
    self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    self.emptyLibraryView = [[[NSBundle mainBundle] loadNibNamed:@"VLCEmptyLibraryView" owner:self options:nil] lastObject];
100
    _emptyLibraryView.emptyLibraryLongDescriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
101
    _emptyLibraryView.emptyLibraryLongDescriptionLabel.numberOfLines = 0;
102
103
104
105
}

#pragma mark -

Felix Paul Kühne's avatar
Felix Paul Kühne committed
106
107
108
- (void)viewDidLoad
{
    [super viewDidLoad];
109
    self.title = NSLocalizedString(@"LIBRARY_ALL_FILES", @"");
110
111
    _menuButton = [UIBarButtonItem themedRevealMenuButtonWithTarget:self andSelector:@selector(leftButtonAction:)];
    self.navigationItem.leftBarButtonItem = _menuButton;
112

Felix Paul Kühne's avatar
Felix Paul Kühne committed
113
    if (SYSTEM_RUNS_IOS7_OR_LATER)
114
115
116
117
118
119
120
        self.editButtonItem.tintColor = [UIColor whiteColor];
    else {
        [self.editButtonItem setBackgroundImage:[UIImage imageNamed:@"button"]
                                       forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
        [self.editButtonItem setBackgroundImage:[UIImage imageNamed:@"buttonHighlight"]
                                       forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
    }
Felix Paul Kühne's avatar
Felix Paul Kühne committed
121

122
123
124
    _emptyLibraryView.emptyLibraryLabel.text = NSLocalizedString(@"EMPTY_LIBRARY", @"");
    _emptyLibraryView.emptyLibraryLongDescriptionLabel.text = NSLocalizedString(@"EMPTY_LIBRARY_LONG", @"");
    [_emptyLibraryView.emptyLibraryLongDescriptionLabel sizeToFit];
125

126
    [self setToolbarItems:@[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], [UIBarButtonItem themedDarkToolbarButtonWithTitle:NSLocalizedString(@"BUTTON_RENAME", @"") target:self andSelector:@selector(renameSelection)], [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(deleteSelection)]]];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
127
    self.navigationController.toolbar.barStyle = UIBarStyleBlack;
128

129
130
    if (SYSTEM_RUNS_IOS7_OR_LATER) {
        self.navigationController.toolbar.tintColor = [UIColor whiteColor];
131
        [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
132
133
    } else
        [self.navigationController.toolbar setBackgroundImage:[UIImage imageNamed:@"bottomBlackBar"] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
134
135
}

136
137
138
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
139
    [self.collectionView.collectionViewLayout invalidateLayout];
140
    [self _displayEmptyLibraryViewIfNeeded];
141
142
}

143
144
- (void)viewDidAppear:(BOOL)animated
{
145
146
    [super viewDidAppear:animated];

147
148
149
150
151
152
153
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    if (![[defaults objectForKey:kDisplayedFirstSteps] boolValue]) {
        [self.emptyLibraryView performSelector:@selector(learnMore:) withObject:nil afterDelay:1.];
        [defaults setObject:[NSNumber numberWithBool:YES] forKey:kDisplayedFirstSteps];
        [defaults synchronize];
    }

154
155
156
    if ([[MLMediaLibrary sharedMediaLibrary] libraryNeedsUpgrade]) {
        self.navigationItem.rightBarButtonItem = nil;
        self.navigationItem.leftBarButtonItem = nil;
Gleb Pinigin's avatar
Gleb Pinigin committed
157
        self.title = @"";
158
159
160
        self.emptyLibraryView.emptyLibraryLabel.text = NSLocalizedString(@"UPGRADING_LIBRARY", @"");
        self.emptyLibraryView.emptyLibraryLongDescriptionLabel.hidden = YES;
        [self.emptyLibraryView.activityIndicator startAnimating];
Gleb Pinigin's avatar
Gleb Pinigin committed
161
        self.emptyLibraryView.frame = self.view.bounds;
162
163
164
165
166
167
168
        [self.view addSubview:self.emptyLibraryView];

        [[MLMediaLibrary sharedMediaLibrary] setDelegate: self];
        [[MLMediaLibrary sharedMediaLibrary] performSelectorInBackground:@selector(upgradeLibrary) withObject:nil];
        return;
    }

169
    if (_foundMedia.count < 1)
170
        [self updateViewContents];
171
172
173
174
175
176
177
178
179
    [[MLMediaLibrary sharedMediaLibrary] performSelector:@selector(libraryDidAppear) withObject:nil afterDelay:1.];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    [[MLMediaLibrary sharedMediaLibrary] libraryDidDisappear];
}

180
181
182
183
184
185
186
187
188
189
190
- (BOOL)canBecomeFirstResponder
{
    return YES;
}

- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
    if (motion == UIEventSubtypeMotionShake)
        [[VLCBugreporter sharedInstance] handleBugreportRequest];
}

191
192
193
- (void)openMediaObject:(NSManagedObject *)mediaObject
{
    if ([mediaObject isKindOfClass:[MLAlbum class]]) {
194
        _foundMedia = [NSMutableArray arrayWithArray:[(MLAlbum *)mediaObject sortedTracks]];
195
        self.navigationItem.leftBarButtonItem = [UIBarButtonItem themedBackButtonWithTarget:self andSelector:@selector(backToAllItems:)];
196
197
198
199
        if (_libraryMode == VLCLibraryModeAllFiles)
            self.navigationItem.leftBarButtonItem.title = NSLocalizedString(@"BUTTON_BACK", @"");
        else
            [self.navigationItem.leftBarButtonItem setTitle:NSLocalizedString(@"LIBRARY_MUSIC", @"")];
200
201
202
        self.title = [(MLAlbum*)mediaObject name];
        [self reloadViews];
    } else if ([mediaObject isKindOfClass:[MLShow class]]) {
203
        _foundMedia = [NSMutableArray arrayWithArray:[(MLShow *)mediaObject sortedEpisodes]];
204
        self.navigationItem.leftBarButtonItem = [UIBarButtonItem themedBackButtonWithTarget:self andSelector:@selector(backToAllItems:)];
205
206
207
208
        if (_libraryMode == VLCLibraryModeAllFiles)
            self.navigationItem.leftBarButtonItem.title = NSLocalizedString(@"BUTTON_BACK", @"");
        else
            [self.navigationItem.leftBarButtonItem setTitle:NSLocalizedString(@"LIBRARY_SERIES", @"")];
209
210
        self.title = [(MLShow*)mediaObject name];
        [self reloadViews];
211
212
    } else
        [(VLCAppDelegate*)[UIApplication sharedApplication].delegate openMediaFromManagedObject:mediaObject];
213
214
}

215
- (void)removeMediaObject:(id)managedObject updateDatabase:(BOOL)updateDB
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
{
        // delete all tracks from an album
    if ([managedObject isKindOfClass:[MLAlbum class]]) {
        MLAlbum *album = managedObject;
        NSSet *iterAlbumTrack = [NSSet setWithSet:album.tracks];

        for (MLAlbumTrack *track in iterAlbumTrack) {
            NSSet *iterFiles = [NSSet setWithSet:track.files];

            for (MLFile *file in iterFiles)
                [self _deleteMediaObject:file];
        }
        // delete all episodes from a show
    } else if ([managedObject isKindOfClass:[MLShow class]]) {
        MLShow *show = managedObject;
        NSSet *iterShowEpisodes = [NSSet setWithSet:show.episodes];

        for (MLShowEpisode *episode in iterShowEpisodes) {
            NSSet *iterFiles = [NSSet setWithSet:episode.files];

            for (MLFile *file in iterFiles)
                [self _deleteMediaObject:file];
        }
        // delete all files from an episode
    } else if ([managedObject isKindOfClass:[MLShowEpisode class]]) {
        MLShowEpisode *episode = managedObject;
        NSSet *iterFiles = [NSSet setWithSet:episode.files];

        for (MLFile *file in iterFiles)
            [self _deleteMediaObject:file];
        // delete all files from a track
    } else if ([managedObject isKindOfClass:[MLAlbumTrack class]]) {
        MLAlbumTrack *track = managedObject;
        NSSet *iterFiles = [NSSet setWithSet:track.files];

        for (MLFile *file in iterFiles)
            [self _deleteMediaObject:file];
253
254
    } else
        [self _deleteMediaObject:managedObject];
255

256
257
258
259
    if (updateDB) {
        [[MLMediaLibrary sharedMediaLibrary] updateMediaDatabase];
        [self updateViewContents];
    }
260
261
262
}

- (void)_deleteMediaObject:(MLFile *)mediaObject
263
{
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *folderLocation = [[[NSURL URLWithString:mediaObject.url] path] stringByDeletingLastPathComponent];
    NSArray *allfiles = [fileManager contentsOfDirectoryAtPath:folderLocation error:nil];
    NSString *fileName = [[[[NSURL URLWithString:mediaObject.url] path] lastPathComponent] stringByDeletingPathExtension];
    NSIndexSet *indexSet = [allfiles indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
       return ([obj rangeOfString:fileName].location != NSNotFound);
    }];
    unsigned int count = indexSet.count;
    NSString *additionalFilePath;
    NSUInteger currentIndex = [indexSet firstIndex];
    for (unsigned int x = 0; x < count; x++) {
        additionalFilePath = allfiles[currentIndex];
        if ([additionalFilePath isSupportedSubtitleFormat])
            [fileManager removeItemAtPath:[folderLocation stringByAppendingPathComponent:additionalFilePath] error:nil];
        currentIndex = [indexSet indexGreaterThanIndex:currentIndex];
    }
    [fileManager removeItemAtPath:[[NSURL URLWithString:mediaObject.url] path] error:nil];
281
282
283
284
}

- (void)_displayEmptyLibraryViewIfNeeded
{
285
286
287
    if (self.emptyLibraryView.superview)
        [self.emptyLibraryView removeFromSuperview];

Gleb Pinigin's avatar
Gleb Pinigin committed
288
289
    if (_foundMedia.count == 0) {
        self.emptyLibraryView.frame = self.view.bounds;
290
        [self.view addSubview:self.emptyLibraryView];
291
        self.navigationItem.rightBarButtonItem = nil;
292
293
    } else
        self.navigationItem.rightBarButtonItem = self.editButtonItem;
294
295
296
297

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        _tableView.separatorStyle = (_foundMedia.count > 0)? UITableViewCellSeparatorStyleSingleLine:
                                                             UITableViewCellSeparatorStyleNone;
298
299
    } else
        [self.collectionView.collectionViewLayout invalidateLayout];
300
301
}

302
303
- (void)libraryUpgradeComplete
{
Gleb Pinigin's avatar
Gleb Pinigin committed
304
305
    self.title = NSLocalizedString(@"LIBRARY_ALL_FILES", @"");
    self.navigationItem.leftBarButtonItem = _menuButton;
306
307
308
309
310
    self.emptyLibraryView.emptyLibraryLongDescriptionLabel.hidden = NO;
    self.emptyLibraryView.emptyLibraryLabel.text = NSLocalizedString(@"EMPTY_LIBRARY", @"");
    [self.emptyLibraryView.activityIndicator stopAnimating];
    [self.emptyLibraryView removeFromSuperview];

311
312
313
314
315
316
    [self updateViewContents];
}

- (void)libraryWasUpdated
{
    [self updateViewContents];
317
318
}

319
- (void)updateViewContents
Felix Paul Kühne's avatar
Felix Paul Kühne committed
320
{
321
322
    _foundMedia = [[NSMutableArray alloc] init];

323
324
325
326
327
328
329
330
    self.navigationItem.leftBarButtonItem = _menuButton;
    if (_libraryMode == VLCLibraryModeAllAlbums)
        self.title = NSLocalizedString(@"LIBRARY_MUSIC", @"");
    else if( _libraryMode == VLCLibraryModeAllSeries)
        self.title = NSLocalizedString(@"LIBRARY_SERIES", @"");
    else
        self.title = NSLocalizedString(@"LIBRARY_ALL_FILES", @"");

331
332
    /* add all albums */
    if (_libraryMode != VLCLibraryModeAllSeries) {
333
        NSArray *rawAlbums = [MLAlbum allAlbums];
334
        for (MLAlbum *album in rawAlbums) {
Carola's avatar
Carola committed
335
            if (album.name.length > 0 && album.tracks.count > 1)
336
337
                [_foundMedia addObject:album];
        }
338
339
340
341
342
    }
    if (_libraryMode == VLCLibraryModeAllAlbums) {
        [self reloadViews];
        return;
    }
343

344
345
346
    /* add all shows */
    NSArray *rawShows = [MLShow allShows];
    for (MLShow *show in rawShows) {
Carola's avatar
Carola committed
347
        if (show.name.length > 0 && show.episodes.count > 1)
348
349
350
351
352
353
354
355
356
357
358
359
            [_foundMedia addObject:show];
    }
    if (_libraryMode == VLCLibraryModeAllSeries) {
        [self reloadViews];
        return;
    }

    /* add all remaining files */
    NSArray *allFiles = [MLFile allFiles];
    for (MLFile *file in allFiles) {
        if (!file.isShowEpisode && !file.isAlbumTrack)
            [_foundMedia addObject:file];
360
361
362
363
364
365
366
        else if (file.isShowEpisode) {
            if (file.showEpisode.show.episodes.count < 2)
                [_foundMedia addObject:file];
        } else if (file.isAlbumTrack) {
            if (file.albumTrack.album.tracks.count < 2)
                [_foundMedia addObject:file];
        }
367
    }
368

369
    [self reloadViews];
370
}
371

372
- (void)reloadViews
373
{
374
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
375
        [self.tableView reloadData];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
376
377
    else
        [self.collectionView reloadData];
378
379

    [self _displayEmptyLibraryViewIfNeeded];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
380
381
}

382
383
#pragma mark - Table View

Felix Paul Kühne's avatar
Felix Paul Kühne committed
384
385
386
387
388
389
390
391
392
393
394
395
396
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return _foundMedia.count;
}

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
397
    static NSString *CellIdentifier = @"PlaylistCell";
Felix Paul Kühne's avatar
Felix Paul Kühne committed
398

399
    VLCPlaylistTableViewCell *cell = (VLCPlaylistTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
400
    if (cell == nil)
401
        cell = [VLCPlaylistTableViewCell cellWithReuseIdentifier:CellIdentifier];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
402

403
404
    NSInteger row = indexPath.row;
    cell.mediaObject = _foundMedia[row];
405

Felix Paul Kühne's avatar
Felix Paul Kühne committed
406
407
408
    return cell;
}

409
410
411
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    cell.backgroundColor = (indexPath.row % 2 == 0)? [UIColor blackColor]: [UIColor colorWithWhite:.122 alpha:1.];
412
    cell.multipleSelectionBackgroundView.backgroundColor = cell.backgroundColor;
413
414
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
415
416
417
418
419
420
421
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
422
    if (editingStyle == UITableViewCellEditingStyleDelete)
423
        [self removeMediaObject: _foundMedia[indexPath.row] updateDatabase:YES];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
424
425
}

426
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Felix Paul Kühne's avatar
Felix Paul Kühne committed
427
{
428
429
430
    if (tableView.isEditing)
        return;

431
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
432
    NSManagedObject *selectedObject = _foundMedia[indexPath.row];
433
434
435
436
437
438
439
    if ([selectedObject isKindOfClass:[MLAlbumTrack class]]) {
        VLCMediaList *list;
        NSArray *tracks = [[(MLAlbumTrack*)selectedObject album] sortedTracks];
        NSUInteger count = tracks.count;
        list = [[VLCMediaList alloc] init];

        MLFile *file;
440
        for (NSInteger x = count - 1; x > -1; x--) {
441
442
443
444
445
446
            file = [(MLAlbumTrack*)tracks[x] files].anyObject;
            [list addMedia:[VLCMedia mediaWithURL: [NSURL URLWithString:file.url]]];
        }
        [(VLCAppDelegate*)[UIApplication sharedApplication].delegate openMediaList:list atIndex:[tracks indexOfObject:selectedObject]];
    } else
        [self openMediaObject:selectedObject];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
447
448
}

449
450
451
452
453
454
455
456
457
#pragma mark - table view gestures
- (void)tableViewLongTouchGestureAction:(UIGestureRecognizer *)recognizer
{
    NSIndexPath *path = [(UITableView *)self.view indexPathForRowAtPoint:[recognizer locationInView:self.view]];
    UITableViewCell *cell = [(UITableView *)self.view cellForRowAtIndexPath:path];

    CGRect frame = cell.frame;
    if (frame.size.height > 90.)
        frame.size.height = 90.;
458
    else if (recognizer.state == UIGestureRecognizerStateBegan)
459
460
461
462
463
464
465
466
        frame.size.height = 180;

    void (^animationBlock)() = ^() {
        cell.frame = frame;
    };

    void (^completionBlock)(BOOL finished) = ^(BOOL finished) {
        cell.frame = frame;
467
        [self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionNone animated:YES];
468
469
470
471
472
473
    };

    NSTimeInterval animationDuration = .2;
    [UIView animateWithDuration:animationDuration animations:animationBlock completion:completionBlock];
 }

474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
#pragma mark - Collection View
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return _foundMedia.count;
}

- (UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    VLCPlaylistCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"PlaylistCell" forIndexPath:indexPath];
    cell.mediaObject = _foundMedia[indexPath.row];
    cell.collectionView = _collectionView;

    [cell setEditing:self.editing animated:NO];

    return cell;
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
493
    if (SYSTEM_RUNS_IOS7_OR_LATER) {
494
        if (UIDeviceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation))
495
496
497
498
            return CGSizeMake(341., 190.);
        else
            return CGSizeMake(384., 216.);
    }
499

500
501
502
503
504
    return CGSizeMake(298.0, 220.0);
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
505
506
    if (SYSTEM_RUNS_IOS7_OR_LATER)
        return UIEdgeInsetsMake(0., 0., 0., 0.);
507
508
509
    return UIEdgeInsetsMake(0.0, 34.0, 0.0, 34.0);
}

510
511
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
512
513
    if (SYSTEM_RUNS_IOS7_OR_LATER)
        return 0.;
514
515
516
517
518
    return 10.0;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
519
520
    if (SYSTEM_RUNS_IOS7_OR_LATER)
        return 0.;
521
522
523
    return 10.0;
}

524
525
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
526
527
528
529
530
    if (self.editing) {
        [(VLCPlaylistCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath] selectionUpdate];
        return;
    }

531
    NSManagedObject *selectedObject = _foundMedia[indexPath.row];
532
533
534
535
536
537
538
    if ([selectedObject isKindOfClass:[MLAlbumTrack class]]) {
        VLCMediaList *list;
        NSArray *tracks = [[(MLAlbumTrack*)selectedObject album] sortedTracks];
        NSUInteger count = tracks.count;
        list = [[VLCMediaList alloc] init];

        MLFile *file;
539
        for (NSInteger x = count - 1; x > -1; x--) {
540
541
542
543
544
545
            file = [(MLAlbumTrack*)tracks[x] files].anyObject;
            [list addMedia:[VLCMedia mediaWithURL: [NSURL URLWithString:file.url]]];
        }
        [(VLCAppDelegate*)[UIApplication sharedApplication].delegate openMediaList:list atIndex:[tracks indexOfObject:selectedObject]];
    } else
        [self openMediaObject:selectedObject];
546
547
}

548
549
550
551
552
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
    [(VLCPlaylistCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath] selectionUpdate];
}

553
#pragma mark - UI implementation
554
555
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
556
    [super setEditing:editing animated:animated];
557

Felix Paul Kühne's avatar
Felix Paul Kühne committed
558
    UIBarButtonItem *editButton = self.editButtonItem;
559
560
    NSString *editImage = editing? @"doneButton": @"button";
    NSString *editImageHighlight = editing? @"doneButtonHighlight": @"buttonHighlight";
Felix Paul Kühne's avatar
Felix Paul Kühne committed
561
    if (SYSTEM_RUNS_IOS7_OR_LATER)
562
563
564
565
566
567
568
569
        editButton.tintColor = [UIColor whiteColor];
    else {
        [editButton setBackgroundImage:[UIImage imageNamed:editImage] forState:UIControlStateNormal
                                     barMetrics:UIBarMetricsDefault];
        [editButton setBackgroundImage:[UIImage imageNamed:editImageHighlight]
                                       forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
        [editButton setTitleTextAttributes: editing ? @{UITextAttributeTextShadowColor : [UIColor whiteColor], UITextAttributeTextColor : [UIColor blackColor]} : @{UITextAttributeTextShadowColor : [UIColor colorWithWhite:0. alpha:.37], UITextAttributeTextColor : [UIColor whiteColor]} forState:UIControlStateNormal];
    }
Felix Paul Kühne's avatar
Felix Paul Kühne committed
570

571
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
Felix Paul Kühne's avatar
Felix Paul Kühne committed
572
        NSArray *visibleCells = self.collectionView.visibleCells;
573

Felix Paul Kühne's avatar
Felix Paul Kühne committed
574
575
        [visibleCells enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            VLCPlaylistCollectionViewCell *aCell = (VLCPlaylistCollectionViewCell*)obj;
576

Felix Paul Kühne's avatar
Felix Paul Kühne committed
577
578
            [aCell setEditing:editing animated:animated];
        }];
579
580
581
582
583
584
585
586
587
588
589
        self.collectionView.allowsMultipleSelection = editing;

        /* UIKit doesn't clear the selection automagically if we leave the editing mode
         * so we need to do so manually */
        if (!editing) {
            NSArray *selectedItems = [self.collectionView indexPathsForSelectedItems];
            NSUInteger count = selectedItems.count;

            for (NSUInteger x = 0; x < count; x++)
                [self.collectionView deselectItemAtIndexPath:selectedItems[x] animated:NO];
        }
590
591
    } else {
        self.tableView.allowsMultipleSelectionDuringEditing = editing;
592
        [self.tableView setEditing:editing animated:YES];
593
594
        [self.editButtonItem setTitle:editing ? NSLocalizedString(@"BUTTON_CANCEL",@"") : NSLocalizedString(@"BUTTON_EDIT", @"")];
    }
595
    self.navigationController.toolbarHidden = !editing;
596
597
}

598
599
600
601
602
- (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewCellEditingStyleDelete;
}

603
- (IBAction)leftButtonAction:(id)sender
604
{
605
    [[(VLCAppDelegate*)[UIApplication sharedApplication].delegate revealController] toggleSidebar:![(VLCAppDelegate*)[UIApplication sharedApplication].delegate revealController].sidebarShowing duration:kGHRevealSidebarDefaultAnimationDuration];
606
607
608

    if (self.isEditing)
        [self setEditing:NO animated:YES];
609
610
}

611
612
613
- (IBAction)backToAllItems:(id)sender
{
    [self setLibraryMode:_libraryMode];
614
    [self updateViewContents];
615
616
}

617
- (void)_endEditingWithHardReset:(BOOL)hardReset
618
{
619
    [[MLMediaLibrary sharedMediaLibrary] updateMediaDatabase];
620
621
622
623
    if (hardReset)
        [self updateViewContents];
    else
        [self reloadViews];
624

625
626
627
628
629
    [self setEditing:NO animated:YES];
}

- (void)deleteSelection
{
630
631
632
633
634
    NSArray *indexPaths;
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        indexPaths = [self.collectionView indexPathsForSelectedItems];
    else
        indexPaths = [self.tableView indexPathsForSelectedRows];
635
636
637
638
639
640
641
642
643
    NSUInteger count = indexPaths.count;
    NSMutableArray *objects = [[NSMutableArray alloc] initWithCapacity:count];

    for (NSUInteger x = 0; x < count; x++)
        [objects addObject:_foundMedia[[indexPaths[x] row]]];

    for (NSUInteger x = 0; x < count; x++)
        [self removeMediaObject:objects[x] updateDatabase:NO];

644
    [self _endEditingWithHardReset:YES];
645
}
646

647
648
- (void)renameSelection
{
649
650
651
652
653
    NSArray *indexPaths;
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        indexPaths = [self.collectionView indexPathsForSelectedItems];
    else
        indexPaths = [self.tableView indexPathsForSelectedRows];
654

655
    if (indexPaths.count < 1) {
656
        [self _endEditingWithHardReset:NO];
657
658
659
        return;
    }

660
661
662
663
664
    NSString *itemName;
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        itemName = [(VLCPlaylistCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:indexPaths[0]] titleLabel].text;
    else
        itemName = [(VLCPlaylistTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPaths[0]] titleLabel].text;
665
666
667
668
669
670
671
672
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:NSLocalizedString(@"RENAME_MEDIA_TO", @""), itemName] message:nil delegate:self cancelButtonTitle:NSLocalizedString(@"BUTTON_CANCEL", @"") otherButtonTitles:NSLocalizedString(@"BUTTON_RENAME", @""), nil];
    [alert setAlertViewStyle:UIAlertViewStylePlainTextInput];
    [[alert textFieldAtIndex:0] setText:itemName];
    [alert show];
}

- (void)renameMediaObjectTo:(NSString*)newName
{
673
674
675
676
677
    NSArray *indexPaths;
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        indexPaths = [self.collectionView indexPathsForSelectedItems];
    else
        indexPaths = [self.tableView indexPathsForSelectedRows];
678
679
680
681
682
683
684
    id mediaObject = _foundMedia[[indexPaths[0] row]];

    if ([mediaObject isKindOfClass:[MLAlbum class]] || [mediaObject isKindOfClass:[MLShowEpisode class]] || [mediaObject isKindOfClass:[MLShow class]])
        [mediaObject setName:newName];
    else
        [mediaObject setTitle:newName];

685
686
687
688
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        [self.collectionView deselectItemAtIndexPath:indexPaths[0] animated:YES];
    else
        [self.tableView deselectRowAtIndexPath:indexPaths[0] animated:YES];
689
690
691
692

    if (indexPaths.count > 1)
        [self renameSelection];
    else
693
        [self _endEditingWithHardReset:NO];
694
695
696
697
698
699
700
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if (buttonIndex == 1)
        [self renameMediaObjectTo:[alertView textFieldAtIndex:0].text];
    else
701
        [self _endEditingWithHardReset:NO];
702
703
}

704
#pragma mark - coin coin
705

706
- (void)setLibraryMode:(VLCLibraryMode)mode
707
708
{
    _libraryMode = mode;
709
    [self updateViewContents];
710
711
}

Gleb Pinigin's avatar
Gleb Pinigin committed
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
#pragma mark - autorotation

// RootController is responsible for supporting interface orientation(iOS6.0+), i.e. navigation controller
// so this will not work as intended without "voodoo magic"(UINavigationController category, subclassing, etc)
/* introduced in iOS 6 */
- (NSUInteger)supportedInterfaceOrientations {
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        return UIInterfaceOrientationMaskAll;

    return (_foundMedia.count > 0)? UIInterfaceOrientationMaskAllButUpsideDown:
    UIInterfaceOrientationMaskPortrait;
}

/* introduced in iOS 6 */
- (BOOL)shouldAutorotate {
    return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (_foundMedia.count > 0);
}

730
731
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
732
733
734

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        [self.collectionView.collectionViewLayout invalidateLayout];
735
736
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
737
@end