Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
475
third_party/FreeRDP/client/iOS/Views/BlockAlertView.m
vendored
Normal file
475
third_party/FreeRDP/client/iOS/Views/BlockAlertView.m
vendored
Normal file
@@ -0,0 +1,475 @@
|
||||
//
|
||||
// BlockAlertView.m
|
||||
//
|
||||
//
|
||||
|
||||
#import "BlockAlertView.h"
|
||||
#import "BlockBackground.h"
|
||||
#import "BlockUI.h"
|
||||
|
||||
@implementation BlockAlertView
|
||||
|
||||
@synthesize view = _view;
|
||||
@synthesize backgroundImage = _backgroundImage;
|
||||
@synthesize vignetteBackground = _vignetteBackground;
|
||||
|
||||
static UIImage *background = nil;
|
||||
static UIImage *backgroundlandscape = nil;
|
||||
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];
|
||||
|
||||
backgroundlandscape = [UIImage imageNamed:kAlertViewBackgroundLandscape];
|
||||
backgroundlandscape = [[backgroundlandscape
|
||||
stretchableImageWithLeftCapWidth:0
|
||||
topCapHeight:kAlertViewBackgroundCapHeight] retain];
|
||||
|
||||
titleFont = [kAlertViewTitleFont retain];
|
||||
messageFont = [kAlertViewMessageFont retain];
|
||||
buttonFont = [kAlertViewButtonFont retain];
|
||||
}
|
||||
}
|
||||
|
||||
+ (BlockAlertView *)alertWithTitle:(NSString *)title message:(NSString *)message
|
||||
{
|
||||
return [[[BlockAlertView alloc] initWithTitle:title message:message] autorelease];
|
||||
}
|
||||
|
||||
+ (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];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark - NSObject
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
- (id)initWithTitle:(NSString *)title message:(NSString *)message
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_title = [title copy];
|
||||
_message = [message copy];
|
||||
|
||||
_view = [[UIView alloc] init];
|
||||
|
||||
_view.autoresizingMask =
|
||||
UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin |
|
||||
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
|
||||
|
||||
_blocks = [[NSMutableArray alloc] init];
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(setupDisplay)
|
||||
name:UIApplicationDidChangeStatusBarOrientationNotification
|
||||
object:nil];
|
||||
|
||||
if ([self class] == [BlockAlertView class])
|
||||
[self setupDisplay];
|
||||
|
||||
_vignetteBackground = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_title release];
|
||||
[_message release];
|
||||
[_backgroundImage release];
|
||||
[_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
|
||||
{
|
||||
_shown = YES;
|
||||
|
||||
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];
|
||||
|
||||
CGFloat maxHalfWidth = floorf((_view.bounds.size.width - kAlertViewBorder * 3) * 0.5);
|
||||
CGFloat width = _view.bounds.size.width - kAlertViewBorder * 2;
|
||||
CGFloat xOffset = kAlertViewBorder;
|
||||
if (isSecondButton)
|
||||
{
|
||||
width = maxHalfWidth;
|
||||
xOffset = width + kAlertViewBorder * 2;
|
||||
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
|
||||
forWidth:_view.bounds.size.width - kAlertViewBorder * 2
|
||||
lineBreakMode:NSLineBreakByClipping];
|
||||
|
||||
if (size.width < maxHalfWidth - kAlertViewBorder)
|
||||
{
|
||||
// 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
|
||||
forWidth:_view.bounds.size.width - kAlertViewBorder * 2
|
||||
lineBreakMode:NSLineBreakByClipping];
|
||||
|
||||
if (size.width < maxHalfWidth - kAlertViewBorder)
|
||||
{
|
||||
// They'll fit!
|
||||
isSecondButton = YES; // For the next iteration
|
||||
width = maxHalfWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_blocks.count == 1)
|
||||
{
|
||||
// In this case this is the only 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);
|
||||
}
|
||||
}
|
||||
|
||||
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
button.frame = CGRectMake(xOffset, _height, width, kAlertButtonHeight);
|
||||
button.titleLabel.font = buttonFont;
|
||||
if (IOS_LESS_THAN_6)
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
button.titleLabel.minimumFontSize = 10;
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
else
|
||||
{
|
||||
button.titleLabel.adjustsFontSizeToFitWidth = YES;
|
||||
button.titleLabel.adjustsLetterSpacingToFitWidth = YES;
|
||||
button.titleLabel.minimumScaleFactor = 0.1;
|
||||
}
|
||||
button.titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
button.titleLabel.shadowOffset = kAlertViewButtonShadowOffset;
|
||||
button.backgroundColor = [UIColor clearColor];
|
||||
button.tag = i + 1;
|
||||
|
||||
[button setBackgroundImage:image forState:UIControlStateNormal];
|
||||
[button setTitleColor:kAlertViewButtonTextColor forState:UIControlStateNormal];
|
||||
[button setTitleShadowColor:kAlertViewButtonShadowColor forState:UIControlStateNormal];
|
||||
[button setTitle:title forState:UIControlStateNormal];
|
||||
button.accessibilityLabel = title;
|
||||
|
||||
[button addTarget:self
|
||||
action:@selector(buttonClicked:)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
[_view addSubview:button];
|
||||
|
||||
if (!isSecondButton)
|
||||
_height += kAlertButtonHeight + kAlertViewBorder;
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
}
|
||||
|
||||
CGRect frame = _view.frame;
|
||||
frame.origin.y = -_height;
|
||||
frame.size.height = _height;
|
||||
_view.frame = frame;
|
||||
|
||||
UIImageView *modalBackground = [[UIImageView alloc] initWithFrame:_view.bounds];
|
||||
|
||||
if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]))
|
||||
modalBackground.image = backgroundlandscape;
|
||||
else
|
||||
modalBackground.image = background;
|
||||
|
||||
modalBackground.contentMode = UIViewContentModeScaleToFill;
|
||||
modalBackground.autoresizingMask =
|
||||
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[_view insertSubview:modalBackground atIndex:0];
|
||||
[modalBackground release];
|
||||
|
||||
if (_backgroundImage)
|
||||
{
|
||||
[BlockBackground sharedInstance].backgroundImage = _backgroundImage;
|
||||
[_backgroundImage release];
|
||||
_backgroundImage = nil;
|
||||
}
|
||||
|
||||
[BlockBackground sharedInstance].vignetteBackground = _vignetteBackground;
|
||||
[[BlockBackground sharedInstance] addToMainWindow:_view];
|
||||
|
||||
__block CGPoint center = _view.center;
|
||||
center.y = floorf([BlockBackground sharedInstance].bounds.size.height * 0.5) + kAlertViewBounce;
|
||||
|
||||
_cancelBounce = NO;
|
||||
|
||||
[UIView animateWithDuration:0.4
|
||||
delay:0.0
|
||||
options:UIViewAnimationCurveEaseOut
|
||||
animations:^{
|
||||
[BlockBackground sharedInstance].alpha = 1.0f;
|
||||
_view.center = center;
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
if (_cancelBounce)
|
||||
return;
|
||||
|
||||
[UIView animateWithDuration:0.1
|
||||
delay:0.0
|
||||
options:0
|
||||
animations:^{
|
||||
center.y -= kAlertViewBounce;
|
||||
_view.center = center;
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:@"AlertViewFinishedAnimations"
|
||||
object:nil];
|
||||
}];
|
||||
}];
|
||||
|
||||
[self retain];
|
||||
}
|
||||
|
||||
- (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
|
||||
{
|
||||
_shown = NO;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
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
|
||||
options:UIViewAnimationCurveEaseIn
|
||||
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
|
||||
Reference in New Issue
Block a user