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

17
#import "VLCLibraryViewController.h"
18
#import "VLCMovieViewController.h"
19
#import "VLCPlaylistTableViewCell.h"
20
#import "VLCPlaylistCollectionViewCell.h"
21
#import "NSString+SupportedMedia.h"
22
#import "VLCBugreporter.h"
23
#import "VLCAppDelegate.h"
24
#import "VLCFirstStepsViewController.h"
25 26
#import "VLCFolderCollectionViewFlowLayout.h"
#import "LXReorderableCollectionViewFlowLayout.h"
27
#import "VLCOpenInActivity.h"
28
#import "VLCNavigationController.h"
29
#import "VLCPlaybackController+MediaLibrary.h"
30
#import "VLCKeychainCoordinator.h"
31
#import "GTScrollNavigationBar.h"
32 33

#import <AssetsLibrary/AssetsLibrary.h>
34
#import <CoreSpotlight/CoreSpotlight.h>
35

36 37
/* prefs keys */
static NSString *kDisplayedFirstSteps = @"Did we display the first steps tutorial?";
38
static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
39
@implementation EmptyLibraryView
40 41 42 43

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

49 50
@end

51
@interface VLCLibraryViewController () <VLCFolderCollectionViewDelegateFlowLayout, LXReorderableCollectionViewDataSource, LXReorderableCollectionViewDelegateFlowLayout, UITableViewDataSource, UITableViewDelegate, MLMediaLibrary, VLCMediaListDelegate, UISearchBarDelegate, UISearchDisplayDelegate> {
Felix Paul Kühne's avatar
Felix Paul Kühne committed
52
    NSMutableArray *_foundMedia;
53
    VLCLibraryMode _libraryMode;
54
    VLCLibraryMode _previousLibraryMode;
55
    UIBarButtonItem *_menuButton;
56 57 58 59
    NSMutableArray *_indexPaths;
    id _folderObject;
    VLCFolderCollectionViewFlowLayout *_folderLayout;
    LXReorderableCollectionViewFlowLayout *_reorderLayout;
60
    BOOL _inFolder;
Soomin Lee's avatar
Soomin Lee committed
61
    BOOL _isSelected;
62
    BOOL _deleteFromTableView;
63
    UILongPressGestureRecognizer *_longPressGestureRecognizer;
64 65 66 67

    NSMutableArray *_searchData;
    UISearchBar *_searchBar;
    UISearchDisplayController *_searchDisplayController;
68

Soomin Lee's avatar
Soomin Lee committed
69
    UIBarButtonItem *_selectAllBarButtonItem;
70 71 72
    UIBarButtonItem *_createFolderBarButtonItem;
    UIBarButtonItem *_openInActivityBarButtonItem;
    UIBarButtonItem *_removeFromFolderBarButtonItem;
73
    UIBarButtonItem *_deleteSelectedBarButtonItem;
74
    VLCOpenInActivity *_openInActivity;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
75
}
76

77
@property (nonatomic, strong) UIBarButtonItem *displayModeBarButtonItem;
78
@property (nonatomic, strong) UITableView *tableView;
79
@property (nonatomic, strong) UICollectionView *collectionView;
80
@property (nonatomic, strong) EmptyLibraryView *emptyLibraryView;
81
@property (nonatomic) BOOL usingTableViewToShowData;
82

Felix Paul Kühne's avatar
Felix Paul Kühne committed
83 84
@end

85
@implementation VLCLibraryViewController
Felix Paul Kühne's avatar
Felix Paul Kühne committed
86

87 88 89 90
- (void)dealloc
{
}

91 92 93 94
+ (void)initialize
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults registerDefaults:@{kDisplayedFirstSteps : [NSNumber numberWithBool:NO]}];
95
    [defaults registerDefaults:@{kUsingTableViewToShowData : [NSNumber numberWithBool:UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone]}];
96 97
}

98 99
- (void)loadView
{
100
    [self setupContentViewWithContentInset:NO];
101
    [self setViewFromDeviceOrientation];
102
    [self updateViewsForCurrentDisplayMode];
103
    _libraryMode = VLCLibraryModeAllFiles;
104

105 106 107 108 109 110 111
    self.emptyLibraryView = [[[NSBundle mainBundle] loadNibNamed:@"VLCEmptyLibraryView" owner:self options:nil] lastObject];
    _emptyLibraryView.emptyLibraryLongDescriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
    _emptyLibraryView.emptyLibraryLongDescriptionLabel.numberOfLines = 0;
}

