From 3809744d974120eb6099eb66757843f925c45f3e Mon Sep 17 00:00:00 2001 From: David Chiles Date: Wed, 18 Feb 2015 13:26:46 -0800 Subject: [PATCH] animate in progress --- ChatSecure.xcodeproj/project.pbxproj | 6 + ChatSecure/Classes/Utilities/OTRColors.h | 2 + ChatSecure/Classes/Utilities/OTRColors.m | 5 + ChatSecure/Classes/Utilities/OTRImages.h | 2 + ChatSecure/Classes/Utilities/OTRImages.m | 94 +++++ .../OTRAudioRecorderViewController.h | 20 + .../OTRAudioRecorderViewController.m | 364 ++++++++++++++++++ .../OTRMessagesViewController.m | 48 +-- media/app-images/microphone/microphone28.svg | 20 + 9 files changed, 523 insertions(+), 38 deletions(-) create mode 100644 ChatSecure/Classes/View Controllers/OTRAudioRecorderViewController.h create mode 100644 ChatSecure/Classes/View Controllers/OTRAudioRecorderViewController.m create mode 100755 media/app-images/microphone/microphone28.svg diff --git a/ChatSecure.xcodeproj/project.pbxproj b/ChatSecure.xcodeproj/project.pbxproj index de3fcb37a..527ac005b 100644 --- a/ChatSecure.xcodeproj/project.pbxproj +++ b/ChatSecure.xcodeproj/project.pbxproj @@ -170,6 +170,7 @@ 63C5B66A1A82F3EE0011BEA8 /* OTRAudioPlaybackController.m in Sources */ = {isa = PBXBuildFile; fileRef = 63C5B6691A82F3EE0011BEA8 /* OTRAudioPlaybackController.m */; }; 63D184861A2D3F2400334CD8 /* OTRNotificationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 63D184851A2D3F2400334CD8 /* OTRNotificationController.m */; }; 63D27FC51A6DC51C00EC251A /* OTRMediaItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 63D27FC41A6DC51C00EC251A /* OTRMediaItem.m */; }; + 63D58C261A8C154D003C5A2D /* OTRAudioRecorderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 63D58C251A8C154D003C5A2D /* OTRAudioRecorderViewController.m */; }; 63D64D661A2FBA8C00E21F77 /* OTRToastOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 63D64D651A2FBA8C00E21F77 /* OTRToastOptions.m */; }; 63F0FF641A798D8E001F0C99 /* OTRAudioControlsView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63F0FF631A798D8E001F0C99 /* OTRAudioControlsView.m */; }; 63F6E1911A69B9BA0011E6F7 /* OTRAttachmentPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 63F6E1901A69B9BA0011E6F7 /* OTRAttachmentPicker.m */; }; @@ -549,6 +550,8 @@ 63D184851A2D3F2400334CD8 /* OTRNotificationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTRNotificationController.m; sourceTree = ""; }; 63D27FC31A6DC51C00EC251A /* OTRMediaItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTRMediaItem.h; sourceTree = ""; }; 63D27FC41A6DC51C00EC251A /* OTRMediaItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTRMediaItem.m; sourceTree = ""; }; + 63D58C241A8C154D003C5A2D /* OTRAudioRecorderViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTRAudioRecorderViewController.h; sourceTree = ""; }; + 63D58C251A8C154D003C5A2D /* OTRAudioRecorderViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTRAudioRecorderViewController.m; sourceTree = ""; }; 63D64D641A2FBA8C00E21F77 /* OTRToastOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTRToastOptions.h; sourceTree = ""; }; 63D64D651A2FBA8C00E21F77 /* OTRToastOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTRToastOptions.m; sourceTree = ""; }; 63DC0EB31A1ABC86002C9598 /* OTR_Codesigning.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = OTR_Codesigning.xcconfig; path = configurations/OTR_Codesigning.xcconfig; sourceTree = ""; }; @@ -890,6 +893,8 @@ 633106331A16D1A300C17BAE /* OTRListSettingViewController.m */, 633106341A16D1A300C17BAE /* OTRMessagesViewController.h */, 633106351A16D1A300C17BAE /* OTRMessagesViewController.m */, + 63D58C241A8C154D003C5A2D /* OTRAudioRecorderViewController.h */, + 63D58C251A8C154D003C5A2D /* OTRAudioRecorderViewController.m */, 633106361A16D1A300C17BAE /* OTRNewAccountViewController.h */, 633106371A16D1A300C17BAE /* OTRNewAccountViewController.m */, 633106381A16D1A300C17BAE /* OTRNewBuddyViewController.h */, @@ -1362,6 +1367,7 @@ 63C4BD1C1A1E9BE1001696CD /* OTRvCardAvatar.m in Sources */, 63C4BD281A1E9BE1001696CD /* _OTRManagedOscarAccount.m in Sources */, 633107031A16D1A300C17BAE /* OTRFingerprintsViewController.m in Sources */, + 63D58C261A8C154D003C5A2D /* OTRAudioRecorderViewController.m in Sources */, 6331068C1A16D1A300C17BAE /* OTRSettingsManager.m in Sources */, 6331070C1A16D1A300C17BAE /* OTRQRCodeViewController.m in Sources */, 6331067B1A16D1A300C17BAE /* UIImage+ChatSecure.m in Sources */, diff --git a/ChatSecure/Classes/Utilities/OTRColors.h b/ChatSecure/Classes/Utilities/OTRColors.h index 816a0622c..d4dc0db73 100644 --- a/ChatSecure/Classes/Utilities/OTRColors.h +++ b/ChatSecure/Classes/Utilities/OTRColors.h @@ -23,4 +23,6 @@ + (UIColor *)greenNoErrorColor; + (UIColor *)warnColor; ++ (UIColor *)defaultBlueColor; + @end diff --git a/ChatSecure/Classes/Utilities/OTRColors.m b/ChatSecure/Classes/Utilities/OTRColors.m index b5e462485..81b99e176 100644 --- a/ChatSecure/Classes/Utilities/OTRColors.m +++ b/ChatSecure/Classes/Utilities/OTRColors.m @@ -103,4 +103,9 @@ + (UIColor *)warnColor { return [UIColor colorWithRed:0.94 green:0.77 blue:0 alpha:1]; } ++ (UIColor *)defaultBlueColor +{ + return [UIColor colorWithRed:0.0 green:122.0/255.0 blue:1.0 alpha:1.0]; +} + @end diff --git a/ChatSecure/Classes/Utilities/OTRImages.h b/ChatSecure/Classes/Utilities/OTRImages.h index 5c5b1945d..1856abeea 100644 --- a/ChatSecure/Classes/Utilities/OTRImages.h +++ b/ChatSecure/Classes/Utilities/OTRImages.h @@ -39,6 +39,8 @@ typedef NS_ENUM(NSUInteger, OTRBubbleMessageType) { + (UIImage *)wifiWithColor:(UIColor *)color; ++ (UIImage *)microphoneWithColor:(UIColor *)color size:(CGSize)size; + + (UIImage *)imageWithIdentifier:(NSString *)identifier; + (void)removeImageWithIdentifier:(NSString *)identifier; + (void)setImage:(UIImage *)image forIdentifier:(NSString *)identifier; diff --git a/ChatSecure/Classes/Utilities/OTRImages.m b/ChatSecure/Classes/Utilities/OTRImages.m index 424d37dda..72893a706 100644 --- a/ChatSecure/Classes/Utilities/OTRImages.m +++ b/ChatSecure/Classes/Utilities/OTRImages.m @@ -22,6 +22,7 @@ NSString *const OTRCheckmarkImageKey = @"OTRCeckmarkImageKey"; NSString *const OTRErrorImageKey = @"OTRErrorImageKey"; NSString *const OTRWifiImageKey = @"OTRWifiImageKey"; +NSString *const OTRMicrophoneImageKey = @"OTRMicrophoneImageKey"; @implementation OTRImages @@ -458,6 +459,99 @@ + (UIImage *)wifiWithColor:(UIColor *)color }]; } ++ (UIImage *)microphoneWithColor:(UIColor *)color size:(CGSize)size +{ + if (!color) { + color = [UIColor blackColor]; + } + + if (CGSizeEqualToSize(size, CGSizeZero)) { + size = CGSizeMake(69.232, 100); + } else { + CGFloat normalRatio = 0.69232; + CGFloat ratio = size.width / size.height; + if (ratio < 0.69232 ) { + size.height = size.width / normalRatio; + + } else { + size.width = size.height * normalRatio; + } + } + + NSString *identifier = [NSString stringWithFormat:@"%@%@",OTRMicrophoneImageKey,[color description]]; + return [UIImage imageWithIdentifier:identifier forSize:size andDrawingBlock:^{ + + CGRect group2 = CGRectMake(0, 0, size.width, size.height); + + + //// Group 2 + { + //// Bezier Drawing + UIBezierPath* bezierPath = UIBezierPath.bezierPath; + [bezierPath moveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.49999 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.69230 * CGRectGetHeight(group2))]; + [bezierPath addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.69616 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.63582 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.57639 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.69230 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.64177 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.67347 * CGRectGetHeight(group2))]; + [bezierPath addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.77775 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.50000 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.75055 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.59817 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.77775 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.55289 * CGRectGetHeight(group2))]; + [bezierPath addLineToPoint: CGPointMake(CGRectGetMinX(group2) + 0.77775 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.19231 * CGRectGetHeight(group2))]; + [bezierPath addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.69616 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.05649 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.77775 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.13942 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.75057 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.09416 * CGRectGetHeight(group2))]; + [bezierPath addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.49999 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.00000 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.64177 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.01884 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.57639 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.00000 * CGRectGetHeight(group2))]; + [bezierPath addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.30382 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.05649 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.42360 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.00000 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.35822 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.01884 * CGRectGetHeight(group2))]; + [bezierPath addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.22222 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.19231 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.24942 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.09415 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.22222 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.13942 * CGRectGetHeight(group2))]; + [bezierPath addLineToPoint: CGPointMake(CGRectGetMinX(group2) + 0.22222 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.50000 * CGRectGetHeight(group2))]; + [bezierPath addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.30382 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.63582 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.22222 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.55289 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.24943 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.59817 * CGRectGetHeight(group2))]; + [bezierPath addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.49999 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.69230 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.35821 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.67347 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.42360 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.69230 * CGRectGetHeight(group2))]; + [bezierPath closePath]; + bezierPath.miterLimit = 4; + + [color setFill]; + [bezierPath fill]; + + + //// Bezier 3 Drawing + UIBezierPath* bezier3Path = UIBezierPath.bezierPath; + [bezier3Path moveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.98349 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.39603 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.94443 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.38461 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.97251 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.38842 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.95947 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.38461 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.90537 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.39603 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.92938 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.38461 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.91636 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.38842 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.88888 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.42307 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.89437 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.40365 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.88888 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.41266 * CGRectGetHeight(group2))]; + [bezier3Path addLineToPoint: CGPointMake(CGRectGetMinX(group2) + 0.88888 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.50000 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.77473 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.69020 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.88888 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.57412 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.85082 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.63751 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.49999 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.76923 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.69864 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.74289 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.60706 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.76923 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.22525 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.69020 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.39293 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.76923 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.30136 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.74289 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.11111 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.50000 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.14916 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.63753 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.11111 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.57412 * CGRectGetHeight(group2))]; + [bezier3Path addLineToPoint: CGPointMake(CGRectGetMinX(group2) + 0.11111 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.42307 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.09462 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.39603 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.11111 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.41266 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.10562 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.40365 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.05556 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.38461 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.08363 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.38842 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.07062 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.38461 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.01649 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.39603 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.04051 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.38461 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.02749 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.38842 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.00000 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.42307 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.00550 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.40365 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.00000 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.41266 * CGRectGetHeight(group2))]; + [bezier3Path addLineToPoint: CGPointMake(CGRectGetMinX(group2) + 0.00000 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.50000 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.12803 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.73107 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.00000 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.58854 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.04268 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.66557 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.44443 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.84374 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.21338 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.79657 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.31885 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.83413 * CGRectGetHeight(group2))]; + [bezier3Path addLineToPoint: CGPointMake(CGRectGetMinX(group2) + 0.44443 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.92307 * CGRectGetHeight(group2))]; + [bezier3Path addLineToPoint: CGPointMake(CGRectGetMinX(group2) + 0.22222 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.92307 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.18316 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.93449 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.20717 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.92307 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.19415 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.92688 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.16666 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.96153 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.17216 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.94210 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.16666 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.95112 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.18316 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.98857 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.16666 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.97194 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.17216 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.98097 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.22222 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 1.00000 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.19415 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.99619 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.20717 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 1.00000 * CGRectGetHeight(group2))]; + [bezier3Path addLineToPoint: CGPointMake(CGRectGetMinX(group2) + 0.77775 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 1.00000 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.81681 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.98857 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.79280 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 1.00000 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.80584 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.99619 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.83332 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.96153 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.82782 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.98097 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.83332 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.97194 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.81681 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.93449 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.83332 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.95112 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.82782 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.94210 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.77775 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.92307 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.80584 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.92688 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.79280 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.92307 * CGRectGetHeight(group2))]; + [bezier3Path addLineToPoint: CGPointMake(CGRectGetMinX(group2) + 0.55556 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.92307 * CGRectGetHeight(group2))]; + [bezier3Path addLineToPoint: CGPointMake(CGRectGetMinX(group2) + 0.55556 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.84374 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.87195 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.73107 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.68112 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.83413 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.78658 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.79657 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 1.00000 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.50000 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 0.95731 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.66557 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 1.00000 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.58854 * CGRectGetHeight(group2))]; + [bezier3Path addLineToPoint: CGPointMake(CGRectGetMinX(group2) + 1.00000 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.42307 * CGRectGetHeight(group2))]; + [bezier3Path addCurveToPoint: CGPointMake(CGRectGetMinX(group2) + 0.98349 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.39603 * CGRectGetHeight(group2)) controlPoint1: CGPointMake(CGRectGetMinX(group2) + 1.00000 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.41266 * CGRectGetHeight(group2)) controlPoint2: CGPointMake(CGRectGetMinX(group2) + 0.99449 * CGRectGetWidth(group2), CGRectGetMinY(group2) + 0.40365 * CGRectGetHeight(group2))]; + [bezier3Path closePath]; + bezier3Path.miterLimit = 4; + + [color setFill]; + [bezier3Path fill]; + } + + }]; +} + + (UIImage *)imageWithIdentifier:(NSString *)identifier { return [[self imageCache] objectForKey:identifier]; diff --git a/ChatSecure/Classes/View Controllers/OTRAudioRecorderViewController.h b/ChatSecure/Classes/View Controllers/OTRAudioRecorderViewController.h new file mode 100644 index 000000000..37262ac0e --- /dev/null +++ b/ChatSecure/Classes/View Controllers/OTRAudioRecorderViewController.h @@ -0,0 +1,20 @@ +// +// OTRAudioRecorderViewController.h +// ChatSecure +// +// Created by David Chiles on 2/11/15. +// Copyright (c) 2015 Chris Ballinger. All rights reserved. +// + +#import + +@class OTRBuddy; + +@interface OTRAudioRecorderViewController : UIViewController + +- (instancetype)initWithBuddy:(OTRBuddy *)buddy; + +- (void)showAudioRecorderFromViewController:(UIViewController *)viewController animated:(BOOL)animated fromMicrophoneRectInWindow:(CGRect)rectInWindow; + + +@end diff --git a/ChatSecure/Classes/View Controllers/OTRAudioRecorderViewController.m b/ChatSecure/Classes/View Controllers/OTRAudioRecorderViewController.m new file mode 100644 index 000000000..3f427ca38 --- /dev/null +++ b/ChatSecure/Classes/View Controllers/OTRAudioRecorderViewController.m @@ -0,0 +1,364 @@ +// +// OTRAudioRecorderViewController.m +// ChatSecure +// +// Created by David Chiles on 2/11/15. +// Copyright (c) 2015 Chris Ballinger. All rights reserved. +// + +#import "OTRAudioRecorderViewController.h" +#import "OTRAudioSessionManager.h" +#import "OTRBuddy.h" +#import "OTRMessage.h" +#import "OTRAudioItem.h" +#import "PureLayout.h" +#import "Strings.h" +#import "OTRDatabaseManager.h" +#import "OTRUtilities.h" +#import "OTRImages.h" +#import "BButton.h" +#import "OTRColors.h" + +@import AVFoundation; + +NSString *const kOTRAudioRecordAnimatePath = @"kOTRAudioRecordAnimatePath"; + +@interface OTRAudioRecorderViewController () + +@property (nonatomic, strong) OTRBuddy *buddy; +@property (nonatomic, strong) OTRAudioSessionManager *audioSessionManager; + +@property (nonatomic) BOOL addedConstraints; + +@property (nonatomic, strong) UIView *microphoneView; +@property (nonatomic, strong) UIView *blurredBackgroundView; +@property (nonatomic, strong) UIImageView *microphoneImageView; +@property (nonatomic, strong) UIButton *sendButton; +@property (nonatomic, strong) UIButton *cancelButton; +@property (nonatomic, strong) UILabel *timerLabel; + +@property (nonatomic, strong) NSLayoutConstraint *sendButtonBottomConstraint; +@property (nonatomic, strong) NSLayoutConstraint *cancelButtonBottomConstraint; + +@property (nonatomic, strong) NSTimer *labelTimer; + +@property (nonatomic) CGFloat microphoneRatio; + +@end + +@implementation OTRAudioRecorderViewController + +- (instancetype) initWithBuddy:(OTRBuddy *)buddy +{ + if (self = [super init]) { + self.buddy = buddy; + self.audioSessionManager = [[OTRAudioSessionManager alloc] init]; + self.addedConstraints = NO; + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + + CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; + maskLayer.bounds = CGRectZero; + [maskLayer setFillColor:[[UIColor blackColor] CGColor]]; + self.blurredBackgroundView.layer.mask = maskLayer; + self.blurredBackgroundView.translatesAutoresizingMaskIntoConstraints = NO; + + + self.microphoneView = [[UIView alloc] initWithFrame:CGRectZero]; + self.microphoneView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; + + UIColor *microphoneColor = [OTRColors defaultBlueColor]; + UIImage *microphoneImage = [OTRImages microphoneWithColor:microphoneColor size:CGSizeMake(CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds))]; + self.microphoneRatio = microphoneImage.size.width / microphoneImage.size.height; + self.microphoneImageView = [[UIImageView alloc] initWithImage:microphoneImage]; + self.microphoneView.contentMode = UIViewContentModeScaleAspectFit; + self.microphoneImageView.translatesAutoresizingMaskIntoConstraints = NO; + + self.sendButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + self.sendButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.sendButton setTitle:@"Send" forState:UIControlStateNormal]; + [self.sendButton addTarget:self action:@selector(didPressSend:) forControlEvents:UIControlEventTouchUpInside]; + + self.cancelButton = [[BButton alloc] initWithFrame:CGRectZero type:BButtonTypeDefault style:BButtonStyleBootstrapV3 icon:FATimes fontSize:12.0]; + self.cancelButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.cancelButton addTarget:self action:@selector(didPressCancel:) forControlEvents:UIControlEventTouchUpInside]; + + self.timerLabel = [[UILabel alloc] initForAutoLayout]; + self.timerLabel.textColor = [UIColor whiteColor]; + self.timerLabel.numberOfLines = 1; + self.timerLabel.minimumScaleFactor = 0.5; + self.timerLabel.adjustsFontSizeToFitWidth = YES; + self.timerLabel.textAlignment = NSTextAlignmentCenter; + + [self.view addSubview:self.blurredBackgroundView]; + [self.view addSubview:self.microphoneView]; + [self.microphoneView addSubview:self.microphoneImageView]; + [self.microphoneView addSubview:self.timerLabel]; + [self.view addSubview:self.sendButton]; + [self.view addSubview:self.cancelButton]; + + [self.view setNeedsUpdateConstraints]; + + self.view.backgroundColor = [UIColor clearColor]; +} + +#pragma - mark Presentation Methods + +- (void)showAudioRecorderFromViewController:(UIViewController *)viewController animated:(BOOL)animated fromMicrophoneRectInWindow:(CGRect)rectInWindow +{ + //Pressenting ViewController on top of another http://www.raywenderlich.com/forums/viewtopic.php?f=2&t=18661 + self.providesPresentationContextTransitionStyle = YES; + self.modalPresentationStyle = UIModalPresentationOverCurrentContext; + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) { + self.modalPresentationCapturesStatusBarAppearance = UIModalPresentationOverCurrentContext; + } else { + self.modalPresentationStyle = UIModalPresentationCurrentContext; + } + + [viewController presentViewController:self animated:NO completion:^{ + //Animate microphon + if (!animated) { + return; + } + + + CGRect referenceFrameInMyView = [self.view convertRect:rectInWindow fromView:nil]; + self.microphoneView.frame = referenceFrameInMyView; + + + CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; + maskLayer.bounds = self.blurredBackgroundView.bounds; + maskLayer.anchorPoint = CGPointMake(0, 0); + CGFloat maxDimension = MAX(CGRectGetWidth(referenceFrameInMyView), CGRectGetHeight(referenceFrameInMyView)); + CGRect circleRect = referenceFrameInMyView; + circleRect.size.height = maxDimension; + circleRect.size.width = maxDimension; + maskLayer.path = [UIBezierPath bezierPathWithOvalInRect:circleRect].CGPath; + + self.blurredBackgroundView.layer.mask = maskLayer; + + + dispatch_async(dispatch_get_main_queue(), ^{ + dispatch_async(dispatch_get_main_queue(), ^{ + + NSTimeInterval duration = 0.5; + + CGPathRef oldPath = maskLayer.path; + CGFloat maxDimension = MAX(CGRectGetHeight(self.view.bounds), CGRectGetWidth(self.view.bounds)); + //Calculate square rect that is bounded by max dimension with same center point + CGRect squareRect = CGRectInset(self.view.bounds, (CGRectGetWidth(self.view.bounds) - maxDimension)/2, (CGRectGetHeight(self.view.bounds)- maxDimension)/2); + //Expand circle to twice the max dimension to cover entire view once done animating but still centered + CGRect newCircleRect = CGRectInset(squareRect, -0.5 * maxDimension, -0.5 * maxDimension); + CGPathRef newPath = [UIBezierPath bezierPathWithOvalInRect:newCircleRect].CGPath; + + CABasicAnimation* revealAnimation = [CABasicAnimation animationWithKeyPath:@"path"]; + revealAnimation.fromValue = (__bridge id)(oldPath); + revealAnimation.toValue = (__bridge id)(newPath); + revealAnimation.duration = duration; + + [self.blurredBackgroundView.layer.mask addAnimation:revealAnimation forKey:kOTRAudioRecordAnimatePath]; + + ((CAShapeLayer *)self.blurredBackgroundView.layer.mask).path = newPath; + + [UIView animateWithDuration:duration animations:^{ + + self.microphoneView.frame = CGRectMake(0, 0, 100, 100); + self.microphoneView.center = self.view.center; + [self.view layoutIfNeeded]; + } completion:^(BOOL finished) { + //Start recording once the microphone icon is presented + if (!self.audioSessionManager.isRecording) { + [self startRecording]; + } + [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:10 options:0 animations:^{ + [self.sendButtonBottomConstraint autoRemove]; + [self.cancelButtonBottomConstraint autoRemove]; + [self.view layoutIfNeeded]; + } completion:nil]; + }]; + }); + }); + }]; +} + +#pragma - mark Private Methods + +- (UIView *)blurredBackgroundView { + if (!_blurredBackgroundView) { + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) { + UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + _blurredBackgroundView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + } else { + UIToolbar *toolbar = [[UIToolbar alloc] init]; + toolbar.barStyle = UIBarStyleDefault; + _blurredBackgroundView = toolbar; + } + } + return _blurredBackgroundView; +} + +- (void)updateTime:(id)sender +{ + NSTimeInterval time = [self.audioSessionManager currentTimeRecordTime]; + time = round(time); + NSUInteger minutes = (int)time / 60; + NSUInteger seconds = (int)time % 60; + + self.timerLabel.text = [NSString stringWithFormat:@"%lu:%02ld",(unsigned long)minutes,seconds]; +} + +- (void)animateAwayViewsWithDuration:(NSTimeInterval)duration completion:(void (^)(BOOL finished))completion +{ + CAShapeLayer *maskLayer = (CAShapeLayer *)self.blurredBackgroundView.layer.mask; + CGPathRef oldPath = maskLayer.path; + //Calculate new rect with same center but only 1 x 1 + CGRect newCircleRect = CGRectMake(CGRectGetMidX(self.view.bounds)-1, CGRectGetMidY(self.view.bounds)-1, 1, 1); + CGPathRef newPath = [UIBezierPath bezierPathWithOvalInRect:newCircleRect].CGPath; + + CABasicAnimation* revealAnimation = [CABasicAnimation animationWithKeyPath:@"path"]; + revealAnimation.fromValue = (__bridge id)(oldPath); + revealAnimation.toValue = (__bridge id)(newPath); + revealAnimation.duration = duration; + + [self.blurredBackgroundView.layer.mask addAnimation:revealAnimation forKey:kOTRAudioRecordAnimatePath]; + + ((CAShapeLayer *)self.blurredBackgroundView.layer.mask).path = newPath; + + [UIView animateWithDuration:duration animations:^{ + self.microphoneView.frame = CGRectMake(0, 0, 0, 0); + self.microphoneView.center = self.view.center; + [self.cancelButton removeFromSuperview]; + [self.view layoutIfNeeded]; + } completion:completion]; +} + +- (void)startRecording +{ + NSString *temporaryPath = NSTemporaryDirectory(); + NSString *fileName = [NSString stringWithFormat:@"%@.m4a",[[NSUUID UUID] UUIDString]]; + NSURL *url = [NSURL fileURLWithPath:[temporaryPath stringByAppendingPathComponent:fileName]]; + [self.audioSessionManager recordAudioToURL:url error:nil]; + [self.labelTimer invalidate]; + [self updateTime:nil]; + self.labelTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES]; +} + +- (void)stopRecording +{ + [self.labelTimer invalidate]; + self.labelTimer = nil; + [self updateTime:nil]; + __block NSURL *url = [self.audioSessionManager currentRecorderURL]; + [self.audioSessionManager stopRecording]; + + __block NSString *buddyUniqueId = self.buddy.uniqueId; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + OTRMessage *message = [[OTRMessage alloc] init]; + message.incoming = NO; + message.buddyUniqueId = buddyUniqueId; + + OTRAudioItem *audioItem = [[OTRAudioItem alloc] init]; + audioItem.isIncoming = message.incoming; + audioItem.filename = [[url absoluteString] lastPathComponent]; + + AVAsset *audioAsset = [AVAsset assetWithURL:url]; + audioItem.timeLength = CMTimeGetSeconds(audioAsset.duration); + + message.mediaItemUniqueId = audioItem.uniqueId; + + [[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [audioItem saveWithTransaction:transaction]; + [message saveWithTransaction:transaction]; + }]; + }); +} + +- (void)removeFile:(NSURL *)url +{ + if ([[NSFileManager defaultManager] fileExistsAtPath:url.path]) { + + [[NSFileManager defaultManager] removeItemAtURL:url error:nil]; + } +} + +#pragma - mark AutoLayout +- (void)updateViewConstraints +{ + if (!self.addedConstraints) { + + [self.blurredBackgroundView autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsZero]; + + [self.timerLabel autoAlignAxis:ALAxisVertical toSameAxisOfView:self.microphoneImageView]; + // The numbers .68 and .56 were calculated from the original svg to find the center of the microphone + [self.timerLabel autoConstrainAttribute:ALAttributeHorizontal toAttribute:ALAttributeHorizontal ofView:self.microphoneImageView withMultiplier:0.68]; + [self.timerLabel autoMatchDimension:ALDimensionWidth toDimension:ALDimensionWidth ofView:self.microphoneImageView withMultiplier:0.56]; + + [self.microphoneImageView autoMatchDimension:ALDimensionHeight toDimension:ALDimensionHeight ofView:self.microphoneImageView.superview]; + [self.microphoneImageView autoMatchDimension:ALDimensionWidth toDimension:ALDimensionHeight ofView:self.microphoneImageView withMultiplier:self.microphoneRatio]; + [self.microphoneImageView autoCenterInSuperview]; + + [self.cancelButton autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:5]; + [UIView autoSetPriority:UILayoutPriorityDefaultLow forConstraints:^{ + [self.cancelButton autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:5]; + }]; + + [self.cancelButton autoSetDimension:ALDimensionHeight toSize:30]; + [self.cancelButton autoMatchDimension:ALDimensionWidth toDimension:ALDimensionHeight ofView:self.cancelButton]; + + [self.sendButton autoAlignAxis:ALAxisVertical toSameAxisOfView:self.microphoneView]; + [UIView autoSetPriority:UILayoutPriorityDefaultLow forConstraints:^{ + [self.sendButton autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.microphoneView]; + }]; + [self.sendButton autoSetDimension:ALDimensionHeight toSize:35]; + [self.sendButton autoMatchDimension:ALDimensionWidth toDimension:ALDimensionWidth ofView:self.microphoneView]; + + if (!self.sendButtonBottomConstraint) { + self.sendButtonBottomConstraint = [NSLayoutConstraint constraintWithItem:self.sendButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:5]; + [self.view addConstraint:self.sendButtonBottomConstraint]; + } + + if (!self.cancelButtonBottomConstraint) { + self.cancelButtonBottomConstraint = [NSLayoutConstraint constraintWithItem:self.cancelButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:5]; + [self.view addConstraint:self.cancelButtonBottomConstraint]; + } + + self.addedConstraints = YES; + } + [super updateViewConstraints]; +} + +#pragma - mark Button Methods + +- (void)didPressCancel:(id)sender +{ + if (self.audioSessionManager.isRecording) { + //Cancel + NSURL *currentURL = [self.audioSessionManager currentRecorderURL]; + [self.audioSessionManager stopRecording]; + [self removeFile:currentURL]; + } + + //Animate away the views + [self animateAwayViewsWithDuration:0.5 completion:^(BOOL finished) { + [self dismissViewControllerAnimated:NO completion:nil]; + }]; +} + +- (void)didPressSend:(id)sender +{ + if (self.audioSessionManager.isRecording) { + [self stopRecording]; + } + [self animateAwayViewsWithDuration:0.5 completion:^(BOOL finished) { + [self dismissViewControllerAnimated:NO completion:nil]; + }]; + +} + +@end diff --git a/ChatSecure/Classes/View Controllers/OTRMessagesViewController.m b/ChatSecure/Classes/View Controllers/OTRMessagesViewController.m index 49744eb09..bc7085517 100644 --- a/ChatSecure/Classes/View Controllers/OTRMessagesViewController.m +++ b/ChatSecure/Classes/View Controllers/OTRMessagesViewController.m @@ -42,6 +42,7 @@ #import "OTRAudioControlsView.h" #import "OTRPlayPauseProgressView.h" #import "OTRAudioPlaybackController.h" +#import "OTRAudioRecorderViewController.h" @import AVFoundation; @import MediaPlayer; @@ -752,6 +753,7 @@ - (void)showImage:(OTRImageItem *)imageItem fromCollectionView:(JSQMessagesColle UIView *cellContainterView = ((JSQMessagesCollectionViewCell *)cell).messageBubbleContainerView; imageInfo.referenceRect = cellContainterView.bounds; imageInfo.referenceView = cellContainterView; + imageInfo.referenceCornerRadius = 5; } JTSImageViewController *imageViewer = [[JTSImageViewController alloc] @@ -848,45 +850,18 @@ - (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL) - (void)didPressSendButton:(UIButton *)button withMessageText:(NSString *)text senderId:(NSString *)senderId senderDisplayName:(NSString *)senderDisplayName date:(NSDate *)date { + self.navigationController.providesPresentationContextTransitionStyle = YES; + self.navigationController.definesPresentationContext = YES; + OTRAudioRecorderViewController *recorderViewController = [[OTRAudioRecorderViewController alloc] initWithBuddy:self.buddy]; + CGRect rectInWindow = [self.microphoneButton convertRect:self.microphoneButton.frame toView:nil]; + [recorderViewController showAudioRecorderFromViewController:self animated:YES fromMicrophoneRectInWindow:rectInWindow]; if ([[OTRProtocolManager sharedInstance] isAccountConnected:self.account]) { //Account is connected if ([button isEqual:self.microphoneButton]) { - //FIXME where should audio be saved - if (self.audioSessionManager.isRecording) { - __block NSURL *url = [self.audioSessionManager currentRecorderURL]; - [self.audioSessionManager stopRecording]; - - __weak typeof(self)weakSelf = self; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - __strong typeof(weakSelf)strongSelf = weakSelf; - OTRMessage *message = [[OTRMessage alloc] init]; - message.incoming = NO; - message.buddyUniqueId = strongSelf.buddy.uniqueId; - - OTRAudioItem *audioItem = [[OTRAudioItem alloc] init]; - audioItem.isIncoming = message.incoming; - audioItem.filename = [[url absoluteString] lastPathComponent]; - - AVAsset *audioAsset = [AVAsset assetWithURL:url]; - audioItem.timeLength = CMTimeGetSeconds(audioAsset.duration); - - message.mediaItemUniqueId = audioItem.uniqueId; - - [[OTRDatabaseManager sharedInstance].readWriteDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [audioItem saveWithTransaction:transaction]; - [message saveWithTransaction:transaction]; - }]; - }); - - - } else { - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *documentsPath = [paths firstObject]; - NSString *fileName = [NSString stringWithFormat:@"%@.m4a",[[NSUUID UUID] UUIDString]]; - NSURL *url = [NSURL fileURLWithPath:[documentsPath stringByAppendingPathComponent:fileName]]; - [self.audioSessionManager recordAudioToURL:url error:nil]; - } + + OTRAudioRecorderViewController *recorderViewController = [[OTRAudioRecorderViewController alloc] initWithBuddy:self.buddy]; + //[recorderViewController showAudioRecorderFromViewController:self]; } else { OTRMessage *message = [[OTRMessage alloc] init]; @@ -1222,9 +1197,6 @@ - (void)yapDatabaseModified:(NSNotification *)notification } } - - [self.collectionView reloadData]; - if (messageRowChanges.count && [self.collectionView numberOfItemsInSection:0] != 0) { NSUInteger lastMessageIndex = [self.collectionView numberOfItemsInSection:0] - 1; NSIndexPath *lastMessageIndexPath = [NSIndexPath indexPathForRow:lastMessageIndex inSection:0]; diff --git a/media/app-images/microphone/microphone28.svg b/media/app-images/microphone/microphone28.svg new file mode 100755 index 000000000..b4863eba8 --- /dev/null +++ b/media/app-images/microphone/microphone28.svg @@ -0,0 +1,20 @@ + + + + + + + + +