Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
40
third_party/FreeRDP/client/iOS/Additions/OrderedDictionary.h
vendored
Normal file
40
third_party/FreeRDP/client/iOS/Additions/OrderedDictionary.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// OrderedDictionary.h
|
||||
// OrderedDictionary
|
||||
//
|
||||
// Modified version (Added indexForKey/Value functions)
|
||||
//
|
||||
// Created by Matt Gallagher on 19/12/08.
|
||||
// Copyright 2008 Matt Gallagher. All rights reserved.
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software. Permission is granted to anyone to
|
||||
// use this software for any purpose, including commercial applications, and to
|
||||
// alter it and redistribute it freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface OrderedDictionary : NSMutableDictionary
|
||||
{
|
||||
NSMutableDictionary *dictionary;
|
||||
NSMutableArray *array;
|
||||
}
|
||||
|
||||
- (void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex;
|
||||
- (id)keyAtIndex:(NSUInteger)anIndex;
|
||||
- (NSUInteger)indexForValue:(id)value;
|
||||
- (NSUInteger)indexForKey:(id)key;
|
||||
- (NSEnumerator *)reverseKeyEnumerator;
|
||||
|
||||
@end
|
||||
167
third_party/FreeRDP/client/iOS/Additions/OrderedDictionary.m
vendored
Normal file
167
third_party/FreeRDP/client/iOS/Additions/OrderedDictionary.m
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// OrderedDictionary.m
|
||||
// OrderedDictionary
|
||||
//
|
||||
// Modified version (Added indexForKey/Value functions)
|
||||
//
|
||||
// Created by Matt Gallagher on 19/12/08.
|
||||
// Copyright 2008 Matt Gallagher. All rights reserved.
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software. Permission is granted to anyone to
|
||||
// use this software for any purpose, including commercial applications, and to
|
||||
// alter it and redistribute it freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
|
||||
#import "OrderedDictionary.h"
|
||||
|
||||
NSString *DescriptionForObject(NSObject *object, id locale, NSUInteger indent)
|
||||
{
|
||||
NSString *objectString;
|
||||
if ([object isKindOfClass:[NSString class]])
|
||||
{
|
||||
objectString = (NSString *)[[object retain] autorelease];
|
||||
}
|
||||
else if ([object respondsToSelector:@selector(descriptionWithLocale:indent:)])
|
||||
{
|
||||
objectString = [(NSDictionary *)object descriptionWithLocale:locale indent:indent];
|
||||
}
|
||||
else if ([object respondsToSelector:@selector(descriptionWithLocale:)])
|
||||
{
|
||||
objectString = [(NSSet *)object descriptionWithLocale:locale];
|
||||
}
|
||||
else
|
||||
{
|
||||
objectString = [object description];
|
||||
}
|
||||
return objectString;
|
||||
}
|
||||
|
||||
@implementation OrderedDictionary
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithCapacity:0];
|
||||
}
|
||||
|
||||
- (id)initWithCapacity:(NSUInteger)capacity
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
dictionary = [[NSMutableDictionary alloc] initWithCapacity:capacity];
|
||||
array = [[NSMutableArray alloc] initWithCapacity:capacity];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[dictionary release];
|
||||
[array release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
return [self mutableCopy];
|
||||
}
|
||||
|
||||
- (void)setObject:(id)anObject forKey:(id)aKey
|
||||
{
|
||||
if (![dictionary objectForKey:aKey])
|
||||
{
|
||||
[array addObject:aKey];
|
||||
}
|
||||
[dictionary setObject:anObject forKey:aKey];
|
||||
}
|
||||
|
||||
- (void)removeObjectForKey:(id)aKey
|
||||
{
|
||||
[dictionary removeObjectForKey:aKey];
|
||||
[array removeObject:aKey];
|
||||
}
|
||||
|
||||
- (NSUInteger)count
|
||||
{
|
||||
return [dictionary count];
|
||||
}
|
||||
|
||||
- (id)objectForKey:(id)aKey
|
||||
{
|
||||
return [dictionary objectForKey:aKey];
|
||||
}
|
||||
|
||||
- (NSEnumerator *)keyEnumerator
|
||||
{
|
||||
return [array objectEnumerator];
|
||||
}
|
||||
|
||||
- (NSEnumerator *)reverseKeyEnumerator
|
||||
{
|
||||
return [array reverseObjectEnumerator];
|
||||
}
|
||||
|
||||
- (void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex
|
||||
{
|
||||
if ([dictionary objectForKey:aKey])
|
||||
{
|
||||
[self removeObjectForKey:aKey];
|
||||
}
|
||||
[array insertObject:aKey atIndex:anIndex];
|
||||
[dictionary setObject:anObject forKey:aKey];
|
||||
}
|
||||
|
||||
- (id)keyAtIndex:(NSUInteger)anIndex
|
||||
{
|
||||
return [array objectAtIndex:anIndex];
|
||||
}
|
||||
|
||||
- (NSUInteger)indexForKey:(id)key
|
||||
{
|
||||
return [array indexOfObject:key];
|
||||
}
|
||||
|
||||
- (NSUInteger)indexForValue:(id)value
|
||||
{
|
||||
NSArray *keys = [self allKeysForObject:value];
|
||||
if ([keys count] > 0)
|
||||
{
|
||||
return [self indexForKey:[keys objectAtIndex:0]];
|
||||
}
|
||||
|
||||
return NSNotFound;
|
||||
}
|
||||
|
||||
- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level
|
||||
{
|
||||
NSMutableString *indentString = [NSMutableString string];
|
||||
NSUInteger count = level;
|
||||
for (NSUInteger i = 0; i < count; i++)
|
||||
{
|
||||
[indentString appendFormat:@" "];
|
||||
}
|
||||
|
||||
NSMutableString *description = [NSMutableString string];
|
||||
[description appendFormat:@"%@{\n", indentString];
|
||||
for (NSObject *key in self)
|
||||
{
|
||||
[description appendFormat:@"%@ %@ = %@;\n", indentString,
|
||||
DescriptionForObject(key, locale, level),
|
||||
DescriptionForObject([self objectForKey:key], locale, level)];
|
||||
}
|
||||
[description appendFormat:@"%@}\n", indentString];
|
||||
return description;
|
||||
}
|
||||
|
||||
@end
|
||||
34
third_party/FreeRDP/client/iOS/Additions/TSXAdditions.h
vendored
Normal file
34
third_party/FreeRDP/client/iOS/Additions/TSXAdditions.h
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Additions to Cocoa touch classes
|
||||
|
||||
Copyright 2013 Thincast Technologies GmbH, Authors: Dorian Johnson, Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSObject (TSXAdditions)
|
||||
- (void)setValuesForKeyPathsWithDictionary:(NSDictionary *)keyedValues;
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
@interface NSString (TSXAdditions)
|
||||
+ (NSString *)stringWithUUID;
|
||||
- (NSData *)dataFromHexString;
|
||||
+ (NSString *)hexStringFromData:(const unsigned char *)data
|
||||
ofSize:(unsigned int)size
|
||||
withSeparator:(NSString *)sep
|
||||
afterNthChar:(int)sepnth;
|
||||
@end
|
||||
|
||||
@interface NSDictionary (TSXAdditions)
|
||||
- (id)mutableDeepCopy;
|
||||
@end
|
||||
|
||||
@interface NSData (TSXAdditions)
|
||||
- (NSString *)hexadecimalString;
|
||||
- (NSString *)base64EncodedString;
|
||||
@end
|
||||
239
third_party/FreeRDP/client/iOS/Additions/TSXAdditions.m
vendored
Normal file
239
third_party/FreeRDP/client/iOS/Additions/TSXAdditions.m
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
Additions to Cocoa touch classes
|
||||
|
||||
Copyright 2013 Thincast Technologies GmbH, Authors: Dorian Johnson, Martin Fleisz
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file, You can obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#import "TSXAdditions.h"
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
@implementation NSObject (TSXAdditions)
|
||||
|
||||
- (void)setValuesForKeyPathsWithDictionary:(NSDictionary *)keyedValues
|
||||
{
|
||||
for (id keyPath in keyedValues)
|
||||
[self setValue:[keyedValues objectForKey:keyPath] forKeyPath:keyPath];
|
||||
}
|
||||
|
||||
- mutableDeepCopy
|
||||
{
|
||||
if ([self respondsToSelector:@selector(mutableCopyWithZone:)])
|
||||
return [self mutableCopy];
|
||||
else if ([self respondsToSelector:@selector(copyWithZone:)])
|
||||
return [self copy];
|
||||
else
|
||||
return [self retain];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation NSString (TSXAdditions)
|
||||
|
||||
#pragma mark Creation routines
|
||||
+ (NSString *)stringWithUUID
|
||||
{
|
||||
CFUUIDRef uuidObj = CFUUIDCreate(nil);
|
||||
NSString *uuidString = (NSString *)CFUUIDCreateString(nil, uuidObj);
|
||||
CFRelease(uuidObj);
|
||||
return [uuidString autorelease];
|
||||
}
|
||||
|
||||
/* Code from
|
||||
* http://code.google.com/p/google-toolbox-for-mac/source/browse/trunk/Foundation/GTMNSData%2BHex.m?r=344
|
||||
*/
|
||||
- (NSData *)dataFromHexString
|
||||
{
|
||||
NSData *hexData = [self dataUsingEncoding:NSASCIIStringEncoding];
|
||||
const char *hexBuf = [hexData bytes];
|
||||
NSUInteger hexLen = [hexData length];
|
||||
|
||||
// This indicates an error converting to ASCII.
|
||||
if (!hexData)
|
||||
return nil;
|
||||
|
||||
if ((hexLen % 2) != 0)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableData *binaryData = [NSMutableData dataWithLength:(hexLen / 2)];
|
||||
unsigned char *binaryPtr = [binaryData mutableBytes];
|
||||
unsigned char value = 0;
|
||||
for (NSUInteger i = 0; i < hexLen; i++)
|
||||
{
|
||||
char c = hexBuf[i];
|
||||
|
||||
if (!isxdigit(c))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (isdigit(c))
|
||||
{
|
||||
value += c - '0';
|
||||
}
|
||||
else if (islower(c))
|
||||
{
|
||||
value += 10 + c - 'a';
|
||||
}
|
||||
else
|
||||
{
|
||||
value += 10 + c - 'A';
|
||||
}
|
||||
|
||||
if (i & 1)
|
||||
{
|
||||
*binaryPtr++ = value;
|
||||
value = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
value <<= 4;
|
||||
}
|
||||
}
|
||||
|
||||
return [NSData dataWithData:binaryData];
|
||||
}
|
||||
|
||||
+ (NSString *)hexStringFromData:(const unsigned char *)data
|
||||
ofSize:(unsigned int)size
|
||||
withSeparator:(NSString *)sep
|
||||
afterNthChar:(int)sepnth
|
||||
{
|
||||
NSMutableString *result;
|
||||
NSString *immutableResult;
|
||||
|
||||
result = [[NSMutableString alloc] init];
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (i && sep && sepnth && i % sepnth == 0)
|
||||
[result appendString:sep];
|
||||
[result appendFormat:@"%02X", data[i]];
|
||||
}
|
||||
|
||||
immutableResult = [NSString stringWithString:result];
|
||||
[result release];
|
||||
return immutableResult;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark Mutable deep copy for dictionary, array and set
|
||||
|
||||
@implementation NSDictionary (TSXAdditions)
|
||||
|
||||
- mutableDeepCopy
|
||||
{
|
||||
NSMutableDictionary *newDictionary = [[NSMutableDictionary alloc] init];
|
||||
NSEnumerator *enumerator = [self keyEnumerator];
|
||||
id key;
|
||||
while ((key = [enumerator nextObject]))
|
||||
{
|
||||
id obj = [[self objectForKey:key] mutableDeepCopy];
|
||||
[newDictionary setObject:obj forKey:key];
|
||||
[obj release];
|
||||
}
|
||||
return newDictionary;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSArray (TSXAdditions)
|
||||
|
||||
- mutableDeepCopy
|
||||
{
|
||||
NSMutableArray *newArray = [[NSMutableArray alloc] init];
|
||||
NSEnumerator *enumerator = [self objectEnumerator];
|
||||
id obj;
|
||||
while ((obj = [enumerator nextObject]))
|
||||
{
|
||||
obj = [obj mutableDeepCopy];
|
||||
[newArray addObject:obj];
|
||||
[obj release];
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSSet (TSXAdditions)
|
||||
|
||||
- mutableDeepCopy
|
||||
{
|
||||
NSMutableSet *newSet = [[NSMutableSet alloc] init];
|
||||
NSEnumerator *enumerator = [self objectEnumerator];
|
||||
id obj;
|
||||
while ((obj = [enumerator nextObject]))
|
||||
{
|
||||
obj = [obj mutableDeepCopy];
|
||||
[newSet addObject:obj];
|
||||
[obj release];
|
||||
}
|
||||
return newSet;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/* Code from
|
||||
* http://stackoverflow.com/questions/1305225/best-way-to-serialize-a-nsdata-into-an-hexadeximal-string
|
||||
*/
|
||||
@implementation NSData (TSXAdditions)
|
||||
|
||||
#pragma mark - String Conversion
|
||||
- (NSString *)hexadecimalString
|
||||
{
|
||||
/* Returns hexadecimal string of NSData. Empty string if data is empty. */
|
||||
|
||||
const unsigned char *dataBuffer = (const unsigned char *)[self bytes];
|
||||
|
||||
if (!dataBuffer)
|
||||
return [NSString string];
|
||||
|
||||
NSUInteger dataLength = [self length];
|
||||
NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];
|
||||
|
||||
for (int i = 0; i < dataLength; ++i)
|
||||
[hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]];
|
||||
|
||||
return [NSString stringWithString:hexString];
|
||||
}
|
||||
|
||||
/* Code from http://cocoawithlove.com/2009/06/base64-encoding-options-on-mac-and.html */
|
||||
- (NSString *)base64EncodedString
|
||||
{
|
||||
// Construct an OpenSSL context
|
||||
BIO *context = BIO_new(BIO_s_mem());
|
||||
|
||||
// Tell the context to encode base64
|
||||
BIO *command = BIO_new(BIO_f_base64());
|
||||
context = BIO_push(command, context);
|
||||
BIO_set_flags(context, BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
// Encode all the data
|
||||
ERR_clear_error();
|
||||
BIO_write(context, [self bytes], [self length]);
|
||||
(void)BIO_flush(context);
|
||||
|
||||
// Get the data out of the context
|
||||
char *outputBuffer;
|
||||
long outputLength = BIO_get_mem_data(context, &outputBuffer);
|
||||
NSString *encodedString = [[NSString alloc] initWithBytes:outputBuffer
|
||||
length:outputLength
|
||||
encoding:NSASCIIStringEncoding];
|
||||
|
||||
BIO_free_all(context);
|
||||
|
||||
return encodedString;
|
||||
}
|
||||
|
||||
@end
|
||||
60
third_party/FreeRDP/client/iOS/Additions/Toast+UIView.h
vendored
Normal file
60
third_party/FreeRDP/client/iOS/Additions/Toast+UIView.h
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/***************************************************************************
|
||||
|
||||
Toast+UIView.h
|
||||
Toast
|
||||
Version 0.1
|
||||
|
||||
Copyright (c) 2011 Charles Scalesse.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIView (Toast)
|
||||
|
||||
#define ToastDurationLong 5.0
|
||||
#define ToastDurationNormal 3.0
|
||||
#define ToastDurationShort 1.0
|
||||
|
||||
// each makeToast method creates a view and displays it as toast
|
||||
- (void)makeToast:(NSString *)message;
|
||||
- (void)makeToast:(NSString *)message duration:(float)interval position:(id)point;
|
||||
- (void)makeToast:(NSString *)message
|
||||
duration:(float)interval
|
||||
position:(id)point
|
||||
title:(NSString *)title;
|
||||
- (void)makeToast:(NSString *)message
|
||||
duration:(float)interval
|
||||
position:(id)point
|
||||
title:(NSString *)title
|
||||
image:(UIImage *)image;
|
||||
- (void)makeToast:(NSString *)message
|
||||
duration:(float)interval
|
||||
position:(id)point
|
||||
image:(UIImage *)image;
|
||||
|
||||
// the showToast method displays an existing view as toast
|
||||
- (void)showToast:(UIView *)toast;
|
||||
- (void)showToast:(UIView *)toast duration:(float)interval position:(id)point;
|
||||
|
||||
@end
|
||||
367
third_party/FreeRDP/client/iOS/Additions/Toast+UIView.m
vendored
Normal file
367
third_party/FreeRDP/client/iOS/Additions/Toast+UIView.m
vendored
Normal file
@@ -0,0 +1,367 @@
|
||||
/***************************************************************************
|
||||
|
||||
Toast+UIView.h
|
||||
Toast
|
||||
Version 0.1
|
||||
|
||||
Copyright (c) 2011 Charles Scalesse.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#import "Toast+UIView.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#define kMaxWidth 0.8
|
||||
#define kMaxHeight 0.8
|
||||
|
||||
#define kHorizontalPadding 10.0
|
||||
#define kVerticalPadding 10.0
|
||||
#define kCornerRadius 10.0
|
||||
#define kOpacity 0.8
|
||||
#define kFontSize 16.0
|
||||
#define kMaxTitleLines 999
|
||||
#define kMaxMessageLines 999
|
||||
|
||||
#define kFadeDuration 0.2
|
||||
|
||||
#define kDefaultLength 3
|
||||
#define kDefaultPosition @"bottom"
|
||||
|
||||
#define kImageWidth 80.0
|
||||
#define kImageHeight 80.0
|
||||
|
||||
static NSString *kDurationKey = @"duration";
|
||||
|
||||
@interface UIView (ToastPrivate)
|
||||
|
||||
- (CGPoint)getPositionFor:(id)position toast:(UIView *)toast;
|
||||
- (UIView *)makeViewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIView (Toast)
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Toast Methods
|
||||
|
||||
- (void)makeToast:(NSString *)message
|
||||
{
|
||||
[self makeToast:message duration:kDefaultLength position:kDefaultPosition];
|
||||
}
|
||||
|
||||
- (void)makeToast:(NSString *)message duration:(float)interval position:(id)point
|
||||
{
|
||||
UIView *toast = [self makeViewForMessage:message title:nil image:nil];
|
||||
[self showToast:toast duration:interval position:point];
|
||||
}
|
||||
|
||||
- (void)makeToast:(NSString *)message
|
||||
duration:(float)interval
|
||||
position:(id)point
|
||||
title:(NSString *)title
|
||||
{
|
||||
UIView *toast = [self makeViewForMessage:message title:title image:nil];
|
||||
[self showToast:toast duration:interval position:point];
|
||||
}
|
||||
|
||||
- (void)makeToast:(NSString *)message
|
||||
duration:(float)interval
|
||||
position:(id)point
|
||||
image:(UIImage *)image
|
||||
{
|
||||
UIView *toast = [self makeViewForMessage:message title:nil image:image];
|
||||
[self showToast:toast duration:interval position:point];
|
||||
}
|
||||
|
||||
- (void)makeToast:(NSString *)message
|
||||
duration:(float)interval
|
||||
position:(id)point
|
||||
title:(NSString *)title
|
||||
image:(UIImage *)image
|
||||
{
|
||||
UIView *toast = [self makeViewForMessage:message title:title image:image];
|
||||
[self showToast:toast duration:interval position:point];
|
||||
}
|
||||
|
||||
- (void)showToast:(UIView *)toast
|
||||
{
|
||||
[self showToast:toast duration:kDefaultLength position:kDefaultPosition];
|
||||
}
|
||||
|
||||
- (void)showToast:(UIView *)toast duration:(float)interval position:(id)point
|
||||
{
|
||||
|
||||
/****************************************************
|
||||
* *
|
||||
* Displays a view for a given duration & position. *
|
||||
* *
|
||||
****************************************************/
|
||||
|
||||
CGPoint toastPoint = [self getPositionFor:point toast:toast];
|
||||
|
||||
// use an associative reference to associate the toast view with the display interval
|
||||
objc_setAssociatedObject(toast, &kDurationKey, [NSNumber numberWithFloat:interval],
|
||||
OBJC_ASSOCIATION_RETAIN);
|
||||
|
||||
[toast setCenter:toastPoint];
|
||||
[toast setAlpha:0.0];
|
||||
[self addSubview:toast];
|
||||
|
||||
[UIView beginAnimations:@"fade_in" context:toast];
|
||||
[UIView setAnimationDuration:kFadeDuration];
|
||||
[UIView setAnimationDelegate:self];
|
||||
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
|
||||
[toast setAlpha:1.0];
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Animation Delegate Method
|
||||
|
||||
- (void)animationDidStop:(NSString *)animationID finished:(BOOL)finished context:(void *)context
|
||||
{
|
||||
|
||||
UIView *toast = (UIView *)context;
|
||||
|
||||
// retrieve the display interval associated with the view
|
||||
float interval = [(NSNumber *)objc_getAssociatedObject(toast, &kDurationKey) floatValue];
|
||||
|
||||
if ([animationID isEqualToString:@"fade_in"])
|
||||
{
|
||||
|
||||
[UIView beginAnimations:@"fade_out" context:toast];
|
||||
[UIView setAnimationDelay:interval];
|
||||
[UIView setAnimationDuration:kFadeDuration];
|
||||
[UIView setAnimationDelegate:self];
|
||||
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
|
||||
[toast setAlpha:0.0];
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
else if ([animationID isEqualToString:@"fade_out"])
|
||||
{
|
||||
|
||||
[toast removeFromSuperview];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Private Methods
|
||||
|
||||
- (CGPoint)getPositionFor:(id)point toast:(UIView *)toast
|
||||
{
|
||||
|
||||
/*************************************************************************************
|
||||
* *
|
||||
* Converts string literals @"top", @"bottom", @"center", or any point wrapped in an *
|
||||
* NSValue object into a CGPoint *
|
||||
* *
|
||||
*************************************************************************************/
|
||||
|
||||
if ([point isKindOfClass:[NSString class]])
|
||||
{
|
||||
|
||||
if ([point caseInsensitiveCompare:@"top"] == NSOrderedSame)
|
||||
{
|
||||
return CGPointMake(self.bounds.size.width / 2,
|
||||
(toast.frame.size.height / 2) + kVerticalPadding);
|
||||
}
|
||||
else if ([point caseInsensitiveCompare:@"bottom"] == NSOrderedSame)
|
||||
{
|
||||
return CGPointMake(self.bounds.size.width / 2,
|
||||
(self.bounds.size.height - (toast.frame.size.height / 2)) -
|
||||
kVerticalPadding);
|
||||
}
|
||||
else if ([point caseInsensitiveCompare:@"center"] == NSOrderedSame)
|
||||
{
|
||||
return CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
|
||||
}
|
||||
}
|
||||
else if ([point isKindOfClass:[NSValue class]])
|
||||
{
|
||||
return [point CGPointValue];
|
||||
}
|
||||
|
||||
NSLog(@"Error: Invalid position for toast.");
|
||||
return [self getPositionFor:kDefaultPosition toast:toast];
|
||||
}
|
||||
|
||||
- (UIView *)makeViewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image
|
||||
{
|
||||
|
||||
/***********************************************************************************
|
||||
* *
|
||||
* Dynamically build a toast view with any combination of message, title, & image. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
|
||||
if ((message == nil) && (title == nil) && (image == nil))
|
||||
return nil;
|
||||
|
||||
UILabel *messageLabel = nil;
|
||||
UILabel *titleLabel = nil;
|
||||
UIImageView *imageView = nil;
|
||||
|
||||
// create the parent view
|
||||
UIView *wrapperView = [[[UIView alloc] init] autorelease];
|
||||
[wrapperView.layer setCornerRadius:kCornerRadius];
|
||||
[wrapperView setBackgroundColor:[[UIColor blackColor] colorWithAlphaComponent:kOpacity]];
|
||||
wrapperView.autoresizingMask =
|
||||
UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin |
|
||||
UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
|
||||
|
||||
if (image != nil)
|
||||
{
|
||||
imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
|
||||
[imageView setContentMode:UIViewContentModeScaleAspectFit];
|
||||
[imageView
|
||||
setFrame:CGRectMake(kHorizontalPadding, kVerticalPadding, kImageWidth, kImageHeight)];
|
||||
}
|
||||
|
||||
float imageWidth, imageHeight, imageLeft;
|
||||
|
||||
// the imageView frame values will be used to size & position the other views
|
||||
if (imageView != nil)
|
||||
{
|
||||
imageWidth = imageView.bounds.size.width;
|
||||
imageHeight = imageView.bounds.size.height;
|
||||
imageLeft = kHorizontalPadding;
|
||||
}
|
||||
else
|
||||
{
|
||||
imageWidth = imageHeight = imageLeft = 0;
|
||||
}
|
||||
|
||||
if (title != nil)
|
||||
{
|
||||
titleLabel = [[[UILabel alloc] init] autorelease];
|
||||
[titleLabel setNumberOfLines:kMaxTitleLines];
|
||||
[titleLabel setFont:[UIFont boldSystemFontOfSize:kFontSize]];
|
||||
[titleLabel setTextAlignment:UITextAlignmentLeft];
|
||||
[titleLabel setLineBreakMode:UILineBreakModeWordWrap];
|
||||
[titleLabel setTextColor:[UIColor whiteColor]];
|
||||
[titleLabel setBackgroundColor:[UIColor clearColor]];
|
||||
[titleLabel setAlpha:1.0];
|
||||
[titleLabel setText:title];
|
||||
|
||||
// size the title label according to the length of the text
|
||||
CGSize maxSizeTitle = CGSizeMake((self.bounds.size.width * kMaxWidth) - imageWidth,
|
||||
self.bounds.size.height * kMaxHeight);
|
||||
CGSize expectedSizeTitle = [title sizeWithFont:titleLabel.font
|
||||
constrainedToSize:maxSizeTitle
|
||||
lineBreakMode:titleLabel.lineBreakMode];
|
||||
[titleLabel setFrame:CGRectMake(0, 0, expectedSizeTitle.width, expectedSizeTitle.height)];
|
||||
}
|
||||
|
||||
if (message != nil)
|
||||
{
|
||||
messageLabel = [[[UILabel alloc] init] autorelease];
|
||||
[messageLabel setNumberOfLines:kMaxMessageLines];
|
||||
[messageLabel setFont:[UIFont systemFontOfSize:kFontSize]];
|
||||
[messageLabel setLineBreakMode:UILineBreakModeWordWrap];
|
||||
[messageLabel setTextColor:[UIColor whiteColor]];
|
||||
[messageLabel setTextAlignment:UITextAlignmentCenter];
|
||||
[messageLabel setBackgroundColor:[UIColor clearColor]];
|
||||
[messageLabel setAlpha:1.0];
|
||||
[messageLabel setText:message];
|
||||
|
||||
// size the message label according to the length of the text
|
||||
CGSize maxSizeMessage = CGSizeMake((self.bounds.size.width * kMaxWidth) - imageWidth,
|
||||
self.bounds.size.height * kMaxHeight);
|
||||
CGSize expectedSizeMessage = [message sizeWithFont:messageLabel.font
|
||||
constrainedToSize:maxSizeMessage
|
||||
lineBreakMode:messageLabel.lineBreakMode];
|
||||
[messageLabel
|
||||
setFrame:CGRectMake(0, 0, expectedSizeMessage.width, expectedSizeMessage.height)];
|
||||
}
|
||||
|
||||
// titleLabel frame values
|
||||
float titleWidth, titleHeight, titleTop, titleLeft;
|
||||
|
||||
if (titleLabel != nil)
|
||||
{
|
||||
titleWidth = titleLabel.bounds.size.width;
|
||||
titleHeight = titleLabel.bounds.size.height;
|
||||
titleTop = kVerticalPadding;
|
||||
titleLeft = imageLeft + imageWidth + kHorizontalPadding;
|
||||
}
|
||||
else
|
||||
{
|
||||
titleWidth = titleHeight = titleTop = titleLeft = 0;
|
||||
}
|
||||
|
||||
// messageLabel frame values
|
||||
float messageWidth, messageHeight, messageLeft, messageTop;
|
||||
|
||||
if (messageLabel != nil)
|
||||
{
|
||||
messageWidth = messageLabel.bounds.size.width;
|
||||
messageHeight = messageLabel.bounds.size.height;
|
||||
messageLeft = imageLeft + imageWidth + kHorizontalPadding;
|
||||
messageTop = titleTop + titleHeight + kVerticalPadding;
|
||||
}
|
||||
else
|
||||
{
|
||||
messageWidth = messageHeight = messageLeft = messageTop = 0;
|
||||
}
|
||||
|
||||
// compare the title & message widths and use the longer value to calculate the size of the
|
||||
// wrapper width the same logic applies to the x value (left)
|
||||
float longerWidth = (messageWidth < titleWidth) ? titleWidth : messageWidth;
|
||||
float longerLeft = (messageLeft < titleLeft) ? titleLeft : messageLeft;
|
||||
|
||||
// if the image width is larger than longerWidth, use the image width to calculate the wrapper
|
||||
// width. the same logic applies to the wrapper height
|
||||
float wrapperWidth =
|
||||
((longerLeft + longerWidth + kHorizontalPadding) < imageWidth + (kHorizontalPadding * 2))
|
||||
? imageWidth + (kHorizontalPadding * 2)
|
||||
: (longerLeft + longerWidth + kHorizontalPadding);
|
||||
float wrapperHeight =
|
||||
((messageTop + messageHeight + kVerticalPadding) < imageHeight + (kVerticalPadding * 2))
|
||||
? imageHeight + (kVerticalPadding * 2)
|
||||
: (messageTop + messageHeight + kVerticalPadding);
|
||||
|
||||
[wrapperView setFrame:CGRectMake(0, 0, wrapperWidth, wrapperHeight)];
|
||||
|
||||
if (titleLabel != nil)
|
||||
{
|
||||
[titleLabel setFrame:CGRectMake(titleLeft, titleTop, titleWidth, titleHeight)];
|
||||
[wrapperView addSubview:titleLabel];
|
||||
}
|
||||
|
||||
if (messageLabel != nil)
|
||||
{
|
||||
[messageLabel setFrame:CGRectMake(messageLeft, messageTop, messageWidth, messageHeight)];
|
||||
[wrapperView addSubview:messageLabel];
|
||||
}
|
||||
|
||||
if (imageView != nil)
|
||||
{
|
||||
[wrapperView addSubview:imageView];
|
||||
}
|
||||
|
||||
return wrapperView;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user