- (void)setupContentViewWithContentInset:(BOOL)setInset
{
Tobias's avatar
Tobias committed
112
    CGRect viewDimensions = [UIApplication sharedApplication].keyWindow.bounds;
113 114 115 116
    UIView *contentView = [[UIView alloc] initWithFrame:viewDimensions];
    contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    contentView.backgroundColor = [UIColor VLCDarkBackgroundColor];

117
    if (self.usingTableViewToShowData) {
118
        if(!_tableView) {
119
            _tableView = [[UITableView alloc] initWithFrame:viewDimensions style:UITableViewStylePlain];
120
            _tableView.backgroundColor = [UIColor VLCDarkBackgroundColor];
121 122 123 124 125
            CGRect frame = _tableView.bounds;
            frame.origin.y = -frame.size.height;
            UIView *topView = [[UIView alloc] initWithFrame:frame];
            topView.backgroundColor = [UIColor VLCDarkBackgroundColor];
            [_tableView addSubview:topView];
126 127 128 129 130 131
            _tableView.rowHeight = [VLCPlaylistTableViewCell heightOfCell];
            _tableView.separatorColor = [UIColor VLCDarkBackgroundColor];
            _tableView.delegate = self;
            _tableView.dataSource = self;
            _tableView.opaque = YES;
            _tableView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
132
            _tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
133
            _tableView.tableHeaderView = _searchBar;
134
            _tableView.tableFooterView = [UIView new];
135 136
            self.navigationController.scrollNavigationBar.scrollView = self.tableView;

137
        }
138
        _tableView.frame = contentView.bounds;
139
        [contentView addSubview:_tableView];
140
        [_tableView reloadData];
141
    } else {
142 143
        if (!_collectionView) {
            _folderLayout = [[VLCFolderCollectionViewFlowLayout alloc] init];
144
            _collectionView = [[UICollectionView alloc] initWithFrame:viewDimensions collectionViewLayout:_folderLayout];
145 146 147 148 149 150
            _collectionView.alwaysBounceVertical = YES;
            _collectionView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
            _collectionView.delegate = self;
            _collectionView.dataSource = self;
            _collectionView.opaque = YES;
            _collectionView.backgroundColor = [UIColor VLCDarkBackgroundColor];
151
            _collectionView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
152 153
            _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_collectionViewHandleLongPressGesture:)];
            [_collectionView addGestureRecognizer:_longPressGestureRecognizer];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
154
            [_collectionView registerNib:[UINib nibWithNibName:@"VLCPlaylistCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:@"PlaylistCell"];
155
            self.navigationController.scrollNavigationBar.scrollView = self.collectionView;
156
        }
157
        _collectionView.frame = contentView.bounds;
158
        [contentView addSubview:_collectionView];
159
        [_collectionView reloadData];
160
    }
161
    self.view = contentView;
162 163 164 165
}

#pragma mark -

166 167 168 169 170 171 172
- (void)viewWillLayoutSubviews {
    UIScrollView *dataView = self.usingTableViewToShowData ? _tableView : _collectionView;

    [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
    [dataView setContentInset:UIEdgeInsetsZero];
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
173 174 175
- (void)viewDidLoad
{
    [super viewDidLoad];
176
    self.title = NSLocalizedString(@"LIBRARY_ALL_FILES", nil);
177 178
    _menuButton = [UIBarButtonItem themedRevealMenuButtonWithTarget:self andSelector:@selector(leftButtonAction:)];
    self.navigationItem.leftBarButtonItem = _menuButton;
179

180
    self.editButtonItem.title = NSLocalizedString(@"BUTTON_EDIT", nil);
Felix Paul Kühne's avatar
Felix Paul Kühne committed
181
    self.editButtonItem.tintColor = [UIColor whiteColor];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
182

Soomin Lee's avatar
Soomin Lee committed
183 184 185 186 187 188
    _selectAllBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"BUTTON_ALL", nil) style:UIBarButtonItemStylePlain target:self action:@selector(handleSelection)];
    _selectAllBarButtonItem.tintColor = [UIColor whiteColor];
    UIFont *font = [UIFont boldSystemFontOfSize:17];
    NSDictionary *attributes = @{NSFontAttributeName: font};
    [_selectAllBarButtonItem setTitleTextAttributes:attributes forState:UIControlStateNormal];

189 190
    _emptyLibraryView.emptyLibraryLabel.text = NSLocalizedString(@"EMPTY_LIBRARY", nil);
    _emptyLibraryView.emptyLibraryLongDescriptionLabel.text = NSLocalizedString(@"EMPTY_LIBRARY_LONG", nil);
191
    [_emptyLibraryView.emptyLibraryLongDescriptionLabel sizeToFit];
192
    [_emptyLibraryView.learnMoreButton setTitle:NSLocalizedString(@"BUTTON_LEARN_MORE", nil) forState:UIControlStateNormal];
193
    _createFolderBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemOrganize target:self action:@selector(createFolder)];
194 195

    // Better visual alignment with the action button
196 197 198 199 200 201 202
    _createFolderBarButtonItem.imageInsets = UIEdgeInsetsMake(4, 0, -4, 0);
    _createFolderBarButtonItem.landscapeImagePhoneInsets = UIEdgeInsetsMake(3, 0, -3, 0);

    _removeFromFolderBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemReply target:self action:@selector(removeFromFolder)];
    _removeFromFolderBarButtonItem.imageInsets = UIEdgeInsetsMake(4, 0, -4, 0);
    _removeFromFolderBarButtonItem.landscapeImagePhoneInsets = UIEdgeInsetsMake(3, 0, -3, 0);
    _removeFromFolderBarButtonItem.enabled = NO;
203

204 205
    _openInActivityBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(actOnSelection:)];
    _openInActivityBarButtonItem.enabled = NO;
206

207 208 209
    _deleteSelectedBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(deleteSelection:)];
    _deleteFromTableView = NO;

210 211
    UIBarButtonItem *fixedSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
    fixedSpace.width = 20;
212 213
    UIBarButtonItem *secondFixedSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
    fixedSpace.width = 20;
214 215 216 217 218

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        fixedSpace.width *= 2;
    }

219 220 221 222 223 224 225 226
    [self setToolbarItems:@[_openInActivityBarButtonItem,
                            fixedSpace,
                            _createFolderBarButtonItem,
                            [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
                            [UIBarButtonItem themedDarkToolbarButtonWithTitle:NSLocalizedString(@"BUTTON_RENAME", nil) target:self andSelector:@selector(renameSelection)],
                            [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
                            _removeFromFolderBarButtonItem,
                            secondFixedSpace,
227
                            _deleteSelectedBarButtonItem]];
228
    self.navigationController.toolbar.barStyle = UIBarStyleBlack;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
229 230
    self.navigationController.toolbar.tintColor = [UIColor whiteColor];
    [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
231

232 233
    _searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
    UINavigationBar *navBar = self.navigationController.navigationBar;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
234 235 236
    _searchBar.barTintColor = navBar.barTintColor;
    // cancel button tint color of UISearchBar with white color
    [[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIColor whiteColor], NSForegroundColorAttributeName, nil] forState:UIControlStateNormal];
237 238 239 240 241 242 243 244 245 246 247
    _searchBar.tintColor = navBar.tintColor;
    _searchBar.translucent = navBar.translucent;
    _searchBar.opaque = navBar.opaque;
    _searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar contentsController:self];
    _searchDisplayController.delegate = self;
    _searchDisplayController.searchResultsDataSource = self;
    _searchDisplayController.searchResultsDelegate = self;
    _searchDisplayController.searchResultsTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    _searchDisplayController.searchResultsTableView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
    _searchBar.delegate = self;

248
    [self setSearchBar:YES resetContent:YES];
249
    self.edgesForExtendedLayout = UIRectEdgeNone;
250

251 252 253
    @synchronized (self) {
        _searchData = [[NSMutableArray alloc] init];
    }
Felix Paul Kühne's avatar
Felix Paul Kühne committed
254 255
}

256 257 258
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
259
    [self.collectionView.collectionViewLayout invalidateLayout];
260
    [self _displayEmptyLibraryViewIfNeeded];
261
    [self enableNavigationBarAnimation:YES resetPositionWithAnimation:YES];
262 263
}

264 265
- (void)viewDidAppear:(BOOL)animated
{
266 267
    [super viewDidAppear:animated];

268 269 270 271 272 273 274
    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];
    }

275
    if (_foundMedia.count < 1)
276
        [self updateViewContents];
277 278 279 280 281 282 283 284 285
    [[MLMediaLibrary sharedMediaLibrary] performSelector:@selector(libraryDidAppear) withObject:nil afterDelay:1.];
}

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

286 287 288 289 290 291 292 293 294 295 296
- (BOOL)canBecomeFirstResponder
{
    return YES;
}

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

297 298
- (void)openMediaObject:(NSManagedObject *)mediaObject
{
299 300 301 302
    if ([mediaObject isKindOfClass:[MLAlbum class]] || [mediaObject isKindOfClass:[MLShow class]]) {

        BOOL isAlbum = [mediaObject isKindOfClass:[MLAlbum class]];
        NSArray* array =  isAlbum ? [(MLAlbum *)mediaObject sortedTracks] : [(MLShow *)mediaObject sortedEpisodes];
303
        @synchronized(_foundMedia) {
304
            _foundMedia = [NSMutableArray arrayWithArray:array];
305
        }
306
        self.navigationItem.leftBarButtonItem = [UIBarButtonItem themedBackButtonWithTarget:self andSelector:@selector(backToAllItems:)];
307
        if (_libraryMode == VLCLibraryModeAllFiles)
308
            self.navigationItem.leftBarButtonItem.title = NSLocalizedString(@"BUTTON_BACK", nil);
309
        else
310
            [self.navigationItem.leftBarButtonItem setTitle: isAlbum ? NSLocalizedString(@"LIBRARY_MUSIC", nil) : NSLocalizedString(@"LIBRARY_SERIES", nil)];
311 312
        self.title = [(MLAlbum*)mediaObject name];
        [self reloadViews];
313 314
    } else if ([mediaObject isKindOfClass:[MLLabel class]]) {
        MLLabel *folder = (MLLabel*) mediaObject;
315
        _inFolder = YES;
316
        [self.navigationController.scrollNavigationBar resetToDefaultPositionWithAnimation:YES];
317
        if (!self.usingTableViewToShowData) {
318
            if (![self.collectionView.collectionViewLayout isEqual:_reorderLayout]) {
319
                for (UIGestureRecognizer *recognizer in _collectionView.gestureRecognizers) {
320 321 322 323 324
                    if (recognizer == _folderLayout.panGestureRecognizer || recognizer == _folderLayout.longPressGestureRecognizer || recognizer == _longPressGestureRecognizer)
                        [self.collectionView removeGestureRecognizer:recognizer];
                }
                _reorderLayout = [[LXReorderableCollectionViewFlowLayout alloc] init];
                [self.collectionView setCollectionViewLayout:_reorderLayout animated:NO];
325
            }
326
        }
327
        _libraryMode = VLCLibraryModeFolder;
328
        @synchronized(_foundMedia) {
329 330
            _foundMedia = [NSMutableArray arrayWithArray:[folder sortedFolderItems]];
        }
331
        self.navigationItem.leftBarButtonItem = [UIBarButtonItem themedBackButtonWithTarget:self andSelector:@selector(backToAllItems:)];
332
        self.navigationItem.leftBarButtonItem.title = NSLocalizedString(@"BUTTON_BACK", nil);
333 334
        self.title = [folder name];

335 336
        _removeFromFolderBarButtonItem.enabled = YES;
        _createFolderBarButtonItem.enabled = NO;
337 338 339

        [self reloadViews];
        return;
340 341 342
    } else {
        VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
        [vpc playMediaLibraryObject:mediaObject];
343 344 345 346 347 348 349

        [self createSpotlightItem:mediaObject];
    }
}

