├── SCFeaturesLite ├── precompiled │ └── SCFeaturesLite.dylib ├── SCFeaturesLite.m └── SCFeaturesLite.h ├── YTEnhancerLite ├── precompiled │ └── YTEnhancerLite.dylib ├── DownloadsTVC.h ├── DownloadsTVC.m ├── MBProgressHUD.h ├── YTEnhancerLite.m ├── YTEnhancerLite.h └── MBProgressHUD.m ├── INSEnhancerLite ├── precompiled │ └── INSEnhancerLite.dylib ├── INSEnhancerLite.m └── INSEnhancerLite.h ├── WAEnhancer9Lite ├── precompiled │ └── WAEnhancer9Lite.dylib ├── WAEnhancer9Lite.m └── WAEnhancer9Lite.h ├── LICENSE └── README.md /SCFeaturesLite/precompiled/SCFeaturesLite.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iMokhles/Tweaks-for-SideLoaded-Apps/HEAD/SCFeaturesLite/precompiled/SCFeaturesLite.dylib -------------------------------------------------------------------------------- /YTEnhancerLite/precompiled/YTEnhancerLite.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iMokhles/Tweaks-for-SideLoaded-Apps/HEAD/YTEnhancerLite/precompiled/YTEnhancerLite.dylib -------------------------------------------------------------------------------- /INSEnhancerLite/precompiled/INSEnhancerLite.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iMokhles/Tweaks-for-SideLoaded-Apps/HEAD/INSEnhancerLite/precompiled/INSEnhancerLite.dylib -------------------------------------------------------------------------------- /WAEnhancer9Lite/precompiled/WAEnhancer9Lite.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iMokhles/Tweaks-for-SideLoaded-Apps/HEAD/WAEnhancer9Lite/precompiled/WAEnhancer9Lite.dylib -------------------------------------------------------------------------------- /YTEnhancerLite/DownloadsTVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // DownloadsTVC.h 3 | // WAForIpad 4 | // 5 | // Created by iMokhles on 05/04/16. 6 | // Copyright © 2016 iMokhles. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DownloadsTVC : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Mokhlas Hussein 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tweaks for SideLoaded Apps 2 | 3 | non jailbroken device tweaks for ( WhatsApp - Snapchat - Instagram ) 4 | 5 | WhatsApp 6 | ------ 7 | 8 | * Freeze Last Seen 9 | * Disable Read Mark ( blue check ) 10 | * Support IPAD 11 | 12 | Snapchat 13 | ------ 14 | 15 | * Save Snaps ( images and videos ) 16 | 17 | Instagram 18 | ------ 19 | 20 | * save/share photos 21 | * save/share videos 22 | * share comments 23 | 24 | How to use 25 | ------ 26 | 27 | * load it inside the app binary using [optool](https://github.com/alexzielenski/optool) 28 | * sign the dylib using 29 | ``` 30 | codesign -fs "iPhone Developer: XXXXXX" 31 | ``` 32 | * copy the dylib inside the app bundle path 33 | * sign the app ipa file using [iOS App Signer](https://github.com/DanTheMan827/ios-app-signer) or [AppSignerCMD](https://github.com/iMokhles/AppSignerCMD) 34 | 35 | * after that install the app using IPAInstaller [Windows](https://github.com/iMokhles/IPAInstaller-Windows/releases/download/1.1/IPAInstaller.exe) - [Mac](https://github.com/iMokhles/IPAInstaller-Mac/releases/download/1.0/IPAInstaller-1.0.zip) 36 | 37 | 38 | #MIT License 39 | 40 | Copyright (c) 2016 iMokhles (Mokhlas Hussien). All rights reserved. 41 | 42 | Permission is hereby granted, free of charge, to any person obtaining a 43 | copy of this software and associated documentation files (the "Software"), 44 | to deal in the Software without restriction, including 45 | without limitation the rights to use, copy, modify, merge, publish, 46 | distribute, sublicense, and/or sell copies of the Software, and to 47 | permit persons to whom the Software is furnished to do so, subject to 48 | the following conditions: 49 | 50 | The above copyright notice and this permission notice shall be included 51 | in all copies or substantial portions of the Software. 52 | 53 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 54 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 55 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 56 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 57 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 58 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 59 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /WAEnhancer9Lite/WAEnhancer9Lite.m: -------------------------------------------------------------------------------- 1 | // 2 | // WAEnhancer9Lite.m 3 | // WAEnhancer9Lite 4 | // 5 | // Created by iMokhles on 04/04/16. 6 | // Copyright © 2016 iMokhles. All rights reserved. 7 | // 8 | 9 | #import "WAEnhancer9Lite.h" 10 | 11 | UISwitch *switchview1; 12 | 13 | BOOL GetBool(NSString *key) 14 | { 15 | return [[[NSUserDefaults standardUserDefaults] objectForKey:key] boolValue]; 16 | } 17 | 18 | #pragma mark - iPAD Support 19 | hook(UIDevice) 20 | - (BOOL)wa_isDeviceSupported { 21 | return YES; 22 | } 23 | - (BOOL)wa_shouldBeAskedToReview { // stop asking for review 24 | return NO; 25 | } 26 | - (BOOL)wa_isDeviceSuspicious { 27 | return NO; 28 | } 29 | endhook 30 | 31 | #pragma mark - jailbreak detection 32 | hook(WASharedAppData) 33 | + (void)showLocalNotificationForJailbrokenPhoneAndTerminate { // LOL in case any issue ( i don't trust WhatsApp devs ) :P 34 | return; 35 | } 36 | endhook 37 | 38 | #pragma mark - Last Seend 39 | 40 | hook(XMPPConnection) 41 | - (void)sendPresenceWithNickname:(id)arg1 { 42 | if (GetBool(@"lastseen_bool")) { 43 | return; 44 | } else { 45 | return _orig(void, arg1); 46 | } 47 | } 48 | - (void)sendReadReceiptsForChatMessages:(id)arg1 { 49 | if (GetBool(@"readmark_bool")) { 50 | return; 51 | } else { 52 | _orig(void, arg1); 53 | } 54 | } 55 | 56 | - (void)sendPlayedReceiptForMessage:(id)arg1 { 57 | if (GetBool(@"readmark_bool")) { 58 | return; 59 | } else { 60 | _orig(void, arg1); 61 | } 62 | } 63 | endhook 64 | 65 | #pragma mark - WAEnhancer Settings 66 | 67 | hook(WAStaticTableViewController) 68 | 69 | - (WATableSection *)addSectionAtTop { 70 | WATableSection *waeTableSection = [[objc_getClass("WATableSection") alloc] init]; 71 | NSMutableArray *sectionsStatic = [self valueForKey:@"_sections"]; 72 | [sectionsStatic insertObject:waeTableSection atIndex:1]; 73 | return waeTableSection; 74 | } 75 | endhook 76 | 77 | 78 | hook(WASettingsViewController) 79 | - (void)setupTableView { 80 | 81 | _orig(void); 82 | WATableSection *waeTabSection = [(WASettingsViewController *)self addSectionAtTop]; 83 | 84 | waeTabSection.headerText = @"WAEnhancer9Lite"; 85 | waeTabSection.footerText = @"WhatsApp tweak without jailbreak by ( iMokhles )"; 86 | 87 | NSString *freezeLastSeen = @"Freeze LastSeen"; 88 | WATableRow *advancedRow = [objc_getClass("WATableRow") new]; 89 | [advancedRow setHandler:^{ 90 | [(WASettingsViewController *)self deselectActiveCell]; 91 | 92 | }]; 93 | UITableViewCell *freezeLastSeenCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"freezeLastSeenCell"]; 94 | freezeLastSeenCell.selectionStyle = UITableViewCellSelectionStyleNone; 95 | switchview1 = [UISwitch new]; 96 | [switchview1 setOn:[[[NSUserDefaults standardUserDefaults] objectForKey:@"lastseen_bool"] boolValue] animated:NO]; 97 | switchview1.tag = 8756; 98 | [switchview1 addTarget:self action:@selector(_didToggleEnableDisable:) forControlEvents:UIControlEventValueChanged]; 99 | freezeLastSeenCell.accessoryView = switchview1; 100 | [advancedRow setCell:freezeLastSeenCell]; 101 | [freezeLastSeenCell.textLabel setText:freezeLastSeen]; 102 | [freezeLastSeenCell.textLabel setTextAlignment:NSTextAlignmentLeft]; 103 | [waeTabSection addRow:advancedRow]; 104 | 105 | NSString *disableReadMark = @"Disable ReadMark"; 106 | WATableRow *disableReadMarkRow = [objc_getClass("WATableRow") new]; 107 | [disableReadMarkRow setHandler:^{ 108 | [(WASettingsViewController *)self deselectActiveCell]; 109 | 110 | }]; 111 | UITableViewCell *disableReadMarkCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"disableReadMarkCell"]; 112 | disableReadMarkCell.selectionStyle = UITableViewCellSelectionStyleNone; 113 | switchview1 = [UISwitch new]; 114 | [switchview1 setOn:[[[NSUserDefaults standardUserDefaults] objectForKey:@"readmark_bool"] boolValue] animated:NO]; 115 | switchview1.tag = 8757; 116 | [switchview1 addTarget:self action:@selector(_didToggleEnableDisable:) forControlEvents:UIControlEventValueChanged]; 117 | disableReadMarkCell.accessoryView = switchview1; 118 | [disableReadMarkRow setCell:disableReadMarkCell]; 119 | [disableReadMarkCell.textLabel setText:disableReadMark]; 120 | [disableReadMarkCell.textLabel setTextAlignment:NSTextAlignmentLeft]; 121 | [waeTabSection addRow:disableReadMarkRow]; 122 | 123 | } 124 | 125 | - (void)_didToggleEnableDisable:(UISwitch *)sw { 126 | if (sw.tag == 8756) { 127 | [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:sw.on] forKey:@"lastseen_bool"]; 128 | } else if (sw.tag == 8757) { 129 | [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:sw.on] forKey:@"readmark_bool"]; 130 | } 131 | [[NSUserDefaults standardUserDefaults] synchronize]; 132 | } 133 | 134 | endhook -------------------------------------------------------------------------------- /YTEnhancerLite/DownloadsTVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // DownloadsTVC.m 3 | // WAForIpad 4 | // 5 | // Created by iMokhles on 05/04/16. 6 | // Copyright © 2016 iMokhles. All rights reserved. 7 | // 8 | 9 | #import "DownloadsTVC.h" 10 | #import "TotoaShopHelper.h" 11 | #import 12 | #import "UIImageView+WebCache.h" 13 | 14 | @interface DownloadsTVC () { 15 | NSUserDefaults *userDefaults; 16 | NSArray *itemsArray; 17 | NSString *staticPath; 18 | } 19 | 20 | @end 21 | 22 | @implementation DownloadsTVC 23 | 24 | - (id)initWithStyle:(UITableViewStyle)style 25 | { 26 | self = [super initWithStyle:style]; 27 | if (self) { 28 | // Custom initialization 29 | } 30 | return self; 31 | } 32 | 33 | - (void)viewWillAppear:(BOOL)animated { 34 | [super viewWillAppear:animated]; 35 | 36 | userDefaults = [NSUserDefaults standardUserDefaults]; 37 | itemsArray = [userDefaults objectForKey:@"fileInfoArray"]; 38 | 39 | } 40 | - (void)viewDidLoad { 41 | [super viewDidLoad]; 42 | 43 | self.title = @"Downloads"; 44 | UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(closeThisPage)]; 45 | [self.navigationItem setRightBarButtonItem:doneButton]; 46 | 47 | // Uncomment the following line to preserve selection between presentations. 48 | // self.clearsSelectionOnViewWillAppear = NO; 49 | 50 | // Uncomment the following line to display an Edit button in the navigation bar for this view controller. 51 | // self.navigationItem.rightBarButtonItem = self.editButtonItem; 52 | } 53 | 54 | - (void)closeThisPage { 55 | [self dismissViewControllerAnimated:YES completion:^{ 56 | 57 | }]; 58 | } 59 | 60 | - (void)didReceiveMemoryWarning { 61 | [super didReceiveMemoryWarning]; 62 | // Dispose of any resources that can be recreated. 63 | } 64 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 65 | return 1; 66 | } 67 | 68 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 69 | return itemsArray.count; 70 | } 71 | 72 | 73 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 74 | static NSString *CellIdentifier = @"Cell"; 75 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 76 | 77 | if (cell == nil) { 78 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 79 | } 80 | NSDictionary *videoInfo = itemsArray[indexPath.row]; 81 | 82 | NSURL *urlImg = [NSURL URLWithString:videoInfo[@"mediumThumbnailURL"]]; 83 | NSNumber *audioNM = videoInfo[@"isAudio"]; 84 | BOOL isAudio = [audioNM boolValue]; 85 | 86 | [cell.imageView sd_setImageWithURL:urlImg]; 87 | cell.textLabel.text = videoInfo[@""]; 88 | 89 | if (isAudio) { 90 | cell.detailTextLabel.text = [NSString stringWithFormat:@"Audio - %@", videoInfo[@"videoDuration"]]; 91 | } else { 92 | cell.detailTextLabel.text = [NSString stringWithFormat:@"Video - %@", videoInfo[@"videoDuration"]]; 93 | } 94 | 95 | // Configure the cell... 96 | 97 | return cell; 98 | } 99 | 100 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 101 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 102 | NSDictionary *fileInfo = itemsArray[indexPath.row]; 103 | NSString *filePath; 104 | NSNumber *audioNM = fileInfo[@"isAudio"]; 105 | BOOL isAudio = [audioNM boolValue]; 106 | if (isAudio == NO) { 107 | filePath = [[TotoaShopHelper getDownloadsPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"mp4/%@-%@.mp4", fileInfo[@"videoTitle"], fileInfo[@"videoID"]]]; 108 | } else { 109 | filePath = [[TotoaShopHelper getDownloadsPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"m4a/%@-%@.m4a", fileInfo[@"videoTitle"], fileInfo[@"videoID"]]]; 110 | } 111 | 112 | staticPath = filePath; 113 | QLPreviewController *preview = [[QLPreviewController alloc] init]; 114 | preview.dataSource = self; 115 | 116 | [self.navigationController pushViewController:preview animated:YES]; 117 | } 118 | 119 | #pragma mark - QuickLook 120 | 121 | - (BOOL)previewController:(QLPreviewController *)controller shouldOpenURL:(NSURL *)url forPreviewItem:(id )item { 122 | 123 | return YES; 124 | } 125 | - (NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller { 126 | return 1; 127 | } 128 | 129 | - (id ) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index { 130 | return [NSURL fileURLWithPath:staticPath]; 131 | } 132 | 133 | 134 | // Override to support conditional editing of the table view. 135 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 136 | // Return NO if you do not want the specified item to be editable. 137 | return YES; 138 | } 139 | 140 | 141 | 142 | // Override to support editing the table view. 143 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 144 | NSDictionary *fileInfo = itemsArray[indexPath.row]; 145 | NSString *filePath; 146 | 147 | NSNumber *audioNM = fileInfo[@"isAudio"]; 148 | BOOL isAudio = [audioNM boolValue]; 149 | 150 | if (isAudio == YES) { 151 | filePath = [[TotoaShopHelper getDownloadsPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"mp4/%@-%@.mp4", fileInfo[@"videoTitle"], fileInfo[@"videoID"]]]; 152 | } else { 153 | filePath = [[TotoaShopHelper getDownloadsPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"m4a/%@-%@.m4a", fileInfo[@"videoTitle"], fileInfo[@"videoID"]]]; 154 | } 155 | if (editingStyle == UITableViewCellEditingStyleDelete) { 156 | // Delete the row from the data source 157 | [[NSFileManager defaultManager] removeItemAtPath:filePath error:NULL]; 158 | NSMutableArray *loadDefects = [itemsArray mutableCopy]; 159 | [loadDefects removeObjectAtIndex:indexPath.row]; 160 | [userDefaults setObject:loadDefects forKey:@"fileInfoArray"]; 161 | [userDefaults synchronize]; 162 | 163 | [[itemsArray mutableCopy] removeAllObjects]; 164 | itemsArray = [userDefaults objectForKey:@"fileInfoArray"]; 165 | [self.tableView reloadData]; 166 | //[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; 167 | } 168 | } 169 | 170 | 171 | /* 172 | // Override to support rearranging the table view. 173 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { 174 | } 175 | */ 176 | 177 | /* 178 | // Override to support conditional rearranging of the table view. 179 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 180 | // Return NO if you do not want the item to be re-orderable. 181 | return YES; 182 | } 183 | */ 184 | 185 | /* 186 | #pragma mark - Navigation 187 | 188 | // In a storyboard-based application, you will often want to do a little preparation before navigation 189 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 190 | // Get the new view controller using [segue destinationViewController]. 191 | // Pass the selected object to the new view controller. 192 | } 193 | */ 194 | 195 | @end 196 | -------------------------------------------------------------------------------- /SCFeaturesLite/SCFeaturesLite.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCFeaturesLite.m 3 | // SCFeaturesLite 4 | // 5 | // Created by iMokhles on 04/04/16. 6 | // Copyright © 2016 iMokhles. All rights reserved. 7 | // 8 | 9 | #import "SCFeaturesLite.h" 10 | 11 | static UIButton *saveSnapButton; 12 | static AVPlayer *videoPlayer = nil; 13 | static BOOL isImageMedia = NO; 14 | 15 | static AVCameraViewController *middleViewController() { 16 | UINavigationController *viewController = (UINavigationController *)[[UIApplication sharedApplication] windows][0].rootViewController; 17 | MainViewController *mainVC = (MainViewController *)viewController.topViewController; 18 | 19 | if (![mainVC respondsToSelector:@selector(middleVC)]) { 20 | return (AVCameraViewController *)mainVC; 21 | } 22 | return mainVC.middleVC; 23 | } 24 | 25 | static MainViewController *mainViewC() { 26 | UINavigationController *viewController = (UINavigationController *)[[UIApplication sharedApplication] windows][0].rootViewController; 27 | MainViewController *mainVC = (MainViewController *)viewController.topViewController; 28 | 29 | return mainVC; 30 | } 31 | 32 | @implementation SCFeaturesLite 33 | + (instancetype)shareFeatures { 34 | static SCFeaturesLite *sharedInstance = nil; 35 | static dispatch_once_t onceToken; 36 | 37 | dispatch_once(&onceToken, ^{ 38 | sharedInstance = [[SCFeaturesLite alloc] init]; 39 | }); 40 | 41 | return sharedInstance; 42 | } 43 | 44 | - (id)init { 45 | if (self == [super init]) { 46 | 47 | } 48 | return self; 49 | } 50 | 51 | -(void)shake: (UIView*)theView { 52 | CAKeyframeAnimation * anim = [ CAKeyframeAnimation animationWithKeyPath:@"transform" ] ; 53 | anim.values = @[ [ NSValue valueWithCATransform3D:CATransform3DMakeTranslation(-5.0f, 0.0f, 0.0f) ], [ NSValue valueWithCATransform3D:CATransform3DMakeTranslation(5.0f, 0.0f, 0.0f) ] ] ; 54 | anim.autoreverses = YES ; 55 | anim.repeatCount = 2.0f ; 56 | anim.duration = 0.07f ; 57 | 58 | [ theView.layer addAnimation:anim forKey:nil ] ; 59 | } 60 | 61 | @end 62 | 63 | hook(SCChatViewController) 64 | -(void)tapToSkip:(UIGestureRecognizer *)tap { 65 | CGPoint coords = [tap locationInView:tap.view]; 66 | 67 | if (coords.x < [UIScreen mainScreen].bounds.size.width - 100 || coords.y < [UIScreen mainScreen].bounds.size.height - 100 ) { 68 | 69 | } 70 | _orig(void, tap); 71 | } 72 | endhook 73 | 74 | 75 | hook(SCFeedViewController) 76 | -(void)tapToSkip:(UIGestureRecognizer *)tap { 77 | CGPoint coords = [tap locationInView:tap.view]; 78 | 79 | if (coords.x < [UIScreen mainScreen].bounds.size.width - 100 || coords.y < [UIScreen mainScreen].bounds.size.height - 100 ) { 80 | 81 | } 82 | _orig(void, tap); 83 | } 84 | endhook 85 | 86 | 87 | hook(SCViewingStoryViewController) 88 | -(void)tapToSkip:(UIGestureRecognizer *)tap { 89 | CGPoint coords = [tap locationInView:tap.view]; 90 | 91 | if (coords.x < [UIScreen mainScreen].bounds.size.width - 100 || coords.y < [UIScreen mainScreen].bounds.size.height - 100 ) { 92 | 93 | } 94 | 95 | _orig(void, tap); 96 | } 97 | endhook 98 | 99 | hook(SCMediaView) 100 | - (void)playPlayer:(AVPlayer *)arg1 { 101 | videoPlayer = arg1; 102 | isImageMedia = NO; 103 | [self addSaveVideoAction]; 104 | _orig(void, arg1); 105 | } 106 | - (void)addSaveVideoAction { 107 | isImageMedia = NO; 108 | [saveSnapButton removeTarget:nil action:NULL forControlEvents:UIControlEventTouchUpInside]; 109 | [saveSnapButton addTarget:videoPlayer action:@selector(saveVideoSnapButtonPress:) forControlEvents:UIControlEventTouchUpInside]; 110 | } 111 | - (void)finishedPlayingMedia:(id)arg1 { 112 | [saveSnapButton removeFromSuperview]; 113 | _orig(void, arg1); 114 | if ([(SCMediaView *)self superview] != nil) { 115 | [[(SCMediaView *)self window] addSubview:saveSnapButton]; 116 | [[(SCMediaView *)self window] bringSubviewToFront:saveSnapButton]; 117 | } 118 | } 119 | - (void)hideMedia { 120 | [saveSnapButton removeFromSuperview]; 121 | _orig(void); 122 | } 123 | - (void)didMoveToWindow { 124 | _orig(void); 125 | if (![saveSnapButton.superview isEqual:[(SCMediaView *)self window]]) { 126 | saveSnapButton = [UIButton buttonWithType:UIButtonTypeCustom]; 127 | [saveSnapButton setFrame:CGRectMake([UIScreen mainScreen].bounds.size.width - 100, [UIScreen mainScreen].bounds.size.height - 100, 60, 60)]; 128 | [saveSnapButton setImage:[UIImage imageNamed:@"save_button"] forState:UIControlStateNormal]; 129 | [saveSnapButton setImageEdgeInsets:UIEdgeInsetsMake(19, 0, 19, 0)]; 130 | saveSnapButton.layer.cornerRadius = 60/2.0f; 131 | saveSnapButton.layer.borderColor=[UIColor whiteColor].CGColor; 132 | saveSnapButton.layer.borderWidth=2.0f; 133 | if ([(SCMediaView *)self superview] != nil) { 134 | [[(SCMediaView *)self window] addSubview:saveSnapButton]; 135 | [[(SCMediaView *)self window] bringSubviewToFront:saveSnapButton]; 136 | } 137 | 138 | for (int i = 0; i < [(SCMediaView *)self playerViews].count; i++) { 139 | SCPlayerView *player1 = [[(SCMediaView *)self playerViews] objectAtIndex:0]; 140 | SCPlayerView *player2 = [[(SCMediaView *)self playerViews] objectAtIndex:1]; 141 | if ([player1 isHidden] && [player2 isHidden]) { 142 | isImageMedia = YES; 143 | } else if (![player1 isHidden] && [player2 isHidden]) { 144 | isImageMedia = NO; 145 | } else if ([player1 isHidden] && ![player2 isHidden]) { 146 | isImageMedia = NO; 147 | } 148 | 149 | } 150 | if (isImageMedia){ 151 | // image 152 | [saveSnapButton removeTarget:nil action:NULL forControlEvents:UIControlEventTouchUpInside]; 153 | [saveSnapButton addTarget:self action:@selector(saveImageSnapButtonPress:) forControlEvents:UIControlEventTouchUpInside]; 154 | } else { 155 | [self addSaveVideoAction]; 156 | } 157 | } 158 | [(SCMediaView *)self setUserInteractionEnabled:YES]; 159 | 160 | } 161 | -(void) saveImageSnapButtonPress:(id)sender 162 | { 163 | [[SCFeaturesLite shareFeatures] shake:sender]; 164 | isImageMedia = NO; 165 | // Save the snap. 166 | if ([[(SCMediaView *)self imageView] image] != nil) { 167 | void (^fillerBlock)(void) = ^{ 168 | Alert *alert = [[Alert alloc] initWithTitle:@"Saved" duration:0.3 completion:^{ 169 | //Custom code here after Alert disappears 170 | }]; 171 | alert.alertType = AlertTypeSuccess; 172 | [alert showAlert]; 173 | }; 174 | 175 | [[objc_getClass("SCSnapSaver") shared] saveSnapImageToSnapAlbum:[[(SCMediaView *)self imageView] image] completionBlock:fillerBlock]; 176 | 177 | } 178 | 179 | } 180 | endhook 181 | 182 | hook(AVPlayer) 183 | -(void) saveVideoSnapButtonPress:(id)sender { 184 | [[SCFeaturesLite shareFeatures] shake:sender]; 185 | NSLog(@"\n\n\n\n Save Video"); 186 | AVAsset *currentPlayerAsset = [(AVPlayer *)self currentItem].asset; 187 | NSURL *videoURL = [(AVURLAsset *)currentPlayerAsset URL]; 188 | NSLog(@"%@", videoURL); 189 | if(UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(videoURL.path)) { 190 | UISaveVideoAtPathToSavedPhotosAlbum(videoURL.path, self, @selector(video:didFinishSavingWithError:contextInfo:), nil); 191 | 192 | } 193 | } 194 | - (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { 195 | if (error == nil) { 196 | Alert *alert = [[Alert alloc] initWithTitle:@"Saved" duration:0.3 completion:^{ 197 | //Custom code here after Alert disappears 198 | }]; 199 | alert.alertType = AlertTypeSuccess; 200 | [alert showAlert]; 201 | } else { 202 | Alert *alert = [[Alert alloc] initWithTitle:@"Failed" duration:0.3 completion:^{ 203 | //Custom code here after Alert disappears 204 | }]; 205 | alert.alertType = AlertTypeError; 206 | [alert showAlert]; 207 | } 208 | videoPlayer = nil; 209 | } 210 | endhook 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /INSEnhancerLite/INSEnhancerLite.m: -------------------------------------------------------------------------------- 1 | // 2 | // INSEnhancerLite.m 3 | // INSEnhancerLite 4 | // 5 | // Created by iMokhles on 04/04/16. 6 | // Copyright © 2016 iMokhles. All rights reserved. 7 | // 8 | 9 | #import "INSEnhancerLite.h" 10 | 11 | static NSString *staticPath = nil; 12 | static UIImage *staticImage = nil; 13 | static BOOL isOldSave = NO; 14 | 15 | @interface INSEnhancerLite () 16 | @end 17 | 18 | @implementation INSEnhancerLite 19 | + (instancetype)shareFeatures { 20 | static INSEnhancerLite *sharedInstance = nil; 21 | static dispatch_once_t onceToken; 22 | 23 | dispatch_once(&onceToken, ^{ 24 | sharedInstance = [[INSEnhancerLite alloc] init]; 25 | }); 26 | 27 | return sharedInstance; 28 | } 29 | 30 | - (id)init { 31 | if (self == [super init]) { 32 | 33 | } 34 | return self; 35 | } 36 | 37 | + (NSString *)insta_DocumentsPath { 38 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 39 | NSString *documentsDirectory = [paths objectAtIndex:0]; 40 | return documentsDirectory; 41 | } 42 | 43 | + (void)addNotificationFromObserver:(id)target withName:(NSString *)notiName andSelector:(SEL)aSelector { 44 | [[NSNotificationCenter defaultCenter] addObserver:target selector:aSelector name:notiName object:nil]; 45 | } 46 | + (void)postNotificationWithName:(NSString *)notiName andObject:(id)object { 47 | NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; 48 | [nc postNotificationName:notiName object:object userInfo:nil]; 49 | } 50 | 51 | + (UIWindow *)mainINGEnhancerWindow { 52 | return [[UIApplication sharedApplication] windows][0]; 53 | } 54 | 55 | + (UIViewController *)mainINGEnhancerViewController { 56 | return self.mainINGEnhancerWindow.rootViewController; 57 | } 58 | 59 | + (NSURL *)urlFromVersionArray:(NSArray *)versions { 60 | NSURL *url; 61 | CGFloat hightResolution = 0.0; 62 | for (NSDictionary *versionDict in versions) { 63 | CGFloat height = [versionDict[@"height"] floatValue]; 64 | CGFloat width = [versionDict[@"width"] floatValue]; 65 | CGFloat resolution = height * width; 66 | 67 | if (resolution > hightResolution) { 68 | hightResolution = resolution; 69 | url = [NSURL URLWithString:versionDict[@"url"]]; 70 | } 71 | } 72 | return url; 73 | } 74 | 75 | + (UIView *)mainView { 76 | UIView *view; 77 | if (!view) { 78 | UIWindow *keyWindow = [UIWindow keyWindow]; 79 | if ([UIWindow respondsToSelector:@selector(rootViewController)]) 80 | view = [[keyWindow rootViewController] view]; 81 | if (!view) 82 | view = [keyWindow.subviews lastObject]; 83 | } 84 | return view; 85 | } 86 | 87 | // INGEnhancer methods 88 | + (void)ingen_shareText:(NSString *)textToShare { 89 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 90 | UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[textToShare] applicationActivities:@[]]; 91 | if (IS_IPAD) { 92 | UIPopoverController *activityPopoverController = [[UIPopoverController alloc] initWithContentViewController:activityViewController]; 93 | [activityPopoverController presentPopoverFromRect:CGRectMake([self mainView].bounds.size.width / 2.0, [self mainView].bounds.size.height / 2.0, 1.0, 1.0) inView:[self mainView] permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; 94 | } else { 95 | dispatch_async(dispatch_get_main_queue(), ^{ 96 | [[self mainINGEnhancerViewController] presentViewController:activityViewController animated:YES completion:NULL]; 97 | }); 98 | } 99 | 100 | }); 101 | } 102 | + (void)ingen_shareFile:(NSString *)fileToShare { 103 | staticPath = fileToShare; 104 | QLPreviewController *preview = [[QLPreviewController alloc] init]; 105 | preview.dataSource = [INSEnhancerLite shareFeatures]; 106 | 107 | [[self mainINGEnhancerViewController] presentViewController:preview animated:YES completion:^{ 108 | 109 | }]; 110 | } 111 | 112 | + (void)ingen_shareImage:(UIImage *)image { 113 | staticImage = image; 114 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 115 | NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Image.png"]; 116 | // Save image. 117 | [UIImagePNGRepresentation(staticImage) writeToFile:filePath atomically:YES]; 118 | staticPath = filePath; 119 | QLPreviewController *preview = [[QLPreviewController alloc] init]; 120 | preview.dataSource = [INSEnhancerLite shareFeatures]; 121 | 122 | [[self mainINGEnhancerViewController] presentViewController:preview animated:YES completion:^{ 123 | 124 | }]; 125 | } 126 | 127 | #pragma mark - QuickLook 128 | 129 | - (BOOL)previewController:(QLPreviewController *)controller shouldOpenURL:(NSURL *)url forPreviewItem:(id )item { 130 | 131 | return YES; 132 | } 133 | - (NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller { 134 | return 1; 135 | } 136 | - (id ) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index { 137 | 138 | return [NSURL fileURLWithPath:staticPath]; 139 | } 140 | 141 | + (NSBundle *)ingen_bundle { 142 | return [NSBundle mainBundle]; 143 | } 144 | @end 145 | 146 | hook(IGCoreTextView) 147 | - (void)handleLongTap { 148 | // i don't like this feature so i replaced it easily :P 149 | [INSEnhancerLite ingen_shareText:[(IGCoreTextView *)self styledString].attributedString.string]; 150 | } 151 | endhook 152 | 153 | hook(IGFeedItemPhotoCell) 154 | - (void)layoutSubviews { 155 | [INSEnhancerLite addNotificationFromObserver:self withName:@"INGShareImageNotification" andSelector:@selector(showShareImageSheet:)]; 156 | _orig(void); 157 | } 158 | 159 | - (void)showShareImageSheet:(NSNotification *)notification { 160 | NSURL *imageURL = (NSURL *)[notification object]; 161 | NSData *urlData = [NSData dataWithContentsOfURL:imageURL]; 162 | UIImage *imageToShare = [UIImage imageWithData:urlData]; 163 | NSData *pngData = UIImagePNGRepresentation(imageToShare); 164 | 165 | if (pngData) { 166 | NSString *filePath = [NSString stringWithFormat:@"%@/%@", [INSEnhancerLite insta_DocumentsPath], @"image.png"]; 167 | [pngData writeToFile:filePath atomically:YES]; 168 | double delayInSeconds = 0.5; 169 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 170 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 171 | [INSEnhancerLite ingen_shareImage:imageToShare]; 172 | }); 173 | } 174 | 175 | } 176 | endhook 177 | 178 | hook(IGFeedItemVideoCell) 179 | - (void)layoutSubviews { 180 | [INSEnhancerLite addNotificationFromObserver:self withName:@"INGShareVideoNotification" andSelector:@selector(showShareVideoSheet:)]; 181 | _orig(void); 182 | } 183 | 184 | - (void)showShareVideoSheet:(NSNotification *)notification { 185 | NSURL *videoURL = (NSURL *)[notification object]; 186 | NSData *videoData = [NSData dataWithContentsOfURL:videoURL]; 187 | if (videoData) { 188 | NSString *filePath = [NSString stringWithFormat:@"%@/%@", [INSEnhancerLite insta_DocumentsPath], @"video.mp4"]; 189 | [videoData writeToFile:filePath atomically:YES]; 190 | double delayInSeconds = 0.5; 191 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 192 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 193 | [INSEnhancerLite ingen_shareFile:filePath]; 194 | }); 195 | } 196 | 197 | } 198 | endhook 199 | 200 | hook(IGFeedItemHeader) 201 | - (void)onChevronTapped:(id)arg1 { 202 | if (!isOldSave) { 203 | NSString *chooseTitle = [NSString translateToAR:@"إختار مشاركة لفتحها" toCA:nil toCS:nil toDA:nil toDE:nil toEL:nil toEN:@"Choose option" toEN_AU:nil toEN_GB:nil toES:nil toES_MX:nil toFI:nil toFR:nil toFR_CA:nil toHE:nil toHI:nil toHR:nil toHU:nil toID:nil toIT:nil toJA:nil toKO:nil toMS:nil toNL:nil toNO:nil toPL:nil toPT:nil toPT_PT:nil toRO:nil toRU:nil toSK:nil toSV:nil toTH:nil toTR:nil toUK:nil toVI:nil toZH_CN:nil toZH_HK:nil toZH_TW:nil]; 204 | 205 | NSString *tweakSettings = [NSString translateToAR:@"مشاركة الاداة" toCA:nil toCS:nil toDA:nil toDE:nil toEL:nil toEN:@"Tweak Share" toEN_AU:nil toEN_GB:nil toES:nil toES_MX:nil toFI:nil toFR:nil toFR_CA:nil toHE:nil toHI:nil toHR:nil toHU:nil toID:nil toIT:nil toJA:nil toKO:nil toMS:nil toNL:nil toNO:nil toPL:nil toPT:nil toPT_PT:nil toRO:nil toRU:nil toSK:nil toSV:nil toTH:nil toTR:nil toUK:nil toVI:nil toZH_CN:nil toZH_HK:nil toZH_TW:nil]; 206 | 207 | NSString *appSettings = [NSString translateToAR:@"مشاركة التطبيق" toCA:nil toCS:nil toDA:nil toDE:nil toEL:nil toEN:@"App Share" toEN_AU:nil toEN_GB:nil toES:nil toES_MX:nil toFI:nil toFR:nil toFR_CA:nil toHE:nil toHI:nil toHR:nil toHU:nil toID:nil toIT:nil toJA:nil toKO:nil toMS:nil toNL:nil toNO:nil toPL:nil toPT:nil toPT_PT:nil toRO:nil toRU:nil toSK:nil toSV:nil toTH:nil toTR:nil toUK:nil toVI:nil toZH_CN:nil toZH_HK:nil toZH_TW:nil]; 208 | 209 | 210 | [UIAlertView showWithTitle:@"INSEnhancer" message:chooseTitle cancelButtonTitle:tweakSettings otherButtonTitles:@[appSettings] tapBlock:^(UIAlertView * _Nonnull alertView, NSInteger buttonIndex) { 211 | if ([[alertView buttonTitleAtIndex:buttonIndex] isEqualToString:appSettings]) { 212 | isOldSave = YES; 213 | [self onChevronTapped:nil]; 214 | } else if ([[alertView buttonTitleAtIndex:buttonIndex] isEqualToString:tweakSettings]) { 215 | isOldSave = NO; 216 | [self shareButtonPressed]; 217 | } 218 | }]; 219 | } else { 220 | isOldSave = NO; 221 | _orig(void); 222 | } 223 | } 224 | 225 | - (void)shareButtonPressed { 226 | int mediaType = [[(IGFeedItemHeader *)self viewModel] feedItem].mediaType; 227 | if (mediaType == 1) { 228 | // Shre image 229 | NSURL *imageURL = [INSEnhancerLite urlFromVersionArray:[[(IGFeedItemHeader *)self viewModel] feedItem].photo.imageVersions]; 230 | [INSEnhancerLite postNotificationWithName:@"INGShareImageNotification" andObject:imageURL]; 231 | } else { 232 | if (mediaType == 2) { 233 | // Share Video 234 | NSURL *videoURL = [INSEnhancerLite urlFromVersionArray:[[(IGFeedItemHeader *)self viewModel] feedItem].video.videoVersions]; 235 | [INSEnhancerLite postNotificationWithName:@"INGShareVideoNotification" andObject:videoURL]; 236 | } 237 | } 238 | } 239 | endhook 240 | 241 | 242 | 243 | 244 | 245 | 246 | -------------------------------------------------------------------------------- /SCFeaturesLite/SCFeaturesLite.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCFeaturesLite.h 3 | // SCFeaturesLite 4 | // 5 | // Created by iMokhles on 04/04/16. 6 | // Copyright © 2016 iMokhles. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "iMoMacros.h" 11 | #import "UIImage+Additions.h" 12 | #import "UIAlertView+Blocks.h" 13 | #import "ZKSwizzle.h" 14 | #import "fakelogos.h" 15 | #import "Alert.h" 16 | 17 | #pragma mark - Snapchat 18 | 19 | @interface UIActivityViewController () 20 | @property (nonatomic, retain) UIAlertController *activityAlertController; 21 | @end 22 | 23 | @interface UIDevice () 24 | - (id)_deviceInfoForKey:(NSString *)key; 25 | @end 26 | 27 | OBJC_EXTERN CFStringRef MGCopyAnswer(CFStringRef key) WEAK_IMPORT_ATTRIBUTE; 28 | 29 | @interface UIWindow () 30 | + (UIWindow *)keyWindow; 31 | - (UIView *)contentView; 32 | @end 33 | 34 | @interface SCReplyToStoryViewController : UIViewController 35 | @end 36 | 37 | @interface SCTextView : UIView 38 | @property(retain, nonatomic) UITextField *textField; // @synthesize textField=_textField; 39 | @end 40 | 41 | @interface SCGrowingButton : UIView 42 | @property(nonatomic) SEL action; 43 | - (id)initWithFrame:(struct CGRect)arg1; 44 | - (void)addTarget:(id)arg1 action:(SEL)arg2; 45 | @property(nonatomic, getter=isEnabled) _Bool enabled; 46 | @property(retain, nonatomic) UIImageView *imageView; 47 | @property(retain, nonatomic) NSString *imageName; 48 | @property(retain, nonatomic) UIImage *image; 49 | @property(nonatomic) struct CGSize imageInset; 50 | - (void)press:(id)arg1; 51 | - (CGPoint)imageCenter; 52 | @end 53 | 54 | @interface FriendButton : SCGrowingButton 55 | @end 56 | 57 | @interface SCCameraOverlayView : UIView 58 | @property(retain, nonatomic) SCGrowingButton *galleryButton; 59 | @property(retain, nonatomic) FriendButton *storiesButton; 60 | @end 61 | 62 | 63 | @interface SCCounterLabel : UILabel 64 | @end 65 | 66 | @interface Media : NSObject 67 | @property(retain, nonatomic) AVPlayerItem *playerItem; 68 | @end 69 | 70 | @interface SCActiveVideoMedia : NSObject 71 | @property(copy, nonatomic) NSString *mediaId; 72 | @property(retain, nonatomic) Media *media; 73 | @end 74 | 75 | @interface SCMediaView : UIImageView 76 | @property(retain, nonatomic) NSArray *playerViews; 77 | @property(retain, nonatomic) NSMutableDictionary *activeVideos; 78 | @property(nonatomic) _Bool playerAPlaying; 79 | @property(nonatomic) _Bool playerBPlaying; 80 | @property(retain, nonatomic) NSArray *overlayImageViews; 81 | @property(retain, nonatomic) UIImageView *imageView; 82 | @property(retain, nonatomic) SCCounterLabel *counter; 83 | @end 84 | 85 | @interface SCCaptionModeButton : SCGrowingButton 86 | { 87 | _Bool _selected; 88 | } 89 | 90 | @property(nonatomic) _Bool selected; // @synthesize selected=_selected; 91 | - (void)loadImage; 92 | - (id)initWithFrame:(struct CGRect)arg1; 93 | 94 | @end 95 | 96 | @interface SCSwipeFilterView : UIView 97 | @end 98 | 99 | @interface SCImageSwipeFilterView : SCSwipeFilterView 100 | - (id)newMediaFilterViewForName:(id)arg1; 101 | - (id)filteredImage; 102 | - (id)mediaFilterScrollView; 103 | @property(retain, nonatomic) UIImage *image; 104 | @end 105 | 106 | @interface PreviewViewController : UIViewController 107 | @property(retain, nonatomic) SCGrowingButton *audioButton; 108 | @property(retain, nonatomic) UIImageView *imageView; 109 | @property(retain, nonatomic) UIView *containerView; 110 | @property(retain, nonatomic) SCSwipeFilterView *swipeFilterView; 111 | @property(nonatomic) _Bool videoSwipeFilterSetupCompleted; 112 | - (void)setupVideoFilterViewWithOverlayViews; 113 | - (void)setupImageFilterViewWithDrawingView; 114 | @property(retain, nonatomic) SCCaptionModeButton *captionModeButton; 115 | @end 116 | 117 | @interface SendViewController : UIViewController 118 | @end 119 | 120 | @interface AVCameraViewController : UIViewController 121 | - (void)presentPreviewForVideoWithURL:(id)arg1 frontFacingCamera:(_Bool)arg2 fromGallery:(_Bool)arg3; 122 | - (unsigned long long)suitableVideoPlaybackQuality; 123 | - (void)presentPreviewForImage:(id)arg1 metadata:(id)arg2 frontFacingCamera:(_Bool)arg3; 124 | - (void)presentPreviewForVideoWithURL:(id)arg1 frontFacingCamera:(_Bool)arg2; 125 | - (void)presentPreviewForImage:(id)arg1 metadata:(id)arg2 frontFacingCamera:(_Bool)arg3 fromGallery:(_Bool)arg4; 126 | @end 127 | 128 | @interface SCStoriesViewController : UIViewController 129 | @end 130 | 131 | @interface SCFeedViewController : UIViewController 132 | @end 133 | 134 | @interface SCDiscoverViewController : UIViewController 135 | @end 136 | 137 | @interface MainViewController : UIViewController 138 | @property(retain, nonatomic) UIViewController *farLeftVC; 139 | @property(retain, nonatomic) UIViewController *partiallyVisibleVC; 140 | @property(retain, nonatomic) SCDiscoverViewController *farRightVC; // @synthesize farRightVC=_farRightVC; 141 | @property(retain, nonatomic) SCStoriesViewController *rightVC; 142 | @property(retain, nonatomic) SCFeedViewController *leftVC; 143 | @property(retain, nonatomic) AVCameraViewController *middleVC; // @synthesize middleVC=_middleVC; 144 | @end 145 | 146 | 147 | 148 | @interface SCPlayerView : UIView 149 | { 150 | } 151 | 152 | + (Class)layerClass; 153 | @property(retain, nonatomic) AVPlayer *player; 154 | @property(readonly, nonatomic) AVPlayerLayer *playerLayer; 155 | 156 | @end 157 | 158 | @interface SCDiscoverFullStackViewController : UIViewController 159 | @property(retain, nonatomic) SCPlayerView *backgroundVideoView; 160 | @end 161 | 162 | @interface Snap : NSObject 163 | - (void)setFailed; 164 | - (_Bool)hasFailedAtLeastOnce; 165 | - (long long)getGroupId; 166 | - (id)clearedDictionary; 167 | - (_Bool)sending; 168 | - (_Bool)failedToSend; 169 | - (_Bool)sentByUser; 170 | - (_Bool)isInvalidAfterUnarchiving; 171 | - (_Bool)isUnread; 172 | - (_Bool)shouldDisplayBelowFoldInChat; 173 | - (id)messageRecipient; 174 | - (id)messageSender; 175 | - (id)feedSortTimestamp; 176 | - (id)feedDisplayTimestamp; 177 | - (id)messageTimestamp; 178 | - (void)imageProcessingDidSucceedForMedia:(id)arg1; 179 | - (void)mediaUploadDidFailForMedia:(id)arg1; 180 | - (void)mediaUploadDidSucceedForMedia:(id)arg1; 181 | - (long long)uploadMediaTypeForMedia:(id)arg1; 182 | - (id)uploadMediaIdForMedia:(id)arg1; 183 | - (void)fetchMediaDidSucceedForMedia:(id)arg1; 184 | - (void)fetchMediaIsGoneForMedia:(id)arg1; 185 | - (void)fetchMediaDidFailForMedia:(id)arg1; 186 | - (void)fetchMediaIsLoadingForMedia:(id)arg1; 187 | - (_Bool)isBroadcastForMedia:(id)arg1; 188 | - (id)requestContexts; 189 | - (long long)requestFallbackPriority; 190 | - (long long)requestPriorityUserInitiated:(_Bool)arg1; 191 | - (_Bool)needsAuthToFetch; 192 | - (_Bool)encrypt; 193 | - (_Bool)persist; 194 | - (id)encryptionDictionaryForMedia:(id)arg1; 195 | - (id)decryptData:(id)arg1 forMedia:(id)arg2; 196 | - (id)mediaIdForMedia:(id)arg1; 197 | - (id)endpointParamsForMedia:(id)arg1; 198 | - (id)endpointForMedia:(id)arg1; 199 | - (id)secretReceivedSnapParameters; 200 | - (id)receivedSnapParameters; 201 | - (id)secretSentSnapParameters; 202 | - (id)sentSnapParameters; 203 | - (void)logSendEvent; 204 | - (id)consistentId; 205 | - (_Bool)veryRecentlyOpen; 206 | - (id)username; 207 | - (_Bool)isExpired; 208 | - (_Bool)canBeRemoved; 209 | - (_Bool)isGroupSend; 210 | - (id)nameForView; 211 | - (id)recipientUsernames; 212 | - (id)initWithCoder:(id)arg1; 213 | - (void)encodeWithCoder:(id)arg1; 214 | - (void)replaceWithSnap:(id)arg1; 215 | - (_Bool)shouldReplaceWithSnap:(id)arg1; 216 | - (_Bool)updateWithSnap:(id)arg1; 217 | - (_Bool)isPreparedToReplayOrReplaying; 218 | - (_Bool)isSentSnap; 219 | - (_Bool)isReceivedAndUnopened; 220 | - (_Bool)isReceivedAndOpened; 221 | - (_Bool)isViewing; 222 | - (_Bool)isLoading; 223 | - (_Bool)isLoaded; 224 | - (_Bool)isNotLoaded; 225 | - (_Bool)isScreenshotted; 226 | - (_Bool)isSentAndOpened; 227 | - (_Bool)isDelivered; 228 | - (_Bool)isSentDeliveredOrOpened; 229 | - (_Bool)isSent; 230 | - (_Bool)isSendingOrHasFailed; 231 | - (_Bool)isMediaProcessingOrFailedToProcess; 232 | - (_Bool)isMediaProcessing; 233 | - (_Bool)hasMediaProcessingFailed; 234 | - (_Bool)hasFailed; 235 | - (_Bool)isSending; 236 | - (id)uploadParametersWithData:(_Bool)arg1; 237 | - (void)retrySending:(_Bool)arg1; 238 | - (_Bool)autoRetrySendingIfNetworkReachable; 239 | - (void)doSend; 240 | - (void)postSend; 241 | - (void)send; 242 | - (void)preSend; 243 | - (void)uploadAndSend; 244 | - (_Bool)shouldClearSentSnap; 245 | - (void)incNumTimesReloaded; 246 | - (_Bool)isSentButNotYetReturned; 247 | - (void)clearNumTimesReloaded; 248 | - (void)markAsViewed; 249 | - (void)replay; 250 | @end 251 | 252 | @interface SCSnapSaver : NSObject 253 | { 254 | } 255 | 256 | + (id)shared; 257 | - (id)_fetchSnapchatAlbums; 258 | - (void)logSnapSaveEventWithError:(id)arg1 context:(id)arg2 isVideo:(_Bool)arg3 isVideoFiltered:(_Bool)arg4 videoDuration:(double)arg5; 259 | - (void)logSnapSaveEventStart:(id)arg1; 260 | - (void)logAlbumPhotoCount:(unsigned long long)arg1 videoCount:(unsigned long long)arg2 albumCounts:(id)arg3; 261 | - (void)fetchAndLogAlbumSize; 262 | - (void)finishedSavingToAlbumWithError:(id)arg1 completionBlock:(id)arg2; 263 | - (void)saveAsset:(id)arg1 toALAssetsGroup:(id)arg2 completionBlock:(id)arg3; 264 | - (void)saveToAlbumUsingALAssetsLibraryWithAssetURL:(id)arg1 completionBlock:(id)arg2; 265 | - (void)saveAsset:(id)arg1 toPHAssetCollection:(id)arg2 completionBlock:(id)arg3; 266 | - (void)saveToAlbumUsingPHPhotoLibraryWithAssetURL:(id)arg1 completionBlock:(id)arg2; 267 | - (void)finishedWritingWithAssetURL:(id)arg1 error:(id)arg2 completionBlock:(id)arg3; 268 | - (void)saveSnapVideoAtURLToSnapAlbum:(id)arg1 completionBlock:(id)arg2 deleteAfterSaving:(_Bool)arg3; 269 | - (void)saveSnapImageToSnapAlbum:(id)arg1 completionBlock:(id)arg2; 270 | 271 | @end 272 | 273 | 274 | @interface User 275 | + (void)performLoginWithUsernameOrEmail:(NSString *)username password:(NSString *)password; 276 | + (void)performLoginWithUsernameOrEmail:(id)arg1 password:(id)arg2 isTwoFA:(_Bool)arg3 preAuthToken:(id)arg4 onComplete:(id)arg5; // new 277 | @end 278 | 279 | @interface Manager : NSObject 280 | + (void)clearUnusedVideoURLsExcludingURLsFromSnaps:(id)arg1 andStories:(id)arg2; 281 | + (id)inspectJsonValidity:(id)arg1; 282 | + (id)shared; 283 | + (_Bool)isInitialized; 284 | - (void)postServerChallenge; 285 | - (void)logConversationsResponse:(id)arg1; 286 | - (void)clearViewedStories; 287 | - (void)clearExpiredStories; 288 | - (void)clearExpiredAndViewedStories; 289 | - (void)didAppStartupComplete; 290 | - (_Bool)userHasValidRequest; 291 | - (void)willEnterForegroundFromRemoteNotification:(_Bool)arg1; 292 | - (void)didEnterBackground; 293 | - (void)prepareForBecomeActiveFromRemoteNotification:(_Bool)arg1; 294 | - (void)prepareForResignActive; 295 | - (void)startTimer:(id)arg1 source:(long long)arg2; 296 | - (void)startTimerIfNecessary; 297 | - (void)markSnapAsViewed:(id)arg1; 298 | - (void)tick:(id)arg1; 299 | - (_Bool)hasUnviewedChats; 300 | - (_Bool)hasUnviewedCash; 301 | - (int)hasUnviewedSnaps; 302 | - (long long)unreadCount; 303 | - (void)registerDeviceToken:(id)arg1; 304 | - (void)checkMobile; 305 | - (void)verifyMobile:(id)arg1 shouldSkipConfirmation:(_Bool)arg2 type:(long long)arg3; 306 | - (void)verifyMobile:(id)arg1 shouldSkipConfirmation:(_Bool)arg2; 307 | - (void)verifyMobile:(id)arg1 type:(long long)arg2; 308 | - (void)verifyMobile:(id)arg1; 309 | @end 310 | 311 | 312 | @interface SCSnapPlayController : NSObject 313 | @property(retain, nonatomic) Snap *visibleSnap; 314 | + (id)shared; 315 | - (_Bool)showingMediaView; 316 | - (_Bool)isPlayingSnap; 317 | - (id)visibleSnapUsername; 318 | - (id)mediaView; 319 | @end 320 | 321 | @interface SCFeaturesLite : NSObject 322 | + (instancetype)shareFeatures; 323 | @end 324 | -------------------------------------------------------------------------------- /INSEnhancerLite/INSEnhancerLite.h: -------------------------------------------------------------------------------- 1 | // 2 | // INSEnhancerLite.h 3 | // INSEnhancerLite 4 | // 5 | // Created by iMokhles on 04/04/16. 6 | // Copyright © 2016 iMokhles. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "iMoMacros.h" 12 | #import "UIImage+Additions.h" 13 | #import "UIAlertView+Blocks.h" 14 | #import "ZKSwizzle.h" 15 | #import "fakelogos.h" 16 | #import "Alert.h" 17 | #import "TransNSString.h" 18 | 19 | #pragma mark - Instagram 20 | 21 | @interface UIDevice () 22 | - (id)_deviceInfoForKey:(NSString *)key; 23 | @end 24 | 25 | OBJC_EXTERN CFStringRef MGCopyAnswer(CFStringRef key) WEAK_IMPORT_ATTRIBUTE; 26 | 27 | @interface UIWindow () 28 | + (UIWindow *)keyWindow; 29 | - (UIView *)contentView; 30 | @end 31 | 32 | @interface AppDelegate : NSObject 33 | { 34 | BOOL _handledPushNoteInDidFinishLaunching; 35 | UIWindow *_window; 36 | } 37 | 38 | @property(nonatomic) BOOL handledPushNoteInDidFinishLaunching; // @synthesize handledPushNoteInDidFinishLaunching=_handledPushNoteInDidFinishLaunching; 39 | @property(retain, nonatomic) UIWindow *window; // @synthesize window=_window; 40 | - (void)registerForPush; 41 | - (BOOL)application:(id)arg1 openURL:(id)arg2 sourceApplication:(id)arg3 annotation:(id)arg4; 42 | - (BOOL)application:(id)arg1 handleOpenURL:(id)arg2; 43 | - (void)userLogout:(id)arg1; 44 | - (void)userLoginCompleted:(id)arg1; 45 | - (void)startMainAppWithMainFeedSource:(id)arg1 animated:(BOOL)arg2; 46 | - (void)setUpInstagramNotifications; 47 | - (void)setUpDefaults; 48 | - (void)applicationLifecycleChange:(id)arg1; 49 | - (void)applicationWillTerminate:(id)arg1; 50 | - (void)applicationDidEnterBackground:(id)arg1; 51 | - (void)applicationDidBecomeActive:(id)arg1; 52 | - (void)applicationWillEnterForeground:(id)arg1; 53 | - (BOOL)application:(id)arg1 didFinishLaunchingWithOptions:(id)arg2; 54 | @end 55 | 56 | @interface IGStyledString : NSObject { 57 | NSMutableDictionary *_heightCache; 58 | NSMutableAttributedString *_attributedString; 59 | } 60 | + (id)createWithCacheKey:(id)arg1 creationBlock:(id)arg2; 61 | @property(retain, nonatomic) NSMutableAttributedString *attributedString; // @synthesize attributedString=_attributedString; 62 | - (int)heightForWidth:(int)arg1; 63 | - (void)applyBaseStyleToAttributedString:(id)arg1; 64 | - (void)appendAnnotatedString:(id)arg1; 65 | - (void)appendAttributedString:(id)arg1; 66 | - (void)appendString:(id)arg1; 67 | - (id)initWithBaseStyle:(id)arg1; 68 | - (id)init; 69 | - (void)appendLinkedTitleString:(id)arg1; 70 | - (void)appendLinkedString:(id)arg1; 71 | 72 | @end 73 | 74 | @interface IGCoreTextView : UIView 75 | { 76 | UIColor *_shadowColor; 77 | float _shadowOffset; 78 | BOOL _heightIsValid; 79 | struct CGPoint _touchPoint; 80 | BOOL _longTapHandled; 81 | IGStyledString *_styledString; 82 | } 83 | 84 | @property(retain, nonatomic) IGStyledString *styledString; // @synthesize styledString=_styledString; 85 | - (void)drawRect:(struct CGRect)arg1; 86 | - (BOOL)handleTapAtIndex:(int)arg1 forTouchEvent:(unsigned int)arg2 fromLongTap:(BOOL)arg3; 87 | - (BOOL)handleTapAtIndex:(int)arg1 forTouchEvent:(unsigned int)arg2; 88 | - (BOOL)handleTapAtPoint:(struct CGPoint)arg1 forTouchEvent:(unsigned int)arg2 fromLongTap:(BOOL)arg3; 89 | - (BOOL)handleTapAtPoint:(struct CGPoint)arg1 forTouchEvent:(unsigned int)arg2; 90 | - (void)handleLongTap; 91 | - (void)touchesEnded:(id)arg1 withEvent:(id)arg2; 92 | - (void)touchesCancelled:(id)arg1 withEvent:(id)arg2; 93 | - (void)touchesBegan:(id)arg1 withEvent:(id)arg2; 94 | - (float)height; 95 | - (void)setFrame:(struct CGRect)arg1; 96 | - (id)initWithWidth:(float)arg1; 97 | @end 98 | 99 | @interface IGCoreTextView (everything_tweak) 100 | @end 101 | 102 | @interface IGVideo : NSObject 103 | 104 | + (int)videoVersionForCurrentNetworkConditions; 105 | @property(retain, nonatomic) NSArray *videoVersions; // @synthesize videoVersions=_videoVersions; 106 | @property(readonly, nonatomic) int videoLength; // @synthesize videoLength=_videoLength; 107 | - (id)allVideoURLs; 108 | - (id)videoURLForVideoVersion:(int)arg1; 109 | - (id)videoInfoDictionaryForVideoVersion:(int)arg1; 110 | - (void)encodeWithCoder:(id)arg1; 111 | - (id)initWithCoder:(id)arg1; 112 | - (id)initWithVideoVersions:(id)arg1 videoLength:(int)arg2 audioDetected:(id)arg3; 113 | - (id)initWithFeedItemDictionary:(id)arg1; 114 | - (id)videoURLForCurrentNetworkConditions; 115 | 116 | @end 117 | 118 | @interface IGPhoto : NSObject 119 | + (id)arrayForImageVersions:(id)arg1; 120 | @property(retain, nonatomic) NSArray *imageVersions; // @synthesize imageVersions=_imageVersions; 121 | @property(readonly, copy, nonatomic) NSString *mediaID; // @synthesize mediaID=_mediaID; 122 | @end 123 | 124 | 125 | @interface IGPost : NSObject 126 | { 127 | BOOL _hasLiked; 128 | BOOL _moreCommentsAvailable; 129 | BOOL _collapseComments; 130 | BOOL _needsFetch; 131 | int _mediaType; 132 | NSNumber *_deviceTimestamp; 133 | NSDictionary *_imageVersions; 134 | NSDictionary *_videoVersions; 135 | int _videoLength; 136 | NSMutableOrderedSet *_likers; 137 | int _likeCount; 138 | NSMutableArray *_pendingComments; 139 | NSArray *_activeComments; 140 | NSMutableArray *_allComments; 141 | NSNumber *_commentCursor; 142 | int _commentCount; 143 | NSString *_rankToken; 144 | NSString *_exploreContext; 145 | } 146 | 147 | @property(readonly) IGVideo *video; 148 | @property(readonly) IGPhoto *photo; 149 | 150 | + (int)fullSizeImageVersionForDevice; 151 | + (int)videoVersionForCurrentNetworkConditions; 152 | @property(nonatomic) BOOL needsFetch; // @synthesize needsFetch=_needsFetch; 153 | @property(readonly, copy) NSString *exploreContext; // @synthesize exploreContext=_exploreContext; 154 | @property(readonly) NSString *rankToken; // @synthesize rankToken=_rankToken; 155 | - (id)urlToFlagComment:(id)arg1; 156 | - (id)urlToDeleteComment:(id)arg1; 157 | - (id)urlToPostComment; 158 | - (void)schedulePostUpdatedNotification; 159 | - (void)postPostUpdatedNotification; 160 | - (void)commentRemoveRequestFailed:(id)arg1; 161 | - (void)commentRemoveRequestFinished:(id)arg1; 162 | - (void)commentRemoveRequestStarted:(id)arg1; 163 | - (void)commentPostRequestFailedSpam:(id)arg1; 164 | - (void)commentPostRequestFailed:(id)arg1; 165 | - (void)commentPostRequestFinished:(id)arg1; 166 | - (void)commentPostRequestStarted:(id)arg1; 167 | - (void)fetchMoreCommentsWithCompletionHandler:(id)arg1; 168 | - (void)invalidateActiveComments; 169 | @property(readonly) NSArray *activeCaptionAndComments; 170 | @property(readonly) NSArray *activeComments; // @synthesize activeComments=_activeComments; 171 | - (void)removeCommentWithPK:(id)arg1; 172 | - (void)addComment:(id)arg1; 173 | - (void)setCommentInfoFromDictionary:(id)arg1 append:(BOOL)arg2; 174 | @property(retain) NSMutableArray *pendingComments; // @synthesize pendingComments=_pendingComments; 175 | @property(readonly) NSMutableArray *allComments; // @synthesize allComments=_allComments; 176 | - (void)performLike:(BOOL)arg1 userDidDoubleTap:(BOOL)arg2 completion:(id)arg3; 177 | - (void)updateLocalLikeStatus:(BOOL)arg1; 178 | - (void)setLikeInfoFromDictionary:(id)arg1; 179 | - (void)removeLocalLocationInformation; 180 | - (void)setLocationInfoFromDictionary:(id)arg1; 181 | - (void)fetchAdditionalInfo; 182 | - (void)setMediaType:(int)arg1; 183 | - (BOOL)updateWithDictionary:(id)arg1; 184 | - (void)encodeWithCoder:(id)arg1; 185 | - (id)initWithCoder:(id)arg1; 186 | - (id)init; 187 | @property(readonly) BOOL collapseComments; // @synthesize collapseComments=_collapseComments; 188 | - (void)setCollapseComments:(BOOL)arg1; 189 | @property(readonly) BOOL moreCommentsAvailable; // @synthesize moreCommentsAvailable=_moreCommentsAvailable; 190 | - (void)setMoreCommentsAvailable:(BOOL)arg1; 191 | @property(readonly) int commentCount; // @synthesize commentCount=_commentCount; 192 | - (void)setCommentCount:(int)arg1; 193 | @property(readonly) NSNumber *commentCursor; // @synthesize commentCursor=_commentCursor; 194 | //- (void)setCommentCursor:(id)arg1; 195 | - (void)setCaption:(id)arg1; 196 | //- (void)setAllComments:(id)arg1; 197 | //- (void)setActiveComments:(id)arg1; 198 | @property(readonly) BOOL hasLiked; // @synthesize hasLiked=_hasLiked; 199 | - (void)setHasLiked:(BOOL)arg1; 200 | @property(readonly) int likeCount; // @synthesize likeCount=_likeCount; 201 | - (void)setLikeCount:(int)arg1; 202 | @property(readonly) NSMutableOrderedSet *likers; // @synthesize likers=_likers; 203 | //- (void)setLikers:(id)arg1; 204 | - (void)setMediaCoord:(id)arg1; 205 | - (void)setLocation:(id)arg1; 206 | @property(readonly) int videoLength; // @synthesize videoLength=_videoLength; 207 | - (void)setVideoLength:(int)arg1; 208 | @property(readonly) NSDictionary *videoVersions; // @synthesize videoVersions=_videoVersions; 209 | //- (void)setVideoVersions:(id)arg1; 210 | @property(readonly) NSDictionary *imageVersions; // @synthesize imageVersions=_imageVersions; 211 | //- (void)setImageVersions:(id)arg1; 212 | @property(readonly) NSNumber *deviceTimestamp; // @synthesize deviceTimestamp=_deviceTimestamp; 213 | //- (void)setDeviceTimestamp:(id)arg1; 214 | - (void)setTakenAt:(id)arg1; 215 | - (void)setUser:(id)arg1; 216 | @property(readonly) int mediaType; // @synthesize mediaType=_mediaType; 217 | - (id)imageURLForImageVersion:(int)arg1; 218 | - (id)imageURLForFullSizeImage; 219 | - (void)reportInappropriateWithCompletionHandler:(id)arg1; 220 | - (id)allVideoURLs; 221 | - (id)videoURLForVideoVersion:(int)arg1; 222 | 223 | @end 224 | 225 | @class IGFeedItemPhotoView; 226 | @interface IGFeedItemPhotoCell : UITableViewCell 227 | 228 | @property(retain, nonatomic) IGPost *post; 229 | @property(retain, nonatomic) IGFeedItemPhotoView *photoView; 230 | - (id)accessibleElements; 231 | - (int)indexOfAccessibilityElement:(id)arg1; 232 | - (id)accessibilityElementAtIndex:(int)arg1; 233 | - (int)accessibilityElementCount; 234 | - (void)layoutSubviews; 235 | - (id)initWithReuseIdentifier:(id)arg1; 236 | - (id)initWithFrame:(id)arg1; 237 | @end 238 | 239 | @interface IGImageView : UIImageView 240 | @property(retain, nonatomic) NSURL *imageURL; 241 | @end 242 | 243 | @interface IGImageProgressView : UIView 244 | @property(readonly, nonatomic) IGImageView *photoImageView; 245 | @end 246 | 247 | @interface IGFeedItemPhotoView : UIView 248 | { 249 | UIImageView *_inTagIndicatorView; 250 | BOOL _isShowingUsertagsIndicator; 251 | UITapGestureRecognizer *_doubleTapRecognizer; 252 | UITapGestureRecognizer *_singleTapRecognizer; 253 | BOOL _isShowingUsertags; 254 | BOOL _enableDoubleTapRecognizer; 255 | IGPost *_post; 256 | } 257 | 258 | + (float)height; 259 | @property(nonatomic) BOOL enableDoubleTapRecognizer; // @synthesize enableDoubleTapRecognizer=_enableDoubleTapRecognizer; 260 | @property(nonatomic) __weak IGFeedItemPhotoCell *parentCellView; // @synthesize parentCellView=_parentCellView; 261 | @property(readonly, nonatomic) BOOL isShowingUsertags; // @synthesize isShowingUsertags=_isShowingUsertags; 262 | @property(retain, nonatomic) IGPost *post; // @synthesize post=_post; 263 | @property(readonly, nonatomic) IGImageProgressView *photoImageView; 264 | - (void)onUsertagGroupWasEdited; 265 | - (void)progressImageView:(id)arg1 didFailLoadWithError:(id)arg2; 266 | - (void)progressImageViewDidLoadImage:(id)arg1; 267 | - (void)showUsertags:(BOOL)arg1 animated:(BOOL)arg2; 268 | - (void)animationDidStop:(id)arg1 finished:(BOOL)arg2; 269 | - (void)showUsertagsIndicator:(BOOL)arg1 animated:(BOOL)arg2; 270 | - (id)usertags; 271 | - (BOOL)hasUsertags; 272 | - (void)updateSingleTapRecognizer; 273 | - (BOOL)gestureRecognizer:(id)arg1 shouldReceiveTouch:(id)arg2; 274 | - (void)onDoubleTap:(id)arg1; 275 | - (void)onTap:(id)arg1; 276 | - (void)prepareForReuse; 277 | - (void)onTagIndicatorTapped; 278 | - (id)initWithFrame:(struct CGRect)arg1; 279 | 280 | @end 281 | @interface IGFeedItemPhotoCell (everything_tweak) 282 | @end 283 | 284 | @interface IGFeedVideoPlayer : NSObject 285 | @property(retain, nonatomic) NSURL *URL; // @synthesize URL=_URL; 286 | - (id)init; 287 | @end 288 | 289 | @interface IGProxyFeedVideoPlayer : IGFeedVideoPlayer 290 | { 291 | NSURL *_proxyURL; 292 | NSURL *_videoURL; 293 | } 294 | 295 | - (id)URL; 296 | - (void)resetPlayer; 297 | - (void)reset; 298 | - (void)stop; 299 | - (void)loadVideoForURL:(id)arg1; 300 | 301 | @end 302 | 303 | @interface IGFeedItemVideoView : UIView 304 | { 305 | UITapGestureRecognizer *_doubleTapRecognizer; 306 | UITapGestureRecognizer *_singleTapRecognizer; 307 | UIView *_videoView; 308 | BOOL _indicatorHidden; 309 | BOOL _posterImageHidden; 310 | BOOL _forceAudio; 311 | BOOL _displayUnmuteButton; 312 | NSDate *_lastVideoStartTime; 313 | int _currentVideoVersion; 314 | BOOL _videoLoadError; 315 | BOOL _enableDoubleTapRecognizer; 316 | BOOL _hasStartedPlayback; 317 | BOOL _userDidTap; 318 | IGPost *_post; 319 | NSNumber *_lastPlaybackTime; 320 | int _originalPlaybackReason; 321 | } 322 | 323 | + (float)height; 324 | @property int originalPlaybackReason; // @synthesize originalPlaybackReason=_originalPlaybackReason; 325 | @property(retain) NSNumber *lastPlaybackTime; // @synthesize lastPlaybackTime=_lastPlaybackTime; 326 | @property BOOL userDidTap; // @synthesize userDidTap=_userDidTap; 327 | @property BOOL hasStartedPlayback; // @synthesize hasStartedPlayback=_hasStartedPlayback; 328 | @property(nonatomic) BOOL enableDoubleTapRecognizer; // @synthesize enableDoubleTapRecognizer=_enableDoubleTapRecognizer; 329 | @property(nonatomic) BOOL videoLoadError; // @synthesize videoLoadError=_videoLoadError; 330 | @property(retain, nonatomic) IGPost *post; // @synthesize post=_post; 331 | //@property(retain, nonatomic) IGFeedVideoPlayer *player; 332 | @property(retain, nonatomic) IGProxyFeedVideoPlayer *player; 333 | - (BOOL)gestureRecognizer:(id)arg1 shouldRecognizeSimultaneouslyWithGestureRecognizer:(id)arg2; 334 | - (BOOL)gestureRecognizer:(id)arg1 shouldReceiveTouch:(id)arg2; 335 | - (BOOL)gestureRecognizerShouldBegin:(id)arg1; 336 | - (void)onDoubleTap:(id)arg1; 337 | - (void)onTap:(id)arg1; 338 | - (void)videoPlayerStateDidChange:(id)arg1 previous:(int)arg2 current:(int)arg3; 339 | - (void)videoPlayer:(id)arg1 didUpdatePlaybackProgress:(float)arg2; 340 | - (void)videoPlayer:(id)arg1 didUpdateLoadingProgress:(float)arg2; 341 | - (void)videoPlayerReadyToPlay:(id)arg1; 342 | - (void)videoPlayerWillReset:(id)arg1; 343 | - (void)progressImageViewDidLoadImage:(id)arg1; 344 | - (void)userDidTapOnAudioButton; 345 | - (void)updateAudioSettings; 346 | - (void)didUnplugHeadphones:(id)arg1; 347 | - (void)muteSwitchStateChanged:(id)arg1; 348 | - (void)logVideoStoppedForPlayer:(id)arg1 reason:(int)arg2; 349 | - (id)playbackTimesForPlayer:(id)arg1; 350 | - (id)playbackAudioSettingsForPlayer:(id)arg1; 351 | - (void)startPlayer:(id)arg1; 352 | - (void)loadAndPlay; 353 | - (BOOL)posterFrameLoaded; 354 | - (void)prepareForAutoPlay:(BOOL)arg1; 355 | - (void)stop; 356 | - (void)play; 357 | - (void)showVideo:(BOOL)arg1 animated:(BOOL)arg2 completion:(id)arg3; 358 | - (void)showVideoIndication:(BOOL)arg1 animated:(BOOL)arg2 duration:(float)arg3; 359 | - (void)showVideoIndication:(BOOL)arg1 animated:(BOOL)arg2; 360 | - (void)showAudioAvailable:(BOOL)arg1 animated:(BOOL)arg2; 361 | - (void)showError:(BOOL)arg1 animated:(BOOL)arg2; 362 | - (void)showPause:(BOOL)arg1 animated:(BOOL)arg2; 363 | - (void)showIdle:(BOOL)arg1 animated:(BOOL)arg2 duration:(float)arg3; 364 | - (void)showIdle:(BOOL)arg1 animated:(BOOL)arg2; 365 | - (void)showAutoPlayIdle:(BOOL)arg1 animated:(BOOL)arg2; 366 | - (void)showBufferingProgress:(BOOL)arg1 animated:(BOOL)arg2; 367 | - (id)initWithFrame:(struct CGRect)arg1; 368 | 369 | @end 370 | 371 | @interface IGFeedItemVideoCell : UITableViewCell 372 | @property(retain, nonatomic) IGFeedItemVideoView *videoView; 373 | @property(retain, nonatomic) IGPost *post; 374 | - (id)accessibleElements; 375 | - (int)indexOfAccessibilityElement:(id)arg1; 376 | - (id)accessibilityElementAtIndex:(int)arg1; 377 | - (int)accessibilityElementCount; 378 | - (void)setNavigationController:(id)arg1; 379 | - (void)layoutSubviews; 380 | - (id)initWithReuseIdentifier:(id)arg1; 381 | 382 | @end 383 | 384 | @interface IGFeedItemVideoCell (everything_tweak) 385 | @end 386 | 387 | @interface IGFeedItem : IGPost 388 | @end 389 | 390 | @interface IGFeedItemActionCell : UICollectionViewCell 391 | @property(retain, nonatomic) IGFeedItem *feedItem; // @synthesize feedItem=_feedItem; 392 | @property(retain, nonatomic) UIButton *sendButton; // @synthesize sendButton=_sendButton; 393 | @property(retain, nonatomic) UIButton *moreButton; // @synthesize moreButton=_moreButton; 394 | @property(retain, nonatomic) UIButton *commentButton; // @synthesize commentButton=_commentButton; 395 | @property(retain, nonatomic) UIButton *likeButton; // @synthesize likeButton=_likeButton; 396 | 397 | // my new button 398 | - (UIButton *)ing_shareButton; 399 | @end 400 | 401 | @interface IGFeedItemHeaderViewModel : NSObject 402 | @property (retain, nonatomic) NSDate *takenAt; 403 | @property(retain, nonatomic) IGFeedItem *feedItem; // @synthesize feedItem=_feedItem; 404 | @end 405 | 406 | @interface IGFeedItemHeader : UIView 407 | @property (readonly, nonatomic) IGFeedItemHeaderViewModel *viewModel; 408 | @end 409 | 410 | 411 | @interface UIImage (Tinted) 412 | + (id)IGTintedImageWithName:(id)arg1 tintColor:(id)arg2; 413 | @end 414 | 415 | @interface INSEnhancerLite : NSObject 416 | // Instagram Stuffs 417 | + (NSString *)insta_DocumentsPath; 418 | + (void)addNotificationFromObserver:(id)target withName:(NSString *)notiName andSelector:(SEL)aSelector; 419 | + (void)postNotificationWithName:(NSString *)notiName andObject:(id)object ; 420 | + (NSURL *)urlFromVersionArray:(NSArray *)versions; 421 | 422 | // INGEnhancer methods 423 | + (void)ingen_shareText:(NSString *)textToShare; 424 | + (void)ingen_shareFile:(NSString *)fileToShare; 425 | + (NSBundle *)ingen_bundle; 426 | @end 427 | -------------------------------------------------------------------------------- /YTEnhancerLite/MBProgressHUD.h: -------------------------------------------------------------------------------- 1 | // 2 | // MBProgressHUD.h 3 | // Version 0.9.2 4 | // Created by Matej Bukovinski on 2.4.09. 5 | // 6 | 7 | // This code is distributed under the terms and conditions of the MIT license. 8 | 9 | // Copyright (c) 2009-2015 Matej Bukovinski 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining a copy 12 | // of this software and associated documentation files (the "Software"), to deal 13 | // in the Software without restriction, including without limitation the rights 14 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | // copies of the Software, and to permit persons to whom the Software is 16 | // furnished to do so, subject to the following conditions: 17 | // 18 | // The above copyright notice and this permission notice shall be included in 19 | // all copies or substantial portions of the Software. 20 | // 21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | // THE SOFTWARE. 28 | 29 | #import 30 | #import 31 | #import 32 | 33 | @protocol MBProgressHUDDelegate; 34 | 35 | 36 | typedef NS_ENUM(NSInteger, MBProgressHUDMode) { 37 | /** Progress is shown using an UIActivityIndicatorView. This is the default. */ 38 | MBProgressHUDModeIndeterminate, 39 | /** Progress is shown using a round, pie-chart like, progress view. */ 40 | MBProgressHUDModeDeterminate, 41 | /** Progress is shown using a horizontal progress bar */ 42 | MBProgressHUDModeDeterminateHorizontalBar, 43 | /** Progress is shown using a ring-shaped progress view. */ 44 | MBProgressHUDModeAnnularDeterminate, 45 | /** Shows a custom view */ 46 | MBProgressHUDModeCustomView, 47 | /** Shows only labels */ 48 | MBProgressHUDModeText 49 | }; 50 | 51 | typedef NS_ENUM(NSInteger, MBProgressHUDAnimation) { 52 | /** Opacity animation */ 53 | MBProgressHUDAnimationFade, 54 | /** Opacity + scale animation */ 55 | MBProgressHUDAnimationZoom, 56 | MBProgressHUDAnimationZoomOut = MBProgressHUDAnimationZoom, 57 | MBProgressHUDAnimationZoomIn 58 | }; 59 | 60 | 61 | #ifndef MB_INSTANCETYPE 62 | #if __has_feature(objc_instancetype) 63 | #define MB_INSTANCETYPE instancetype 64 | #else 65 | #define MB_INSTANCETYPE id 66 | #endif 67 | #endif 68 | 69 | #ifndef MB_STRONG 70 | #if __has_feature(objc_arc) 71 | #define MB_STRONG strong 72 | #else 73 | #define MB_STRONG retain 74 | #endif 75 | #endif 76 | 77 | #ifndef MB_WEAK 78 | #if __has_feature(objc_arc_weak) 79 | #define MB_WEAK weak 80 | #elif __has_feature(objc_arc) 81 | #define MB_WEAK unsafe_unretained 82 | #else 83 | #define MB_WEAK assign 84 | #endif 85 | #endif 86 | 87 | #if NS_BLOCKS_AVAILABLE 88 | typedef void (^MBProgressHUDCompletionBlock)(); 89 | #endif 90 | 91 | 92 | /** 93 | * Displays a simple HUD window containing a progress indicator and two optional labels for short messages. 94 | * 95 | * This is a simple drop-in class for displaying a progress HUD view similar to Apple's private UIProgressHUD class. 96 | * The MBProgressHUD window spans over the entire space given to it by the initWithFrame constructor and catches all 97 | * user input on this region, thereby preventing the user operations on components below the view. The HUD itself is 98 | * drawn centered as a rounded semi-transparent view which resizes depending on the user specified content. 99 | * 100 | * This view supports four modes of operation: 101 | * - MBProgressHUDModeIndeterminate - shows a UIActivityIndicatorView 102 | * - MBProgressHUDModeDeterminate - shows a custom round progress indicator 103 | * - MBProgressHUDModeAnnularDeterminate - shows a custom annular progress indicator 104 | * - MBProgressHUDModeCustomView - shows an arbitrary, user specified view (see `customView`) 105 | * 106 | * All three modes can have optional labels assigned: 107 | * - If the labelText property is set and non-empty then a label containing the provided content is placed below the 108 | * indicator view. 109 | * - If also the detailsLabelText property is set then another label is placed below the first label. 110 | */ 111 | @interface MBProgressHUD : UIView 112 | 113 | /** 114 | * Creates a new HUD, adds it to provided view and shows it. The counterpart to this method is hideHUDForView:animated:. 115 | * 116 | * @note This method sets `removeFromSuperViewOnHide`. The HUD will automatically be removed from the view hierarchy when hidden. 117 | * 118 | * @param view The view that the HUD will be added to 119 | * @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use 120 | * animations while appearing. 121 | * @return A reference to the created HUD. 122 | * 123 | * @see hideHUDForView:animated: 124 | * @see animationType 125 | */ 126 | + (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated; 127 | 128 | /** 129 | * Finds the top-most HUD subview and hides it. The counterpart to this method is showHUDAddedTo:animated:. 130 | * 131 | * @note This method sets `removeFromSuperViewOnHide`. The HUD will automatically be removed from the view hierarchy when hidden. 132 | * 133 | * @param view The view that is going to be searched for a HUD subview. 134 | * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use 135 | * animations while disappearing. 136 | * @return YES if a HUD was found and removed, NO otherwise. 137 | * 138 | * @see showHUDAddedTo:animated: 139 | * @see animationType 140 | */ 141 | + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated; 142 | 143 | /** 144 | * Finds all the HUD subviews and hides them. 145 | * 146 | * @note This method sets `removeFromSuperViewOnHide`. The HUDs will automatically be removed from the view hierarchy when hidden. 147 | * 148 | * @param view The view that is going to be searched for HUD subviews. 149 | * @param animated If set to YES the HUDs will disappear using the current animationType. If set to NO the HUDs will not use 150 | * animations while disappearing. 151 | * @return the number of HUDs found and removed. 152 | * 153 | * @see hideHUDForView:animated: 154 | * @see animationType 155 | */ 156 | + (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated; 157 | 158 | /** 159 | * Finds the top-most HUD subview and returns it. 160 | * 161 | * @param view The view that is going to be searched. 162 | * @return A reference to the last HUD subview discovered. 163 | */ 164 | + (MB_INSTANCETYPE)HUDForView:(UIView *)view; 165 | 166 | /** 167 | * Finds all HUD subviews and returns them. 168 | * 169 | * @param view The view that is going to be searched. 170 | * @return All found HUD views (array of MBProgressHUD objects). 171 | */ 172 | + (NSArray *)allHUDsForView:(UIView *)view; 173 | 174 | /** 175 | * A convenience constructor that initializes the HUD with the window's bounds. Calls the designated constructor with 176 | * window.bounds as the parameter. 177 | * 178 | * @param window The window instance that will provide the bounds for the HUD. Should be the same instance as 179 | * the HUD's superview (i.e., the window that the HUD will be added to). 180 | */ 181 | - (id)initWithWindow:(UIWindow *)window; 182 | 183 | /** 184 | * A convenience constructor that initializes the HUD with the view's bounds. Calls the designated constructor with 185 | * view.bounds as the parameter 186 | * 187 | * @param view The view instance that will provide the bounds for the HUD. Should be the same instance as 188 | * the HUD's superview (i.e., the view that the HUD will be added to). 189 | */ 190 | - (id)initWithView:(UIView *)view; 191 | 192 | /** 193 | * Display the HUD. You need to make sure that the main thread completes its run loop soon after this method call so 194 | * the user interface can be updated. Call this method when your task is already set-up to be executed in a new thread 195 | * (e.g., when using something like NSOperation or calling an asynchronous call like NSURLRequest). 196 | * 197 | * @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use 198 | * animations while appearing. 199 | * 200 | * @see animationType 201 | */ 202 | - (void)show:(BOOL)animated; 203 | 204 | /** 205 | * Hide the HUD. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to 206 | * hide the HUD when your task completes. 207 | * 208 | * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use 209 | * animations while disappearing. 210 | * 211 | * @see animationType 212 | */ 213 | - (void)hide:(BOOL)animated; 214 | 215 | /** 216 | * Hide the HUD after a delay. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to 217 | * hide the HUD when your task completes. 218 | * 219 | * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use 220 | * animations while disappearing. 221 | * @param delay Delay in seconds until the HUD is hidden. 222 | * 223 | * @see animationType 224 | */ 225 | - (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay; 226 | 227 | /** 228 | * Shows the HUD while a background task is executing in a new thread, then hides the HUD. 229 | * 230 | * This method also takes care of autorelease pools so your method does not have to be concerned with setting up a 231 | * pool. 232 | * 233 | * @param method The method to be executed while the HUD is shown. This method will be executed in a new thread. 234 | * @param target The object that the target method belongs to. 235 | * @param object An optional object to be passed to the method. 236 | * @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will not use 237 | * animations while (dis)appearing. 238 | */ 239 | - (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated; 240 | 241 | #if NS_BLOCKS_AVAILABLE 242 | 243 | /** 244 | * Shows the HUD while a block is executing on a background queue, then hides the HUD. 245 | * 246 | * @see showAnimated:whileExecutingBlock:onQueue:completionBlock: 247 | */ 248 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block; 249 | 250 | /** 251 | * Shows the HUD while a block is executing on a background queue, then hides the HUD. 252 | * 253 | * @see showAnimated:whileExecutingBlock:onQueue:completionBlock: 254 | */ 255 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(MBProgressHUDCompletionBlock)completion; 256 | 257 | /** 258 | * Shows the HUD while a block is executing on the specified dispatch queue, then hides the HUD. 259 | * 260 | * @see showAnimated:whileExecutingBlock:onQueue:completionBlock: 261 | */ 262 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue; 263 | 264 | /** 265 | * Shows the HUD while a block is executing on the specified dispatch queue, executes completion block on the main queue, and then hides the HUD. 266 | * 267 | * @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will 268 | * not use animations while (dis)appearing. 269 | * @param block The block to be executed while the HUD is shown. 270 | * @param queue The dispatch queue on which the block should be executed. 271 | * @param completion The block to be executed on completion. 272 | * 273 | * @see completionBlock 274 | */ 275 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue 276 | completionBlock:(MBProgressHUDCompletionBlock)completion; 277 | 278 | /** 279 | * A block that gets called after the HUD was completely hidden. 280 | */ 281 | @property (copy) MBProgressHUDCompletionBlock completionBlock; 282 | 283 | #endif 284 | 285 | /** 286 | * MBProgressHUD operation mode. The default is MBProgressHUDModeIndeterminate. 287 | * 288 | * @see MBProgressHUDMode 289 | */ 290 | @property (assign) MBProgressHUDMode mode; 291 | 292 | /** 293 | * The animation type that should be used when the HUD is shown and hidden. 294 | * 295 | * @see MBProgressHUDAnimation 296 | */ 297 | @property (assign) MBProgressHUDAnimation animationType; 298 | 299 | /** 300 | * The UIView (e.g., a UIImageView) to be shown when the HUD is in MBProgressHUDModeCustomView. 301 | * For best results use a 37 by 37 pixel view (so the bounds match the built in indicator bounds). 302 | */ 303 | @property (MB_STRONG) UIView *customView; 304 | 305 | /** 306 | * The HUD delegate object. 307 | * 308 | * @see MBProgressHUDDelegate 309 | */ 310 | @property (MB_WEAK) id delegate; 311 | 312 | /** 313 | * An optional short message to be displayed below the activity indicator. The HUD is automatically resized to fit 314 | * the entire text. If the text is too long it will get clipped by displaying "..." at the end. If left unchanged or 315 | * set to @"", then no message is displayed. 316 | */ 317 | @property (copy) NSString *labelText; 318 | 319 | /** 320 | * An optional details message displayed below the labelText message. This message is displayed only if the labelText 321 | * property is also set and is different from an empty string (@""). The details text can span multiple lines. 322 | */ 323 | @property (copy) NSString *detailsLabelText; 324 | 325 | /** 326 | * The opacity of the HUD window. Defaults to 0.8 (80% opacity). 327 | */ 328 | @property (assign) float opacity; 329 | 330 | /** 331 | * The color of the HUD window. Defaults to black. If this property is set, color is set using 332 | * this UIColor and the opacity property is not used. using retain because performing copy on 333 | * UIColor base colors (like [UIColor greenColor]) cause problems with the copyZone. 334 | */ 335 | @property (MB_STRONG) UIColor *color; 336 | 337 | /** 338 | * The x-axis offset of the HUD relative to the centre of the superview. 339 | */ 340 | @property (assign) float xOffset; 341 | 342 | /** 343 | * The y-axis offset of the HUD relative to the centre of the superview. 344 | */ 345 | @property (assign) float yOffset; 346 | 347 | /** 348 | * The amount of space between the HUD edge and the HUD elements (labels, indicators or custom views). 349 | * Defaults to 20.0 350 | */ 351 | @property (assign) float margin; 352 | 353 | /** 354 | * The corner radius for the HUD 355 | * Defaults to 10.0 356 | */ 357 | @property (assign) float cornerRadius; 358 | 359 | /** 360 | * Cover the HUD background view with a radial gradient. 361 | */ 362 | @property (assign) BOOL dimBackground; 363 | 364 | /* 365 | * Grace period is the time (in seconds) that the invoked method may be run without 366 | * showing the HUD. If the task finishes before the grace time runs out, the HUD will 367 | * not be shown at all. 368 | * This may be used to prevent HUD display for very short tasks. 369 | * Defaults to 0 (no grace time). 370 | * Grace time functionality is only supported when the task status is known! 371 | * @see taskInProgress 372 | */ 373 | @property (assign) float graceTime; 374 | 375 | /** 376 | * The minimum time (in seconds) that the HUD is shown. 377 | * This avoids the problem of the HUD being shown and than instantly hidden. 378 | * Defaults to 0 (no minimum show time). 379 | */ 380 | @property (assign) float minShowTime; 381 | 382 | /** 383 | * Indicates that the executed operation is in progress. Needed for correct graceTime operation. 384 | * If you don't set a graceTime (different than 0.0) this does nothing. 385 | * This property is automatically set when using showWhileExecuting:onTarget:withObject:animated:. 386 | * When threading is done outside of the HUD (i.e., when the show: and hide: methods are used directly), 387 | * you need to set this property when your task starts and completes in order to have normal graceTime 388 | * functionality. 389 | */ 390 | @property (assign) BOOL taskInProgress; 391 | 392 | /** 393 | * Removes the HUD from its parent view when hidden. 394 | * Defaults to NO. 395 | */ 396 | @property (assign) BOOL removeFromSuperViewOnHide; 397 | 398 | /** 399 | * Font to be used for the main label. Set this property if the default is not adequate. 400 | */ 401 | @property (MB_STRONG) UIFont* labelFont; 402 | 403 | /** 404 | * Color to be used for the main label. Set this property if the default is not adequate. 405 | */ 406 | @property (MB_STRONG) UIColor* labelColor; 407 | 408 | /** 409 | * Font to be used for the details label. Set this property if the default is not adequate. 410 | */ 411 | @property (MB_STRONG) UIFont* detailsLabelFont; 412 | 413 | /** 414 | * Color to be used for the details label. Set this property if the default is not adequate. 415 | */ 416 | @property (MB_STRONG) UIColor* detailsLabelColor; 417 | 418 | /** 419 | * The color of the activity indicator. Defaults to [UIColor whiteColor] 420 | * Does nothing on pre iOS 5. 421 | */ 422 | @property (MB_STRONG) UIColor *activityIndicatorColor; 423 | 424 | /** 425 | * The progress of the progress indicator, from 0.0 to 1.0. Defaults to 0.0. 426 | */ 427 | @property (assign) float progress; 428 | 429 | /** 430 | * The minimum size of the HUD bezel. Defaults to CGSizeZero (no minimum size). 431 | */ 432 | @property (assign) CGSize minSize; 433 | 434 | 435 | /** 436 | * The actual size of the HUD bezel. 437 | * You can use this to limit touch handling on the bezel area only. 438 | * @see https://github.com/jdg/MBProgressHUD/pull/200 439 | */ 440 | @property (atomic, assign, readonly) CGSize size; 441 | 442 | 443 | /** 444 | * Force the HUD dimensions to be equal if possible. 445 | */ 446 | @property (assign, getter = isSquare) BOOL square; 447 | 448 | @end 449 | 450 | 451 | @protocol MBProgressHUDDelegate 452 | 453 | @optional 454 | 455 | /** 456 | * Called after the HUD was fully hidden from the screen. 457 | */ 458 | - (void)hudWasHidden:(MBProgressHUD *)hud; 459 | 460 | @end 461 | 462 | 463 | /** 464 | * A progress view for showing definite progress by filling up a circle (pie chart). 465 | */ 466 | @interface MBRoundProgressView : UIView 467 | 468 | /** 469 | * Progress (0.0 to 1.0) 470 | */ 471 | @property (nonatomic, assign) float progress; 472 | 473 | /** 474 | * Indicator progress color. 475 | * Defaults to white [UIColor whiteColor] 476 | */ 477 | @property (nonatomic, MB_STRONG) UIColor *progressTintColor; 478 | 479 | /** 480 | * Indicator background (non-progress) color. 481 | * Defaults to translucent white (alpha 0.1) 482 | */ 483 | @property (nonatomic, MB_STRONG) UIColor *backgroundTintColor; 484 | 485 | /* 486 | * Display mode - NO = round or YES = annular. Defaults to round. 487 | */ 488 | @property (nonatomic, assign, getter = isAnnular) BOOL annular; 489 | 490 | @end 491 | 492 | 493 | /** 494 | * A flat bar progress view. 495 | */ 496 | @interface MBBarProgressView : UIView 497 | 498 | /** 499 | * Progress (0.0 to 1.0) 500 | */ 501 | @property (nonatomic, assign) float progress; 502 | 503 | /** 504 | * Bar border line color. 505 | * Defaults to white [UIColor whiteColor]. 506 | */ 507 | @property (nonatomic, MB_STRONG) UIColor *lineColor; 508 | 509 | /** 510 | * Bar background color. 511 | * Defaults to clear [UIColor clearColor]; 512 | */ 513 | @property (nonatomic, MB_STRONG) UIColor *progressRemainingColor; 514 | 515 | /** 516 | * Bar progress color. 517 | * Defaults to white [UIColor whiteColor]. 518 | */ 519 | @property (nonatomic, MB_STRONG) UIColor *progressColor; 520 | 521 | @end 522 | -------------------------------------------------------------------------------- /YTEnhancerLite/YTEnhancerLite.m: -------------------------------------------------------------------------------- 1 | // 2 | // YTEnhancerLite.m 3 | // YTEnhancerLite 4 | // 5 | // Created by iMokhles on 04/04/16. 6 | // Copyright © 2016 iMokhles. All rights reserved. 7 | // 8 | 9 | #import "YTEnhancerLite.h" 10 | #import "XCDYouTubeKit.h" 11 | #import "YTProcessor.h" 12 | #import "TWRDownloadManager.h" 13 | #import "TotoaShopHelper.h" 14 | #import "DownloadsTVC.h" 15 | #import "UIAlertView+Blocks.h" 16 | #import "MBProgressHUD.h" 17 | #import "TransNSString.h" 18 | 19 | 20 | static UIWindow *currentWindow() { 21 | 22 | UIWindow *currentWindow = [UIApplication sharedApplication].keyWindow; 23 | 24 | if (!currentWindow) { 25 | NSEnumerator *frontToBackWindows = [[[UIApplication sharedApplication] windows] reverseObjectEnumerator]; 26 | 27 | for (UIWindow *window in frontToBackWindows) { 28 | if (window.windowLevel == UIWindowLevelNormal) { 29 | currentWindow = window; 30 | break; 31 | } 32 | } 33 | } 34 | 35 | return currentWindow; 36 | } 37 | BOOL isAudioFile = NO; 38 | NSTimeInterval videoDuration; 39 | id currentCellView = nil; 40 | static GOODialogActionButton *downloadButton = nil; 41 | static NSString *videoTitle = nil; 42 | static NSString *videoStaticID = nil; 43 | static _Bool isDownloadsVC = NO; 44 | static UIButton *downloadPage = nil; 45 | static NSUserDefaults *userDefaults; 46 | @implementation YTEnhancerLite 47 | 48 | + (instancetype)shareFeatures { 49 | static YTEnhancerLite *sharedInstance = nil; 50 | static dispatch_once_t onceToken; 51 | 52 | dispatch_once(&onceToken, ^{ 53 | sharedInstance = [[YTEnhancerLite alloc] init]; 54 | }); 55 | 56 | return sharedInstance; 57 | } 58 | 59 | - (id)init { 60 | if (self == [super init]) { 61 | 62 | } 63 | return self; 64 | } 65 | 66 | - (NSString *)timeFormatted:(int)totalSeconds{ 67 | 68 | int seconds = totalSeconds % 60; 69 | int minutes = (totalSeconds / 60) % 60; 70 | int hours = totalSeconds / 3600; 71 | 72 | return [NSString stringWithFormat:@"%02d:%02d:%02d",hours, minutes, seconds]; 73 | } 74 | 75 | - (NSArray *) preferredVideoQualities 76 | { 77 | return @[ XCDYouTubeVideoQualityHTTPLiveStreaming, @(XCDYouTubeVideoQualityHD1080), @(XCDYouTubeVideoQualityHD720), @(XCDYouTubeVideoQualityMedium360), @(XCDYouTubeVideoQualitySmall240) ]; 78 | } 79 | 80 | - (void)saveVideoToPlist:(XCDYouTubeVideo *)video { 81 | 82 | NSMutableArray *fileInfoArray = [userDefaults objectForKey:@"fileInfoArray"]; 83 | NSMutableDictionary *newMutableDict = [NSMutableDictionary new]; 84 | NSDictionary *newDict = nil; 85 | NSMutableArray *fileInfoArrayNEW = nil; 86 | if (!fileInfoArray) { 87 | fileInfoArray = [[NSMutableArray alloc] init]; 88 | if (isAudioFile) { 89 | [newMutableDict setObject:[NSNumber numberWithBool:YES] forKey:@"isAudio"]; 90 | } else { 91 | [newMutableDict setObject:[NSNumber numberWithBool:NO] forKey:@"isAudio"]; 92 | } 93 | [newMutableDict setObject:[NSString stringWithFormat:@"%@", video.identifier] forKey:@"videoID"]; 94 | [newMutableDict setObject:[NSString stringWithFormat:@"%@", video.mediumThumbnailURL] forKey:@"mediumThumbnailURL"]; 95 | [newMutableDict setObject:[NSString stringWithFormat:@"%@", video.title] forKey:@"videoTitle"]; 96 | [newMutableDict setObject:[NSString stringWithFormat:@"%@", [self timeFormatted:video.duration]] forKey:@"videoDuration"]; 97 | newDict = [newMutableDict copy]; 98 | [fileInfoArray addObject:newDict]; 99 | [userDefaults setObject:fileInfoArray forKey:@"fileInfoArray"]; 100 | [userDefaults synchronize]; 101 | } else { 102 | fileInfoArrayNEW = [[NSMutableArray alloc] initWithArray:fileInfoArray]; 103 | if (isAudioFile) { 104 | [newMutableDict setObject:[NSNumber numberWithBool:YES] forKey:@"isAudio"]; 105 | } else { 106 | [newMutableDict setObject:[NSNumber numberWithBool:NO] forKey:@"isAudio"]; 107 | } 108 | [newMutableDict setObject:[NSString stringWithFormat:@"%@", video.identifier] forKey:@"videoID"]; 109 | [newMutableDict setObject:[NSString stringWithFormat:@"%@", video.mediumThumbnailURL] forKey:@"mediumThumbnailURL"]; 110 | [newMutableDict setObject:[NSString stringWithFormat:@"%@", video.title] forKey:@"videoTitle"]; 111 | [newMutableDict setObject:[NSString stringWithFormat:@"%@", [self timeFormatted:video.duration]] forKey:@"videoDuration"]; 112 | newDict = [newMutableDict copy]; 113 | for (NSDictionary *dictCheck in fileInfoArray) { 114 | NSString *curHex = dictCheck[@"videoID"]; 115 | NSNumber *audioNM = dictCheck[@"isAudio"]; 116 | BOOL isAudio = [audioNM boolValue]; 117 | 118 | NSNumber *audioNewNM = newDict[@"isAudio"]; 119 | BOOL isNewAudio = [audioNewNM boolValue]; 120 | 121 | if ([curHex isEqualToString:newDict[@"videoID"]] && isAudio == isNewAudio) { 122 | return; 123 | } 124 | } 125 | [fileInfoArrayNEW addObject:newDict]; 126 | [userDefaults setObject:fileInfoArrayNEW forKey:@"fileInfoArray"]; 127 | [userDefaults synchronize]; 128 | } 129 | } 130 | - (void)getVideoInformationFromID:(NSString *)videoID forINT:(NSInteger)intger { 131 | [[XCDYouTubeClient defaultClient] getVideoWithIdentifier:videoID completionHandler:^(XCDYouTubeVideo * _Nullable video, NSError * _Nullable error) { 132 | if (video) { 133 | dispatch_async(dispatch_get_main_queue(), ^{ 134 | MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:currentWindow() animated:YES]; 135 | hud.labelText = @"Preparing"; 136 | }); 137 | videoTitle = video.title; 138 | videoStaticID = video.identifier; 139 | videoDuration = video.duration; 140 | NSURL *streamVideoURL = nil; 141 | NSURL *streamAudioURL = nil; 142 | if (intger == 0) { 143 | isAudioFile = NO; 144 | streamVideoURL = video.streamURLs[[NSNumber numberWithInt:XCDYouTubeVideoQualityHD720]]; 145 | } else if (intger == 1) { 146 | isAudioFile = NO; 147 | streamVideoURL = video.streamURLs[[NSNumber numberWithInt:XCDYouTubeVideoQualityMedium360]]; 148 | } else if (intger == 2) { 149 | isAudioFile = YES; 150 | streamVideoURL = video.streamURLs[[NSNumber numberWithInt:XCDYouTubeAudioOnly140]]; 151 | } 152 | streamAudioURL = video.streamURLs[[NSNumber numberWithInt:XCDYouTubeAudioOnly140]]; 153 | NSURL *midURL = streamVideoURL; 154 | if(midURL == nil){ 155 | midURL = [[video.streamURLs objectEnumerator] nextObject]; 156 | } 157 | NSString *filePath; 158 | 159 | if (intger == 0 || intger == 1) { 160 | filePath = [[TotoaShopHelper getDownloadsPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"mp4/%@-%@.mp4", video.title, video.identifier]]; 161 | } else { 162 | filePath = [[TotoaShopHelper getDownloadsPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"m4a/%@-%@.m4a", video.title, video.identifier]]; 163 | } 164 | if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) { 165 | [self saveVideoToPlist:video]; 166 | NSURLRequest *req = [NSURLRequest requestWithURL:midURL];//[NSURL URLWithString:]]; 167 | NSURLConnection *conn = [NSURLConnection connectionWithRequest:req delegate:self]; 168 | [conn start]; 169 | } else { 170 | [UIAlertView showWithTitle:@"YTEnhancer (WARNING)" message:@"Video downloaded already !!" cancelButtonTitle:@"Ok" otherButtonTitles:nil tapBlock:^(UIAlertView * _Nonnull alertView, NSInteger buttonIndex) { 171 | dispatch_async(dispatch_get_main_queue(), ^{ 172 | MBProgressHUD *hud = [MBProgressHUD HUDForView:currentWindow()]; 173 | hud.labelText = @"Failed"; 174 | [hud hide:YES afterDelay:3.f]; 175 | }); 176 | }]; 177 | 178 | } 179 | NSLog(@"*********** \n%@\n\n%@\nDuration: %@\n", streamAudioURL, streamVideoURL, [self timeFormatted:video.duration]); 180 | 181 | } 182 | 183 | }]; 184 | } 185 | - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 186 | NSString *mime = [response MIMEType]; 187 | NSString *urlToDOwnload = response.URL.absoluteString; 188 | CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef)(mime), NULL); 189 | CFStringRef extension = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension); 190 | NSString *fileExtension = (NSString *)CFBridgingRelease(extension); 191 | 192 | NSString *savedPath; 193 | if (isAudioFile == NO) { 194 | savedPath = [NSString stringWithFormat:@"%@-%@.%@",videoTitle, videoStaticID, [NSString stringWithFormat:@"%@",fileExtension]]; 195 | } else { 196 | savedPath = [NSString stringWithFormat:@"%@-%@.m4a",videoTitle, videoStaticID]; 197 | } 198 | 199 | TWRDownloadManager *downloadManager = [TWRDownloadManager sharedManager]; 200 | [downloadManager downloadFileForURL:urlToDOwnload withName:savedPath inDirectoryNamed:nil progressBlock:^(CGFloat progress) { 201 | // 202 | dispatch_async(dispatch_get_main_queue(), ^{ 203 | MBProgressHUD *hud = [MBProgressHUD HUDForView:currentWindow()]; 204 | hud.labelText = @"Downloading..."; 205 | hud.mode = MBProgressHUDModeDeterminate; 206 | hud.progress = progress; 207 | }); 208 | } completionBlock:^(BOOL completed) { 209 | // 210 | dispatch_async(dispatch_get_main_queue(), ^{ 211 | MBProgressHUD *hud = [MBProgressHUD HUDForView:currentWindow()]; 212 | hud.labelText = @"Completed..."; 213 | hud.mode = MBProgressHUDModeIndeterminate; 214 | [hud hide:YES afterDelay:3.f]; 215 | }); 216 | videoTitle = nil; 217 | } enableBackgroundMode:YES]; 218 | 219 | } 220 | - (void)handleAction:(SEL)selector fromTarget:(id)target { 221 | [target performSelector:selector]; 222 | } 223 | 224 | - (void)openDownloadsPage { 225 | 226 | DownloadsTVC *dwnsVC = [[DownloadsTVC alloc] initWithStyle:UITableViewStylePlain]; 227 | UINavigationController *dwnsNVC = [[UINavigationController alloc] initWithRootViewController:dwnsVC]; 228 | dwnsNVC.modalPresentationStyle = UIModalPresentationFormSheet; 229 | [[[UIApplication sharedApplication] windows][0].rootViewController presentViewController:dwnsNVC animated:YES completion:^{ 230 | 231 | }]; 232 | } 233 | 234 | @end 235 | 236 | hook(GOOActionSheetController) 237 | - (void)popoverViewControllerDidCancel:(id)arg1 { 238 | NSLog(@"********* popoverViewControllerDidCancel"); 239 | downloadButton = nil; 240 | _orig(void, arg1); 241 | } 242 | - (void)dismiss { 243 | NSLog(@"********* dismiss"); 244 | downloadButton = nil; 245 | _orig(void); 246 | } 247 | - (void)addAction:(id)arg1 { 248 | NSLog(@"********* addAction"); 249 | _orig(void, arg1); 250 | } 251 | - (void)present { 252 | NSLog(@"********* addAction"); 253 | _orig(void); 254 | id btnSuperView = [[(GOOActionSheetController *)self sourceView] superview]; 255 | if ([btnSuperView isKindOfClass:NSClassFromString(@"YTVideoView")] || [[btnSuperView superview] isKindOfClass:objc_getClass("YTVideoCell")] || [[btnSuperView superview] isKindOfClass:objc_getClass("YTGridVideoCell")] || [btnSuperView isKindOfClass:NSClassFromString(@"YTGridVideoView")] || [btnSuperView isKindOfClass:NSClassFromString(@"YTCompactVideoView")]) { 256 | 257 | UIImage *downloadImage = [UIImage imageNamed:@"downbutton"]; // won't appear ;) 258 | UIImage *downloadResized = [downloadImage imageByScalingToSize:CGSizeMake(24, 24)]; 259 | [self addAction:[objc_getClass("GOOAction") actionWithTitle:[NSString translateToAR:@"صفحة التحميلات" toCA:nil toCS:nil toDA:nil toDE:nil toEL:nil toEN:@"Downloads Page" toEN_AU:nil toEN_GB:nil toES:nil toES_MX:nil toFI:nil toFR:nil toFR_CA:nil toHE:nil toHI:nil toHR:nil toHU:nil toID:nil toIT:nil toJA:nil toKO:nil toMS:nil toNL:nil toNO:nil toPL:nil toPT:nil toPT_PT:nil toRO:nil toRU:nil toSK:nil toSV:nil toTH:nil toTR:nil toUK:nil toVI:nil toZH_CN:nil toZH_HK:nil toZH_TW:nil] iconImage:downloadResized style:1 handler:^{ 260 | [[YTEnhancerLite shareFeatures] openDownloadsPage]; 261 | 262 | }]]; 263 | 264 | [self addAction:[objc_getClass("GOOAction") actionWithTitle:[NSString translateToAR:@"HD720 تحميل جودة" toCA:nil toCS:nil toDA:nil toDE:nil toEL:nil toEN:@"Download 720HD" toEN_AU:nil toEN_GB:nil toES:nil toES_MX:nil toFI:nil toFR:nil toFR_CA:nil toHE:nil toHI:nil toHR:nil toHU:nil toID:nil toIT:nil toJA:nil toKO:nil toMS:nil toNL:nil toNO:nil toPL:nil toPT:nil toPT_PT:nil toRO:nil toRU:nil toSK:nil toSV:nil toTH:nil toTR:nil toUK:nil toVI:nil toZH_CN:nil toZH_HK:nil toZH_TW:nil] iconImage:downloadResized style:1 handler:^{ 265 | NSString *videoPreID = nil; 266 | if ([[(GOOActionSheetController *)self sourceView] isKindOfClass:objc_getClass("YTButton")]) { 267 | if ([btnSuperView isKindOfClass:NSClassFromString(@"YTVideoView")]) { 268 | YTVideoCell *videoCell = (YTVideoCell *)[(YTVideoView *)btnSuperView superview].superview; 269 | YTIVideoRenderer *videoRenderer = [videoCell valueForKey:@"_videoRenderer"]; 270 | videoPreID = videoRenderer.videoId; 271 | NSLog(@"FOUND1: %@\nVideID: %@", NSStringFromClass([videoCell class]), videoRenderer.videoId); 272 | } else if ([btnSuperView isKindOfClass:NSClassFromString(@"YTGridVideoView")]) { 273 | YTGridVideoView *videoGridView = btnSuperView; 274 | YTIGridVideoRenderer *videoGridRenderer = [videoGridView valueForKey:@"_entry"]; 275 | videoPreID = videoGridRenderer.videoId; 276 | // YTGridVideoCell *videoGridCell = (YTGridVideoCell *)[(YTGridVideoView *)btnSuperView superview]; 277 | NSLog(@"FOUND2: %@\nVideID: %@", NSStringFromClass([videoGridView class]), videoGridRenderer.videoId); 278 | } else if ([btnSuperView isKindOfClass:NSClassFromString(@"YTCompactVideoView")]) { 279 | YTCompactVideoView *videoCompactView = btnSuperView; 280 | YTICompactVideoRenderer *videoCompactRenderer = [videoCompactView valueForKey:@"_renderer"]; 281 | videoPreID = videoCompactRenderer.videoId; 282 | // YTGridVideoCell *videoGridCell = (YTGridVideoCell *)[(YTGridVideoView *)btnSuperView superview]; 283 | NSLog(@"FOUND2: %@\nVideID: %@", NSStringFromClass([videoCompactView class]), videoCompactRenderer.videoId); 284 | } 285 | } else { 286 | NSLog(@"FOUND3: %@", NSStringFromClass([btnSuperView class])); // UIView 287 | NSLog(@"FOUND4: %@", NSStringFromClass([[btnSuperView superview] class])); // YTGridVideoCell || YTVideoCell 288 | 289 | if ([[btnSuperView superview] isKindOfClass:objc_getClass("YTVideoCell")]) { 290 | YTVideoCell *videoCell = (YTVideoCell *)[btnSuperView superview]; 291 | YTIVideoRenderer *videoRenderer = [videoCell valueForKey:@"_videoRenderer"]; 292 | videoPreID = videoRenderer.videoId; 293 | } else if ([[btnSuperView superview] isKindOfClass:objc_getClass("YTGridVideoCell")]) { 294 | YTGridVideoCell *videoGridCell = (YTGridVideoCell *)[btnSuperView superview]; 295 | YTGridVideoView *videoGridView = (YTGridVideoView *)videoGridCell.gridView; 296 | YTIGridVideoRenderer *videoGridRenderer = [videoGridView valueForKey:@"_entry"]; 297 | videoPreID = videoGridRenderer.videoId; 298 | } else if ([btnSuperView isKindOfClass:NSClassFromString(@"YTCompactVideoCell")]) { 299 | YTCompactVideoView *videoCompactView = [btnSuperView valueForKey:@"_videoView"]; 300 | YTICompactVideoRenderer *videoCompactRenderer = [videoCompactView valueForKey:@"_renderer"]; 301 | videoPreID = videoCompactRenderer.videoId; 302 | // YTGridVideoCell *videoGridCell = (YTGridVideoCell *)[(YTGridVideoView *)btnSuperView superview]; 303 | NSLog(@"FOUND2: %@\nVideID: %@", NSStringFromClass([videoCompactView class]), videoCompactRenderer.videoId); 304 | } 305 | } 306 | [[YTEnhancerLite shareFeatures] getVideoInformationFromID:videoPreID forINT:0]; 307 | 308 | }]]; 309 | 310 | [self addAction:[objc_getClass("GOOAction") actionWithTitle:[NSString translateToAR:@"تحميل جودة 360" toCA:nil toCS:nil toDA:nil toDE:nil toEL:nil toEN:@"Download 360" toEN_AU:nil toEN_GB:nil toES:nil toES_MX:nil toFI:nil toFR:nil toFR_CA:nil toHE:nil toHI:nil toHR:nil toHU:nil toID:nil toIT:nil toJA:nil toKO:nil toMS:nil toNL:nil toNO:nil toPL:nil toPT:nil toPT_PT:nil toRO:nil toRU:nil toSK:nil toSV:nil toTH:nil toTR:nil toUK:nil toVI:nil toZH_CN:nil toZH_HK:nil toZH_TW:nil] iconImage:downloadResized style:1 handler:^{ 311 | NSString *videoPreID = nil; 312 | if ([[(GOOActionSheetController *)self sourceView] isKindOfClass:objc_getClass("YTButton")]) { 313 | if ([btnSuperView isKindOfClass:NSClassFromString(@"YTVideoView")]) { 314 | YTVideoCell *videoCell = (YTVideoCell *)[(YTVideoView *)btnSuperView superview].superview; 315 | YTIVideoRenderer *videoRenderer = [videoCell valueForKey:@"_videoRenderer"]; 316 | videoPreID = videoRenderer.videoId; 317 | NSLog(@"FOUND1: %@\nVideID: %@", NSStringFromClass([videoCell class]), videoRenderer.videoId); 318 | } else if ([btnSuperView isKindOfClass:NSClassFromString(@"YTGridVideoView")]) { 319 | YTGridVideoView *videoGridView = btnSuperView; 320 | YTIGridVideoRenderer *videoGridRenderer = [videoGridView valueForKey:@"_entry"]; 321 | videoPreID = videoGridRenderer.videoId; 322 | // YTGridVideoCell *videoGridCell = (YTGridVideoCell *)[(YTGridVideoView *)btnSuperView superview]; 323 | NSLog(@"FOUND2: %@\nVideID: %@", NSStringFromClass([videoGridView class]), videoGridRenderer.videoId); 324 | } else if ([btnSuperView isKindOfClass:NSClassFromString(@"YTCompactVideoView")]) { 325 | YTCompactVideoView *videoCompactView = btnSuperView; 326 | YTICompactVideoRenderer *videoCompactRenderer = [videoCompactView valueForKey:@"_renderer"]; 327 | videoPreID = videoCompactRenderer.videoId; 328 | // YTGridVideoCell *videoGridCell = (YTGridVideoCell *)[(YTGridVideoView *)btnSuperView superview]; 329 | NSLog(@"FOUND2: %@\nVideID: %@", NSStringFromClass([videoCompactView class]), videoCompactRenderer.videoId); 330 | } 331 | } else { 332 | NSLog(@"FOUND3: %@", NSStringFromClass([btnSuperView class])); // UIView 333 | NSLog(@"FOUND4: %@", NSStringFromClass([[btnSuperView superview] class])); // YTGridVideoCell || YTVideoCell 334 | 335 | if ([[btnSuperView superview] isKindOfClass:objc_getClass("YTVideoCell")]) { 336 | YTVideoCell *videoCell = (YTVideoCell *)[btnSuperView superview]; 337 | YTIVideoRenderer *videoRenderer = [videoCell valueForKey:@"_videoRenderer"]; 338 | videoPreID = videoRenderer.videoId; 339 | } else if ([[btnSuperView superview] isKindOfClass:objc_getClass("YTGridVideoCell")]) { 340 | YTGridVideoCell *videoGridCell = (YTGridVideoCell *)[btnSuperView superview]; 341 | YTGridVideoView *videoGridView = (YTGridVideoView *)videoGridCell.gridView; 342 | YTIGridVideoRenderer *videoGridRenderer = [videoGridView valueForKey:@"_entry"]; 343 | videoPreID = videoGridRenderer.videoId; 344 | } else if ([btnSuperView isKindOfClass:NSClassFromString(@"YTCompactVideoCell")]) { 345 | YTCompactVideoView *videoCompactView = [btnSuperView valueForKey:@"_videoView"]; 346 | YTICompactVideoRenderer *videoCompactRenderer = [videoCompactView valueForKey:@"_renderer"]; 347 | videoPreID = videoCompactRenderer.videoId; 348 | // YTGridVideoCell *videoGridCell = (YTGridVideoCell *)[(YTGridVideoView *)btnSuperView superview]; 349 | NSLog(@"FOUND2: %@\nVideID: %@", NSStringFromClass([videoCompactView class]), videoCompactRenderer.videoId); 350 | } 351 | } 352 | [[YTEnhancerLite shareFeatures] getVideoInformationFromID:videoPreID forINT:1]; 353 | 354 | }]]; 355 | [self addAction:[objc_getClass("GOOAction") actionWithTitle:[NSString translateToAR:@"تحميل صوت" toCA:nil toCS:nil toDA:nil toDE:nil toEL:nil toEN:@"Download Audio" toEN_AU:nil toEN_GB:nil toES:nil toES_MX:nil toFI:nil toFR:nil toFR_CA:nil toHE:nil toHI:nil toHR:nil toHU:nil toID:nil toIT:nil toJA:nil toKO:nil toMS:nil toNL:nil toNO:nil toPL:nil toPT:nil toPT_PT:nil toRO:nil toRU:nil toSK:nil toSV:nil toTH:nil toTR:nil toUK:nil toVI:nil toZH_CN:nil toZH_HK:nil toZH_TW:nil] iconImage:downloadResized style:1 handler:^{ 356 | NSString *videoPreID = nil; 357 | if ([[(GOOActionSheetController *)self sourceView] isKindOfClass:objc_getClass("YTButton")]) { 358 | if ([btnSuperView isKindOfClass:NSClassFromString(@"YTVideoView")]) { 359 | YTVideoCell *videoCell = (YTVideoCell *)[(YTVideoView *)btnSuperView superview].superview; 360 | YTIVideoRenderer *videoRenderer = [videoCell valueForKey:@"_videoRenderer"]; 361 | videoPreID = videoRenderer.videoId; 362 | NSLog(@"FOUND1: %@\nVideID: %@", NSStringFromClass([videoCell class]), videoRenderer.videoId); 363 | } else if ([btnSuperView isKindOfClass:NSClassFromString(@"YTGridVideoView")]) { 364 | YTGridVideoView *videoGridView = btnSuperView; 365 | YTIGridVideoRenderer *videoGridRenderer = [videoGridView valueForKey:@"_entry"]; 366 | videoPreID = videoGridRenderer.videoId; 367 | // YTGridVideoCell *videoGridCell = (YTGridVideoCell *)[(YTGridVideoView *)btnSuperView superview]; 368 | NSLog(@"FOUND2: %@\nVideID: %@", NSStringFromClass([videoGridView class]), videoGridRenderer.videoId); 369 | } else if ([btnSuperView isKindOfClass:NSClassFromString(@"YTCompactVideoView")]) { 370 | YTCompactVideoView *videoCompactView = btnSuperView; 371 | YTICompactVideoRenderer *videoCompactRenderer = [videoCompactView valueForKey:@"_renderer"]; 372 | videoPreID = videoCompactRenderer.videoId; 373 | // YTGridVideoCell *videoGridCell = (YTGridVideoCell *)[(YTGridVideoView *)btnSuperView superview]; 374 | NSLog(@"FOUND2: %@\nVideID: %@", NSStringFromClass([videoCompactView class]), videoCompactRenderer.videoId); 375 | } 376 | } else { 377 | NSLog(@"FOUND3: %@", NSStringFromClass([btnSuperView class])); // UIView 378 | NSLog(@"FOUND4: %@", NSStringFromClass([[btnSuperView superview] class])); // YTGridVideoCell || YTVideoCell 379 | 380 | if ([[btnSuperView superview] isKindOfClass:objc_getClass("YTVideoCell")]) { 381 | YTVideoCell *videoCell = (YTVideoCell *)[btnSuperView superview]; 382 | YTIVideoRenderer *videoRenderer = [videoCell valueForKey:@"_videoRenderer"]; 383 | videoPreID = videoRenderer.videoId; 384 | } else if ([[btnSuperView superview] isKindOfClass:objc_getClass("YTGridVideoCell")]) { 385 | YTGridVideoCell *videoGridCell = (YTGridVideoCell *)[btnSuperView superview]; 386 | YTGridVideoView *videoGridView = (YTGridVideoView *)videoGridCell.gridView; 387 | YTIGridVideoRenderer *videoGridRenderer = [videoGridView valueForKey:@"_entry"]; 388 | videoPreID = videoGridRenderer.videoId; 389 | } else if ([btnSuperView isKindOfClass:NSClassFromString(@"YTCompactVideoCell")]) { 390 | YTCompactVideoView *videoCompactView = [btnSuperView valueForKey:@"_videoView"]; 391 | YTICompactVideoRenderer *videoCompactRenderer = [videoCompactView valueForKey:@"_renderer"]; 392 | videoPreID = videoCompactRenderer.videoId; 393 | // YTGridVideoCell *videoGridCell = (YTGridVideoCell *)[(YTGridVideoView *)btnSuperView superview]; 394 | NSLog(@"FOUND2: %@\nVideID: %@", NSStringFromClass([videoCompactView class]), videoCompactRenderer.videoId); 395 | } 396 | } 397 | [[YTEnhancerLite shareFeatures] getVideoInformationFromID:videoPreID forINT:2]; 398 | 399 | }]]; 400 | } 401 | } 402 | endhook 403 | 404 | hook(YTIPlayabilityStatus) 405 | - (_Bool)playableInBackground { 406 | return YES; 407 | } 408 | - (_Bool)playableOffline { 409 | return YES; 410 | } 411 | - (_Bool)hasOfflineability { 412 | return YES; 413 | } 414 | - (_Bool)hasPlayableInBackground { 415 | return YES; 416 | } 417 | - (_Bool)isPlayableInBackground { 418 | return YES; 419 | } 420 | - (_Bool)hasBackgroundability { // new background check 421 | return YES; 422 | } 423 | - (_Bool)hasOfflineability { // offline videos 424 | return YES; 425 | } 426 | endhook 427 | 428 | hook(MLAVPlayer) 429 | - (_Bool)backgroundPlaybackAllowed { 430 | return YES; 431 | } 432 | endhook 433 | 434 | hook(MLEXOPlayer) 435 | - (_Bool)backgroundPlaybackAllowed { 436 | return YES; 437 | } 438 | endhook 439 | 440 | ctor { 441 | userDefaults = [NSUserDefaults standardUserDefaults]; 442 | } 443 | 444 | -------------------------------------------------------------------------------- /YTEnhancerLite/YTEnhancerLite.h: -------------------------------------------------------------------------------- 1 | // 2 | // YTEnhancerLite.h 3 | // YTEnhancerLite 4 | // 5 | // Created by iMokhles on 04/04/16. 6 | // Copyright © 2016 iMokhles. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | #import "iMoMacros.h" 13 | #import "ZKSwizzle.h" 14 | #import "fakelogos.h" 15 | 16 | @interface YTEnhancerLite : NSObject 17 | 18 | @end 19 | 20 | #pragma mark - Youtube 21 | 22 | @interface QTMColorGroup : NSObject 23 | { 24 | unsigned long long _numTones; 25 | long long _groupID; 26 | UIColor *_bodyTextColor; 27 | UIColor *_bodyTextColorOnLightestColor; 28 | UIColor *_bodyTextColorOnLighterColor; 29 | UIColor *_bodyTextColorOnRegularColor; 30 | UIColor *_bodyTextColorOnDarkerColor; 31 | UIColor *_bodyTextColorOnAccentColor; 32 | UIColor *_bodyTextColorOnBrightAccentColor; 33 | UIColor *_lightBodyTextColor; 34 | UIColor *_buttonBackgroundColor; 35 | UIColor *_buttonDisabledBackgroundColorDark; 36 | UIColor *_buttonDisabledBackgroundColorLight; 37 | UIColor *_buttonActionTextColor; 38 | UIColor *_buttonTextColor; 39 | UIColor *_buttonInkColor; 40 | } 41 | 42 | + (double)minContrastRatioForOptions:(unsigned long long)arg1; 43 | + (id)exceptionColorFromChoices:(id)arg1 onColor:(id)arg2 options:(unsigned long long)arg3; 44 | + (id)bodyTextColorOnBackgroundImage:(id)arg1 inRegion:(struct CGRect)arg2 withFont:(id)arg3; 45 | + (id)bodyTextColorOnBackgroundImage:(id)arg1 withFont:(id)arg2; 46 | + (id)bodyTextColorOnColor:(id)arg1 withFont:(id)arg2; 47 | + (_Bool)supportsSecureCoding; 48 | + (double)minAlphaOfColor:(id)arg1 onColor:(id)arg2 options:(unsigned long long)arg3; 49 | + (double)luminanceOfColor:(id)arg1; 50 | + (id)textColorOnColor:(id)arg1 textAlpha:(double)arg2 font:(id)arg3; 51 | + (id)textColorOnColor:(id)arg1 textAlpha:(double)arg2 options:(unsigned long long)arg3; 52 | + (id)textColorFromChoices:(id)arg1 onColor:(id)arg2 options:(unsigned long long)arg3; 53 | + (double)contrastRatioForColor:(id)arg1 onColor:(id)arg2; 54 | + (_Bool)colorToneIsAccent:(long long)arg1; 55 | + (_Bool)colorToneIsTint:(long long)arg1; 56 | + (id)colorGroupFromTargetColor:(id)arg1 checkStandardGroups:(_Bool)arg2; 57 | + (id)colorGroupFromTargetColor:(id)arg1; 58 | + (id)colorGroupWithName:(id)arg1; 59 | + (id)colorGroupWithID:(long long)arg1; 60 | + (id)clearColors; 61 | + (id)googleYellowColors; 62 | + (id)googleGreenColors; 63 | + (id)googleRedColors; 64 | + (id)googleBlueColors; 65 | + (id)greyColors; 66 | + (id)whiteColors; 67 | + (void)initialize; 68 | @property(readonly, nonatomic) UIColor *buttonInkColor; // @synthesize buttonInkColor=_buttonInkColor; 69 | @property(readonly, nonatomic) UIColor *buttonTextColor; // @synthesize buttonTextColor=_buttonTextColor; 70 | @property(readonly, nonatomic) UIColor *buttonActionTextColor; // @synthesize buttonActionTextColor=_buttonActionTextColor; 71 | @property(readonly, nonatomic) UIColor *buttonDisabledBackgroundColorLight; // @synthesize buttonDisabledBackgroundColorLight=_buttonDisabledBackgroundColorLight; 72 | @property(readonly, nonatomic) UIColor *buttonDisabledBackgroundColorDark; // @synthesize buttonDisabledBackgroundColorDark=_buttonDisabledBackgroundColorDark; 73 | @property(readonly, nonatomic) UIColor *buttonBackgroundColor; // @synthesize buttonBackgroundColor=_buttonBackgroundColor; 74 | @property(readonly, nonatomic) UIColor *lightBodyTextColor; // @synthesize lightBodyTextColor=_lightBodyTextColor; 75 | @property(readonly, nonatomic) UIColor *bodyTextColorOnBrightAccentColor; // @synthesize bodyTextColorOnBrightAccentColor=_bodyTextColorOnBrightAccentColor; 76 | @property(readonly, nonatomic) UIColor *bodyTextColorOnAccentColor; // @synthesize bodyTextColorOnAccentColor=_bodyTextColorOnAccentColor; 77 | @property(readonly, nonatomic) UIColor *bodyTextColorOnDarkerColor; // @synthesize bodyTextColorOnDarkerColor=_bodyTextColorOnDarkerColor; 78 | @property(readonly, nonatomic) UIColor *bodyTextColorOnRegularColor; // @synthesize bodyTextColorOnRegularColor=_bodyTextColorOnRegularColor; 79 | @property(readonly, nonatomic) UIColor *bodyTextColorOnLighterColor; // @synthesize bodyTextColorOnLighterColor=_bodyTextColorOnLighterColor; 80 | @property(readonly, nonatomic) UIColor *bodyTextColorOnLightestColor; // @synthesize bodyTextColorOnLightestColor=_bodyTextColorOnLightestColor; 81 | @property(readonly, nonatomic) UIColor *bodyTextColor; // @synthesize bodyTextColor=_bodyTextColor; 82 | @property(readonly, nonatomic) long long groupID; // @synthesize groupID=_groupID; 83 | - (void)initBodyTextColors; 84 | - (void)initButtonColors; 85 | - (_Bool)hasAccentColors; 86 | - (id)colorWithTone:(long long)arg1; 87 | - (id)lightBodyTextColorOnColor:(id)arg1 withFont:(id)arg2; 88 | - (id)lightBodyTextColorOnTone:(long long)arg1 withFont:(id)arg2; 89 | - (id)bodyTextColorOnTone:(long long)arg1 withFont:(id)arg2; 90 | - (id)bodyTextColorOnDarkerColorWithFont:(id)arg1; 91 | - (id)bodyTextColorOnRegularColorWithFont:(id)arg1; 92 | - (id)bodyTextColorOnLighterColorWithFont:(id)arg1; 93 | - (id)bodyTextColorOnLightestColorWithFont:(id)arg1; 94 | - (void)encodeWithCoder:(id)arg1; 95 | - (id)initWithCoder:(id)arg1; 96 | @property(readonly, nonatomic) NSString *name; 97 | @property(readonly, nonatomic) UIColor *statusBarColor; 98 | @property(readonly, nonatomic) UIColor *brightAccentColor; 99 | @property(readonly, nonatomic) UIColor *accentColor; 100 | @property(readonly, nonatomic) UIColor *darkerColor; 101 | @property(readonly, nonatomic) UIColor *regularColor; 102 | @property(readonly, nonatomic) UIColor *lighterColor; 103 | @property(readonly, nonatomic) UIColor *lightestColor; 104 | - (_Bool)isEqual:(id)arg1; 105 | - (id)description; 106 | - (void)dealloc; 107 | - (id)initWithName:(id)arg1; 108 | - (id)initWithTargetColor:(id)arg1 checkStandardGroups:(_Bool)arg2; 109 | - (id)initWithPredefinedColorGroupID:(long long)arg1; 110 | - (id)init; 111 | 112 | @end 113 | 114 | @interface PBRootObject : NSObject 115 | @end 116 | 117 | @interface PBGeneratedMessage : PBRootObject 118 | @end 119 | 120 | @interface PBArray : NSObject 121 | - (id)lastObject; 122 | - (id)firstObject; 123 | - (id)objectAtIndexedSubscript:(unsigned long long)arg1; 124 | - (id)objectAtIndex:(unsigned long long)arg1; 125 | - (id)valueForKey:(id)arg1; 126 | - (id)initWithInt32:(int)arg1; 127 | - (id)initWithObject:(id)arg1; 128 | - (id)initWithArray:(id)arg1 valueType:(int)arg2; 129 | - (id)initWithValues:(const void *)arg1 count:(unsigned long long)arg2 valueType:(int)arg3; 130 | - (id)initWithValueType:(int)arg1; 131 | - (id)arrayByAppendingArray:(id)arg1; 132 | + (id)arrayWithInt32s:(int)arg1; 133 | + (id)arrayWithInt32:(int)arg1; 134 | + (id)arrayWithObjects:(id)arg1; 135 | + (id)arrayWithObject:(id)arg1; 136 | + (id)arrayWithArray:(id)arg1 valueType:(int)arg2; 137 | + (id)arrayWithValues:(const void *)arg1 count:(unsigned long long)arg2 valueType:(int)arg3; 138 | + (id)arrayWithValueType:(int)arg1; 139 | @end 140 | 141 | @interface PBMutableArray : PBArray 142 | + (id)arrayWithValueType:(int)arg1 capacity:(unsigned long long)arg2; 143 | - (void)appendValues:(const void *)arg1 valueType:(int)arg2 count:(unsigned long long)arg3; 144 | - (void)removeAllValues; 145 | - (void)setArray:(id)arg1; 146 | - (void)replaceDoubleAtIndex:(unsigned long long)arg1 withDouble:(double)arg2; 147 | - (void)replaceFloatAtIndex:(unsigned long long)arg1 withFloat:(float)arg2; 148 | - (void)replaceUInt64AtIndex:(unsigned long long)arg1 withUInt64:(unsigned long long)arg2; 149 | - (void)replaceInt64AtIndex:(unsigned long long)arg1 withInt64:(long long)arg2; 150 | - (void)replaceUInt32AtIndex:(unsigned long long)arg1 withUInt32:(unsigned int)arg2; 151 | - (void)replaceInt32AtIndex:(unsigned long long)arg1 withInt32:(int)arg2; 152 | - (void)replaceBoolAtIndex:(unsigned long long)arg1 withBool:(_Bool)arg2; 153 | - (void)setObject:(id)arg1 atIndexedSubscript:(unsigned long long)arg2; 154 | - (void)replaceObjectAtIndex:(unsigned long long)arg1 withObject:(id)arg2; 155 | - (void)addDouble:(double)arg1; 156 | - (void)addFloat:(float)arg1; 157 | - (void)addUInt64:(unsigned long long)arg1; 158 | - (void)addInt64:(long long)arg1; 159 | - (void)addUInt32:(unsigned int)arg1; 160 | - (void)addInt32:(int)arg1; 161 | - (void)addBool:(_Bool)arg1; 162 | - (void)addObject:(id)arg1; 163 | 164 | @end 165 | 166 | @interface YTIThumbnailDetails : PBGeneratedMessage 167 | @property(nonatomic) _Bool hasPlaceholderColor; // @dynamic hasPlaceholderColor; 168 | @property(nonatomic) _Bool hasThumbnailsArray; // @dynamic hasThumbnailsArray; 169 | @property(nonatomic) unsigned int placeholderColor; // @dynamic placeholderColor; 170 | @property(retain, nonatomic) PBMutableArray *thumbnailsArray; // @dynamic thumbnailsArray; 171 | @end 172 | 173 | @interface YTIFormattedString : PBGeneratedMessage 174 | @property(nonatomic) _Bool hasAccessibility; // @dynamic hasAccessibility; 175 | @property(nonatomic) _Bool hasRtl; // @dynamic hasRtl; 176 | @property(nonatomic) _Bool hasRunsArray; // @dynamic hasRunsArray; 177 | @property(nonatomic) _Bool rtl; // @dynamic rtl; 178 | @property(retain, nonatomic) PBMutableArray *runsArray; // @dynamic runsArray; 179 | @end 180 | 181 | @interface YTIVideoRenderer : PBGeneratedMessage 182 | - (_Bool)isLive; 183 | @property(retain, nonatomic) YTIFormattedString *title; // @dynamic title; 184 | @property(retain, nonatomic) YTIThumbnailDetails *thumbnail; // @dynamic thumbnail; 185 | @property(retain, nonatomic) NSString *videoId; // @dynamic videoId; 186 | @end 187 | 188 | @interface YTIGridVideoRenderer : PBGeneratedMessage 189 | @property(retain, nonatomic) YTIFormattedString *title; // @dynamic title; 190 | @property(retain, nonatomic) YTIThumbnailDetails *thumbnail; // @dynamic thumbnail; 191 | @property(retain, nonatomic) NSString *videoId; // @dynamic videoId; 192 | @end 193 | 194 | @interface YTIVideoWithContextRenderer : PBGeneratedMessage 195 | @property(retain, nonatomic) YTIThumbnailDetails *thumbnail; // @dynamic thumbnail; 196 | @property(retain, nonatomic) NSString *videoId; // @dynamic videoId; 197 | @property(retain, nonatomic) YTIFormattedString *headline; // @dynamic headline; 198 | @end 199 | 200 | @interface YTCollectionViewCell : UICollectionViewCell 201 | @property(nonatomic, getter=isHighlightable) _Bool highlightable; // @synthesize highlightable=_highlightable; 202 | @property(nonatomic, getter=isSelectable) _Bool selectable; // @synthesize selectable=_selectable; 203 | @property(nonatomic) int cellSeparatorStyle; // @synthesize cellSeparatorStyle=_cellSeparatorStyle; 204 | @property(nonatomic) int cellBackgroundStyle; // @synthesize cellBackgroundStyle=_cellBackgroundStyle; 205 | @end 206 | 207 | @interface YTButton : UIButton 208 | //+ (id)buttonWithType:(long long)arg1; 209 | @property(nonatomic) double buttonImageTitlePadding; // @synthesize buttonImageTitlePadding=_buttonImageTitlePadding; 210 | @property(nonatomic) double verticalContentPadding; // @synthesize verticalContentPadding=_verticalContentPadding; 211 | @property(nonatomic) double horizontalContentPadding; // @synthesize horizontalContentPadding=_horizontalContentPadding; 212 | @property(nonatomic) double minHitTargetSize; // @synthesize minHitTargetSize=_minHitTargetSize; 213 | - (void)applyTypeStyle; 214 | - (void)traitCollectionDidChange:(id)arg1; 215 | - (void)setTitleTypeKind:(long long)arg1 typeVariant:(long long)arg2; 216 | - (void)setTitleTypeKind:(long long)arg1; 217 | - (void)enableHitTargetDebugging; 218 | - (void)setButtonLayoutStyle:(long long)arg1; 219 | - (struct CGSize)sizeThatFits:(struct CGSize)arg1; 220 | - (struct CGRect)accessibilityFrame; 221 | - (_Bool)pointInside:(struct CGPoint)arg1 withEvent:(id)arg2; 222 | - (id)initWithDefaultImageTitlePadding; 223 | - (id)initWithFrame:(struct CGRect)arg1; 224 | @end 225 | 226 | @protocol YTGridItem 227 | + (double)preferredHeightForWidth:(double)arg1 entry:(id)arg2; 228 | @property(retain, nonatomic) id entry; 229 | - (void)setHighlighted:(_Bool)arg1; 230 | @end 231 | 232 | @interface YTGridBaseView : UIView 233 | - (void)removeLongPressTarget; 234 | - (void)setLongPressTarget:(id)arg1 action:(SEL)arg2; 235 | - (void)removeActionTarget; 236 | - (void)setActionTarget:(id)arg1 action:(SEL)arg2; 237 | @end 238 | 239 | @interface YTGridVideoView : YTGridBaseView { 240 | YTIGridVideoRenderer *_entry; 241 | } 242 | @end 243 | 244 | @interface YTVideoView : UIView 245 | - (void)removeLongPressTarget; 246 | - (void)setLongPressTarget:(id)arg1 action:(SEL)arg2; 247 | - (void)removeActionTarget; 248 | - (void)setActionTarget:(id)arg1 action:(SEL)arg2; 249 | @end 250 | 251 | @interface YTVideoCell : YTCollectionViewCell { 252 | YTIVideoRenderer *_videoRenderer; 253 | YTVideoView *_videoView; 254 | } 255 | - (void)removeLongPressTarget; 256 | - (void)setLongPressTarget:(id)arg1 action:(SEL)arg2; 257 | - (void)removeActionTarget; 258 | - (void)setActionTarget:(id)arg1 action:(SEL)arg2; 259 | @end 260 | 261 | @interface YTGridCell : UICollectionViewCell 262 | @property(retain, nonatomic) UIView *gridView; // @synthesize gridView=_gridView; 263 | - (void)setLongPressTarget:(id)arg1 action:(SEL)arg2; 264 | - (void)removeActionTarget; 265 | - (void)setActionTarget:(id)arg1 action:(SEL)arg2; 266 | @end 267 | 268 | @interface YTGridVideoCell : YTGridCell 269 | - (void)setAccelerated:(_Bool)arg1; 270 | @end 271 | 272 | @interface YTCellController : NSObject 273 | @property(readonly, nonatomic) id entry; // @synthesize entry=_entry; 274 | - (void)imageLoadDidFailWithError:(id)arg1; 275 | - (void)imageDidLoad; 276 | - (_Bool)hasThumbnailMapping:(id)arg1; 277 | - (void)updateThumbnailMapping; 278 | - (void)setCellTargets; 279 | - (void)handleLongPress:(id)arg1; 280 | - (struct CGSize)cellSizeWithSize:(struct CGSize)arg1; 281 | @end 282 | 283 | 284 | @interface YTInnerTubeCellController : YTCellController 285 | { 286 | _Bool _visibilityUpdated; 287 | } 288 | 289 | - (void)cellDidPressLinkedURL:(id)arg1; 290 | - (void)cellDidPressLinkedNavigationEndpoint:(id)arg1 linkText:(id)arg2; 291 | - (void)didSelectItem; 292 | - (void)cellDidBecomeVisible; 293 | - (void)setCell:(id)arg1; 294 | @end 295 | 296 | @interface YTVideoCellController : YTInnerTubeCellController 297 | - (id)menuRenderer; 298 | - (void)setAccelerated:(_Bool)arg1; 299 | - (void)handleLongPressBegan:(id)arg1; 300 | - (void)handleAction:(id)arg1; 301 | @end 302 | 303 | @interface QTMButton : UIButton 304 | + (id)buttonWithColorGroup:(id)arg1 shape:(long long)arg2; 305 | + (id)buttonWithColorGroup:(id)arg1; 306 | //+ (id)buttonWithType:(long long)arg1; 307 | @property(retain, nonatomic) UIColor *customTitleColor; // @synthesize customTitleColor=_customTitleColor; 308 | @property(retain, nonatomic) UIColor *disabledBackgroundColorDark; // @synthesize disabledBackgroundColorDark=_disabledBackgroundColorDark; 309 | @property(retain, nonatomic) UIColor *disabledBackgroundColorLight; // @synthesize disabledBackgroundColorLight=_disabledBackgroundColorLight; 310 | @property(retain, nonatomic) UIColor *enabledBackgroundColor; // @synthesize 311 | - (_Bool)isTransparentColor:(id)arg1; 312 | - (_Bool)isDarkColor:(id)arg1; 313 | - (double)cornerRadius; 314 | @end 315 | 316 | 317 | @interface GOODialogActionButton : QTMButton 318 | @property(nonatomic) _Bool disableRTLTextAlignmentForTitle; // @synthesize disableRTLTextAlignmentForTitle=_disableRTLTextAlignmentForTitle; 319 | @property(nonatomic) double minimumWidth; // @synthesize minimumWidth=_minimumWidth; 320 | @property(nonatomic) double minimumContentHeight; // @synthesize minimumContentHeight=_minimumContentHeight; 321 | @end 322 | 323 | @interface GOOMultiLineView : UIView 324 | @end 325 | 326 | @interface GOODialogView : GOOMultiLineView 327 | - (void)addButton:(id)arg1 style:(int)arg2 insets:(struct UIEdgeInsets)arg3 showHorizontalDivider:(_Bool)arg4 action:(id)arg5; 328 | - (void)addButton:(id)arg1 style:(int)arg2 action:(id)arg3; 329 | @end 330 | 331 | @interface GOOAction : NSObject 332 | + (id)actionWithTitle:(id)arg1 iconImage:(id)arg2 style:(long long)arg3 handler:(id)arg4; 333 | @end 334 | 335 | @interface GOOActionSheetController : NSObject 336 | + (id)actionSheetControllerWithMessage:(id)arg1; 337 | + (id)actionSheetController; 338 | @property(nonatomic) struct CGSize offset; // @synthesize offset=_offset; 339 | @property(retain, nonatomic) UIView *sourceView; // @synthesize sourceView=_sourceView; 340 | @property(nonatomic) unsigned long long anchorCorner; // @synthesize anchorCorner=_anchorCorner; 341 | @property(nonatomic) unsigned long long permittedArrowDirections; // @synthesize 342 | - (void)popoverViewControllerDidCancel:(id)arg1; 343 | - (void)bottomSheetControllerDidCancel:(id)arg1; 344 | - (void)dismissViewControllerAnimated:(_Bool)arg1 completion:(id)arg2; 345 | - (void)dismissWithAction:(id)arg1 animated:(_Bool)arg2 completion:(id)arg3; 346 | - (void)dismiss; 347 | - (id)bestGuessWindow; 348 | - (void)present; 349 | - (void)presentFromViewController:(id)arg1 animated:(_Bool)arg2 completion:(id)arg3; 350 | - (void)addAction:(id)arg1; 351 | @property(readonly, nonatomic) NSArray *actions; 352 | - (id)popoverViewController; 353 | - (id)initWithMessage:(id)arg1; 354 | - (id)init; 355 | @end 356 | 357 | @interface GOOModalView : UIView 358 | - (id)initWithTarget:(id)arg1; 359 | - (void)dismissDialog:(_Bool)arg1; 360 | - (_Bool)shouldDimBackground; 361 | - (void)reposition; 362 | - (void)dismissDueToApplicationBackground; 363 | - (void)dismissWithCancelAction:(_Bool)arg1; 364 | - (void)dismiss; 365 | @property(retain, nonatomic) UIColor *actionButtonIconColor; 366 | @property(retain, nonatomic) UIColor *actionButtonTitleColor; 367 | @property(retain, nonatomic) QTMColorGroup *actionButtonColorGroup; 368 | - (void)didTapBackground; 369 | - (void)sizeToFit; 370 | @end 371 | 372 | @interface GOOActionSheet : GOOModalView 373 | - (void)addTitle:(id)arg1 iconImage:(id)arg2 withStyle:(int)arg3 automationIdentifier:(id)arg4 action:(id)arg5; 374 | - (id)initWithTarget:(id)arg1; 375 | - (void)dismissWithCancelAction:(_Bool)arg1; 376 | - (void)dismiss; 377 | - (void)showPointingAtView:(id)arg1 withRect:(struct CGRect)arg2 arrowDirections:(unsigned long long)arg3; 378 | - (void)showPointingAtView:(id)arg1 withOffset:(struct CGSize)arg2 arrowDirections:(unsigned long long)arg3; 379 | - (void)showPointingAtView:(id)arg1 arrowDirections:(unsigned long long)arg2; 380 | - (id)cancelButtonIconImage; 381 | - (void)showWithCancelButton:(_Bool)arg1 cancelAction:(id)arg2; 382 | - (void)showWithCancelButton:(_Bool)arg1; 383 | - (void)show; 384 | - (void)addButton:(id)arg1 withAction:(id)arg2; 385 | - (void)addMessage:(id)arg1; 386 | @end 387 | 388 | @interface GOOPopoverActionSheet : GOOActionSheet 389 | @end 390 | 391 | @interface YTISoftTabRenderer : PBGeneratedMessage 392 | { 393 | } 394 | 395 | + (id)descriptor; 396 | 397 | // Remaining properties 398 | //@property(retain, nonatomic) YTITabContentSupportedRenderers *content; // @dynamic content; 399 | @property(nonatomic) _Bool hasContent; // @dynamic hasContent; 400 | @property(nonatomic) _Bool hasIcon; // @dynamic hasIcon; 401 | @property(nonatomic) _Bool hasSelected; // @dynamic hasSelected; 402 | @property(nonatomic) _Bool hasTabIdentifier; // @dynamic hasTabIdentifier; 403 | @property(nonatomic) _Bool hasTitle; // @dynamic hasTitle; 404 | //@property(retain, nonatomic) YTIIcon *icon; // @dynamic icon; 405 | @property(nonatomic) _Bool selected; // @dynamic selected; 406 | @property(retain, nonatomic) NSString *tabIdentifier; // @dynamic tabIdentifier; 407 | @property(retain, nonatomic) NSString *title; // @dynamic title; 408 | 409 | @end 410 | 411 | @interface YTIIcon : PBGeneratedMessage 412 | { 413 | } 414 | 415 | + (id)descriptor; 416 | 417 | // Remaining properties 418 | @property(nonatomic) _Bool hasIconType; // @dynamic hasIconType; 419 | @property(nonatomic) int iconType; // @dynamic iconType; 420 | 421 | @end 422 | 423 | @interface YTIRenderers : PBGeneratedMessage 424 | @end 425 | 426 | @interface YTIBrowseEndpoint : PBGeneratedMessage 427 | { 428 | } 429 | 430 | + (id)descriptor; 431 | 432 | // Remaining properties 433 | //@property(retain, nonatomic) YTIBrowseEndpointContextSupportedConfigs *browseEndpointContextSupportedConfigs; // @dynamic browseEndpointContextSupportedConfigs; 434 | @property(retain, nonatomic) NSString *browseId; // @dynamic browseId; 435 | @property(retain, nonatomic) NSString *canonicalBaseUrl; // @dynamic canonicalBaseUrl; 436 | @property(nonatomic) _Bool hasBrowseEndpointContextSupportedConfigs; // @dynamic hasBrowseEndpointContextSupportedConfigs; 437 | @property(nonatomic) _Bool hasBrowseId; // @dynamic hasBrowseId; 438 | @property(nonatomic) _Bool hasCanonicalBaseUrl; // @dynamic hasCanonicalBaseUrl; 439 | @property(nonatomic) _Bool hasOffline; // @dynamic hasOffline; 440 | @property(nonatomic) _Bool hasParams; // @dynamic hasParams; 441 | @property(nonatomic) _Bool hasQuery; // @dynamic hasQuery; 442 | @property(nonatomic) _Bool offline; // @dynamic offline; 443 | @property(retain, nonatomic) NSString *params; // @dynamic params; 444 | @property(retain, nonatomic) NSString *query; // @dynamic query; 445 | 446 | @end 447 | 448 | @interface YTINavigationEndpoint : PBGeneratedMessage 449 | @property(retain, nonatomic) YTIBrowseEndpoint *browseEndpoint; // @dynamic browseEndpoint; 450 | 451 | @end 452 | 453 | @interface YTITabRenderer : PBGeneratedMessage 454 | { 455 | } 456 | 457 | + (id)descriptor; 458 | 459 | // Remaining properties 460 | //@property(retain, nonatomic) YTIAccessibilitySupportedDatas *accessibility; // @dynamic accessibility; 461 | //@property(retain, nonatomic) YTITabContentSupportedRenderers *content; // @dynamic content; 462 | @property(retain, nonatomic) YTINavigationEndpoint *endpoint; // @dynamic endpoint; 463 | //@property(retain, nonatomic) YTITabFooterSupportedRenderers *footer; // @dynamic footer; 464 | @property(nonatomic) _Bool hasAccessibility; // @dynamic hasAccessibility; 465 | @property(nonatomic) _Bool hasContent; // @dynamic hasContent; 466 | @property(nonatomic) _Bool hasEndpoint; // @dynamic hasEndpoint; 467 | @property(nonatomic) _Bool hasFooter; // @dynamic hasFooter; 468 | @property(nonatomic) _Bool hasHeader; // @dynamic hasHeader; 469 | @property(nonatomic) _Bool hasIcon; // @dynamic hasIcon; 470 | @property(nonatomic) _Bool hasIndicator; // @dynamic hasIndicator; 471 | @property(nonatomic) _Bool hasPresentationStyle; // @dynamic hasPresentationStyle; 472 | @property(nonatomic) _Bool hasSelected; // @dynamic hasSelected; 473 | @property(nonatomic) _Bool hasSelectionStyle; // @dynamic hasSelectionStyle; 474 | @property(nonatomic) _Bool hasTabIdentifier; // @dynamic hasTabIdentifier; 475 | @property(nonatomic) _Bool hasTitle; // @dynamic hasTitle; 476 | @property(nonatomic) _Bool hasTrackingParams; // @dynamic hasTrackingParams; 477 | //@property(retain, nonatomic) YTITabHeaderSupportedRenderers *header; // @dynamic header; 478 | @property(retain, nonatomic) YTIIcon *icon; // @dynamic icon; 479 | //@property(retain, nonatomic) YTITabIndicatorSupportedRenderers *indicator; // @dynamic indicator; 480 | //@property(retain, nonatomic) YTITabRendererPresentationStyle *presentationStyle; // @dynamic presentationStyle; 481 | @property(nonatomic) _Bool selected; // @dynamic selected; 482 | //@property(retain, nonatomic) YTITabRendererSelectionStyle *selectionStyle; // @dynamic selectionStyle; 483 | @property(retain, nonatomic) NSString *tabIdentifier; // @dynamic tabIdentifier; 484 | @property(retain, nonatomic) NSString *title; // @dynamic title; 485 | @property(retain, nonatomic) NSData *trackingParams; // @dynamic trackingParams; 486 | 487 | @end 488 | 489 | @interface YTICompactVideoRenderer : PBGeneratedMessage 490 | @property(retain, nonatomic) NSString *videoId; // @dynamic videoId; 491 | @end 492 | 493 | @interface YTCompactVideoView : UIView 494 | @property(retain, nonatomic) YTICompactVideoRenderer *renderer; // @synthesize renderer=_renderer; 495 | @end 496 | 497 | @interface YTIExpandableTabRenderer : PBGeneratedMessage 498 | { 499 | } 500 | 501 | + (id)descriptor; 502 | 503 | // Remaining properties 504 | //@property(retain, nonatomic) YTITabContentSupportedRenderers *content; // @dynamic content; 505 | @property(retain, nonatomic) YTINavigationEndpoint *endpoint; // @dynamic endpoint; 506 | @property(retain, nonatomic) NSString *expandedText; // @dynamic expandedText; 507 | @property(nonatomic) _Bool hasContent; // @dynamic hasContent; 508 | @property(nonatomic) _Bool hasEndpoint; // @dynamic hasEndpoint; 509 | @property(nonatomic) _Bool hasExpandedText; // @dynamic hasExpandedText; 510 | @property(nonatomic) _Bool hasSelected; // @dynamic hasSelected; 511 | @property(nonatomic) _Bool hasSelectionStyle; // @dynamic hasSelectionStyle; 512 | @property(nonatomic) _Bool hasTitle; // @dynamic hasTitle; 513 | @property(nonatomic) _Bool selected; // @dynamic selected; 514 | //@property(retain, nonatomic) YTITabRendererSelectionStyle *selectionStyle; // @dynamic selectionStyle; 515 | @property(retain, nonatomic) NSString *title; // @dynamic title; 516 | 517 | @end 518 | 519 | @interface YTIBrowseTabSupportedRenderers : PBGeneratedMessage 520 | { 521 | } 522 | 523 | + (id)descriptor; 524 | 525 | // Remaining properties 526 | @property(retain, nonatomic) YTIExpandableTabRenderer *expandableTabRenderer; // @dynamic expandableTabRenderer; 527 | @property(nonatomic) _Bool hasExpandableTabRenderer; // @dynamic hasExpandableTabRenderer; 528 | @property(nonatomic) _Bool hasSoftTabRenderer; // @dynamic hasSoftTabRenderer; 529 | @property(nonatomic) _Bool hasTabRenderer; // @dynamic hasTabRenderer; 530 | @property(retain, nonatomic) YTISoftTabRenderer *softTabRenderer; // @dynamic softTabRenderer; 531 | @property(retain, nonatomic) YTITabRenderer *tabRenderer; // @dynamic tabRenderer; 532 | 533 | @end 534 | 535 | @interface YTVariableHeightHeaderViewController : UIViewController 536 | @property(retain, nonatomic) UIViewController *contentViewController; 537 | @end 538 | 539 | @interface YTTabRendererViewController : YTVariableHeightHeaderViewController { 540 | UIViewController *_contentViewController; 541 | // UIViewController *_headerViewController; 542 | // UIViewController *_footerViewController; 543 | YTITabRenderer *_model; 544 | } 545 | @property(readonly, nonatomic) __weak id parentResponder; 546 | - (id)initWithParentResponder:(id)arg1; 547 | @end 548 | 549 | @interface YTDownloadedViewController : NSObject 550 | 551 | @end 552 | 553 | @interface YTTabsRendererViewController : UIViewController 554 | @property(nonatomic) _Bool navBarScrollEnabled; // @synthesize navBarScrollEnabled=_navBarScrollEnabled; 555 | @property(readonly, nonatomic) unsigned long long selectedIndex; // @synthesize selectedIndex=_selectedIndex; 556 | - (id)findLabelWithBrowseId:(id)arg1; 557 | - (id)hintPresentationResponderProvider; 558 | - (id)navEndpointProvider; 559 | - (void)prepareSelectedTab; 560 | - (void)switchToTab:(unsigned long long)arg1; 561 | - (void)setupDefaultContentViewControllers; 562 | - (void)removeAllContentViewControllers; 563 | - (id)tabsRendererView; 564 | @end 565 | 566 | @interface YTTintableButtonsView : UIView 567 | - (id)cacheKeyForButton:(id)arg1 state:(unsigned long long)arg2; 568 | - (id)tintableImageForImage:(id)arg1 cacheKey:(id)arg2; 569 | - (void)cacheOriginalImage:(id)arg1 cacheKey:(id)arg2; 570 | - (void)tintButtons:(id)arg1 color:(id)arg2; 571 | - (id)initWithFrame:(struct CGRect)arg1; 572 | @end 573 | 574 | @interface YTRightNavigationButtons : YTTintableButtonsView 575 | @property(retain, nonatomic) UIButton *rightButton; // @synthesize rightButton=_rightButton; 576 | @property(retain, nonatomic) UIButton *leftButton; // @synthesize leftButton=_leftButton; 577 | - (id)visibleButtons; 578 | - (void)tintAllButtons; 579 | - (void)setTintColor:(id)arg1; 580 | - (_Bool)pointInside:(struct CGPoint)arg1 withEvent:(id)arg2; 581 | - (_Bool)isRightButtonVisible; 582 | - (_Bool)isLeftButtonVisible; 583 | - (void)layoutSubviews; 584 | - (struct CGSize)sizeThatFits:(struct CGSize)arg1; 585 | - (id)initWithLocator:(id)arg1; 586 | @end 587 | 588 | @interface YTNavigationTitleView : UIView 589 | @property(retain, nonatomic) UIView *titleButton; // @synthesize titleButton=_titleButton; 590 | - (void)layoutSubviews; 591 | @end 592 | 593 | @interface YTAppViewController : UIViewController 594 | @property(readonly, nonatomic) UINavigationController *navigationController; 595 | @end 596 | 597 | @interface YTRootNavigationController : UINavigationController 598 | @end 599 | 600 | @interface YTBaseViewController : UIViewController 601 | @end 602 | 603 | @interface YTBaseNavigationViewController : YTBaseViewController 604 | @end 605 | 606 | @interface UINavigationItem (GOONavigationInternal) 607 | + (void)goo_swizzleSetterSel:(SEL)arg1; 608 | + (void)goo_swizzleBarButtonSettersForKVO; 609 | - (void)goo_setRightBarButtonItems:(id)arg1 animated:(_Bool)arg2; 610 | - (void)goo_setRightBarButtonItem:(id)arg1 animated:(_Bool)arg2; 611 | - (void)goo_setLeftBarButtonItems:(id)arg1 animated:(_Bool)arg2; 612 | - (void)goo_setLeftBarButtonItem:(id)arg1 animated:(_Bool)arg2; 613 | - (void)goo_setRightBarButtonItems:(id)arg1; 614 | - (void)goo_setRightBarButtonItem:(id)arg1; 615 | - (void)goo_setLeftBarButtonItems:(id)arg1; 616 | - (void)goo_setLeftBarButtonItem:(id)arg1; 617 | @property(retain, nonatomic, setter=goo_setTitleView:) UIView *goo_titleView; // @dynamic goo_titleView; 618 | @end 619 | 620 | @interface YTAppDelegate : UIResponder 621 | @end -------------------------------------------------------------------------------- /WAEnhancer9Lite/WAEnhancer9Lite.h: -------------------------------------------------------------------------------- 1 | // 2 | // WAEnhancer9Lite.h 3 | // WAEnhancer9Lite 4 | // 5 | // Created by iMokhles on 04/04/16. 6 | // Copyright © 2016 iMokhles. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | #import "fakelogos.h" 13 | #import "iMoMacros.h" 14 | #import "ZKSwizzle.h" 15 | #import "TransNSString.h" 16 | 17 | // private API 18 | @interface UIWindow () 19 | + (UIWindow *)keyWindow; 20 | - (UIView *)contentView; 21 | @end 22 | 23 | @interface WAEnhancer : NSObject 24 | 25 | @end 26 | 27 | @interface NSData (Additions) 28 | + (id)wa_randomDataOfLength:(unsigned long long)arg1; 29 | - (id)wa_URLEncodedString; 30 | - (id)wa_SHA256String; 31 | - (id)wa_MD5String; 32 | - (id)aesDecodeWithKey:(id)arg1; 33 | - (id)aesEncodeWithKey:(id)arg1; 34 | - (id)aesDecodeWithPassphrase:(id)arg1; 35 | - (id)aesEncodeWithPassphrase:(id)arg1; 36 | - (id)aesCryptoWithPassphrase:(id)arg1 encode:(_Bool)arg2; 37 | - (id)aesCryptoWithKey:(id)arg1 encode:(_Bool)arg2 options:(unsigned int)arg3; 38 | - (id)wa_stringValue; 39 | - (id)wa_stringDump; 40 | - (id)wa_base64DecodedData; 41 | - (id)wa_URLSafeBase64DecodedData; 42 | - (id)wa_base64EncodedString; 43 | - (id)wa_URLSafeBase64EncodedString; 44 | - (id)wa_UTF8StringValue; 45 | - (id)wa_HEXStringValue; 46 | - (id)wa_SHA256Digest; 47 | - (id)wa_MD5Digest; 48 | - (_Bool)wa_constantTimeIsEqualToData:(id)arg1; 49 | @end 50 | 51 | 52 | #pragma mark - WhatsApp headers 53 | 54 | @class NSArray, PeopleMultiPickerNavigationController; 55 | 56 | @protocol PeopleMultiPickerNavigationControllerDelegate 57 | - (void)peopleMultiPickerNavigationControllerDidCancel:(PeopleMultiPickerNavigationController *)arg1; 58 | - (void)peopleMultiPickerNavigationController:(PeopleMultiPickerNavigationController *)arg1 didSelectContacts:(NSArray *)arg2; 59 | @end 60 | 61 | @interface PeopleMultiPickerNavigationController : UINavigationController 62 | @property(retain, nonatomic) NSArray *selectedContacts; // @synthesize selectedContacts=_selectedContacts; 63 | @property(nonatomic) long long tag; // @synthesize tag=_tag; 64 | @property(nonatomic) long long selectionLimit; // @synthesize selectionLimit=_selectionLimit; 65 | @property(nonatomic) unsigned long long pickerMode; // @synthesize pickerMode=_pickerMode; 66 | - (void)peopleViewControllerDidCancel:(id)arg1; 67 | - (void)peopleViewController:(id)arg1 didSelectContacts:(id)arg2; 68 | - (void)groupViewControllerDidCancel:(id)arg1; 69 | - (void)groupViewController:(id)arg1 didSelectGroupWithID:(id)arg2; 70 | - (void)viewDidLoad; 71 | - (void)loadPeopleViewController:(int)arg1; 72 | - (void)loadGroupViewController; 73 | - (id)initWithDelegate:(id)arg1; 74 | 75 | // Remaining properties 76 | @property(nonatomic, strong) id delegate; // @dynamic delegate; 77 | 78 | @end 79 | 80 | @interface WADataFormatters : NSObject 81 | { 82 | } 83 | 84 | + (id)backupSizeStringFromLongLong:(long long)arg1; 85 | + (id)sizeStringFromLongLong:(long long)arg1; 86 | + (id)localizedStringWithFormat:(id)arg1 number:(id)arg2; 87 | + (id)dayOfTheWeekFromDate:(id)arg1; 88 | + (id)messageTimestampStringFromDate:(id)arg1; 89 | + (id)messageDateStringFromDate:(id)arg1; 90 | + (id)dateTimeStringFromDate:(id)arg1; 91 | + (id)chatTimestampFromDate:(id)arg1; 92 | + (id)lastActiveStringFromDate:(id)arg1; 93 | + (id)lastSeenStringFromDate:(id)arg1; 94 | + (id)fullWeekdayFormatter; 95 | + (id)dateFormatterMediumStyleNoYear; 96 | + (id)sharedCalendar; 97 | + (id)shortWeekdayFormatter; 98 | + (id)messageTimestampFormatter; 99 | + (id)dateTimeFormatterLongStyleNoYear; 100 | + (id)dateTimeFormatterLongStyle; 101 | + (id)dateTimeFormatter; 102 | + (id)timeFormatter; 103 | + (id)dateFormatterMediumStyle; 104 | + (id)dateFormatterShortStyle; 105 | + (id)numberFormatter; 106 | + (void)currentLocaleDidChange:(id)arg1; 107 | + (void)initialize; 108 | 109 | @end 110 | 111 | @interface WATheme : NSObject 112 | + (id)colorPalette; 113 | + (id)defaultTheme; 114 | - (void)reloadFonts; 115 | - (void)contentSizeCategoryDidChange:(id)arg1; 116 | - (void)reloadDynamicTypeFontSize; 117 | - (void)setFontSize:(double)arg1; 118 | - (long long)fontIndexForSize:(long long)arg1; 119 | - (long long)fontSizeForIndex:(long long)arg1; 120 | - (id)fontNameForIndex:(long long)arg1; 121 | - (long long)numberOfFonts; 122 | - (long long)defaultFontSize; 123 | - (long long)fontSize; 124 | - (id)fontName; 125 | @end 126 | 127 | @interface NSString (Additions) 128 | + (id)wa_stringWithData:(id)arg1 encodingHint:(unsigned long long)arg2 actualEncoding:(unsigned long long *)arg3; 129 | + (id)digraphs; 130 | - (id)wa_componentsOfURLStringForIndexing; 131 | - (id)wa_htmlUnescapedString; 132 | - (_Bool)wa_isIPAddress; 133 | - (id)wa_decodedStringFromBase64; 134 | - (_Bool)wa_hasVideoFileExtension; 135 | - (id)wa_whatsAppIDFromJID; 136 | - (id)wa_jidFromIdOrJID; 137 | - (id)wa_jidFromWhatsAppID; 138 | - (id)localPhoneNumberFormattedUsingCountryCode:(id)arg1; 139 | - (id)unformattedPhoneNumber; 140 | - (id)unformattedPhoneNumberFromJID; 141 | - (id)formattedPhoneNumberFromJID; 142 | - (id)formattedPhoneNumber; 143 | - (id)phoneNumberForVoiceOver; 144 | - (id)wa_splitIntoPartsWithMaxParts:(unsigned long long)arg1 maxCharactersPerPart:(unsigned long long)arg2 overflowed:(_Bool *)arg3; 145 | - (unsigned long long)wa_indexOfClosestWordBoundaryBeforeIndex:(unsigned long long)arg1; 146 | - (unsigned long long)wa_indexOfComposedCharacterContainingIndex:(unsigned long long)arg1; 147 | - (id)wa_redactedURLString; 148 | - (id)wa_redactedString; 149 | - (id)wa_stringByReplacingGreaterThanSignWithImageUsingColor:(id)arg1 andFont:(id)arg2; 150 | - (id)wa_substringWithComposedCharacterSequenceLength:(unsigned long long)arg1; 151 | - (unsigned long long)wa_lengthInCharacters; 152 | - (id)wa_bestStringLanguage; 153 | - (_Bool)isRTLText; 154 | - (_Bool)isEmptyOrWhitespace; 155 | - (id)wa_suffixWithMaximumLength:(unsigned long long)arg1; 156 | - (id)wa_trimmedStringByNormalizingNewlines; 157 | - (id)wa_trimmedString; 158 | - (id)wa_stringByRemovingEmoji; 159 | - (id)wa_stringByStandardizingEmoji; 160 | - (id)mimeType; 161 | - (id)tokens; 162 | - (id)upperBoundSearchString; 163 | - (id)normalizedString; 164 | - (id)wa_URLEncodedString; 165 | @end 166 | 167 | 168 | @interface WABlockBasedAlertView : UIAlertView 169 | { 170 | NSMutableDictionary *_actionMap; 171 | _Bool _shouldLog; 172 | } 173 | 174 | + (void)showErrorMessage:(id)arg1; 175 | + (void)showErrorInAlertView:(id)arg1; 176 | + (id)alertViewWithTitle:(id)arg1 message:(id)arg2; 177 | @property(readonly, nonatomic) _Bool shouldLog; // @synthesize shouldLog=_shouldLog; 178 | - (void)show; 179 | - (void)cancelAlertViewWithAnimation:(_Bool)arg1; 180 | - (void)addCancelButtonWithTitle:(id)arg1 handler:(id)arg2; 181 | - (void)addButtonWithTitle:(id)arg1 handler:(id)arg2; 182 | - (void)alertView:(id)arg1 clickedButtonAtIndex:(long long)arg2; 183 | - (void)didPresentAlertView:(id)arg1; 184 | - (void)applicationDidEnterBackground:(id)arg1; 185 | - (void)dealloc; 186 | - (id)initWithTitle:(id)arg1 message:(id)arg2 shouldLogContent:(_Bool)arg3; 187 | - (id)initWithTitle:(id)arg1 message:(id)arg2; 188 | - (id)initWithFrame:(struct CGRect)arg1; 189 | - (id)initWithCoder:(id)arg1; 190 | 191 | @end 192 | 193 | @interface WAServerProperties : NSObject 194 | { 195 | } 196 | 197 | 198 | + (id)tosValue; 199 | + (_Bool)isEndToEndIdentityVerificationEnabled; 200 | + (_Bool)isEndToEndUsesRegularPush; 201 | + (_Bool)isEndToEndEncAudioEnabled; 202 | + (_Bool)isEndToEndEncImagesEnabled; 203 | + (_Bool)isEndToEndEncBroadcastEnabled; 204 | + (_Bool)isEndToEndEncGroupsEnabled; 205 | + (int)encPlaintextReenableThreshold; 206 | + (_Bool)isEncMspesSet; 207 | + (long long)videoMaxEdge; 208 | + (struct CGSize)maxLandscapeVideoFrameSizeForInAppVideoRecording; 209 | + (_Bool)isWebClientEnabled; 210 | + (_Bool)isWhatsAppIDEnabledForVOIP:(id)arg1; 211 | + (_Bool)isPTTOpusRecordingEnabled; 212 | + (_Bool)isVOIPEnabled; 213 | + (long long)maxListSize; 214 | + (unsigned long long)placeSource; 215 | + (_Bool)isLocationSharingEnabled; 216 | + (_Bool)isReadReceiptsEnabledForDate:(id)arg1; 217 | + (_Bool)isAudioSharingEnabled; 218 | + (double)imageQuality; 219 | + (long long)imageMaxEdge; 220 | + (long long)imageMaxKBytes; 221 | + (_Bool)isDocumentSharingEnabled; 222 | + (id)supportedDocumentTypes; 223 | + (long long)maxDocumentSize; 224 | + (long long)maxGroupSubjectLength; 225 | + (long long)maxGroupParticipants; 226 | + (id)maxVideoDuration; 227 | + (unsigned long long)maxMediaSize; 228 | + (_Bool)shouldQueryVersion:(id)arg1; 229 | + (void)setProperties:(id)arg1 version:(id)arg2; 230 | + (void)resetToDefaults; 231 | + (void)reloadServerPropertiesFromPreferences; 232 | + (id)prefBundleKey; 233 | + (void)initialize; 234 | 235 | @end 236 | 237 | @interface WASharedAppData : NSObject 238 | { 239 | } 240 | 241 | + (void)sendDataToServer:(id)arg1; 242 | + (void)handleClientConnection:(int)arg1; 243 | + (_Bool)startIPCServer; 244 | + (id)IPCSocketPath; 245 | + (void)unlockConnection; 246 | + (void)lockConnection; 247 | + (_Bool)tryConnectionLock; 248 | + (void)unmigrateData; 249 | + (void)migrateUserPreferences; 250 | + (void)migrateData; 251 | + (_Bool)isDataInAppGroup; 252 | + (void)showAlertText:(id)arg1 fromViewController:(id)arg2; 253 | + (void)setPhoneNumber:(id)arg1; 254 | + (id)phoneNumber; 255 | + (void)setCountryCode:(id)arg1; 256 | + (id)countryCode; 257 | + (void)removePasswordFile; 258 | + (_Bool)setPassword:(id)arg1; 259 | + (id)password; 260 | + (id)passwordFilePathInMainContainer; 261 | + (id)passwordFilePathInAppGroup; 262 | + (id)passwordFilePath; 263 | + (id)normalizedNumberFromJID:(id)arg1; 264 | + (id)normalizedNumber; 265 | + (void)setUserJID:(id)arg1; 266 | + (id)userJID; 267 | + (void)showCriticallyLowStorageAlert; 268 | + (void)showLocalNotificationForJailbrokenPhoneAndTerminate; 269 | + (void)setStatusBarStyle:(long long)arg1 animated:(_Bool)arg2; 270 | + (void)setStatusBarHidden:(_Bool)arg1 withAnimation:(long long)arg2; 271 | + (void)endIgnoringInteractionEventsInExtension; 272 | + (void)beginIgnoringInteractionEventsInExtension; 273 | + (void)endIgnoringInteractionEvents; 274 | + (void)beginIgnoringInteractionEvents; 275 | + (void)endBackgroundTask:(unsigned long long)arg1; 276 | + (unsigned long long)beginBackgroundTaskWithName:(id)arg1 expirationHandler:(id)arg2; 277 | + (void)internalEndBackgroundTask:(unsigned long long)arg1; 278 | + (unsigned long long)internalBeginBackgroundTaskWithExpirationHandler:(id)arg1; 279 | + (void)prepareToSuspend; 280 | + (void)setDidResumeHandler:(id)arg1; 281 | + (void)setWillSuspendHandler:(id)arg1; 282 | + (void)resetSuspendingIfNeeded; 283 | + (void)checkApplicationBackgroundState; 284 | + (void)setUpMainBackgroundTaskIfNeeded; 285 | + (void)applicationWillEnterForeground:(id)arg1; 286 | + (void)applicationDidEnterBackground:(id)arg1; 287 | + (id)sharedApplication; 288 | + (_Bool)isRestoreInProgress; 289 | + (_Bool)isBackupInProgress; 290 | + (id)launchTime; 291 | + (double)backgroundTimeRemaining; 292 | + (long long)applicationState; 293 | + (_Bool)isVOIPCallActive; 294 | + (_Bool)hasVOIPCallStarted; 295 | + (_Bool)isWebClientAvailable; 296 | + (_Bool)isUserAvailable; 297 | + (id)URLSessionManager; 298 | + (void *)sharedAddressBook; 299 | + (id)profilePictureManager; 300 | + (id)xmppConnection; 301 | + (id)notificationsConfig; 302 | + (id)contactsStorage; 303 | + (id)chatStorage; 304 | + (id)axolotlDatabaseURLInMainContainer; 305 | + (id)axolotlDatabaseURLInAppGroup; 306 | + (id)axolotlDatabaseURL; 307 | + (id)sharedLogsDirectoryURL; 308 | + (id)profilePicturesStorageDirectoryInMainContainer; 309 | + (id)profilePicturesStorageDirectoryInAppGroup; 310 | + (id)contactsDatabaseURLInMainContainer; 311 | + (id)contactsDatabaseURLInAppGroup; 312 | + (id)contactsDatabaseURL; 313 | + (id)chatSearchDatabaseURLInMainContainer; 314 | + (id)chatSearchDatabaseURLInAppGroup; 315 | + (id)chatSearchDatabaseURL; 316 | + (id)chatDatabaseURLInMainContainer; 317 | + (id)chatDatabaseURLInAppGroup; 318 | + (id)chatDatabaseURL; 319 | + (id)sharedItemOutboxesURL; 320 | + (id)userDefaults; 321 | + (id)appGroupURL; 322 | + (void)registerExtensionContainerView:(id)arg1; 323 | + (_Bool)isRunningAsExtension; 324 | + (_Bool)isChatDatabaseAccessible; 325 | + (void)prepareConnectionLock; 326 | + (void)registerConnectionConditionals; 327 | + (void)prepareBackgroundTaskManagement; 328 | + (_Bool)prepareAppContainer; 329 | + (_Bool)internalPrepare; 330 | + (_Bool)prepare; 331 | 332 | @end 333 | 334 | @interface UITabBarButtonLabel : UILabel 335 | @end 336 | 337 | @interface UITabBarButton : UIControl { 338 | UIView *_info; 339 | } 340 | @property(getter=_isSelected,setter=_setSelected:) bool _selected; 341 | @property(getter=_unselectedTintColor,setter=_setUnselectedTintColor:,retain) UIColor * unselectedTintColor; 342 | @end 343 | 344 | @interface WATabBarController : UITabBarController 345 | @end 346 | 347 | @interface WAChatCellData : NSObject 348 | @property(readonly, nonatomic) NSArray *messages; // @synthesize messages=_messages; 349 | @property(retain, nonatomic) NSArray *textMessages; // @synthesize textMessages=_textMessages; 350 | - (id)message; 351 | @end 352 | 353 | @interface WAMessageCell : UITableViewCell { 354 | UIImageView *_imageViewBubble; 355 | UIImageView *_imageViewCheckmark; 356 | } 357 | @property(readonly, nonatomic) UIView *bubbleView; // @synthesize bubbleView=_bubbleView; 358 | @property(readonly, nonatomic) WAChatCellData *cellData; // @synthesize cellData=_cellData; 359 | @property(retain, nonatomic) UIImageView *bubbleImageView; // @synthesize bubbleImageView=_bubbleImageView; 360 | @end 361 | 362 | @interface WAMessageTextView : UIView { 363 | NSArray *_textMessages; 364 | } 365 | - (void)handleLongPress; 366 | - (void)handleSingleTap; 367 | - (void)unhighlightAllTextBlocks; 368 | - (void)highlightTextBlock:(id)arg1; 369 | @end 370 | 371 | @interface WATextMessageCell : WAMessageCell { 372 | WAMessageTextView *_messageTextView; 373 | } 374 | @end 375 | 376 | @interface TextMessage : NSObject 377 | @property(nonatomic) BOOL textStoragePrepared; // @synthesize textStoragePrepared=_textStoragePrepared; 378 | @property(retain, nonatomic) UIColor *highlightBoxColor; // @synthesize highlightBoxColor=_highlightBoxColor; 379 | @property(nonatomic) BOOL underlineLinks; // @synthesize underlineLinks=_underlineLinks; 380 | @property(copy, nonatomic) NSArray *highlightedTerms; // @synthesize highlightedTerms=_highlightedTerms; 381 | @property(retain, nonatomic) NSArray *textBlocks; // @synthesize textBlocks=_textBlocks; 382 | @property(retain, nonatomic) UIColor *shadowColor; // @synthesize shadowColor=_shadowColor; 383 | @property(retain, nonatomic) UIColor *urlBackgroundColor; // @synthesize urlBackgroundColor=_urlBackgroundColor; 384 | @property(retain, nonatomic) UIColor *highlightedUrlColor; // @synthesize highlightedUrlColor=_highlightedUrlColor; 385 | @property(retain, nonatomic) UIColor *urlColor; // @synthesize urlColor=_urlColor; 386 | @property(retain, nonatomic) UIColor *textColor; // @synthesize textColor=_textColor; 387 | @property(retain, nonatomic) UIFont *font; // @synthesize font=_font; 388 | @property(retain, nonatomic) NSString *originalText; // @synthesize originalText=_originalText; 389 | @property(retain, nonatomic) NSString *text; // @synthesize text=_text; 390 | @property(nonatomic) BOOL dataDetectionEnabled; // @synthesize dataDetectionEnabled=_dataDetectionEnabled; 391 | @end 392 | 393 | @interface _TextMessage_TextKit : TextMessage 394 | - (void)setFont:(id)arg1; 395 | @end 396 | 397 | @class WAChatSession; 398 | 399 | @interface WAMessage : NSObject 400 | @property(retain, nonatomic) WAChatSession *chatSession; // @dynamic chatSession; 401 | @property(retain, nonatomic) NSSet *childMessages; // @dynamic childMessages; 402 | @property(retain, nonatomic) NSNumber *childMessagesDeliveredCount; // @dynamic childMessagesDeliveredCount; 403 | @property(retain, nonatomic) NSNumber *childMessagesPlayedCount; // @dynamic childMessagesPlayedCount; 404 | @property(retain, nonatomic) NSNumber *childMessagesReadCount; // @dynamic childMessagesReadCount; 405 | @property(readonly, copy) NSString *debugDescription; 406 | @property(readonly, copy) NSString *description; 407 | @property(retain, nonatomic) NSNumber *docID; // @dynamic docID; 408 | @property(retain, nonatomic) NSNumber *encRetryCount; // @dynamic encRetryCount; 409 | @property(retain, nonatomic) NSNumber *filteredRecipientCount; // @dynamic filteredRecipientCount; 410 | @property(retain, nonatomic) NSNumber *flags; // @dynamic flags; 411 | @property(retain, nonatomic) NSString *fromJID; // @dynamic fromJID; 412 | @property(retain, nonatomic) NSNumber *groupEventType; // @dynamic groupEventType; 413 | // @property(retain, nonatomic) WAGroupMember *groupMember; // @dynamic groupMember; 414 | @property(readonly) unsigned long long hash; 415 | @property(retain, nonatomic) NSNumber *isFromMe; // @dynamic isFromMe; 416 | // @property(retain, nonatomic) WAMediaItem *mediaItem; // @dynamic mediaItem; 417 | @property(retain, nonatomic) NSString *mediaSectionID; // @dynamic mediaSectionID; 418 | @property(retain, nonatomic) NSDate *messageDate; // @dynamic messageDate; 419 | @property(retain, nonatomic) NSNumber *messageErrorStatus; // @dynamic messageErrorStatus; 420 | // @property(retain, nonatomic) WAMessageInfo *messageInfo; // @dynamic messageInfo; 421 | @property(retain, nonatomic) NSNumber *messageType; // @dynamic messageType; 422 | @property(retain, nonatomic) WAMessage *parentMessage; // @dynamic parentMessage; 423 | @property(retain, nonatomic) NSString *pushName; // @dynamic pushName; 424 | @property(retain, nonatomic) NSDate *sentDate; // @dynamic sentDate; 425 | @property(retain, nonatomic) NSNumber *sort; // @dynamic sort; 426 | @property(retain, nonatomic) NSString *stanzaID; // @dynamic stanzaID; 427 | @property(retain, nonatomic) NSString *text; // @dynamic text; 428 | @property(retain, nonatomic) NSString *toJID; // @dynamic toJID; 429 | @end 430 | 431 | @interface WAChatSession : NSObject 432 | // Remaining properties 433 | @property(readonly, nonatomic, getter=isBroadcastListJIDValid) _Bool broadcastListJIDValid; 434 | @property(retain, nonatomic) NSNumber *archived; // @dynamic archived; 435 | @property(retain, nonatomic) NSNumber *contactABID; // @dynamic contactABID; 436 | @property(retain, nonatomic) NSString *eTag; // @dynamic eTag; 437 | @property(retain, nonatomic) NSNumber *flags; // @dynamic flags; 438 | // @property(retain, nonatomic) WAGroupInfo *groupInfo; // @dynamic groupInfo; 439 | @property(retain, nonatomic) NSSet *groupMembers; // @dynamic groupMembers; 440 | @property(retain, nonatomic) NSNumber *hidden; // @dynamic hidden; 441 | @property(retain, nonatomic) WAMessage *lastMessage; // @dynamic lastMessage; 442 | @property(retain, nonatomic) NSDate *lastMessageDate; // @dynamic lastMessageDate; 443 | @property(retain, nonatomic) NSString *lastMessageText; // @dynamic lastMessageText; 444 | @property(retain, nonatomic) NSDate *locationSharingEndDate; // @dynamic locationSharingEndDate; 445 | @property(retain, nonatomic) NSNumber *messageCounter; // @dynamic messageCounter; 446 | @property(retain, nonatomic) NSString *partnerName; // @dynamic partnerName; 447 | @property(retain, nonatomic) NSNumber *removed; // @dynamic removed; 448 | @property(retain, nonatomic) NSString *savedInput; // @dynamic savedInput; 449 | @property(retain, nonatomic) NSNumber *sessionType; // @dynamic sessionType; 450 | @property(retain, nonatomic) NSNumber *unreadCount; // @dynamic unreadCount; 451 | @property(retain, nonatomic) NSString *contactJID; // @dynamic contactJID; 452 | @end 453 | 454 | @interface WALabel : UILabel 455 | @end 456 | 457 | @interface WAConversationHeaderView : UIView { 458 | WALabel *_titleLabel; 459 | UILabel *_captionLabel; 460 | UILabel *_activityLabel; 461 | } 462 | @property(copy, nonatomic) NSString *activityText; // @synthesize activityText=_activityText; 463 | @property(copy, nonatomic) NSString *captionTextForVoiceOver; // @synthesize captionTextForVoiceOver=_captionTextForVoiceOver; 464 | @property(copy, nonatomic) NSString *caption; // @synthesize caption=_caption; 465 | @property(copy, nonatomic) NSString *title; // @synthesize title=_title; 466 | - (void)setCaption:(id)arg1 animated:(_Bool)arg2 autoscroll:(_Bool)arg3 scrollCompletion:(id)arg4; 467 | @end 468 | 469 | @interface _WAConversationHeaderViewModern : WAConversationHeaderView 470 | @property(retain, nonatomic) UIButton *callButton; // @synthesize callButton=_callButton; 471 | @end 472 | 473 | @interface WAChatMessagesController : NSObject 474 | - (id)allSelectedMessages; 475 | - (id)allSelectedCellDataObjects; 476 | @end 477 | 478 | @interface WADocumentAttachment : NSObject 479 | - (id)initWithFileURL:(id)arg1 transferFileOwnership:(_Bool)arg2; 480 | - (id)init; 481 | @end 482 | 483 | @interface ChatViewController : UIViewController 484 | @property(retain, nonatomic) WAChatMessagesController *messagesController; // @synthesize 485 | @property(retain, nonatomic) WAConversationHeaderView *headerView; // @synthesize headerView=_headerView; 486 | @property(readonly, nonatomic) WAChatSession *chatSession; 487 | @property(retain, nonatomic) UIBarButtonItem *barButtonDeleteAll; // @synthesize barButtonDeleteAll=_barButtonDeleteAll; 488 | @property(retain, nonatomic) UIBarButtonItem *barButtonDoneEditing; // @synthesize barButtonDoneEditing=_barButtonDoneEditing; 489 | @property(retain, nonatomic) UIBarButtonItem *barButtonEditModeTitle; // @synthesize barButtonEditModeTitle=_barButtonEditModeTitle; 490 | @property(retain, nonatomic) UIBarButtonItem *barButtonDelete; // @synthesize barButtonDelete=_barButtonDelete; 491 | @property(retain, nonatomic) UIBarButtonItem *barButtonShare; // @synthesize barButtonShare=_barButtonShare; 492 | @property(retain, nonatomic) UIBarButtonItem *barButtonForward; // @synthesize barButtonForward=_barButtonForward; 493 | @property(retain, nonatomic) NSString *jid; // @synthesize jid=_jid; 494 | - (void)sendAudioTrack:(id)arg1; 495 | - (void)sendImage:(id)arg1 caption:(id)arg2; 496 | - (void)messageCell:(id)arg1 didSelectTextBlock:(id)arg2; 497 | - (void)sendAudioAtURL:(id)arg1 durationSeconds:(int)arg2 streamingHash:(id)arg3; 498 | - (void)unblockContact; 499 | - (void)blockContact; 500 | - (void)sendDocumentAttachment:(id)arg1; 501 | @end 502 | 503 | @interface CallManager : NSObject 504 | + (id)sharedManager; 505 | - (void)attemptOutgoingCellularVoiceCallWithPhoneURL:(id)arg1; 506 | - (void)attemptOutgoingVoiceCallWithJID:(id)arg1 bypassEligibilityCheck:(_Bool)arg2 callUISource:(int)arg3; 507 | @end 508 | 509 | @interface WAListsViewController : UIViewController { 510 | NSFetchedResultsController *_fetchedResultsController; 511 | UIView *_emptyListView; 512 | UITableView *_tableView; 513 | BOOL _chatStorageAvailable; 514 | WAChatSession *_activeList; 515 | } 516 | - (void)createNewList:(id)arg1; 517 | - (void)deleteExistingList:(id)arg1; 518 | @end 519 | 520 | @interface XMPPIQStanza : NSObject 521 | { 522 | } 523 | 524 | + (unsigned long long)typeForString:(id)arg1; 525 | + (id)stringForType:(unsigned long long)arg1; 526 | + (id)stringsForTypes; 527 | - (id)log; 528 | @property(retain, nonatomic) NSString *xmlns; 529 | - (_Bool)matchXMLNS:(id)arg1; 530 | @property(nonatomic) unsigned long long type; 531 | @property(readonly, nonatomic) NSData *password; 532 | @property(readonly, nonatomic) NSDate *lastActivity; 533 | - (_Bool)isLocation; 534 | - (_Bool)hasPassword; 535 | - (_Bool)hasPing; 536 | - (id)initWithFromJID:(id)arg1 toJID:(id)arg2 type:(unsigned long long)arg3; 537 | 538 | @end 539 | 540 | @interface XMPPClient : NSObject 541 | @property(retain) NSString *jid; // @synthesize jid=_jid; 542 | @property(retain) NSDate *lastSeenTimestamp; // @synthesize lastSeenTimestamp=_lastSeenTimestamp; 543 | @property(retain) NSString *groupJIDForChatState; // @synthesize groupJIDForChatState=_groupJIDForChatState; 544 | @property(retain) NSDate *incomingChatStateTimestamp; // @synthesize incomingChatStateTimestamp=_incomingChatStateTimestamp; 545 | @property(retain) NSDate *outgoingChatStateTimestamp; // @synthesize outgoingChatStateTimestamp=_outgoingChatStateTimestamp; 546 | @property unsigned long long presence; // @synthesize presence=_presence; 547 | @property unsigned long long lastReceivedChatState; 548 | @property unsigned long long lastSentChatState; 549 | - (void)reset; 550 | - (id)initWithJID:(id)arg1; 551 | @end 552 | 553 | @interface XMPPConnection : NSObject 554 | @property(getter=isConnected) BOOL connected; // @synthesize connected=_connected; 555 | - (void)close; 556 | - (id)lastSeenTimestampForJID:(id)arg1; 557 | - (void)removeClientDataForJID:(id)arg1; 558 | - (_Bool)isOnline:(id)arg1; 559 | - (id)addClientDataForJID:(id)arg1; 560 | - (XMPPClient *)clientDataForJID:(id)arg1; 561 | - (unsigned long long)chatStateForContactWithJID:(id)arg1; 562 | @end 563 | 564 | @interface WATableRow : NSObject 565 | { 566 | _Bool _editable; 567 | _Bool _disabled; 568 | id _editHandler; 569 | id _handler; 570 | UITableViewCell *_cell; 571 | } 572 | 573 | @property(nonatomic) _Bool disabled; // @synthesize disabled=_disabled; 574 | @property(nonatomic, getter=isEditable) _Bool editable; // @synthesize editable=_editable; 575 | @property(retain, nonatomic) UITableViewCell *cell; // @synthesize cell=_cell; 576 | @property(copy, nonatomic) id handler; // @synthesize handler=_handler; 577 | 578 | @end 579 | 580 | @interface WATableSection : NSObject 581 | { 582 | NSMutableArray *_rows; 583 | NSString *_headerText; 584 | NSString *_footerText; 585 | } 586 | 587 | @property(retain, nonatomic) NSString *footerText; // @synthesize footerText=_footerText; 588 | @property(retain, nonatomic) NSString *headerText; // @synthesize headerText=_headerText; 589 | @property(retain, nonatomic) NSArray *rows; // @synthesize rows=_rows; 590 | - (void)deleteRow:(id)arg1; 591 | - (id)addTableRowWithCellStyle:(long long)arg1; 592 | - (id)addDefaultTableRow; 593 | - (void)addRow:(id)arg1; 594 | - (id)init; 595 | 596 | @end 597 | 598 | @interface WAStaticTableViewController : UITableViewController 599 | { 600 | NSMutableArray *_sections; 601 | } 602 | 603 | @property(retain, nonatomic) NSArray *sections; // @synthesize sections=_sections; 604 | - (void)deselectActiveCell; 605 | - (void)wa_fontSizeDidChange; 606 | - (void)tableView:(id)arg1 didSelectRowAtIndexPath:(id)arg2; 607 | - (id)tableView:(id)arg1 willSelectRowAtIndexPath:(id)arg2; 608 | - (id)tableView:(id)arg1 titleForFooterInSection:(int)arg2; 609 | - (id)tableView:(id)arg1 titleForHeaderInSection:(int)arg2; 610 | - (id)tableView:(id)arg1 cellForRowAtIndexPath:(id)arg2; 611 | - (int)tableView:(id)arg1 numberOfRowsInSection:(int)arg2; 612 | - (int)numberOfSectionsInTableView:(id)arg1; 613 | - (id)rowAtIndexPath:(id)arg1; 614 | - (id)addSection; 615 | - (void)setupTableView; 616 | - (void)viewDidLoad; 617 | - (id)initWithStyle:(int)arg1; 618 | 619 | @end 620 | 621 | @interface WAStaticTableViewController (WAEnhancer9) 622 | - (WATableSection *)addSectionAtTop; 623 | @end 624 | 625 | @interface WASettingsViewController : WAStaticTableViewController 626 | @end 627 | 628 | 629 | @interface WAContactInfo : NSObject 630 | - (id)initWithChatSession:(id)arg1; 631 | - (id)initWithContact:(id)arg1; 632 | - (id)initWithWAContactObjectID:(id)arg1; 633 | @property(copy, nonatomic) NSString *statusText; // @synthesize statusText=_statusText; 634 | @property(copy, nonatomic) NSString *highlightedName; // @synthesize highlightedName=_highlightedName; 635 | @property(copy, nonatomic) NSString *jid; // @synthesize jid=_jid; 636 | @property(copy, nonatomic) NSString *firstName; // @synthesize firstName=_firstName; 637 | @property(copy, nonatomic) NSString *fullName; // @synthesize fullName=_fullName; 638 | @end 639 | 640 | 641 | @interface ChatManager : NSObject 642 | - (id)localizedChatActivityStringForJID:(id)arg1; 643 | - (id)localizedChatActivityStringForContactWithJID:(id)arg1; 644 | - (id)localizedChatActivityStringForGroupWithJID:(id)arg1; 645 | @end 646 | 647 | @interface WATableViewController : UITableViewController 648 | @end 649 | 650 | @class WAForwardPickerViewController; 651 | @protocol WAForwardPickerViewControllerDelegate 652 | - (_Bool)forwardPicker:(WAForwardPickerViewController *)arg1 shouldProceedWithContactInfo:(WAContactInfo *)arg2; 653 | - (void)forwardPickerDidCancel:(WAForwardPickerViewController *)arg1; 654 | - (void)forwardPicker:(WAForwardPickerViewController *)arg1 didSelectContactInfo:(WAContactInfo *)arg2; 655 | 656 | @optional 657 | - (NSString *)forwardPicker:(WAForwardPickerViewController *)arg1 confirmationButtonTitleForContactInfo:(WAContactInfo *)arg2; 658 | - (NSString *)forwardPicker:(WAForwardPickerViewController *)arg1 confirmationTextForContactInfo:(WAContactInfo *)arg2; 659 | @end 660 | 661 | 662 | @interface WAForwardPickerViewController : WATableViewController 663 | + (id)controller; 664 | @property(nonatomic) __weak id delegate; // @synthesize delegate=_delegate; 665 | @end 666 | //@interface WADocumentAttachment : NSObject 667 | //- (id)initWithFileURL:(id)arg1 transferFileOwnership:(_Bool)arg2; 668 | //- (id)init; 669 | //@end 670 | 671 | @interface WAChatStorage : NSObject 672 | - (id)allChatSessions; 673 | - (void)sendDocumentAttachment:(id)arg1 inChatSession:(id)arg2 completion:(id)arg3; 674 | - (id)existingChatSessionsForJIDs:(id)arg1 prefetchingLastMessage:(_Bool)arg2; 675 | - (id)newOrExistingChatSessionForJID:(id)arg1; // new beta 676 | -(id)existingChatSessionForJID:(id)jid; // old 677 | -(id)chatSessionForJID:(id)jid; 678 | - (void)sendMessageWithText:(id)arg1 metadata:(id)arg2 inChatSession:(id)arg3; // new beta 679 | - (void)sendMessageWithText:(id)arg1 inChatSession:(id)arg2; 680 | - (void)sendMessageWithImage:(id)arg1 caption:(id)arg2 inChatSession:(id)arg3 completion:(id)arg4; 681 | -(void)sendMessage:(id)message notify:(BOOL)notify; 682 | - (void)retrySendingMessage:(id)arg1; 683 | - (void)forwardMessages:(id)arg1 toChatSession:(id)arg2; 684 | @end 685 | 686 | //@class WAMessage; 687 | //@interface WAChatSession : NSObject 688 | //@property(retain, nonatomic) NSSet *messages; // @dynamic messages; 689 | //@property(retain, nonatomic) NSNumber *unreadCount; // @dynamic unreadCount; 690 | //@property(retain, nonatomic) NSString *partnerName; // @dynamic partnerName; 691 | //@property(retain, nonatomic) NSString *lastMessageText; // @dynamic lastMessageText; 692 | //@property(retain, nonatomic) WAMessage *lastMessage; // @dynamic lastMessage; 693 | //@end 694 | 695 | //@interface WAMessage : NSObject 696 | //@property(retain, nonatomic) NSString *text; // @dynamic text; 697 | //@property(retain, nonatomic) NSString *toJID; // @dynamic toJID; 698 | //@property(retain, nonatomic) NSString *fromJID; // @dynamic fromJID; 699 | //@property(retain, nonatomic) NSString *pushName; // @dynamic pushName; 700 | //@property(retain, nonatomic) NSString *stanzaID; // @dynamic stanzaID; 701 | //@property(retain, nonatomic) NSNumber *isFromMe; // @dynamic isFromMe; 702 | //@property(retain, nonatomic) NSNumber *messageStatus; // @dynamic messageStatus; 703 | //@property(retain, nonatomic) NSNumber *messageErrorStatus; // @dynamic messageErrorStatus; 704 | //@property(retain, nonatomic) WAChatSession *chatSession; // @dynamic chatSession; 705 | //@end 706 | 707 | @interface WAChatListViewController : UITableViewController 708 | - (void)presentChatSession:(id)arg1; 709 | @end 710 | 711 | @interface WAVoiceCallViewController : UIViewController 712 | - (void)minimizeWithAnimation:(_Bool)arg1; 713 | @end 714 | 715 | @interface WhatsAppAppDelegate : NSObject { 716 | WAVoiceCallViewController *_activeVoiceCallViewController; 717 | } 718 | @property(readonly, nonatomic) _Bool isCallWindowVisible; 719 | @property(retain, nonatomic) NSString *chatJID; // @synthesize chatJID=_chatJID; 720 | @property(readonly, nonatomic) UITabBarController *tabBarController; // @synthesize 721 | //- (void)openChatAnimated:(_Bool)arg1 presentKeyboard:(_Bool)arg2; 722 | @property(readonly, nonatomic) WAChatListViewController *chatListViewController; 723 | - (void)openChatAnimated:(_Bool)arg1 presentKeyboard:(_Bool)arg2; 724 | @end 725 | 726 | @interface WARecentsWA : NSObject 727 | + (WARecentsWA *)sharedInstance; 728 | - (void)startDeamon; 729 | - (void)stopDeamon; 730 | - (void)hideStatusBar_type; 731 | - (void)showOutSideAppReadNotificationForJID:(NSString *)jid; 732 | - (void)showOutSideDeliveredNotificationForJID:(NSString *)jid; 733 | - (void)showOutSideAppTypingNotificationForJID:(NSString *)jid; 734 | - (void)showInsideAppTypingNotificationForJID:(NSString *)jid; 735 | - (void)showInsideAppDeliveredNotificationForJID:(NSString *)jid; 736 | - (void)showInsideAppReadNotificationForJID:(NSString *)jid; 737 | - (void)createLocalNotificationFromMessage:(WAMessage *)message; 738 | 739 | - (void)showInsideAppProfilePictureNotificationForJID:(NSString *)jid isGroup:(BOOL)group; 740 | - (void)showInsideStatusNotificationForJID:(NSString *)jid withText:(NSString *)statusText isGroup:(BOOL)group; 741 | - (void)showOutSideProfilePictureNotificationForJID:(NSString *)jid isGroup:(BOOL)group; 742 | - (void)showOutSideStatusNotificationForJID:(NSString *)jid withText:(NSString *)statusText isGroup:(BOOL)group; 743 | - (void)writeJidToList:(NSString *)jid; 744 | - (BOOL)isJIDExisteInList:(NSString *)jid; 745 | - (void)writeJidToList:(NSString *)jid withStatus:(NSString *)status; 746 | @end 747 | 748 | @interface XMPPStatus : NSObject 749 | @property(retain, nonatomic) NSDate *timestamp; // @synthesize timestamp=_timestamp; 750 | @property(copy, nonatomic) NSString *jid; // @synthesize jid=_jid; 751 | @property(copy, nonatomic) NSString *text; // @synthesize text=_text; 752 | @end 753 | 754 | @interface WAChatButton : UIButton 755 | + (void)initialize; 756 | + (id)button; 757 | @property(nonatomic) _Bool backgroundHidden; // @synthesize backgroundHidden=_backgroundHidden; 758 | - (void)tintColorDidChange; 759 | - (void)configureForLegacyOS; 760 | - (void)configure; 761 | @property(nonatomic, getter=isSpinnerHidden) _Bool spinnerHidden; 762 | - (void)commonInit; 763 | - (void)awakeFromNib; 764 | - (id)initWithFrame:(CGRect)arg1; 765 | @end 766 | 767 | @interface WAChatListHeaderCell : UITableViewCell 768 | @property(readonly, nonatomic) UIButton *groupButton; // @synthesize groupButton=_groupButton; 769 | @property(readonly, nonatomic) UIButton *broadcastButton; // @synthesize broadcastButton=_broadcastButton; 770 | - (void)layoutSubviews; 771 | - (double)preferredHeight; 772 | - (id)init; 773 | @end 774 | 775 | @interface UIApplication (WARecents) 776 | - (id)_accessibilityFrontMostApplication; 777 | @end 778 | 779 | @interface WAChatSessionCell : UITableViewCell 780 | + (id)camcorderIconImageHighlighted; 781 | + (id)camcorderIconImage; 782 | + (id)cameraIconImageHighlighted; 783 | + (id)cameraIconImage; 784 | + (id)locationIconImageHighlighted; 785 | + (id)locationIconImage; 786 | + (id)microphoneImageHighlighted; 787 | + (id)microphoneImageForPTTIconType:(unsigned long long)arg1; 788 | + (id)cellWithReuseIdentifier:(id)arg1; 789 | // @property(nonatomic) __weak id delegate; // @synthesize delegate=_delegate; 790 | @end 791 | 792 | @interface WARecentsTable : UIViewController 793 | @property (strong, nonatomic) UITableView *infoTableView; 794 | @property (strong, nonatomic) NSMutableArray *listArray; 795 | @end 796 | 797 | @interface WAProfilePictureManager : NSObject 798 | + (id)fullPathToProfilePictureThumbnailForJID:(id)arg1; 799 | @end 800 | 801 | @interface WAContactsStorage : NSObject 802 | - (id)bestContactForJID:(id)arg1; 803 | - (id)capabilitiesForJid:(id)arg1; 804 | @end 805 | 806 | @interface WAContact : NSObject 807 | @property(retain, nonatomic) NSString *fullName; // @dynamic fullName; 808 | 809 | // Remaining properties 810 | @property(retain, nonatomic) NSNumber *abUserID; // @dynamic abUserID; 811 | @property(retain, nonatomic) NSSet *children; // @dynamic children; 812 | @property(retain, nonatomic) NSString *firstName; // @dynamic firstName; 813 | @property(retain, nonatomic) NSString *highlightedName; // @dynamic highlightedName; 814 | @property(retain, nonatomic) NSString *indexName; // @dynamic indexName; 815 | @property(retain, nonatomic) NSDate *lastModifiedDate; // @dynamic lastModifiedDate; 816 | // @property(retain, nonatomic) WAContact *parent; // @dynamic parent; 817 | @property(retain, nonatomic) NSSet *phones; // @dynamic phones; 818 | // @property(retain, nonatomic) WAContactSection *section; // @dynamic section; 819 | @property(retain, nonatomic) NSNumber *sort; // @dynamic sort; 820 | @property(retain, nonatomic) NSArray *tokens; // @dynamic tokens; 821 | @end 822 | 823 | @interface XMPPGroupNotification : NSObject 824 | @property(readonly, copy, nonatomic) NSString *groupJID; // @synthesize groupJID=_groupJID; 825 | @end 826 | 827 | @interface WAForwardActivity : UIActivity 828 | - (void)performActivity; 829 | - (id)activityViewController; 830 | - (void)prepareWithActivityItems:(id)arg1; 831 | - (_Bool)canPerformWithActivityItems:(id)arg1; 832 | - (id)activityType; 833 | @property(copy, nonatomic) NSString *activityTitle; 834 | - (id)activitySettingsImage; 835 | - (id)activityImage; 836 | - (id)initWithMessages:(id)arg1; 837 | @end 838 | 839 | @interface WAActivityViewController : UIActivityViewController 840 | { 841 | } 842 | 843 | - (id)_availableActivitiesForItems:(id)arg1 applicationExtensionActivities:(id)arg2; 844 | 845 | @end 846 | 847 | @interface DebugViewController : WAStaticTableViewController 848 | - (id)init; 849 | @end 850 | 851 | @interface WAMediaBrowserViewController : UIViewController 852 | @end 853 | -------------------------------------------------------------------------------- /YTEnhancerLite/MBProgressHUD.m: -------------------------------------------------------------------------------- 1 | // 2 | // MBProgressHUD.m 3 | // Version 0.9.2 4 | // Created by Matej Bukovinski on 2.4.09. 5 | // 6 | 7 | #import "MBProgressHUD.h" 8 | #import 9 | 10 | 11 | #if __has_feature(objc_arc) 12 | #define MB_AUTORELEASE(exp) exp 13 | #define MB_RELEASE(exp) exp 14 | #define MB_RETAIN(exp) exp 15 | #else 16 | #define MB_AUTORELEASE(exp) [exp autorelease] 17 | #define MB_RELEASE(exp) [exp release] 18 | #define MB_RETAIN(exp) [exp retain] 19 | #endif 20 | 21 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 22 | #define MBLabelAlignmentCenter NSTextAlignmentCenter 23 | #else 24 | #define MBLabelAlignmentCenter UITextAlignmentCenter 25 | #endif 26 | 27 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 28 | #define MB_TEXTSIZE(text, font) [text length] > 0 ? [text \ 29 | sizeWithAttributes:@{NSFontAttributeName:font}] : CGSizeZero; 30 | #else 31 | #define MB_TEXTSIZE(text, font) [text length] > 0 ? [text sizeWithFont:font] : CGSizeZero; 32 | #endif 33 | 34 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 35 | #define MB_MULTILINE_TEXTSIZE(text, font, maxSize, mode) [text length] > 0 ? [text \ 36 | boundingRectWithSize:maxSize options:(NSStringDrawingUsesLineFragmentOrigin) \ 37 | attributes:@{NSFontAttributeName:font} context:nil].size : CGSizeZero; 38 | #else 39 | #define MB_MULTILINE_TEXTSIZE(text, font, maxSize, mode) [text length] > 0 ? [text \ 40 | sizeWithFont:font constrainedToSize:maxSize lineBreakMode:mode] : CGSizeZero; 41 | #endif 42 | 43 | #ifndef kCFCoreFoundationVersionNumber_iOS_7_0 44 | #define kCFCoreFoundationVersionNumber_iOS_7_0 847.20 45 | #endif 46 | 47 | #ifndef kCFCoreFoundationVersionNumber_iOS_8_0 48 | #define kCFCoreFoundationVersionNumber_iOS_8_0 1129.15 49 | #endif 50 | 51 | 52 | static const CGFloat kPadding = 4.f; 53 | static const CGFloat kLabelFontSize = 16.f; 54 | static const CGFloat kDetailsLabelFontSize = 12.f; 55 | 56 | 57 | @interface MBProgressHUD () { 58 | BOOL useAnimation; 59 | SEL methodForExecution; 60 | id targetForExecution; 61 | id objectForExecution; 62 | UILabel *label; 63 | UILabel *detailsLabel; 64 | BOOL isFinished; 65 | CGAffineTransform rotationTransform; 66 | } 67 | 68 | @property (atomic, MB_STRONG) UIView *indicator; 69 | @property (atomic, MB_STRONG) NSTimer *graceTimer; 70 | @property (atomic, MB_STRONG) NSTimer *minShowTimer; 71 | @property (atomic, MB_STRONG) NSDate *showStarted; 72 | 73 | @end 74 | 75 | 76 | @implementation MBProgressHUD 77 | 78 | #pragma mark - Properties 79 | 80 | @synthesize animationType; 81 | @synthesize delegate; 82 | @synthesize opacity; 83 | @synthesize color; 84 | @synthesize labelFont; 85 | @synthesize labelColor; 86 | @synthesize detailsLabelFont; 87 | @synthesize detailsLabelColor; 88 | @synthesize indicator; 89 | @synthesize xOffset; 90 | @synthesize yOffset; 91 | @synthesize minSize; 92 | @synthesize square; 93 | @synthesize margin; 94 | @synthesize dimBackground; 95 | @synthesize graceTime; 96 | @synthesize minShowTime; 97 | @synthesize graceTimer; 98 | @synthesize minShowTimer; 99 | @synthesize taskInProgress; 100 | @synthesize removeFromSuperViewOnHide; 101 | @synthesize customView; 102 | @synthesize showStarted; 103 | @synthesize mode; 104 | @synthesize labelText; 105 | @synthesize detailsLabelText; 106 | @synthesize progress; 107 | @synthesize size; 108 | @synthesize activityIndicatorColor; 109 | #if NS_BLOCKS_AVAILABLE 110 | @synthesize completionBlock; 111 | #endif 112 | 113 | #pragma mark - Class methods 114 | 115 | + (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated { 116 | MBProgressHUD *hud = [[self alloc] initWithView:view]; 117 | hud.removeFromSuperViewOnHide = YES; 118 | [view addSubview:hud]; 119 | [hud show:animated]; 120 | return MB_AUTORELEASE(hud); 121 | } 122 | 123 | + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated { 124 | MBProgressHUD *hud = [self HUDForView:view]; 125 | if (hud != nil) { 126 | hud.removeFromSuperViewOnHide = YES; 127 | [hud hide:animated]; 128 | return YES; 129 | } 130 | return NO; 131 | } 132 | 133 | + (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated { 134 | NSArray *huds = [MBProgressHUD allHUDsForView:view]; 135 | for (MBProgressHUD *hud in huds) { 136 | hud.removeFromSuperViewOnHide = YES; 137 | [hud hide:animated]; 138 | } 139 | return [huds count]; 140 | } 141 | 142 | + (MB_INSTANCETYPE)HUDForView:(UIView *)view { 143 | NSEnumerator *subviewsEnum = [view.subviews reverseObjectEnumerator]; 144 | for (UIView *subview in subviewsEnum) { 145 | if ([subview isKindOfClass:self]) { 146 | return (MBProgressHUD *)subview; 147 | } 148 | } 149 | return nil; 150 | } 151 | 152 | + (NSArray *)allHUDsForView:(UIView *)view { 153 | NSMutableArray *huds = [NSMutableArray array]; 154 | NSArray *subviews = view.subviews; 155 | for (UIView *aView in subviews) { 156 | if ([aView isKindOfClass:self]) { 157 | [huds addObject:aView]; 158 | } 159 | } 160 | return [NSArray arrayWithArray:huds]; 161 | } 162 | 163 | #pragma mark - Lifecycle 164 | 165 | - (id)initWithFrame:(CGRect)frame { 166 | self = [super initWithFrame:frame]; 167 | if (self) { 168 | // Set default values for properties 169 | self.animationType = MBProgressHUDAnimationFade; 170 | self.mode = MBProgressHUDModeIndeterminate; 171 | self.labelText = nil; 172 | self.detailsLabelText = nil; 173 | self.opacity = 0.8f; 174 | self.color = nil; 175 | self.labelFont = [UIFont boldSystemFontOfSize:kLabelFontSize]; 176 | self.labelColor = [UIColor whiteColor]; 177 | self.detailsLabelFont = [UIFont boldSystemFontOfSize:kDetailsLabelFontSize]; 178 | self.detailsLabelColor = [UIColor whiteColor]; 179 | self.activityIndicatorColor = [UIColor whiteColor]; 180 | self.xOffset = 0.0f; 181 | self.yOffset = 0.0f; 182 | self.dimBackground = NO; 183 | self.margin = 20.0f; 184 | self.cornerRadius = 10.0f; 185 | self.graceTime = 0.0f; 186 | self.minShowTime = 0.0f; 187 | self.removeFromSuperViewOnHide = NO; 188 | self.minSize = CGSizeZero; 189 | self.square = NO; 190 | self.contentMode = UIViewContentModeCenter; 191 | self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin 192 | | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; 193 | 194 | // Transparent background 195 | self.opaque = NO; 196 | self.backgroundColor = [UIColor clearColor]; 197 | // Make it invisible for now 198 | self.alpha = 0.0f; 199 | 200 | taskInProgress = NO; 201 | rotationTransform = CGAffineTransformIdentity; 202 | 203 | [self setupLabels]; 204 | [self updateIndicators]; 205 | [self registerForKVO]; 206 | [self registerForNotifications]; 207 | } 208 | return self; 209 | } 210 | 211 | - (id)initWithView:(UIView *)view { 212 | NSAssert(view, @"View must not be nil."); 213 | return [self initWithFrame:view.bounds]; 214 | } 215 | 216 | - (id)initWithWindow:(UIWindow *)window { 217 | return [self initWithView:window]; 218 | } 219 | 220 | - (void)dealloc { 221 | [self unregisterFromNotifications]; 222 | [self unregisterFromKVO]; 223 | #if !__has_feature(objc_arc) 224 | [color release]; 225 | [indicator release]; 226 | [label release]; 227 | [detailsLabel release]; 228 | [labelText release]; 229 | [detailsLabelText release]; 230 | [graceTimer release]; 231 | [minShowTimer release]; 232 | [showStarted release]; 233 | [customView release]; 234 | [labelFont release]; 235 | [labelColor release]; 236 | [detailsLabelFont release]; 237 | [detailsLabelColor release]; 238 | #if NS_BLOCKS_AVAILABLE 239 | [completionBlock release]; 240 | #endif 241 | [super dealloc]; 242 | #endif 243 | } 244 | 245 | #pragma mark - Show & hide 246 | 247 | - (void)show:(BOOL)animated { 248 | NSAssert([NSThread isMainThread], @"MBProgressHUD needs to be accessed on the main thread."); 249 | useAnimation = animated; 250 | // If the grace time is set postpone the HUD display 251 | if (self.graceTime > 0.0) { 252 | NSTimer *newGraceTimer = [NSTimer timerWithTimeInterval:self.graceTime target:self selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO]; 253 | [[NSRunLoop currentRunLoop] addTimer:newGraceTimer forMode:NSRunLoopCommonModes]; 254 | self.graceTimer = newGraceTimer; 255 | } 256 | // ... otherwise show the HUD imediately 257 | else { 258 | [self showUsingAnimation:useAnimation]; 259 | } 260 | } 261 | 262 | - (void)hide:(BOOL)animated { 263 | NSAssert([NSThread isMainThread], @"MBProgressHUD needs to be accessed on the main thread."); 264 | useAnimation = animated; 265 | // If the minShow time is set, calculate how long the hud was shown, 266 | // and pospone the hiding operation if necessary 267 | if (self.minShowTime > 0.0 && showStarted) { 268 | NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:showStarted]; 269 | if (interv < self.minShowTime) { 270 | self.minShowTimer = [NSTimer scheduledTimerWithTimeInterval:(self.minShowTime - interv) target:self 271 | selector:@selector(handleMinShowTimer:) userInfo:nil repeats:NO]; 272 | return; 273 | } 274 | } 275 | // ... otherwise hide the HUD immediately 276 | [self hideUsingAnimation:useAnimation]; 277 | } 278 | 279 | - (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay { 280 | [self performSelector:@selector(hideDelayed:) withObject:[NSNumber numberWithBool:animated] afterDelay:delay]; 281 | } 282 | 283 | - (void)hideDelayed:(NSNumber *)animated { 284 | [self hide:[animated boolValue]]; 285 | } 286 | 287 | #pragma mark - Timer callbacks 288 | 289 | - (void)handleGraceTimer:(NSTimer *)theTimer { 290 | // Show the HUD only if the task is still running 291 | if (taskInProgress) { 292 | [self showUsingAnimation:useAnimation]; 293 | } 294 | } 295 | 296 | - (void)handleMinShowTimer:(NSTimer *)theTimer { 297 | [self hideUsingAnimation:useAnimation]; 298 | } 299 | 300 | #pragma mark - View Hierrarchy 301 | 302 | - (void)didMoveToSuperview { 303 | [self updateForCurrentOrientationAnimated:NO]; 304 | } 305 | 306 | #pragma mark - Internal show & hide operations 307 | 308 | - (void)showUsingAnimation:(BOOL)animated { 309 | // Cancel any scheduled hideDelayed: calls 310 | [NSObject cancelPreviousPerformRequestsWithTarget:self]; 311 | [self setNeedsDisplay]; 312 | 313 | if (animated && animationType == MBProgressHUDAnimationZoomIn) { 314 | self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5f, 0.5f)); 315 | } else if (animated && animationType == MBProgressHUDAnimationZoomOut) { 316 | self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5f, 1.5f)); 317 | } 318 | self.showStarted = [NSDate date]; 319 | // Fade in 320 | if (animated) { 321 | [UIView beginAnimations:nil context:NULL]; 322 | [UIView setAnimationDuration:0.30]; 323 | self.alpha = 1.0f; 324 | if (animationType == MBProgressHUDAnimationZoomIn || animationType == MBProgressHUDAnimationZoomOut) { 325 | self.transform = rotationTransform; 326 | } 327 | [UIView commitAnimations]; 328 | } 329 | else { 330 | self.alpha = 1.0f; 331 | } 332 | } 333 | 334 | - (void)hideUsingAnimation:(BOOL)animated { 335 | // Fade out 336 | if (animated && showStarted) { 337 | [UIView beginAnimations:nil context:NULL]; 338 | [UIView setAnimationDuration:0.30]; 339 | [UIView setAnimationDelegate:self]; 340 | [UIView setAnimationDidStopSelector:@selector(animationFinished:finished:context:)]; 341 | // 0.02 prevents the hud from passing through touches during the animation the hud will get completely hidden 342 | // in the done method 343 | if (animationType == MBProgressHUDAnimationZoomIn) { 344 | self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5f, 1.5f)); 345 | } else if (animationType == MBProgressHUDAnimationZoomOut) { 346 | self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5f, 0.5f)); 347 | } 348 | 349 | self.alpha = 0.02f; 350 | [UIView commitAnimations]; 351 | } 352 | else { 353 | self.alpha = 0.0f; 354 | [self done]; 355 | } 356 | self.showStarted = nil; 357 | } 358 | 359 | - (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void*)context { 360 | [self done]; 361 | } 362 | 363 | - (void)done { 364 | [NSObject cancelPreviousPerformRequestsWithTarget:self]; 365 | isFinished = YES; 366 | self.alpha = 0.0f; 367 | if (removeFromSuperViewOnHide) { 368 | [self removeFromSuperview]; 369 | } 370 | #if NS_BLOCKS_AVAILABLE 371 | if (self.completionBlock) { 372 | self.completionBlock(); 373 | self.completionBlock = NULL; 374 | } 375 | #endif 376 | if ([delegate respondsToSelector:@selector(hudWasHidden:)]) { 377 | [delegate performSelector:@selector(hudWasHidden:) withObject:self]; 378 | } 379 | } 380 | 381 | #pragma mark - Threading 382 | 383 | - (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated { 384 | methodForExecution = method; 385 | targetForExecution = MB_RETAIN(target); 386 | objectForExecution = MB_RETAIN(object); 387 | // Launch execution in new thread 388 | self.taskInProgress = YES; 389 | [NSThread detachNewThreadSelector:@selector(launchExecution) toTarget:self withObject:nil]; 390 | // Show HUD view 391 | [self show:animated]; 392 | } 393 | 394 | #if NS_BLOCKS_AVAILABLE 395 | 396 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block { 397 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 398 | [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:NULL]; 399 | } 400 | 401 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(void (^)())completion { 402 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 403 | [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:completion]; 404 | } 405 | 406 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue { 407 | [self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:NULL]; 408 | } 409 | 410 | - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue 411 | completionBlock:(MBProgressHUDCompletionBlock)completion { 412 | self.taskInProgress = YES; 413 | self.completionBlock = completion; 414 | dispatch_async(queue, ^(void) { 415 | block(); 416 | dispatch_async(dispatch_get_main_queue(), ^(void) { 417 | [self cleanUp]; 418 | }); 419 | }); 420 | [self show:animated]; 421 | } 422 | 423 | #endif 424 | 425 | - (void)launchExecution { 426 | @autoreleasepool { 427 | #pragma clang diagnostic push 428 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 429 | // Start executing the requested task 430 | [targetForExecution performSelector:methodForExecution withObject:objectForExecution]; 431 | #pragma clang diagnostic pop 432 | // Task completed, update view in main thread (note: view operations should 433 | // be done only in the main thread) 434 | [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO]; 435 | } 436 | } 437 | 438 | - (void)cleanUp { 439 | taskInProgress = NO; 440 | #if !__has_feature(objc_arc) 441 | [targetForExecution release]; 442 | [objectForExecution release]; 443 | #else 444 | targetForExecution = nil; 445 | objectForExecution = nil; 446 | #endif 447 | [self hide:useAnimation]; 448 | } 449 | 450 | #pragma mark - UI 451 | 452 | - (void)setupLabels { 453 | label = [[UILabel alloc] initWithFrame:self.bounds]; 454 | label.adjustsFontSizeToFitWidth = NO; 455 | label.textAlignment = MBLabelAlignmentCenter; 456 | label.opaque = NO; 457 | label.backgroundColor = [UIColor clearColor]; 458 | label.textColor = self.labelColor; 459 | label.font = self.labelFont; 460 | label.text = self.labelText; 461 | [self addSubview:label]; 462 | 463 | detailsLabel = [[UILabel alloc] initWithFrame:self.bounds]; 464 | detailsLabel.font = self.detailsLabelFont; 465 | detailsLabel.adjustsFontSizeToFitWidth = NO; 466 | detailsLabel.textAlignment = MBLabelAlignmentCenter; 467 | detailsLabel.opaque = NO; 468 | detailsLabel.backgroundColor = [UIColor clearColor]; 469 | detailsLabel.textColor = self.detailsLabelColor; 470 | detailsLabel.numberOfLines = 0; 471 | detailsLabel.font = self.detailsLabelFont; 472 | detailsLabel.text = self.detailsLabelText; 473 | [self addSubview:detailsLabel]; 474 | } 475 | 476 | - (void)updateIndicators { 477 | 478 | BOOL isActivityIndicator = [indicator isKindOfClass:[UIActivityIndicatorView class]]; 479 | BOOL isRoundIndicator = [indicator isKindOfClass:[MBRoundProgressView class]]; 480 | 481 | if (mode == MBProgressHUDModeIndeterminate) { 482 | if (!isActivityIndicator) { 483 | // Update to indeterminate indicator 484 | [indicator removeFromSuperview]; 485 | self.indicator = MB_AUTORELEASE([[UIActivityIndicatorView alloc] 486 | initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]); 487 | [(UIActivityIndicatorView *)indicator startAnimating]; 488 | [self addSubview:indicator]; 489 | } 490 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 491 | [(UIActivityIndicatorView *)indicator setColor:self.activityIndicatorColor]; 492 | #endif 493 | } 494 | else if (mode == MBProgressHUDModeDeterminateHorizontalBar) { 495 | // Update to bar determinate indicator 496 | [indicator removeFromSuperview]; 497 | self.indicator = MB_AUTORELEASE([[MBBarProgressView alloc] init]); 498 | [self addSubview:indicator]; 499 | } 500 | else if (mode == MBProgressHUDModeDeterminate || mode == MBProgressHUDModeAnnularDeterminate) { 501 | if (!isRoundIndicator) { 502 | // Update to determinante indicator 503 | [indicator removeFromSuperview]; 504 | self.indicator = MB_AUTORELEASE([[MBRoundProgressView alloc] init]); 505 | [self addSubview:indicator]; 506 | } 507 | if (mode == MBProgressHUDModeAnnularDeterminate) { 508 | [(MBRoundProgressView *)indicator setAnnular:YES]; 509 | } 510 | [(MBRoundProgressView *)indicator setProgressTintColor:self.activityIndicatorColor]; 511 | [(MBRoundProgressView *)indicator setBackgroundTintColor:[self.activityIndicatorColor colorWithAlphaComponent:0.1f]]; 512 | } 513 | else if (mode == MBProgressHUDModeCustomView && customView != indicator) { 514 | // Update custom view indicator 515 | [indicator removeFromSuperview]; 516 | self.indicator = customView; 517 | [self addSubview:indicator]; 518 | } else if (mode == MBProgressHUDModeText) { 519 | [indicator removeFromSuperview]; 520 | self.indicator = nil; 521 | } 522 | } 523 | 524 | #pragma mark - Layout 525 | 526 | - (void)layoutSubviews { 527 | [super layoutSubviews]; 528 | 529 | // Entirely cover the parent view 530 | UIView *parent = self.superview; 531 | if (parent) { 532 | self.frame = parent.bounds; 533 | } 534 | CGRect bounds = self.bounds; 535 | 536 | // Determine the total width and height needed 537 | CGFloat maxWidth = bounds.size.width - 4 * margin; 538 | CGSize totalSize = CGSizeZero; 539 | 540 | CGRect indicatorF = indicator.bounds; 541 | indicatorF.size.width = MIN(indicatorF.size.width, maxWidth); 542 | totalSize.width = MAX(totalSize.width, indicatorF.size.width); 543 | totalSize.height += indicatorF.size.height; 544 | 545 | CGSize labelSize = MB_TEXTSIZE(label.text, label.font); 546 | labelSize.width = MIN(labelSize.width, maxWidth); 547 | totalSize.width = MAX(totalSize.width, labelSize.width); 548 | totalSize.height += labelSize.height; 549 | if (labelSize.height > 0.f && indicatorF.size.height > 0.f) { 550 | totalSize.height += kPadding; 551 | } 552 | 553 | CGFloat remainingHeight = bounds.size.height - totalSize.height - kPadding - 4 * margin; 554 | CGSize maxSize = CGSizeMake(maxWidth, remainingHeight); 555 | CGSize detailsLabelSize = MB_MULTILINE_TEXTSIZE(detailsLabel.text, detailsLabel.font, maxSize, detailsLabel.lineBreakMode); 556 | totalSize.width = MAX(totalSize.width, detailsLabelSize.width); 557 | totalSize.height += detailsLabelSize.height; 558 | if (detailsLabelSize.height > 0.f && (indicatorF.size.height > 0.f || labelSize.height > 0.f)) { 559 | totalSize.height += kPadding; 560 | } 561 | 562 | totalSize.width += 2 * margin; 563 | totalSize.height += 2 * margin; 564 | 565 | // Position elements 566 | CGFloat yPos = round(((bounds.size.height - totalSize.height) / 2)) + margin + yOffset; 567 | CGFloat xPos = xOffset; 568 | indicatorF.origin.y = yPos; 569 | indicatorF.origin.x = round((bounds.size.width - indicatorF.size.width) / 2) + xPos; 570 | indicator.frame = indicatorF; 571 | yPos += indicatorF.size.height; 572 | 573 | if (labelSize.height > 0.f && indicatorF.size.height > 0.f) { 574 | yPos += kPadding; 575 | } 576 | CGRect labelF; 577 | labelF.origin.y = yPos; 578 | labelF.origin.x = round((bounds.size.width - labelSize.width) / 2) + xPos; 579 | labelF.size = labelSize; 580 | label.frame = labelF; 581 | yPos += labelF.size.height; 582 | 583 | if (detailsLabelSize.height > 0.f && (indicatorF.size.height > 0.f || labelSize.height > 0.f)) { 584 | yPos += kPadding; 585 | } 586 | CGRect detailsLabelF; 587 | detailsLabelF.origin.y = yPos; 588 | detailsLabelF.origin.x = round((bounds.size.width - detailsLabelSize.width) / 2) + xPos; 589 | detailsLabelF.size = detailsLabelSize; 590 | detailsLabel.frame = detailsLabelF; 591 | 592 | // Enforce minsize and quare rules 593 | if (square) { 594 | CGFloat max = MAX(totalSize.width, totalSize.height); 595 | if (max <= bounds.size.width - 2 * margin) { 596 | totalSize.width = max; 597 | } 598 | if (max <= bounds.size.height - 2 * margin) { 599 | totalSize.height = max; 600 | } 601 | } 602 | if (totalSize.width < minSize.width) { 603 | totalSize.width = minSize.width; 604 | } 605 | if (totalSize.height < minSize.height) { 606 | totalSize.height = minSize.height; 607 | } 608 | 609 | size = totalSize; 610 | } 611 | 612 | #pragma mark BG Drawing 613 | 614 | - (void)drawRect:(CGRect)rect { 615 | 616 | CGContextRef context = UIGraphicsGetCurrentContext(); 617 | UIGraphicsPushContext(context); 618 | 619 | if (self.dimBackground) { 620 | //Gradient colours 621 | size_t gradLocationsNum = 2; 622 | CGFloat gradLocations[2] = {0.0f, 1.0f}; 623 | CGFloat gradColors[8] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.75f}; 624 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 625 | CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum); 626 | CGColorSpaceRelease(colorSpace); 627 | //Gradient center 628 | CGPoint gradCenter= CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); 629 | //Gradient radius 630 | float gradRadius = MIN(self.bounds.size.width , self.bounds.size.height) ; 631 | //Gradient draw 632 | CGContextDrawRadialGradient (context, gradient, gradCenter, 633 | 0, gradCenter, gradRadius, 634 | kCGGradientDrawsAfterEndLocation); 635 | CGGradientRelease(gradient); 636 | } 637 | 638 | // Set background rect color 639 | if (self.color) { 640 | CGContextSetFillColorWithColor(context, self.color.CGColor); 641 | } else { 642 | CGContextSetGrayFillColor(context, 0.0f, self.opacity); 643 | } 644 | 645 | 646 | // Center HUD 647 | CGRect allRect = self.bounds; 648 | // Draw rounded HUD backgroud rect 649 | CGRect boxRect = CGRectMake(round((allRect.size.width - size.width) / 2) + self.xOffset, 650 | round((allRect.size.height - size.height) / 2) + self.yOffset, size.width, size.height); 651 | float radius = self.cornerRadius; 652 | CGContextBeginPath(context); 653 | CGContextMoveToPoint(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect)); 654 | CGContextAddArc(context, CGRectGetMaxX(boxRect) - radius, CGRectGetMinY(boxRect) + radius, radius, 3 * (float)M_PI / 2, 0, 0); 655 | CGContextAddArc(context, CGRectGetMaxX(boxRect) - radius, CGRectGetMaxY(boxRect) - radius, radius, 0, (float)M_PI / 2, 0); 656 | CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMaxY(boxRect) - radius, radius, (float)M_PI / 2, (float)M_PI, 0); 657 | CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect) + radius, radius, (float)M_PI, 3 * (float)M_PI / 2, 0); 658 | CGContextClosePath(context); 659 | CGContextFillPath(context); 660 | 661 | UIGraphicsPopContext(); 662 | } 663 | 664 | #pragma mark - KVO 665 | 666 | - (void)registerForKVO { 667 | for (NSString *keyPath in [self observableKeypaths]) { 668 | [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; 669 | } 670 | } 671 | 672 | - (void)unregisterFromKVO { 673 | for (NSString *keyPath in [self observableKeypaths]) { 674 | [self removeObserver:self forKeyPath:keyPath]; 675 | } 676 | } 677 | 678 | - (NSArray *)observableKeypaths { 679 | return [NSArray arrayWithObjects:@"mode", @"customView", @"labelText", @"labelFont", @"labelColor", 680 | @"detailsLabelText", @"detailsLabelFont", @"detailsLabelColor", @"progress", @"activityIndicatorColor", nil]; 681 | } 682 | 683 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 684 | if (![NSThread isMainThread]) { 685 | [self performSelectorOnMainThread:@selector(updateUIForKeypath:) withObject:keyPath waitUntilDone:NO]; 686 | } else { 687 | [self updateUIForKeypath:keyPath]; 688 | } 689 | } 690 | 691 | - (void)updateUIForKeypath:(NSString *)keyPath { 692 | if ([keyPath isEqualToString:@"mode"] || [keyPath isEqualToString:@"customView"] || 693 | [keyPath isEqualToString:@"activityIndicatorColor"]) { 694 | [self updateIndicators]; 695 | } else if ([keyPath isEqualToString:@"labelText"]) { 696 | label.text = self.labelText; 697 | } else if ([keyPath isEqualToString:@"labelFont"]) { 698 | label.font = self.labelFont; 699 | } else if ([keyPath isEqualToString:@"labelColor"]) { 700 | label.textColor = self.labelColor; 701 | } else if ([keyPath isEqualToString:@"detailsLabelText"]) { 702 | detailsLabel.text = self.detailsLabelText; 703 | } else if ([keyPath isEqualToString:@"detailsLabelFont"]) { 704 | detailsLabel.font = self.detailsLabelFont; 705 | } else if ([keyPath isEqualToString:@"detailsLabelColor"]) { 706 | detailsLabel.textColor = self.detailsLabelColor; 707 | } else if ([keyPath isEqualToString:@"progress"]) { 708 | if ([indicator respondsToSelector:@selector(setProgress:)]) { 709 | [(id)indicator setValue:@(progress) forKey:@"progress"]; 710 | } 711 | return; 712 | } 713 | [self setNeedsLayout]; 714 | [self setNeedsDisplay]; 715 | } 716 | 717 | #pragma mark - Notifications 718 | 719 | - (void)registerForNotifications { 720 | #if !TARGET_OS_TV 721 | NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 722 | 723 | [nc addObserver:self selector:@selector(statusBarOrientationDidChange:) 724 | name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; 725 | #endif 726 | } 727 | 728 | - (void)unregisterFromNotifications { 729 | #if !TARGET_OS_TV 730 | NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 731 | [nc removeObserver:self name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; 732 | #endif 733 | } 734 | 735 | #if !TARGET_OS_TV 736 | - (void)statusBarOrientationDidChange:(NSNotification *)notification { 737 | UIView *superview = self.superview; 738 | if (!superview) { 739 | return; 740 | } else { 741 | [self updateForCurrentOrientationAnimated:YES]; 742 | } 743 | } 744 | #endif 745 | 746 | - (void)updateForCurrentOrientationAnimated:(BOOL)animated { 747 | // Stay in sync with the superview in any case 748 | if (self.superview) { 749 | self.bounds = self.superview.bounds; 750 | [self setNeedsDisplay]; 751 | } 752 | 753 | // Not needed on iOS 8+, compile out when the deployment target allows, 754 | // to avoid sharedApplication problems on extension targets 755 | #if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 756 | // Only needed pre iOS 7 when added to a window 757 | BOOL iOS8OrLater = kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0; 758 | if (iOS8OrLater || ![self.superview isKindOfClass:[UIWindow class]]) return; 759 | 760 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 761 | CGFloat radians = 0; 762 | if (UIInterfaceOrientationIsLandscape(orientation)) { 763 | if (orientation == UIInterfaceOrientationLandscapeLeft) { radians = -(CGFloat)M_PI_2; } 764 | else { radians = (CGFloat)M_PI_2; } 765 | // Window coordinates differ! 766 | self.bounds = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.width); 767 | } else { 768 | if (orientation == UIInterfaceOrientationPortraitUpsideDown) { radians = (CGFloat)M_PI; } 769 | else { radians = 0; } 770 | } 771 | rotationTransform = CGAffineTransformMakeRotation(radians); 772 | 773 | if (animated) { 774 | [UIView beginAnimations:nil context:nil]; 775 | [UIView setAnimationDuration:0.3]; 776 | } 777 | [self setTransform:rotationTransform]; 778 | if (animated) { 779 | [UIView commitAnimations]; 780 | } 781 | #endif 782 | } 783 | 784 | @end 785 | 786 | 787 | @implementation MBRoundProgressView 788 | 789 | #pragma mark - Lifecycle 790 | 791 | - (id)init { 792 | return [self initWithFrame:CGRectMake(0.f, 0.f, 37.f, 37.f)]; 793 | } 794 | 795 | - (id)initWithFrame:(CGRect)frame { 796 | self = [super initWithFrame:frame]; 797 | if (self) { 798 | self.backgroundColor = [UIColor clearColor]; 799 | self.opaque = NO; 800 | _progress = 0.f; 801 | _annular = NO; 802 | _progressTintColor = [[UIColor alloc] initWithWhite:1.f alpha:1.f]; 803 | _backgroundTintColor = [[UIColor alloc] initWithWhite:1.f alpha:.1f]; 804 | [self registerForKVO]; 805 | } 806 | return self; 807 | } 808 | 809 | - (void)dealloc { 810 | [self unregisterFromKVO]; 811 | #if !__has_feature(objc_arc) 812 | [_progressTintColor release]; 813 | [_backgroundTintColor release]; 814 | [super dealloc]; 815 | #endif 816 | } 817 | 818 | #pragma mark - Drawing 819 | 820 | - (void)drawRect:(CGRect)rect { 821 | 822 | CGRect allRect = self.bounds; 823 | CGRect circleRect = CGRectInset(allRect, 2.0f, 2.0f); 824 | CGContextRef context = UIGraphicsGetCurrentContext(); 825 | 826 | if (_annular) { 827 | // Draw background 828 | BOOL isPreiOS7 = kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_7_0; 829 | CGFloat lineWidth = isPreiOS7 ? 5.f : 2.f; 830 | UIBezierPath *processBackgroundPath = [UIBezierPath bezierPath]; 831 | processBackgroundPath.lineWidth = lineWidth; 832 | processBackgroundPath.lineCapStyle = kCGLineCapButt; 833 | CGPoint center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); 834 | CGFloat radius = (self.bounds.size.width - lineWidth)/2; 835 | CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees 836 | CGFloat endAngle = (2 * (float)M_PI) + startAngle; 837 | [processBackgroundPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; 838 | [_backgroundTintColor set]; 839 | [processBackgroundPath stroke]; 840 | // Draw progress 841 | UIBezierPath *processPath = [UIBezierPath bezierPath]; 842 | processPath.lineCapStyle = isPreiOS7 ? kCGLineCapRound : kCGLineCapSquare; 843 | processPath.lineWidth = lineWidth; 844 | endAngle = (self.progress * 2 * (float)M_PI) + startAngle; 845 | [processPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; 846 | [_progressTintColor set]; 847 | [processPath stroke]; 848 | } else { 849 | // Draw background 850 | [_progressTintColor setStroke]; 851 | [_backgroundTintColor setFill]; 852 | CGContextSetLineWidth(context, 2.0f); 853 | CGContextFillEllipseInRect(context, circleRect); 854 | CGContextStrokeEllipseInRect(context, circleRect); 855 | // Draw progress 856 | CGPoint center = CGPointMake(allRect.size.width / 2, allRect.size.height / 2); 857 | CGFloat radius = (allRect.size.width - 4) / 2; 858 | CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees 859 | CGFloat endAngle = (self.progress * 2 * (float)M_PI) + startAngle; 860 | [_progressTintColor setFill]; 861 | CGContextMoveToPoint(context, center.x, center.y); 862 | CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0); 863 | CGContextClosePath(context); 864 | CGContextFillPath(context); 865 | } 866 | } 867 | 868 | #pragma mark - KVO 869 | 870 | - (void)registerForKVO { 871 | for (NSString *keyPath in [self observableKeypaths]) { 872 | [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; 873 | } 874 | } 875 | 876 | - (void)unregisterFromKVO { 877 | for (NSString *keyPath in [self observableKeypaths]) { 878 | [self removeObserver:self forKeyPath:keyPath]; 879 | } 880 | } 881 | 882 | - (NSArray *)observableKeypaths { 883 | return [NSArray arrayWithObjects:@"progressTintColor", @"backgroundTintColor", @"progress", @"annular", nil]; 884 | } 885 | 886 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 887 | [self setNeedsDisplay]; 888 | } 889 | 890 | @end 891 | 892 | 893 | @implementation MBBarProgressView 894 | 895 | #pragma mark - Lifecycle 896 | 897 | - (id)init { 898 | return [self initWithFrame:CGRectMake(.0f, .0f, 120.0f, 20.0f)]; 899 | } 900 | 901 | - (id)initWithFrame:(CGRect)frame { 902 | self = [super initWithFrame:frame]; 903 | if (self) { 904 | _progress = 0.f; 905 | _lineColor = [UIColor whiteColor]; 906 | _progressColor = [UIColor whiteColor]; 907 | _progressRemainingColor = [UIColor clearColor]; 908 | self.backgroundColor = [UIColor clearColor]; 909 | self.opaque = NO; 910 | [self registerForKVO]; 911 | } 912 | return self; 913 | } 914 | 915 | - (void)dealloc { 916 | [self unregisterFromKVO]; 917 | #if !__has_feature(objc_arc) 918 | [_lineColor release]; 919 | [_progressColor release]; 920 | [_progressRemainingColor release]; 921 | [super dealloc]; 922 | #endif 923 | } 924 | 925 | #pragma mark - Drawing 926 | 927 | - (void)drawRect:(CGRect)rect { 928 | CGContextRef context = UIGraphicsGetCurrentContext(); 929 | 930 | CGContextSetLineWidth(context, 2); 931 | CGContextSetStrokeColorWithColor(context,[_lineColor CGColor]); 932 | CGContextSetFillColorWithColor(context, [_progressRemainingColor CGColor]); 933 | 934 | // Draw background 935 | float radius = (rect.size.height / 2) - 2; 936 | CGContextMoveToPoint(context, 2, rect.size.height/2); 937 | CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius); 938 | CGContextAddLineToPoint(context, rect.size.width - radius - 2, 2); 939 | CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius); 940 | CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius); 941 | CGContextAddLineToPoint(context, radius + 2, rect.size.height - 2); 942 | CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height/2, radius); 943 | CGContextFillPath(context); 944 | 945 | // Draw border 946 | CGContextMoveToPoint(context, 2, rect.size.height/2); 947 | CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius); 948 | CGContextAddLineToPoint(context, rect.size.width - radius - 2, 2); 949 | CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius); 950 | CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius); 951 | CGContextAddLineToPoint(context, radius + 2, rect.size.height - 2); 952 | CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height/2, radius); 953 | CGContextStrokePath(context); 954 | 955 | CGContextSetFillColorWithColor(context, [_progressColor CGColor]); 956 | radius = radius - 2; 957 | float amount = self.progress * rect.size.width; 958 | 959 | // Progress in the middle area 960 | if (amount >= radius + 4 && amount <= (rect.size.width - radius - 4)) { 961 | CGContextMoveToPoint(context, 4, rect.size.height/2); 962 | CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); 963 | CGContextAddLineToPoint(context, amount, 4); 964 | CGContextAddLineToPoint(context, amount, radius + 4); 965 | 966 | CGContextMoveToPoint(context, 4, rect.size.height/2); 967 | CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); 968 | CGContextAddLineToPoint(context, amount, rect.size.height - 4); 969 | CGContextAddLineToPoint(context, amount, radius + 4); 970 | 971 | CGContextFillPath(context); 972 | } 973 | 974 | // Progress in the right arc 975 | else if (amount > radius + 4) { 976 | float x = amount - (rect.size.width - radius - 4); 977 | 978 | CGContextMoveToPoint(context, 4, rect.size.height/2); 979 | CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); 980 | CGContextAddLineToPoint(context, rect.size.width - radius - 4, 4); 981 | float angle = -acos(x/radius); 982 | if (isnan(angle)) angle = 0; 983 | CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height/2, radius, M_PI, angle, 0); 984 | CGContextAddLineToPoint(context, amount, rect.size.height/2); 985 | 986 | CGContextMoveToPoint(context, 4, rect.size.height/2); 987 | CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); 988 | CGContextAddLineToPoint(context, rect.size.width - radius - 4, rect.size.height - 4); 989 | angle = acos(x/radius); 990 | if (isnan(angle)) angle = 0; 991 | CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height/2, radius, -M_PI, angle, 1); 992 | CGContextAddLineToPoint(context, amount, rect.size.height/2); 993 | 994 | CGContextFillPath(context); 995 | } 996 | 997 | // Progress is in the left arc 998 | else if (amount < radius + 4 && amount > 0) { 999 | CGContextMoveToPoint(context, 4, rect.size.height/2); 1000 | CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); 1001 | CGContextAddLineToPoint(context, radius + 4, rect.size.height/2); 1002 | 1003 | CGContextMoveToPoint(context, 4, rect.size.height/2); 1004 | CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); 1005 | CGContextAddLineToPoint(context, radius + 4, rect.size.height/2); 1006 | 1007 | CGContextFillPath(context); 1008 | } 1009 | } 1010 | 1011 | #pragma mark - KVO 1012 | 1013 | - (void)registerForKVO { 1014 | for (NSString *keyPath in [self observableKeypaths]) { 1015 | [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; 1016 | } 1017 | } 1018 | 1019 | - (void)unregisterFromKVO { 1020 | for (NSString *keyPath in [self observableKeypaths]) { 1021 | [self removeObserver:self forKeyPath:keyPath]; 1022 | } 1023 | } 1024 | 1025 | - (NSArray *)observableKeypaths { 1026 | return [NSArray arrayWithObjects:@"lineColor", @"progressRemainingColor", @"progressColor", @"progress", nil]; 1027 | } 1028 | 1029 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 1030 | [self setNeedsDisplay]; 1031 | } 1032 | 1033 | @end 1034 | --------------------------------------------------------------------------------