Path: blob/main/Natives/LauncherPrefGameDirViewController.m
589 views
#import "LauncherNavigationController.h"1#import "LauncherPreferences.h"2#import "LauncherPrefGameDirViewController.h"3#import "NSFileManager+NRFileManager.h"4#import "PLProfiles.h"5#import "ios_uikit_bridge.h"6#import "utils.h"78@interface LauncherPrefGameDirViewController ()<UITextFieldDelegate>9@property(nonatomic) NSMutableArray *array;10@end1112@implementation LauncherPrefGameDirViewController1314- (void)viewDidLoad15{16[super viewDidLoad];17[self setTitle:localize(@"preference.title.game_directory", nil)];1819self.array = [[NSMutableArray alloc] init];20[self.array addObject:@"default"];2122self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped];23self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;24self.tableView.sectionFooterHeight = 50;2526NSString *path = [NSString stringWithFormat:@"%s/instances", getenv("POJAV_HOME")];2728NSFileManager *fm = NSFileManager.defaultManager;29NSArray *files = [fm contentsOfDirectoryAtPath:path error:nil];30BOOL isDir;31for (NSString *file in files) {32[fm fileExistsAtPath:path isDirectory:(&isDir)];33if (isDir && ![file isEqualToString:@"default"]) {34[self.array addObject:file];35}36}37}3839- (void)changeSelectionTo:(NSString *)name {40if (getenv("DEMO_LOCK")) return;4142setPrefObject(@"general.game_directory", name);43NSString *multidirPath = [NSString stringWithFormat:@"%s/instances/%@", getenv("POJAV_HOME"), name];44NSString *lasmPath = @(getenv("POJAV_GAME_DIR"));45[NSFileManager.defaultManager removeItemAtPath:lasmPath error:nil];46[NSFileManager.defaultManager createSymbolicLinkAtPath:lasmPath withDestinationPath:multidirPath error:nil];47[NSFileManager.defaultManager changeCurrentDirectoryPath:lasmPath];48toggleIsolatedPref(NO);49[self.navigationController performSelector:@selector(reloadProfileList)];50}5152- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section53{54return self.array.count;55}5657- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath58{59UITextField *view;60UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];61if (cell == nil) {62cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];63view = [[UITextField alloc] initWithFrame:CGRectMake(20, 10, (cell.bounds.size.width-40)/2, cell.bounds.size.height-20)];64[view addTarget:view action:@selector(resignFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];65view.autocorrectionType = UITextAutocorrectionTypeNo;66view.autocapitalizationType = UITextAutocapitalizationTypeNone;67view.autoresizingMask = UIViewAutoresizingFlexibleWidth;68view.delegate = self;69view.returnKeyType = UIReturnKeyDone;70view.userInteractionEnabled = indexPath.row != 0;71[cell.contentView addSubview:view];72cell.detailTextLabel.text = @"...";73}74view = cell.contentView.subviews.firstObject;75view.placeholder = self.array[indexPath.row];76view.text = self.array[indexPath.row];77cell.textLabel.hidden = YES;78cell.textLabel.text = view.text;7980// Calculate the instance size81dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{82unsigned long long folderSize = 0;83NSString *directory = [NSString stringWithFormat:@"%s/instances/%@", getenv("POJAV_HOME"), self.array[indexPath.row]];84[NSFileManager.defaultManager nr_getAllocatedSize:&folderSize ofDirectoryAtURL:[NSURL fileURLWithPath:directory] error:nil];85dispatch_async(dispatch_get_main_queue(), ^{86cell.detailTextLabel.text = [NSByteCountFormatter stringFromByteCount:folderSize countStyle:NSByteCountFormatterCountStyleMemory];87});88});8990if ([getPrefObject(@"general.game_directory") isEqualToString:self.array[indexPath.row]]) {91cell.accessoryType = UITableViewCellAccessoryCheckmark;92} else {93cell.accessoryType = UITableViewCellAccessoryNone;94}9596return cell;97}9899- (UIView *)tableView:(UITableView *)tableView100viewForFooterInSection:(NSInteger)section101{102UITextField *view = [[UITextField alloc] init];103[view addTarget:view action:@selector(resignFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];104view.autocorrectionType = UITextAutocorrectionTypeNo;105view.autocapitalizationType = UITextAutocapitalizationTypeNone;106view.delegate = self;107view.placeholder = localize(@"preference.multidir.add_directory", nil);108view.returnKeyType = UIReturnKeyDone;109return view;110}111112- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {113[self changeSelectionTo:self.array[indexPath.row]];114[tableView deselectRowAtIndexPath:indexPath animated:NO];115for (int i = 0; i < self.array.count; i++) {116UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];117if (i == indexPath.row) {118cell.accessoryType = UITableViewCellAccessoryCheckmark;119} else {120cell.accessoryType = UITableViewCellAccessoryNone;121}122}123}124125- (id)createOpenScheme:(NSString *)scheme at:(NSString *)directory {126return ^(UIAction *action) {127[UIApplication.sharedApplication128openURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@://%@", scheme, directory]]129options:@{} completionHandler:nil];130};131}132133- (UIContextMenuConfiguration *)tableView:(UITableView *)tableView contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point134{135NSArray *menuItems;136NSMutableArray *openItems = [[NSMutableArray alloc] init];137138NSString *directory = [NSString stringWithFormat:@"%s/instances/%@", getenv("POJAV_HOME"), self.array[indexPath.row]];139NSDictionary *apps = @{140@"shareddocuments": @"Files",141@"filza": @"Filza",142@"santander": @"Santander",143};144for (NSString *key in apps.allKeys) {145NSString *url = [NSString stringWithFormat:@"%@://", key];146if ([UIApplication.sharedApplication canOpenURL:[NSURL URLWithString:url]]) {147[openItems addObject:[UIAction148actionWithTitle:apps[key]149image:nil150identifier:nil151handler:[self createOpenScheme:key at:directory]]];152}153}154UIMenu *open = [UIMenu155menuWithTitle:@""156image:nil157identifier:nil158options:UIMenuOptionsDisplayInline159children:openItems];160161if (indexPath.row == 0) {162// You can't delete or rename the default instance, though there will be a reset action (TODO)163menuItems = @[open];164} else {165UIAction *rename = [UIAction166actionWithTitle:localize(@"Rename", nil)167image:[UIImage systemImageNamed:@"pencil"]168identifier:nil169handler:^(UIAction *action) {170UITableViewCell *view = [self.tableView cellForRowAtIndexPath:indexPath];171[view.contentView.subviews.firstObject becomeFirstResponder];172}173];174175UIAction *delete = [UIAction176actionWithTitle:localize(@"Delete", nil)177image:[UIImage systemImageNamed:@"trash"]178identifier:nil179handler:^(UIAction *action) {180[self actionDeleteAtIndexPath:indexPath];181}182];183delete.attributes = UIMenuElementAttributesDestructive;184185menuItems = @[open, rename, delete];186}187188return [UIContextMenuConfiguration189configurationWithIdentifier:nil190previewProvider:nil191actionProvider:^UIMenu *(NSArray<UIMenuElement *> *suggestedActions) {192return [UIMenu menuWithTitle:self.array[indexPath.row] children:menuItems];193}194];195}196197- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath198{199if (editingStyle == UITableViewCellEditingStyleDelete) {200[self actionDeleteAtIndexPath:indexPath];201}202}203204- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath205{206if (indexPath.row == 0) {207// TODO: Reset action?208return UITableViewCellEditingStyleNone;209} else {210return UITableViewCellEditingStyleDelete;211}212}213214- (void)actionDeleteAtIndexPath:(NSIndexPath *)indexPath215{216UITableViewCell *view = [self.tableView cellForRowAtIndexPath:indexPath];217NSString *title = localize(@"preference.title.confirm", nil);218NSString *message = [NSString stringWithFormat:localize(@"preference.title.confirm.delete_game_directory", nil), self.array[indexPath.row]];219UIAlertController *confirmAlert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleActionSheet];220confirmAlert.popoverPresentationController.sourceView = view;221confirmAlert.popoverPresentationController.sourceRect = view.bounds;222UIAlertAction *ok = [UIAlertAction actionWithTitle:localize(@"OK", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {223NSString *directory = [NSString stringWithFormat:@"%s/instances/%@", getenv("POJAV_HOME"), self.array[indexPath.row]];224NSError *error;225if([NSFileManager.defaultManager removeItemAtPath:directory error:&error]) {226if ([getPrefObject(@"general.game_directory") isEqualToString:self.array[indexPath.row]]) {227[self changeSelectionTo:self.array[0]];228[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].accessoryType = UITableViewCellAccessoryCheckmark;229}230[self.array removeObjectAtIndex:indexPath.row];231[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];232} else {233showDialog(localize(@"Error", nil), error.localizedDescription);234}235}];236UIAlertAction *cancel = [UIAlertAction actionWithTitle:localize(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil];237[confirmAlert addAction:cancel];238[confirmAlert addAction:ok];239[self presentViewController:confirmAlert animated:YES completion:nil];240}241242- (void) dismissModalViewController {243[self.navigationController dismissViewControllerAnimated:YES completion:nil];244}245246#pragma mark UITextField247248- (void)textFieldDidEndEditing:(UITextField *)sender {249BOOL isFooterView = sender.superview == self.tableView;250if (!sender.hasText || [sender.text isEqualToString:sender.placeholder]) {251if (isFooterView) {252return;253}254sender.text = sender.placeholder;255return;256}257258NSError *error;259260NSString *dest = [NSString stringWithFormat:@"%s/instances/%@", getenv("POJAV_HOME"), sender.text];261if (isFooterView) {262[NSFileManager.defaultManager createDirectoryAtPath:dest withIntermediateDirectories:NO attributes:nil error:&error];263} else {264NSString *source = [NSString stringWithFormat:@"%s/instances/%@", getenv("POJAV_HOME"), sender.placeholder];265[NSFileManager.defaultManager moveItemAtPath:source toPath:dest error:&error];266}267268if (error == nil) {269[self changeSelectionTo:sender.text];270if (isFooterView) {271NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.array.count inSection:0];272[self.array addObject:sender.text];273[self.tableView beginUpdates];274[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];275[self.tableView endUpdates];276[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];277// Clear text278sender.text = @"";279} else {280int index = [self.array indexOfObject:sender.placeholder];281self.array[index] = sender.placeholder = sender.text;282NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];283[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];284}285} else {286// Restore to the previous name if we encounter an error287if (!isFooterView) {288sender.text = sender.placeholder;289}290showDialog(localize(@"Error", nil), error.localizedDescription);291}292}293294- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {295[textField invalidateIntrinsicContentSize];296CGRect frame = textField.frame;297frame.size.width = MAX(50, textField.intrinsicContentSize.width + 10);298textField.frame = frame;299return YES;300}301302@end303304305