- (void)createSpotlightItem:(nonnull NSManagedObject *)mediaObject
{
350
    if ([CSSearchableItemAttributeSet class] != nil && ![[VLCKeychainCoordinator defaultCoordinator] passcodeLockEnabled]) {
351
        self.userActivity = [[NSUserActivity alloc] initWithActivityType:kVLCUserActivityPlaying];
352 353

        MLFile *file = nil;
354
        if ([mediaObject isKindOfClass:[MLAlbumTrack class]]) {
355
            file = [(MLAlbumTrack *)mediaObject anyFileFromTrack];
356
        } else if ([mediaObject isKindOfClass:[MLShowEpisode class]]) {
357 358 359
            file = [(MLShowEpisode *)mediaObject anyFileFromEpisode];
        } else if ([mediaObject isKindOfClass:[MLFile class]]){
            file = (MLFile *)mediaObject;
360
        }
361 362 363 364
        self.userActivity.title = file.title;
        self.userActivity.contentAttributeSet = file.coreSpotlightAttributeSet;
        self.userActivity.userInfo = @{@"playingmedia":mediaObject.objectID.URIRepresentation};

365 366 367 368
        self.userActivity.eligibleForSearch = YES;
        self.userActivity.eligibleForHandoff = YES;
        //self.userActivity.contentUserAction = NSUserActivityContentUserActionPlay;
        [self.userActivity becomeCurrent];
369
    }
370 371
}

372
- (void)removeMediaObject:(id)managedObject updateDatabase:(BOOL)updateDB
373 374 375 376 377 378 379 380 381 382 383 384
{
        // 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];
        }
385
        [[MLMediaLibrary sharedMediaLibrary] removeObject: album];
386 387 388 389 390 391 392 393 394 395 396
        // 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];
        }
397
        [[MLMediaLibrary sharedMediaLibrary] removeObject: show];
398 399 400 401 402 403 404 405
        // 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
406
        [[MLMediaLibrary sharedMediaLibrary] removeObject: episode];
407 408 409 410 411 412
    } else if ([managedObject isKindOfClass:[MLAlbumTrack class]]) {
        MLAlbumTrack *track = managedObject;
        NSSet *iterFiles = [NSSet setWithSet:track.files];

        for (MLFile *file in iterFiles)
            [self _deleteMediaObject:file];
413 414 415 416 417 418 419 420 421
    } else if ([managedObject isKindOfClass:[MLLabel class]]) {
        MLLabel *folder = managedObject;
        NSSet *iterFiles = [NSSet setWithSet:folder.files];
        [folder removeFiles:folder.files];
        for (MLFile *file in iterFiles)
            [self _deleteMediaObject:file];
        [[MLMediaLibrary sharedMediaLibrary] removeObject:folder];
    }
    else
422
        [self _deleteMediaObject:managedObject];
423

424 425 426 427
    if (updateDB) {
        [[MLMediaLibrary sharedMediaLibrary] updateMediaDatabase];
        [self updateViewContents];
    }
428 429 430
}

- (void)_deleteMediaObject:(MLFile *)mediaObject
431
{
432
    if (_inFolder)
433 434
        [self rearrangeFolderTrackNumbersForRemovedItem:mediaObject];

435 436 437 438 439 440 441 442 443 444
    /* stop playback if needed */
    VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
    if (vpc.isPlaying) {
        MLFile *currentlyPlayingFile = [[MLFile fileForURL:vpc.mediaPlayer.media.url] firstObject];
        if (currentlyPlayingFile) {
            if (currentlyPlayingFile == mediaObject)
                [vpc stopPlayback];
        }
    }

445
    NSFileManager *fileManager = [NSFileManager defaultManager];
446
    NSString *folderLocation = [[mediaObject.url path] stringByDeletingLastPathComponent];
447
    NSArray *allfiles = [fileManager contentsOfDirectoryAtPath:folderLocation error:nil];
448
    NSString *fileName = [mediaObject.path.lastPathComponent stringByDeletingPathExtension];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
449 450
    if (!fileName)
        return;
451 452 453
    NSIndexSet *indexSet = [allfiles indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
       return ([obj rangeOfString:fileName].location != NSNotFound);
    }];
454
    NSUInteger count = indexSet.count;
455 456 457 458 459 460 461 462
    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];
    }
