|
@@ -24,6 +24,7 @@
|
|
|
#import "VLCFirstStepsViewController.h"
|
|
|
#import "VLCFolderCollectionViewFlowLayout.h"
|
|
|
#import "VLCKeychainCoordinator.h"
|
|
|
+#import "VLCLibrarySearchDisplayDataSource.h"
|
|
|
#import "VLCMovieViewController.h"
|
|
|
#import "VLCNavigationController.h"
|
|
|
#import "VLCPlaylistCollectionViewCell.h"
|
|
@@ -63,7 +64,7 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
|
|
|
BOOL _deleteFromTableView;
|
|
|
UILongPressGestureRecognizer *_longPressGestureRecognizer;
|
|
|
|
|
|
- NSMutableArray *_searchData;
|
|
|
+ VLCLibrarySearchDisplayDataSource *_searchDataSource;
|
|
|
UISearchBar *_searchBar;
|
|
|
UISearchDisplayController *_searchDisplayController;
|
|
|
|
|
@@ -101,6 +102,7 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
|
|
|
[self setViewFromDeviceOrientation];
|
|
|
[self updateViewsForCurrentDisplayMode];
|
|
|
_libraryMode = VLCLibraryModeAllFiles;
|
|
|
+ _searchDataSource = [VLCLibrarySearchDisplayDataSource new];
|
|
|
|
|
|
self.emptyLibraryView = [[[NSBundle mainBundle] loadNibNamed:@"VLCEmptyLibraryView" owner:self options:nil] lastObject];
|
|
|
_emptyLibraryView.emptyLibraryLongDescriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
|
@@ -133,7 +135,6 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
|
|
|
_tableView.tableHeaderView = _searchBar;
|
|
|
_tableView.tableFooterView = [UIView new];
|
|
|
self.navigationController.scrollNavigationBar.scrollView = self.tableView;
|
|
|
-
|
|
|
}
|
|
|
_tableView.frame = contentView.bounds;
|
|
|
[contentView addSubview:_tableView];
|
|
@@ -237,18 +238,16 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
|
|
|
_searchBar.opaque = navBar.opaque;
|
|
|
_searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar contentsController:self];
|
|
|
_searchDisplayController.delegate = self;
|
|
|
- _searchDisplayController.searchResultsDataSource = self;
|
|
|
+ _searchDisplayController.searchResultsDataSource = _searchDataSource;
|
|
|
_searchDisplayController.searchResultsDelegate = self;
|
|
|
_searchDisplayController.searchResultsTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
|
|
_searchDisplayController.searchResultsTableView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
|
|
|
+ [_searchDisplayController.searchResultsTableView registerNib:[_searchDataSource nibclass] forCellReuseIdentifier:[_searchDataSource cellIdentifier]];
|
|
|
_searchBar.delegate = self;
|
|
|
|
|
|
[self setSearchBar:YES resetContent:YES];
|
|
|
self.edgesForExtendedLayout = UIRectEdgeNone;
|
|
|
|
|
|
- @synchronized (self) {
|
|
|
- _searchData = [[NSMutableArray alloc] init];
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
- (void)viewWillAppear:(BOOL)animated
|
|
@@ -708,9 +707,6 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
|
|
|
|
|
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
|
|
{
|
|
|
- if (tableView == self.searchDisplayController.searchResultsTableView)
|
|
|
- return _searchData.count;
|
|
|
-
|
|
|
return _foundMedia.count;
|
|
|
}
|
|
|
|
|
@@ -731,16 +727,9 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
|
|
|
|
|
|
NSInteger row = indexPath.row;
|
|
|
|
|
|
- if (tableView == self.searchDisplayController.searchResultsTableView) {
|
|
|
- @synchronized (_searchData) {
|
|
|
- if (row < _searchData.count)
|
|
|
- cell.mediaObject = _searchData[row];
|
|
|
- }
|
|
|
- } else {
|
|
|
- @synchronized (_foundMedia) {
|
|
|
- if (row < _foundMedia.count)
|
|
|
- cell.mediaObject = _foundMedia[row];
|
|
|
- }
|
|
|
+ @synchronized (_foundMedia) {
|
|
|
+ if (row < _foundMedia.count)
|
|
|
+ cell.mediaObject = _foundMedia[row];
|
|
|
}
|
|
|
|
|
|
return cell;
|
|
@@ -826,10 +815,7 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
|
|
|
|
|
|
NSUInteger row = indexPath.row;
|
|
|
if (tableView == self.searchDisplayController.searchResultsTableView) {
|
|
|
- @synchronized (_searchData) {
|
|
|
- if (row < _searchData.count)
|
|
|
- selectedObject = _searchData[row];
|
|
|
- }
|
|
|
+ selectedObject = [_searchDataSource objectAtIndex:row];
|
|
|
} else {
|
|
|
@synchronized (_foundMedia) {
|
|
|
if (row < _foundMedia.count)
|
|
@@ -1712,212 +1698,12 @@ static NSString *kUsingTableViewToShowData = @"UsingTableViewToShowData";
|
|
|
|
|
|
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
|
|
|
{
|
|
|
- @synchronized (_searchData) {
|
|
|
- [_searchData removeAllObjects];
|
|
|
- }
|
|
|
- NSManagedObject *item;
|
|
|
- NSRange nameRange;
|
|
|
-
|
|
|
@synchronized(_foundMedia) {
|
|
|
- NSInteger listCount = _foundMedia.count;
|
|
|
- for (int i = 0; i < listCount; i++) {
|
|
|
- item = _foundMedia[i];
|
|
|
-
|
|
|
- if ([item isKindOfClass:[MLAlbum class]]) {
|
|
|
- nameRange = [self _searchAlbum:(MLAlbum *)item forString:searchString];
|
|
|
- } else if ([item isKindOfClass:[MLAlbumTrack class]]) {
|
|
|
- nameRange = [self _searchAlbumTrack:(MLAlbumTrack *)item forString:searchString];
|
|
|
- } else if ([item isKindOfClass:[MLShowEpisode class]]) {
|
|
|
- nameRange = [self _searchShowEpisode:(MLShowEpisode *)item forString:searchString];
|
|
|
- } else if ([item isKindOfClass:[MLShow class]]) {
|
|
|
- nameRange = [self _searchShow:(MLShow *)item forString:searchString];
|
|
|
- } else if ([item isKindOfClass:[MLLabel class]])
|
|
|
- nameRange = [self _searchLabel:(MLLabel *)item forString:searchString];
|
|
|
- else // simple file
|
|
|
- nameRange = [self _searchFile:(MLFile*)item forString:searchString];
|
|
|
-
|
|
|
- @synchronized (_searchData) {
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- [_searchData addObject:item];
|
|
|
- }
|
|
|
- }
|
|
|
+ [_searchDataSource shouldReloadTableForSearchString:searchString searchableFiles:_foundMedia];
|
|
|
}
|
|
|
-
|
|
|
return YES;
|
|
|
}
|
|
|
|
|
|
-- (NSRange)_searchAlbumTrack:(MLAlbumTrack *)albumTrack forString:(NSString *)searchString
|
|
|
-{
|
|
|
- NSString *trackTitle = albumTrack.title;
|
|
|
- NSRange nameRange = [trackTitle rangeOfString:searchString options:NSCaseInsensitiveSearch];
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- return nameRange;
|
|
|
-
|
|
|
- NSMutableArray *stringsToSearch = [[NSMutableArray alloc] initWithObjects:trackTitle, nil];
|
|
|
- if ([albumTrack artist])
|
|
|
- [stringsToSearch addObject:[albumTrack artist]];
|
|
|
- if ([albumTrack genre])
|
|
|
- [stringsToSearch addObject:[albumTrack genre]];
|
|
|
-
|
|
|
- NSArray *substrings = [searchString componentsSeparatedByString:@" "];
|
|
|
- NSUInteger substringCount = substrings.count;
|
|
|
- NSUInteger searchStringCount = stringsToSearch.count;
|
|
|
-
|
|
|
- for (NSUInteger x = 0; x < substringCount; x++) {
|
|
|
- for (NSUInteger y = 0; y < searchStringCount; y++) {
|
|
|
- nameRange = [stringsToSearch[y] rangeOfString:substrings[x] options:NSCaseInsensitiveSearch];
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- break;
|
|
|
- }
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- break;
|
|
|
- }
|
|
|
- return nameRange;
|
|
|
-}
|
|
|
-
|
|
|
-- (NSRange)_searchAlbum:(MLAlbum *)album forString:(NSString *)searchString
|
|
|
-{
|
|
|
- NSString *albumName = [album name];
|
|
|
- NSRange nameRange = [albumName rangeOfString:searchString options:NSCaseInsensitiveSearch];
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- return nameRange;
|
|
|
-
|
|
|
- if ([album releaseYear]) {
|
|
|
- nameRange = [[album releaseYear] rangeOfString:searchString options:NSCaseInsensitiveSearch];
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- return nameRange;
|
|
|
- }
|
|
|
-
|
|
|
- /* split search string into substrings and try again */
|
|
|
- NSArray *substrings = [searchString componentsSeparatedByString:@" "];
|
|
|
- NSUInteger substringCount = substrings.count;
|
|
|
- if (substringCount > 1) {
|
|
|
- for (NSUInteger x = 0; x < substringCount; x++) {
|
|
|
- nameRange = [searchString rangeOfString:substrings[x] options:NSCaseInsensitiveSearch];
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- return nameRange;
|
|
|
-
|
|
|
- /* search our tracks if we can't find what the user is looking for */
|
|
|
- NSArray *tracks = [album sortedTracks];
|
|
|
- NSUInteger trackCount = tracks.count;
|
|
|
- for (NSUInteger x = 0; x < trackCount; x++) {
|
|
|
- nameRange = [self _searchAlbumTrack:tracks[x] forString:searchString];
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- break;
|
|
|
- }
|
|
|
- return nameRange;
|
|
|
-}
|
|
|
-
|
|
|
-- (NSRange)_searchShowEpisode:(MLShowEpisode *)episode forString:(NSString *)searchString
|
|
|
-{
|
|
|
- /* basic search first, then try more complex things */
|
|
|
- NSString *episodeName = [episode name];
|
|
|
- NSRange nameRange;
|
|
|
-
|
|
|
- if (episodeName) {
|
|
|
- nameRange = [episodeName rangeOfString:searchString options:NSCaseInsensitiveSearch];
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- return nameRange;
|
|
|
- }
|
|
|
-
|
|
|
- /* split search string into substrings and try again */
|
|
|
- NSArray *substrings = [searchString componentsSeparatedByString:@" "];
|
|
|
- NSUInteger substringCount = substrings.count;
|
|
|
- if (substringCount > 1) {
|
|
|
- for (NSUInteger x = 0; x < substringCount; x++) {
|
|
|
- nameRange = [searchString rangeOfString:substrings[x] options:NSCaseInsensitiveSearch];
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return nameRange;
|
|
|
-}
|
|
|
-
|
|
|
-- (NSRange)_searchShow:(MLShow *)mediaShow forString:(NSString *)searchString
|
|
|
-{
|
|
|
- /* basic search first, then try more complex things */
|
|
|
- NSRange nameRange = [[mediaShow name] rangeOfString:searchString options:NSCaseInsensitiveSearch];
|
|
|
-
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- return nameRange;
|
|
|
-
|
|
|
- /* split search string into substrings and try again */
|
|
|
- NSArray *substrings = [searchString componentsSeparatedByString:@" "];
|
|
|
- NSUInteger substringCount = substrings.count;
|
|
|
- if (substringCount > 1) {
|
|
|
- for (NSUInteger x = 0; x < substringCount; x++) {
|
|
|
- nameRange = [searchString rangeOfString:substrings[x] options:NSCaseInsensitiveSearch];
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- return nameRange;
|
|
|
-
|
|
|
- /* user didn't search for our show name, let's do a deeper search on the episodes */
|
|
|
- NSArray *episodes = [mediaShow sortedEpisodes];
|
|
|
- NSUInteger episodeCount = episodes.count;
|
|
|
- for (NSUInteger x = 0; x < episodeCount; x++)
|
|
|
- nameRange = [self _searchShowEpisode:episodes[x] forString:searchString];
|
|
|
-
|
|
|
- return nameRange;
|
|
|
-}
|
|
|
-
|
|
|
-- (NSRange)_searchLabel:(MLLabel *)mediaLabel forString:(NSString *)searchString
|
|
|
-{
|
|
|
- /* basic search first, then try more complex things */
|
|
|
- NSRange nameRange = [[mediaLabel name] rangeOfString:searchString options:NSCaseInsensitiveSearch];
|
|
|
-
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- return nameRange;
|
|
|
-
|
|
|
- /* user didn't search for our label name, let's do a deeper search */
|
|
|
- NSArray *files = [mediaLabel sortedFolderItems];
|
|
|
- NSUInteger fileCount = files.count;
|
|
|
- for (NSUInteger x = 0; x < fileCount; x++) {
|
|
|
- nameRange = [self _searchFile:files[x] forString:searchString];
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- break;
|
|
|
- }
|
|
|
- return nameRange;
|
|
|
-}
|
|
|
-
|
|
|
-- (NSRange)_searchFile:(MLFile *)mediaFile forString:(NSString *)searchString
|
|
|
-{
|
|
|
- /* basic search first, then try more complex things */
|
|
|
- NSRange nameRange = [[mediaFile title] rangeOfString:searchString options:NSCaseInsensitiveSearch];
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- return nameRange;
|
|
|
-
|
|
|
- NSMutableArray *stringsToSearch = [[NSMutableArray alloc] initWithObjects:[mediaFile title], nil];
|
|
|
- if ([mediaFile artist])
|
|
|
- [stringsToSearch addObject:[mediaFile artist]];
|
|
|
- if ([mediaFile releaseYear])
|
|
|
- [stringsToSearch addObject:[mediaFile releaseYear]];
|
|
|
-
|
|
|
- NSArray *substrings = [searchString componentsSeparatedByString:@" "];
|
|
|
- NSUInteger substringCount = substrings.count;
|
|
|
- NSUInteger searchStringCount = stringsToSearch.count;
|
|
|
-
|
|
|
- for (NSUInteger x = 0; x < substringCount; x++) {
|
|
|
- for (NSUInteger y = 0; y < searchStringCount; y++) {
|
|
|
- nameRange = [stringsToSearch[y] rangeOfString:substrings[x] options:NSCaseInsensitiveSearch];
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- break;
|
|
|
- }
|
|
|
- if (nameRange.location != NSNotFound)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return nameRange;
|
|
|
-}
|
|
|
-
|
|
|
#pragma mark - handoff
|
|
|
|
|
|
- (void)restoreUserActivityState:(NSUserActivity *)activity
|