ifish/Ifish/controllers/IfishYooseeFile/IfishYooseeHelper/MPNotificationView/MPNotificationView.m

496 lines
18 KiB
Objective-C

//
// MPNotificationView.m
// Moped
//
// Created by Engin Kurutepe on 1/2/13.
// Copyright (c) 2013 Moped Inc. All rights reserved.
//
#import "MPNotificationView.h"
#import "OBGradientView.h"
#define kMPNotificationHeight 40.0f
#define kMPNotificationIPadWidth 480.0f
#define RADIANS(deg) ((deg) * M_PI / 180.0f)
static CGRect notificationRect()
{
if (UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]))
{
return CGRectMake(0.0f, 0.0f, [UIScreen mainScreen].bounds.size.height, kMPNotificationHeight);
}
return CGRectMake(0.0f, 0.0f, [UIScreen mainScreen].bounds.size.width, kMPNotificationHeight);
}
NSString *kMPNotificationViewTapReceivedNotification = @"kMPNotificationViewTapReceivedNotification";
#pragma mark MPNotificationWindow
@interface MPNotificationWindow : UIWindow
@property (nonatomic, strong) NSMutableArray *notificationQueue;
@property (nonatomic, strong) UIView *currentNotification;
@end
@implementation MPNotificationWindow
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (id) initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.windowLevel = UIWindowLevelStatusBar + 1;
self.backgroundColor = [UIColor clearColor];
_notificationQueue = [[NSMutableArray alloc] initWithCapacity:4];
UIView *topHalfBlackView = [[UIView alloc] initWithFrame:CGRectMake(CGRectGetMinX(frame),
CGRectGetMinY(frame),
CGRectGetWidth(frame),
0.5 * CGRectGetHeight(frame))];
topHalfBlackView.backgroundColor = [UIColor blackColor];
topHalfBlackView.layer.zPosition = -100;
topHalfBlackView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:topHalfBlackView];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(willRotateScreen:)
name:UIApplicationWillChangeStatusBarFrameNotification
object:nil];
[self rotateStatusBarWithFrame:frame];
}
return self;
}
- (void) willRotateScreen:(NSNotification *)notification
{
CGRect notificationBarFrame = notificationRect();
if (self.hidden)
{
[self rotateStatusBarWithFrame:notificationBarFrame];
}
else
{
[self rotateStatusBarAnimatedWithFrame:notificationBarFrame];
}
}
- (void) rotateStatusBarAnimatedWithFrame:(CGRect)frame
{
CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration;
[UIView animateWithDuration:duration
animations:^{
self.alpha = 0;
} completion:^(BOOL finished) {
[self rotateStatusBarWithFrame:frame];
[UIView animateWithDuration:duration
animations:^{
self.alpha = 1;
}];
}];
}
- (void) rotateStatusBarWithFrame:(CGRect)frame
{
BOOL isPortrait = (frame.size.width == [UIScreen mainScreen].bounds.size.width);
if (isPortrait)
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
frame.size.width = kMPNotificationIPadWidth;
}
if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown)
{
frame.origin.y = [UIScreen mainScreen].bounds.size.height - kMPNotificationHeight;
self.transform = CGAffineTransformMakeRotation(RADIANS(180.0f));
}
else
{
self.transform = CGAffineTransformIdentity;
}
}
else
{
frame.size.height = frame.size.width;
frame.size.width = kMPNotificationHeight;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
frame.size.height = kMPNotificationIPadWidth;
}
if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft)
{
frame.origin.x = [UIScreen mainScreen].bounds.size.width - frame.size.width;
self.transform = CGAffineTransformMakeRotation(RADIANS(90.0f));
}
else
{
self.transform = CGAffineTransformMakeRotation(RADIANS(-90.0f));
}
}
self.frame = frame;
CGPoint center = self.center;
if (isPortrait)
{
center.x = CGRectGetMidX([UIScreen mainScreen].bounds);
}
else
{
center.y = CGRectGetMidY([UIScreen mainScreen].bounds);
}
self.center = center;
}
@end
static MPNotificationWindow * __notificationWindow = nil;
static CGFloat const __imagePadding = 8.0f;
#pragma mark -
#pragma mark MPNotificationView
@interface MPNotificationView ()
@property (nonatomic, strong) OBGradientView * contentView;
@property (nonatomic, copy) MPNotificationSimpleAction tapBlock;
@property (nonatomic, strong) UITapGestureRecognizer *tapGestureRecognizer;
+ (void) showNextNotification;
+ (UIImage*) screenImageWithRect:(CGRect)rect;
@end
@implementation MPNotificationView
- (void) dealloc
{
_delegate = nil;
[self removeGestureRecognizer:_tapGestureRecognizer];
[super dealloc];
}
- (id) initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
CGFloat notificationWidth = notificationRect().size.width;
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_contentView = [[OBGradientView alloc] initWithFrame:self.bounds];
_contentView.colors = @[(id)[[UIColor colorWithWhite:0.99f alpha:1.0f] CGColor],
(id)[[UIColor colorWithWhite:0.9f alpha:1.0f] CGColor]];
_contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_contentView.layer.cornerRadius = 0.0f;
_contentView.clipsToBounds = YES;
[self addSubview:_contentView];
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(6, 6, 28, 28)];
_imageView.contentMode = UIViewContentModeScaleAspectFill;
_imageView.layer.cornerRadius = 4.0f;
_imageView.clipsToBounds = YES;
[self addSubview:_imageView];
UIFont *textFont = [UIFont boldSystemFontOfSize:14.0f];
CGRect textFrame = CGRectMake(__imagePadding + CGRectGetMaxX(_imageView.frame),
2,
notificationWidth - __imagePadding * 2 - CGRectGetMaxX(_imageView.frame),
textFont.lineHeight);
_textLabel = [[UILabel alloc] initWithFrame:textFrame];
_textLabel.font = textFont;
_textLabel.numberOfLines = 1;
_textLabel.textAlignment = NSTextAlignmentLeft;
_textLabel.lineBreakMode = UILineBreakModeTailTruncation;
_textLabel.backgroundColor = [UIColor clearColor];
[_contentView addSubview:_textLabel];
UIFont *detailFont = [UIFont systemFontOfSize:13.0f];
CGRect detailFrame = CGRectMake(CGRectGetMinX(textFrame),
CGRectGetMaxY(textFrame),
notificationWidth - __imagePadding * 2 - CGRectGetMaxX(_imageView.frame),
detailFont.lineHeight);
_detailTextLabel = [[UILabel alloc] initWithFrame:detailFrame];
_detailTextLabel.font = detailFont;
_detailTextLabel.numberOfLines = 1;
_detailTextLabel.textAlignment = NSTextAlignmentLeft;
_detailTextLabel.lineBreakMode = UILineBreakModeTailTruncation;
_detailTextLabel.backgroundColor = [UIColor clearColor];
[_contentView addSubview:_detailTextLabel];
UIView *bottomLine = [[UIView alloc] initWithFrame:CGRectMake(CGRectGetMinX(frame),
CGRectGetHeight(frame) - 1.0f,
CGRectGetWidth(frame),
1.0f)];
bottomLine.backgroundColor = [UIColor colorWithWhite:0.92 alpha:1.0];
[_contentView addSubview:bottomLine];
}
return self;
}
+ (MPNotificationView *) notifyWithText:(NSString*)text
andDetail:(NSString*)detail
{
return [self notifyWithText:text
detail:detail
andDuration:2.0f];
}
+ (MPNotificationView *) notifyWithText:(NSString*)text
detail:(NSString*)detail
andDuration:(NSTimeInterval)duration
{
return [self notifyWithText:text
detail:detail
image:nil
andDuration:duration];
}
+ (MPNotificationView *) notifyWithText:(NSString*)text
detail:(NSString*)detail
image:(UIImage*)image
andDuration:(NSTimeInterval)duration
{
return [self notifyWithText:text
detail:detail
image:image
duration:duration
andTouchBlock:nil];
}
+ (MPNotificationView *) notifyWithText:(NSString*)text
detail:(NSString*)detail
duration:(NSTimeInterval)duration
andTouchBlock:(MPNotificationSimpleAction)block
{
return [self notifyWithText:text
detail:detail
image:nil
duration:duration
andTouchBlock:block];
}
+ (MPNotificationView *) notifyWithText:(NSString*)text
detail:(NSString*)detail
andTouchBlock:(MPNotificationSimpleAction)block
{
return [self notifyWithText:text
detail:detail
image:nil
duration:2.0
andTouchBlock:block];
}
+ (MPNotificationView *) notifyWithText:(NSString*)text
detail:(NSString*)detail
image:(UIImage*)image
duration:(NSTimeInterval)duration
andTouchBlock:(MPNotificationSimpleAction)block
{
if (__notificationWindow == nil)
{
__notificationWindow = [[MPNotificationWindow alloc] initWithFrame:notificationRect()];
__notificationWindow.hidden = NO;
}
MPNotificationView * notification = [[MPNotificationView alloc] initWithFrame:__notificationWindow.bounds];
notification.textLabel.text = text;
notification.detailTextLabel.text = detail;
notification.imageView.image = image;
notification.duration = duration;
notification.tapBlock = block;
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:notification
action:@selector(handleTap:)];
notification.tapGestureRecognizer = gr;
[notification addGestureRecognizer:gr];
[__notificationWindow.notificationQueue addObject:notification];
if (__notificationWindow.currentNotification == nil)
{
[self showNextNotification];
}
return notification;
}
- (void) handleTap:(UITapGestureRecognizer *)gestureRecognizer
{
if (_tapBlock != nil)
{
_tapBlock(self);
}
if ([_delegate respondsToSelector:@selector(tapReceivedForNotificationView:)])
{
[_delegate didTapOnNotificationView:self];
}
[[NSNotificationCenter defaultCenter] postNotificationName:kMPNotificationViewTapReceivedNotification
object:self];
[NSObject cancelPreviousPerformRequestsWithTarget:[self class]
selector:@selector(showNextNotification)
object:nil];
[MPNotificationView showNextNotification];
}
+ (void) showNextNotification
{
UIView *viewToRotateOut = nil;
UIImage *screenshot = [self screenImageWithRect:__notificationWindow.frame];
if (__notificationWindow.currentNotification)
{
viewToRotateOut = __notificationWindow.currentNotification;
}
else
{
viewToRotateOut = [[UIImageView alloc] initWithFrame:__notificationWindow.bounds];
((UIImageView *)viewToRotateOut).image = screenshot;
[__notificationWindow addSubview:viewToRotateOut];
__notificationWindow.hidden = NO;
}
UIView *viewToRotateIn = nil;
if ([__notificationWindow.notificationQueue count] > 0)
{
viewToRotateIn = __notificationWindow.notificationQueue[0];
}
else
{
viewToRotateIn = [[UIImageView alloc] initWithFrame:__notificationWindow.bounds];
((UIImageView *)viewToRotateIn).image = screenshot;
}
viewToRotateIn.layer.anchorPointZ = 11.547f;
viewToRotateIn.layer.doubleSided = NO;
viewToRotateIn.layer.zPosition = 2;
CATransform3D viewInStartTransform = CATransform3DMakeRotation(RADIANS(-120), 1.0, 0.0, 0.0);
viewInStartTransform.m34 = -1.0 / 200.0;
viewToRotateOut.layer.anchorPointZ = 11.547f;
viewToRotateOut.layer.doubleSided = NO;
viewToRotateOut.layer.zPosition = 2;
CATransform3D viewOutEndTransform = CATransform3DMakeRotation(RADIANS(120), 1.0, 0.0, 0.0);
viewOutEndTransform.m34 = -1.0 / 200.0;
[__notificationWindow addSubview:viewToRotateIn];
__notificationWindow.backgroundColor = [UIColor blackColor];
viewToRotateIn.layer.transform = viewInStartTransform;
if ([viewToRotateIn isKindOfClass:[MPNotificationView class]] )
{
UIImageView *bgImage = [[UIImageView alloc] initWithFrame:__notificationWindow.bounds];
bgImage.image = screenshot;
[viewToRotateIn addSubview:bgImage];
[viewToRotateIn sendSubviewToBack:bgImage];
__notificationWindow.currentNotification = viewToRotateIn;
}
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
viewToRotateIn.layer.transform = CATransform3DIdentity;
viewToRotateOut.layer.transform = viewOutEndTransform;
}
completion:^(BOOL finished) {
[viewToRotateOut removeFromSuperview];
[__notificationWindow.notificationQueue removeObject:viewToRotateOut];
if ([viewToRotateIn isKindOfClass:[MPNotificationView class]])
{
MPNotificationView *notification = (MPNotificationView*)viewToRotateIn;
[self performSelector:@selector(showNextNotification)
withObject:nil
afterDelay:notification.duration];
__notificationWindow.currentNotification = notification;
[__notificationWindow.notificationQueue removeObject:notification];
}
else
{
[viewToRotateIn removeFromSuperview];
__notificationWindow.hidden = YES;
__notificationWindow.currentNotification = nil;
}
__notificationWindow.backgroundColor = [UIColor clearColor];
}];
}
+ (UIImage *) screenImageWithRect:(CGRect)rect
{
CALayer *layer = [[UIApplication sharedApplication] keyWindow].layer;
CGFloat scale = [UIScreen mainScreen].scale;
UIGraphicsBeginImageContextWithOptions(layer.frame.size, NO, scale);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
rect = CGRectMake(rect.origin.x * scale, rect.origin.y * scale
, rect.size.width * scale, rect.size.height * scale);
CGImageRef imageRef = CGImageCreateWithImageInRect([screenshot CGImage], rect);
UIImage *croppedScreenshot = [UIImage imageWithCGImage:imageRef
scale:screenshot.scale
orientation:screenshot.imageOrientation];
CGImageRelease(imageRef);
UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
UIImageOrientation imageOrientation = UIImageOrientationUp;
switch (orientation)
{
case UIDeviceOrientationPortraitUpsideDown:
imageOrientation = UIImageOrientationDown;
break;
case UIDeviceOrientationLandscapeRight:
imageOrientation = UIImageOrientationRight;
break;
case UIDeviceOrientationLandscapeLeft:
imageOrientation = UIImageOrientationLeft;
break;
default:
break;
}
return [[UIImage alloc] initWithCGImage:croppedScreenshot.CGImage
scale:croppedScreenshot.scale
orientation:imageOrientation];
}
@end