463
    [fileManager removeItemAtURL:mediaObject.url error:nil];
464 465 466 467
}

- (void)_displayEmptyLibraryViewIfNeeded
{
468 469 470
    if (self.emptyLibraryView.superview)
        [self.emptyLibraryView removeFromSuperview];

Gleb Pinigin's avatar
Gleb Pinigin committed
471
    if (_foundMedia.count == 0) {
472 473 474 475
        _inFolder = (_libraryMode == VLCLibraryModeFolder || _libraryMode == VLCLibraryModeCreateFolder);
        self.emptyLibraryView.emptyLibraryLabel.text = _inFolder ? NSLocalizedString(@"FOLDER_EMPTY", nil) : NSLocalizedString(@"EMPTY_LIBRARY", nil);
        self.emptyLibraryView.emptyLibraryLongDescriptionLabel.text = _inFolder ? NSLocalizedString(@"FOLDER_EMPTY_LONG", nil) : NSLocalizedString(@"EMPTY_LIBRARY_LONG", nil);
        self.emptyLibraryView.learnMoreButton.hidden = _inFolder;
Gleb Pinigin's avatar
Gleb Pinigin committed
476
        self.emptyLibraryView.frame = self.view.bounds;
477
        [self.view addSubview:self.emptyLibraryView];
478
        self.navigationItem.rightBarButtonItems = nil;
479 480 481 482
    } else {
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
            UIBarButtonItem *toggleDisplayedView = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"tableViewIcon"] style:UIBarButtonItemStylePlain target:self action:@selector(toggleDisplayedView:)];
            self.navigationItem.rightBarButtonItems = @[toggleDisplayedView, self.editButtonItem];
483
            self.displayModeBarButtonItem = toggleDisplayedView;
484 485 486 487
        } else {
            self.navigationItem.rightBarButtonItem = self.editButtonItem;
        }
    }
488
    if (self.usingTableViewToShowData)
489 490
        _tableView.separatorStyle = (_foundMedia.count > 0)? UITableViewCellSeparatorStyleSingleLine:
                                                             UITableViewCellSeparatorStyleNone;
491
    else
492
        [self.collectionView.collectionViewLayout invalidateLayout];
493 494

    [self updateViewsForCurrentDisplayMode];
495 496
}

497
- (void)setViewFromDeviceOrientation
498
{
499 500
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        UIDevice *currentDevice = [UIDevice currentDevice];
501 502 503
        UIDeviceOrientation orientation = currentDevice.orientation;

        BOOL isPortrait = (orientation == UIDeviceOrientationUnknown) ? self.usingTableViewToShowData : UIDeviceOrientationIsPortrait(orientation);
504

505 506 507
        if (self.isEditing) {
            [self setEditing:NO animated:NO];
        }
508
        [self setUsingTableViewToShowData:isPortrait];
509
        [self _displayEmptyLibraryViewIfNeeded];
510
        [self enableNavigationBarAnimation:YES resetPositionWithAnimation:YES];
511 512 513 514 515 516 517 518 519
    }
}

- (void)setSearchBar:(BOOL)enable resetContent:(BOOL)resetContent
{
    if (enable)
        self.tableView.tableHeaderView = _searchBar;
    else
        self.tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.tableView.bounds.size.width, CGFLOAT_MIN)];
520 521 522 523 524 525 526
    if (resetContent) {
        CGPoint contentOffset = self.tableView.contentOffset;
        contentOffset.y += CGRectGetHeight(self.tableView.tableHeaderView.frame);
        self.tableView.contentOffset = contentOffset;
    }
}

527 528 529 530 531 532 533 534 535 536 537 538 539
- (void)enableNavigationBarAnimation:(BOOL)enable resetPositionWithAnimation:(BOOL)resetPositionWithAnimation
{
    if (!enable) {
        self.navigationController.scrollNavigationBar.scrollView = nil;
    } else {
        self.navigationController.scrollNavigationBar.scrollView = self.usingTableViewToShowData ? self.tableView : self.collectionView;
    }

    if (resetPositionWithAnimation) {
        [self.navigationController.scrollNavigationBar resetToDefaultPositionWithAnimation:YES];
    }
}

540 541
- (void)libraryUpgradeComplete
{
542
    self.title = NSLocalizedString(@"LIBRARY_ALL_FILES", nil);
Gleb Pinigin's avatar
Gleb Pinigin committed
543
    self.navigationItem.leftBarButtonItem = _menuButton;
544
    self.emptyLibraryView.emptyLibraryLongDescriptionLabel.hidden = NO;
545
    self.emptyLibraryView.emptyLibraryLabel.text = NSLocalizedString(@"EMPTY_LIBRARY", nil);
546 547 548
    [self.emptyLibraryView.activityIndicator stopAnimating];
    [self.emptyLibraryView removeFromSuperview];

549 550 551 552
    [self updateViewContents];
}

