VLCPlaylistViewController.m 30.2 KB
Newer Older
1
2
3
4
/*****************************************************************************
 * VLCPlaylistViewController.m
 * VLC for iOS
 *****************************************************************************
Felix Paul Kühne's avatar
Felix Paul Kühne committed
5
 * Copyright (c) 2013-2014 VideoLAN. All rights reserved.
6
7
8
9
10
11
12
13
 * $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
405
406
    UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRightGestureAction:)];
    [swipeRight setDirection:(UISwipeGestureRecognizerDirectionRight)];
    [cell addGestureRecognizer:swipeRight];

407
408
    NSInteger row = indexPath.row;
    cell.mediaObject = _foundMedia[row];
409

Felix Paul Kühne's avatar
Felix Paul Kühne committed
410
411
412
    return cell;
}

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

Felix Paul Kühne's avatar
Felix Paul Kühne committed
419
420
421
422
423
424
425
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

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

430
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Felix Paul Kühne's avatar
Felix Paul Kühne committed
431
{
432
433
434
    if (tableView.isEditing)
        return;

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

        MLFile *file;
444
        VLCMedia *media;
445
        for (NSInteger x = count - 1; x > -1; x--) {
446
            file = [(MLAlbumTrack*)tracks[x] files].anyObject;
447
448
449
            media = [VLCMedia mediaWithURL: [NSURL URLWithString:file.url]];
            [media parse];
            [list addMedia:media];
450
451
452
453
        }
        [(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
454
455
}

456
457
458
459
460
461
462
463
464
#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.;
465
    else if (recognizer.state == UIGestureRecognizerStateBegan)
466
467
468
469
470
471
472
473
        frame.size.height = 180;

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

    void (^completionBlock)(BOOL finished) = ^(BOOL finished) {
        cell.frame = frame;
474
        [self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionNone animated:YES];
475
476
477
478
479
480
    };

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

481
482
483
484
485
486
487
488
489
490
491
492
493
494
- (void)swipeRightGestureAction:(UIGestureRecognizer *)recognizer
{
    if ([[self.editButtonItem title] isEqualToString:NSLocalizedString(@"BUTTON_CANCEL",@"")])
        [self setEditing:NO animated:YES];
    else {
        [self setEditing:YES animated:YES];

        NSIndexPath *path = [(UITableView *)self.view indexPathForRowAtPoint:[recognizer locationInView:self.view]];
        [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:path.row inSection:path.section]
                                    animated:YES
                              scrollPosition:UITableViewScrollPositionNone];
    }
}

495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
#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
{
514
    if (SYSTEM_RUNS_IOS7_OR_LATER) {
515
        if (UIDeviceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation))
516
517
518
519
            return CGSizeMake(341., 190.);
        else
            return CGSizeMake(384., 216.);
    }
520

521
522
523
524
525
    return CGSizeMake(298.0, 220.0);
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
526
527
    if (SYSTEM_RUNS_IOS7_OR_LATER)
        return UIEdgeInsetsMake(0., 0., 0., 0.);
528
529
530
    return UIEdgeInsetsMake(0.0, 34.0, 0.0, 34.0);
}

531
532
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
533
534
    if (SYSTEM_RUNS_IOS7_OR_LATER)
        return 0.;
535
536
537
538
539
    return 10.0;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
540
541
    if (SYSTEM_RUNS_IOS7_OR_LATER)
        return 0.;
542
543
544
    return 10.0;
}

545
546
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
547
548
549
550
551
    if (self.editing) {
        [(VLCPlaylistCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath] selectionUpdate];
        return;
    }

552
    NSManagedObject *selectedObject = _foundMedia[indexPath.row];
553
554
555
556
557
558
559
    if ([selectedObject isKindOfClass:[MLAlbumTrack class]]) {
        VLCMediaList *list;
        NSArray *tracks = [[(MLAlbumTrack*)selectedObject album] sortedTracks];
        NSUInteger count = tracks.count;
        list = [[VLCMediaList alloc] init];

        MLFile *file;
560
        for (NSInteger x = count - 1; x > -1; x--) {
561
562
563
564
565
566
            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];
567
568
}

569
570
571
572
573
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
    [(VLCPlaylistCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath] selectionUpdate];
}

574
#pragma mark - UI implementation
575
576
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
577
    [super setEditing:editing animated:animated];
578

Felix Paul Kühne's avatar
Felix Paul Kühne committed
579
    UIBarButtonItem *editButton = self.editButtonItem;
580
581
    NSString *editImage = editing? @"doneButton": @"button";
    NSString *editImageHighlight = editing? @"doneButtonHighlight": @"buttonHighlight";
Felix Paul Kühne's avatar
Felix Paul Kühne committed
582
    if (SYSTEM_RUNS_IOS7_OR_LATER)
583
584
585
586
587
588
589
590
        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
591

592
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
Felix Paul Kühne's avatar
Felix Paul Kühne committed
593
        NSArray *visibleCells = self.collectionView.visibleCells;
594

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

Felix Paul Kühne's avatar
Felix Paul Kühne committed
598
599
            [aCell setEditing:editing animated:animated];
        }];
600
601
602
603
604
605
606
607
608
609
610
        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];
        }
611
612
    } else {
        self.tableView.allowsMultipleSelectionDuringEditing = editing;
613
        [self.tableView setEditing:editing animated:YES];
614
615
        [self.editButtonItem setTitle:editing ? NSLocalizedString(@"BUTTON_CANCEL",@"") : NSLocalizedString(@"BUTTON_EDIT", @"")];
    }
616
    self.navigationController.toolbarHidden = !editing;
617
618
}

619
620
621
622
623
- (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewCellEditingStyleDelete;
}

624
- (IBAction)leftButtonAction:(id)sender
625
{
626
    [[(VLCAppDelegate*)[UIApplication sharedApplication].delegate revealController] toggleSidebar:![(VLCAppDelegate*)[UIApplication sharedApplication].delegate revealController].sidebarShowing duration:kGHRevealSidebarDefaultAnimationDuration];
627
628
629

    if (self.isEditing)
        [self setEditing:NO animated:YES];
630
631
}

632
633
634
- (IBAction)backToAllItems:(id)sender
{
    [self setLibraryMode:_libraryMode];
635
    [self updateViewContents];
636
637
}

638
- (void)_endEditingWithHardReset:(BOOL)hardReset
639
{
640
    [[MLMediaLibrary sharedMediaLibrary] updateMediaDatabase];
641
642
643
644
    if (hardReset)
        [self updateViewContents];
    else
        [self reloadViews];
645

646
647
648
649
650
    [self setEditing:NO animated:YES];
}

- (void)deleteSelection
{
651
652
653
654
655
    NSArray *indexPaths;
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        indexPaths = [self.collectionView indexPathsForSelectedItems];
    else
        indexPaths = [self.tableView indexPathsForSelectedRows];
656
657
658
659
660
661
662
663
664
    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];

665
    [self _endEditingWithHardReset:YES];
666
}
667

668
669
- (void)renameSelection
{
670
671
672
673
674
    NSArray *indexPaths;
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        indexPaths = [self.collectionView indexPathsForSelectedItems];
    else
        indexPaths = [self.tableView indexPathsForSelectedRows];
675

676
    if (indexPaths.count < 1) {
677
        [self _endEditingWithHardReset:NO];
678
679
680
        return;
    }

681
682
683
684
685
    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;
686
687
688
689
690
691
692
693
    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
{
694
695
696
697
698
    NSArray *indexPaths;
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        indexPaths = [self.collectionView indexPathsForSelectedItems];
    else
        indexPaths = [self.tableView indexPathsForSelectedRows];
699
700
701
702
703
704
705
    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];

706
707
708
709
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        [self.collectionView deselectItemAtIndexPath:indexPaths[0] animated:YES];
    else
        [self.tableView deselectRowAtIndexPath:indexPaths[0] animated:YES];
710
711
712
713

    if (indexPaths.count > 1)
        [self renameSelection];
    else
714
        [self _endEditingWithHardReset:NO];
715
716
717
718
719
720
721
}

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

725
#pragma mark - coin coin
726

727
- (void)setLibraryMode:(VLCLibraryMode)mode
728
729
{
    _libraryMode = mode;
730
    [self updateViewContents];
731
732
}

Gleb Pinigin's avatar
Gleb Pinigin committed
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
#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);
}

751
752
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
753
754
755

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
        [self.collectionView.collectionViewLayout invalidateLayout];
756
757
}

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