diff --git a/Natives/CMakeLists.txt b/Natives/CMakeLists.txt index f624a4a5..419cca93 100644 --- a/Natives/CMakeLists.txt +++ b/Natives/CMakeLists.txt @@ -17,6 +17,7 @@ include_directories( "external/AFNetworking/AFNetworking" "external/AFNetworking/UIKit+AFNetworking" "external/DBNumberedSlider/Classes" + "external/NRFileManager" "external/TOInsetGroupedTableView/TOInsetGroupedTableView" "external/fishhook" "external/mesa" @@ -67,7 +68,7 @@ target_link_libraries(tinygl4angle ) -add_executable(PojavLauncher +add_library(AFNetworking SHARED external/AFNetworking/AFNetworking/AFSecurityPolicy.m external/AFNetworking/AFNetworking/AFHTTPSessionManager.m external/AFNetworking/AFNetworking/AFURLRequestSerialization.m @@ -79,7 +80,17 @@ add_executable(PojavLauncher external/AFNetworking/UIKit+AFNetworking/AFImageDownloader.m external/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.m external/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.m +) +target_link_libraries(AFNetworking + "-framework CoreGraphics" + "-framework CoreServices" + "-framework Security" + "-framework SystemConfiguration" + "-framework UIKit" +) + +add_executable(PojavLauncher main.m main_hook.m JavaLauncher.m @@ -97,6 +108,7 @@ add_executable(PojavLauncher customcontrols/CustomControlsUtils.m external/DBNumberedSlider/Classes/DBNumberedSlider.m + external/NRFileManager/NSFileManager+NRFileManager.m external/TOInsetGroupedTableView/TOInsetGroupedTableView/TOInsetGroupedTableView.m input/ControllerInput.m @@ -136,6 +148,7 @@ target_sources(PojavLauncher PUBLIC non_darwin_utils.m) endif() target_link_libraries(PojavLauncher + PUBLIC AFNetworking "-F'${CMAKE_CURRENT_LIST_DIR}/build'" "-F'${CMAKE_CURRENT_LIST_DIR}/resources/Frameworks'" "-framework AltKit" @@ -145,11 +158,8 @@ target_link_libraries(PojavLauncher "-framework CoreGraphics" "-framework CoreImage" "-framework CoreMotion" - "-framework CoreServices" "-framework GameController" "-framework QuartzCore" - "-framework Security" - "-framework SystemConfiguration" "-framework UIKit" "-framework WebKit" ) diff --git a/Natives/LauncherPrefGameDirViewController.m b/Natives/LauncherPrefGameDirViewController.m index 8eb53998..24200476 100644 --- a/Natives/LauncherPrefGameDirViewController.m +++ b/Natives/LauncherPrefGameDirViewController.m @@ -1,6 +1,7 @@ #import "LauncherNavigationController.h" #import "LauncherPreferences.h" #import "LauncherPrefGameDirViewController.h" +#import "NSFileManager+NRFileManager.h" #import "TOInsetGroupedTableView.h" #import "ios_uikit_bridge.h" #import "utils.h" @@ -62,7 +63,7 @@ UITextField *view; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; if (cell == nil) { - cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"]; + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"]; view = [[UITextField alloc] initWithFrame:CGRectMake(20, 10, (cell.bounds.size.width-40)/2, cell.bounds.size.height-20)]; [view addTarget:view action:@selector(resignFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit]; view.autocorrectionType = UITextAutocorrectionTypeNo; @@ -72,10 +73,23 @@ view.returnKeyType = UIReturnKeyDone; view.userInteractionEnabled = indexPath.row != 0; [cell.contentView addSubview:view]; + cell.detailTextLabel.text = @"..."; } - view = cell.contentView.subviews.lastObject; + view = cell.contentView.subviews.firstObject; view.placeholder = self.array[indexPath.row]; view.text = self.array[indexPath.row]; + cell.textLabel.hidden = YES; + cell.textLabel.text = view.text; + + // Calculate the instance size + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + unsigned long long folderSize = 0; + NSString *directory = [NSString stringWithFormat:@"%s/instances/%@", getenv("POJAV_HOME"), self.array[indexPath.row]]; + [NSFileManager.defaultManager nr_getAllocatedSize:&folderSize ofDirectoryAtURL:[NSURL fileURLWithPath:directory] error:nil]; + dispatch_async(dispatch_get_main_queue(), ^{ + cell.detailTextLabel.text = [NSByteCountFormatter stringFromByteCount:folderSize countStyle:NSByteCountFormatterCountStyleMemory]; + }); + }); if ([getPreference(@"game_directory") isEqualToString:self.array[indexPath.row]]) { cell.accessoryType = UITableViewCellAccessoryCheckmark; @@ -181,7 +195,7 @@ viewForFooterInSection:(NSInteger)section identifier:nil handler:^(UIAction *action) { UITableViewCell *view = [self.tableView cellForRowAtIndexPath:indexPath]; - [view.contentView.subviews.lastObject becomeFirstResponder]; + [view.contentView.subviews.firstObject becomeFirstResponder]; } ]; diff --git a/Natives/external/NRFileManager/NSFileManager+NRFileManager.h b/Natives/external/NRFileManager/NSFileManager+NRFileManager.h new file mode 100644 index 00000000..d7a2dc87 --- /dev/null +++ b/Natives/external/NRFileManager/NSFileManager+NRFileManager.h @@ -0,0 +1,15 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Created and contributed by Nikolai Ruhe + * https://github.com/NikolaiRuhe/NRFoundation */ + +#import + + +@interface NSFileManager (NRFileManager) + +- (BOOL)nr_getAllocatedSize:(unsigned long long *)size ofDirectoryAtURL:(NSURL *)url error:(NSError * __autoreleasing *)error; + +@end diff --git a/Natives/external/NRFileManager/NSFileManager+NRFileManager.m b/Natives/external/NRFileManager/NSFileManager+NRFileManager.m new file mode 100644 index 00000000..a2888a60 --- /dev/null +++ b/Natives/external/NRFileManager/NSFileManager+NRFileManager.m @@ -0,0 +1,93 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Created and contributed by Nikolai Ruhe + * https://github.com/NikolaiRuhe/NRFoundation */ + +#import "NSFileManager+NRFileManager.h" + +@implementation NSFileManager (NRFileManager) + +// This method calculates the accumulated size of a directory on the volume in bytes. +// +// As there's no simple way to get this information from the file system it has to crawl the entire hierarchy, +// accumulating the overall sum on the way. The resulting value is roughly equivalent with the amount of bytes +// that would become available on the volume if the directory would be deleted. +// +// Caveat: There are a couple of oddities that are not taken into account (like symbolic links, meta data of +// directories, hard links, ...). + +- (BOOL)nr_getAllocatedSize:(unsigned long long *)size ofDirectoryAtURL:(NSURL *)directoryURL error:(NSError * __autoreleasing *)error +{ + NSParameterAssert(size != NULL); + NSParameterAssert(directoryURL != nil); + + // We'll sum up content size here: + unsigned long long accumulatedSize = 0; + + // prefetching some properties during traversal will speed up things a bit. + NSArray *prefetchedProperties = @[ + NSURLIsRegularFileKey, + NSURLFileAllocatedSizeKey, + NSURLTotalFileAllocatedSizeKey, + ]; + + // The error handler simply signals errors to outside code. + __block BOOL errorDidOccur = NO; + BOOL (^errorHandler)(NSURL *, NSError *) = ^(NSURL *url, NSError *localError) { + if (error != NULL) + *error = localError; + errorDidOccur = YES; + return NO; + }; + + // We have to enumerate all directory contents, including subdirectories. + NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:directoryURL + includingPropertiesForKeys:prefetchedProperties + options:(NSDirectoryEnumerationOptions)0 + errorHandler:errorHandler]; + + // Start the traversal: + for (NSURL *contentItemURL in enumerator) { + + // Bail out on errors from the errorHandler. + if (errorDidOccur) + return NO; + + // Get the type of this item, making sure we only sum up sizes of regular files. + NSNumber *isRegularFile; + if (! [contentItemURL getResourceValue:&isRegularFile forKey:NSURLIsRegularFileKey error:error]) + return NO; + if (! [isRegularFile boolValue]) + continue; // Ignore anything except regular files. + + // To get the file's size we first try the most comprehensive value in terms of what the file may use on disk. + // This includes metadata, compression (on file system level) and block size. + NSNumber *fileSize; + if (! [contentItemURL getResourceValue:&fileSize forKey:NSURLTotalFileAllocatedSizeKey error:error]) + return NO; + + // In case the value is unavailable we use the fallback value (excluding meta data and compression) + // This value should always be available. + if (fileSize == nil) { + if (! [contentItemURL getResourceValue:&fileSize forKey:NSURLFileAllocatedSizeKey error:error]) + return NO; + + NSAssert(fileSize != nil, @"huh? NSURLFileAllocatedSizeKey should always return a value"); + } + + // We're good, add up the value. + accumulatedSize += [fileSize unsignedLongLongValue]; + } + + // Bail out on errors from the errorHandler. + if (errorDidOccur) + return NO; + + // We finally got it. + *size = accumulatedSize; + return YES; +} + +@end diff --git a/README.md b/README.md index 1e494562..a0f2027b 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,7 @@ PojavLauncher is amazing, and surprisingly stable, and it wouldn't be this way w - [fishhook](https://github.com/khanhduytran0/fishhook): [BSD-3 License](https://github.com/facebook/fishhook/blob/main/LICENSE). - [Java Native Access](https://github.com/java-native-access/jna): [Apache 2.0 License](https://github.com/java-native-access/jna/blob/master/LICENSE). - [shaderc](https://github.com/khanhduytran0/shaderc) (used by Vulkan rendering mods): [Apache 2.0 License](https://github.com/google/shaderc/blob/main/LICENSE). +- [NRFileManager](https://github.com/mozilla-mobile/firefox-ios/tree/b2f89ac40835c5988a1a3eb642982544e00f0f90/ThirdParty/NRFileManager): [MPL-2.0 License](https://www.mozilla.org/en-US/MPL/2.0) - [TOInsetGroupedTableView](https://github.com/TimOliver/TOInsetGroupedTableView): [MIT License](https://github.com/TimOliver/TOInsetGroupedTableView/blob/master/LICENSE). - [AltKit](https://github.com/rileytestut/AltKit) - Thanks to [MCHeads](https://mc-heads.net) for providing Minecraft avatars.