- (void)updateViewContents
Felix Paul Kühne's avatar
Felix Paul Kühne committed
553
{
554 555 556
    @synchronized(self) {
        _foundMedia = [[NSMutableArray alloc] init];
    }
557

558 559 560 561 562
    if (![(VLCAppDelegate *)[UIApplication sharedApplication].delegate passcodeValidated]) {
        APLog(@"library is locked, won't show contents");
        return;
    }

563
    self.navigationItem.leftBarButtonItem = _menuButton;
564

565
    if (_libraryMode == VLCLibraryModeAllAlbums)
566
        self.title = NSLocalizedString(@"LIBRARY_MUSIC", nil);
567
    else if( _libraryMode == VLCLibraryModeAllSeries)
568
        self.title = NSLocalizedString(@"LIBRARY_SERIES", nil);
569
    else
570
        self.title = NSLocalizedString(@"LIBRARY_ALL_FILES", nil);
571

572 573
    _createFolderBarButtonItem.enabled = (_libraryMode == VLCLibraryModeAllAlbums || _libraryMode == VLCLibraryModeAllSeries) ? NO : YES;
    _removeFromFolderBarButtonItem.enabled = NO;
574

575 576
    /* add all albums */
    if (_libraryMode != VLCLibraryModeAllSeries) {
577
        NSArray *rawAlbums = [MLAlbum allAlbums];
578
        for (MLAlbum *album in rawAlbums) {
579 580
            if (_libraryMode != VLCLibraryModeAllAlbums) {
                if (album.name.length > 0 && album.tracks.count > 1) {
581
                    @synchronized(_foundMedia) {
582 583 584 585 586
                        [_foundMedia addObject:album];
                    }
                }
            } else {
                if (album.name.length > 0) {
587
                    @synchronized(_foundMedia) {
588 589
                        [_foundMedia addObject:album];
                    }
590 591
                }
            }
592
        }
593 594 595 596 597
    }
    if (_libraryMode == VLCLibraryModeAllAlbums) {
        [self reloadViews];
        return;
    }
598

599 600 601
    /* add all shows */
    NSArray *rawShows = [MLShow allShows];
    for (MLShow *show in rawShows) {
602
        if (show.name.length > 0 && show.episodes.count > 1) {
603
            @synchronized(_foundMedia) {
604 605 606
                [_foundMedia addObject:show];
            }
        }
607 608 609 610 611 612
    }
    if (_libraryMode == VLCLibraryModeAllSeries) {
        [self reloadViews];
        return;
    }

613 614
    /* add all folders*/
    NSArray *allFolders = [MLLabel allLabels];
615
    for (MLLabel *folder in allFolders) {
616
        @synchronized(_foundMedia) {
617 618 619
            [_foundMedia addObject:folder];
        }
    }
620

621 622 623
    /* add all remaining files */
    NSArray *allFiles = [MLFile allFiles];
    for (MLFile *file in allFiles) {
Felix Paul Kühne's avatar
Felix Paul Kühne committed
624 625 626 627 628 629
        if (file.labels != nil) {
            @synchronized(file.labels) {
                if (file.labels.count > 0)
                    continue;
            }
        }
630

631
        if (!file.isShowEpisode && !file.isAlbumTrack) {
632
            @synchronized(_foundMedia) {
633
                [_foundMedia addObject:file];
634 635 636 637
            }
        }
        else if (file.isShowEpisode) {
            if (file.showEpisode.show.episodes.count < 2) {
638
                @synchronized(_foundMedia) {
639 640 641
                    [_foundMedia addObject:file];
                }
            }
642 643 644 645 646 647

            /* older MediaLibraryKit versions don't send a show name in a popular
             * corner case. hence, we need to work-around here and force a reload
             * afterwards as this could lead to the 'all my shows are gone' 
             * syndrome (see #10435, #10464, #10432 et al) */
            if (file.showEpisode.show.name.length == 0) {
648
                file.showEpisode.show.name = NSLocalizedString(@"UNTITLED_SHOW", nil);
649 650
                [self performSelector:@selector(updateViewContents) withObject:nil afterDelay:0.1];
            }
651
        } else if (file.isAlbumTrack) {
652
            if (file.albumTrack.album.tracks.count < 2) {
653
                @synchronized(_foundMedia) {
654 655 656
                    [_foundMedia addObject:file];
                }
            }
657
        }
658
    }
659

660
    [self reloadViews];
661
}
662

663
- (void)reloadViews
664
{
665
    // Since this gets can get called at any point and wipe away the selections, we update the actionBarButtonItem here because this can happen if you tap "Save Video" in the UIActivityController and a media access alert view takes away focus (the corresponding 'became active' notification of UIApplication will call this). Or simply try bringing down the notification center to trigger this. Any existing UIActivityViewController session should be safe as it would have copies of the selected file references.
666
    if (self.usingTableViewToShowData) {
667
        [self.tableView reloadData];
668
        [self updateActionBarButtonItemStateWithSelectedIndexPaths:[self.tableView indexPathsForSelectedRows]];
669
        _isSelected = NO;
670
    } else {
Felix Paul Kühne's avatar
Felix Paul Kühne committed
671
        [self.collectionView reloadData];
672
        [self updateActionBarButtonItemStateWithSelectedIndexPaths:[self.collectionView indexPathsForSelectedItems]];
673 674 675
        if (_libraryMode == VLCLibraryModeAllFiles) {
            if (self.collectionView.collectionViewLayout != _folderLayout) {
                for (UIGestureRecognizer *recognizer in _collectionView.gestureRecognizers) {
676 677
                    if (recognizer == _reorderLayout.panGestureRecognizer ||
                        recognizer == _reorderLayout.longPressGestureRecognizer) {
678
                        [self.collectionView removeGestureRecognizer:recognizer];
679
                    }
680 681 682 683 684
                }
                [self.collectionView setCollectionViewLayout:_folderLayout animated:NO];
                [self.collectionView addGestureRecognizer:_longPressGestureRecognizer];
            }
        }
685
    }
686 687

    [self _displayEmptyLibraryViewIfNeeded];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
688 689
}

