mirror of https://github.com/LIJI32/SameBoy.git
Syncing with the App Store branch (iCloud support)
This commit is contained in:
parent
8cb94e7a8b
commit
1931c2830f
|
@ -231,6 +231,7 @@
|
|||
self.navigationController.toolbar.disableCompactLayout = true;
|
||||
}
|
||||
|
||||
|
||||
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url
|
||||
{
|
||||
[url startAccessingSecurityScopedResource];
|
||||
|
|
|
@ -218,7 +218,6 @@
|
|||
if ([GBROMManager.sharedManager romFileForROM:_game.title]) {
|
||||
[GBROMManager sharedManager].currentROM = _game.title;
|
||||
[self.navigationController dismissViewControllerAnimated:true completion:nil];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBROMChanged" object:nil];
|
||||
}
|
||||
else {
|
||||
UIActivityIndicatorViewStyle style = UIActivityIndicatorViewStyleWhite;
|
||||
|
@ -237,9 +236,9 @@
|
|||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Could not download ROM"
|
||||
message:@"Could not download this ROM from Homebrew Hub. Please try again later."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[self presentViewController:alert animated:true completion:nil];
|
||||
self.navigationItem.rightBarButtonItem.customView = nil;
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface GBLibraryViewController : UITabBarController
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#import "GBLibraryViewController.h"
|
||||
#import "GBLoadROMTableViewController.h"
|
||||
#import "GBROMViewController.h"
|
||||
#import "GBHubViewController.h"
|
||||
#import "GBViewController.h"
|
||||
#import "GBROMManager.h"
|
||||
|
||||
|
||||
@implementation GBLibraryViewController
|
||||
|
||||
|
@ -19,8 +21,9 @@
|
|||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
self.viewControllers = @[
|
||||
[self.class wrapViewController:[[GBLoadROMTableViewController alloc] init]],
|
||||
[self.class wrapViewController:[[GBROMViewController alloc] init]],
|
||||
[self.class wrapViewController:[[GBHubViewController alloc] init]],
|
||||
];
|
||||
if (@available(iOS 13.0, *)) {
|
||||
|
@ -42,7 +45,7 @@
|
|||
}
|
||||
}
|
||||
self.viewControllers[0].tabBarItem.image = [UIImage systemImageNamed:symbol] ?: [UIImage systemImageNamed:@"folder.fill"];
|
||||
self.viewControllers[1].tabBarItem.image = [UIImage systemImageNamed:@"globe"];
|
||||
self.viewControllers.lastObject.tabBarItem.image = [UIImage systemImageNamed:@"globe"];
|
||||
}
|
||||
else {
|
||||
self.viewControllers[0].tabBarItem.image = [UIImage imageNamed:@"FolderTemplate"];
|
||||
|
@ -50,4 +53,5 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface GBLoadROMTableViewController : UITableViewController
|
||||
|
||||
@end
|
|
@ -10,6 +10,8 @@
|
|||
@property (readonly) NSString *batterySaveFile;
|
||||
@property (readonly) NSString *autosaveStateFile;
|
||||
@property (readonly) NSString *cheatsFile;
|
||||
|
||||
@property (readonly) NSString *localRoot;
|
||||
- (NSString *)stateFile:(unsigned)index;
|
||||
|
||||
- (NSString *)romFileForROM:(NSString *)rom;
|
||||
|
@ -21,4 +23,5 @@
|
|||
- (NSString *)renameROM:(NSString *)rom toName:(NSString *)newName;
|
||||
- (NSString *)duplicateROM:(NSString *)rom;
|
||||
- (void)deleteROM:(NSString *)rom;
|
||||
|
||||
@end
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
@implementation GBROMManager
|
||||
{
|
||||
NSString *_romFile;
|
||||
NSMutableDictionary<NSString *,NSString *> *_cloudNameToFile;
|
||||
bool _doneInitializing;
|
||||
}
|
||||
|
||||
+ (instancetype)sharedManager
|
||||
|
@ -21,6 +23,7 @@
|
|||
self = [super init];
|
||||
if (!self) return nil;
|
||||
self.currentROM = [[NSUserDefaults standardUserDefaults] stringForKey:@"GBLastROM"];
|
||||
_doneInitializing = true;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -28,11 +31,16 @@
|
|||
{
|
||||
_romFile = nil;
|
||||
_currentROM = currentROM;
|
||||
if (currentROM && !self.romFile) {
|
||||
bool foundROM = self.romFile;
|
||||
|
||||
if (currentROM && !foundROM) {
|
||||
_currentROM = nil;
|
||||
}
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:_currentROM forKey:@"GBLastROM"];
|
||||
if (_doneInitializing) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBROMChanged" object:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)romFileForDirectory:(NSString *)romDirectory
|
||||
|
@ -47,13 +55,17 @@
|
|||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)romDirectoryForROM:(NSString *)romFile
|
||||
{
|
||||
|
||||
return [self.localRoot stringByAppendingPathComponent:romFile];
|
||||
}
|
||||
|
||||
- (NSString *)romFile
|
||||
{
|
||||
if (_romFile) return _romFile;
|
||||
if (!_currentROM) return nil;
|
||||
NSString *root = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).firstObject;
|
||||
NSString *romDirectory = [root stringByAppendingPathComponent:_currentROM];
|
||||
return _romFile = [self romFileForDirectory:romDirectory];
|
||||
return _romFile = [self romFileForDirectory:[self romDirectoryForROM:_currentROM]];
|
||||
}
|
||||
|
||||
- (NSString *)romFileForROM:(NSString *)rom
|
||||
|
@ -63,9 +75,9 @@
|
|||
if (rom == _currentROM) {
|
||||
return self.romFile;
|
||||
}
|
||||
NSString *root = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).firstObject;
|
||||
NSString *romDirectory = [root stringByAppendingPathComponent:rom];
|
||||
return [self romFileForDirectory:romDirectory];
|
||||
|
||||
|
||||
return [self romFileForDirectory:[self romDirectoryForROM:rom]];
|
||||
}
|
||||
|
||||
- (NSString *)auxilaryFileForROM:(NSString *)rom withExtension:(NSString *)extension
|
||||
|
@ -117,7 +129,7 @@
|
|||
- (NSArray<NSString *> *)allROMs
|
||||
{
|
||||
NSMutableArray<NSString *> *ret = [NSMutableArray array];
|
||||
NSString *root = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).firstObject;
|
||||
NSString *root = self.localRoot;
|
||||
for (NSString *romDirectory in [NSFileManager.defaultManager contentsOfDirectoryAtPath:root
|
||||
error:nil]) {
|
||||
if ([romDirectory hasPrefix:@"."] || [romDirectory isEqualToString:@"Inbox"]) continue;
|
||||
|
@ -130,7 +142,7 @@
|
|||
|
||||
- (NSString *)makeNameUnique:(NSString *)name
|
||||
{
|
||||
NSString *root = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).firstObject;
|
||||
NSString *root = self.localRoot;
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:[root stringByAppendingPathComponent:name]]) return name;
|
||||
|
||||
unsigned i = 2;
|
||||
|
@ -150,27 +162,14 @@
|
|||
NSString *friendlyName = [[romFile lastPathComponent] stringByDeletingPathExtension];
|
||||
friendlyName = [regex stringByReplacingMatchesInString:friendlyName options:0 range:NSMakeRange(0, [friendlyName length]) withTemplate:@""];
|
||||
friendlyName = [friendlyName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||||
|
||||
NSString *root = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).firstObject;
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:[root stringByAppendingPathComponent:friendlyName]]) {
|
||||
unsigned i = 2;
|
||||
while (true) {
|
||||
NSString *attempt = [friendlyName stringByAppendingFormat:@" %u", i];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:[root stringByAppendingPathComponent:attempt]]) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
friendlyName = attempt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
friendlyName = [self makeNameUnique:friendlyName];
|
||||
|
||||
return [self importROM:romFile withName:friendlyName keepOriginal:keep];
|
||||
}
|
||||
|
||||
- (NSString *)importROM:(NSString *)romFile withName:(NSString *)friendlyName keepOriginal:(bool)keep
|
||||
{
|
||||
NSString *root = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).firstObject;
|
||||
NSString *root = self.localRoot;
|
||||
NSString *romFolder = [root stringByAppendingPathComponent:friendlyName];
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:romFolder
|
||||
withIntermediateDirectories:false
|
||||
|
@ -205,9 +204,9 @@
|
|||
{
|
||||
newName = [self makeNameUnique:newName];
|
||||
if ([rom isEqualToString:_currentROM]) {
|
||||
_currentROM = newName;
|
||||
self.currentROM = newName;
|
||||
}
|
||||
NSString *root = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).firstObject;
|
||||
NSString *root = self.localRoot;
|
||||
|
||||
[[NSFileManager defaultManager] moveItemAtPath:[root stringByAppendingPathComponent:rom]
|
||||
toPath:[root stringByAppendingPathComponent:newName] error:nil];
|
||||
|
@ -224,9 +223,14 @@
|
|||
|
||||
- (void)deleteROM:(NSString *)rom
|
||||
{
|
||||
NSString *root = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).firstObject;
|
||||
NSString *root = self.localRoot;
|
||||
NSString *romDirectory = [root stringByAppendingPathComponent:rom];
|
||||
[[NSFileManager defaultManager] removeItemAtPath:romDirectory error:nil];
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)localRoot
|
||||
{
|
||||
return NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).firstObject;
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface GBROMViewController : UITableViewController<UIDocumentPickerDelegate>
|
||||
|
||||
/* For inheritance */
|
||||
- (void)romSelectedAtIndex:(unsigned)index;
|
||||
- (void)deleteROMAtIndex:(unsigned)index;
|
||||
- (void)renameROM:(NSString *)oldName toName:(NSString *)newName;
|
||||
- (void)duplicateROMAtIndex:(unsigned)index;
|
||||
- (NSString *)rootPath;
|
||||
|
||||
/* To be used by subclasses */
|
||||
- (UITableViewCell *)cellForROM:(NSString *)rom;
|
||||
@end
|
|
@ -1,13 +1,11 @@
|
|||
#import "GBLoadROMTableViewController.h"
|
||||
#import "GBROMViewController.h"
|
||||
#import "GBROMManager.h"
|
||||
#import "GBViewController.h"
|
||||
#import "GBLibraryViewController.h"
|
||||
#import <CoreServices/CoreServices.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@interface GBLoadROMTableViewController() <UIDocumentPickerDelegate>
|
||||
@end
|
||||
|
||||
@implementation GBLoadROMTableViewController
|
||||
@implementation GBROMViewController
|
||||
{
|
||||
NSIndexPath *_renamingPath;
|
||||
}
|
||||
|
@ -36,19 +34,10 @@
|
|||
return [GBROMManager sharedManager].allROMs.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
- (UITableViewCell *)cellForROM:(NSString *)rom
|
||||
{
|
||||
if (indexPath.section == 1) {
|
||||
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
|
||||
switch (indexPath.item) {
|
||||
case 0: cell.textLabel.text = @"Import ROM files"; break;
|
||||
case 1: cell.textLabel.text = @"Show Library in Files"; break;
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
|
||||
NSString *rom = [GBROMManager sharedManager].allROMs[[indexPath indexAtPosition:1]];
|
||||
cell.textLabel.text = rom;
|
||||
cell.textLabel.text = rom.lastPathComponent;
|
||||
cell.accessoryType = [rom isEqualToString:[GBROMManager sharedManager].currentROM]? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
|
||||
|
||||
NSString *pngPath = [[[GBROMManager sharedManager] autosaveStateFileForROM:rom] stringByAppendingPathExtension:@"png"];
|
||||
|
@ -68,6 +57,20 @@
|
|||
UIGraphicsEndImageContext();
|
||||
|
||||
return cell;
|
||||
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (indexPath.section == 1) {
|
||||
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
|
||||
switch (indexPath.item) {
|
||||
case 0: cell.textLabel.text = @"Import ROM files"; break;
|
||||
case 1: cell.textLabel.text = @"Show Library in Files"; break;
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
return [self cellForROM:[GBROMManager sharedManager].allROMs[[indexPath indexAtPosition:1]]];
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
|
@ -89,6 +92,12 @@
|
|||
return @"You can also import ROM files by opening them in SameBoy using the Files app or a web browser, or by sending them over with AirDrop.";
|
||||
}
|
||||
|
||||
- (void)romSelectedAtIndex:(unsigned)index
|
||||
{
|
||||
[GBROMManager sharedManager].currentROM = [GBROMManager sharedManager].allROMs[index];
|
||||
[self.presentingViewController dismissViewControllerAnimated:true completion:nil];
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (indexPath.section == 1) {
|
||||
|
@ -110,9 +119,9 @@
|
|||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"File Association Conflict"
|
||||
message:@"Due to a limitation in iOS, the file picker will allow you to select files not supported by SameBoy. SameBoy will only import GB, GBC and ISX files.\n\nIf you have a multi-system emulator installed, updating it could fix this problem."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *action) {
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *action) {
|
||||
[[NSUserDefaults standardUserDefaults] setBool:true forKey:@"GBShownUTIWarning"];
|
||||
[self tableView:tableView didSelectRowAtIndexPath:indexPath];
|
||||
}]];
|
||||
|
@ -141,22 +150,22 @@
|
|||
return;
|
||||
}
|
||||
case 1: {
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"shareddocuments://%@", NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).firstObject]]
|
||||
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"shareddocuments://%@",
|
||||
[self.rootPath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]]]];
|
||||
[[UIApplication sharedApplication] openURL:url
|
||||
options:nil
|
||||
completionHandler:nil];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
[GBROMManager sharedManager].currentROM = [GBROMManager sharedManager].allROMs[[indexPath indexAtPosition:1]];
|
||||
[self.presentingViewController dismissViewControllerAnimated:true completion:^{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBROMChanged" object:nil];
|
||||
}];
|
||||
[self romSelectedAtIndex:indexPath.row];
|
||||
}
|
||||
|
||||
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray <NSURL *>*)urls
|
||||
{
|
||||
[(GBViewController *)[UIApplication sharedApplication] handleOpenURLs:urls openInPlace:false];
|
||||
[(GBViewController *)[UIApplication sharedApplication].delegate handleOpenURLs:urls
|
||||
openInPlace:false];
|
||||
}
|
||||
|
||||
- (UIModalPresentationStyle)modalPresentationStyle
|
||||
|
@ -164,28 +173,34 @@
|
|||
return UIModalPresentationOverFullScreen;
|
||||
}
|
||||
|
||||
- (void)deleteROMAtIndex:(unsigned)index
|
||||
{
|
||||
NSString *rom = [GBROMManager sharedManager].allROMs[index];
|
||||
|
||||
[[GBROMManager sharedManager] deleteROM:rom];
|
||||
[self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
if ([[GBROMManager sharedManager].currentROM isEqualToString:rom]) {
|
||||
[GBROMManager sharedManager].currentROM = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (indexPath.section == 1) return;
|
||||
|
||||
if (editingStyle != UITableViewCellEditingStyleDelete) return;
|
||||
NSString *rom = [GBROMManager sharedManager].allROMs[[indexPath indexAtPosition:1]];
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Delete ROM “%@”?", rom]
|
||||
NSString *rom = [self.tableView cellForRowAtIndexPath:indexPath].textLabel.text;
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Delete “%@”?", rom]
|
||||
message: @"Save data for this ROM will also be deleted."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Delete"
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction *action) {
|
||||
[[GBROMManager sharedManager] deleteROM:rom];
|
||||
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
if ([[GBROMManager sharedManager].currentROM isEqualToString:rom]) {
|
||||
[GBROMManager sharedManager].currentROM = nil;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBROMChanged" object:nil];
|
||||
}
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Delete"
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction *action) {
|
||||
[self deleteROMAtIndex:indexPath.row];
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[self presentViewController:alert animated:true completion:nil];
|
||||
}
|
||||
|
||||
|
@ -197,7 +212,7 @@
|
|||
UITextField *field = [[UITextField alloc] initWithFrame:cell.textLabel.frame];
|
||||
field.font = cell.textLabel.font;
|
||||
field.text = cell.textLabel.text;
|
||||
cell.textLabel.text = @"";
|
||||
cell.textLabel.textColor = [UIColor clearColor];
|
||||
[[cell.textLabel superview] addSubview:field];
|
||||
[field becomeFirstResponder];
|
||||
[field selectAll:nil];
|
||||
|
@ -205,29 +220,36 @@
|
|||
[field addTarget:self action:@selector(doneRename:) forControlEvents:UIControlEventEditingDidEnd | UIControlEventEditingDidEndOnExit];
|
||||
}
|
||||
|
||||
- (void)renameROM:(NSString *)oldName toName:(NSString *)newName
|
||||
{
|
||||
[[GBROMManager sharedManager] renameROM:oldName toName:newName];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)doneRename:(UITextField *)sender
|
||||
{
|
||||
if (!_renamingPath) return;
|
||||
NSString *newName = sender.text;
|
||||
NSString *oldName = [GBROMManager sharedManager].allROMs[[_renamingPath indexAtPosition:1]];
|
||||
NSString *oldName = [self.tableView cellForRowAtIndexPath:_renamingPath].textLabel.text;
|
||||
|
||||
_renamingPath = nil;
|
||||
if ([newName isEqualToString:oldName]) {
|
||||
[self.tableView reloadData];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([newName containsString:@"/"]) {
|
||||
[self.tableView reloadData];
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"You can't use a name that contains “/”. Please choose another name."
|
||||
message:nil
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"OK"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"OK"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[self presentViewController:alert animated:true completion:nil];
|
||||
return;
|
||||
}
|
||||
[[GBROMManager sharedManager] renameROM:oldName toName:newName];
|
||||
[self.tableView reloadData];
|
||||
[self renameROM:oldName toName:newName];
|
||||
_renamingPath = nil;
|
||||
}
|
||||
|
||||
|
@ -236,6 +258,13 @@
|
|||
return indexPath.section == 0;
|
||||
}
|
||||
|
||||
- (void)duplicateROMAtIndex:(unsigned)index
|
||||
{
|
||||
[[GBROMManager sharedManager] duplicateROM:[GBROMManager sharedManager].allROMs[index]];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
|
||||
// Leave these ROM management to iOS 13.0 and up for now
|
||||
- (UIContextMenuConfiguration *)tableView:(UITableView *)tableView
|
||||
contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
|
@ -266,8 +295,7 @@ contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
|
|||
image:[UIImage systemImageNamed:@"plus.square.on.square"]
|
||||
identifier:nil
|
||||
handler:^(__kindof UIAction *action) {
|
||||
[[GBROMManager sharedManager] duplicateROM:[GBROMManager sharedManager].allROMs[[indexPath indexAtPosition:1]]];
|
||||
[self.tableView reloadData];
|
||||
[self duplicateROMAtIndex:indexPath.row];
|
||||
}],
|
||||
deleteAction,
|
||||
]];
|
||||
|
@ -286,4 +314,9 @@ contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
|
|||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (NSString *)rootPath
|
||||
{
|
||||
return [GBROMManager sharedManager].localRoot;
|
||||
}
|
||||
|
||||
@end
|
|
@ -696,9 +696,9 @@ static NSString *LocalizedNameForElement(GCControllerElement *element, GBControl
|
|||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"No Controllers Connected"
|
||||
message:@"There are no connected game controllers to configure"
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[self presentViewController:alert animated:true completion:nil];
|
||||
return false;
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
|
|
@ -57,16 +57,16 @@
|
|||
// No supporter-only themes outside the App Store release
|
||||
}
|
||||
else {
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Apply Theme"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Apply Theme"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:_verticalLayout.theme.name forKey:@"GBInterfaceTheme"];
|
||||
[[self presentingViewController] dismissViewControllerAnimated:true completion:nil];
|
||||
}]];
|
||||
}
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Exit Preview"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Exit Preview"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
[[self presentingViewController] dismissViewControllerAnimated:true completion:nil];
|
||||
}]];
|
||||
[self presentViewController:alert animated:true completion:^{
|
||||
|
|
|
@ -27,7 +27,8 @@ typedef enum {
|
|||
- (void)emptyPrinterFeed;
|
||||
- (void)saveStateToFile:(NSString *)file;
|
||||
- (bool)loadStateFromFile:(NSString *)file;
|
||||
- (bool)handleOpenURLs:(NSArray <NSURL *> *)urls openInPlace:(bool)inPlace;
|
||||
- (bool)handleOpenURLs:(NSArray <NSURL *> *)urls
|
||||
openInPlace:(bool)inPlace;
|
||||
- (void)dismissViewController;
|
||||
@property (nonatomic) GBRunMode runMode;
|
||||
@end
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
bool _rewindOver;
|
||||
bool _romLoaded;
|
||||
bool _swappingROM;
|
||||
bool _loadingState;
|
||||
|
||||
UIInterfaceOrientation _orientation;
|
||||
GBHorizontalLayout *_horizontalLayout;
|
||||
|
@ -265,12 +266,12 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
|
|||
|
||||
_audioLock = [[NSCondition alloc] init];
|
||||
|
||||
[self loadROM];
|
||||
[[NSNotificationCenter defaultCenter] addObserverForName:@"GBROMChanged"
|
||||
object:nil
|
||||
queue:nil
|
||||
usingBlock:^(NSNotification *note) {
|
||||
[self loadROM];
|
||||
_swappingROM = true;
|
||||
[self stop];
|
||||
[self start];
|
||||
}];
|
||||
|
||||
|
@ -628,9 +629,9 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
|
|||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"SameBoy is not properly signed and might not be able to open ROMs"
|
||||
message:[NSString stringWithFormat:@"The bundle identifier in the Info.plist file (“%@”) does not match the one in the entitlements (“%@”)", plistIdentifier, entIdentifier]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[self presentViewController:alert animated:true completion:nil];
|
||||
}
|
||||
}
|
||||
|
@ -648,7 +649,7 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
|
|||
|
||||
- (bool)loadStateFromFile:(NSString *)file
|
||||
{
|
||||
[self stop];
|
||||
_loadingState = true;
|
||||
GB_model_t model;
|
||||
if (!GB_get_state_model(file.fileSystemRepresentation, &model)) {
|
||||
if (GB_get_model(&_gb) != model) {
|
||||
|
@ -656,53 +657,56 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
|
|||
}
|
||||
return GB_load_state(&_gb, file.fileSystemRepresentation) == 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
- (void)loadROM
|
||||
{
|
||||
_swappingROM = true;
|
||||
[self stop];
|
||||
GBROMManager *romManager = [GBROMManager sharedManager];
|
||||
if (romManager.romFile) {
|
||||
// Todo: display errors and warnings
|
||||
if ([romManager.romFile.pathExtension.lowercaseString isEqualToString:@"isx"]) {
|
||||
_romLoaded = GB_load_isx(&_gb, romManager.romFile.fileSystemRepresentation) == 0;
|
||||
}
|
||||
else {
|
||||
_romLoaded = GB_load_rom(&_gb, romManager.romFile.fileSystemRepresentation) == 0;
|
||||
}
|
||||
if (_romLoaded) {
|
||||
GB_reset(&_gb);
|
||||
GB_load_battery(&_gb, [GBROMManager sharedManager].batterySaveFile.fileSystemRepresentation);
|
||||
GB_remove_all_cheats(&_gb);
|
||||
GB_load_cheats(&_gb, [GBROMManager sharedManager].cheatsFile.UTF8String, false);
|
||||
if (![self loadStateFromFile:[GBROMManager sharedManager].autosaveStateFile]) {
|
||||
// Newly played ROM, pick the best model
|
||||
uint8_t *rom = GB_get_direct_access(&_gb, GB_DIRECT_ACCESS_ROM, NULL, NULL);
|
||||
|
||||
if ((rom[0x143] & 0x80)) {
|
||||
if (!GB_is_cgb(&_gb)) {
|
||||
GB_switch_model_and_reset(&_gb, [[NSUserDefaults standardUserDefaults] integerForKey:@"GBCGBModel"]);
|
||||
if (!_loadingState) {
|
||||
// Todo: display errors and warnings
|
||||
if ([romManager.romFile.pathExtension.lowercaseString isEqualToString:@"isx"]) {
|
||||
_romLoaded = GB_load_isx(&_gb, romManager.romFile.fileSystemRepresentation) == 0;
|
||||
}
|
||||
else {
|
||||
_romLoaded = GB_load_rom(&_gb, romManager.romFile.fileSystemRepresentation) == 0;
|
||||
}
|
||||
if (_romLoaded) {
|
||||
GB_reset(&_gb);
|
||||
GB_load_battery(&_gb, [GBROMManager sharedManager].batterySaveFile.fileSystemRepresentation);
|
||||
GB_remove_all_cheats(&_gb);
|
||||
GB_load_cheats(&_gb, [GBROMManager sharedManager].cheatsFile.UTF8String, false);
|
||||
if (![self loadStateFromFile:[GBROMManager sharedManager].autosaveStateFile]) {
|
||||
// Newly played ROM, pick the best model
|
||||
uint8_t *rom = GB_get_direct_access(&_gb, GB_DIRECT_ACCESS_ROM, NULL, NULL);
|
||||
|
||||
if ((rom[0x143] & 0x80)) {
|
||||
if (!GB_is_cgb(&_gb)) {
|
||||
GB_switch_model_and_reset(&_gb, [[NSUserDefaults standardUserDefaults] integerForKey:@"GBCGBModel"]);
|
||||
}
|
||||
}
|
||||
else if ((rom[0x146] == 3) && !GB_is_sgb(&_gb)) {
|
||||
GB_switch_model_and_reset(&_gb, [[NSUserDefaults standardUserDefaults] integerForKey:@"GBSGBModel"]);
|
||||
}
|
||||
}
|
||||
else if ((rom[0x146] == 3) && !GB_is_sgb(&_gb)) {
|
||||
GB_switch_model_and_reset(&_gb, [[NSUserDefaults standardUserDefaults] integerForKey:@"GBSGBModel"]);
|
||||
}
|
||||
}
|
||||
GB_rewind_reset(&_gb);
|
||||
}
|
||||
GB_rewind_reset(&_gb);
|
||||
}
|
||||
else {
|
||||
_romLoaded = false;
|
||||
}
|
||||
_gbView.hidden = !_romLoaded;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
_gbView.hidden = !_romLoaded;
|
||||
});
|
||||
_swappingROM = false;
|
||||
_loadingState = false;
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application
|
||||
{
|
||||
if (self.presentedViewController) return;
|
||||
[self start];
|
||||
}
|
||||
|
||||
|
@ -758,9 +762,9 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
|
|||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"SameBoy is not a Game Boy Advance Emulator"
|
||||
message:@"SameBoy cannot play GBA games. Changing the model to Game Boy Advance lets you play Game Boy games as if on a Game Boy Advance in Game Boy Color mode."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *action) {
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *action) {
|
||||
[self start];
|
||||
[[NSUserDefaults standardUserDefaults] setBool:true forKey:@"GBShownGBAWarning"];
|
||||
}]];
|
||||
|
@ -836,9 +840,9 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
|
|||
if (completion) {
|
||||
completion();
|
||||
}
|
||||
if (!self.presentedViewController) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self start];
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
|
@ -846,9 +850,9 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
|
|||
{
|
||||
/* Hack. Some view controllers dismiss without calling the method above. */
|
||||
[super setNeedsUpdateOfSupportedInterfaceOrientations];
|
||||
if (!self.presentedViewController) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self start];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)dismissViewController
|
||||
|
@ -1047,6 +1051,12 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
|
|||
|
||||
- (void)run
|
||||
{
|
||||
[self loadROM];
|
||||
if (!_romLoaded) {
|
||||
_running = false;
|
||||
_stopping = false;
|
||||
return;
|
||||
}
|
||||
[self preRun];
|
||||
while (_running) {
|
||||
if (_rewind) {
|
||||
|
@ -1168,8 +1178,8 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
|
|||
|
||||
- (void)start
|
||||
{
|
||||
if (!_romLoaded) return;
|
||||
if (_running) return;
|
||||
if (self.presentedViewController) return;
|
||||
_running = true;
|
||||
[[[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil] start];
|
||||
}
|
||||
|
@ -1289,7 +1299,8 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
|
|||
GB_set_palette(&_gb, &_palette);
|
||||
}
|
||||
|
||||
- (bool)handleOpenURLs:(NSArray <NSURL *> *)urls openInPlace:(bool)inPlace
|
||||
- (bool)handleOpenURLs:(NSArray <NSURL *> *)urls
|
||||
openInPlace:(bool)inPlace
|
||||
{
|
||||
NSMutableArray<NSURL *> *validURLs = [NSMutableArray array];
|
||||
NSMutableArray<NSString *> *skippedBasenames = [NSMutableArray array];
|
||||
|
@ -1335,10 +1346,9 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
|
|||
message:[NSString stringWithFormat:@"Could not find any Game Boy ROM files in the following archives:\n%@",
|
||||
[unusedZips componentsJoinedByString:@"\n"]]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[self stop];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[self presentViewController:alert animated:true completion:nil];
|
||||
}
|
||||
|
||||
|
@ -1347,15 +1357,15 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
|
|||
message:[NSString stringWithFormat:@"Could not import the following files because they're not supported:\n%@",
|
||||
[skippedBasenames componentsJoinedByString:@"\n"]]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *action) {
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Close"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *action) {
|
||||
[[NSUserDefaults standardUserDefaults] setBool:false forKey:@"GBShownUTIWarning"]; // Somebody might need a reminder
|
||||
}]];
|
||||
[self stop];
|
||||
[self presentViewController:alert animated:true completion:nil];
|
||||
}
|
||||
|
||||
|
||||
if (validURLs.count == 1 && urls.count == 1) {
|
||||
NSURL *url = validURLs.firstObject;
|
||||
NSString *potentialROM = [[url.path stringByDeletingLastPathComponent] lastPathComponent];
|
||||
|
@ -1369,7 +1379,6 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
|
|||
keepOriginal:![url.path hasPrefix:tempDir] && !inPlace];
|
||||
[url stopAccessingSecurityScopedResource];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"GBROMChanged" object:nil];
|
||||
return true;
|
||||
}
|
||||
for (NSURL *url in validURLs) {
|
||||
|
@ -1383,7 +1392,6 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
|
|||
keepOriginal:![url.path hasPrefix:tempDir] && !inPlace];
|
||||
[url stopAccessingSecurityScopedResource];
|
||||
}
|
||||
[self stop];
|
||||
[self openLibrary];
|
||||
|
||||
return validURLs.count;
|
||||
|
@ -1391,15 +1399,18 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
|
|||
|
||||
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
|
||||
{
|
||||
if (self.presentedViewController && ![self.presentedViewController isKindOfClass:[UIAlertController class]]) {
|
||||
[self dismissViewController];
|
||||
}
|
||||
NSString *potentialROM = [[url.path stringByDeletingLastPathComponent] lastPathComponent];
|
||||
if ([[[GBROMManager sharedManager] romFileForROM:potentialROM].stringByStandardizingPath isEqualToString:url.path.stringByStandardizingPath]) {
|
||||
[self stop];
|
||||
[GBROMManager sharedManager].currentROM = potentialROM;
|
||||
[self loadROM];
|
||||
[self start];
|
||||
return [GBROMManager sharedManager].currentROM != nil;
|
||||
}
|
||||
return [self handleOpenURLs:@[url] openInPlace:[options[UIApplicationOpenURLOptionsOpenInPlaceKey] boolValue]];
|
||||
return [self handleOpenURLs:@[url]
|
||||
openInPlace:[options[UIApplicationOpenURLOptionsOpenInPlaceKey] boolValue]];
|
||||
}
|
||||
|
||||
- (void)setRunMode:(GBRunMode)runMode ignoreDynamicSpeed:(bool)ignoreDynamicSpeed
|
||||
|
|
Loading…
Reference in New Issue