From b8f0c35833f98a25e3d31747b56d72d71e9b0fee Mon Sep 17 00:00:00 2001 From: meancoot Date: Tue, 19 Feb 2013 20:14:25 -0500 Subject: [PATCH] ios: Add coverart support (iOS 6+ only). --- ios/RetroArch.xcodeproj/project.pbxproj | 22 ++++- ios/RetroArch/RADirectoryFilterList.m | 4 +- ios/RetroArch/RADirectoryGrid.m | 120 ++++++++++++++++++++++++ ios/RetroArch/RADirectoryList.m | 59 +++++++----- ios/RetroArch/browser.h | 10 ++ ios/RetroArch/views.h | 5 +- 6 files changed, 191 insertions(+), 29 deletions(-) create mode 100644 ios/RetroArch/RADirectoryGrid.m create mode 100644 ios/RetroArch/browser.h diff --git a/ios/RetroArch.xcodeproj/project.pbxproj b/ios/RetroArch.xcodeproj/project.pbxproj index 3ae59b4e56..e7e64056fa 100644 --- a/ios/RetroArch.xcodeproj/project.pbxproj +++ b/ios/RetroArch.xcodeproj/project.pbxproj @@ -81,6 +81,7 @@ 96AFAFAD16C1EEE9009DE44C /* sinc.c in Sources */ = {isa = PBXBuildFile; fileRef = 96AFAEF716C1DC73009DE44C /* sinc.c */; }; 96AFAFD416C1FBC0009DE44C /* input_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 96AFAFC916C1FBC0009DE44C /* input_common.c */; }; 96C19C2216D2F3BA00FE8D5A /* RADirectoryFilterList.m in Sources */ = {isa = PBXBuildFile; fileRef = 96C19C2116D2F3BA00FE8D5A /* RADirectoryFilterList.m */; }; + 96C19C2416D453BA00FE8D5A /* RADirectoryGrid.m in Sources */ = {isa = PBXBuildFile; fileRef = 96C19C2316D453BA00FE8D5A /* RADirectoryGrid.m */; }; 96CF015016C2C0B700ABF9C9 /* overlay.c in Sources */ = {isa = PBXBuildFile; fileRef = 96AFAFCE16C1FBC0009DE44C /* overlay.c */; }; 96CF015C16C2F72900ABF9C9 /* ios_input.c in Sources */ = {isa = PBXBuildFile; fileRef = 96CF015B16C2F72900ABF9C9 /* ios_input.c */; }; /* End PBXBuildFile section */ @@ -225,6 +226,9 @@ 96AFAFCE16C1FBC0009DE44C /* overlay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = overlay.c; sourceTree = ""; }; 96AFAFCF16C1FBC0009DE44C /* overlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = overlay.h; sourceTree = ""; }; 96C19C2116D2F3BA00FE8D5A /* RADirectoryFilterList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RADirectoryFilterList.m; sourceTree = ""; }; + 96C19C2316D453BA00FE8D5A /* RADirectoryGrid.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RADirectoryGrid.m; sourceTree = ""; }; + 96C19C2516D455BE00FE8D5A /* browser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = browser.h; sourceTree = ""; }; + 96C19C2616D455BE00FE8D5A /* rarch_wrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rarch_wrapper.h; sourceTree = ""; }; 96CF015B16C2F72900ABF9C9 /* ios_input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ios_input.c; sourceTree = ""; }; /* End PBXFileReference section */ @@ -300,14 +304,14 @@ 96AFAE3316C1D4EA009DE44C /* RetroArch */ = { isa = PBXGroup; children = ( + 96C19C2716D455C600FE8D5A /* Browser */, 96366C6F16CAF62200D64A22 /* settings */, 96AFAE3416C1D4EA009DE44C /* Supporting Files */, 96CF015B16C2F72900ABF9C9 /* ios_input.c */, - 96C19C2116D2F3BA00FE8D5A /* RADirectoryFilterList.m */, - 963F5AC416CC523B009BBD19 /* RADirectoryList.m */, 963F5AC516CC523B009BBD19 /* RAGameView.m */, 96096DD716D1ABAF00BF4499 /* RAModuleInfoList.m */, 963F5AC616CC523B009BBD19 /* RAModuleList.m */, + 96C19C2616D455BE00FE8D5A /* rarch_wrapper.h */, 96297A0A16C5AD8D00E6DCE0 /* RetroArch_iOS.h */, 96297A0B16C5AD8D00E6DCE0 /* RetroArch_iOS.m */, 96297A0D16C5ADDA00E6DCE0 /* views.h */, @@ -542,6 +546,17 @@ path = ../input; sourceTree = ""; }; + 96C19C2716D455C600FE8D5A /* Browser */ = { + isa = PBXGroup; + children = ( + 96C19C2516D455BE00FE8D5A /* browser.h */, + 96C19C2116D2F3BA00FE8D5A /* RADirectoryFilterList.m */, + 96C19C2316D453BA00FE8D5A /* RADirectoryGrid.m */, + 963F5AC416CC523B009BBD19 /* RADirectoryList.m */, + ); + name = Browser; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -671,6 +686,7 @@ 963F5AC916CC523B009BBD19 /* RAModuleList.m in Sources */, 96096DD816D1ABAF00BF4499 /* RAModuleInfoList.m in Sources */, 96C19C2216D2F3BA00FE8D5A /* RADirectoryFilterList.m in Sources */, + 96C19C2416D453BA00FE8D5A /* RADirectoryGrid.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -788,6 +804,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "RetroArch/RetroArch-Prefix.pch"; INFOPLIST_FILE = "RetroArch/RetroArch-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)\"", @@ -823,6 +840,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "RetroArch/RetroArch-Prefix.pch"; INFOPLIST_FILE = "RetroArch/RetroArch-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)\"", diff --git a/ios/RetroArch/RADirectoryFilterList.m b/ios/RetroArch/RADirectoryFilterList.m index 0e9bf15f27..13c133f6bb 100644 --- a/ios/RetroArch/RADirectoryFilterList.m +++ b/ios/RetroArch/RADirectoryFilterList.m @@ -6,6 +6,8 @@ // Copyright (c) 2013 RetroArch. All rights reserved. // +#import "browser.h" + @implementation RADirectoryFilterList { NSString* _path; @@ -49,7 +51,7 @@ NSRegularExpression* expr = [NSRegularExpression regularExpressionWithPattern:[NSString stringWithUTF8String:regex] options:0 error:nil]; free(regex); - [[RetroArch_iOS get] pushViewController:[[RADirectoryList alloc] initWithPath:_path filter:expr]]; + [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListWithPath:_path filter:expr]]; } } } diff --git a/ios/RetroArch/RADirectoryGrid.m b/ios/RetroArch/RADirectoryGrid.m new file mode 100644 index 0000000000..63fff44843 --- /dev/null +++ b/ios/RetroArch/RADirectoryGrid.m @@ -0,0 +1,120 @@ +// +// dirlist.m +// RetroArch +// +// Created by Jason Fetters on 2/7/13. +// Copyright (c) 2013 RetroArch. All rights reserved. +// + +#import "browser.h" + +@implementation RADirectoryGrid +{ + NSString* _path; + NSArray* _list; + + UIImage* _templateImage; +} + +- (id)initWithPath:(NSString*)path filter:(NSRegularExpression*)regex +{ + UICollectionViewFlowLayout* layout = [UICollectionViewFlowLayout new]; + layout.itemSize = CGSizeMake(175, 248); + self = [super initWithCollectionViewLayout:layout]; + + if (path == nil) + { + if (ra_ios_is_directory(@"/var/mobile/RetroArchGames")) path = @"/var/mobile/RetroArchGames"; + else if (ra_ios_is_directory(@"/var/mobile")) path = @"/var/mobile"; + else path = @"/"; + } + + _path = path; + + NSString* templateName = [NSString stringWithFormat:@"%@/.coverart/template.png", _path]; + _templateImage = [UIImage imageWithContentsOfFile:templateName]; + + if (!_templateImage) + { + [RetroArch_iOS displayErrorMessage:@"Coverart template.png is missing."]; + _templateImage = [RetroArch_iOS get].file_icon; + } + + _list = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:_path error:nil]; + _list = [_path stringsByAppendingPaths:_list]; + + if (regex) + { + _list = [_list filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^(id object, NSDictionary* bindings) + { + if (ra_ios_is_directory(object)) + return YES; + + return (BOOL)([regex numberOfMatchesInString:[object lastPathComponent] options:0 range:NSMakeRange(0, [[object lastPathComponent] length])] != 0); + }]]; + } + + _list = [_list sortedArrayUsingComparator:^(id left, id right) + { + const BOOL left_is_dir = ra_ios_is_directory((NSString*)left); + const BOOL right_is_dir = ra_ios_is_directory((NSString*)right); + + return (left_is_dir != right_is_dir) ? + (left_is_dir ? -1 : 1) : + ([left caseInsensitiveCompare:right]); + }]; + + self.navigationItem.rightBarButtonItem = [RetroArch_iOS get].settings_button; + [self setTitle: [_path lastPathComponent]]; + + [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"filecell"]; + + return self; +} + +- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView +{ + return 1; +} + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +{ + return [_list count]; +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath +{ + NSString* path = [_list objectAtIndex: indexPath.row]; + + if(ra_ios_is_directory(path)) + { + [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListWithPath:path]]; + } + else + { + [[RetroArch_iOS get] runGame:path]; + } +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath +{ + NSString* path = [_list objectAtIndex: indexPath.row]; + BOOL isdir = ra_ios_is_directory(path); + + UICollectionViewCell* cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"filecell" forIndexPath:indexPath]; + if (isdir) + cell.backgroundView = [[UIImageView alloc] initWithImage:[RetroArch_iOS get].folder_icon]; + else + { + NSString* img = [NSString stringWithFormat:@"%@/.coverart/%@.png", _path, [[path lastPathComponent] stringByDeletingPathExtension]]; + if (ra_ios_is_file(img)) + cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:img]]; + else + cell.backgroundView = [[UIImageView alloc] initWithImage:_templateImage]; + } + + return cell; +} + +@end diff --git a/ios/RetroArch/RADirectoryList.m b/ios/RetroArch/RADirectoryList.m index dc4751d7fb..604d8cb817 100644 --- a/ios/RetroArch/RADirectoryList.m +++ b/ios/RetroArch/RADirectoryList.m @@ -6,18 +6,31 @@ // Copyright (c) 2013 RetroArch. All rights reserved. // -static BOOL is_file(NSString* path) +#import "browser.h" + +BOOL ra_ios_is_file(NSString* path) { return [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:nil]; } -static BOOL is_directory(NSString* path) +BOOL ra_ios_is_directory(NSString* path) { BOOL result = NO; [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&result]; return result; } +static NSString* check_path(NSString* path) +{ + if (path && !ra_ios_is_directory(path)) + { + [RetroArch_iOS displayErrorMessage:@"Browsed path is not a directory."]; + return nil; + } + else + return path; +} + @implementation RADirectoryList { NSString* _path; @@ -26,17 +39,23 @@ static BOOL is_directory(NSString* path) + (id)directoryListWithPath:(NSString*)path { - if (path && !is_directory(path)) - { - [RetroArch_iOS displayErrorMessage:@"Browsed path is not a directory."]; - path = nil; - } + path = check_path(path); - if (path && is_file([path stringByAppendingPathComponent:@".rafilter"])) + if (path && ra_ios_is_file([path stringByAppendingPathComponent:@".rafilter"])) return [[RADirectoryFilterList alloc] initWithPath:path]; else - return [[RADirectoryList alloc] initWithPath:path filter:nil]; - + return [RADirectoryList directoryListWithPath:path filter:nil]; +} + ++ (id)directoryListWithPath:(NSString*)path filter:(NSRegularExpression*)regex +{ + path = check_path(path); + + NSString* coverDir = path ? [path stringByAppendingPathComponent:@".coverart"] : nil; + if (coverDir && ra_ios_is_directory(coverDir) && ra_ios_is_file([coverDir stringByAppendingPathComponent:@"template.png"])) + return [[RADirectoryGrid alloc] initWithPath:path filter:regex]; + else + return [[RADirectoryList alloc] initWithPath:path filter:regex]; } - (id)initWithPath:(NSString*)path filter:(NSRegularExpression*)regex @@ -45,9 +64,9 @@ static BOOL is_directory(NSString* path) if (path == nil) { - if (is_directory(@"/var/mobile/RetroArchGames")) path = @"/var/mobile/RetroArchGames"; - else if (is_directory(@"/var/mobile")) path = @"/var/mobile"; - else path = @"/"; + if (ra_ios_is_directory(@"/var/mobile/RetroArchGames")) path = @"/var/mobile/RetroArchGames"; + else if (ra_ios_is_directory(@"/var/mobile")) path = @"/var/mobile"; + else path = @"/"; } _path = path; @@ -59,7 +78,7 @@ static BOOL is_directory(NSString* path) { _list = [_list filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^(id object, NSDictionary* bindings) { - if (is_directory(object)) + if (ra_ios_is_directory(object)) return YES; return (BOOL)([regex numberOfMatchesInString:[object lastPathComponent] options:0 range:NSMakeRange(0, [[object lastPathComponent] length])] != 0); @@ -68,8 +87,8 @@ static BOOL is_directory(NSString* path) _list = [_list sortedArrayUsingComparator:^(id left, id right) { - const BOOL left_is_dir = is_directory((NSString*)left); - const BOOL right_is_dir = is_directory((NSString*)right); + const BOOL left_is_dir = ra_ios_is_directory((NSString*)left); + const BOOL right_is_dir = ra_ios_is_directory((NSString*)right); return (left_is_dir != right_is_dir) ? (left_is_dir ? -1 : 1) : @@ -86,14 +105,10 @@ static BOOL is_directory(NSString* path) { NSString* path = [_list objectAtIndex: indexPath.row]; - if(is_directory(path)) - { + if(ra_ios_is_directory(path)) [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListWithPath:path]]; - } else - { [[RetroArch_iOS get] runGame:path]; - } } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section @@ -104,7 +119,7 @@ static BOOL is_directory(NSString* path) - (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString* path = [_list objectAtIndex: indexPath.row]; - BOOL isdir = is_directory(path); + BOOL isdir = ra_ios_is_directory(path); UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:@"path"]; cell = (cell != nil) ? cell : [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"path"]; diff --git a/ios/RetroArch/browser.h b/ios/RetroArch/browser.h new file mode 100644 index 0000000000..9f3697fbb8 --- /dev/null +++ b/ios/RetroArch/browser.h @@ -0,0 +1,10 @@ +extern BOOL ra_ios_is_directory(NSString* path); +extern BOOL ra_ios_is_file(NSString* path); + +@interface RADirectoryGrid : UICollectionViewController +- (id)initWithPath:(NSString*)path filter:(NSRegularExpression*)regex; +@end + +@interface RADirectoryFilterList : UITableViewController +- (id)initWithPath:(NSString*)path; +@end diff --git a/ios/RetroArch/views.h b/ios/RetroArch/views.h index 0469354ea9..897dc8d6fb 100644 --- a/ios/RetroArch/views.h +++ b/ios/RetroArch/views.h @@ -20,12 +20,9 @@ @interface RAModuleList : UITableViewController @end -@interface RADirectoryFilterList : UITableViewController -- (id)initWithPath:(NSString*)path; -@end - @interface RADirectoryList : UITableViewController + (id)directoryListWithPath:(NSString*)path; ++ (id)directoryListWithPath:(NSString*)path filter:(NSRegularExpression*)regex; - (id)initWithPath:(NSString*)path filter:(NSRegularExpression*)regex; @end