690 691
#pragma mark - Table View

Felix Paul Kühne's avatar
Felix Paul Kühne committed
692 693 694 695 696 697 698
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
699 700
    if (tableView == self.searchDisplayController.searchResultsTableView)
        return _searchData.count;
701

702
    return _foundMedia.count;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
703 704 705 706 707
}

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

710
    VLCPlaylistTableViewCell *cell = (VLCPlaylistTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
711
    if (cell == nil)
712
        cell = [VLCPlaylistTableViewCell cellWithReuseIdentifier:CellIdentifier];
713 714
    else
        [cell collapsWithAnimation:NO];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
715

716
    UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRightOnTableViewCellGestureAction:)];
717 718 719
    [swipeRight setDirection:(UISwipeGestureRecognizerDirectionRight)];
    [cell addGestureRecognizer:swipeRight];

720
    NSInteger row = indexPath.row;
721

722 723
    if (tableView == self.searchDisplayController.searchResultsTableView) {
        @synchronized (_searchData) {
724 725
            if (row < _searchData.count)
                cell.mediaObject = _searchData[row];
726 727 728
        }
    } else {
        @synchronized (_foundMedia) {
729 730
            if (row < _foundMedia.count)
                cell.mediaObject = _foundMedia[row];
731 732
        }
    }
733

Felix Paul Kühne's avatar
Felix Paul Kühne committed
734 735 736
    return cell;
}

737 738
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
739
    @synchronized(_foundMedia) {
740 741 742
        MLFile* object = _foundMedia[fromIndexPath.item];
        [_foundMedia removeObjectAtIndex:fromIndexPath.item];
        [_foundMedia insertObject:object atIndex:toIndexPath.item];
743 744
        if (![object isKindOfClass:[MLFile class]])
            return;
745 746
        object.folderTrackNumber = @(toIndexPath.item - 1);
        object = [_foundMedia objectAtIndex:fromIndexPath.item];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
747 748
        if (![object isKindOfClass:[MLFile class]])
            return;
749 750
        object.folderTrackNumber = @(fromIndexPath.item - 1);
    }
751 752 753 754
}

- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
755
    return _inFolder;
756 757
}

758 759
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
760
    cell.backgroundColor = (indexPath.row % 2 == 0)? [UIColor blackColor]: [UIColor VLCDarkBackgroundColor];
761
    cell.multipleSelectionBackgroundView.backgroundColor = cell.backgroundColor;
762 763
}

Felix Paul Kühne's avatar
Felix Paul Kühne committed
764 765 766 767 768 769 770
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
Felix Paul Kühne's avatar
Felix Paul Kühne committed
771 772
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        NSInteger row = indexPath.row;
773
        _deleteFromTableView = YES;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
774
        if (row < _foundMedia.count)
775
            [self deleteSelection:indexPath];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
776
    }
Felix Paul Kühne's avatar
Felix Paul Kühne committed
777 778
}

779 780 781 782 783 784 785
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (tableView.isEditing) {
        [self updateActionBarButtonItemStateWithSelectedIndexPaths:[tableView indexPathsForSelectedRows]];
    }
}

786
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Felix Paul Kühne's avatar
Felix Paul Kühne committed
787
{
788 789 790 791 792 793 794 795 796 797 798 799
    if ([(VLCPlaylistTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] isExpanded]) {
        [(VLCPlaylistTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] collapsWithAnimation:YES];
        return;
    }

    NSArray *visibleCells = [tableView visibleCells];
    NSUInteger cellCount = visibleCells.count;
    for (NSUInteger x = 0; x < cellCount; x++) {
        if ([visibleCells[x] isExpanded])
            [visibleCells[x] collapsWithAnimation:NO];
    }

800 801 802 803 804 805
    if (tableView.isEditing) {
        if (_libraryMode == VLCLibraryModeCreateFolder) {
            _folderObject = _foundMedia[indexPath.row];
            _libraryMode = _previousLibraryMode;
            [self updateViewContents];
            [self createFolderWithName:nil];
806 807
        } else {
            [self updateActionBarButtonItemStateWithSelectedIndexPaths:[tableView indexPathsForSelectedRows]];
808
        }
809
        return;
810
    }
811

812
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
813
    NSManagedObject *selectedObject;
814

Felix Paul Kühne's avatar
Felix Paul Kühne committed
815 816
    NSUInteger row = indexPath.row;
    if (tableView == self.searchDisplayController.searchResultsTableView) {
817 818 819 820
        @synchronized (_searchData) {
            if (row < _searchData.count)
                selectedObject = _searchData[row];
        }
Felix Paul Kühne's avatar
Felix Paul Kühne committed
821
    } else {
822 823 824 825
        @synchronized (_foundMedia) {
            if (row < _foundMedia.count)
                selectedObject = _foundMedia[row];
        }
Felix Paul Kühne's avatar
Felix Paul Kühne committed
826
    }
827

828
    if (_searchDisplayController.active)
829
        [_searchDisplayController setActive:NO animated:NO];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
830

Felix Paul Kühne's avatar
Felix Paul Kühne committed
831 832
    if (selectedObject != nil)
        [self openMediaObject:selectedObject];
833 834
}

