diff --git a/Classes/BITFeedbackComposeViewController.m b/Classes/BITFeedbackComposeViewController.m index b9ab0f15c0..ac687dc263 100644 --- a/Classes/BITFeedbackComposeViewController.m +++ b/Classes/BITFeedbackComposeViewController.m @@ -42,8 +42,10 @@ #import "BITHockeyHelper.h" +#import "BITImageAnnotationViewController.h" -@interface BITFeedbackComposeViewController () { + +@interface BITFeedbackComposeViewController () { UIStatusBarStyle _statusBarStyle; } @@ -469,12 +471,38 @@ [attachment deleteContents]; // mandatory call to delete the files associatd. [self.attachments removeObject:attachment]; } - + self.selectedAttachmentIndex = NSNotFound; + + [self refreshAttachmentScrollview]; + } else { + if (self.selectedAttachmentIndex != NSNotFound){ + BITFeedbackMessageAttachment* attachment = [self.attachments objectAtIndex:self.selectedAttachmentIndex]; + BITImageAnnotationViewController *annotationEditor = [[BITImageAnnotationViewController alloc ] init]; + annotationEditor.delegate = self; + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:annotationEditor]; + annotationEditor.image = attachment.imageRepresentation; + [self presentViewController:navController animated:YES completion:nil]; + } + + } + + +} + +#pragma mark - Image Annotation Delegate + +- (void)annotationController:(BITImageAnnotationViewController *)annotationController didFinishWithImage:(UIImage *)image { + if (self.selectedAttachmentIndex != NSNotFound){ + BITFeedbackMessageAttachment* attachment = [self.attachments objectAtIndex:self.selectedAttachmentIndex]; + [attachment replaceData:UIImageJPEGRepresentation(image, 0.7f)]; [self refreshAttachmentScrollview]; } self.selectedAttachmentIndex = NSNotFound; - +} + +- (void)annotationControllerDidCancel:(BITImageAnnotationViewController *)annotationController { + self.selectedAttachmentIndex = NSNotFound; } @end diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index e194a8fff0..e727ea5233 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -1035,7 +1035,7 @@ -(void)setFeedbackObservationMode:(BITFeedbackObservationMode)mode { if (mode == BITFeedbackObservationModeOnScreenshot){ - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(screenshotNotificationReceived:) name:UIApplicationUserDidTakeScreenshotNotification object:nil]; + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(screenshotNotificationReceived:) name:UIApplicationUserDidTakeScreenshotNotification object:nil]; } } diff --git a/Classes/BITFeedbackMessageAttachment.h b/Classes/BITFeedbackMessageAttachment.h index 77a4b92b11..4a9a8ea646 100644 --- a/Classes/BITFeedbackMessageAttachment.h +++ b/Classes/BITFeedbackMessageAttachment.h @@ -44,6 +44,8 @@ - (UIImage *)thumbnailWithSize:(CGSize)size; +- (void)replaceData:(NSData *)data; + - (void)deleteContents; @end diff --git a/Classes/BITFeedbackMessageAttachment.m b/Classes/BITFeedbackMessageAttachment.m index 9184a723cb..eebc4693e5 100644 --- a/Classes/BITFeedbackMessageAttachment.m +++ b/Classes/BITFeedbackMessageAttachment.m @@ -76,6 +76,11 @@ return nil; } +- (void)replaceData:(NSData *)data { + self.data = data; + self.thumbnailRepresentations = [NSMutableDictionary new]; +} + #pragma mark NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder { diff --git a/Classes/BITImageAnnotation.h b/Classes/BITImageAnnotation.h new file mode 100644 index 0000000000..51e3a8c634 --- /dev/null +++ b/Classes/BITImageAnnotation.h @@ -0,0 +1,13 @@ +// +// BITImageAnnotation.h +// HockeySDK +// +// Created by Moritz Haarmann on 24.02.14. +// +// + +#import + +@interface BITImageAnnotation : UIView + +@end diff --git a/Classes/BITImageAnnotation.m b/Classes/BITImageAnnotation.m new file mode 100644 index 0000000000..644a27b379 --- /dev/null +++ b/Classes/BITImageAnnotation.m @@ -0,0 +1,34 @@ +// +// BITImageAnnotation.m +// HockeySDK +// +// Created by Moritz Haarmann on 24.02.14. +// +// + +#import "BITImageAnnotation.h" + +@implementation BITImageAnnotation + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + //self.backgroundColor = [UIColor redColor]; + } + return self; +} + + + +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect +{ + // Drawing code +} +*/ + +@end diff --git a/Classes/BITImageAnnotationViewController.h b/Classes/BITImageAnnotationViewController.h index 6321c9bd83..d333d612c2 100644 --- a/Classes/BITImageAnnotationViewController.h +++ b/Classes/BITImageAnnotationViewController.h @@ -8,8 +8,18 @@ #import +@class BITImageAnnotationViewController; + +@protocol BITImageAnnotationDelegate + +- (void)annotationControllerDidCancel:(BITImageAnnotationViewController *)annotationController; +- (void)annotationController:(BITImageAnnotationViewController *)annotationController didFinishWithImage:(UIImage *)image; + +@end + @interface BITImageAnnotationViewController : UIViewController @property (nonatomic, strong) UIImage *image; +@property (nonatomic, weak) id delegate; @end diff --git a/Classes/BITImageAnnotationViewController.m b/Classes/BITImageAnnotationViewController.m index e6101ab587..a49800dab7 100644 --- a/Classes/BITImageAnnotationViewController.m +++ b/Classes/BITImageAnnotationViewController.m @@ -7,12 +7,19 @@ // #import "BITImageAnnotationViewController.h" +#import "BITImageAnnotation.h" +#import "BITRectangleImageAnnotation.h" @interface BITImageAnnotationViewController () @property (nonatomic, strong) UIImageView *imageView; @property (nonatomic, strong) UISegmentedControl *editingControls; -@property (nonatomic, strong) NSMutableArray *layers; +@property (nonatomic, strong) NSMutableArray *objects; +@property (nonatomic, strong) UIPanGestureRecognizer *panRecognizer; +@property (nonatomic, strong) UITapGestureRecognizer *tapRecognizer; + +@property (nonatomic) CGPoint panStart; +@property (nonatomic,strong) BITImageAnnotation *currentAnnotation; @end @@ -41,11 +48,78 @@ self.imageView.image = self.image; self.imageView.contentMode = UIViewContentModeScaleAspectFit; + + + [self.view addSubview:self.imageView]; + self.imageView.frame = self.view.bounds; + + + self.tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)]; + self.panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panned:)]; + + [self.tapRecognizer requireGestureRecognizerToFail:self.panRecognizer]; + + [self.view addGestureRecognizer:self.tapRecognizer]; + [self.view addGestureRecognizer:self.panRecognizer]; + + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc ] initWithTitle:@"Discard" style:UIBarButtonItemStyleBordered target:self action:@selector(discard:)]; + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc ] initWithTitle:@"Save" style:UIBarButtonItemStyleBordered target:self action:@selector(save:)]; + // Do any additional setup after loading the view. } -(void)editingAction:(id)sender { +} + +- (BITImageAnnotation *)annotationForCurrentMode { + if (self.editingControls.selectedSegmentIndex == 0){ + return [[BITRectangleImageAnnotation alloc] initWithFrame:CGRectZero]; + } else { + return [[BITImageAnnotation alloc] initWithFrame:CGRectZero]; + } +} + +#pragma mark - Actions + +- (void)discard:(id)sender { + [self.delegate annotationControllerDidCancel:self]; + [self dismissModalViewControllerAnimated:YES]; +} + +- (void)save:(id)sender { + UIImage *image = [self extractImage]; + [self.delegate annotationController:self didFinishWithImage:image]; + [self dismissModalViewControllerAnimated:YES]; +} + +- (UIImage *)extractImage { + UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, YES, 0.0); + CGContextRef ctx = UIGraphicsGetCurrentContext(); + [self.view.layer renderInContext:ctx]; + UIImage *renderedImageOfMyself = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return renderedImageOfMyself; +} + +#pragma mark - Gesture Handling + +- (void)panned:(UIPanGestureRecognizer *)gestureRecognizer { + if (gestureRecognizer.state == UIGestureRecognizerStateBegan){ + self.currentAnnotation = [self annotationForCurrentMode]; + + [self.view insertSubview:self.currentAnnotation aboveSubview:self.imageView]; + self.panStart = [gestureRecognizer locationInView:self.imageView]; + } else if (gestureRecognizer.state == UIGestureRecognizerStateChanged){ + CGPoint bla = [gestureRecognizer translationInView:self.imageView]; + self.currentAnnotation.frame = CGRectMake(self.panStart.x, self.panStart.y, bla.x, bla.y); + } + +} + +-(void)tapped:(UITapGestureRecognizer *)gestureRecognizer { + + } - (void)didReceiveMemoryWarning diff --git a/Classes/BITRectangleImageAnnotation.h b/Classes/BITRectangleImageAnnotation.h new file mode 100644 index 0000000000..0ba16c0c68 --- /dev/null +++ b/Classes/BITRectangleImageAnnotation.h @@ -0,0 +1,13 @@ +// +// BITRectangleImageAnnotation.h +// HockeySDK +// +// Created by Moritz Haarmann on 25.02.14. +// +// + +#import "BITImageAnnotation.h" + +@interface BITRectangleImageAnnotation : BITImageAnnotation + +@end diff --git a/Classes/BITRectangleImageAnnotation.m b/Classes/BITRectangleImageAnnotation.m new file mode 100644 index 0000000000..465008fec2 --- /dev/null +++ b/Classes/BITRectangleImageAnnotation.m @@ -0,0 +1,49 @@ +// +// BITRectangleImageAnnotation.m +// HockeySDK +// +// Created by Moritz Haarmann on 25.02.14. +// +// + +#import "BITRectangleImageAnnotation.h" + +@interface BITRectangleImageAnnotation() + +@property (nonatomic, strong) CAShapeLayer *shapeLayer; + +@end + +@implementation BITRectangleImageAnnotation + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + self.shapeLayer = [CAShapeLayer layer]; + self.shapeLayer.strokeColor = [UIColor redColor].CGColor; + self.shapeLayer.lineWidth = 5; + self.shapeLayer.fillColor = [UIColor clearColor].CGColor; + [self.layer addSublayer:self.shapeLayer]; + + } + return self; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + self.shapeLayer.frame = self.bounds; + self.shapeLayer.path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:10].CGPath; +} + +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect +{ + // Drawing code +} +*/ + +@end diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index e9a92d28f4..002105aabb 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -131,10 +131,14 @@ 1EF95CA7162CB037000AE3AD /* BITFeedbackActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EF95CA5162CB036000AE3AD /* BITFeedbackActivity.m */; }; 1EF95CAA162CB314000AE3AD /* BITFeedbackComposeViewControllerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EF95CA9162CB313000AE3AD /* BITFeedbackComposeViewControllerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1EFF03E517F2485500A5F13C /* BITCrashManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EFF03E417F2485500A5F13C /* BITCrashManagerTests.m */; }; + 973EC8B418BCA7BC00DBFFBB /* BITImageAnnotationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 97F0FA0018AE375E00EF50AA /* BITImageAnnotationViewController.m */; }; + 973EC8B718BCA8A200DBFFBB /* BITRectangleImageAnnotation.h in Headers */ = {isa = PBXBuildFile; fileRef = 973EC8B518BCA8A200DBFFBB /* BITRectangleImageAnnotation.h */; }; + 973EC8B818BCA8A200DBFFBB /* BITRectangleImageAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 973EC8B618BCA8A200DBFFBB /* BITRectangleImageAnnotation.m */; }; 9760F6C418BB4D2D00959B93 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9760F6C318BB4D2D00959B93 /* AssetsLibrary.framework */; }; + 9760F6CF18BB685600959B93 /* BITImageAnnotation.h in Headers */ = {isa = PBXBuildFile; fileRef = 9760F6CD18BB685600959B93 /* BITImageAnnotation.h */; }; + 9760F6D018BB685600959B93 /* BITImageAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 9760F6CE18BB685600959B93 /* BITImageAnnotation.m */; }; 97F0F9FD18ABAECD00EF50AA /* iconCamera.png in Resources */ = {isa = PBXBuildFile; fileRef = 97F0F9FB18ABAECD00EF50AA /* iconCamera.png */; }; 97F0F9FE18ABAECD00EF50AA /* iconCamera@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 97F0F9FC18ABAECD00EF50AA /* iconCamera@2x.png */; }; - 97F0FA0118AE375E00EF50AA /* BITImageAnnotationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 97F0FA0018AE375E00EF50AA /* BITImageAnnotationViewController.m */; }; 97F0FA0518B2294D00EF50AA /* BITFeedbackMessageAttachment.m in Sources */ = {isa = PBXBuildFile; fileRef = 97F0FA0318AE5AED00EF50AA /* BITFeedbackMessageAttachment.m */; }; E405266217A2AD300096359C /* BITFeedbackManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = E405266117A2AD300096359C /* BITFeedbackManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; E40E0B0917DA19DC005E38C1 /* BITHockeyAppClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E40E0B0817DA19DC005E38C1 /* BITHockeyAppClientTests.m */; }; @@ -294,7 +298,11 @@ 1EF95CA9162CB313000AE3AD /* BITFeedbackComposeViewControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackComposeViewControllerDelegate.h; sourceTree = ""; }; 1EFF03D717F20F8300A5F13C /* BITCrashManagerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerPrivate.h; sourceTree = ""; }; 1EFF03E417F2485500A5F13C /* BITCrashManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashManagerTests.m; sourceTree = ""; }; + 973EC8B518BCA8A200DBFFBB /* BITRectangleImageAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITRectangleImageAnnotation.h; sourceTree = ""; }; + 973EC8B618BCA8A200DBFFBB /* BITRectangleImageAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITRectangleImageAnnotation.m; sourceTree = ""; }; 9760F6C318BB4D2D00959B93 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; }; + 9760F6CD18BB685600959B93 /* BITImageAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITImageAnnotation.h; sourceTree = ""; }; + 9760F6CE18BB685600959B93 /* BITImageAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITImageAnnotation.m; sourceTree = ""; }; 97F0F9FB18ABAECD00EF50AA /* iconCamera.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = iconCamera.png; sourceTree = ""; }; 97F0F9FC18ABAECD00EF50AA /* iconCamera@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "iconCamera@2x.png"; sourceTree = ""; }; 97F0F9FF18AE375E00EF50AA /* BITImageAnnotationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITImageAnnotationViewController.h; sourceTree = ""; }; @@ -451,6 +459,7 @@ 1E754E461621FA9A0070AB92 /* Feedback */ = { isa = PBXGroup; children = ( + 9760F6CC18BB684200959B93 /* Image Editor */, 1E49A4361612223B00463151 /* BITFeedbackMessage.h */, 1E49A4371612223B00463151 /* BITFeedbackMessage.m */, 97F0FA0218AE5AED00EF50AA /* BITFeedbackMessageAttachment.h */, @@ -470,8 +479,6 @@ 1E49A4341612223B00463151 /* BITFeedbackManager.m */, E405266117A2AD300096359C /* BITFeedbackManagerDelegate.h */, 1E49A4351612223B00463151 /* BITFeedbackManagerPrivate.h */, - 97F0F9FF18AE375E00EF50AA /* BITImageAnnotationViewController.h */, - 97F0FA0018AE375E00EF50AA /* BITImageAnnotationViewController.m */, ); name = Feedback; sourceTree = ""; @@ -548,6 +555,19 @@ name = Private; sourceTree = ""; }; + 9760F6CC18BB684200959B93 /* Image Editor */ = { + isa = PBXGroup; + children = ( + 97F0F9FF18AE375E00EF50AA /* BITImageAnnotationViewController.h */, + 97F0FA0018AE375E00EF50AA /* BITImageAnnotationViewController.m */, + 9760F6CD18BB685600959B93 /* BITImageAnnotation.h */, + 9760F6CE18BB685600959B93 /* BITImageAnnotation.m */, + 973EC8B518BCA8A200DBFFBB /* BITRectangleImageAnnotation.h */, + 973EC8B618BCA8A200DBFFBB /* BITRectangleImageAnnotation.m */, + ); + name = "Image Editor"; + sourceTree = ""; + }; E400560F148D79B500EB22B9 = { isa = PBXGroup; children = ( @@ -681,6 +701,7 @@ 1E49A4BE161222B900463151 /* BITHockeyHelper.h in Headers */, 1E49A4C4161222B900463151 /* BITAppStoreHeader.h in Headers */, 1E49A4CA161222B900463151 /* BITStoreButton.h in Headers */, + 973EC8B718BCA8A200DBFFBB /* BITRectangleImageAnnotation.h in Headers */, E405266217A2AD300096359C /* BITFeedbackManagerDelegate.h in Headers */, 1E49A4D0161222B900463151 /* BITWebTableViewCell.h in Headers */, 1E49A4D8161222D400463151 /* HockeySDKPrivate.h in Headers */, @@ -690,6 +711,7 @@ 1EACC97B162F041E007578C5 /* BITAttributedLabel.h in Headers */, 1E0FEE28173BDB260061331F /* BITKeychainUtils.h in Headers */, 1E94F9E416E9136B006570AD /* BITStoreUpdateManagerPrivate.h in Headers */, + 9760F6CF18BB685600959B93 /* BITImageAnnotation.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -894,6 +916,7 @@ 1E49A43F1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */, E40E0B0D17DA1AFF005E38C1 /* BITHockeyAppClient.m in Sources */, 1E49A4451612223B00463151 /* BITFeedbackListViewCell.m in Sources */, + 973EC8B818BCA8A200DBFFBB /* BITRectangleImageAnnotation.m in Sources */, 1E49A44B1612223B00463151 /* BITFeedbackListViewController.m in Sources */, 1E49A4511612223B00463151 /* BITFeedbackManager.m in Sources */, E4933E8117B66CDA00B11ACC /* BITHTTPOperation.m in Sources */, @@ -905,6 +928,7 @@ 1E49A4821612226D00463151 /* BITUpdateViewController.m in Sources */, E4B4DB7E17B435550099C67F /* BITAuthenticationViewController.m in Sources */, 1E49A4B2161222B900463151 /* BITHockeyBaseManager.m in Sources */, + 9760F6D018BB685600959B93 /* BITImageAnnotation.m in Sources */, 1E49A4BB161222B900463151 /* BITHockeyBaseViewController.m in Sources */, 97F0FA0518B2294D00EF50AA /* BITFeedbackMessageAttachment.m in Sources */, 1E49A4C7161222B900463151 /* BITAppStoreHeader.m in Sources */, @@ -916,6 +940,7 @@ 1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */, 1EF95CA7162CB037000AE3AD /* BITFeedbackActivity.m in Sources */, 1EACC97C162F041E007578C5 /* BITAttributedLabel.m in Sources */, + 973EC8B418BCA7BC00DBFFBB /* BITImageAnnotationViewController.m in Sources */, 1E0FEE29173BDB260061331F /* BITKeychainUtils.m in Sources */, 1E94F9E216E91330006570AD /* BITStoreUpdateManager.m in Sources */, ); @@ -925,7 +950,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 97F0FA0118AE375E00EF50AA /* BITImageAnnotationViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };