2013-04-08 15:25:00 +04:00
//
// BlockAlertView . m
//
//
# import "BlockAlertView.h"
# import "BlockBackground.h"
2013-04-08 16:17:47 +04:00
# import "BlockUI.h"
2013-04-08 15:25:00 +04:00
@ implementation BlockAlertView
@ synthesize view = _view ;
2013-04-08 16:17:47 +04:00
@ synthesize backgroundImage = _backgroundImage ;
@ synthesize vignetteBackground = _vignetteBackground ;
2013-04-08 15:25:00 +04:00
static UIImage * background = nil ;
2013-04-08 16:17:47 +04:00
static UIImage * backgroundlandscape = nil ;
2013-04-08 15:25:00 +04:00
static UIFont * titleFont = nil ;
static UIFont * messageFont = nil ;
static UIFont * buttonFont = nil ;
# pragma mark - init
+ ( void ) initialize
{
if ( self = = [ BlockAlertView class ] )
{
background = [ UIImage imageNamed : kAlertViewBackground ] ;
background = [ [ background stretchableImageWithLeftCapWidth : 0 topCapHeight : kAlertViewBackgroundCapHeight ] retain ] ;
2013-04-08 16:17:47 +04:00
backgroundlandscape = [ UIImage imageNamed : kAlertViewBackgroundLandscape ] ;
backgroundlandscape = [ [ backgroundlandscape stretchableImageWithLeftCapWidth : 0 topCapHeight : kAlertViewBackgroundCapHeight ] retain ] ;
titleFont = [ kAlertViewTitleFont retain ] ;
messageFont = [ kAlertViewMessageFont retain ] ;
buttonFont = [ kAlertViewButtonFont retain ] ;
2013-04-08 15:25:00 +04:00
}
}
+ ( BlockAlertView * ) alertWithTitle : ( NSString * ) title message : ( NSString * ) message
{
return [ [ [ BlockAlertView alloc ] initWithTitle : title message : message ] autorelease ] ;
}
2013-04-08 16:17:47 +04:00
+ ( void ) showInfoAlertWithTitle : ( NSString * ) title message : ( NSString * ) message
{
BlockAlertView * alert = [ [ BlockAlertView alloc ] initWithTitle : title message : message ] ;
[ alert setCancelButtonWithTitle : NSLocalizedString ( @ "Dismiss" , nil ) block : nil ] ;
[ alert show ] ;
[ alert release ] ;
}
+ ( void ) showErrorAlert : ( NSError * ) error
{
BlockAlertView * alert = [ [ BlockAlertView alloc ] initWithTitle : NSLocalizedString ( @ "Operation Failed" , nil ) message : [ NSString stringWithFormat : NSLocalizedString ( @ "The operation did not complete successfully: %@" , nil ) , error ] ] ;
[ alert setCancelButtonWithTitle : @ "Dismiss" block : nil ] ;
[ alert show ] ;
[ alert release ] ;
}
2013-04-08 15:25:00 +04:00
// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // /
# pragma mark - NSObject
2013-04-08 16:17:47 +04:00
- ( void ) addComponents : ( CGRect ) frame {
if ( _title )
{
CGSize size = [ _title sizeWithFont : titleFont
constrainedToSize : CGSizeMake ( frame . size . width - kAlertViewBorder * 2 , 1000 )
lineBreakMode : NSLineBreakByWordWrapping ] ;
UILabel * labelView = [ [ UILabel alloc ] initWithFrame : CGRectMake ( kAlertViewBorder , _height , frame . size . width - kAlertViewBorder * 2 , size . height ) ] ;
labelView . font = titleFont ;
labelView . numberOfLines = 0 ;
labelView . lineBreakMode = NSLineBreakByWordWrapping ;
labelView . textColor = kAlertViewTitleTextColor ;
labelView . backgroundColor = [ UIColor clearColor ] ;
labelView . textAlignment = NSTextAlignmentCenter ;
labelView . shadowColor = kAlertViewTitleShadowColor ;
labelView . shadowOffset = kAlertViewTitleShadowOffset ;
labelView . text = _title ;
[ _view addSubview : labelView ] ;
[ labelView release ] ;
_height + = size . height + kAlertViewBorder ;
}
if ( _message )
{
CGSize size = [ _message sizeWithFont : messageFont
constrainedToSize : CGSizeMake ( frame . size . width - kAlertViewBorder * 2 , 1000 )
lineBreakMode : NSLineBreakByWordWrapping ] ;
UILabel * labelView = [ [ UILabel alloc ] initWithFrame : CGRectMake ( kAlertViewBorder , _height , frame . size . width - kAlertViewBorder * 2 , size . height ) ] ;
labelView . font = messageFont ;
labelView . numberOfLines = 0 ;
labelView . lineBreakMode = NSLineBreakByWordWrapping ;
labelView . textColor = kAlertViewMessageTextColor ;
labelView . backgroundColor = [ UIColor clearColor ] ;
labelView . textAlignment = NSTextAlignmentCenter ;
labelView . shadowColor = kAlertViewMessageShadowColor ;
labelView . shadowOffset = kAlertViewMessageShadowOffset ;
labelView . text = _message ;
[ _view addSubview : labelView ] ;
[ labelView release ] ;
_height + = size . height + kAlertViewBorder ;
}
}
- ( void ) setupDisplay
{
[ [ _view subviews ] enumerateObjectsUsingBlock : ^ ( id obj , NSUInteger idx , BOOL * stop ) {
[ obj removeFromSuperview ] ;
} ] ;
UIWindow * parentView = [ BlockBackground sharedInstance ] ;
CGRect frame = parentView . bounds ;
frame . origin . x = floorf ( ( frame . size . width - background . size . width ) * 0.5 ) ;
frame . size . width = background . size . width ;
UIInterfaceOrientation orientation = [ [ UIApplication sharedApplication ] statusBarOrientation ] ;
if ( UIInterfaceOrientationIsLandscape ( orientation ) ) {
frame . size . width + = 150 ;
frame . origin . x - = 75 ;
}
_view . frame = frame ;
_height = kAlertViewBorder + 15 ;
if ( NeedsLandscapePhoneTweaks ) {
_height - = 15 ; // landscape phones need to trimmed a bit
}
[ self addComponents : frame ] ;
if ( _shown )
[ self show ] ;
}
2013-04-08 15:25:00 +04:00
- ( id ) initWithTitle : ( NSString * ) title message : ( NSString * ) message
{
2013-04-08 16:17:47 +04:00
self = [ super init ] ;
if ( self )
2013-04-08 15:25:00 +04:00
{
2013-04-08 16:17:47 +04:00
_title = [ title copy ] ;
_message = [ message copy ] ;
_view = [ [ UIView alloc ] init ] ;
_view . autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin ;
2013-04-08 15:25:00 +04:00
_blocks = [ [ NSMutableArray alloc ] init ] ;
2013-04-08 16:17:47 +04:00
[ [ NSNotificationCenter defaultCenter ] addObserver : self
selector : @ selector ( setupDisplay )
name : UIApplicationDidChangeStatusBarOrientationNotification
object : nil ] ;
if ( [ self class ] = = [ BlockAlertView class ] )
[ self setupDisplay ] ;
_vignetteBackground = NO ;
2013-04-08 15:25:00 +04:00
}
return self ;
}
- ( void ) dealloc
{
2013-04-08 16:17:47 +04:00
[ _title release ] ;
[ _message release ] ;
[ _backgroundImage release ] ;
2013-04-08 15:25:00 +04:00
[ _view release ] ;
[ _blocks release ] ;
[ super dealloc ] ;
}
// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // /
# pragma mark - Public
- ( void ) addButtonWithTitle : ( NSString * ) title color : ( NSString * ) color block : ( void ( ^ ) ( ) ) block
{
[ _blocks addObject : [ NSArray arrayWithObjects :
block ? [ [ block copy ] autorelease ] : [ NSNull null ] ,
title ,
color ,
nil ] ] ;
}
- ( void ) addButtonWithTitle : ( NSString * ) title block : ( void ( ^ ) ( ) ) block
{
[ self addButtonWithTitle : title color : @ "gray" block : block ] ;
}
- ( void ) setCancelButtonWithTitle : ( NSString * ) title block : ( void ( ^ ) ( ) ) block
{
[ self addButtonWithTitle : title color : @ "black" block : block ] ;
}
- ( void ) setDestructiveButtonWithTitle : ( NSString * ) title block : ( void ( ^ ) ( ) ) block
{
[ self addButtonWithTitle : title color : @ "red" block : block ] ;
}
- ( void ) show
{
2013-04-08 16:17:47 +04:00
_shown = YES ;
2013-04-08 15:25:00 +04:00
BOOL isSecondButton = NO ;
NSUInteger index = 0 ;
for ( NSUInteger i = 0 ; i < _blocks . count ; i + + )
{
NSArray * block = [ _blocks objectAtIndex : i ] ;
NSString * title = [ block objectAtIndex : 1 ] ;
NSString * color = [ block objectAtIndex : 2 ] ;
UIImage * image = [ UIImage imageNamed : [ NSString stringWithFormat : @ "alert-%@-button.png" , color ] ] ;
image = [ image stretchableImageWithLeftCapWidth : ( int ) ( image . size . width + 1 ) > > 1 topCapHeight : 0 ] ;
2013-04-08 16:17:47 +04:00
CGFloat maxHalfWidth = floorf ( ( _view . bounds . size . width - kAlertViewBorder * 3 ) * 0.5 ) ;
CGFloat width = _view . bounds . size . width - kAlertViewBorder * 2 ;
CGFloat xOffset = kAlertViewBorder ;
2013-04-08 15:25:00 +04:00
if ( isSecondButton )
{
width = maxHalfWidth ;
2013-04-08 16:17:47 +04:00
xOffset = width + kAlertViewBorder * 2 ;
2013-04-08 15:25:00 +04:00
isSecondButton = NO ;
}
else if ( i + 1 < _blocks . count )
{
// In this case there ' s another button .
// Let ' s check if they fit on the same line .
CGSize size = [ title sizeWithFont : buttonFont
minFontSize : 10
actualFontSize : nil
2013-04-08 16:17:47 +04:00
forWidth : _view . bounds . size . width - kAlertViewBorder * 2
2013-04-08 15:25:00 +04:00
lineBreakMode : NSLineBreakByClipping ] ;
2013-04-08 16:17:47 +04:00
if ( size . width < maxHalfWidth - kAlertViewBorder )
2013-04-08 15:25:00 +04:00
{
// It might fit . Check the next Button
NSArray * block2 = [ _blocks objectAtIndex : i + 1 ] ;
NSString * title2 = [ block2 objectAtIndex : 1 ] ;
size = [ title2 sizeWithFont : buttonFont
minFontSize : 10
actualFontSize : nil
2013-04-08 16:17:47 +04:00
forWidth : _view . bounds . size . width - kAlertViewBorder * 2
2013-04-08 15:25:00 +04:00
lineBreakMode : NSLineBreakByClipping ] ;
2013-04-08 16:17:47 +04:00
if ( size . width < maxHalfWidth - kAlertViewBorder )
2013-04-08 15:25:00 +04:00
{
// They ' ll fit !
isSecondButton = YES ; // For the next iteration
width = maxHalfWidth ;
}
}
}
2013-04-08 16:17:47 +04:00
else if ( _blocks . count = = 1 )
{
// In this case this is the ony button . We ' ll size according to the text
CGSize size = [ title sizeWithFont : buttonFont
minFontSize : 10
actualFontSize : nil
forWidth : _view . bounds . size . width - kAlertViewBorder * 2
lineBreakMode : UILineBreakModeClip ] ;
size . width = MAX ( size . width , 80 ) ;
if ( size . width + 2 * kAlertViewBorder < width )
{
width = size . width + 2 * kAlertViewBorder ;
xOffset = floorf ( ( _view . bounds . size . width - width ) * 0.5 ) ;
}
}
2013-04-08 15:25:00 +04:00
UIButton * button = [ UIButton buttonWithType : UIButtonTypeCustom ] ;
2013-04-08 16:17:47 +04:00
button . frame = CGRectMake ( xOffset , _height , width , kAlertButtonHeight ) ;
2013-04-08 15:25:00 +04:00
button . titleLabel . font = buttonFont ;
2013-04-08 16:17:47 +04:00
if ( IOS_LESS _THAN _6 ) {
# pragma clan diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
button . titleLabel . minimumFontSize = 10 ;
# pragma clan diagnostic pop
}
else {
button . titleLabel . adjustsFontSizeToFitWidth = YES ;
button . titleLabel . adjustsLetterSpacingToFitWidth = YES ;
button . titleLabel . minimumScaleFactor = 0.1 ;
}
2013-04-08 15:25:00 +04:00
button . titleLabel . textAlignment = NSTextAlignmentCenter ;
2013-04-08 16:17:47 +04:00
button . titleLabel . shadowOffset = kAlertViewButtonShadowOffset ;
2013-04-08 15:25:00 +04:00
button . backgroundColor = [ UIColor clearColor ] ;
button . tag = i + 1 ;
[ button setBackgroundImage : image forState : UIControlStateNormal ] ;
2013-04-08 16:17:47 +04:00
[ button setTitleColor : kAlertViewButtonTextColor forState : UIControlStateNormal ] ;
[ button setTitleShadowColor : kAlertViewButtonShadowColor forState : UIControlStateNormal ] ;
2013-04-08 15:25:00 +04:00
[ button setTitle : title forState : UIControlStateNormal ] ;
button . accessibilityLabel = title ;
[ button addTarget : self action : @ selector ( buttonClicked : ) forControlEvents : UIControlEventTouchUpInside ] ;
[ _view addSubview : button ] ;
if ( ! isSecondButton )
2013-04-08 16:17:47 +04:00
_height + = kAlertButtonHeight + kAlertViewBorder ;
2013-04-08 15:25:00 +04:00
index + + ;
}
2013-04-08 16:17:47 +04:00
_height + = 10 ; // Margin for the shadow
if ( _height < background . size . height )
{
CGFloat offset = background . size . height - _height ;
_height = background . size . height ;
CGRect frame ;
for ( NSUInteger i = 0 ; i < _blocks . count ; i + + )
{
UIButton * btn = ( UIButton * ) [ _view viewWithTag : i + 1 ] ;
frame = btn . frame ;
frame . origin . y + = offset ;
btn . frame = frame ;
}
}
2013-04-08 15:25:00 +04:00
CGRect frame = _view . frame ;
frame . origin . y = - _height ;
frame . size . height = _height ;
_view . frame = frame ;
UIImageView * modalBackground = [ [ UIImageView alloc ] initWithFrame : _view . bounds ] ;
2013-04-08 16:17:47 +04:00
if ( UIInterfaceOrientationIsLandscape ( [ [ UIApplication sharedApplication ] statusBarOrientation ] ) )
modalBackground . image = backgroundlandscape ;
else
modalBackground . image = background ;
2013-04-08 15:25:00 +04:00
modalBackground . contentMode = UIViewContentModeScaleToFill ;
2013-04-08 16:17:47 +04:00
modalBackground . autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight ;
2013-04-08 15:25:00 +04:00
[ _view insertSubview : modalBackground atIndex : 0 ] ;
[ modalBackground release ] ;
2013-04-08 16:17:47 +04:00
if ( _backgroundImage )
{
[ BlockBackground sharedInstance ] . backgroundImage = _backgroundImage ;
[ _backgroundImage release ] ;
_backgroundImage = nil ;
}
[ BlockBackground sharedInstance ] . vignetteBackground = _vignetteBackground ;
2013-04-08 15:25:00 +04:00
[ [ BlockBackground sharedInstance ] addToMainWindow : _view ] ;
__block CGPoint center = _view . center ;
2013-04-08 16:17:47 +04:00
center . y = floorf ( [ BlockBackground sharedInstance ] . bounds . size . height * 0.5 ) + kAlertViewBounce ;
_cancelBounce = NO ;
2013-04-08 15:25:00 +04:00
[ UIView animateWithDuration : 0.4
delay : 0.0
2013-04-08 16:17:47 +04:00
options : UIViewAnimationCurveEaseOut
2013-04-08 15:25:00 +04:00
animations : ^ {
[ BlockBackground sharedInstance ] . alpha = 1.0 f ;
_view . center = center ;
}
completion : ^ ( BOOL finished ) {
2013-04-08 16:17:47 +04:00
if ( _cancelBounce ) return ;
2013-04-08 15:25:00 +04:00
[ UIView animateWithDuration : 0.1
delay : 0.0
options : 0
animations : ^ {
2013-04-08 16:17:47 +04:00
center . y - = kAlertViewBounce ;
2013-04-08 15:25:00 +04:00
_view . center = center ;
}
2013-04-08 16:17:47 +04:00
completion : ^ ( BOOL finished ) {
[ [ NSNotificationCenter defaultCenter ] postNotificationName : @ "AlertViewFinishedAnimations" object : nil ] ;
} ] ;
2013-04-08 15:25:00 +04:00
} ] ;
[ self retain ] ;
}
- ( void ) dismissWithClickedButtonIndex : ( NSInteger ) buttonIndex animated : ( BOOL ) animated
{
2013-04-08 16:17:47 +04:00
_shown = NO ;
[ [ NSNotificationCenter defaultCenter ] removeObserver : self ] ;
2013-04-08 15:25:00 +04:00
if ( buttonIndex >= 0 && buttonIndex < [ _blocks count ] )
{
id obj = [ [ _blocks objectAtIndex : buttonIndex ] objectAtIndex : 0 ] ;
if ( ! [ obj isEqual : [ NSNull null ] ] )
{
( ( void ( ^ ) ( ) ) obj ) ( ) ;
}
}
if ( animated )
{
[ UIView animateWithDuration : 0.1
delay : 0.0
options : 0
animations : ^ {
CGPoint center = _view . center ;
center . y + = 20 ;
_view . center = center ;
}
completion : ^ ( BOOL finished ) {
[ UIView animateWithDuration : 0.4
delay : 0.0
2013-04-08 16:17:47 +04:00
options : UIViewAnimationCurveEaseIn
2013-04-08 15:25:00 +04:00
animations : ^ {
CGRect frame = _view . frame ;
frame . origin . y = - frame . size . height ;
_view . frame = frame ;
[ [ BlockBackground sharedInstance ] reduceAlphaIfEmpty ] ;
}
completion : ^ ( BOOL finished ) {
[ [ BlockBackground sharedInstance ] removeView : _view ] ;
[ _view release ] ; _view = nil ;
[ self autorelease ] ;
} ] ;
} ] ;
}
else
{
[ [ BlockBackground sharedInstance ] removeView : _view ] ;
[ _view release ] ; _view = nil ;
[ self autorelease ] ;
}
}
// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // /
# pragma mark - Action
- ( void ) buttonClicked : ( id ) sender
{
/ * Run the button ' s block * /
int buttonIndex = [ sender tag ] - 1 ;
[ self dismissWithClickedButtonIndex : buttonIndex animated : YES ] ;
}
@ end