diff --git a/BugshotKit.xcodeproj/project.pbxproj b/BugshotKit.xcodeproj/project.pbxproj index ded457f..2c52300 100644 --- a/BugshotKit.xcodeproj/project.pbxproj +++ b/BugshotKit.xcodeproj/project.pbxproj @@ -15,8 +15,6 @@ 4C15DA5F188F491000767C78 /* BSKAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C15DA47188F491000767C78 /* BSKAnnotationView.m */; }; 4C15DA61188F491000767C78 /* BSKCheckerboardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C15DA49188F491000767C78 /* BSKCheckerboardView.m */; }; 4C15DA63188F491000767C78 /* BSKLogViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C15DA4B188F491000767C78 /* BSKLogViewController.m */; }; - 4C15DA64188F491000767C78 /* BSKMainViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C15DA4C188F491000767C78 /* BSKMainViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4C15DA65188F491000767C78 /* BSKMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C15DA4D188F491000767C78 /* BSKMainViewController.m */; }; 4C15DA67188F491000767C78 /* BSKNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C15DA4F188F491000767C78 /* BSKNavigationController.m */; }; 4C15DA69188F491000767C78 /* BSKScreenshotViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C15DA51188F491000767C78 /* BSKScreenshotViewController.m */; }; 4C15DA6B188F491000767C78 /* BSKToggleButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C15DA53188F491000767C78 /* BSKToggleButton.m */; }; @@ -46,8 +44,6 @@ 4C15DA49188F491000767C78 /* BSKCheckerboardView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSKCheckerboardView.m; sourceTree = ""; }; 4C15DA4A188F491000767C78 /* BSKLogViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSKLogViewController.h; sourceTree = ""; }; 4C15DA4B188F491000767C78 /* BSKLogViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSKLogViewController.m; sourceTree = ""; }; - 4C15DA4C188F491000767C78 /* BSKMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSKMainViewController.h; sourceTree = ""; }; - 4C15DA4D188F491000767C78 /* BSKMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSKMainViewController.m; sourceTree = ""; }; 4C15DA4E188F491000767C78 /* BSKNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSKNavigationController.h; sourceTree = ""; }; 4C15DA4F188F491000767C78 /* BSKNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSKNavigationController.m; sourceTree = ""; }; 4C15DA50188F491000767C78 /* BSKScreenshotViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSKScreenshotViewController.h; sourceTree = ""; }; @@ -116,8 +112,6 @@ 4C15DA49188F491000767C78 /* BSKCheckerboardView.m */, 4C15DA4A188F491000767C78 /* BSKLogViewController.h */, 4C15DA4B188F491000767C78 /* BSKLogViewController.m */, - 4C15DA4C188F491000767C78 /* BSKMainViewController.h */, - 4C15DA4D188F491000767C78 /* BSKMainViewController.m */, 4C15DA4E188F491000767C78 /* BSKNavigationController.h */, 4C15DA4F188F491000767C78 /* BSKNavigationController.m */, 4C15DA50188F491000767C78 /* BSKScreenshotViewController.h */, @@ -152,7 +146,6 @@ files = ( 4C15DA70188F49AB00767C78 /* BugshotKit.h in Headers */, A9AF1AA418995AA90025693B /* MABGTimer.h in Headers */, - 4C15DA64188F491000767C78 /* BSKMainViewController.h in Headers */, 4C15DAA2188F563A00767C78 /* BSKWindow.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -248,7 +241,6 @@ 4C15DA63188F491000767C78 /* BSKLogViewController.m in Sources */, 4C15DA59188F491000767C78 /* BSKAnnotationArrowView.m in Sources */, 4C15DA5B188F491000767C78 /* BSKAnnotationBlurView.m in Sources */, - 4C15DA65188F491000767C78 /* BSKMainViewController.m in Sources */, A9AF1AA518995AA90025693B /* MABGTimer.m in Sources */, 4C15DA69188F491000767C78 /* BSKScreenshotViewController.m in Sources */, 4C15DA67188F491000767C78 /* BSKNavigationController.m in Sources */, diff --git a/BugshotKit/BSKLogViewController.m b/BugshotKit/BSKLogViewController.m index 071d401..a6918be 100755 --- a/BugshotKit/BSKLogViewController.m +++ b/BugshotKit/BSKLogViewController.m @@ -19,7 +19,6 @@ - (instancetype)init if ( (self = [super init]) ) { self.title = @"Debug Log"; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addMarkerButtonTapped:)]; - [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(updateLiveLog:) name:BSKNewLogMessageNotification object:nil]; } return self; } @@ -37,13 +36,6 @@ - (void)viewDidLoad UIView *console = ([BugshotKit.sharedManager displayConsoleTextInLogViewer] ? self.consoleTextView : self.consoleView); [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[c]|" options:0 metrics:nil views:@{ @"c" : console }]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[top][c]|" options:0 metrics:nil views:@{ @"c" : console, @"top" : self.topLayoutGuide }]]; - - dispatch_async(dispatch_get_main_queue(), ^{ [self updateLiveLog:nil]; }); -} - -- (void)dealloc -{ - [NSNotificationCenter.defaultCenter removeObserver:self name:BSKNewLogMessageNotification object:nil]; } - (void)loadView @@ -71,23 +63,4 @@ - (void)loadView self.view = view; } -- (void)updateLiveLog:(NSNotification *)n -{ - if (! self.isViewLoaded) return; - - if ([BugshotKit.sharedManager displayConsoleTextInLogViewer]) { - [BugshotKit.sharedManager currentConsoleLogWithDateStamps:YES - withCompletion:^(NSString *result) { - self.consoleTextView.text = result; - [self.consoleTextView scrollRangeToVisible:NSMakeRange([result length], 0)]; - }]; - } - else { - [BugshotKit.sharedManager consoleImageWithSize:self.consoleView.bounds.size fontSize:(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? 13.0f : 9.0f) emptyBottomLine:YES withCompletion:^(UIImage *image) { - self.consoleView.image = image; - }]; - } -} - - @end diff --git a/BugshotKit/BSKMainViewController.h b/BugshotKit/BSKMainViewController.h deleted file mode 100755 index 0056a63..0000000 --- a/BugshotKit/BSKMainViewController.h +++ /dev/null @@ -1,21 +0,0 @@ -// BSKMainViewController.h -// See included LICENSE file for the (MIT) license. -// Created by Marco Arment on 1/17/14. - -#import -@import MessageUI; - -@class BSKMainViewController; - -@protocol BSKMainViewControllerDelegate - -- (void)mainViewControllerDidClose:(BSKMainViewController *)mainViewController; - -@end - - -@interface BSKMainViewController : UITableViewController - -@property (nonatomic, weak) id delegate; - -@end diff --git a/BugshotKit/BSKMainViewController.m b/BugshotKit/BSKMainViewController.m deleted file mode 100755 index 6d8def4..0000000 --- a/BugshotKit/BSKMainViewController.m +++ /dev/null @@ -1,391 +0,0 @@ -// BSKMainViewController.m -// See included LICENSE file for the (MIT) license. -// Created by Marco Arment on 1/17/14. - -#import "BSKMainViewController.h" -#import "BugshotKit.h" -#import "BSKLogViewController.h" -#import "BSKScreenshotViewController.h" -#import "BSKToggleButton.h" -#import -#import -#include -#include - -static UIImage *rotateIfNeeded(UIImage *src); - -@interface BSKMainViewController () -@property (nonatomic) BSKToggleButton *includeScreenshotToggle; -@property (nonatomic) BSKToggleButton *includeLogToggle; -@property (nonatomic) UIButton *screenshotView; -@property (nonatomic) UIImageView *screenshotAccessoryView; -@property (nonatomic) UIButton *consoleView; -@property (nonatomic) UIImageView *consoleAccessoryView; -@property (nonatomic) UILabel *screenshotLabel; -@property (nonatomic) UILabel *consoleLabel; -@end - -@implementation BSKMainViewController - -- (BOOL)shouldAutorotate { return NO; } - -- (instancetype)init -{ - if ( (self = [super initWithStyle:UITableViewStyleGrouped]) ) { - [BugshotKit.sharedManager addObserver:self forKeyPath:@"annotatedImage" options:0 context:NULL]; - [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(updateLiveLog:) name:BSKNewLogMessageNotification object:nil]; - - self.title = @"Bugshot"; - self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelButtonTapped:)]; - self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil]; - } - return self; -} - -- (void)dealloc -{ - [BugshotKit.sharedManager removeObserver:self forKeyPath:@"annotatedImage"]; - [NSNotificationCenter.defaultCenter removeObserver:self name:BSKNewLogMessageNotification object:nil]; -} - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - CGSize chevronSize = CGSizeMake(15, 30); - UIImage *chevronImage = BSKImageWithDrawing(chevronSize, ^{ - CGRect chevronBounds = CGRectMake(0, 0, chevronSize.width, chevronSize.height); - chevronBounds = CGRectInset(chevronBounds, 3.0f, 6.0f); - - UIBezierPath *path = [UIBezierPath bezierPath]; - [path moveToPoint:CGPointMake(chevronBounds.origin.x, chevronBounds.origin.y)]; - [path addLineToPoint:CGPointMake(chevronBounds.origin.x + chevronBounds.size.width, chevronBounds.origin.y + (chevronBounds.size.height / 2.0f))]; - [path addLineToPoint:CGPointMake(chevronBounds.origin.x, chevronBounds.origin.y + chevronBounds.size.height)]; - [path setLineWidth:ceilf((float)chevronSize.width * 0.2f)]; - [BugshotKit.sharedManager.toggleOffColor setStroke]; - [path stroke]; - }); - - UIImage *screenshotImage = (BugshotKit.sharedManager.annotatedImage ?: BugshotKit.sharedManager.snapshotImage); - - CGFloat maxHeaderHeight = - UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? (UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? 570 : 480) : - UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? (UIScreen.mainScreen.bounds.size.height < 568 ? 300 : 340) : 220 - ; - UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, maxHeaderHeight)]; - - UIView *screenshotContainer = [UIView new]; - screenshotContainer.translatesAutoresizingMaskIntoConstraints = NO; - - UIView *consoleContainer = [UIView new]; - consoleContainer.translatesAutoresizingMaskIntoConstraints = NO; - - self.screenshotLabel = [UILabel new]; - self.screenshotLabel.text = @"SCREENSHOT"; - self.screenshotLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption2]; - self.screenshotLabel.textColor = BugshotKit.sharedManager.annotationFillColor; - self.screenshotLabel.textAlignment = NSTextAlignmentCenter; - self.screenshotLabel.translatesAutoresizingMaskIntoConstraints = NO; - [screenshotContainer addSubview:self.screenshotLabel]; - - self.consoleLabel = [UILabel new]; - self.consoleLabel.text = @"LOG"; - self.consoleLabel.font = self.screenshotLabel.font; - self.consoleLabel.textAlignment = self.screenshotLabel.textAlignment; - self.consoleLabel.textColor = self.screenshotLabel.textColor; - self.consoleLabel.translatesAutoresizingMaskIntoConstraints = NO; - [consoleContainer addSubview:self.consoleLabel]; - - CGFloat toggleWidth = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && UIInterfaceOrientationIsLandscape(self.interfaceOrientation) ? 44 : 74; - - self.includeScreenshotToggle = [[BSKToggleButton alloc] initWithFrame:CGRectMake(0, 0, toggleWidth, toggleWidth)]; - self.includeScreenshotToggle.on = YES; - [self.includeScreenshotToggle addTarget:self action:@selector(includeScreenshotToggled:) forControlEvents:UIControlEventValueChanged]; - self.includeScreenshotToggle.translatesAutoresizingMaskIntoConstraints = NO; - self.includeScreenshotToggle.accessibilityLabel = @"Include screenshot"; - [screenshotContainer addSubview:self.includeScreenshotToggle]; - - self.includeLogToggle = [[BSKToggleButton alloc] initWithFrame:CGRectMake(0, 0, toggleWidth, toggleWidth)]; - self.includeLogToggle.on = YES; - [self.includeLogToggle addTarget:self action:@selector(includeLogToggled:) forControlEvents:UIControlEventValueChanged]; - self.includeLogToggle.translatesAutoresizingMaskIntoConstraints = NO; - self.includeLogToggle.accessibilityLabel = @"Include log"; - [consoleContainer addSubview:self.includeLogToggle]; - - self.screenshotView = [UIButton buttonWithType:UIButtonTypeCustom]; - [self.screenshotView addTarget:self action:@selector(openScreenshotEditor:) forControlEvents:UIControlEventTouchUpInside]; - [self.screenshotView setBackgroundImage:screenshotImage forState:UIControlStateNormal]; - self.screenshotView.translatesAutoresizingMaskIntoConstraints = NO; - self.screenshotView.layer.borderColor = BugshotKit.sharedManager.annotationFillColor.CGColor; - self.screenshotView.layer.borderWidth = 1.0f; - self.screenshotView.accessibilityLabel = @"Annotate screenshot"; - [screenshotContainer addSubview:self.screenshotView]; - - self.consoleView = [UIButton buttonWithType:UIButtonTypeCustom]; - [self.consoleView addTarget:self action:@selector(openConsoleViewer:) forControlEvents:UIControlEventTouchUpInside]; - self.consoleView.translatesAutoresizingMaskIntoConstraints = NO; - self.consoleView.layer.borderColor = BugshotKit.sharedManager.annotationFillColor.CGColor; - self.consoleView.layer.borderWidth = 1.0f; - self.consoleView.accessibilityLabel = @"View log"; - self.consoleView.backgroundColor = UIColor.whiteColor; - [consoleContainer addSubview:self.consoleView]; - - self.screenshotAccessoryView = [[UIImageView alloc] initWithImage:chevronImage]; - self.screenshotAccessoryView.translatesAutoresizingMaskIntoConstraints = NO; - self.screenshotAccessoryView.isAccessibilityElement = NO; - [screenshotContainer addSubview:self.screenshotAccessoryView]; - - self.consoleAccessoryView = [[UIImageView alloc] initWithImage:chevronImage]; - self.consoleAccessoryView.translatesAutoresizingMaskIntoConstraints = NO; - self.consoleAccessoryView.isAccessibilityElement = NO; - [consoleContainer addSubview:self.consoleAccessoryView]; - - // Make both images match the screenshot's aspect ratio (and lock its ratio) - CGSize imageSize = screenshotImage.size; - CGFloat imageAspect = imageSize.width / imageSize.height; - [screenshotContainer addConstraint:[NSLayoutConstraint - constraintWithItem:self.screenshotView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.screenshotView attribute:NSLayoutAttributeHeight multiplier:imageAspect constant:0 - ]]; - [consoleContainer addConstraint:[NSLayoutConstraint - constraintWithItem:self.consoleView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.consoleView attribute:NSLayoutAttributeHeight multiplier:imageAspect constant:0 - ]]; - - void (^layoutScreenshotUnit)(UIView *container, NSDictionary *views) = ^(UIView *container, NSDictionary *views){ - NSDictionary *metrics = @{ - @"aw" : @(chevronSize.width), @"ah" : @(chevronSize.height), @"apad" : @(chevronSize.width + 5.0f), - @"lfont" : @( ((UILabel *)views[@"label"]).font.pointSize ), - @"padImageHeight" : @(384) - }; - - [container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-15-[label(>=lfont)]-5-[image]-15-[toggle]" options:0 metrics:metrics views:views]]; - [container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"[accessory(==aw)]|" options:0 metrics:metrics views:views]]; - [container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[accessory(==ah)]" options:0 metrics:metrics views:views]]; - [container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[label]|" options:0 metrics:nil views:views]]; - [container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-apad-[image]-apad-|" options:0 metrics:metrics views:views]]; - [container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[toggle]-15-|" options:0 metrics:nil views:views]]; - - // horizontally center toggle - [container addConstraint:[NSLayoutConstraint - constraintWithItem:views[@"toggle"] attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:container attribute:NSLayoutAttributeCenterX multiplier:1 constant:0 - ]]; - - // vertically center accessory to image - [container addConstraint:[NSLayoutConstraint - constraintWithItem:views[@"accessory"] attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:views[@"image"] attribute:NSLayoutAttributeCenterY multiplier:1 constant:0 - ]]; - - // toggle is always square - [container addConstraint:[NSLayoutConstraint - constraintWithItem:views[@"toggle"] attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:views[@"toggle"] attribute:NSLayoutAttributeWidth multiplier:1 constant:0 - ]]; - }; - - layoutScreenshotUnit(screenshotContainer, @{ - @"label" : self.screenshotLabel, - @"image" : self.screenshotView, - @"accessory" : self.screenshotAccessoryView, - @"toggle" : self.includeScreenshotToggle - }); - - layoutScreenshotUnit(consoleContainer, @{ - @"label" : self.consoleLabel, - @"image" : self.consoleView, - @"accessory" : self.consoleAccessoryView, - @"toggle" : self.includeLogToggle - }); - - [headerView addSubview:screenshotContainer]; - [headerView addSubview:consoleContainer]; - - NSDictionary *views = NSDictionaryOfVariableBindings(screenshotContainer, consoleContainer); - [headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[screenshotContainer]|" options:0 metrics:nil views:views]]; - [headerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[consoleContainer]|" options:0 metrics:nil views:views]]; - - [headerView addConstraint:[NSLayoutConstraint - constraintWithItem:screenshotContainer attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationLessThanOrEqual toItem:headerView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0 - ]]; - [headerView addConstraint:[NSLayoutConstraint - constraintWithItem:consoleContainer attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationLessThanOrEqual toItem:headerView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0 - ]]; - - [headerView addConstraint:[NSLayoutConstraint - constraintWithItem:screenshotContainer attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:consoleContainer attribute:NSLayoutAttributeWidth multiplier:1 constant:0 - ]]; - - [headerView sizeToFit]; - self.tableView.tableHeaderView = headerView; - - dispatch_async(dispatch_get_main_queue(), ^{ - [self updateLiveLog:nil]; - }); -} - -- (void)openScreenshotEditor:(id)sender -{ - [self.navigationController pushViewController:[[BSKScreenshotViewController alloc] initWithImage:BugshotKit.sharedManager.snapshotImage annotations:BugshotKit.sharedManager.annotations] animated:YES]; -} - -- (void)openConsoleViewer:(id)sender -{ - [self.navigationController pushViewController:[[BSKLogViewController alloc] init] animated:YES]; -} - -- (void)includeScreenshotToggled:(id)sender -{ - if (self.includeScreenshotToggle.on) { - self.screenshotLabel.textColor = BugshotKit.sharedManager.annotationFillColor; - self.screenshotView.layer.borderColor = BugshotKit.sharedManager.annotationFillColor.CGColor; - } else { - self.screenshotLabel.textColor = BugshotKit.sharedManager.toggleOffColor; - self.screenshotView.layer.borderColor = BugshotKit.sharedManager.toggleOffColor.CGColor; - } -} - -- (void)includeLogToggled:(id)sender -{ - if (self.includeLogToggle.on) { - self.consoleLabel.textColor = BugshotKit.sharedManager.annotationFillColor; - self.consoleView.layer.borderColor = BugshotKit.sharedManager.annotationFillColor.CGColor; - } else { - self.consoleLabel.textColor = BugshotKit.sharedManager.toggleOffColor; - self.consoleView.layer.borderColor = BugshotKit.sharedManager.toggleOffColor.CGColor; - } -} - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context -{ - if (! self.isViewLoaded) return; - [self.screenshotView setBackgroundImage:(BugshotKit.sharedManager.annotatedImage ?: BugshotKit.sharedManager.snapshotImage) forState:UIControlStateNormal]; -} - -- (void)cancelButtonTapped:(id)sender -{ - [self.navigationController.presentingViewController dismissViewControllerAnimated:YES completion:^{ - if (self.delegate) [self.delegate mainViewControllerDidClose:self]; - }]; -} - -- (void)consoleButtonTapped:(id)sender -{ - [self.navigationController pushViewController:[[BSKLogViewController alloc] init] animated:YES]; -} - -- (void)sendButtonTapped:(id)sender -{ - if (self.includeLogToggle.on) { - [BugshotKit.sharedManager currentConsoleLogWithDateStamps:YES withCompletion:^(NSString *result) { - [self sendButtonTappedWithLog:result]; - }]; - } - else { - [self sendButtonTappedWithLog:nil]; - } -} - -- (void)sendButtonTappedWithLog:(NSString *)log -{ - UIImage *screenshot = self.includeScreenshotToggle.on ? (BugshotKit.sharedManager.annotatedImage ?: BugshotKit.sharedManager.snapshotImage) : nil; - if (log && ! log.length) log = nil; - - NSString *appNameString = [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"]; - NSString *appVersionString = [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"]; - - size_t size; - sysctlbyname("hw.machine", NULL, &size, NULL, 0); - char *name = malloc(size); - sysctlbyname("hw.machine", name, &size, NULL, 0); - NSString *modelIdentifier = [NSString stringWithCString:name encoding:NSUTF8StringEncoding]; - free(name); - - NSDictionary *userInfo = @{ - @"appName" : appNameString, - @"appVersion" : appVersionString, - @"systemVersion" : UIDevice.currentDevice.systemVersion, - @"deviceModel" : modelIdentifier, - }; - - NSDictionary *extraUserInfo = BugshotKit.sharedManager.extraInfoBlock ? BugshotKit.sharedManager.extraInfoBlock() : nil; - if (extraUserInfo) { - userInfo = userInfo.mutableCopy; - [(NSMutableDictionary *)userInfo addEntriesFromDictionary:extraUserInfo]; - }; - - NSData *userInfoJSON = [NSJSONSerialization dataWithJSONObject:userInfo options:NSJSONWritingPrettyPrinted error:NULL]; - - MFMailComposeViewController *mf = [MFMailComposeViewController canSendMail] ? [[MFMailComposeViewController alloc] init] : nil; - if (! mf) { - NSString *msg = [NSString stringWithFormat:@"Mail is not configured on your %@.", UIDevice.currentDevice.localizedModel]; - [[[UIAlertView alloc] initWithTitle:@"Cannot Send Mail" message:msg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; - return; - } - - mf.toRecipients = [BugshotKit.sharedManager.destinationEmailAddress componentsSeparatedByString:@","]; - mf.subject = BugshotKit.sharedManager.emailSubjectBlock ? BugshotKit.sharedManager.emailSubjectBlock(userInfo) : [NSString stringWithFormat:@"%@ %@ Feedback", appNameString, appVersionString]; - [mf setMessageBody:BugshotKit.sharedManager.emailBodyBlock ? BugshotKit.sharedManager.emailBodyBlock(userInfo) : nil isHTML:NO]; - - if (screenshot) [mf addAttachmentData:UIImagePNGRepresentation(rotateIfNeeded(screenshot)) mimeType:@"image/png" fileName:@"screenshot.png"]; - if (log) [mf addAttachmentData:[log dataUsingEncoding:NSUTF8StringEncoding] mimeType:@"text/plain" fileName:@"log.txt"]; - if (userInfoJSON) [mf addAttachmentData:userInfoJSON mimeType:@"application/json" fileName:@"info.json"]; - if(BugshotKit.sharedManager.mailComposeCustomizeBlock) BugshotKit.sharedManager.mailComposeCustomizeBlock(mf); - - mf.mailComposeDelegate = self; - [self presentViewController:mf animated:YES completion:NULL]; -} - -- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error -{ - [self dismissViewControllerAnimated:YES completion:^{ - if (result == MFMailComposeResultSaved || result == MFMailComposeResultSent) [self cancelButtonTapped:nil]; - }]; -} - -#pragma mark - Table junk - -- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 1; } - -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; - cell.textLabel.textAlignment = NSTextAlignmentCenter; - cell.textLabel.textColor = BugshotKit.sharedManager.annotationFillColor; - cell.textLabel.text = @"Compose Email…"; - - return cell; -} - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ - [self sendButtonTapped:nil]; - [tableView deselectRowAtIndexPath:indexPath animated:YES]; -} - -#pragma mark - Live console image - -- (void)updateLiveLog:(NSNotification *)n -{ - if (! self.isViewLoaded) return; - [BugshotKit.sharedManager consoleImageWithSize:self.consoleView.bounds.size fontSize:7 emptyBottomLine:NO withCompletion:^(UIImage *image) { - [self.consoleView setBackgroundImage:image forState:UIControlStateNormal]; - }]; -} - -@end - - -// By Matteo Gavagnin on 21/01/14. -static UIImage *rotateIfNeeded(UIImage *src) -{ - if (src.imageOrientation == UIImageOrientationDown && src.size.width < src.size.height) { - UIGraphicsBeginImageContext(src.size); - [src drawAtPoint:CGPointMake(0, 0)]; - return UIGraphicsGetImageFromCurrentImageContext(); - } else if ((src.imageOrientation == UIImageOrientationLeft || src.imageOrientation == UIImageOrientationRight) && src.size.width > src.size.height) { - UIGraphicsBeginImageContext(src.size); - [src drawAtPoint:CGPointMake(0, 0)]; - return UIGraphicsGetImageFromCurrentImageContext(); - } else { - return src; - } -} diff --git a/BugshotKit/BSKScreenshotViewController.h b/BugshotKit/BSKScreenshotViewController.h index 4f99a10..690feb7 100755 --- a/BugshotKit/BSKScreenshotViewController.h +++ b/BugshotKit/BSKScreenshotViewController.h @@ -5,10 +5,21 @@ #import #import -@interface BSKScreenshotViewController : UIViewController +@import MessageUI; + +@class BSKScreenshotViewController; + +@protocol BSKScreenshotViewControllerDelegate + +- (void)screenshotViewControllerDidClose:(BSKScreenshotViewController *)screenshotViewController; + +@end + +@interface BSKScreenshotViewController : UIViewController - (id)initWithImage:(UIImage *)image annotations:(NSArray *)annotations; +@property (nonatomic, weak) id delegate; @property (nonatomic, retain) IBOutlet UIImageView *screenshotImageView; @end diff --git a/BugshotKit/BSKScreenshotViewController.m b/BugshotKit/BSKScreenshotViewController.m index e15bdde..9c85166 100755 --- a/BugshotKit/BSKScreenshotViewController.m +++ b/BugshotKit/BSKScreenshotViewController.m @@ -9,6 +9,7 @@ #import "BSKAnnotationBlurView.h" #import #import "BSKCheckerboardView.h" +#include #define kAnnotationToolArrow 0 #define kAnnotationToolBox 1 @@ -18,6 +19,7 @@ #define kGridOverlayOpacity 0.2f +static UIImage *rotateIfNeeded(UIImage *src); @interface BSKScreenshotViewController () { BSKAnnotationView *annotationInProgress; @@ -64,41 +66,24 @@ - (id)initWithImage:(UIImage *)image annotations:(NSArray *)annotations [[UIBezierPath bezierPathWithRoundedRect:boxRect cornerRadius:4.0f] stroke]; }); - CGSize blurIconSize = CGSizeMake(20, 20); - UIImage *blurIcon = BSKImageWithDrawing(blurIconSize, ^{ - [UIColor.blackColor setStroke]; - [UIColor.blackColor setFill]; - - CGRect blurRect = CGRectMake(0, 0, blurIconSize.width, blurIconSize.height); - blurRect = CGRectInset(blurRect, 2.5f, 2.5f); - - [[UIBezierPath bezierPathWithRect:blurRect] stroke]; - - CGRect quarterRect = CGRectMake(blurRect.origin.x, blurRect.origin.y, blurRect.size.width / 2.0f, blurRect.size.height / 2.0f); - [[UIBezierPath bezierPathWithRect:quarterRect] fill]; - quarterRect.origin.x += blurRect.size.width / 2.0f; - quarterRect.origin.y += blurRect.size.width / 2.0f; - [[UIBezierPath bezierPathWithRect:quarterRect] fill]; - }); - arrowIcon.accessibilityLabel = @"Arrow"; boxIcon.accessibilityLabel = @"Box"; boxIcon.accessibilityLabel = @"Blur"; - UISegmentedControl *annotationPicker = [[UISegmentedControl alloc] initWithItems:@[ arrowIcon, boxIcon, blurIcon ]]; - annotationPicker.accessibilityLabel = @"Drawing tool"; - annotationPicker.tintColor = BugshotKit.sharedManager.annotationFillColor; + NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; - annotationToolChosen = kAnnotationToolArrow; - annotationPicker.selectedSegmentIndex = annotationToolChosen; + self.navigationItem.prompt = [NSString stringWithFormat:@"Thank you for trying out %@!", [info objectForKey:@"CFBundleDisplayName"]]; - [annotationPicker setWidth:65.0f forSegmentAtIndex:kAnnotationToolArrow]; - [annotationPicker setWidth:65.0f forSegmentAtIndex:kAnnotationToolBox]; - [annotationPicker setWidth:65.0f forSegmentAtIndex:kAnnotationToolBlur]; + UILabel *infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 80, 44)]; + infoLabel.text = @"Drag to draw arrows"; + infoLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:12.0f]; + infoLabel.textColor = [UIColor darkGrayColor]; + infoLabel.numberOfLines = 0; + infoLabel.textAlignment = NSTextAlignmentCenter; - [self annotationPickerPicked:annotationPicker]; - [annotationPicker addTarget:self action:@selector(annotationPickerPicked:) forControlEvents:UIControlEventValueChanged]; - self.navigationItem.titleView = annotationPicker; + self.navigationItem.titleView = infoLabel; + + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStyleBordered target:self action:@selector(cancelButtonTapped:)]; self.contentAreaTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(contentAreaTapped:)]; } @@ -135,40 +120,105 @@ - (void)loadView [view addGestureRecognizer:self.contentAreaTapGestureRecognizer]; self.view = view; + self.navigationController.toolbarHidden = NO; + + // toolbarItems doesn't work ... + UIButton *sendButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, 44)]; + sendButton.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleTopMargin; + [sendButton setTitle:@"Send Email" forState:UIControlStateNormal]; + [sendButton setTitleColor:[UIColor colorWithRed:0.0 green:122.0/255.0 blue:1.0 alpha:1.0] forState:UIControlStateNormal]; + [sendButton setTitleColor:[UIColor colorWithRed:0.0 green:122.0/255.0 blue:1.0 alpha:0.2] forState:UIControlStateHighlighted]; + [sendButton addTarget:self action:@selector(sendButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; + [self.navigationController.toolbar addSubview:sendButton]; } -- (void)viewWillDisappear:(BOOL)animated +- (void)contentAreaTapped:(UITapGestureRecognizer *)sender { - self.gridOverlay.hidden = YES; + if (sender.state == UIGestureRecognizerStateRecognized && ! UIAccessibilityIsVoiceOverRunning()) { + BOOL hidden = ! self.navigationController.navigationBarHidden; + [self.navigationController setNavigationBarHidden:hidden animated:YES]; + [self.navigationController setToolbarHidden:hidden animated:YES]; + [UIView animateWithDuration:UINavigationControllerHideShowBarDuration animations:^{ + self.gridOverlay.alpha = hidden ? 0.0f : kGridOverlayOpacity; + }]; + } +} + +- (void)cancelButtonTapped:(id)sender +{ + [self.navigationController.presentingViewController dismissViewControllerAnimated:YES completion:^{ + if (self.delegate) [self.delegate screenshotViewControllerDidClose:self]; + }]; +} +- (void)sendButtonTapped:(UIButton *)sender +{ + sender.enabled = NO; + + self.gridOverlay.hidden = YES; + UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, YES, UIScreen.mainScreen.scale); // [self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES]; // doesn't work to hide the overlay; I guess I need renderInContext:. Ugh. [self.view.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *annotatedImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); - + self.gridOverlay.hidden = NO; - + NSMutableArray *savedAnnotations = [NSMutableArray array]; for (UIView *annotation in self.view.subviews) { if ([annotation isKindOfClass:BSKAnnotationView.class]) [savedAnnotations addObject:annotation]; } - + BugshotKit.sharedManager.annotations = savedAnnotations; BugshotKit.sharedManager.annotatedImage = annotatedImage; - - [super viewWillDisappear:animated]; -} - -- (void)contentAreaTapped:(UITapGestureRecognizer *)sender -{ - if (sender.state == UIGestureRecognizerStateRecognized && ! UIAccessibilityIsVoiceOverRunning()) { - BOOL hidden = ! self.navigationController.navigationBarHidden; - [self.navigationController setNavigationBarHidden:hidden animated:YES]; - [UIView animateWithDuration:UINavigationControllerHideShowBarDuration animations:^{ - self.gridOverlay.alpha = hidden ? 0.0f : kGridOverlayOpacity; - }]; + + UIImage *screenshot = (BugshotKit.sharedManager.annotatedImage ?: BugshotKit.sharedManager.snapshotImage); + + NSString *appNameString = [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"]; + NSString *appVersionString = [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"]; + + size_t size; + sysctlbyname("hw.machine", NULL, &size, NULL, 0); + char *name = malloc(size); + sysctlbyname("hw.machine", name, &size, NULL, 0); + NSString *modelIdentifier = [NSString stringWithCString:name encoding:NSUTF8StringEncoding]; + free(name); + + NSDictionary *userInfo = @{ + @"appName" : appNameString, + @"appVersion" : appVersionString, + @"systemVersion" : UIDevice.currentDevice.systemVersion, + @"deviceModel" : modelIdentifier, + }; + + NSDictionary *extraUserInfo = BugshotKit.sharedManager.extraInfoBlock ? BugshotKit.sharedManager.extraInfoBlock() : nil; + if (extraUserInfo) { + userInfo = userInfo.mutableCopy; + [(NSMutableDictionary *)userInfo addEntriesFromDictionary:extraUserInfo]; + }; + + NSData *userInfoJSON = [NSJSONSerialization dataWithJSONObject:userInfo options:NSJSONWritingPrettyPrinted error:NULL]; + + MFMailComposeViewController *mf = [MFMailComposeViewController canSendMail] ? [[MFMailComposeViewController alloc] init] : nil; + if (! mf) { + NSString *msg = [NSString stringWithFormat:@"Mail is not configured on your %@.", UIDevice.currentDevice.localizedModel]; + [[[UIAlertView alloc] initWithTitle:@"Cannot Send Mail" message:msg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; + return; } + + mf.toRecipients = [BugshotKit.sharedManager.destinationEmailAddress componentsSeparatedByString:@","]; + mf.subject = BugshotKit.sharedManager.emailSubjectBlock ? BugshotKit.sharedManager.emailSubjectBlock(userInfo) : [NSString stringWithFormat:@"%@ %@ Feedback", appNameString, appVersionString]; + [mf setMessageBody:BugshotKit.sharedManager.emailBodyBlock ? BugshotKit.sharedManager.emailBodyBlock(userInfo) : nil isHTML:NO]; + + if (screenshot) [mf addAttachmentData:UIImagePNGRepresentation(rotateIfNeeded(screenshot)) mimeType:@"image/png" fileName:@"screenshot.png"]; + if (userInfoJSON) [mf addAttachmentData:userInfoJSON mimeType:@"application/json" fileName:@"info.json"]; + if(BugshotKit.sharedManager.mailComposeCustomizeBlock) BugshotKit.sharedManager.mailComposeCustomizeBlock(mf); + + mf.mailComposeDelegate = self; + [self presentViewController:mf animated:YES completion:^{ + sender.enabled = YES; + }]; } - (void)annotationPickerPicked:(UISegmentedControl *)sender @@ -264,4 +314,29 @@ - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event } } +#pragma mark - MFMailCompose + +- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error +{ + [self dismissViewControllerAnimated:YES completion:^{ + if (result == MFMailComposeResultSaved || result == MFMailComposeResultSent) [self cancelButtonTapped:nil]; + }]; +} + +// By Matteo Gavagnin on 21/01/14. +static UIImage *rotateIfNeeded(UIImage *src) +{ + if (src.imageOrientation == UIImageOrientationDown && src.size.width < src.size.height) { + UIGraphicsBeginImageContext(src.size); + [src drawAtPoint:CGPointMake(0, 0)]; + return UIGraphicsGetImageFromCurrentImageContext(); + } else if ((src.imageOrientation == UIImageOrientationLeft || src.imageOrientation == UIImageOrientationRight) && src.size.width > src.size.height) { + UIGraphicsBeginImageContext(src.size); + [src drawAtPoint:CGPointMake(0, 0)]; + return UIGraphicsGetImageFromCurrentImageContext(); + } else { + return src; + } +} + @end diff --git a/BugshotKit/BugshotKit.h b/BugshotKit/BugshotKit.h index 34a835b..dc0ec3c 100755 --- a/BugshotKit/BugshotKit.h +++ b/BugshotKit/BugshotKit.h @@ -3,8 +3,8 @@ // Created by Marco Arment on 1/15/14. #import -#import "BSKMainViewController.h" #import "BSKWindow.h" +#import "BSKScreenshotViewController.h" #if ! DEBUG #warning BugshotKit is being included in a non-debug build. @@ -23,7 +23,7 @@ typedef enum : NSUInteger { BSKInvocationGestureLongPress = (1 << 5), } BSKInvocationGestureMask; -@interface BugshotKit : NSObject +@interface BugshotKit : NSObject /* Call this from your UIApplication didFinishLaunching:... method. @@ -88,15 +88,6 @@ typedef enum : NSUInteger { */ + (void)setDisplayConsoleTextInLogViewer:(BOOL)displayText; -// feel free to mess with these if you want - -- (void)currentConsoleLogWithDateStamps:(BOOL)dateStamps - withCompletion:(void (^)(NSString *result))completion; -- (void)consoleImageWithSize:(CGSize)size - fontSize:(CGFloat)fontSize - emptyBottomLine:(BOOL)emptyBottomLine - withCompletion:(void (^)(UIImage *result))completion; - @property (nonatomic) BOOL displayConsoleTextInLogViewer; @property (nonatomic, strong) UIColor *annotationFillColor; diff --git a/BugshotKit/BugshotKit.m b/BugshotKit/BugshotKit.m index a1213cc..1045e15 100755 --- a/BugshotKit/BugshotKit.m +++ b/BugshotKit/BugshotKit.m @@ -7,11 +7,12 @@ #import "BSKNavigationController.h" #import #import "MABGTimer.h" +#import "BSKScreenshotViewController.h" @import CoreText; -@interface UIViewController () -- (void)attentionClassDumpUser:(id)fp8 yesItsUsAgain:(id)fp12 althoughSwizzlingAndOverridingPrivateMethodsIsFun:(id)fp16 itWasntMuchFunWhenYourAppStoppedWorking:(id)fp20 pleaseRefrainFromDoingSoInTheFutureOkayThanksBye:(id)fp24; -@end +//@interface UIViewController () +//- (void)attentionClassDumpUser:(id)fp8 yesItsUsAgain:(id)fp12 althoughSwizzlingAndOverridingPrivateMethodsIsFun:(id)fp16 itWasntMuchFunWhenYourAppStoppedWorking:(id)fp20 pleaseRefrainFromDoingSoInTheFutureOkayThanksBye:(id)fp24; +//@end NSString * const BSKNewLogMessageNotification = @"BSKNewLogMessageNotification"; @@ -118,24 +119,24 @@ + (UIFont *)consoleFontWithSize:(CGFloat)size dispatch_once(&onceToken, ^{ consoleFontName = nil; - NSData *inData = [NSData dataWithContentsOfFile:[[NSBundle bundleForClass:[self class]].resourcePath stringByAppendingPathComponent:@"Inconsolata.otf"]]; - if (inData) { - CFErrorRef error; - CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData); - CGFontRef font = CGFontCreateWithDataProvider(provider); - if (CTFontManagerRegisterGraphicsFont(font, &error)) { - if ([UIFont fontWithName:@"Inconsolata" size:size]) consoleFontName = @"Inconsolata"; - else NSLog(@"[BugshotKit] failed to instantiate console font"); - } else { - CFStringRef errorDescription = CFErrorCopyDescription(error); - NSLog(@"[BugshotKit] failed to load console font: %@", errorDescription); - CFRelease(errorDescription); - } - CFRelease(font); - CFRelease(provider); - } else { - NSLog(@"[BugshotKit] Console font not found. Please add Inconsolata.otf to your Resources."); - } +// NSData *inData = [NSData dataWithContentsOfFile:[[NSBundle bundleForClass:[self class]].resourcePath stringByAppendingPathComponent:@"Inconsolata.otf"]]; +// if (inData) { +// CFErrorRef error; +// CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData); +// CGFontRef font = CGFontCreateWithDataProvider(provider); +// if (CTFontManagerRegisterGraphicsFont(font, &error)) { +// if ([UIFont fontWithName:@"Inconsolata" size:size]) consoleFontName = @"Inconsolata"; +// else NSLog(@"[BugshotKit] failed to instantiate console font"); +// } else { +// CFStringRef errorDescription = CFErrorCopyDescription(error); +// NSLog(@"[BugshotKit] failed to load console font: %@", errorDescription); +// CFRelease(errorDescription); +// } +// CFRelease(font); +// CFRelease(provider); +// } else { +// NSLog(@"[BugshotKit] Console font not found. Please add Inconsolata.otf to your Resources."); +// } if (! consoleFontName) consoleFontName = @"CourierNewPSMT"; }); @@ -146,11 +147,11 @@ + (UIFont *)consoleFontWithSize:(CGFloat)size - (instancetype)init { if ( (self = [super init]) ) { - if ([self.class isProbablyAppStoreBuild]) { - self.isDisabled = YES; - NSLog(@"[BugshotKit] App Store build detected. BugshotKit is disabled."); - return self; - } +// if ([self.class isProbablyAppStoreBuild]) { +// self.isDisabled = YES; +// NSLog(@"[BugshotKit] App Store build detected. BugshotKit is disabled."); +// return self; +// } self.windowsWithGesturesAttached = [NSMapTable weakToWeakObjectsMapTable]; @@ -211,14 +212,14 @@ - (void)ensureWindow // The purpose of this is to immediately get rejected from App Store submissions in case you accidentally submit an app with BugshotKit. // BugshotKit is only meant to be used during development and beta testing. Do not ship it in App Store builds. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wundeclared-selector" - if ([UIEvent.class instancesRespondToSelector:@selector(_gsEvent)] && - [UIViewController.class instancesRespondToSelector:@selector(attentionClassDumpUser:yesItsUsAgain:althoughSwizzlingAndOverridingPrivateMethodsIsFun:itWasntMuchFunWhenYourAppStoppedWorking:pleaseRefrainFromDoingSoInTheFutureOkayThanksBye:)]) { - // I can't believe I actually had a reason to call this method. - [self.window.rootViewController attentionClassDumpUser:nil yesItsUsAgain:nil althoughSwizzlingAndOverridingPrivateMethodsIsFun:nil itWasntMuchFunWhenYourAppStoppedWorking:nil pleaseRefrainFromDoingSoInTheFutureOkayThanksBye:nil]; - } -#pragma clang diagnostic pop +//#pragma clang diagnostic push +//#pragma clang diagnostic ignored "-Wundeclared-selector" +// if ([UIEvent.class instancesRespondToSelector:@selector(_gsEvent)] && +// [UIViewController.class instancesRespondToSelector:@selector(attentionClassDumpUser:yesItsUsAgain:althoughSwizzlingAndOverridingPrivateMethodsIsFun:itWasntMuchFunWhenYourAppStoppedWorking:pleaseRefrainFromDoingSoInTheFutureOkayThanksBye:)]) { +// // I can't believe I actually had a reason to call this method. +// [self.window.rootViewController attentionClassDumpUser:nil yesItsUsAgain:nil althoughSwizzlingAndOverridingPrivateMethodsIsFun:nil itWasntMuchFunWhenYourAppStoppedWorking:nil pleaseRefrainFromDoingSoInTheFutureOkayThanksBye:nil]; +// } +//#pragma clang diagnostic pop } - (void)newWindowDidBecomeVisible:(NSNotification *)n @@ -419,12 +420,10 @@ - (void)handleOpenGesture:(UIGestureRecognizer *)sender UIViewController *presentingViewController = self.window.rootViewController; while (presentingViewController.presentedViewController) presentingViewController = presentingViewController.presentedViewController; - BSKMainViewController *mvc = [[BSKMainViewController alloc] init]; - mvc.delegate = self; - BSKNavigationController *nc = [[BSKNavigationController alloc] initWithRootViewController:mvc lockedToRotation:self.window.rootViewController.interfaceOrientation]; + BSKScreenshotViewController *svc = [[BSKScreenshotViewController alloc] initWithImage:BugshotKit.sharedManager.snapshotImage annotations:BugshotKit.sharedManager.annotations]; + svc.delegate = self; + BSKNavigationController *nc = [[BSKNavigationController alloc] initWithRootViewController:svc lockedToRotation:self.window.rootViewController.interfaceOrientation]; self.presentedNavigationController = nc; - nc.navigationBar.tintColor = BugshotKit.sharedManager.annotationFillColor; - nc.navigationBar.titleTextAttributes = @{ NSForegroundColorAttributeName:BugshotKit.sharedManager.annotationFillColor }; [presentingViewController presentViewController:nc animated:YES completion:NULL]; } @@ -432,13 +431,13 @@ + (void)dismissAnimated:(BOOL)animated completion:(void(^)())completion { UIViewController *presentingVC = BugshotKit.sharedManager.presentedNavigationController.presentingViewController; if (presentingVC) { [presentingVC dismissViewControllerAnimated:animated completion:completion]; - [BugshotKit.sharedManager mainViewControllerDidClose:nil]; + [BugshotKit.sharedManager screenshotViewControllerDidClose:nil]; } else { if (completion) completion(); } } -- (void)mainViewControllerDidClose:(BSKMainViewController *)mainViewController +- (void)screenshotViewControllerDidClose:(BSKScreenshotViewController *)screenshotViewController { self.isShowing = NO; self.snapshotImage = nil; @@ -446,32 +445,6 @@ - (void)mainViewControllerDidClose:(BSKMainViewController *)mainViewController self.annotations = nil; } -#pragma mark - Console logging - -- (void)currentConsoleLogWithDateStamps:(BOOL)dateStamps - withCompletion:(void (^)(NSString *result))completion -{ - dispatch_async(self.logQueue, ^{ - NSMutableString *string = [NSMutableString string]; - - char fdate[24]; - for (BSKLogMessage *msg in self.consoleMessages) { - if (dateStamps) { - time_t timestamp = (time_t) msg.timestamp; - struct tm *lt = localtime(×tamp); - strftime(fdate, 24, "%Y-%m-%d %T", lt); - [string appendFormat:@"%s.%03d %@\n", fdate, (int) (1000.0 * (msg.timestamp - floor(msg.timestamp))), msg.message]; - } else { - [string appendFormat:@"%@\n", msg.message]; - } - } - - dispatch_async(dispatch_get_main_queue(), ^{ - completion(string); - }); - }); -} - - (void)clearLog { if (self.isDisabled) return; @@ -569,51 +542,6 @@ - (BOOL)updateFromASL return foundNewEntries; } -- (void)consoleImageWithSize:(CGSize)size - fontSize:(CGFloat)fontSize - emptyBottomLine:(BOOL)emptyBottomLine - withCompletion:(void (^)(UIImage *result))completion -{ - [self currentConsoleLogWithDateStamps:NO withCompletion:^(NSString *consoleText) { - NSUInteger characterLimit = (NSUInteger) ((size.width / (fontSize / 2.0f)) * (size.height / fontSize)); - if (consoleText.length > characterLimit) consoleText = [consoleText substringFromIndex:(consoleText.length - characterLimit)]; - - NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; - paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping; - paragraphStyle.alignment = NSTextAlignmentLeft; - - NSDictionary *attributes = @{ - NSFontAttributeName : [BugshotKit consoleFontWithSize:fontSize], - NSForegroundColorAttributeName : UIColor.blackColor, - NSParagraphStyleAttributeName : paragraphStyle, - }; - - NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:consoleText attributes:attributes]; - - NSStringDrawingContext *stringDrawingContext = [NSStringDrawingContext new]; - stringDrawingContext.minimumScaleFactor = 1.0; - - NSStringDrawingOptions options = (NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesFontLeading); - - CGFloat padding = 2.0f; - CGSize renderSize = CGSizeMake(size.width - padding * 2.0f, size.height - padding * 2.0f); - if (emptyBottomLine) renderSize.height -= fontSize; - - completion(BSKImageWithDrawing(size, ^{ - [UIColor.whiteColor setFill]; - [[UIBezierPath bezierPathWithRect:CGRectMake(0, 0, size.width, size.height)] fill]; - - CGRect stringRect = [attrString boundingRectWithSize:CGSizeMake(renderSize.width, MAXFLOAT) options:options context:stringDrawingContext]; - - stringRect.origin = CGPointMake(padding, padding); - if (stringRect.size.height < renderSize.height) stringRect.size.height = renderSize.height; - else stringRect.origin.y -= (stringRect.size.height - renderSize.height); - - [attrString drawWithRect:stringRect options:options context:stringDrawingContext]; - })); - }]; -} - #pragma mark - App Store build detection + (BOOL)isProbablyAppStoreBuild diff --git a/Test Project/TestBugshotKit.xcodeproj/project.pbxproj b/Test Project/TestBugshotKit.xcodeproj/project.pbxproj index 7368b22..50492a1 100644 --- a/Test Project/TestBugshotKit.xcodeproj/project.pbxproj +++ b/Test Project/TestBugshotKit.xcodeproj/project.pbxproj @@ -24,7 +24,6 @@ A9A84754188D8696009C5B78 /* BSKAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9A84742188D8696009C5B78 /* BSKAnnotationView.m */; }; A9A84755188D8696009C5B78 /* BSKCheckerboardView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9A84744188D8696009C5B78 /* BSKCheckerboardView.m */; }; A9A84756188D8696009C5B78 /* BSKLogViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9A84746188D8696009C5B78 /* BSKLogViewController.m */; }; - A9A84757188D8696009C5B78 /* BSKMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9A84748188D8696009C5B78 /* BSKMainViewController.m */; }; A9A84758188D8696009C5B78 /* BSKScreenshotViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9A8474A188D8696009C5B78 /* BSKScreenshotViewController.m */; }; A9A84759188D8696009C5B78 /* BSKToggleButton.m in Sources */ = {isa = PBXBuildFile; fileRef = A9A8474C188D8696009C5B78 /* BSKToggleButton.m */; }; A9A8475A188D8696009C5B78 /* BugshotKit.m in Sources */ = {isa = PBXBuildFile; fileRef = A9A8474E188D8696009C5B78 /* BugshotKit.m */; }; @@ -65,8 +64,6 @@ A9A84744188D8696009C5B78 /* BSKCheckerboardView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSKCheckerboardView.m; sourceTree = ""; }; A9A84745188D8696009C5B78 /* BSKLogViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSKLogViewController.h; sourceTree = ""; }; A9A84746188D8696009C5B78 /* BSKLogViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSKLogViewController.m; sourceTree = ""; }; - A9A84747188D8696009C5B78 /* BSKMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSKMainViewController.h; sourceTree = ""; }; - A9A84748188D8696009C5B78 /* BSKMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSKMainViewController.m; sourceTree = ""; }; A9A84749188D8696009C5B78 /* BSKScreenshotViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSKScreenshotViewController.h; sourceTree = ""; }; A9A8474A188D8696009C5B78 /* BSKScreenshotViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSKScreenshotViewController.m; sourceTree = ""; }; A9A8474B188D8696009C5B78 /* BSKToggleButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSKToggleButton.h; sourceTree = ""; }; @@ -169,8 +166,6 @@ A9A84744188D8696009C5B78 /* BSKCheckerboardView.m */, A9A84745188D8696009C5B78 /* BSKLogViewController.h */, A9A84746188D8696009C5B78 /* BSKLogViewController.m */, - A9A84747188D8696009C5B78 /* BSKMainViewController.h */, - A9A84748188D8696009C5B78 /* BSKMainViewController.m */, A9A84749188D8696009C5B78 /* BSKScreenshotViewController.h */, A9A8474A188D8696009C5B78 /* BSKScreenshotViewController.m */, A9A8474B188D8696009C5B78 /* BSKToggleButton.h */, @@ -253,7 +248,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A9A84757188D8696009C5B78 /* BSKMainViewController.m in Sources */, A9A84755188D8696009C5B78 /* BSKCheckerboardView.m in Sources */, A9A8475B188D8696009C5B78 /* UIImage+ImageEffects.m in Sources */, A9595413189329470000850E /* MABGTimer.m in Sources */,