mirror of
				https://github.com/opa334/TrollStore.git
				synced 2025-11-04 15:42:35 +08:00 
			
		
		
		
	1.1
This commit is contained in:
		
							parent
							
								
									690545931c
								
							
						
					
					
						commit
						b67e3aa9d1
					
				@ -1,6 +1,6 @@
 | 
			
		||||
Package: com.opa334.trollstoreroothelper
 | 
			
		||||
Name: trollstoreroothelper
 | 
			
		||||
Version: 1.0.10
 | 
			
		||||
Version: 1.1
 | 
			
		||||
Architecture: iphoneos-arm
 | 
			
		||||
Description: An awesome tool of some sort!!
 | 
			
		||||
Maintainer: opa334
 | 
			
		||||
 | 
			
		||||
@ -730,6 +730,11 @@ int installApp(NSString* appPath, BOOL sign, BOOL force)
 | 
			
		||||
	// Wipe old version if needed
 | 
			
		||||
	if(existed)
 | 
			
		||||
	{
 | 
			
		||||
		if(![appId isEqualToString:@"com.opa334.TrollStore"])
 | 
			
		||||
		{
 | 
			
		||||
			BKSTerminateApplicationForReasonAndReportWithDescription(appId, 5, false, @"TrollStore - App updated");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		NSLog(@"[installApp] found existing TrollStore app, cleaning directory");
 | 
			
		||||
		NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:appContainer.url includingPropertiesForKeys:nil options:0 errorHandler:nil];
 | 
			
		||||
		NSURL* fileURL;
 | 
			
		||||
@ -738,7 +743,7 @@ int installApp(NSString* appPath, BOOL sign, BOOL force)
 | 
			
		||||
			// do not under any circumstance delete this file as it makes iOS loose the app registration
 | 
			
		||||
			if([fileURL.lastPathComponent isEqualToString:@".com.apple.mobile_container_manager.metadata.plist"] || [fileURL.lastPathComponent isEqualToString:@"_TrollStore"])
 | 
			
		||||
			{
 | 
			
		||||
				NSLog(@"[installApp] skip removal of %@", fileURL);
 | 
			
		||||
				NSLog(@"[installApp] skipping removal of %@", fileURL);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@ -767,6 +772,8 @@ int installApp(NSString* appPath, BOOL sign, BOOL force)
 | 
			
		||||
 | 
			
		||||
int uninstallApp(NSString* appPath, NSString* appId)
 | 
			
		||||
{
 | 
			
		||||
	BKSTerminateApplicationForReasonAndReportWithDescription(appId, 5, false, @"TrollStore - App uninstalled");
 | 
			
		||||
 | 
			
		||||
	LSApplicationProxy* appProxy = [LSApplicationProxy applicationProxyForIdentifier:appId];
 | 
			
		||||
	MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil];
 | 
			
		||||
	NSString *containerPath = [appContainer url].path;
 | 
			
		||||
@ -1156,6 +1163,14 @@ int main(int argc, char *argv[], char *envp[]) {
 | 
			
		||||
		} else if([cmd isEqualToString:@"uninstall-persistence-helper"])
 | 
			
		||||
		{
 | 
			
		||||
			uninstallPersistenceHelper();
 | 
			
		||||
		} else if([cmd isEqualToString:@"dash"])
 | 
			
		||||
		{
 | 
			
		||||
			LSApplicationProxy* appProxy = findPersistenceHelperApp();
 | 
			
		||||
			if(appProxy)
 | 
			
		||||
			{
 | 
			
		||||
				NSString* executablePath = appProxy.canonicalExecutablePath;
 | 
			
		||||
				registerPath((char*)executablePath.UTF8String, 1);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		NSLog(@"returning %d", ret);
 | 
			
		||||
 | 
			
		||||
@ -127,7 +127,6 @@ void registerPath(char* cPath, int unregister)
 | 
			
		||||
		// Misc
 | 
			
		||||
 | 
			
		||||
		dictToRegister[@"ApplicationType"] = @"System";
 | 
			
		||||
		dictToRegister[@"BundleNameIsLocalized"] = @1;
 | 
			
		||||
		dictToRegister[@"CFBundleIdentifier"] = appBundleID;
 | 
			
		||||
		dictToRegister[@"CodeInfoIdentifier"] = appBundleID;
 | 
			
		||||
		dictToRegister[@"CompatibilityState"] = @0;
 | 
			
		||||
@ -144,6 +143,10 @@ void registerPath(char* cPath, int unregister)
 | 
			
		||||
		dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
 | 
			
		||||
		dictToRegister[@"IsAdHocSigned"] = @YES;
 | 
			
		||||
		dictToRegister[@"LSInstallType"] = @1;
 | 
			
		||||
		dictToRegister[@"HasMIDBasedSINF"] = @0;
 | 
			
		||||
		dictToRegister[@"MissingSINF"] = @0;
 | 
			
		||||
		dictToRegister[@"FamilyID"] = @0;
 | 
			
		||||
		dictToRegister[@"IsOnDemandInstallCapable"] = @0;
 | 
			
		||||
 | 
			
		||||
		NSString* teamIdentifier = constructTeamIdentifierForEntitlements(entitlements);
 | 
			
		||||
		if(teamIdentifier) dictToRegister[@"TeamIdentifier"] = teamIdentifier;
 | 
			
		||||
@ -199,7 +202,6 @@ void registerPath(char* cPath, int unregister)
 | 
			
		||||
			// Misc
 | 
			
		||||
 | 
			
		||||
			pluginDict[@"ApplicationType"] = @"PluginKitPlugin";
 | 
			
		||||
			pluginDict[@"BundleNameIsLocalized"] = @1;
 | 
			
		||||
			pluginDict[@"CFBundleIdentifier"] = pluginBundleID;
 | 
			
		||||
			pluginDict[@"CodeInfoIdentifier"] = pluginBundleID;
 | 
			
		||||
			pluginDict[@"CompatibilityState"] = @0;
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ include $(THEOS)/makefiles/common.mk
 | 
			
		||||
 | 
			
		||||
APPLICATION_NAME = TrollStorePersistenceHelper
 | 
			
		||||
 | 
			
		||||
TrollStorePersistenceHelper_FILES = $(wildcard *.m) ../Helper/Shared.m ../Store/TSUtil.m
 | 
			
		||||
TrollStorePersistenceHelper_FILES = $(wildcard *.m) ../Helper/Shared.m ../Store/TSUtil.m ../Store/TSListControllerShared.m
 | 
			
		||||
TrollStorePersistenceHelper_FRAMEWORKS = UIKit CoreGraphics CoreServices
 | 
			
		||||
TrollStorePersistenceHelper_PRIVATE_FRAMEWORKS = Preferences
 | 
			
		||||
TrollStorePersistenceHelper_CFLAGS = -fobjc-arc
 | 
			
		||||
 | 
			
		||||
@ -52,7 +52,7 @@
 | 
			
		||||
		<string>iPhoneOS</string>
 | 
			
		||||
	</array>
 | 
			
		||||
	<key>CFBundleVersion</key>
 | 
			
		||||
	<string>1.0.10</string>
 | 
			
		||||
	<string>1.1</string>
 | 
			
		||||
	<key>LSRequiresIPhoneOS</key>
 | 
			
		||||
	<true/>
 | 
			
		||||
	<key>UIDeviceFamily</key>
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,7 @@
 | 
			
		||||
#import <UIKit/UIKit.h>
 | 
			
		||||
#import <Preferences/PSListController.h>
 | 
			
		||||
#import <Preferences/PSSpecifier.h>
 | 
			
		||||
#import "../Store/TSListControllerShared.h"
 | 
			
		||||
 | 
			
		||||
@interface TSPHRootViewController : PSListController
 | 
			
		||||
@interface TSPHRootViewController : TSListControllerShared
 | 
			
		||||
{
 | 
			
		||||
    UIAlertController* _activityController;
 | 
			
		||||
    NSString* _newerVersion;
 | 
			
		||||
}
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
@ -4,38 +4,29 @@
 | 
			
		||||
 | 
			
		||||
@implementation TSPHRootViewController
 | 
			
		||||
 | 
			
		||||
- (void)loadView
 | 
			
		||||
- (BOOL)isTrollStore
 | 
			
		||||
{
 | 
			
		||||
	[super loadView];
 | 
			
		||||
	return NO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)viewDidLoad
 | 
			
		||||
{
 | 
			
		||||
	[super viewDidLoad];
 | 
			
		||||
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSpecifiers) name:UIApplicationWillEnterForegroundNotification object:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)startActivity:(NSString*)activity
 | 
			
		||||
{
 | 
			
		||||
	if(_activityController) return;
 | 
			
		||||
 | 
			
		||||
	_activityController = [UIAlertController alertControllerWithTitle:activity message:@"" preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
	UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)];
 | 
			
		||||
	activityIndicator.hidesWhenStopped = YES;
 | 
			
		||||
	activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium;
 | 
			
		||||
	[activityIndicator startAnimating];
 | 
			
		||||
	[_activityController.view addSubview:activityIndicator];
 | 
			
		||||
 | 
			
		||||
	[self presentViewController:_activityController animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)stopActivityWithCompletion:(void (^)(void))completion
 | 
			
		||||
{
 | 
			
		||||
	if(!_activityController) return;
 | 
			
		||||
 | 
			
		||||
	[_activityController dismissViewControllerAnimated:YES completion:^
 | 
			
		||||
	fetchLatestTrollStoreVersion(^(NSString* latestVersion)
 | 
			
		||||
	{
 | 
			
		||||
		_activityController = nil;
 | 
			
		||||
		if(completion)
 | 
			
		||||
		NSString* currentVersion = [self getTrollStoreVersion];
 | 
			
		||||
		NSComparisonResult result = [currentVersion compare:latestVersion options:NSNumericSearch];
 | 
			
		||||
		if(result == NSOrderedAscending)
 | 
			
		||||
		{
 | 
			
		||||
			completion();
 | 
			
		||||
			_newerVersion = latestVersion;
 | 
			
		||||
			dispatch_async(dispatch_get_main_queue(), ^
 | 
			
		||||
			{
 | 
			
		||||
				[self reloadSpecifiers];
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}];
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSMutableArray*)specifiers
 | 
			
		||||
@ -60,10 +51,28 @@
 | 
			
		||||
 | 
			
		||||
		[_specifiers addObject:infoSpecifier];
 | 
			
		||||
 | 
			
		||||
		BOOL isInstalled = trollStoreAppPath();
 | 
			
		||||
 | 
			
		||||
		if(_newerVersion && isInstalled)
 | 
			
		||||
		{
 | 
			
		||||
			// Update TrollStore
 | 
			
		||||
			PSSpecifier* updateTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:[NSString stringWithFormat:@"Update TrollStore to %@", _newerVersion]
 | 
			
		||||
										target:self
 | 
			
		||||
										set:nil
 | 
			
		||||
										get:nil
 | 
			
		||||
										detail:nil
 | 
			
		||||
										cell:PSButtonCell
 | 
			
		||||
										edit:nil];
 | 
			
		||||
			updateTrollStoreSpecifier.identifier = @"updateTrollStore";
 | 
			
		||||
			[updateTrollStoreSpecifier setProperty:@YES forKey:@"enabled"];
 | 
			
		||||
			updateTrollStoreSpecifier.buttonAction = @selector(updateTrollStorePressed);
 | 
			
		||||
			[_specifiers addObject:updateTrollStoreSpecifier];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		PSSpecifier* utilitiesGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
 | 
			
		||||
		[_specifiers addObject:utilitiesGroupSpecifier];
 | 
			
		||||
 | 
			
		||||
		if(trollStoreAppPath())
 | 
			
		||||
		if(isInstalled)
 | 
			
		||||
		{
 | 
			
		||||
			PSSpecifier* refreshAppRegistrationsSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Refresh App Registrations"
 | 
			
		||||
												target:self
 | 
			
		||||
@ -74,7 +83,7 @@
 | 
			
		||||
												edit:nil];
 | 
			
		||||
			refreshAppRegistrationsSpecifier.identifier = @"refreshAppRegistrations";
 | 
			
		||||
			[refreshAppRegistrationsSpecifier setProperty:@YES forKey:@"enabled"];
 | 
			
		||||
			refreshAppRegistrationsSpecifier.buttonAction = @selector(refreshAppRegistrations);
 | 
			
		||||
			refreshAppRegistrationsSpecifier.buttonAction = @selector(refreshAppRegistrationsPressed);
 | 
			
		||||
			[_specifiers addObject:refreshAppRegistrationsSpecifier];
 | 
			
		||||
 | 
			
		||||
			PSSpecifier* uninstallTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Uninstall TrollStore"
 | 
			
		||||
@ -130,122 +139,21 @@
 | 
			
		||||
 | 
			
		||||
- (NSString*)getTrollStoreInfoString
 | 
			
		||||
{
 | 
			
		||||
	NSString* trollStore = trollStoreAppPath();
 | 
			
		||||
	if(!trollStore)
 | 
			
		||||
	NSString* version = [self getTrollStoreVersion];
 | 
			
		||||
	if(!version)
 | 
			
		||||
	{
 | 
			
		||||
		return @"Not Installed";
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		NSBundle* trollStoreBundle = [NSBundle bundleWithPath:trollStore];
 | 
			
		||||
		NSString* version = [trollStoreBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
 | 
			
		||||
		return [NSString stringWithFormat:@"Installed, %@", version];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)refreshAppRegistrations
 | 
			
		||||
- (void)handleUninstallation
 | 
			
		||||
{
 | 
			
		||||
	[self startActivity:@"Refreshing"];
 | 
			
		||||
 | 
			
		||||
	dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
 | 
			
		||||
	{
 | 
			
		||||
		spawnRoot(helperPath(), @[@"refresh"], nil, nil);
 | 
			
		||||
		respring();
 | 
			
		||||
 | 
			
		||||
		dispatch_async(dispatch_get_main_queue(), ^
 | 
			
		||||
		{
 | 
			
		||||
			[self stopActivityWithCompletion:nil];
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)installTrollStorePressed
 | 
			
		||||
{
 | 
			
		||||
	NSURL* trollStoreURL = [NSURL URLWithString:@"https://github.com/opa334/TrollStore/releases/latest/download/TrollStore.tar"];
 | 
			
		||||
	NSURLRequest* trollStoreRequest = [NSURLRequest requestWithURL:trollStoreURL];
 | 
			
		||||
 | 
			
		||||
	[self startActivity:@"Installing TrollStore"];
 | 
			
		||||
 | 
			
		||||
	NSURLSessionDownloadTask* downloadTask = [NSURLSession.sharedSession downloadTaskWithRequest:trollStoreRequest completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error)
 | 
			
		||||
	{
 | 
			
		||||
		if(error)
 | 
			
		||||
		{
 | 
			
		||||
			UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error downloading TrollStore: %@", error] preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
			UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil];
 | 
			
		||||
			[errorAlert addAction:closeAction];
 | 
			
		||||
 | 
			
		||||
			dispatch_async(dispatch_get_main_queue(), ^
 | 
			
		||||
			{
 | 
			
		||||
				[self stopActivityWithCompletion:^
 | 
			
		||||
				{
 | 
			
		||||
					[self presentViewController:errorAlert animated:YES completion:nil];
 | 
			
		||||
				}];
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			NSString* tarTmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"TrollStore.tar"];
 | 
			
		||||
			[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:tarTmpPath error:nil];
 | 
			
		||||
 | 
			
		||||
			int ret = spawnRoot(helperPath(), @[@"install-trollstore", tarTmpPath], nil, nil);
 | 
			
		||||
			dispatch_async(dispatch_get_main_queue(), ^
 | 
			
		||||
			{
 | 
			
		||||
				[[NSFileManager defaultManager] removeItemAtPath:tarTmpPath error:nil];
 | 
			
		||||
				[self stopActivityWithCompletion:^
 | 
			
		||||
				{
 | 
			
		||||
					[self reloadSpecifiers];
 | 
			
		||||
 | 
			
		||||
					if(ret == 0)
 | 
			
		||||
					{
 | 
			
		||||
						respring();
 | 
			
		||||
					}
 | 
			
		||||
					else
 | 
			
		||||
					{
 | 
			
		||||
						UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error installing TrollStore: trollstorehelper returned %d", ret] preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
						UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil];
 | 
			
		||||
						[errorAlert addAction:closeAction];
 | 
			
		||||
						[self presentViewController:errorAlert animated:YES completion:nil];
 | 
			
		||||
					}
 | 
			
		||||
				}];
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}];
 | 
			
		||||
 | 
			
		||||
	[downloadTask resume];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)uninstallTrollStorePressed
 | 
			
		||||
{
 | 
			
		||||
	UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"About to uninstall TrollStore and all of the apps installed by it. Continue?" preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
	
 | 
			
		||||
	UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
 | 
			
		||||
	[uninstallWarningAlert addAction:cancelAction];
 | 
			
		||||
 | 
			
		||||
	UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
 | 
			
		||||
	{
 | 
			
		||||
		spawnRoot(helperPath(), @[@"uninstall-trollstore"], nil, nil);
 | 
			
		||||
		[self reloadSpecifiers];
 | 
			
		||||
	}];
 | 
			
		||||
	[uninstallWarningAlert addAction:continueAction];
 | 
			
		||||
 | 
			
		||||
	[self presentViewController:uninstallWarningAlert animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)uninstallPersistenceHelperPressed
 | 
			
		||||
{
 | 
			
		||||
	UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"Uninstalling the persistence helper will revert this app back to it's original state, you will however no longer be able to persistently refresh the TrollStore app registrations. Continue?" preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
	
 | 
			
		||||
	UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
 | 
			
		||||
	[uninstallWarningAlert addAction:cancelAction];
 | 
			
		||||
 | 
			
		||||
	UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
 | 
			
		||||
	{
 | 
			
		||||
		spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], nil, nil);
 | 
			
		||||
		exit(0);
 | 
			
		||||
	}];
 | 
			
		||||
	[uninstallWarningAlert addAction:continueAction];
 | 
			
		||||
 | 
			
		||||
	[self presentViewController:uninstallWarningAlert animated:YES completion:nil];
 | 
			
		||||
	_newerVersion = nil;
 | 
			
		||||
	[super handleUninstallation];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
Package: com.opa334.trollstorehelper
 | 
			
		||||
Name: TrollStore Helper
 | 
			
		||||
Version: 1.0.10
 | 
			
		||||
Version: 1.1
 | 
			
		||||
Architecture: iphoneos-arm
 | 
			
		||||
Description: Helper utility to install and manage TrollStore!
 | 
			
		||||
Maintainer: opa334
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,7 @@
 | 
			
		||||
		<string>iPhoneOS</string>
 | 
			
		||||
	</array>
 | 
			
		||||
	<key>CFBundleVersion</key>
 | 
			
		||||
	<string>1.0.10</string>
 | 
			
		||||
	<string>1.1</string>
 | 
			
		||||
	<key>LSRequiresIPhoneOS</key>
 | 
			
		||||
	<true/>
 | 
			
		||||
	<key>UIDeviceFamily</key>
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,32 @@
 | 
			
		||||
 | 
			
		||||
#import "TSApplicationsManager.h"
 | 
			
		||||
 | 
			
		||||
#define ICON_FORMAT_IPAD 8
 | 
			
		||||
#define ICON_FORMAT_IPHONE 10
 | 
			
		||||
 | 
			
		||||
NSInteger iconFormatToUse(void)
 | 
			
		||||
{
 | 
			
		||||
	if(UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad)
 | 
			
		||||
	{
 | 
			
		||||
		return ICON_FORMAT_IPAD;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		return ICON_FORMAT_IPHONE;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
UIImage* imageWithSize(UIImage* image, CGSize size)
 | 
			
		||||
{
 | 
			
		||||
	if(CGSizeEqualToSize(image.size, size)) return image;
 | 
			
		||||
	UIGraphicsBeginImageContextWithOptions(size, NO, UIScreen.mainScreen.scale);
 | 
			
		||||
	CGRect imageRect = CGRectMake(0.0, 0.0, size.width, size.height);
 | 
			
		||||
	[image drawInRect:imageRect];
 | 
			
		||||
	UIImage* outImage = UIGraphicsGetImageFromCurrentImageContext();
 | 
			
		||||
	UIGraphicsEndImageContext();
 | 
			
		||||
	return outImage;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@interface UIImage ()
 | 
			
		||||
+ (UIImage *)_applicationIconImageForBundleIdentifier:(NSString *)id format:(NSInteger)format scale:(double)scale;
 | 
			
		||||
@end
 | 
			
		||||
@ -10,7 +36,14 @@
 | 
			
		||||
 | 
			
		||||
- (void)loadCachedAppPaths
 | 
			
		||||
{
 | 
			
		||||
	_cachedAppPaths = [[TSApplicationsManager sharedInstance] installedAppPaths];
 | 
			
		||||
	NSArray* appPaths = [[TSApplicationsManager sharedInstance] installedAppPaths];
 | 
			
		||||
 | 
			
		||||
	_cachedAppPaths = [appPaths sortedArrayUsingComparator:^NSComparisonResult(NSString* appPathA, NSString* appPathB) {
 | 
			
		||||
		NSString* displayNameA = [[TSApplicationsManager sharedInstance] displayNameForAppPath:appPathA];
 | 
			
		||||
		NSString* displayNameB = [[TSApplicationsManager sharedInstance] displayNameForAppPath:appPathB];
 | 
			
		||||
 | 
			
		||||
		return [displayNameA localizedStandardCompare:displayNameB];
 | 
			
		||||
	}];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (instancetype)init
 | 
			
		||||
@ -19,7 +52,7 @@
 | 
			
		||||
	if(self)
 | 
			
		||||
	{
 | 
			
		||||
		[self loadCachedAppPaths];
 | 
			
		||||
		_placeholderIcon = [UIImage _applicationIconImageForBundleIdentifier:@"com.apple.WebSheet" format:10 scale:[UIScreen mainScreen].scale];
 | 
			
		||||
		_placeholderIcon = [UIImage _applicationIconImageForBundleIdentifier:@"com.apple.WebSheet" format:iconFormatToUse() scale:[UIScreen mainScreen].scale];
 | 
			
		||||
		_cachedIcons = [NSMutableDictionary new];
 | 
			
		||||
	}
 | 
			
		||||
	return self;
 | 
			
		||||
@ -120,6 +153,11 @@
 | 
			
		||||
	return _cachedAppPaths.count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
 | 
			
		||||
{
 | 
			
		||||
	[self reloadTable];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 | 
			
		||||
	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ApplicationCell"];
 | 
			
		||||
	if (!cell) {
 | 
			
		||||
@ -133,9 +171,11 @@
 | 
			
		||||
	// Configure the cell...
 | 
			
		||||
	cell.textLabel.text = [[TSApplicationsManager sharedInstance] displayNameForAppPath:appPath];
 | 
			
		||||
	cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ • %@", appVersion, appId];
 | 
			
		||||
	cell.imageView.layer.borderWidth = 0.34;
 | 
			
		||||
	cell.imageView.layer.borderColor = [UIColor separatorColor].CGColor;
 | 
			
		||||
	cell.imageView.layer.cornerRadius = 13.8;
 | 
			
		||||
	cell.imageView.layer.borderWidth = 1;
 | 
			
		||||
	cell.imageView.layer.borderColor = [UIColor.labelColor colorWithAlphaComponent:0.1].CGColor;
 | 
			
		||||
	cell.imageView.layer.cornerRadius = 13.5;
 | 
			
		||||
	cell.imageView.layer.masksToBounds = YES;
 | 
			
		||||
	cell.imageView.layer.cornerCurve = kCACornerCurveContinuous;
 | 
			
		||||
 | 
			
		||||
	if(appId)
 | 
			
		||||
	{
 | 
			
		||||
@ -150,12 +190,13 @@
 | 
			
		||||
			dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
 | 
			
		||||
			{
 | 
			
		||||
				//usleep(1000 * 5000); // (test delay for debugging)
 | 
			
		||||
				UIImage* iconImage = [UIImage _applicationIconImageForBundleIdentifier:appId format:10 scale:[UIScreen mainScreen].scale];
 | 
			
		||||
				UIImage* iconImage = imageWithSize([UIImage _applicationIconImageForBundleIdentifier:appId format:iconFormatToUse() scale:[UIScreen mainScreen].scale], _placeholderIcon.size);
 | 
			
		||||
				_cachedIcons[appId] = iconImage;
 | 
			
		||||
				dispatch_async(dispatch_get_main_queue(), ^{
 | 
			
		||||
					if([tableView.indexPathsForVisibleRows containsObject:indexPath])
 | 
			
		||||
					{
 | 
			
		||||
						cell.imageView.image = iconImage;
 | 
			
		||||
						[cell setNeedsLayout];
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
@ -207,7 +248,7 @@
 | 
			
		||||
	[appSelectAlert addAction:detachAction];*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	UIAlertAction* openAction = [UIAlertAction actionWithTitle: @"Open" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action)
 | 
			
		||||
	UIAlertAction* openAction = [UIAlertAction actionWithTitle:@"Open" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action)
 | 
			
		||||
	{
 | 
			
		||||
		[self openAppPressedForRowAtIndexPath:indexPath];
 | 
			
		||||
		[self deselectRow];
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								Store/TSListControllerShared.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Store/TSListControllerShared.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
#import <UIKit/UIKit.h>
 | 
			
		||||
#import <Preferences/PSListController.h>
 | 
			
		||||
#import <Preferences/PSSpecifier.h>
 | 
			
		||||
 | 
			
		||||
@interface TSListControllerShared : PSListController
 | 
			
		||||
{
 | 
			
		||||
    UIAlertController* _activityController;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (BOOL)isTrollStore;
 | 
			
		||||
- (NSString*)getTrollStoreVersion;
 | 
			
		||||
 | 
			
		||||
- (void)startActivity:(NSString*)activity;
 | 
			
		||||
- (void)stopActivityWithCompletion:(void (^)(void))completion;
 | 
			
		||||
 | 
			
		||||
- (void)installTrollStorePressed;
 | 
			
		||||
- (void)updateTrollStorePressed;
 | 
			
		||||
- (void)rebuildIconCachePressed;
 | 
			
		||||
- (void)refreshAppRegistrationsPressed;
 | 
			
		||||
- (void)uninstallPersistenceHelperPressed;
 | 
			
		||||
- (void)handleUninstallation;
 | 
			
		||||
- (void)uninstallTrollStorePressed;
 | 
			
		||||
@end
 | 
			
		||||
							
								
								
									
										227
									
								
								Store/TSListControllerShared.m
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								Store/TSListControllerShared.m
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,227 @@
 | 
			
		||||
#import "TSListControllerShared.h"
 | 
			
		||||
#import "TSUtil.h"
 | 
			
		||||
#import "../Helper/Shared.h"
 | 
			
		||||
 | 
			
		||||
@implementation TSListControllerShared
 | 
			
		||||
 | 
			
		||||
- (BOOL)isTrollStore
 | 
			
		||||
{
 | 
			
		||||
	return YES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSString*)getTrollStoreVersion
 | 
			
		||||
{
 | 
			
		||||
	if([self isTrollStore])
 | 
			
		||||
	{
 | 
			
		||||
		return [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		NSString* trollStorePath = trollStoreAppPath();
 | 
			
		||||
		if(!trollStorePath) return nil;
 | 
			
		||||
 | 
			
		||||
		NSBundle* trollStoreBundle = [NSBundle bundleWithPath:trollStorePath];
 | 
			
		||||
		return [trollStoreBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)startActivity:(NSString*)activity
 | 
			
		||||
{
 | 
			
		||||
	if(_activityController) return;
 | 
			
		||||
 | 
			
		||||
	_activityController = [UIAlertController alertControllerWithTitle:activity message:@"" preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
	UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)];
 | 
			
		||||
	activityIndicator.hidesWhenStopped = YES;
 | 
			
		||||
	activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium;
 | 
			
		||||
	[activityIndicator startAnimating];
 | 
			
		||||
	[_activityController.view addSubview:activityIndicator];
 | 
			
		||||
 | 
			
		||||
	[self presentViewController:_activityController animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)stopActivityWithCompletion:(void (^)(void))completion
 | 
			
		||||
{
 | 
			
		||||
	if(!_activityController) return;
 | 
			
		||||
 | 
			
		||||
	[_activityController dismissViewControllerAnimated:YES completion:^
 | 
			
		||||
	{
 | 
			
		||||
		_activityController = nil;
 | 
			
		||||
		if(completion)
 | 
			
		||||
		{
 | 
			
		||||
			completion();
 | 
			
		||||
		}
 | 
			
		||||
	}];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)_updateOrInstallTrollStore:(BOOL)update
 | 
			
		||||
{
 | 
			
		||||
	NSURL* trollStoreURL = [NSURL URLWithString:@"https://github.com/opa334/TrollStore/releases/latest/download/TrollStore.tar"];
 | 
			
		||||
	NSURLRequest* trollStoreRequest = [NSURLRequest requestWithURL:trollStoreURL];
 | 
			
		||||
 | 
			
		||||
	if(update)
 | 
			
		||||
	{
 | 
			
		||||
		[self startActivity:@"Updating TrollStore"];
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		[self startActivity:@"Installing TrollStore"];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	NSURLSessionDownloadTask* downloadTask = [NSURLSession.sharedSession downloadTaskWithRequest:trollStoreRequest completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error)
 | 
			
		||||
	{
 | 
			
		||||
		if(error)
 | 
			
		||||
		{
 | 
			
		||||
			UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error downloading TrollStore: %@", error] preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
			UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil];
 | 
			
		||||
			[errorAlert addAction:closeAction];
 | 
			
		||||
 | 
			
		||||
			dispatch_async(dispatch_get_main_queue(), ^
 | 
			
		||||
			{
 | 
			
		||||
				[self stopActivityWithCompletion:^
 | 
			
		||||
				{
 | 
			
		||||
					[self presentViewController:errorAlert animated:YES completion:nil];
 | 
			
		||||
				}];
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			NSString* tarTmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"TrollStore.tar"];
 | 
			
		||||
			[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:tarTmpPath error:nil];
 | 
			
		||||
 | 
			
		||||
			int ret = spawnRoot(helperPath(), @[@"install-trollstore", tarTmpPath], nil, nil);
 | 
			
		||||
			[[NSFileManager defaultManager] removeItemAtPath:tarTmpPath error:nil];
 | 
			
		||||
 | 
			
		||||
			if(ret == 0)
 | 
			
		||||
			{
 | 
			
		||||
				respring();
 | 
			
		||||
 | 
			
		||||
				if([self isTrollStore])
 | 
			
		||||
				{
 | 
			
		||||
					exit(0);
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					dispatch_async(dispatch_get_main_queue(), ^
 | 
			
		||||
					{
 | 
			
		||||
						[self stopActivityWithCompletion:^
 | 
			
		||||
						{
 | 
			
		||||
							[self reloadSpecifiers];
 | 
			
		||||
						}];
 | 
			
		||||
					});
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				dispatch_async(dispatch_get_main_queue(), ^
 | 
			
		||||
				{
 | 
			
		||||
					[self stopActivityWithCompletion:^
 | 
			
		||||
					{
 | 
			
		||||
						UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error installing TrollStore: trollstorehelper returned %d", ret] preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
						UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil];
 | 
			
		||||
						[errorAlert addAction:closeAction];
 | 
			
		||||
						[self presentViewController:errorAlert animated:YES completion:nil];
 | 
			
		||||
					}];
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}];
 | 
			
		||||
 | 
			
		||||
	[downloadTask resume];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)installTrollStorePressed
 | 
			
		||||
{
 | 
			
		||||
	[self _updateOrInstallTrollStore:NO];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)updateTrollStorePressed
 | 
			
		||||
{
 | 
			
		||||
	[self _updateOrInstallTrollStore:YES];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)rebuildIconCachePressed
 | 
			
		||||
{
 | 
			
		||||
	[self startActivity:@"Rebuilding Icon Cache"];
 | 
			
		||||
 | 
			
		||||
	dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
 | 
			
		||||
	{
 | 
			
		||||
		spawnRoot(helperPath(), @[@"refresh-all"], nil, nil);
 | 
			
		||||
 | 
			
		||||
		dispatch_async(dispatch_get_main_queue(), ^
 | 
			
		||||
		{
 | 
			
		||||
			[self stopActivityWithCompletion:nil];
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)refreshAppRegistrationsPressed
 | 
			
		||||
{
 | 
			
		||||
	[self startActivity:@"Refreshing"];
 | 
			
		||||
 | 
			
		||||
	dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
 | 
			
		||||
	{
 | 
			
		||||
		spawnRoot(helperPath(), @[@"refresh"], nil, nil);
 | 
			
		||||
		respring();
 | 
			
		||||
 | 
			
		||||
		dispatch_async(dispatch_get_main_queue(), ^
 | 
			
		||||
		{
 | 
			
		||||
			[self stopActivityWithCompletion:nil];
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)uninstallPersistenceHelperPressed
 | 
			
		||||
{
 | 
			
		||||
	if([self isTrollStore])
 | 
			
		||||
	{
 | 
			
		||||
		spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], nil, nil);
 | 
			
		||||
		[self reloadSpecifiers];
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"Uninstalling the persistence helper will revert this app back to it's original state, you will however no longer be able to persistently refresh the TrollStore app registrations. Continue?" preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
	
 | 
			
		||||
		UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
 | 
			
		||||
		[uninstallWarningAlert addAction:cancelAction];
 | 
			
		||||
 | 
			
		||||
		UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
 | 
			
		||||
		{
 | 
			
		||||
			spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], nil, nil);
 | 
			
		||||
			exit(0);
 | 
			
		||||
		}];
 | 
			
		||||
		[uninstallWarningAlert addAction:continueAction];
 | 
			
		||||
 | 
			
		||||
		[self presentViewController:uninstallWarningAlert animated:YES completion:nil];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)handleUninstallation
 | 
			
		||||
{
 | 
			
		||||
	if([self isTrollStore])
 | 
			
		||||
	{
 | 
			
		||||
		exit(0);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		[self reloadSpecifiers];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)uninstallTrollStorePressed
 | 
			
		||||
{
 | 
			
		||||
	UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"About to uninstall TrollStore and all of the apps installed by it. Continue?" preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
	
 | 
			
		||||
	UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
 | 
			
		||||
	[uninstallWarningAlert addAction:cancelAction];
 | 
			
		||||
 | 
			
		||||
	UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
 | 
			
		||||
	{
 | 
			
		||||
		spawnRoot(helperPath(), @[@"uninstall-trollstore"], nil, nil);
 | 
			
		||||
		[self handleUninstallation];
 | 
			
		||||
	}];
 | 
			
		||||
	[uninstallWarningAlert addAction:continueAction];
 | 
			
		||||
 | 
			
		||||
	[self presentViewController:uninstallWarningAlert animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@ -1,9 +1,8 @@
 | 
			
		||||
#import <Preferences/PSListController.h>
 | 
			
		||||
#import <Preferences/PSSpecifier.h>
 | 
			
		||||
#import "TSListControllerShared.h"
 | 
			
		||||
 | 
			
		||||
@interface TSSettingsListController : PSListController
 | 
			
		||||
@interface TSSettingsListController : TSListControllerShared
 | 
			
		||||
{
 | 
			
		||||
    UIAlertController* _activityController;
 | 
			
		||||
    PSSpecifier* _installPersistenceHelperSpecifier;
 | 
			
		||||
    NSString* _newerVersion;
 | 
			
		||||
}
 | 
			
		||||
@end
 | 
			
		||||
@ -6,38 +6,24 @@
 | 
			
		||||
 | 
			
		||||
@implementation TSSettingsListController
 | 
			
		||||
 | 
			
		||||
- (void)loadView
 | 
			
		||||
- (void)viewDidLoad
 | 
			
		||||
{
 | 
			
		||||
	[super loadView];
 | 
			
		||||
	[super viewDidLoad];
 | 
			
		||||
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSpecifiers) name:UIApplicationWillEnterForegroundNotification object:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)startActivity:(NSString*)activity
 | 
			
		||||
{
 | 
			
		||||
	if(_activityController) return;
 | 
			
		||||
 | 
			
		||||
	_activityController = [UIAlertController alertControllerWithTitle:activity message:@"" preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
	UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)];
 | 
			
		||||
	activityIndicator.hidesWhenStopped = YES;
 | 
			
		||||
	activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium;
 | 
			
		||||
	[activityIndicator startAnimating];
 | 
			
		||||
	[_activityController.view addSubview:activityIndicator];
 | 
			
		||||
 | 
			
		||||
	[self presentViewController:_activityController animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)stopActivityWithCompletion:(void (^)(void))completion
 | 
			
		||||
{
 | 
			
		||||
	if(!_activityController) return;
 | 
			
		||||
 | 
			
		||||
	[_activityController dismissViewControllerAnimated:YES completion:^
 | 
			
		||||
	fetchLatestTrollStoreVersion(^(NSString* latestVersion)
 | 
			
		||||
	{
 | 
			
		||||
		_activityController = nil;
 | 
			
		||||
		if(completion)
 | 
			
		||||
		NSString* currentVersion = [self getTrollStoreVersion];
 | 
			
		||||
		NSComparisonResult result = [currentVersion compare:latestVersion options:NSNumericSearch];
 | 
			
		||||
		if(result == NSOrderedAscending)
 | 
			
		||||
		{
 | 
			
		||||
			completion();
 | 
			
		||||
			_newerVersion = latestVersion;
 | 
			
		||||
			dispatch_async(dispatch_get_main_queue(), ^
 | 
			
		||||
			{
 | 
			
		||||
				[self reloadSpecifiers];
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}];
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSMutableArray*)specifiers
 | 
			
		||||
@ -46,6 +32,25 @@
 | 
			
		||||
	{
 | 
			
		||||
		_specifiers = [NSMutableArray new];
 | 
			
		||||
 | 
			
		||||
		if(_newerVersion)
 | 
			
		||||
		{
 | 
			
		||||
			PSSpecifier* updateTrollStoreGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
 | 
			
		||||
			updateTrollStoreGroupSpecifier.name = @"Update Available";
 | 
			
		||||
			[_specifiers addObject:updateTrollStoreGroupSpecifier];
 | 
			
		||||
 | 
			
		||||
			PSSpecifier* updateTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:[NSString stringWithFormat:@"Update TrollStore to %@", _newerVersion]
 | 
			
		||||
										target:self
 | 
			
		||||
										set:nil
 | 
			
		||||
										get:nil
 | 
			
		||||
										detail:nil
 | 
			
		||||
										cell:PSButtonCell
 | 
			
		||||
										edit:nil];
 | 
			
		||||
			updateTrollStoreSpecifier.identifier = @"updateTrollStore";
 | 
			
		||||
			[updateTrollStoreSpecifier setProperty:@YES forKey:@"enabled"];
 | 
			
		||||
			updateTrollStoreSpecifier.buttonAction = @selector(updateTrollStorePressed);
 | 
			
		||||
			[_specifiers addObject:updateTrollStoreSpecifier];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		PSSpecifier* utilitiesGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
 | 
			
		||||
		utilitiesGroupSpecifier.name = @"Utilities";
 | 
			
		||||
		[utilitiesGroupSpecifier setProperty:@"If an app does not immediately appear after installation, respring here and it should appear afterwards." forKey:@"footerText"];
 | 
			
		||||
@ -192,7 +197,7 @@
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		PSSpecifier* otherGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
 | 
			
		||||
		[otherGroupSpecifier setProperty:[NSString stringWithFormat:@"TrollStore %@\n\n© 2022 Lars Fröder (opa334)\n\nCredits:\n@LinusHenze: CoreTrust bug\n@zhuowei: CoreTrust bug writeup and cert\n@lunotech11, @SerenaKit, @tylinux: Various contributions\n@ProcursusTeam: uicache and ldid build\n@cstar_ow: uicache\n@saurik: ldid", getTrollStoreVersion()] forKey:@"footerText"];
 | 
			
		||||
		[otherGroupSpecifier setProperty:[NSString stringWithFormat:@"TrollStore %@\n\n© 2022 Lars Fröder (opa334)\n\nCredits:\n@LinusHenze: CoreTrust bug\n@zhuowei: CoreTrust bug writeup and cert\n@lunotech11, @SerenaKit, @tylinux: Various contributions\n@ProcursusTeam: uicache and ldid build\n@cstar_ow: uicache\n@saurik: ldid", [self getTrollStoreVersion]] forKey:@"footerText"];
 | 
			
		||||
		[_specifiers addObject:otherGroupSpecifier];
 | 
			
		||||
 | 
			
		||||
		// Uninstall TrollStore
 | 
			
		||||
@ -208,6 +213,18 @@
 | 
			
		||||
		[uninstallTrollStoreSpecifier setProperty:NSClassFromString(@"PSDeleteButtonCell") forKey:@"cellClass"];
 | 
			
		||||
		uninstallTrollStoreSpecifier.buttonAction = @selector(uninstallTrollStorePressed);
 | 
			
		||||
		[_specifiers addObject:uninstallTrollStoreSpecifier];
 | 
			
		||||
 | 
			
		||||
		/*PSSpecifier* doTheDashSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Do the Dash"
 | 
			
		||||
										target:self
 | 
			
		||||
										set:nil
 | 
			
		||||
										get:nil
 | 
			
		||||
										detail:nil
 | 
			
		||||
										cell:PSButtonCell
 | 
			
		||||
										edit:nil];
 | 
			
		||||
		doTheDashSpecifier.identifier = @"doTheDash";
 | 
			
		||||
		[doTheDashSpecifier setProperty:@YES forKey:@"enabled"];
 | 
			
		||||
		uninstallTrollStoreSpecifier.buttonAction = @selector(doTheDashPressed);
 | 
			
		||||
		[_specifiers addObject:doTheDashSpecifier];*/
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[(UINavigationItem *)self.navigationItem setTitle:@"Settings"];
 | 
			
		||||
@ -219,21 +236,6 @@
 | 
			
		||||
	respring();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)rebuildIconCachePressed
 | 
			
		||||
{
 | 
			
		||||
	[self startActivity:@"Rebuilding Icon Cache"];
 | 
			
		||||
 | 
			
		||||
	dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
 | 
			
		||||
	{
 | 
			
		||||
		spawnRoot(helperPath(), @[@"refresh-all"], nil, nil);
 | 
			
		||||
 | 
			
		||||
		dispatch_async(dispatch_get_main_queue(), ^
 | 
			
		||||
		{
 | 
			
		||||
			[self stopActivityWithCompletion:nil];
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)installLdidPressed
 | 
			
		||||
{
 | 
			
		||||
	NSURL* ldidURL = [NSURL URLWithString:@"https://github.com/opa334/ldid/releases/download/v2.1.5-procursus5/ldid"];
 | 
			
		||||
@ -312,27 +314,9 @@
 | 
			
		||||
	[self presentViewController:selectAppAlert animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)uninstallPersistenceHelperPressed
 | 
			
		||||
- (void)doTheDashPressed
 | 
			
		||||
{
 | 
			
		||||
	spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], nil, nil);
 | 
			
		||||
	[self reloadSpecifiers];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)uninstallTrollStorePressed
 | 
			
		||||
{
 | 
			
		||||
	UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"About to uninstall TrollStore and all of the apps installed by it. Continue?" preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
	
 | 
			
		||||
	UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
 | 
			
		||||
	[uninstallWarningAlert addAction:cancelAction];
 | 
			
		||||
 | 
			
		||||
	UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
 | 
			
		||||
	{
 | 
			
		||||
		spawnRoot(helperPath(), @[@"uninstall-trollstore"], nil, nil);
 | 
			
		||||
		exit(0);
 | 
			
		||||
	}];
 | 
			
		||||
	[uninstallWarningAlert addAction:continueAction];
 | 
			
		||||
 | 
			
		||||
	[self presentViewController:uninstallWarningAlert animated:YES completion:nil];
 | 
			
		||||
	spawnRoot(helperPath(), @[@"dash"], nil, nil);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@ -4,4 +4,4 @@ extern NSString* helperPath(void);
 | 
			
		||||
extern void printMultilineNSString(NSString* stringToPrint);
 | 
			
		||||
extern int spawnRoot(NSString* path, NSArray* args, NSString** stdOut, NSString** stdErr);
 | 
			
		||||
extern void respring(void);
 | 
			
		||||
extern NSString* getTrollStoreVersion(void);
 | 
			
		||||
extern void fetchLatestTrollStoreVersion(void (^completionHandler)(NSString* latestVersion));
 | 
			
		||||
@ -186,7 +186,26 @@ void respring(void)
 | 
			
		||||
	exit(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NSString* getTrollStoreVersion(void)
 | 
			
		||||
void fetchLatestTrollStoreVersion(void (^completionHandler)(NSString* latestVersion))
 | 
			
		||||
{
 | 
			
		||||
	return [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
 | 
			
		||||
	NSURL* githubLatestAPIURL = [NSURL URLWithString:@"https://api.github.com/repos/opa334/TrollStore/releases/latest"];
 | 
			
		||||
 | 
			
		||||
	NSURLSessionDataTask* task = [NSURLSession.sharedSession dataTaskWithURL:githubLatestAPIURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
 | 
			
		||||
	{
 | 
			
		||||
		if(!error)
 | 
			
		||||
		{
 | 
			
		||||
			if ([response isKindOfClass:[NSHTTPURLResponse class]])
 | 
			
		||||
			{
 | 
			
		||||
				NSError *jsonError;
 | 
			
		||||
				NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
 | 
			
		||||
 | 
			
		||||
				if (!jsonError)
 | 
			
		||||
				{
 | 
			
		||||
					completionHandler(jsonResponse[@"tag_name"]);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}];
 | 
			
		||||
 | 
			
		||||
	[task resume];
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
Package: com.opa334.trollstore
 | 
			
		||||
Name: TrollStore
 | 
			
		||||
Version: 1.0.10
 | 
			
		||||
Version: 1.1
 | 
			
		||||
Architecture: iphoneos-arm
 | 
			
		||||
Description: An awesome application!
 | 
			
		||||
Maintainer: opa334
 | 
			
		||||
 | 
			
		||||
@ -48,18 +48,20 @@ COPYFILE_DISABLE=1 tar -czvf TrollStore.tar ./TrollStore.app
 | 
			
		||||
rm -rf ./TrollStore.app
 | 
			
		||||
cd -
 | 
			
		||||
 | 
			
		||||
# Step five: compile installer
 | 
			
		||||
xcodebuild -project ../Installer/TrollInstaller/TrollInstaller.xcodeproj -scheme TrollInstaller -destination generic/platform=iOS -archivePath ./out/Installer.xcarchive archive
 | 
			
		||||
if [[ $1 == "installer" ]]; then
 | 
			
		||||
    # Step five: compile installer
 | 
			
		||||
    xcodebuild -project ../Installer/TrollInstaller/TrollInstaller.xcodeproj -scheme TrollInstaller -destination generic/platform=iOS -archivePath ./out/Installer.xcarchive archive
 | 
			
		||||
 | 
			
		||||
if [[ -f "./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision" ]]; then
 | 
			
		||||
    rm ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision
 | 
			
		||||
    if [[ -f "./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision" ]]; then
 | 
			
		||||
        rm ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    ldid -s ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app
 | 
			
		||||
    mkdir ./out/Payload
 | 
			
		||||
    mv ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app ./out/Payload/TrollInstaller.app
 | 
			
		||||
    cd out
 | 
			
		||||
    zip -vr TrollInstaller.ipa Payload
 | 
			
		||||
    cd -
 | 
			
		||||
    rm -rf ./out/Payload
 | 
			
		||||
    rm -rf ./out/Installer.xcarchive
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
ldid -s ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app
 | 
			
		||||
mkdir ./out/Payload
 | 
			
		||||
mv ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app ./out/Payload/TrollInstaller.app
 | 
			
		||||
cd out
 | 
			
		||||
zip -vr TrollInstaller.ipa Payload
 | 
			
		||||
cd -
 | 
			
		||||
rm -rf ./out/Payload
 | 
			
		||||
rm -rf ./out/Installer.xcarchive
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user