835
#pragma mark - Gesture Action
836
- (void)swipeRightOnTableViewCellGestureAction:(UIGestureRecognizer *)recognizer
837
{
838
    if (self.tableView.isEditing) {
839
        [self setEditing:NO animated:YES];
840
    } else {
841 842
        [self setEditing:YES animated:YES];

843 844
        NSIndexPath *path = [self.tableView indexPathForRowAtPoint:[recognizer locationInView:self.tableView]];
        [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:path.row inSection:path.section]
845 846
                                animated:YES
                          scrollPosition:UITableViewScrollPositionNone];
847
        [self updateActionBarButtonItemStateWithSelectedIndexPaths:[self.tableView indexPathsForSelectedRows]];
848 849 850
    }
}

851 852 853 854 855 856 857
- (void)swipeRightOnCollectionViewCellGestureAction:(UIGestureRecognizer *)recognizer
{
    NSIndexPath *path = [self.collectionView indexPathForItemAtPoint:[recognizer locationInView:self.collectionView]];
    VLCPlaylistCollectionViewCell *cell = (VLCPlaylistCollectionViewCell *)[self.collectionView cellForItemAtIndexPath:path];
    [cell showMetadata:!cell.showsMetaData];
}

858 859 860 861 862 863 864 865 866
#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];
867 868 869 870 871
    @synchronized (_foundMedia) {
        NSUInteger row = indexPath.row;
        if (row < _foundMedia.count)
            cell.mediaObject = _foundMedia[row];
    }
Felix Paul Kühne's avatar
Felix Paul Kühne committed
872

873 874 875 876
    cell.collectionView = _collectionView;

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

877 878 879 880
    UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeRightOnCollectionViewCellGestureAction:)];
    [swipeRight setDirection:(UISwipeGestureRecognizerDirectionRight)];
    [cell addGestureRecognizer:swipeRight];

881 882 883 884 885
    return cell;
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
886
    const CGFloat maxCellWidth = [UIScreen mainScreen].bounds.size.width / 3;
Tobias's avatar
Tobias committed
887
    const CGFloat aspectRatio = 9.0/16.0;
888 889 890 891 892 893

    CGRect windowFrame = [UIApplication sharedApplication].keyWindow.frame;
    CGFloat windowWidth = windowFrame.size.width;

    int numberOfCellsPerRow = ceil(windowWidth/maxCellWidth);
    CGFloat cellWidth = windowWidth/numberOfCellsPerRow;
894
    cellWidth -= 5;
895 896

    return CGSizeMake(cellWidth, cellWidth * aspectRatio);
897 898 899 900
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
901
    return UIEdgeInsetsMake(5, 5, 5, 5);
902 903
}

904 905
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
906
    return 2.5;
907 908 909 910
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
Felix Paul Kühne's avatar
Felix Paul Kühne committed
911
    return 0.;
912 913
}

914 915
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
916
    if (self.editing) {
917 918
        if (_libraryMode == VLCLibraryModeCreateFolder) {
            _folderObject = _foundMedia[indexPath.item];
919
            [self updateViewContents];
920
            [self createFolderWithName:nil];
921
             _libraryMode = _previousLibraryMode;
922 923
        } else {
            [self updateActionBarButtonItemStateWithSelectedIndexPaths:[collectionView indexPathsForSelectedItems]];
924
        }
925 926 927 928
        [(VLCPlaylistCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath] selectionUpdate];
        return;
    }

929
    [collectionView deselectItemAtIndexPath:indexPath animated:NO];
Felix Paul Kühne's avatar
Felix Paul Kühne committed
930 931
    NSArray *visibleCells = [[collectionView visibleCells] copy];
    NSUInteger cellCount = visibleCells.count;
932

933 934 935 936 937 938
    for (NSUInteger x = 0; x < cellCount; x++) {
        VLCPlaylistCollectionViewCell *cell = visibleCells[x];
        if ([cell showsMetaData])
            [cell showMetadata:NO];
    }

939
    NSManagedObject *selectedObject;
Felix Paul Kühne's avatar
Felix Paul Kühne committed
940
    NSInteger row = indexPath.row;
941
    @synchronized(_foundMedia) {
Felix Paul Kühne's avatar
Felix Paul Kühne committed
942 943
        if (row < _foundMedia.count)
            selectedObject = _foundMedia[row];
944
    }
Felix Paul Kühne's avatar
Felix Paul Kühne committed
945 946
    if (selectedObject != nil)
        [self openMediaObject:selectedObject];
947 948
}

949 950
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
951 952 953 954
    if (self.editing) {
        [self updateActionBarButtonItemStateWithSelectedIndexPaths:[collectionView indexPathsForSelectedItems]];
    }

955 956 957
    [(VLCPlaylistCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath] selectionUpdate];
}