123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927 |
- //
- // TWMessageBarManager.m
- //
- // Created by Terry Worona on 5/13/13.
- // Copyright (c) 2013 Terry Worona. All rights reserved.
- //
- #import "TWMessageBarManager.h"
- // Quartz
- #import <QuartzCore/QuartzCore.h>
- // Numerics (TWMessageBarStyleSheet)
- CGFloat const kTWMessageBarStyleSheetMessageBarAlpha = 0.96f;
- // Numerics (TWMessageView)
- CGFloat const kTWMessageViewBarPadding = 10.0f;
- CGFloat const kTWMessageViewIconSize = 36.0f;
- CGFloat const kTWMessageViewTextOffset = 2.0f;
- NSUInteger const kTWMessageViewiOS7Identifier = 7;
- // Numerics (TWMessageBarManager)
- CGFloat const kTWMessageBarManagerDisplayDelay = 3.0f;
- CGFloat const kTWMessageBarManagerDismissAnimationDuration = 0.25f;
- CGFloat const kTWMessageBarManagerPanVelocity = 0.2f;
- CGFloat const kTWMessageBarManagerPanAnimationDuration = 0.0002f;
- // Strings (TWMessageBarStyleSheet)
- NSString * const kTWMessageBarStyleSheetImageIconError = @"icon-error.png";
- NSString * const kTWMessageBarStyleSheetImageIconSuccess = @"icon-success.png";
- NSString * const kTWMessageBarStyleSheetImageIconInfo = @"icon-info.png";
- // Fonts (TWMessageView)
- static UIFont *kTWMessageViewTitleFont = nil;
- static UIFont *kTWMessageViewDescriptionFont = nil;
- // Colors (TWMessageView)
- static UIColor *kTWMessageViewTitleColor = nil;
- static UIColor *kTWMessageViewDescriptionColor = nil;
- // Colors (TWDefaultMessageBarStyleSheet)
- static UIColor *kTWDefaultMessageBarStyleSheetErrorBackgroundColor = nil;
- static UIColor *kTWDefaultMessageBarStyleSheetSuccessBackgroundColor = nil;
- static UIColor *kTWDefaultMessageBarStyleSheetInfoBackgroundColor = nil;
- static UIColor *kTWDefaultMessageBarStyleSheetErrorStrokeColor = nil;
- static UIColor *kTWDefaultMessageBarStyleSheetSuccessStrokeColor = nil;
- static UIColor *kTWDefaultMessageBarStyleSheetInfoStrokeColor = nil;
- static NSString *prevMessage;
- @protocol TWMessageViewDelegate;
- @interface TWMessageView : UIView
- @property (nonatomic, copy) NSString *titleString;
- @property (nonatomic, copy) NSString *descriptionString;
- @property (nonatomic, assign) TWMessageBarMessageType messageType;
- @property (nonatomic, assign) BOOL hasCallback;
- @property (nonatomic, strong) NSArray *callbacks;
- @property (nonatomic, assign, getter = isHit) BOOL hit;
- @property (nonatomic, assign) CGFloat duration;
- @property (nonatomic, assign) UIStatusBarStyle statusBarStyle;
- @property (nonatomic, assign) BOOL statusBarHidden;
- @property (nonatomic, weak) id <TWMessageViewDelegate> delegate;
- // Initializers
- - (id)initWithTitle:(NSString *)title description:(NSString *)description type:(TWMessageBarMessageType)type;
- // Getters
- - (CGFloat)height;
- - (CGFloat)width;
- - (CGFloat)statusBarOffset;
- - (CGFloat)availableWidth;
- - (CGSize)titleSize;
- - (CGSize)descriptionSize;
- - (CGRect)statusBarFrame;
- - (UIFont *)titleFont;
- - (UIFont *)descriptionFont;
- - (UIColor *)titleColor;
- - (UIColor *)descriptionColor;
- // Helpers
- - (CGRect)orientFrame:(CGRect)frame;
- // Notifications
- - (void)didChangeDeviceOrientation:(NSNotification *)notification;
- @end
- @protocol TWMessageViewDelegate <NSObject>
- - (NSObject<TWMessageBarStyleSheet> *)styleSheetForMessageView:(TWMessageView *)messageView;
- @end
- @interface TWDefaultMessageBarStyleSheet : NSObject <TWMessageBarStyleSheet>
- + (TWDefaultMessageBarStyleSheet *)styleSheet;
- @end
- @interface TWMessageWindow : UIWindow
- @end
- @interface TWMessageBarViewController : UIViewController
- @property (nonatomic, assign) UIStatusBarStyle statusBarStyle;
- @property (nonatomic, assign) BOOL statusBarHidden;
- @end
- @interface TWMessageBarManager () <TWMessageViewDelegate>
- @property (nonatomic, strong) NSMutableArray *messageBarQueue;
- @property (nonatomic, assign, getter = isMessageVisible) BOOL messageVisible;
- @property (nonatomic, strong) TWMessageWindow *messageWindow;
- @property (nonatomic, readwrite) NSArray *accessibleElements; // accessibility
- // Static
- + (CGFloat)durationForMessageType:(TWMessageBarMessageType)messageType;
- // Helpers
- - (void)showNextMessage;
- - (void)generateAccessibleElementWithTitle:(NSString *)title description:(NSString *)description;
- // Gestures
- - (void)itemSelected:(UITapGestureRecognizer *)recognizer;
- // Getters
- - (UIView *)messageWindowView;
- - (TWMessageBarViewController *)messageBarViewController;
- // Master presetation
- - (void)showMessageWithTitle:(NSString *)title description:(NSString *)description type:(TWMessageBarMessageType)type duration:(CGFloat)duration statusBarHidden:(BOOL)statusBarHidden statusBarStyle:(UIStatusBarStyle)statusBarStyle callback:(void (^)())callback;
- @end
- @implementation TWMessageBarManager
- #pragma mark - Singleton
- + (nonnull TWMessageBarManager *)sharedInstance
- {
- static dispatch_once_t pred;
- static TWMessageBarManager *instance = nil;
- dispatch_once(&pred, ^{
- instance = [[self alloc] init];
- });
- return instance;
- }
- #pragma mark - Static
- + (CGFloat)defaultDuration
- {
- return kTWMessageBarManagerDisplayDelay;
- }
- + (CGFloat)durationForMessageType:(TWMessageBarMessageType)messageType
- {
- return kTWMessageBarManagerDisplayDelay;
- }
- #pragma mark - Alloc/Init
- - (id)init
- {
- self = [super init];
- if (self)
- {
- _messageBarQueue = [[NSMutableArray alloc] init];
- _messageVisible = NO;
- _styleSheet = [TWDefaultMessageBarStyleSheet styleSheet];
- _managerSupportedOrientationsMask = UIInterfaceOrientationMaskAll;
- }
- return self;
- }
- #pragma mark - Public
- - (void)showMessageWithTitle:(nullable NSString *)title description:(nullable NSString *)description type:(TWMessageBarMessageType)type
- {
- [self showMessageWithTitle:title description:description type:type duration:[TWMessageBarManager durationForMessageType:type] callback:nil];
- }
- - (void)showMessageWithTitle:(nullable NSString *)title description:(nullable NSString *)description type:(TWMessageBarMessageType)type callback:(nullable void (^)())callback
- {
- [self showMessageWithTitle:title description:description type:type duration:[TWMessageBarManager durationForMessageType:type] callback:callback];
- }
- - (void)showMessageWithTitle:(nullable NSString *)title description:(nullable NSString *)description type:(TWMessageBarMessageType)type duration:(CGFloat)duration
- {
- [self showMessageWithTitle:title description:description type:type duration:duration callback:nil];
- }
- - (void)showMessageWithTitle:(nullable NSString *)title description:(nullable NSString *)description type:(TWMessageBarMessageType)type duration:(CGFloat)duration callback:(nullable void (^)())callback
- {
- [self showMessageWithTitle:title description:description type:type duration:duration statusBarStyle:UIStatusBarStyleDefault callback:callback];
- }
- - (void)showMessageWithTitle:(nullable NSString *)title description:(nullable NSString *)description type:(TWMessageBarMessageType)type statusBarStyle:(UIStatusBarStyle)statusBarStyle callback:(nullable void (^)())callback
- {
- [self showMessageWithTitle:title description:description type:type duration:kTWMessageBarManagerDisplayDelay statusBarStyle:statusBarStyle callback:callback];
- }
- - (void)showMessageWithTitle:(nullable NSString *)title description:(nullable NSString *)description type:(TWMessageBarMessageType)type duration:(CGFloat)duration statusBarStyle:(UIStatusBarStyle)statusBarStyle callback:(nullable void (^)())callback
- {
- [self showMessageWithTitle:title description:description type:type duration:duration statusBarHidden:NO statusBarStyle:statusBarStyle callback:callback];
- }
- - (void)showMessageWithTitle:(nullable NSString *)title description:(nullable NSString *)description type:(TWMessageBarMessageType)type statusBarHidden:(BOOL)statusBarHidden callback:(nullable void (^)())callback
- {
- [self showMessageWithTitle:title description:description type:type duration:[TWMessageBarManager durationForMessageType:type] statusBarHidden:statusBarHidden statusBarStyle:UIStatusBarStyleDefault callback:callback];
- }
- - (void)showMessageWithTitle:(nullable NSString *)title description:(nullable NSString *)description type:(TWMessageBarMessageType)type duration:(CGFloat)duration statusBarHidden:(BOOL)statusBarHidden callback:(nullable void (^)())callback
- {
- [self showMessageWithTitle:title description:description type:type duration:duration statusBarHidden:statusBarHidden statusBarStyle:UIStatusBarStyleDefault callback:callback];
- }
- #pragma mark - Master Presentation
- - (void)showMessageWithTitle:(NSString *)title description:(NSString *)description type:(TWMessageBarMessageType)type duration:(CGFloat)duration statusBarHidden:(BOOL)statusBarHidden statusBarStyle:(UIStatusBarStyle)statusBarStyle callback:(void (^)())callback
- {
- //TWS
- if ([prevMessage isEqualToString:[title stringByAppendingString:description]]) {
-
- return;
-
- } else {
-
- prevMessage = [title stringByAppendingString:description];
- }
-
- for (TWMessageView *messageView in self.messageBarQueue) {
- if ([messageView.titleString isEqualToString:title] && [messageView.descriptionString isEqualToString:description])
- return;
- }
-
- TWMessageView *messageView = [[TWMessageView alloc] initWithTitle:title description:description type:type];
- messageView.delegate = self;
-
- messageView.callbacks = callback ? [NSArray arrayWithObject:callback] : [NSArray array];
- messageView.hasCallback = callback ? YES : NO;
-
- messageView.duration = duration;
- messageView.hidden = YES;
-
- messageView.statusBarStyle = statusBarStyle;
- messageView.statusBarHidden = statusBarHidden;
-
- [[self messageWindowView] addSubview:messageView];
- [[self messageWindowView] bringSubviewToFront:messageView];
-
- [self.messageBarQueue addObject:messageView];
-
- if (!self.messageVisible)
- {
- [self showNextMessage];
- }
- }
- - (void)hideAllAnimated:(BOOL)animated
- {
- for (UIView *subview in [[self messageWindowView] subviews])
- {
- if ([subview isKindOfClass:[TWMessageView class]])
- {
- TWMessageView *currentMessageView = (TWMessageView *)subview;
- if (animated)
- {
- [UIView animateWithDuration:kTWMessageBarManagerDismissAnimationDuration animations:^{
- currentMessageView.frame = CGRectMake(currentMessageView.frame.origin.x, -currentMessageView.frame.size.height, currentMessageView.frame.size.width, currentMessageView.frame.size.height);
- } completion:^(BOOL finished) {
- [currentMessageView removeFromSuperview];
- }];
- }
- else
- {
- [currentMessageView removeFromSuperview];
- }
- }
- }
-
- self.messageVisible = NO;
- [self.messageBarQueue removeAllObjects];
- [NSObject cancelPreviousPerformRequestsWithTarget:self];
- self.messageWindow.hidden = YES;
- self.messageWindow = nil;
-
- //TWS
- prevMessage = nil;
- }
- - (void)hideAll
- {
- [self hideAllAnimated:NO];
- }
- #pragma mark - Helpers
- - (void)showNextMessage
- {
- if ([self.messageBarQueue count] > 0)
- {
- self.messageVisible = YES;
-
- TWMessageView *messageView = [self.messageBarQueue objectAtIndex:0];
- [self messageBarViewController].statusBarHidden = messageView.statusBarHidden; // important to do this prior to hiding
- messageView.frame = CGRectMake(0, -[messageView height], [messageView width], [messageView height]);
- messageView.hidden = NO;
- [messageView setNeedsDisplay];
-
- UITapGestureRecognizer *gest = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(itemSelected:)];
- [messageView addGestureRecognizer:gest];
-
- if (messageView)
- {
- [self.messageBarQueue removeObject:messageView];
-
- [self messageBarViewController].statusBarStyle = messageView.statusBarStyle;
- [UIView animateWithDuration:kTWMessageBarManagerDismissAnimationDuration animations:^{
- [messageView setFrame:CGRectMake(messageView.frame.origin.x, messageView.frame.origin.y + [messageView height], [messageView width], [messageView height])]; // slide down
- }];
- [self performSelector:@selector(itemSelected:) withObject:messageView afterDelay:messageView.duration];
-
- [self generateAccessibleElementWithTitle:messageView.titleString description:messageView.descriptionString];
- }
- }
- }
- - (void)generateAccessibleElementWithTitle:(NSString *)title description:(NSString *)description
- {
- UIAccessibilityElement *textElement = [[UIAccessibilityElement alloc] initWithAccessibilityContainer:self];
- textElement.accessibilityLabel = [NSString stringWithFormat:@"%@\n%@", title, description];
- textElement.accessibilityTraits = UIAccessibilityTraitStaticText;
- self.accessibleElements = @[textElement];
- UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self); // notify the accessibility framework to read the message
- }
- #pragma mark - Gestures
- - (void)itemSelected:(id)sender
- {
- TWMessageView *messageView = nil;
- BOOL itemHit = NO;
- if ([sender isKindOfClass:[UIGestureRecognizer class]])
- {
- messageView = (TWMessageView *)((UIGestureRecognizer *)sender).view;
- itemHit = YES;
- }
- else if ([sender isKindOfClass:[TWMessageView class]])
- {
- messageView = (TWMessageView *)sender;
- }
-
- if (messageView && ![messageView isHit])
- {
- messageView.hit = YES;
-
- [UIView animateWithDuration:kTWMessageBarManagerDismissAnimationDuration animations:^{
- [messageView setFrame:CGRectMake(messageView.frame.origin.x, messageView.frame.origin.y - [messageView height], [messageView width], [messageView height])]; // slide back up
- } completion:^(BOOL finished) {
- if (itemHit)
- {
- if ([messageView.callbacks count] > 0)
- {
- id obj = [messageView.callbacks objectAtIndex:0];
- if (![obj isEqual:[NSNull null]])
- {
- ((void (^)())obj)();
- }
- }
- }
-
- self.messageVisible = NO;
- [messageView removeFromSuperview];
-
- //TWS
- prevMessage = nil;
-
- if([self.messageBarQueue count] > 0)
- {
- [self showNextMessage];
- }
- else
- {
- self.messageWindow.hidden = YES;
- self.messageWindow = nil;
- }
- }];
- }
- }
- #pragma mark - Getters
- - (UIView *)messageWindowView
- {
- return [self messageBarViewController].view;
- }
- - (TWMessageBarViewController *)messageBarViewController
- {
- if (!self.messageWindow)
- {
- self.messageWindow = [[TWMessageWindow alloc] init];
- self.messageWindow.frame = [UIApplication sharedApplication].keyWindow.frame;
- self.messageWindow.hidden = NO;
- self.messageWindow.windowLevel = UIWindowLevelNormal;
- self.messageWindow.backgroundColor = [UIColor clearColor];
- self.messageWindow.rootViewController = [[TWMessageBarViewController alloc] init];
- }
- return (TWMessageBarViewController *)self.messageWindow.rootViewController;
- }
- - (NSArray *)accessibleElements
- {
- if (_accessibleElements != nil)
- {
- return _accessibleElements;
- }
- _accessibleElements = [NSArray array];
- return _accessibleElements;
- }
- #pragma mark - Setters
- - (void)setStyleSheet:(NSObject<TWMessageBarStyleSheet> *)styleSheet
- {
- if (styleSheet != nil)
- {
- _styleSheet = styleSheet;
- }
- }
- #pragma mark - TWMessageViewDelegate
- - (NSObject<TWMessageBarStyleSheet> *)styleSheetForMessageView:(TWMessageView *)messageView
- {
- return self.styleSheet;
- }
- #pragma mark - UIAccessibilityContainer
- - (NSInteger)accessibilityElementCount
- {
- return (NSInteger)[self.accessibleElements count];
- }
- - (id)accessibilityElementAtIndex:(NSInteger)index
- {
- return [self.accessibleElements objectAtIndex:(NSUInteger)index];
- }
- - (NSInteger)indexOfAccessibilityElement:(id)element
- {
- return (NSInteger)[self.accessibleElements indexOfObject:element];
- }
- - (BOOL)isAccessibilityElement
- {
- return NO;
- }
- @end
- @implementation TWMessageView
- #pragma mark - Alloc/Init
- + (void)initialize
- {
- if (self == [TWMessageView class])
- {
- // Fonts
- kTWMessageViewTitleFont = [UIFont boldSystemFontOfSize:16.0];
- kTWMessageViewDescriptionFont = [UIFont systemFontOfSize:14.0];
-
- // Colors
- kTWMessageViewTitleColor = [UIColor colorWithWhite:1.0 alpha:1.0];
- kTWMessageViewDescriptionColor = [UIColor colorWithWhite:1.0 alpha:1.0];
- }
- }
- - (id)initWithTitle:(NSString *)title description:(NSString *)description type:(TWMessageBarMessageType)type
- {
- self = [super initWithFrame:CGRectZero];
- if (self)
- {
- self.backgroundColor = [UIColor clearColor];
- self.clipsToBounds = NO;
- self.userInteractionEnabled = YES;
-
- _titleString = title;
- _descriptionString = description;
- _messageType = type;
-
- _hasCallback = NO;
- _hit = NO;
-
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeDeviceOrientation:) name:UIDeviceOrientationDidChangeNotification object:nil];
- }
- return self;
- }
- #pragma mark - Memory Management
- - (void)dealloc
- {
- [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
- }
- #pragma mark - Drawing
- - (void)drawRect:(CGRect)rect
- {
- CGContextRef context = UIGraphicsGetCurrentContext();
-
- if ([self.delegate respondsToSelector:@selector(styleSheetForMessageView:)])
- {
- id<TWMessageBarStyleSheet> styleSheet = [self.delegate styleSheetForMessageView:self];
-
- // background fill
- CGContextSaveGState(context);
- {
- if ([styleSheet respondsToSelector:@selector(backgroundColorForMessageType:)])
- {
- [[styleSheet backgroundColorForMessageType:self.messageType] set];
- CGContextFillRect(context, rect);
- }
- }
- CGContextRestoreGState(context);
-
- // bottom stroke
- CGContextSaveGState(context);
- {
- if ([styleSheet respondsToSelector:@selector(strokeColorForMessageType:)])
- {
- CGContextBeginPath(context);
- CGContextMoveToPoint(context, 0, rect.size.height);
- CGContextSetStrokeColorWithColor(context, [styleSheet strokeColorForMessageType:self.messageType].CGColor);
- CGContextSetLineWidth(context, 1.0);
- CGContextAddLineToPoint(context, rect.size.width, rect.size.height);
- CGContextStrokePath(context);
- }
- }
- CGContextRestoreGState(context);
-
- CGFloat xOffset = kTWMessageViewBarPadding;
- CGFloat yOffset = kTWMessageViewBarPadding + [self statusBarOffset];
-
- // icon
- CGContextSaveGState(context);
- {
- if ([styleSheet respondsToSelector:@selector(iconImageForMessageType:)])
- {
- [[styleSheet iconImageForMessageType:self.messageType] drawInRect:CGRectMake(xOffset, yOffset, kTWMessageViewIconSize, kTWMessageViewIconSize)];
- }
- }
- CGContextRestoreGState(context);
-
- yOffset -= kTWMessageViewTextOffset;
- xOffset += kTWMessageViewIconSize + kTWMessageViewBarPadding;
-
- CGSize titleLabelSize = [self titleSize];
- CGSize descriptionLabelSize = [self descriptionSize];
-
- if (self.titleString && !self.descriptionString)
- {
- yOffset = ceil(rect.size.height * 0.5) - ceil(titleLabelSize.height * 0.5) - kTWMessageViewTextOffset;
- }
-
- if ([[UIDevice currentDevice] tw_isRunningiOS7OrLater])
- {
- NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
- paragraphStyle.alignment = NSTextAlignmentLeft;
-
- [[self titleColor] set];
- [self.titleString drawWithRect:CGRectMake(xOffset, yOffset, titleLabelSize.width, titleLabelSize.height)
- options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine
- attributes:@{NSFontAttributeName:[self titleFont], NSForegroundColorAttributeName:[self titleColor], NSParagraphStyleAttributeName:paragraphStyle}
- context:nil];
-
- yOffset += titleLabelSize.height;
-
- [[self descriptionColor] set];
- [self.descriptionString drawWithRect:CGRectMake(xOffset, yOffset, descriptionLabelSize.width, descriptionLabelSize.height)
- options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine
- attributes:@{NSFontAttributeName:[self descriptionFont], NSForegroundColorAttributeName:[self descriptionColor], NSParagraphStyleAttributeName:paragraphStyle}
- context:nil];
- }
- else
- {
- [[self titleColor] set];
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- [self.titleString drawInRect:CGRectMake(xOffset, yOffset, titleLabelSize.width, titleLabelSize.height) withFont:[self titleFont] lineBreakMode:NSLineBreakByTruncatingTail alignment:NSTextAlignmentLeft];
- #pragma clang diagnostic pop
-
- yOffset += titleLabelSize.height;
-
- [[self descriptionColor] set];
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- [self.descriptionString drawInRect:CGRectMake(xOffset, yOffset, descriptionLabelSize.width, descriptionLabelSize.height) withFont:[self descriptionFont] lineBreakMode:NSLineBreakByTruncatingTail alignment:NSTextAlignmentLeft];
- #pragma clang diagnostic pop
- }
- }
- }
- #pragma mark - Getters
- - (CGFloat)height
- {
- CGSize titleLabelSize = [self titleSize];
- CGSize descriptionLabelSize = [self descriptionSize];
- return MAX((kTWMessageViewBarPadding * 2) + titleLabelSize.height + descriptionLabelSize.height + [self statusBarOffset], (kTWMessageViewBarPadding * 2) + kTWMessageViewIconSize + [self statusBarOffset]);
- }
- - (CGFloat)width
- {
- return [self statusBarFrame].size.width;
- }
- - (CGFloat)statusBarOffset
- {
- return [[UIDevice currentDevice] tw_isRunningiOS7OrLater] ? [self statusBarFrame].size.height : 0.0;
- }
- - (CGFloat)availableWidth
- {
- return ([self width] - (kTWMessageViewBarPadding * 3) - kTWMessageViewIconSize);
- }
- - (CGSize)titleSize
- {
- CGSize boundedSize = CGSizeMake([self availableWidth], CGFLOAT_MAX);
- CGSize titleLabelSize;
-
- if ([[UIDevice currentDevice] tw_isRunningiOS7OrLater])
- {
- NSDictionary *titleStringAttributes = [NSDictionary dictionaryWithObject:[self titleFont] forKey: NSFontAttributeName];
- titleLabelSize = [self.titleString boundingRectWithSize:boundedSize
- options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin
- attributes:titleStringAttributes
- context:nil].size;
- }
- else
- {
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- titleLabelSize = [_titleString sizeWithFont:[self titleFont] constrainedToSize:boundedSize lineBreakMode:NSLineBreakByTruncatingTail];
- #pragma clang diagnostic pop
- }
-
- return CGSizeMake(ceilf(titleLabelSize.width), ceilf(titleLabelSize.height));
- }
- - (CGSize)descriptionSize
- {
- CGSize boundedSize = CGSizeMake([self availableWidth], CGFLOAT_MAX);
- CGSize descriptionLabelSize;
-
- if ([[UIDevice currentDevice] tw_isRunningiOS7OrLater])
- {
- NSDictionary *descriptionStringAttributes = [NSDictionary dictionaryWithObject:[self descriptionFont] forKey: NSFontAttributeName];
- descriptionLabelSize = [self.descriptionString boundingRectWithSize:boundedSize
- options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin
- attributes:descriptionStringAttributes
- context:nil].size;
- }
- else
- {
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- descriptionLabelSize = [_descriptionString sizeWithFont:[self descriptionFont] constrainedToSize:boundedSize lineBreakMode:NSLineBreakByTruncatingTail];
- #pragma clang diagnostic pop
- }
-
- return CGSizeMake(ceilf(descriptionLabelSize.width), ceilf(descriptionLabelSize.height));
- }
- - (CGRect)statusBarFrame
- {
- CGRect windowFrame = NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1 ? [self orientFrame:[UIApplication sharedApplication].keyWindow.frame] : [UIApplication sharedApplication].keyWindow.frame;
- CGRect statusFrame = NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1 ? [self orientFrame:[UIApplication sharedApplication].statusBarFrame] : [UIApplication sharedApplication].statusBarFrame;
- return CGRectMake(windowFrame.origin.x, windowFrame.origin.y, windowFrame.size.width, statusFrame.size.height);
- }
- - (UIFont *)titleFont
- {
- if ([self.delegate respondsToSelector:@selector(styleSheetForMessageView:)])
- {
- id<TWMessageBarStyleSheet> styleSheet = [self.delegate styleSheetForMessageView:self];
- if ([styleSheet respondsToSelector:@selector(titleFontForMessageType:)])
- {
- return [styleSheet titleFontForMessageType:self.messageType];
- }
- }
- return kTWMessageViewTitleFont;
- }
- - (UIFont *)descriptionFont
- {
- if ([self.delegate respondsToSelector:@selector(styleSheetForMessageView:)])
- {
- id<TWMessageBarStyleSheet> styleSheet = [self.delegate styleSheetForMessageView:self];
- if ([styleSheet respondsToSelector:@selector(descriptionFontForMessageType:)])
- {
- return [styleSheet descriptionFontForMessageType:self.messageType];
- }
- }
- return kTWMessageViewDescriptionFont;
- }
- - (UIColor *)titleColor
- {
- if ([self.delegate respondsToSelector:@selector(styleSheetForMessageView:)])
- {
- id<TWMessageBarStyleSheet> styleSheet = [self.delegate styleSheetForMessageView:self];
- if ([styleSheet respondsToSelector:@selector(titleColorForMessageType:)])
- {
- return [styleSheet titleColorForMessageType:self.messageType];
- }
- }
- return kTWMessageViewTitleColor;
- }
- - (UIColor *)descriptionColor
- {
- if ([self.delegate respondsToSelector:@selector(styleSheetForMessageView:)])
- {
- id<TWMessageBarStyleSheet> styleSheet = [self.delegate styleSheetForMessageView:self];
- if ([styleSheet respondsToSelector:@selector(descriptionColorForMessageType:)])
- {
- return [styleSheet descriptionColorForMessageType:self.messageType];
- }
- }
- return kTWMessageViewDescriptionColor;
- }
- #pragma mark - Helpers
- - (CGRect)orientFrame:(CGRect)frame
- {
- return frame;
- }
- #pragma mark - Notifications
- - (void)didChangeDeviceOrientation:(NSNotification *)notification
- {
- self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, [self statusBarFrame].size.width, self.frame.size.height);
- [self setNeedsDisplay];
- }
- @end
- @implementation TWDefaultMessageBarStyleSheet
- #pragma mark - Alloc/Init
- + (void)initialize
- {
- if (self == [TWDefaultMessageBarStyleSheet class])
- {
- // Colors (background)
- kTWDefaultMessageBarStyleSheetErrorBackgroundColor = [UIColor colorWithRed:1.0 green:0.611 blue:0.0 alpha:kTWMessageBarStyleSheetMessageBarAlpha]; // orange
- kTWDefaultMessageBarStyleSheetSuccessBackgroundColor = [UIColor colorWithRed:0.0f green:0.831f blue:0.176f alpha:kTWMessageBarStyleSheetMessageBarAlpha]; // green
- kTWDefaultMessageBarStyleSheetInfoBackgroundColor = [UIColor colorWithRed:0.0 green:0.482 blue:1.0 alpha:kTWMessageBarStyleSheetMessageBarAlpha]; // blue
-
- // Colors (stroke)
- kTWDefaultMessageBarStyleSheetErrorStrokeColor = [UIColor colorWithRed:0.949f green:0.580f blue:0.0f alpha:1.0f]; // orange
- kTWDefaultMessageBarStyleSheetSuccessStrokeColor = [UIColor colorWithRed:0.0f green:0.772f blue:0.164f alpha:1.0f]; // green
- kTWDefaultMessageBarStyleSheetInfoStrokeColor = [UIColor colorWithRed:0.0f green:0.415f blue:0.803f alpha:1.0f]; // blue
- }
- }
- + (TWDefaultMessageBarStyleSheet *)styleSheet
- {
- return [[TWDefaultMessageBarStyleSheet alloc] init];
- }
- #pragma mark - TWMessageBarStyleSheet
- - (nonnull UIColor *)backgroundColorForMessageType:(TWMessageBarMessageType)type
- {
- UIColor *backgroundColor = nil;
- switch (type)
- {
- case TWMessageBarMessageTypeError:
- backgroundColor = kTWDefaultMessageBarStyleSheetErrorBackgroundColor;
- break;
- case TWMessageBarMessageTypeSuccess:
- backgroundColor = kTWDefaultMessageBarStyleSheetSuccessBackgroundColor;
- break;
- case TWMessageBarMessageTypeInfo:
- backgroundColor = kTWDefaultMessageBarStyleSheetInfoBackgroundColor;
- break;
- }
- return backgroundColor;
- }
- - (nonnull UIColor *)strokeColorForMessageType:(TWMessageBarMessageType)type
- {
- UIColor *strokeColor = nil;
- switch (type)
- {
- case TWMessageBarMessageTypeError:
- strokeColor = kTWDefaultMessageBarStyleSheetErrorStrokeColor;
- break;
- case TWMessageBarMessageTypeSuccess:
- strokeColor = kTWDefaultMessageBarStyleSheetSuccessStrokeColor;
- break;
- case TWMessageBarMessageTypeInfo:
- strokeColor = kTWDefaultMessageBarStyleSheetInfoStrokeColor;
- break;
- }
- return strokeColor;
- }
- - (nonnull UIImage *)iconImageForMessageType:(TWMessageBarMessageType)type
- {
- UIImage *iconImage = nil;
- switch (type)
- {
- case TWMessageBarMessageTypeError:
- iconImage = [UIImage imageNamed:kTWMessageBarStyleSheetImageIconError];
- break;
- case TWMessageBarMessageTypeSuccess:
- iconImage = [UIImage imageNamed:kTWMessageBarStyleSheetImageIconSuccess];
- break;
- case TWMessageBarMessageTypeInfo:
- iconImage = [UIImage imageNamed:kTWMessageBarStyleSheetImageIconInfo];
- break;
- }
- return iconImage;
- }
- @end
- @implementation TWMessageWindow
- #pragma mark - Touches
- - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
- {
- UIView *hitView = [super hitTest:point withEvent:event];
-
- /*
- * Pass touches through if they land on the rootViewController's view.
- * Allows notification interaction without blocking the window below.
- */
- if ([hitView isEqual: self.rootViewController.view])
- {
- hitView = nil;
- }
-
- return hitView;
- }
- @end
- @implementation UIDevice (Additions)
- #pragma mark - OS Helpers
- - (BOOL)tw_isRunningiOS7OrLater
- {
- NSString *systemVersion = self.systemVersion;
- NSUInteger systemInt = [systemVersion intValue];
- return systemInt >= kTWMessageViewiOS7Identifier;
- }
- @end
- @implementation TWMessageBarViewController
- - (UIInterfaceOrientationMask)supportedInterfaceOrientations
- {
- return [TWMessageBarManager sharedInstance].managerSupportedOrientationsMask;
- }
- #pragma mark - Setters
- - (void)setStatusBarStyle:(UIStatusBarStyle)statusBarStyle
- {
- _statusBarStyle = statusBarStyle;
-
- if ([[UIDevice currentDevice] tw_isRunningiOS7OrLater])
- {
- [self setNeedsStatusBarAppearanceUpdate];
- }
- }
- - (void)setStatusBarHidden:(BOOL)statusBarHidden
- {
- _statusBarHidden = statusBarHidden;
- if ([[UIDevice currentDevice] tw_isRunningiOS7OrLater])
- {
- [self setNeedsStatusBarAppearanceUpdate];
- }
- }
- #pragma mark - Status Bar
- - (UIStatusBarStyle)preferredStatusBarStyle
- {
- return self.statusBarStyle;
- }
- - (BOOL)prefersStatusBarHidden
- {
- return self.statusBarHidden;
- }
- @end
|